1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/os/windows/vm/attachListener_windows.cpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,400 @@ 1.4 +/* 1.5 + * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +# include "incls/_precompiled.incl" 1.29 +# include "incls/_attachListener_windows.cpp.incl" 1.30 + 1.31 +#include <windows.h> 1.32 +#include <signal.h> // SIGBREAK 1.33 + 1.34 +// The AttachListener thread services a queue of operations. It blocks in the dequeue 1.35 +// function until an operation is enqueued. A client enqueues an operation by creating 1.36 +// a thread in this process using the Win32 CreateRemoteThread function. That thread 1.37 +// executes a small stub generated by the client. The stub invokes the 1.38 +// JVM_EnqueueOperation function which checks the operation parameters and enqueues 1.39 +// the operation to the queue serviced by the attach listener. The thread created by 1.40 +// the client is a native thread and is restricted to a single page of stack. To keep 1.41 +// it simple operations are pre-allocated at initialization time. An enqueue thus 1.42 +// takes a preallocated operation, populates the operation parameters, adds it to 1.43 +// queue and wakes up the attach listener. 1.44 +// 1.45 +// When an operation has completed the attach listener is required to send the 1.46 +// operation result and any result data to the client. In this implementation the 1.47 +// client is a pipe server. In the enqueue operation it provides the name of pipe 1.48 +// to this process. When the operation is completed this process opens the pipe and 1.49 +// sends the result and output back to the client. Note that writing to the pipe 1.50 +// (and flushing the output) is a blocking operation. This means that a non-responsive 1.51 +// client could potentially hang the attach listener thread indefinitely. In that 1.52 +// case no new operations would be executed but the VM would continue as normal. 1.53 +// As only suitably privileged processes can open this process we concluded that 1.54 +// this wasn't worth worrying about. 1.55 + 1.56 + 1.57 +// forward reference 1.58 +class Win32AttachOperation; 1.59 + 1.60 + 1.61 +class Win32AttachListener: AllStatic { 1.62 + private: 1.63 + enum { 1.64 + preallocate_count = 4 // number of preallocated operations 1.65 + }; 1.66 + 1.67 + // protects the preallocated list and the operation list 1.68 + static HANDLE _mutex; 1.69 + 1.70 + // head of preallocated operations list 1.71 + static Win32AttachOperation* _avail; 1.72 + 1.73 + // head and tail of enqueue operations list 1.74 + static Win32AttachOperation* _head; 1.75 + static Win32AttachOperation* _tail; 1.76 + 1.77 + 1.78 + static Win32AttachOperation* head() { return _head; } 1.79 + static void set_head(Win32AttachOperation* head) { _head = head; } 1.80 + 1.81 + static Win32AttachOperation* tail() { return _tail; } 1.82 + static void set_tail(Win32AttachOperation* tail) { _tail = tail; } 1.83 + 1.84 + 1.85 + // used to wakeup the listener 1.86 + static HANDLE _wakeup; 1.87 + static HANDLE wakeup() { return _wakeup; } 1.88 + 1.89 + public: 1.90 + enum { 1.91 + ATTACH_ERROR_DISABLED = 100, // error codes 1.92 + ATTACH_ERROR_RESOURCE = 101, 1.93 + ATTACH_ERROR_ILLEGALARG = 102, 1.94 + ATTACH_ERROR_INTERNAL = 103 1.95 + }; 1.96 + 1.97 + static int init(); 1.98 + static HANDLE mutex() { return _mutex; } 1.99 + 1.100 + static Win32AttachOperation* available() { return _avail; } 1.101 + static void set_available(Win32AttachOperation* avail) { _avail = avail; } 1.102 + 1.103 + // enqueue an operation to the end of the list 1.104 + static int enqueue(char* cmd, char* arg1, char* arg2, char* arg3, char* pipename); 1.105 + 1.106 + // dequeue an operation from from head of the list 1.107 + static Win32AttachOperation* dequeue(); 1.108 +}; 1.109 + 1.110 +// statics 1.111 +HANDLE Win32AttachListener::_mutex; 1.112 +HANDLE Win32AttachListener::_wakeup; 1.113 +Win32AttachOperation* Win32AttachListener::_avail; 1.114 +Win32AttachOperation* Win32AttachListener::_head; 1.115 +Win32AttachOperation* Win32AttachListener::_tail; 1.116 + 1.117 + 1.118 +// Win32AttachOperation is an AttachOperation that additionally encapsulates the name 1.119 +// of a pipe which is used to send the operation reply/output to the client. 1.120 +// Win32AttachOperation can also be linked in a list. 1.121 + 1.122 +class Win32AttachOperation: public AttachOperation { 1.123 + private: 1.124 + friend class Win32AttachListener; 1.125 + 1.126 + enum { 1.127 + pipe_name_max = 256 // maximum pipe name 1.128 + }; 1.129 + 1.130 + char _pipe[pipe_name_max+1]; 1.131 + 1.132 + const char* pipe() const { return _pipe; } 1.133 + void set_pipe(const char* pipe) { 1.134 + assert(strlen(pipe) <= pipe_name_max, "execeds maximum length of pipe name"); 1.135 + strcpy(_pipe, pipe); 1.136 + } 1.137 + 1.138 + HANDLE open_pipe(); 1.139 + static BOOL write_pipe(HANDLE hPipe, char* buf, int len); 1.140 + 1.141 + Win32AttachOperation* _next; 1.142 + 1.143 + Win32AttachOperation* next() const { return _next; } 1.144 + void set_next(Win32AttachOperation* next) { _next = next; } 1.145 + 1.146 + // noarg constructor as operation is preallocated 1.147 + Win32AttachOperation() : AttachOperation("<noname>") { 1.148 + set_pipe("<nopipe>"); 1.149 + set_next(NULL); 1.150 + } 1.151 + 1.152 + public: 1.153 + void Win32AttachOperation::complete(jint result, bufferedStream* result_stream); 1.154 +}; 1.155 + 1.156 + 1.157 +// preallocate the required number of operations 1.158 +int Win32AttachListener::init() { 1.159 + _mutex = (void*)::CreateMutex(NULL, FALSE, NULL); 1.160 + guarantee(_mutex != (HANDLE)NULL, "mutex creation failed"); 1.161 + 1.162 + _wakeup = ::CreateSemaphore(NULL, 0, 1, NULL); 1.163 + guarantee(_wakeup != (HANDLE)NULL, "semaphore creation failed"); 1.164 + 1.165 + set_head(NULL); 1.166 + set_tail(NULL); 1.167 + 1.168 + // preallocate a few operations 1.169 + set_available(NULL); 1.170 + for (int i=0; i<preallocate_count; i++) { 1.171 + Win32AttachOperation* op = new Win32AttachOperation(); 1.172 + op->set_next(available()); 1.173 + set_available(op); 1.174 + } 1.175 + 1.176 + return 0; 1.177 +} 1.178 + 1.179 +// Enqueue an operation. This is called from a native thread that is not attached to VM. 1.180 +// Also we need to be careful not to execute anything that results in more than a 4k stack. 1.181 +// 1.182 +int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { 1.183 + // listener not running 1.184 + if (!AttachListener::is_initialized()) { 1.185 + return ATTACH_ERROR_DISABLED; 1.186 + } 1.187 + 1.188 + // check that all paramteres to the operation 1.189 + if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG; 1.190 + if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; 1.191 + if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; 1.192 + if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG; 1.193 + 1.194 + // check for a well-formed pipename 1.195 + if (strstr(pipename, "\\\\.\\pipe\\") != pipename) return ATTACH_ERROR_ILLEGALARG; 1.196 + 1.197 + // grab the lock for the list 1.198 + DWORD res = ::WaitForSingleObject(mutex(), INFINITE); 1.199 + if (res != WAIT_OBJECT_0) { 1.200 + return ATTACH_ERROR_INTERNAL; 1.201 + } 1.202 + 1.203 + // try to get an operation from the available list 1.204 + Win32AttachOperation* op = available(); 1.205 + if (op != NULL) { 1.206 + set_available(op->next()); 1.207 + 1.208 + // add to end (tail) of list 1.209 + op->set_next(NULL); 1.210 + if (tail() == NULL) { 1.211 + set_head(op); 1.212 + } else { 1.213 + tail()->set_next(op); 1.214 + } 1.215 + set_tail(op); 1.216 + 1.217 + op->set_name(cmd); 1.218 + op->set_arg(0, arg0); 1.219 + op->set_arg(1, arg1); 1.220 + op->set_arg(2, arg2); 1.221 + op->set_pipe(pipename); 1.222 + 1.223 + // wakeup the thread waiting for operations 1.224 + ::ReleaseSemaphore(wakeup(), 1, NULL); 1.225 + } 1.226 + ::ReleaseMutex(mutex()); 1.227 + 1.228 + return (op != NULL) ? 0 : ATTACH_ERROR_RESOURCE; 1.229 +} 1.230 + 1.231 + 1.232 +// dequeue the operation from the head of the operation list. If 1.233 +Win32AttachOperation* Win32AttachListener::dequeue() { 1.234 + for (;;) { 1.235 + DWORD res = ::WaitForSingleObject(wakeup(), INFINITE); 1.236 + guarantee(res == WAIT_OBJECT_0, "wait failed"); 1.237 + 1.238 + res = ::WaitForSingleObject(mutex(), INFINITE); 1.239 + guarantee(res == WAIT_OBJECT_0, "wait failed"); 1.240 + 1.241 + Win32AttachOperation* op = head(); 1.242 + if (op != NULL) { 1.243 + set_head(op->next()); 1.244 + if (head() == NULL) { // list is empty 1.245 + set_tail(NULL); 1.246 + } 1.247 + } 1.248 + ::ReleaseMutex(mutex()); 1.249 + 1.250 + if (op != NULL) { 1.251 + return op; 1.252 + } 1.253 + } 1.254 +} 1.255 + 1.256 + 1.257 +// open the pipe to the client 1.258 +HANDLE Win32AttachOperation::open_pipe() { 1.259 + HANDLE hPipe; 1.260 + 1.261 + hPipe = ::CreateFile( pipe(), // pipe name 1.262 + GENERIC_WRITE, // write only 1.263 + 0, // no sharing 1.264 + NULL, // default security attributes 1.265 + OPEN_EXISTING, // opens existing pipe 1.266 + 0, // default attributes 1.267 + NULL); // no template file 1.268 + 1.269 + if (hPipe != INVALID_HANDLE_VALUE) { 1.270 + // shouldn't happen as there is a pipe created per operation 1.271 + if (::GetLastError() == ERROR_PIPE_BUSY) { 1.272 + return INVALID_HANDLE_VALUE; 1.273 + } 1.274 + } 1.275 + return hPipe; 1.276 +} 1.277 + 1.278 +// write to the pipe 1.279 +BOOL Win32AttachOperation::write_pipe(HANDLE hPipe, char* buf, int len) { 1.280 + do { 1.281 + DWORD nwrote; 1.282 + 1.283 + BOOL fSuccess = WriteFile( hPipe, // pipe handle 1.284 + (LPCVOID)buf, // message 1.285 + (DWORD)len, // message length 1.286 + &nwrote, // bytes written 1.287 + NULL); // not overlapped 1.288 + if (!fSuccess) { 1.289 + return fSuccess; 1.290 + } 1.291 + buf += nwrote; 1.292 + len -= nwrote; 1.293 + } 1.294 + while (len > 0); 1.295 + return TRUE; 1.296 +} 1.297 + 1.298 +// Complete the operation: 1.299 +// - open the pipe to the client 1.300 +// - write the operation result (a jint) 1.301 +// - write the operation output (the result stream) 1.302 +// 1.303 +void Win32AttachOperation::complete(jint result, bufferedStream* result_stream) { 1.304 + JavaThread* thread = JavaThread::current(); 1.305 + ThreadBlockInVM tbivm(thread); 1.306 + 1.307 + thread->set_suspend_equivalent(); 1.308 + // cleared by handle_special_suspend_equivalent_condition() or 1.309 + // java_suspend_self() via check_and_wait_while_suspended() 1.310 + 1.311 + HANDLE hPipe = open_pipe(); 1.312 + if (hPipe != INVALID_HANDLE_VALUE) { 1.313 + BOOL fSuccess; 1.314 + 1.315 + char msg[32]; 1.316 + sprintf(msg, "%d\n", result); 1.317 + 1.318 + fSuccess = write_pipe(hPipe, msg, (int)strlen(msg)); 1.319 + if (fSuccess) { 1.320 + write_pipe(hPipe, (char*) result_stream->base(), (int)(result_stream->size())); 1.321 + } 1.322 + 1.323 + // Need to flush buffers 1.324 + FlushFileBuffers(hPipe); 1.325 + CloseHandle(hPipe); 1.326 + } 1.327 + 1.328 + DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE); 1.329 + if (res == WAIT_OBJECT_0) { 1.330 + 1.331 + // put the operation back on the available list 1.332 + set_next(Win32AttachListener::available()); 1.333 + Win32AttachListener::set_available(this); 1.334 + 1.335 + ::ReleaseMutex(Win32AttachListener::mutex()); 1.336 + } 1.337 + 1.338 + // were we externally suspended while we were waiting? 1.339 + thread->check_and_wait_while_suspended(); 1.340 +} 1.341 + 1.342 + 1.343 +// AttachOperation functions 1.344 + 1.345 +AttachOperation* AttachListener::dequeue() { 1.346 + JavaThread* thread = JavaThread::current(); 1.347 + ThreadBlockInVM tbivm(thread); 1.348 + 1.349 + thread->set_suspend_equivalent(); 1.350 + // cleared by handle_special_suspend_equivalent_condition() or 1.351 + // java_suspend_self() via check_and_wait_while_suspended() 1.352 + 1.353 + AttachOperation* op = Win32AttachListener::dequeue(); 1.354 + 1.355 + // were we externally suspended while we were waiting? 1.356 + thread->check_and_wait_while_suspended(); 1.357 + 1.358 + return op; 1.359 +} 1.360 + 1.361 +int AttachListener::pd_init() { 1.362 + return Win32AttachListener::init(); 1.363 +} 1.364 + 1.365 +// always startup on Windows NT/2000/XP 1.366 +bool AttachListener::init_at_startup() { 1.367 + return os::win32::is_nt(); 1.368 +} 1.369 + 1.370 +// no trigger mechanism on Windows to start Attach Listener lazily 1.371 +bool AttachListener::is_init_trigger() { 1.372 + return false; 1.373 +} 1.374 + 1.375 +void AttachListener::abort() { 1.376 + // nothing to do 1.377 +} 1.378 + 1.379 +void AttachListener::pd_data_dump() { 1.380 + os::signal_notify(SIGBREAK); 1.381 +} 1.382 + 1.383 +AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { 1.384 + return NULL; 1.385 +} 1.386 + 1.387 +jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { 1.388 + out->print_cr("flag '%s' cannot be changed", op->arg(0)); 1.389 + return JNI_ERR; 1.390 +} 1.391 + 1.392 +void AttachListener::pd_detachall() { 1.393 + // do nothing for now 1.394 +} 1.395 + 1.396 +// Native thread started by remote client executes this. 1.397 +extern "C" { 1.398 + JNIEXPORT jint JNICALL 1.399 + JVM_EnqueueOperation(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { 1.400 + return (jint)Win32AttachListener::enqueue(cmd, arg0, arg1, arg2, pipename); 1.401 + } 1.402 + 1.403 +} // extern