Пример #1
0
static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
  int result;
  DWORD bytes;
  uv_write_t* req = (uv_write_t*) parameter;
  uv_pipe_t* handle = (uv_pipe_t*) req->handle;
  uv_loop_t* loop = handle->loop;

  assert(req != NULL);
  assert(req->type == UV_WRITE);
  assert(handle->type == UV_NAMED_PIPE);
  assert(req->write_buffer.base);

  result = WriteFile(handle->handle,
                     req->write_buffer.base,
                     req->write_buffer.len,
                     &bytes,
                     NULL);

  if (!result) {
    SET_REQ_ERROR(req, GetLastError());
  }

  POST_COMPLETION_FOR_REQ(loop, req);
  return 0;
}
Пример #2
0
/*
 * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
 * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
 * no active signal watchers observing this signal.
 */
int uv__signal_dispatch(int signum) {
  uv_signal_t lookup;
  uv_signal_t* handle;
  int dispatched = 0;

  EnterCriticalSection(&uv__signal_lock);

  lookup.signum = signum;
  lookup.loop = NULL;

  for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
       handle != NULL && handle->signum == signum;
       handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
    unsigned long previous = InterlockedExchange(&handle->pending_signum, signum);

    if (!previous) {
      POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
    }

    dispatched = 1;
  }

  LeaveCriticalSection(&uv__signal_lock);

  return dispatched;
}
Пример #3
0
/*
 * Called on windows thread pool when CreateProcess failed. It writes an error
 * message to the process' intended stderr and then posts a PROCESS_EXIT
 * packet to the completion port.
 */
static DWORD WINAPI spawn_failure(void* data) {
  char syscall[] = "CreateProcessW: ";
  char unknown[] = "unknown error\n";
  uv_process_t* process = (uv_process_t*) data;
  uv_loop_t* loop = process->loop;
  HANDLE child_stderr = process->child_stdio[2];
  char* buf = NULL;
  DWORD count, written;

  WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);

  count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                         FORMAT_MESSAGE_FROM_SYSTEM |
                         FORMAT_MESSAGE_IGNORE_INSERTS,
                         NULL,
                         process->spawn_errno,
                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                         (LPSTR) &buf,
                         0,
                         NULL);

  if (buf != NULL && count > 0) {
    WriteFile(child_stderr, buf, count, &written, NULL);
    LocalFree(buf);
  } else {
    WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
  }

  FlushFileBuffers(child_stderr);

  /* Post completed */
  POST_COMPLETION_FOR_REQ(loop, &process->exit_req);

  return 0;
}
Пример #4
0
/*
 * Called on Windows thread-pool thread to indicate that
 * UnregisterWaitEx has completed.
 */
static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
  uv_process_t* process = (uv_process_t*)data;

  assert(didTimeout == FALSE);
  assert(process);

  /* Post completed */
  POST_COMPLETION_FOR_REQ(&process->close_req);
}
Пример #5
0
/*
 * Called on Windows thread-pool thread to indicate that
 * a child process has exited.
 */
