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