重写 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 库

原文地址:https://www.cnblogs.com/JesseFang/p/4682305.html