Knowing all callbacks have run with libevent and bufferevent_free

时间:2015-07-28 23:15:24

标签: ios c sockets libevent

I'm doing some work with libevent, version 2.0.22, and I'm struggling with dealing with bufferevent_free and making sure sockets close at the right time. This is within an iOS app built with Xcode 6.4, running on iOS 8.4.

Each socket is managed by a struct bufferevent, and I also have a data structure which keeps track of application state for that socket:

bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_socket_connect_hostname(bev, dns_base, AF_UNSPEC, host, port_number);
struct stream_data *data = malloc(sizeof(struct stream_data));
/* initialize stream data here */
bufferevent_setcb(bev, read_cb, write_cb, event_cb, data);

In a callback from some other buffer socket, I decide I don't need the buffer I just tried to open. This happens before I get the connected callback on the bev in question. Because I created it with BEV_OPT_CLOSE_ON_FREE, I just free it. Then I delete the data structure I'm using. Looks like this:

bufferevent_free(bev);
free(stream_data); // the data corresponding to that bev

In this case, though, the socket actually finished connecting in the meantime. So my event callback fires:

void event_cb(struct bufferevent *bev, short what, void *ctx)
{
    struct stream_data *data = ctx;
    // data now points to already freed memory
}

And now I've got a pointer to already freed memory. I've confirmed with debugger breakpoints, NSLog, etc that the event callback is firing after the free above.

Is this expected behavior? If so, how can I ever tell that a bufferevent I freed is well and truly gone, making it safe to remove my own data structures?

1 个答案:

答案 0 :(得分:1)

是的,这是预期的libevent行为:在bufferevent_free()之后它仍然可以调用你的回调。来自libevent书:

  

Bufferevents是内部引用计数的,因此如果bufferevent在释放时有挂起的延迟回调,则在回调完成之前不会删除它。

最简单的解决方案是在释放bufferevent对象之前删除所有回调:

bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
bufferevent_free(bev);