static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
  uv_process_t* process = (uv_process_t*)data;
  uv_loop_t* loop = process->loop;

  assert(didTimeout == FALSE);
  assert(process);

  /* Post completed */
  POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
}
Пример #6
0
int uv_async_send(uv_async_t* handle) {
  /* First do a cheap read. */
  if (handle->async_sent != 0)
    return 0;

  if (InterlockedExchange(&handle->async_sent, 1) == 0) {
    uv_loop_t* loop = handle->loop;
    POST_COMPLETION_FOR_REQ(loop, &loop->async_req);
  }

  return 0;
}
Пример #7
0
static DWORD WINAPI uv_work_thread_proc(void* parameter) {
  uv_work_t* req = (uv_work_t*)parameter;
  uv_loop_t* loop = req->loop;

  assert(req != NULL);
  assert(req->type == UV_WORK);
  assert(req->work_cb);

  req->work_cb(req);

  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #8
0
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
  HANDLE pipeHandle = INVALID_HANDLE_VALUE;
  int errno;
  uv_loop_t* loop;
  uv_pipe_t* handle;
  uv_connect_t* req;

  req = (uv_connect_t*) parameter;
  assert(req);
  handle = (uv_pipe_t*) req->handle;
  assert(handle);
  loop = handle->loop;
  assert(loop);

  /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
  /* We wait for the pipe to become available with WaitNamedPipe. */
  while (WaitNamedPipeW(handle->name, 30000)) {
    /* The pipe is now available, try to connect. */
    pipeHandle = CreateFileW(handle->name,
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_OVERLAPPED,
                            NULL);

    if (pipeHandle != INVALID_HANDLE_VALUE) {
      break;
    }

    SwitchToThread();
  }

  if (pipeHandle != INVALID_HANDLE_VALUE &&
      !uv_set_pipe_handle(loop, handle, pipeHandle)) {
    handle->handle = pipeHandle;
    SET_REQ_SUCCESS(req);
  } else {
    SET_REQ_ERROR(req, GetLastError());
  }

  /* Post completed */
  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #9
0
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
  int errno;
  uv_pipe_t* handle;
  uv_shutdown_t* req;

  req = (uv_shutdown_t*) parameter;
  assert(req);
  handle = (uv_pipe_t*) req->handle;
  assert(handle);

  FlushFileBuffers(handle->handle);

  /* Post completed */
  POST_COMPLETION_FOR_REQ(req);

  return 0;
}
Пример #10
0
/* thread pool callback when socket is signalled */
static void CALLBACK uv_ares_socksignal_tp(void* parameter,
    BOOLEAN timerfired) {
  WSANETWORKEVENTS network_events;
  uv_ares_task_t* sockhandle;
  uv_ares_action_t* selhandle;
  uv_req_t* uv_ares_req;
  uv_loop_t* loop;

  assert(parameter != NULL);

  if (parameter != NULL) {
    sockhandle = (uv_ares_task_t*) parameter;
    loop = sockhandle->loop;

    /* clear socket status for this event */
    /* do not fail if error, thread may run after socket close */
    /* The code assumes that c-ares will write all pending data in the */
    /* callback, unless the socket would block. We can clear the state here */
    /* to avoid unnecessary signals. */
    WSAEnumNetworkEvents(sockhandle->sock,
                         sockhandle->h_event,
                         &network_events);

    /* setup new handle */
    selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t));
    if (selhandle == NULL) {
      uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
    }
    selhandle->type = UV_ARES_EVENT;
    selhandle->close_cb = NULL;
    selhandle->data = sockhandle->data;
    selhandle->sock = sockhandle->sock;
    selhandle->read =
        (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0;
    selhandle->write =
        (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0;

    uv_ares_req = &selhandle->ares_req;
    uv_req_init(loop, uv_ares_req);
    uv_ares_req->type = UV_ARES_EVENT_REQ;
    uv_ares_req->data = selhandle;

    /* post ares needs to called */
    POST_COMPLETION_FOR_REQ(loop, uv_ares_req);
  }
}
Пример #11
0
Файл: tty.c Проект: hghazal/node
static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
  uv_loop_t* loop;
  uv_tty_t* handle;
  uv_req_t* req;

  assert(data);
  assert(!didTimeout);

  req = (uv_req_t*) data;
  handle = (uv_tty_t*) req->data;
  loop = handle->loop;

  UnregisterWait(handle->read_raw_wait);
  handle->read_raw_wait = NULL;

  SET_REQ_SUCCESS(req);
  POST_COMPLETION_FOR_REQ(loop, req);
}
Пример #12
0
int uv_async_send(uv_async_t* handle) {
  uv_loop_t* loop = handle->loop;

  if (handle->type != UV_ASYNC) {
    /* Can't set errno because that's not thread-safe. */
    return -1;
  }

  /* The user should make sure never to call uv_async_send to a closing */
  /* or closed handle. */
  assert(!(handle->flags & UV__HANDLE_CLOSING));

  if (!uv__atomic_exchange_set(&handle->async_sent)) {
    POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
  }

  return 0;
}
Пример #13
0
/* getaddrinfo worker thread implementation */
static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
  uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter;
  uv_loop_t* loop = req->loop;
  int ret;

  assert(req != NULL);

  /* call OS function on this thread */
  ret = GetAddrInfoW(req->node,
                     req->service,
                     req->hints,
                     &req->res);
  req->retcode = ret;

  /* post getaddrinfo completed */
  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #14
