attachListener_windows.cpp revision 4977:2e8f19c2feef
1296341Sdelphij/* 296593Smarkm * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 396593Smarkm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4142429Snectar * 596593Smarkm * This code is free software; you can redistribute it and/or modify it 696593Smarkm * under the terms of the GNU General Public License version 2 only, as 796593Smarkm * published by the Free Software Foundation. 896593Smarkm * 996593Smarkm * This code is distributed in the hope that it will be useful, but WITHOUT 1096593Smarkm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1196593Smarkm * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1296593Smarkm * version 2 for more details (a copy is included in the LICENSE file that 1396593Smarkm * accompanied this code). 1496593Smarkm * 1596593Smarkm * You should have received a copy of the GNU General Public License version 1696593Smarkm * 2 along with this work; if not, write to the Free Software Foundation, 1796593Smarkm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1896593Smarkm * 1996593Smarkm * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20215698Ssimon * or visit www.oracle.com if you need additional information or have any 21215698Ssimon * questions. 22215698Ssimon * 23215698Ssimon */ 24215698Ssimon 2596593Smarkm#include "precompiled.hpp" 2696593Smarkm#include "runtime/interfaceSupport.hpp" 2796593Smarkm#include "runtime/os.hpp" 2896593Smarkm#include "services/attachListener.hpp" 2996593Smarkm#include "services/dtraceAttacher.hpp" 3096593Smarkm 3196593Smarkm#include <windows.h> 3296593Smarkm#include <signal.h> // SIGBREAK 3396593Smarkm 3496593Smarkm// The AttachListener thread services a queue of operations. It blocks in the dequeue 3596593Smarkm// function until an operation is enqueued. A client enqueues an operation by creating 3696593Smarkm// a thread in this process using the Win32 CreateRemoteThread function. That thread 3796593Smarkm// executes a small stub generated by the client. The stub invokes the 3896593Smarkm// JVM_EnqueueOperation function which checks the operation parameters and enqueues 3996593Smarkm// the operation to the queue serviced by the attach listener. The thread created by 4096593Smarkm// the client is a native thread and is restricted to a single page of stack. To keep 41279264Sdelphij// it simple operations are pre-allocated at initialization time. An enqueue thus 42279264Sdelphij// takes a preallocated operation, populates the operation parameters, adds it to 4396593Smarkm// queue and wakes up the attach listener. 4496593Smarkm// 45215698Ssimon// When an operation has completed the attach listener is required to send the 46215698Ssimon// operation result and any result data to the client. In this implementation the 47215698Ssimon// client is a pipe server. In the enqueue operation it provides the name of pipe 48215698Ssimon// to this process. When the operation is completed this process opens the pipe and 49142429Snectar// sends the result and output back to the client. Note that writing to the pipe 50215698Ssimon// (and flushing the output) is a blocking operation. This means that a non-responsive 51142429Snectar// client could potentially hang the attach listener thread indefinitely. In that 52142429Snectar// case no new operations would be executed but the VM would continue as normal. 53279264Sdelphij// As only suitably privileged processes can open this process we concluded that 54279264Sdelphij// this wasn't worth worrying about. 55279264Sdelphij 5696593Smarkm 57279264Sdelphij// forward reference 58279264Sdelphijclass Win32AttachOperation; 59279264Sdelphij 60279264Sdelphij 61279264Sdelphijclass Win32AttachListener: AllStatic { 62279264Sdelphij private: 63215698Ssimon enum { 64279264Sdelphij preallocate_count = 4 // number of preallocated operations 65279264Sdelphij }; 66279264Sdelphij 67279264Sdelphij // protects the preallocated list and the operation list 68279264Sdelphij static HANDLE _mutex; 69215698Ssimon 70279264Sdelphij // head of preallocated operations list 7196593Smarkm static Win32AttachOperation* _avail; 7296593Smarkm 7396593Smarkm // head and tail of enqueue operations list 7496593Smarkm static Win32AttachOperation* _head; 7596593Smarkm static Win32AttachOperation* _tail; 7696593Smarkm 7796593Smarkm 7896593Smarkm static Win32AttachOperation* head() { return _head; } 7996593Smarkm static void set_head(Win32AttachOperation* head) { _head = head; } 8096593Smarkm 8196593Smarkm static Win32AttachOperation* tail() { return _tail; } 8296593Smarkm static void set_tail(Win32AttachOperation* tail) { _tail = tail; } 8396593Smarkm 8496593Smarkm 8596593Smarkm // used to wakeup the listener 8696593Smarkm static HANDLE _wakeup; 8796593Smarkm static HANDLE wakeup() { return _wakeup; } 8896593Smarkm 8996593Smarkm public: 9096593Smarkm enum { 9196593Smarkm ATTACH_ERROR_DISABLED = 100, // error codes 9296593Smarkm ATTACH_ERROR_RESOURCE = 101, 9396593Smarkm ATTACH_ERROR_ILLEGALARG = 102, 9496593Smarkm ATTACH_ERROR_INTERNAL = 103 9596593Smarkm }; 9696593Smarkm 9796593Smarkm static int init(); 9896593Smarkm static HANDLE mutex() { return _mutex; } 9996593Smarkm 10096593Smarkm static Win32AttachOperation* available() { return _avail; } 10196593Smarkm static void set_available(Win32AttachOperation* avail) { _avail = avail; } 10296593Smarkm 10396593Smarkm // enqueue an operation to the end of the list 10496593Smarkm static int enqueue(char* cmd, char* arg1, char* arg2, char* arg3, char* pipename); 10596593Smarkm 10696593Smarkm // dequeue an operation from from head of the list 10796593Smarkm static Win32AttachOperation* dequeue(); 10896593Smarkm}; 10996593Smarkm 11096593Smarkm// statics 11196593SmarkmHANDLE Win32AttachListener::_mutex; 11296593SmarkmHANDLE Win32AttachListener::_wakeup; 11396593SmarkmWin32AttachOperation* Win32AttachListener::_avail; 11496593SmarkmWin32AttachOperation* Win32AttachListener::_head; 11596593SmarkmWin32AttachOperation* Win32AttachListener::_tail; 11696593Smarkm 11796593Smarkm 11896593Smarkm// Win32AttachOperation is an AttachOperation that additionally encapsulates the name 11996593Smarkm// of a pipe which is used to send the operation reply/output to the client. 12096593Smarkm// Win32AttachOperation can also be linked in a list. 12196593Smarkm 12296593Smarkmclass Win32AttachOperation: public AttachOperation { 12396593Smarkm private: 12496593Smarkm friend class Win32AttachListener; 12596593Smarkm 12696593Smarkm enum { 12796593Smarkm pipe_name_max = 256 // maximum pipe name 12896593Smarkm }; 12996593Smarkm 13096593Smarkm char _pipe[pipe_name_max+1]; 13196593Smarkm 13296593Smarkm const char* pipe() const { return _pipe; } 133142429Snectar void set_pipe(const char* pipe) { 13496593Smarkm assert(strlen(pipe) <= pipe_name_max, "execeds maximum length of pipe name"); 135100946Snectar strcpy(_pipe, pipe); 136296341Sdelphij } 137215698Ssimon 138215698Ssimon HANDLE open_pipe(); 139215698Ssimon static BOOL write_pipe(HANDLE hPipe, char* buf, int len); 140215698Ssimon 14196593Smarkm Win32AttachOperation* _next; 14296593Smarkm 143110010Smarkm Win32AttachOperation* next() const { return _next; } 144142429Snectar void set_next(Win32AttachOperation* next) { _next = next; } 14596593Smarkm 14696593Smarkm // noarg constructor as operation is preallocated 14796593Smarkm Win32AttachOperation() : AttachOperation("<noname>") { 14896593Smarkm set_pipe("<nopipe>"); 149215698Ssimon set_next(NULL); 150110010Smarkm } 151215698Ssimon 15296593Smarkm public: 153215698Ssimon void Win32AttachOperation::complete(jint result, bufferedStream* result_stream); 154110010Smarkm}; 155215698Ssimon 156110010Smarkm 157215698Ssimon// preallocate the required number of operations 15896593Smarkmint Win32AttachListener::init() { 159215698Ssimon _mutex = (void*)::CreateMutex(NULL, FALSE, NULL); 16096593Smarkm guarantee(_mutex != (HANDLE)NULL, "mutex creation failed"); 161215698Ssimon 162110010Smarkm _wakeup = ::CreateSemaphore(NULL, 0, 1, NULL); 163215698Ssimon guarantee(_wakeup != (HANDLE)NULL, "semaphore creation failed"); 16496593Smarkm 16596593Smarkm set_head(NULL); 16696593Smarkm set_tail(NULL); 16796593Smarkm 16896593Smarkm // preallocate a few operations 169110010Smarkm set_available(NULL); 170110010Smarkm for (int i=0; i<preallocate_count; i++) { 171279264Sdelphij Win32AttachOperation* op = new Win32AttachOperation(); 172110010Smarkm op->set_next(available()); 17396593Smarkm set_available(op); 174110010Smarkm } 175110010Smarkm 17696593Smarkm return 0; 177110010Smarkm} 178110010Smarkm 179279264Sdelphij// Enqueue an operation. This is called from a native thread that is not attached to VM. 18096593Smarkm// Also we need to be careful not to execute anything that results in more than a 4k stack. 18196593Smarkm// 182279264Sdelphijint Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { 183279264Sdelphij // listener not running 184110010Smarkm if (!AttachListener::is_initialized()) { 18596593Smarkm return ATTACH_ERROR_DISABLED; 186110010Smarkm } 187110010Smarkm 188279264Sdelphij // check that all paramteres to the operation 189110010Smarkm if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG; 190110010Smarkm if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; 191110010Smarkm if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; 192110010Smarkm if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG; 193110010Smarkm 19496593Smarkm // check for a well-formed pipename 195110010Smarkm if (strstr(pipename, "\\\\.\\pipe\\") != pipename) return ATTACH_ERROR_ILLEGALARG; 196110010Smarkm 197110010Smarkm // grab the lock for the list 198110010Smarkm DWORD res = ::WaitForSingleObject(mutex(), INFINITE); 199110010Smarkm if (res != WAIT_OBJECT_0) { 20096593Smarkm return ATTACH_ERROR_INTERNAL; 201110010Smarkm } 202279264Sdelphij 203110010Smarkm // try to get an operation from the available list 204110010Smarkm Win32AttachOperation* op = available(); 205279264Sdelphij if (op != NULL) { 206110010Smarkm set_available(op->next()); 207110010Smarkm 208110010Smarkm // add to end (tail) of list 20996593Smarkm op->set_next(NULL); 21096593Smarkm if (tail() == NULL) { 21196593Smarkm set_head(op); 21296593Smarkm } else { 21396593Smarkm tail()->set_next(op); 21496593Smarkm } 21596593Smarkm set_tail(op); 21696593Smarkm 21796593Smarkm op->set_name(cmd); 21896593Smarkm op->set_arg(0, arg0); 21996593Smarkm op->set_arg(1, arg1); 22096593Smarkm op->set_arg(2, arg2); 221215698Ssimon op->set_pipe(pipename); 22296593Smarkm 22396593Smarkm // wakeup the thread waiting for operations 22496593Smarkm ::ReleaseSemaphore(wakeup(), 1, NULL); 225215698Ssimon } 22696593Smarkm ::ReleaseMutex(mutex()); 22796593Smarkm 22896593Smarkm return (op != NULL) ? 0 : ATTACH_ERROR_RESOURCE; 229215698Ssimon} 23096593Smarkm 23196593Smarkm 23296593Smarkm// dequeue the operation from the head of the operation list. If 233215698SsimonWin32AttachOperation* Win32AttachListener::dequeue() { 23496593Smarkm for (;;) { 23596593Smarkm DWORD res = ::WaitForSingleObject(wakeup(), INFINITE); 23696593Smarkm guarantee(res == WAIT_OBJECT_0, "wait failed"); 237215698Ssimon 238215698Ssimon res = ::WaitForSingleObject(mutex(), INFINITE); 23996593Smarkm guarantee(res == WAIT_OBJECT_0, "wait failed"); 24096593Smarkm 241215698Ssimon Win32AttachOperation* op = head(); 24296593Smarkm if (op != NULL) { 24396593Smarkm set_head(op->next()); 24496593Smarkm if (head() == NULL) { // list is empty 245215698Ssimon set_tail(NULL); 24696593Smarkm } 24796593Smarkm } 248215698Ssimon ::ReleaseMutex(mutex()); 24996593Smarkm 25096593Smarkm if (op != NULL) { 251215698Ssimon return op; 252215698Ssimon } 25396593Smarkm } 25496593Smarkm} 255215698Ssimon 256215698Ssimon 25796593Smarkm// open the pipe to the client 25896593SmarkmHANDLE Win32AttachOperation::open_pipe() { 259215698Ssimon HANDLE hPipe; 26096593Smarkm 261215698Ssimon hPipe = ::CreateFile( pipe(), // pipe name 26296593Smarkm GENERIC_WRITE, // write only 26396593Smarkm 0, // no sharing 26496593Smarkm NULL, // default security attributes 265269686Sjkim OPEN_EXISTING, // opens existing pipe 266269686Sjkim 0, // default attributes 267269686Sjkim NULL); // no template file 26896593Smarkm 26996593Smarkm if (hPipe != INVALID_HANDLE_VALUE) { 27096593Smarkm // shouldn't happen as there is a pipe created per operation 271269686Sjkim if (::GetLastError() == ERROR_PIPE_BUSY) { 272269686Sjkim return INVALID_HANDLE_VALUE; 273269686Sjkim } 274269686Sjkim } 275269686Sjkim return hPipe; 276269686Sjkim} 277215698Ssimon 27896593Smarkm// write to the pipe 27996593SmarkmBOOL Win32AttachOperation::write_pipe(HANDLE hPipe, char* buf, int len) { 28096593Smarkm do { 28196593Smarkm DWORD nwrote; 282110010Smarkm 283110010Smarkm BOOL fSuccess = WriteFile( hPipe, // pipe handle 28496593Smarkm (LPCVOID)buf, // message 28596593Smarkm (DWORD)len, // message length 28696593Smarkm &nwrote, // bytes written 287110010Smarkm NULL); // not overlapped 288110010Smarkm if (!fSuccess) { 289279264Sdelphij return fSuccess; 290110010Smarkm } 291110010Smarkm buf += nwrote; 292110010Smarkm len -= nwrote; 293110010Smarkm } 29496593Smarkm while (len > 0); 295110010Smarkm return TRUE; 296142429Snectar} 297110010Smarkm 298110010Smarkm// Complete the operation: 299110010Smarkm// - open the pipe to the client 300110010Smarkm// - write the operation result (a jint) 301279264Sdelphij// - write the operation output (the result stream) 302110010Smarkm// 303279264Sdelphijvoid Win32AttachOperation::complete(jint result, bufferedStream* result_stream) { 304279264Sdelphij JavaThread* thread = JavaThread::current(); 305110010Smarkm ThreadBlockInVM tbivm(thread); 306110010Smarkm 307110010Smarkm thread->set_suspend_equivalent(); 308110010Smarkm // cleared by handle_special_suspend_equivalent_condition() or 309110010Smarkm // java_suspend_self() via check_and_wait_while_suspended() 310110010Smarkm 311110010Smarkm HANDLE hPipe = open_pipe(); 312110010Smarkm if (hPipe != INVALID_HANDLE_VALUE) { 313110010Smarkm BOOL fSuccess; 314110010Smarkm 315110010Smarkm char msg[32]; 316110010Smarkm sprintf(msg, "%d\n", result); 317110010Smarkm 31896593Smarkm fSuccess = write_pipe(hPipe, msg, (int)strlen(msg)); 31996593Smarkm if (fSuccess) { 320142429Snectar write_pipe(hPipe, (char*) result_stream->base(), (int)(result_stream->size())); 32196593Smarkm } 32296593Smarkm 32396593Smarkm // Need to flush buffers 32496593Smarkm FlushFileBuffers(hPipe); 32596593Smarkm CloseHandle(hPipe); 32696593Smarkm } 327110010Smarkm 328110010Smarkm DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE); 329110010Smarkm if (res == WAIT_OBJECT_0) { 330110010Smarkm 331110010Smarkm // put the operation back on the available list 332279264Sdelphij set_next(Win32AttachListener::available()); 333279264Sdelphij Win32AttachListener::set_available(this); 334110010Smarkm 335279264Sdelphij ::ReleaseMutex(Win32AttachListener::mutex()); 336279264Sdelphij } 337110010Smarkm 338 // were we externally suspended while we were waiting? 339 thread->check_and_wait_while_suspended(); 340} 341 342 343// AttachOperation functions 344 345AttachOperation* AttachListener::dequeue() { 346 JavaThread* thread = JavaThread::current(); 347 ThreadBlockInVM tbivm(thread); 348 349 thread->set_suspend_equivalent(); 350 // cleared by handle_special_suspend_equivalent_condition() or 351 // java_suspend_self() via check_and_wait_while_suspended() 352 353 AttachOperation* op = Win32AttachListener::dequeue(); 354 355 // were we externally suspended while we were waiting? 356 thread->check_and_wait_while_suspended(); 357 358 return op; 359} 360 361void AttachListener::vm_start() { 362 // nothing to do 363} 364 365int AttachListener::pd_init() { 366 return Win32AttachListener::init(); 367} 368 369// always startup on Windows NT/2000/XP 370bool AttachListener::init_at_startup() { 371 return os::win32::is_nt(); 372} 373 374// no trigger mechanism on Windows to start Attach Listener lazily 375bool AttachListener::is_init_trigger() { 376 return false; 377} 378 379void AttachListener::abort() { 380 // nothing to do 381} 382 383void AttachListener::pd_data_dump() { 384 os::signal_notify(SIGBREAK); 385} 386 387AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { 388 return NULL; 389} 390 391jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { 392 out->print_cr("flag '%s' cannot be changed", op->arg(0)); 393 return JNI_ERR; 394} 395 396void AttachListener::pd_detachall() { 397 // do nothing for now 398} 399 400// Native thread started by remote client executes this. 401extern "C" { 402 JNIEXPORT jint JNICALL 403 JVM_EnqueueOperation(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { 404 return (jint)Win32AttachListener::enqueue(cmd, arg0, arg1, arg2, pipename); 405 } 406 407} // extern 408