重写 libev 的 EV_WIN32_HANDLE_TO_FD
libev 的 EV_WIN32_HANDLE_TO_FD 默认实现是调用C库的 _open_osfhandle ,但这里有个问题是转换后,关闭 fd 就默认关闭了 handle。当它遇到 libcurl 时就出现了问题。 libcurl handle 的创建和关闭都是 libcurl 来管理的,适配 libev 时只需要简单的映射和反映射、关闭 fd 只取消映射关系不关闭底层 handle。
这里重新实现了 EV_WIN32_HANDLE_TO_FD ,解决了 _open_osfhandle 的限制
ev_win32_handle.h
#pragma once #if defined(_WIN32) && defined(EV_STANDALONE) /* ANFD ev_loop::anfds[anfdmax], that is an array use fd as its index. so we must map win32 socket to [0, FD_SETSIZE). if you can limit mapped fd to be used only in one specified thread, we can use per thread map also--reduce lock and reduce little memory. */ #ifdef __cplusplus extern "C" { #endif int OpenFd(SOCKET h); SOCKET GetHandle(int fd); int CloseFd(int fd, int close_handle); #define EV_FD_TO_WIN32_HANDLE(fd) GetHandle(fd) #define EV_WIN32_HANDLE_TO_FD(handle) OpenFd(handle) #define EV_WIN32_CLOSE_FD(fd) CloseFd(fd, 1) #ifdef __cplusplus } #endif #endif
ev_win32_handle.cpp
#if defined(_WIN32) && defined(EV_STANDALONE) #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <windows.h> #include <assert.h> #include <mutex> // std::call_once, std::once_flag #include "ev_win32_handle.h" typedef struct vfd_entry_t { SOCKET handle; /* OS handle, i.e. SOCKET */ //int fd; /* fd */ vfd_entry_t *next; /* Next free fd, -1 if last */ } vfd_entry; vfd_entry vfds[FD_SETSIZE] = {}; vfd_entry *vfd_free = NULL; std::once_flag vfds_init_flag; std::mutex vfds_mutex; void InitFd() { vfd_entry *pre = NULL; for (int idx = FD_SETSIZE - 1; idx >= 0; --idx) { vfds[idx].handle = /*INVALID_HANDLE_VALUE;*/INVALID_SOCKET; //vfds[idx].fd = idx; vfds[idx].next = pre; pre = &vfds[idx]; } vfd_free = pre; } int OpenFd(SOCKET h) { std::call_once(vfds_init_flag, InitFd); std::lock_guard<std::mutex> lck (vfds_mutex); int fd = -1; if (vfd_free) { vfd_entry *next = vfd_free->next; vfd_free->handle = h; vfd_free->next = NULL; //fd = vfd_free->fd; fd = vfd_free - vfds; vfd_free = next; } assert(fd >= 0 && fd < FD_SETSIZE); return fd; } SOCKET GetHandle(int fd) { assert(fd >= 0 && fd < FD_SETSIZE); return vfds[fd].handle; } extern int CloseFd(int fd, int close_handle /*= 0*/) { assert(fd >= 0 && fd < FD_SETSIZE); if (close_handle) { assert(vfds[fd].next == NULL); closesocket(vfds[fd].handle); } std::lock_guard<std::mutex> lck (vfds_mutex); vfds[fd].handle = /*INVALID_HANDLE_VALUE;*/INVALID_SOCKET; vfds[fd].next = vfd_free; vfd_free = &vfds[fd]; return 0; } #endif
libev 整合 libcurl 使用可以参考 libcurl 的官方样例 http://curl.haxx.se/libcurl/c/evhiperfifo.html
自定义 libev 的映射,也可以参考 python 的 gevent 库