0
/* getnameinfo worker thread implementation */
static DWORD WINAPI getnameinfo_thread_proc(void* parameter) {
  uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter;
  uv_loop_t* loop = req->loop;
  WCHAR host[NI_MAXHOST];
  WCHAR service[NI_MAXSERV];
  int ret = 0;

  assert(req != NULL);

  ret = GetNameInfoW((struct sockaddr*)&req->storage,
                     sizeof(req->storage),
                     host,
                     sizeof(host),
                     service,
                     sizeof(service),
                     req->flags);
  req->retcode = uv__getaddrinfo_translate_error(ret);

  /* convert results to UTF-8 */
  WideCharToMultiByte(CP_UTF8,
                      0,
                      host,
                      -1,
                      req->host,
                      sizeof(req->host),
                      NULL,
                      NULL);

  WideCharToMultiByte(CP_UTF8,
                      0,
                      service,
                      -1,
                      req->service,
                      sizeof(req->service),
                      NULL,
                      NULL);

  /* post getnameinfo completed */
  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #15
0
/* getaddrinfo worker thread implementation */
static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
  uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*) parameter;
  uv_loop_t* loop = handle->loop;
  int ret;

  assert(handle != NULL);

  if (handle != NULL) {
    /* call OS function on this thread */
    ret = GetAddrInfoW(handle->node,
                       handle->service,
                       handle->hints,
                       &handle->res);
    handle->retcode = ret;

    /* post getaddrinfo completed */
    POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req);
  }

  return 0;
}
Пример #16
0
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
  uv_loop_t* loop;
  uv_pipe_t* handle;
  uv_connect_t* req;
  HANDLE pipeHandle = INVALID_HANDLE_VALUE;
  DWORD duplex_flags;

  req = (uv_connect_t*) parameter;
  assert(req);
  handle = (uv_pipe_t*) req->handle;
  assert(handle);
  loop = handle->loop;
  assert(loop);

  /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
  /* We wait for the pipe to become available with WaitNamedPipe. */
  while (WaitNamedPipeW(handle->name, 30000)) {
    /* The pipe is now available, try to connect. */
    pipeHandle = open_named_pipe(handle->name, &duplex_flags);
    if (pipeHandle != INVALID_HANDLE_VALUE) {
      break;
    }

    SwitchToThread();
  }

  if (pipeHandle != INVALID_HANDLE_VALUE &&
      !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) {
    SET_REQ_SUCCESS(req);
  } else {
    SET_REQ_ERROR(req, GetLastError());
  }

  /* Post completed */
  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #17
