Example #1
0
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
    uv_write_t* req) {
  assert(handle->type == UV_NAMED_PIPE);

  assert(handle->write_queue_size >= req->queued_bytes);
  handle->write_queue_size -= req->queued_bytes;

  if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
    if (req->wait_handle != INVALID_HANDLE_VALUE) {
      UnregisterWait(req->wait_handle);
      req->wait_handle = INVALID_HANDLE_VALUE;
    }
    if (req->event_handle) {
      CloseHandle(req->event_handle);
      req->event_handle = NULL;
    }
  }

  if (req->ipc_header) {
    if (req == &handle->ipc_header_write_req) {
      req->type = UV_UNKNOWN_REQ;
    } else {
      free(req);
    }
  } else {
    if (req->cb) {
      if (!REQ_SUCCESS(req)) {
        uv__set_sys_error(loop, GET_REQ_ERROR(req));
        ((uv_write_cb)req->cb)(req, -1);
      } else {
        ((uv_write_cb)req->cb)(req, 0);
      }
    }
  }

  handle->write_reqs_pending--;

  if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
      handle->non_overlapped_writes_tail) {
    assert(handle->write_reqs_pending > 0);
    uv_queue_non_overlapped_write(handle);
  }

  if (handle->write_reqs_pending == 0) {
    uv_unref(loop);
  }

  if (handle->write_reqs_pending == 0 &&
      handle->flags & UV_HANDLE_SHUTTING) {
    uv_want_endgame(loop, (uv_handle_t*)handle);
  }

  DECREASE_PENDING_REQ_COUNT(handle);
}
Example #2
0
static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
    uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
    uv_stream_t* send_handle, uv_write_cb cb) {
  int result;
  uv_tcp_t* tcp_send_handle;
  uv_write_t* ipc_header_req;
  uv_ipc_frame_uv_stream ipc_frame;

  if (bufcnt != 1 && (bufcnt != 0 || !send_handle)) {
    uv__set_artificial_error(loop, UV_ENOTSUP);
    return -1;
  }

  /* Only TCP handles are supported for sharing. */
  if (send_handle && ((send_handle->type != UV_TCP) ||
      (!(send_handle->flags & UV_HANDLE_BOUND) &&
       !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
    uv__set_artificial_error(loop, UV_ENOTSUP);
    return -1;
  }

  assert(handle->handle != INVALID_HANDLE_VALUE);

  uv_req_init(loop, (uv_req_t*) req);
  req->type = UV_WRITE;
  req->handle = (uv_stream_t*) handle;
  req->cb = cb;
  req->ipc_header = 0;
  req->event_handle = NULL;
  req->wait_handle = INVALID_HANDLE_VALUE;
  memset(&req->overlapped, 0, sizeof(req->overlapped));

  if (handle->ipc) {
    assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
    ipc_frame.header.flags = 0;

    /* Use the IPC framing protocol. */
    if (send_handle) {
      tcp_send_handle = (uv_tcp_t*)send_handle;

      if (uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
          &ipc_frame.socket_info)) {
        return -1;
      }
      ipc_frame.header.flags |= UV_IPC_TCP_SERVER;

      if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
        ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
      }
    }

    if (bufcnt == 1) {
      ipc_frame.header.flags |= UV_IPC_RAW_DATA;
      ipc_frame.header.raw_data_length = bufs[0].len;
    }

    /*
     * Use the provided req if we're only doing a single write.
     * If we're doing multiple writes, use ipc_header_write_req to do
     * the first write, and then use the provided req for the second write.
     */
    if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
      ipc_header_req = req;
    } else {
      /*
       * Try to use the preallocated write req if it's available.
       * Otherwise allocate a new one.
       */
      if (handle->ipc_header_write_req.type != UV_WRITE) {
        ipc_header_req = (uv_write_t*)&handle->ipc_header_write_req;
      } else {
        ipc_header_req = (uv_write_t*)malloc(sizeof(uv_write_t));
        if (!ipc_header_req) {
          uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
        }
      }

      uv_req_init(loop, (uv_req_t*) ipc_header_req);
      ipc_header_req->type = UV_WRITE;
      ipc_header_req->handle = (uv_stream_t*) handle;
      ipc_header_req->cb = NULL;
      ipc_header_req->ipc_header = 1;
    }

    /* Write the header or the whole frame. */
    memset(&ipc_header_req->overlapped, 0, sizeof(ipc_header_req->overlapped));

    result = WriteFile(handle->handle,
                        &ipc_frame,
                        ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
                          sizeof(ipc_frame) : sizeof(ipc_frame.header),
                        NULL,
                        &ipc_header_req->overlapped);
    if (!result && GetLastError() != ERROR_IO_PENDING) {
      uv__set_sys_error(loop, GetLastError());
      return -1;
    }

    if (result) {
      /* Request completed immediately. */
      ipc_header_req->queued_bytes = 0;
    } else {
      /* Request queued by the kernel. */
      ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
        sizeof(ipc_frame) : sizeof(ipc_frame.header);
      handle->write_queue_size += ipc_header_req->queued_bytes;
    }

    REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
    handle->reqs_pending++;
    handle->write_reqs_pending++;

    /* If we don't have any raw data to write - we're done. */
    if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
      return 0;
    }
  }

  if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
    req->write_buffer = bufs[0];
    uv_insert_non_overlapped_write_req(handle, req);
    if (handle->write_reqs_pending == 0) {
      uv_queue_non_overlapped_write(handle);
    }

    /* Request queued by the kernel. */
    req->queued_bytes = uv_count_bufs(bufs, bufcnt);
    handle->write_queue_size += req->queued_bytes;
  } else {
    result = WriteFile(handle->handle,
                       bufs[0].base,
                       bufs[0].len,
                       NULL,
                       &req->overlapped);

    if (!result && GetLastError() != ERROR_IO_PENDING) {
      uv__set_sys_error(loop, GetLastError());
      return -1;
    }

    if (result) {
      /* Request completed immediately. */
      req->queued_bytes = 0;
    } else {
      /* Request queued by the kernel. */
      req->queued_bytes = uv_count_bufs(bufs, bufcnt);
      handle->write_queue_size += req->queued_bytes;
    }

    if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
      req->event_handle = CreateEvent(NULL, 0, 0, NULL);
      if (!req->event_handle) {
        uv_fatal_error(GetLastError(), "CreateEvent");
      }
      if (!RegisterWaitForSingleObject(&req->wait_handle,
          req->overlapped.hEvent, post_completion_write_wait, (void*) req,
          INFINITE, WT_EXECUTEINWAITTHREAD)) {
        uv__set_sys_error(loop, GetLastError());
        return -1;
      }
    }
  }

  REGISTER_HANDLE_REQ(loop, handle, req);
  handle->reqs_pending++;
  handle->write_reqs_pending++;

  return 0;
}