首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >libcurl异步集成与macOS塞拉利昂上的kevent

libcurl异步集成与macOS塞拉利昂上的kevent
EN

Stack Overflow用户
提问于 2016-11-28 16:03:17
回答 1查看 202关注 0票数 0

我正在将curl集成到基于kqueue的异步I/O事件循环中。

libcurl有一个很好的API来集成到应用程序事件循环中。

您可以为libcurl提供两个回调,一个用于设置计时器(用于限制请求/连接时间),另一个用于为读/写/错误事件注册libcurl的文件描述符。

用于执行FD注册的回调文档如下:SOCKETFUNCTION

通知回调libcurl感兴趣的事件的参数有四个枚举值:

代码语言:javascript
运行
复制
CURL_POLL_IN

Wait for incoming data. For the socket to become readable.

CURL_POLL_OUT

Wait for outgoing data. For the socket to become writable.

CURL_POLL_INOUT

Wait for incoming and outgoing data. For the socket to become readable or writable.

CURL_POLL_REMOVE

The specified socket/file descriptor is no longer used by libcurl.

虽然没有显式记录,但是libcurl希望在随后对回调的调用中,事件循环的筛选状态被更新,以匹配它传递的内容。也就是说,如果在第一次调用时它通过了CURL_POLL_IN (EVFILT_READ),并且在随后的调用中传递了CURL_POLL_OUT (EVFILT_WRITE),那么原始的EVFILT_READ过滤器就会被删除。

我更新了FD注册代码来处理这个问题。

代码语言:javascript
运行
复制
int fr_event_fd_insert(fr_event_list_t *el, int fd,
               fr_event_fd_handler_t read,
               fr_event_fd_handler_t write,
               fr_event_fd_handler_t error,
               void *ctx)
{
    int       filter = 0;
    struct kevent evset[2];
    struct kevent *ev_p = evset;
    fr_event_fd_t *ef, find;

    if (!el) {
        fr_strerror_printf("Invalid argument: NULL event list");
        return -1;
    }

    if (!read && !write) {
        fr_strerror_printf("Invalid arguments: NULL read and write callbacks");
        return -1;
    }

    if (fd < 0) {
        fr_strerror_printf("Invalid arguments: Bad FD %i", fd);
        return -1;
    }

    if (el->exit) {
        fr_strerror_printf("Event loop exiting");
        return -1;
    }

    memset(&find, 0, sizeof(find));

    /*
     *  Get the existing fr_event_fd_t if it exists.
     */
    find.fd = fd;
    ef = rbtree_finddata(el->fds, &find);
    if (!ef) {
        ef = talloc_zero(el, fr_event_fd_t);
        if (!ef) {
            fr_strerror_printf("Out of memory");
            return -1;
        }
        talloc_set_destructor(ef, _fr_event_fd_free);
        el->num_fds++;
        ef->fd = fd;
        rbtree_insert(el->fds, ef);
    /*
     *  Existing filters will be overwritten if there's
     *  a new filter which takes their place.  If there
     *  is no new filter however, we need to delete the
     *  existing one.
     */
    } else {
        if (ef->read && !read) filter |= EVFILT_READ;
        if (ef->write && !write) filter |= EVFILT_WRITE;

        if (filter) {
            EV_SET(ev_p++, ef->fd, filter, EV_DELETE, 0, 0, 0);
            filter = 0;
        }

        /*
         *  I/O handler may delete an event, then
         *  re-add it.  To avoid deleting modified
         *  events we unset the do_delete flag.
         */
        ef->do_delete = false;
    }

    ef->ctx = ctx;

    if (read) {
        ef->read = read;
        filter |= EVFILT_READ;
    }

    if (write) {
        ef->write = write;
        filter |= EVFILT_WRITE;
    }
    ef->error = error;

    EV_SET(ev_p++, fd, filter, EV_ADD | EV_ENABLE, 0, 0, ef);
    if (kevent(el->kq, evset, ev_p - evset, NULL, 0, NULL) < 0) {
        fr_strerror_printf("Failed inserting event for FD %i: %s", fd, fr_syserror(errno));
        talloc_free(ef);
        return -1;
    }
    ef->is_registered = true;

    return 0;
 }

不幸的是,它不起作用。kevent似乎没有删除旧的过滤器(我们继续接收来自它们的通知)。

更奇怪的是,如果我在两个单独的调用中应用这两个操作,它就会完美地工作。

代码语言:javascript
运行
复制
if (filter) {
    EV_SET(&evset, ef->fd, filter, EV_DELETE, 0, 0, 0);
    kevent(el->kq, evset, ev_p - evset, NULL, 0, NULL);
    filter = 0;
}

这是塞拉事件实现中的一个错误,还是我误解了kevent应该如何工作?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-07 23:54:06

这里的问题是,您不能将EVFILT_READEVFILT_WRITE标志组合在一起。

启用或禁用多个筛选器时,需要在多个EV_SET()结构上多次调用evset

上面示例中的非功能代码:

代码语言:javascript
运行
复制
struct kevent evset[2];
struct kevent *ev_p = evset;

if (read) {
    ef->read = read;
    filter |= EVFILT_READ;
}

if (write) {
    ef->write = write;
    filter |= EVFILT_WRITE;
}
ef->error = error;

EV_SET(ev_p++, fd, filter, EV_ADD | EV_ENABLE, 0, 0, ef);
event(el->kq, evset, ev_p - evset, NULL, 0, NULL)

变成:

代码语言:javascript
运行
复制
int count = 0;
struct ev_set[2];

if (read) {
    ef->read = read;
    EV_SET(ev_set[count++], fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, ef);
}

if (write) {
    ef->write = write;
    EV_SET(ev_set[count++], fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, ef);
}
ef->error = error;
kevent(el->kq, ev_set, count, NULL, 0, NULL)

在进行此更改之后,一切都按预期进行了工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40848603

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档