0
Файл: tty.c Проект: hghazal/node
static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
  uv_loop_t* loop;
  uv_tty_t* handle;
  uv_req_t* req;
  DWORD bytes, read_bytes;

  assert(data);

  req = (uv_req_t*) data;
  handle = (uv_tty_t*) req->data;
  loop = handle->loop;

  assert(handle->read_line_buffer.base != NULL);
  assert(handle->read_line_buffer.len > 0);

  /* ReadConsole can't handle big buffers. */
  if (handle->read_line_buffer.len < 8192) {
    bytes = handle->read_line_buffer.len;
  } else {
    bytes = 8192;
  }

  /* Todo: Unicode */
  if (ReadConsoleA(handle->read_line_handle,
                   (void*) handle->read_line_buffer.base,
                   bytes,
                   &read_bytes,
                   NULL)) {
    SET_REQ_SUCCESS(req);
    req->overlapped.InternalHigh = read_bytes;
  } else {
    SET_REQ_ERROR(req, GetLastError());
  }

  POST_COMPLETION_FOR_REQ(loop, req);
  return 0;
}
Пример #18
0
/* called via uv_poll when ares is finished with socket */
void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle,
    uv_req_t* req) {
  /* check for event complete without waiting */
  unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0);

  if (signaled != WAIT_TIMEOUT) {
    uv_unref(loop);

    /* close event handle and free uv handle memory */
    CloseHandle(handle->h_close_event);
    free(handle);

    /* decrement active count. if it becomes 0 stop polling */
    if (loop->ares_active_sockets > 0) {
      loop->ares_active_sockets--;
      if (loop->ares_active_sockets == 0) {
        uv_close((uv_handle_t*) &loop->ares_polling_timer, NULL);
      }
    }
  } else {
    /* still busy - repost and try again */
    POST_COMPLETION_FOR_REQ(loop, req);
  }
}
Пример #19
0
static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
  int result;
  DWORD bytes;
  uv_read_t* req = (uv_read_t*) parameter;
  uv_pipe_t* handle = (uv_pipe_t*) req->data;
  uv_loop_t* loop = handle->loop;

  assert(req != NULL);
  assert(req->type == UV_READ);
  assert(handle->type == UV_NAMED_PIPE);

  result = ReadFile(handle->handle,
                    &uv_zero_,
                    0,
                    &bytes,
                    NULL);

  if (!result) {
    SET_REQ_ERROR(req, GetLastError());
  }

  POST_COMPLETION_FOR_REQ(loop, req);
  return 0;
}
Пример #20
0
/* callback from ares when socket operation is started */
static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
    int write) {
  /* look to see if we have a handle for this socket in our list */
  uv_loop_t* loop = (uv_loop_t*) data;
  uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock);

  if (read == 0 && write == 0) {
    /* if read and write are 0, cleanup existing data */
    /* The code assumes that c-ares does a callback with read = 0 and */
    /* write = 0 when the socket is closed. After we receive this we stop */
    /* monitoring the socket. */
    if (uv_handle_ares != NULL) {
      uv_req_t* uv_ares_req;

      uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL);
      /* remove Wait */
      if (uv_handle_ares->h_wait) {
        UnregisterWaitEx(uv_handle_ares->h_wait,
                         uv_handle_ares->h_close_event);
        uv_handle_ares->h_wait = NULL;
      }

      /* detach socket from the event */
      WSAEventSelect(sock, NULL, 0);
      if (uv_handle_ares->h_event != WSA_INVALID_EVENT) {
        WSACloseEvent(uv_handle_ares->h_event);
        uv_handle_ares->h_event = WSA_INVALID_EVENT;
      }
      /* remove handle from list */
      uv_remove_ares_handle(uv_handle_ares);

      /* Post request to cleanup the Task */
      uv_ares_req = &uv_handle_ares->ares_req;
      uv_req_init(loop, uv_ares_req);
      uv_ares_req->type = UV_ARES_CLEANUP_REQ;
      uv_ares_req->data = uv_handle_ares;

      /* post ares done with socket - finish cleanup when all threads done. */
      POST_COMPLETION_FOR_REQ(loop, uv_ares_req);
    } else {
      assert(0);
      uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB");
    }
  } else {
    if (uv_handle_ares == NULL) {
      /* setup new handle */
      /* The code assumes that c-ares will call us when it has an open socket.
        We need to call into c-ares when there is something to read,
        or when it becomes writable. */
      uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t));
      if (uv_handle_ares == NULL) {
        uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
      }
      uv_handle_ares->type = UV_ARES_TASK;
      uv_handle_ares->close_cb = NULL;
      uv_handle_ares->loop = loop;
      uv_handle_ares->data = loop;
      uv_handle_ares->sock = sock;
      uv_handle_ares->h_wait = NULL;
      uv_handle_ares->flags = 0;

      /* create an event to wait on socket signal */
      uv_handle_ares->h_event = WSACreateEvent();
      if (uv_handle_ares->h_event == WSA_INVALID_EVENT) {
        uv_fatal_error(WSAGetLastError(), "WSACreateEvent");
      }

      /* tie event to socket */
      if (SOCKET_ERROR == WSAEventSelect(sock,
                                         uv_handle_ares->h_event,
                                         FD_READ | FD_WRITE | FD_CONNECT)) {
        uv_fatal_error(WSAGetLastError(), "WSAEventSelect");
      }

      /* add handle to list */
      uv_add_ares_handle(loop, uv_handle_ares);
      uv_ref(loop);

      /*
       * we have a single polling timer for all ares sockets.
       * This is preferred to using ares_timeout. See ares_timeout.c warning.
       * if timer is not running start it, and keep socket count
       */
      if (loop->ares_active_sockets == 0) {
        uv_timer_init(loop, &loop->ares_polling_timer);
        uv_timer_start(&loop->ares_polling_timer, uv_ares_poll, 1000L, 1000L);
      }
      loop->ares_active_sockets++;

      /* specify thread pool function to call when event is signaled */
      if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait,
                                  uv_handle_ares->h_event,
                                  uv_ares_socksignal_tp,
                                  (void*)uv_handle_ares,
                                  INFINITE,
                                  WT_EXECUTEINWAITTHREAD) == 0) {
        uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
      }
    } else {
      /* found existing handle.  */
      assert(uv_handle_ares->type == UV_ARES_TASK);
      assert(uv_handle_ares->data != NULL);
      assert(uv_handle_ares->h_event != WSA_INVALID_EVENT);
    }
  }
}
Пример #21
0
Файл: fs.c Проект: Cahya/node
static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
  uv_fs_t* req = (uv_fs_t*) parameter;
  uv_loop_t* loop = req->loop;

  assert(req != NULL);
  assert(req->type == UV_FS);

  switch (req->fs_type) {
    case UV_FS_OPEN:
      fs__open(req, req->path, (int)req->arg0, (int)req->arg1);
      break;
    case UV_FS_CLOSE:
      fs__close(req, (uv_file)req->arg0);
      break;
    case UV_FS_READ:
      fs__read(req,
               (uv_file) req->arg0,
               req->arg1,
               (size_t) req->arg2,
               (off_t) req->arg3);
      break;
    case UV_FS_WRITE:
      fs__write(req,
                (uv_file)req->arg0,
                req->arg1,
                (size_t) req->arg2,
                (off_t) req->arg3);
      break;
    case UV_FS_UNLINK:
      fs__unlink(req, req->path);
      break;
    case UV_FS_MKDIR:
      fs__mkdir(req, req->path, (int)req->arg0);
      break;
    case UV_FS_RMDIR:
      fs__rmdir(req, req->path);
      break;
    case UV_FS_READDIR:
      fs__readdir(req, req->path, (int)req->arg0);
      break;
    case UV_FS_STAT:
    case UV_FS_LSTAT:
      fs__stat(req, req->path);
      break;
    case UV_FS_FSTAT:
      fs__fstat(req, (uv_file)req->arg0);
      break;
    case UV_FS_RENAME:
      fs__rename(req, req->path, (const char*)req->arg0);
      break;
    case UV_FS_FSYNC:
    case UV_FS_FDATASYNC:
      fs__fsync(req, (uv_file)req->arg0);
      break;
    case UV_FS_FTRUNCATE:
      fs__ftruncate(req, (uv_file)req->arg0, (off_t)req->arg1);
      break;
    case UV_FS_SENDFILE:
      fs__sendfile(req,
        (uv_file) req->arg0,
        (uv_file) req->arg1,
        (off_t) req->arg2,
        (size_t) req->arg3);
      break;
    case UV_FS_CHMOD:
      fs__chmod(req, req->path, (int)req->arg0);
      break;
    case UV_FS_FCHMOD:
      fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1);
      break;
    case UV_FS_UTIME:
      fs__utime(req, req->path, req->arg4, req->arg5);
      break;
    case UV_FS_FUTIME:
      fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5);
      break;
    case UV_FS_LINK:
      fs__link(req, req->path, (const char*)req->arg0);
      break;
    case UV_FS_SYMLINK:
      fs__symlink(req, req->path, (const char*)req->arg0, (int)req->arg1);
      break;
    case UV_FS_READLINK:
      fs__readlink(req, req->path);
      break;
    case UV_FS_CHOWN:
    case UV_FS_FCHOWN:
      fs__nop(req);
      break;
    default:
      assert(!"bad uv_fs_type");
  }

  POST_COMPLETION_FOR_REQ(loop, req);

  return 0;
}
Пример #22
0
static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
    uv_req_t* req = (uv_req_t*) arg;
    uv_poll_t* handle = (uv_poll_t*) req->data;
    unsigned char events, reported_events;
    int r;
    uv_single_fd_set_t rfds, wfds, efds;
    struct timeval timeout;

    assert(handle->type == UV_POLL);
    assert(req->type == UV_POLL_REQ);

    if (req == &handle->poll_req_1) {
        events = handle->submitted_events_1;
    } else if (req == &handle->poll_req_2) {
        events = handle->submitted_events_2;
    } else {
        assert(0);
    }

    if (handle->events & UV_READABLE) {
        rfds.fd_count = 1;
        rfds.fd_array[0] = handle->socket;
    } else {
        rfds.fd_count = 0;
    }

    if (handle->events & UV_WRITABLE) {
        wfds.fd_count = 1;
        wfds.fd_array[0] = handle->socket;
        efds.fd_count = 1;
        efds.fd_array[0] = handle->socket;
    } else {
        wfds.fd_count = 0;
        efds.fd_count = 0;
    }

    /* Make the select() time out after 3 minutes. If select() hangs because */
    /* the user closed the socket, we will at least not hang indefinitely. */
    timeout.tv_sec = 3 * 60;
    timeout.tv_usec = 0;

    r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
    if (r == SOCKET_ERROR) {
        /* Queue this req, reporting an error. */
        SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
        POST_COMPLETION_FOR_REQ(handle->loop, req);
        return 0;
    }

    reported_events = 0;

    if (r > 0) {
        if (rfds.fd_count > 0) {
            assert(rfds.fd_count == 1);
            assert(rfds.fd_array[0] == handle->socket);
            reported_events |= UV_READABLE;
        }

        if (wfds.fd_count > 0) {
            assert(wfds.fd_count == 1);
            assert(wfds.fd_array[0] == handle->socket);
            reported_events |= UV_WRITABLE;
        } else if (efds.fd_count > 0) {
            assert(efds.fd_count == 1);
            assert(efds.fd_array[0] == handle->socket);
            reported_events |= UV_WRITABLE;
        }
    }

    SET_REQ_SUCCESS(req);
    req->overlapped.InternalHigh = (DWORD) reported_events;
    POST_COMPLETION_FOR_REQ(handle->loop, req);

    return 0;
}