// Preallocate the maximum number of operations that can be enqueued.
int Win32AttachListener::init() {
  _mutex = (void*)::CreateMutex(NULL, FALSE, NULL);
  guarantee(_mutex != (HANDLE)NULL, "mutex creation failed");

  _enqueued_ops_semaphore = ::CreateSemaphore(NULL, 0, max_enqueued_operations, NULL);
  guarantee(_enqueued_ops_semaphore != (HANDLE)NULL, "semaphore creation failed");

  set_head(NULL);
  set_tail(NULL);
  set_available(NULL);

  for (int i=0; i<max_enqueued_operations; i++) {
    Win32AttachOperation* op = new Win32AttachOperation();
    op->set_next(available());
    set_available(op);
  }

  return 0;
}
// preallocate the required number of operations
int Win32AttachListener::init() {
  _mutex = (void*)::CreateMutex(NULL, FALSE, NULL);
  guarantee(_mutex != (HANDLE)NULL, "mutex creation failed");

  _wakeup = ::CreateSemaphore(NULL, 0, 1, NULL);
  guarantee(_wakeup != (HANDLE)NULL, "semaphore creation failed");

  set_head(NULL);
  set_tail(NULL);

  // preallocate a few operations
  set_available(NULL);
  for (int i=0; i<preallocate_count; i++) {
    Win32AttachOperation* op = new Win32AttachOperation();
    op->set_next(available());
    set_available(op);
  }

  return 0;
}
// dequeue the operation from the head of the operation list. If
Win32AttachOperation* Win32AttachListener::dequeue() {
  for (;;) {
    DWORD res = ::WaitForSingleObject(wakeup(), INFINITE);
    guarantee(res == WAIT_OBJECT_0, "wait failed");

    res = ::WaitForSingleObject(mutex(), INFINITE);
    guarantee(res == WAIT_OBJECT_0, "wait failed");

    Win32AttachOperation* op = head();
    if (op != NULL) {
      set_head(op->next());
      if (head() == NULL) {     // list is empty
        set_tail(NULL);
      }
    }
    ::ReleaseMutex(mutex());

    if (op != NULL) {
      return op;
    }
  }
}
// Enqueue an operation. This is called from a native thread that is not attached to VM.
// Also we need to be careful not to execute anything that results in more than a 4k stack.
//
int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) {
  // listener not running
  if (!AttachListener::is_initialized()) {
    return ATTACH_ERROR_DISABLED;
  }

  // check that all paramteres to the operation
  if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(arg1) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(arg2) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG;

  // check for a well-formed pipename
  if (strstr(pipename, "\\\\.\\pipe\\") != pipename) return ATTACH_ERROR_ILLEGALARG;

  // grab the lock for the list
  DWORD res = ::WaitForSingleObject(mutex(), INFINITE);
  if (res != WAIT_OBJECT_0) {
    return ATTACH_ERROR_INTERNAL;
  }

  // try to get an operation from the available list
  Win32AttachOperation* op = available();
  if (op != NULL) {
    set_available(op->next());

    // add to end (tail) of list
    op->set_next(NULL);
    if (tail() == NULL) {
      set_head(op);
    } else {
      tail()->set_next(op);
    }
    set_tail(op);

    op->set_name(cmd);
    op->set_arg(0, arg0);
    op->set_arg(1, arg1);
    op->set_arg(2, arg2);
    op->set_pipe(pipename);

    // Increment number of enqueued operations.
    // Side effect: Semaphore will be signaled and will release
    // any blocking waiters (i.e. the AttachListener thread).
    BOOL not_exceeding_semaphore_maximum_count =
      ::ReleaseSemaphore(enqueued_ops_semaphore(), 1, NULL);
    guarantee(not_exceeding_semaphore_maximum_count, "invariant");
  }
  ::ReleaseMutex(mutex());

  return (op != NULL) ? 0 : ATTACH_ERROR_RESOURCE;
}
// dequeue the operation from the head of the operation list.
Win32AttachOperation* Win32AttachListener::dequeue() {
  for (;;) {
    DWORD res = ::WaitForSingleObject(enqueued_ops_semaphore(), INFINITE);
    // returning from WaitForSingleObject will have decreased
    // the current count of the semaphore by 1.
    guarantee(res == WAIT_OBJECT_0, "wait failed");

    res = ::WaitForSingleObject(mutex(), INFINITE);
    guarantee(res == WAIT_OBJECT_0, "wait failed");

    Win32AttachOperation* op = head();
    if (op != NULL) {
      set_head(op->next());
      if (head() == NULL) {     // list is empty
        set_tail(NULL);
      }
    }
    ::ReleaseMutex(mutex());

    if (op != NULL) {
      return op;
    }
  }
}
// Enqueue an operation. This is called from a native thread that is not attached to VM.
// Also we need to be careful not to execute anything that results in more than a 4k stack.
//
int Win32AttachListener::enqueue(char* cmd, char* arg0, char* arg1, char* arg2, char* pipename) {
  // listener not running
  if (!AttachListener::is_initialized()) {
    return ATTACH_ERROR_DISABLED;
  }

  // check that all paramteres to the operation
  if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
  if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG;

  // check for a well-formed pipename
  if (strstr(pipename, "\\\\.\\pipe\\") != pipename) return ATTACH_ERROR_ILLEGALARG;

  // grab the lock for the list
  DWORD res = ::WaitForSingleObject(mutex(), INFINITE);
  if (res != WAIT_OBJECT_0) {
    return ATTACH_ERROR_INTERNAL;
  }

  // try to get an operation from the available list
  Win32AttachOperation* op = available();
  if (op != NULL) {
    set_available(op->next());

    // add to end (tail) of list
    op->set_next(NULL);
    if (tail() == NULL) {
      set_head(op);
    } else {
      tail()->set_next(op);
    }
    set_tail(op);

    op->set_name(cmd);
    op->set_arg(0, arg0);
    op->set_arg(1, arg1);
    op->set_arg(2, arg2);
    op->set_pipe(pipename);

    // wakeup the thread waiting for operations
    ::ReleaseSemaphore(wakeup(), 1, NULL);
  }
  ::ReleaseMutex(mutex());

  return (op != NULL) ? 0 : ATTACH_ERROR_RESOURCE;
}