// 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;
}
// 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;
}