Mercurial > hg > graal-compiler
annotate src/os/windows/vm/attachListener_windows.cpp @ 1597:b34c75c0b6b8
Added tag jdk7-b99 for changeset 6a236384a379
author | mikejwre |
---|---|
date | Thu, 24 Jun 2010 20:03:00 -0700 |
parents | c18cbe5936b8 |
children | f95d63e2154a |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_attachListener_windows.cpp.incl" | |
27 | |
28 #include <windows.h> | |
29 #include <signal.h> // SIGBREAK | |
30 | |
31 // The AttachListener thread services a queue of operations. It blocks in the dequeue | |
32 // function until an operation is enqueued. A client enqueues an operation by creating | |
33 // a thread in this process using the Win32 CreateRemoteThread function. That thread | |
34 // executes a small stub generated by the client. The stub invokes the | |
35 // JVM_EnqueueOperation function which checks the operation parameters and enqueues | |
36 // the operation to the queue serviced by the attach listener. The thread created by | |
37 // the client is a native thread and is restricted to a single page of stack. To keep | |
38 // it simple operations are pre-allocated at initialization time. An enqueue thus | |
39 // takes a preallocated operation, populates the operation parameters, adds it to | |
40 // queue and wakes up the attach listener. | |
41 // | |
42 // When an operation has completed the attach listener is required to send the | |
43 // operation result and any result data to the client. In this implementation the | |
44 // client is a pipe server. In the enqueue operation it provides the name of pipe | |
45 // to this process. When the operation is completed this process opens the pipe and | |
46 // sends the result and output back to the client. Note that writing to the pipe | |
47 // (and flushing the output) is a blocking operation. This means that a non-responsive | |
48 // client could potentially hang the attach listener thread indefinitely. In that | |
49 // case no new operations would be executed but the VM would continue as normal. | |
50 // As only suitably privileged processes can open this process we concluded that | |
51 // this wasn't worth worrying about. | |
52 | |
53 | |
54 // forward reference | |
55 class Win32AttachOperation; | |
56 | |
57 | |
58 class Win32AttachListener: AllStatic { | |
59 private: | |
60 enum { | |
61 preallocate_count = 4 // number of preallocated operations | |
62 }; | |
63 | |
64 // protects the preallocated list and the operation list | |
65 static HANDLE _mutex; | |
66 | |
67 // head of preallocated operations list | |
68 static Win32AttachOperation* _avail; | |
69 | |
70 // head and tail of enqueue operations list | |
71 static Win32AttachOperation* _head; | |
72 static Win32AttachOperation* _tail; | |
73 | |
74 | |
75 static Win32AttachOperation* head() { return _head; } | |
76 static void set_head(Win32AttachOperation* head) { _head = head; } | |
77 | |
78 static Win32AttachOperation* tail() { return _tail; } | |
79 static void set_tail(Win32AttachOperation* tail) { _tail = tail; } | |
80 | |
81 | |
82 // used to wakeup the listener | |
83 static HANDLE _wakeup; | |
84 static HANDLE wakeup() { return _wakeup; } | |
85 | |
86 public: | |
87 enum { | |
88 ATTACH_ERROR_DISABLED = 100, // error codes | |
89 ATTACH_ERROR_RESOURCE = 101, | |
90 ATTACH_ERROR_ILLEGALARG = 102, | |
91 ATTACH_ERROR_INTERNAL = 103 | |
92 }; | |
93 | |
94 static int init(); | |
95 static HANDLE mutex() { return _mutex; } | |
96 | |
97 static Win32AttachOperation* available() { return _avail; } | |
98 static void set_available(Win32AttachOperation* avail) { _avail = avail; } | |
99 | |
100 // enqueue an operation to the end of the list | |
101 static int enqueue(char* cmd, char* arg1, char* arg2, char* arg3, char* pipename); | |
102 | |
103 // dequeue an operation from from head of the list | |
104 static Win32AttachOperation* dequeue(); | |
105 }; | |
106 | |
107 // statics | |
108 HANDLE Win32AttachListener::_mutex; | |
109 HANDLE Win32AttachListener::_wakeup; | |
110 Win32AttachOperation* Win32AttachListener::_avail; | |
111 Win32AttachOperation* Win32AttachListener::_head; | |
112 Win32AttachOperation* Win32AttachListener::_tail; | |
113 | |
114 | |
115 // Win32AttachOperation is an AttachOperation that additionally encapsulates the name | |
116 // of a pipe which is used to send the operation reply/output to the client. | |
117 // Win32AttachOperation can also be linked in a list. | |
118 | |
119 class Win32AttachOperation: public AttachOperation { | |
120 private: | |
121 friend class Win32AttachListener; | |
122 | |
123 enum { | |
124 pipe_name_max = 256 // maximum pipe name | |
125 }; | |
126 | |
127 char _pipe[pipe_name_max+1]; | |
128 | |
129 const char* pipe() const { return _pipe; } | |
130 void set_pipe(const char* pipe) { | |
131 assert(strlen(pipe) <= pipe_name_max, "execeds maximum length of pipe name"); | |
132 strcpy(_pipe, pipe); | |
133 } | |
134 | |
135 HANDLE open_pipe(); | |
136 static BOOL write_pipe(HANDLE hPipe, char* buf, int len); | |
137 | |
138 Win32AttachOperation* _next; | |
139 | |
140 Win32AttachOperation* next() const { return _next; } | |
141 void set_next(Win32AttachOperation* next) { _next = next; } | |
142 | |
143 // noarg constructor as operation is preallocated | |
144 Win32AttachOperation() : AttachOperation("<noname>") { | |
145 set_pipe("<nopipe>"); | |
146 set_next(NULL); | |
147 } | |
148 | |
149 public: | |
150 void Win32AttachOperation::complete(jint result, bufferedStream* result_stream); | |
151 }; | |
152 | |
153 | |
154 // preallocate the required number of operations | |
155 int Win32AttachListener::init() { | |
156 _mutex = (void*)::CreateMutex(NULL, FALSE, NULL); | |
157 guarantee(_mutex != (HANDLE)NULL, "mutex creation failed"); | |
158 | |
159 _wakeup = ::CreateSemaphore(NULL, 0, 1, NULL); | |
160 guarantee(_wakeup != (HANDLE)NULL, "semaphore creation failed"); | |
161 | |
162 set_head(NULL); | |
163 set_tail(NULL); | |
164 | |
165 // preallocate a few operations | |
166 set_available(NULL); | |
167 for (int i=0; i<preallocate_count; i++) { | |
168 Win32AttachOperation* op = new Win32AttachOperation(); | |
169 op->set_next(available()); | |
170 set_available(op); | |
171 } | |
172 | |
173 return 0; | |
174 } | |
175 | |
176 // Enqueue an operation. This is called from a native thread that is not attached to VM. | |
177 // Also we need to be careful not to execute anything that results in more than a 4k stack. | |
178 // | |
179 int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { | |
180 // listener not running | |
181 if (!AttachListener::is_initialized()) { | |
182 return ATTACH_ERROR_DISABLED; | |
183 } | |
184 | |
185 // check that all paramteres to the operation | |
186 if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG; | |
187 if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; | |
188 if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG; | |
189 if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG; | |
190 | |
191 // check for a well-formed pipename | |
192 if (strstr(pipename, "\\\\.\\pipe\\") != pipename) return ATTACH_ERROR_ILLEGALARG; | |
193 | |
194 // grab the lock for the list | |
195 DWORD res = ::WaitForSingleObject(mutex(), INFINITE); | |
196 if (res != WAIT_OBJECT_0) { | |
197 return ATTACH_ERROR_INTERNAL; | |
198 } | |
199 | |
200 // try to get an operation from the available list | |
201 Win32AttachOperation* op = available(); | |
202 if (op != NULL) { | |
203 set_available(op->next()); | |
204 | |
205 // add to end (tail) of list | |
206 op->set_next(NULL); | |
207 if (tail() == NULL) { | |
208 set_head(op); | |
209 } else { | |
210 tail()->set_next(op); | |
211 } | |
212 set_tail(op); | |
213 | |
214 op->set_name(cmd); | |
215 op->set_arg(0, arg0); | |
216 op->set_arg(1, arg1); | |
217 op->set_arg(2, arg2); | |
218 op->set_pipe(pipename); | |
219 | |
220 // wakeup the thread waiting for operations | |
221 ::ReleaseSemaphore(wakeup(), 1, NULL); | |
222 } | |
223 ::ReleaseMutex(mutex()); | |
224 | |
225 return (op != NULL) ? 0 : ATTACH_ERROR_RESOURCE; | |
226 } | |
227 | |
228 | |
229 // dequeue the operation from the head of the operation list. If | |
230 Win32AttachOperation* Win32AttachListener::dequeue() { | |
231 for (;;) { | |
232 DWORD res = ::WaitForSingleObject(wakeup(), INFINITE); | |
233 guarantee(res == WAIT_OBJECT_0, "wait failed"); | |
234 | |
235 res = ::WaitForSingleObject(mutex(), INFINITE); | |
236 guarantee(res == WAIT_OBJECT_0, "wait failed"); | |
237 | |
238 Win32AttachOperation* op = head(); | |
239 if (op != NULL) { | |
240 set_head(op->next()); | |
241 if (head() == NULL) { // list is empty | |
242 set_tail(NULL); | |
243 } | |
244 } | |
245 ::ReleaseMutex(mutex()); | |
246 | |
247 if (op != NULL) { | |
248 return op; | |
249 } | |
250 } | |
251 } | |
252 | |
253 | |
254 // open the pipe to the client | |
255 HANDLE Win32AttachOperation::open_pipe() { | |
256 HANDLE hPipe; | |
257 | |
258 hPipe = ::CreateFile( pipe(), // pipe name | |
259 GENERIC_WRITE, // write only | |
260 0, // no sharing | |
261 NULL, // default security attributes | |
262 OPEN_EXISTING, // opens existing pipe | |
263 0, // default attributes | |
264 NULL); // no template file | |
265 | |
266 if (hPipe != INVALID_HANDLE_VALUE) { | |
267 // shouldn't happen as there is a pipe created per operation | |
268 if (::GetLastError() == ERROR_PIPE_BUSY) { | |
269 return INVALID_HANDLE_VALUE; | |
270 } | |
271 } | |
272 return hPipe; | |
273 } | |
274 | |
275 // write to the pipe | |
276 BOOL Win32AttachOperation::write_pipe(HANDLE hPipe, char* buf, int len) { | |
277 do { | |
278 DWORD nwrote; | |
279 | |
280 BOOL fSuccess = WriteFile( hPipe, // pipe handle | |
281 (LPCVOID)buf, // message | |
282 (DWORD)len, // message length | |
283 &nwrote, // bytes written | |
284 NULL); // not overlapped | |
285 if (!fSuccess) { | |
286 return fSuccess; | |
287 } | |
288 buf += nwrote; | |
289 len -= nwrote; | |
290 } | |
291 while (len > 0); | |
292 return TRUE; | |
293 } | |
294 | |
295 // Complete the operation: | |
296 // - open the pipe to the client | |
297 // - write the operation result (a jint) | |
298 // - write the operation output (the result stream) | |
299 // | |
300 void Win32AttachOperation::complete(jint result, bufferedStream* result_stream) { | |
301 JavaThread* thread = JavaThread::current(); | |
302 ThreadBlockInVM tbivm(thread); | |
303 | |
304 thread->set_suspend_equivalent(); | |
305 // cleared by handle_special_suspend_equivalent_condition() or | |
306 // java_suspend_self() via check_and_wait_while_suspended() | |
307 | |
308 HANDLE hPipe = open_pipe(); | |
309 if (hPipe != INVALID_HANDLE_VALUE) { | |
310 BOOL fSuccess; | |
311 | |
312 char msg[32]; | |
313 sprintf(msg, "%d\n", result); | |
314 | |
315 fSuccess = write_pipe(hPipe, msg, (int)strlen(msg)); | |
316 if (fSuccess) { | |
317 write_pipe(hPipe, (char*) result_stream->base(), (int)(result_stream->size())); | |
318 } | |
319 | |
320 // Need to flush buffers | |
321 FlushFileBuffers(hPipe); | |
322 CloseHandle(hPipe); | |
323 } | |
324 | |
325 DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE); | |
326 if (res == WAIT_OBJECT_0) { | |
327 | |
328 // put the operation back on the available list | |
329 set_next(Win32AttachListener::available()); | |
330 Win32AttachListener::set_available(this); | |
331 | |
332 ::ReleaseMutex(Win32AttachListener::mutex()); | |
333 } | |
334 | |
335 // were we externally suspended while we were waiting? | |
336 thread->check_and_wait_while_suspended(); | |
337 } | |
338 | |
339 | |
340 // AttachOperation functions | |
341 | |
342 AttachOperation* AttachListener::dequeue() { | |
343 JavaThread* thread = JavaThread::current(); | |
344 ThreadBlockInVM tbivm(thread); | |
345 | |
346 thread->set_suspend_equivalent(); | |
347 // cleared by handle_special_suspend_equivalent_condition() or | |
348 // java_suspend_self() via check_and_wait_while_suspended() | |
349 | |
350 AttachOperation* op = Win32AttachListener::dequeue(); | |
351 | |
352 // were we externally suspended while we were waiting? | |
353 thread->check_and_wait_while_suspended(); | |
354 | |
355 return op; | |
356 } | |
357 | |
358 int AttachListener::pd_init() { | |
359 return Win32AttachListener::init(); | |
360 } | |
361 | |
362 // always startup on Windows NT/2000/XP | |
363 bool AttachListener::init_at_startup() { | |
364 return os::win32::is_nt(); | |
365 } | |
366 | |
367 // no trigger mechanism on Windows to start Attach Listener lazily | |
368 bool AttachListener::is_init_trigger() { | |
369 return false; | |
370 } | |
371 | |
372 void AttachListener::abort() { | |
373 // nothing to do | |
374 } | |
375 | |
376 void AttachListener::pd_data_dump() { | |
377 os::signal_notify(SIGBREAK); | |
378 } | |
379 | |
380 AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { | |
381 return NULL; | |
382 } | |
383 | |
384 jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { | |
385 out->print_cr("flag '%s' cannot be changed", op->arg(0)); | |
386 return JNI_ERR; | |
387 } | |
388 | |
389 void AttachListener::pd_detachall() { | |
390 // do nothing for now | |
391 } | |
392 | |
393 // Native thread started by remote client executes this. | |
394 extern "C" { | |
395 JNIEXPORT jint JNICALL | |
396 JVM_EnqueueOperation(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) { | |
397 return (jint)Win32AttachListener::enqueue(cmd, arg0, arg1, arg2, pipename); | |
398 } | |
399 | |
400 } // extern |