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