| 
 | 
 
这个巧妙的做法是取得socket底层的afd的句柄,然后将select的调用变成NtDeviceIoControlFile调用,就可以跟iocp进行关联起来了。 
有人可能说这个没有用,这个的用处在于使用第三方库。 
注:在xp,2003平台上无效,具体原因看代码。 
 
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, 
    uv_os_sock_t socket) { 
  WSAPROTOCOL_INFOW protocol_info; 
  int len; 
  SOCKET peer_socket, base_socket; 
  DWORD bytes; 
  DWORD yes = 1; 
 
  /* Set the socket to nonblocking mode */ 
  if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) 
    return uv_translate_sys_error(WSAGetLastError()); 
 
  /* Try to obtain a base handle for the socket. This increases this chances */ 
  /* that we find an AFD handle and are able to use the fast poll mechanism. */ 
  /* This will always fail on windows XP/2k3, since they don't support the */ 
  /* SIO_BASE_HANDLE ioctl. */ 
#ifndef NDEBUG 
  base_socket = INVALID_SOCKET; 
#endif 
 
  if (WSAIoctl(socket, 
               SIO_BASE_HANDLE, 
               NULL, 
               0, 
               &base_socket, 
               sizeof base_socket, 
               &bytes, 
               NULL, 
               NULL) == 0) { 
    assert(base_socket != 0 && base_socket != INVALID_SOCKET); 
    socket = base_socket; 
  } 
 
  uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); 
  handle->socket = socket; 
  handle->events = 0; 
 
  /* Obtain protocol information about the socket. */ 
  len = sizeof protocol_info; 
  if (getsockopt(socket, 
                 SOL_SOCKET, 
                 SO_PROTOCOL_INFOW, 
                 (char*) &protocol_info, 
                 &len) != 0) { 
    return uv_translate_sys_error(WSAGetLastError()); 
  } 
 
  /* Get the peer socket that is needed to enable fast poll. If the returned */ 
  /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ 
  /* to use slow mode. */ 
  peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); 
 
  if (peer_socket != INVALID_SOCKET) { 
    /* Initialize fast poll specific fields. */ 
    handle->peer_socket = peer_socket; 
  } else { 
    /* Initialize slow poll specific fields. */ 
    handle->flags |= UV_HANDLE_POLL_SLOW; 
  } 
 
  /* Initialize 2 poll reqs. */ 
  handle->submitted_events_1 = 0; 
  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); 
  handle->poll_req_1.type = UV_POLL_REQ; 
  handle->poll_req_1.data = handle; 
 
  handle->submitted_events_2 = 0; 
  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); 
  handle->poll_req_2.type = UV_POLL_REQ; 
  handle->poll_req_2.data = handle; 
 
  return 0; 
} 
 
 
 
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { 
  uv_req_t* req; 
  AFD_POLL_INFO* afd_poll_info; 
  DWORD result; 
 
  /* Find a yet unsubmitted req to submit. */ 
  if (handle->submitted_events_1 == 0) { 
    req = &handle->poll_req_1; 
    afd_poll_info = &handle->afd_poll_info_1; 
    handle->submitted_events_1 = handle->events; 
    handle->mask_events_1 = 0; 
    handle->mask_events_2 = handle->events; 
  } else if (handle->submitted_events_2 == 0) { 
    req = &handle->poll_req_2; 
    afd_poll_info = &handle->afd_poll_info_2; 
    handle->submitted_events_2 = handle->events; 
    handle->mask_events_1 = handle->events; 
    handle->mask_events_2 = 0; 
  } else { 
    assert(0); 
    return; 
  } 
 
  /* Setting Exclusive to TRUE makes the other poll request return if there */ 
  /* is any. */ 
  afd_poll_info->Exclusive = TRUE; 
  afd_poll_info->NumberOfHandles = 1; 
  afd_poll_info->Timeout.QuadPart = INT64_MAX; 
  afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; 
  afd_poll_info->Handles[0].Status = 0; 
  afd_poll_info->Handles[0].Events = 0; 
 
  if (handle->events & UV_READABLE) { 
    afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | 
        AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; 
  } 
  if (handle->events & UV_WRITABLE) { 
    afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; 
  } 
 
  memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped); 
 
  result = uv_msafd_poll((SOCKET) handle->peer_socket, 
                         afd_poll_info, 
                         afd_poll_info, 
                         &req->u.io.overlapped); 
  if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { 
    /* Queue this req, reporting an error. */ 
    SET_REQ_ERROR(req, WSAGetLastError()); 
    uv_insert_pending_req(loop, req); 
  } 
} 
 
 
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, 
    AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { 
  IO_STATUS_BLOCK iosb; 
  IO_STATUS_BLOCK* iosb_ptr; 
  HANDLE event = NULL; 
  void* apc_context; 
  NTSTATUS status; 
  DWORD error; 
 
  if (overlapped != NULL) { 
    /* Overlapped operation. */ 
    iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; 
    event = overlapped->hEvent; 
 
    /* Do not report iocp completion if hEvent is tagged. */ 
    if ((uintptr_t) event & 1) { 
      event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); 
      apc_context = NULL; 
    } else { 
      apc_context = overlapped; 
    } 
 
  } else { 
    /* Blocking operation. */ 
    iosb_ptr = &iosb; 
    event = CreateEvent(NULL, FALSE, FALSE, NULL); 
    if (event == NULL) { 
      return SOCKET_ERROR; 
    } 
    apc_context = NULL; 
  } 
 
  iosb_ptr->Status = STATUS_PENDING; 
  status = pNtDeviceIoControlFile((HANDLE) socket, 
                                  event, 
                                  NULL, 
                                  apc_context, 
                                  iosb_ptr, 
                                  IOCTL_AFD_POLL, 
                                  info_in, 
                                  sizeof *info_in, 
                                  info_out, 
                                  sizeof *info_out); 
 
  if (overlapped == NULL) { 
    /* If this is a blocking operation, wait for the event to become */ 
    /* signaled, and then grab the real status from the io status block. */ 
    if (status == STATUS_PENDING) { 
      DWORD r = WaitForSingleObject(event, INFINITE); 
 
      if (r == WAIT_FAILED) { 
        DWORD saved_error = GetLastError(); 
        CloseHandle(event); 
        WSASetLastError(saved_error); 
        return SOCKET_ERROR; 
      } 
 
      status = iosb.Status; 
    } 
 
    CloseHandle(event); 
  } 
 
  switch (status) { 
    case STATUS_SUCCESS: 
      error = ERROR_SUCCESS; 
      break; 
 
    case STATUS_PENDING: 
      error = WSA_IO_PENDING; 
      break; 
 
    default: 
      error = uv_ntstatus_to_winsock_error(status); 
      break; 
  } 
 
  WSASetLastError(error); 
 
  if (error == ERROR_SUCCESS) { 
    return 0; 
  } else { 
    return SOCKET_ERROR; 
  } 
} 
 
 
 |   
 
 
 
 |