struct bufferevent * bufferevent_async_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_async *bev_a; struct bufferevent *bev; struct event_iocp_port *iocp; options |= BEV_OPT_THREADSAFE; if (!(iocp = event_base_get_iocp(base))) return NULL; if (fd >= 0 && event_iocp_port_associate(iocp, fd, 1)<0) { int err = GetLastError(); /* We may have alrady associated this fd with a port. * Let's hope it's this port, and that the error code * for doing this neer changes. */ if (err != ERROR_INVALID_PARAMETER) return NULL; } if (!(bev_a = mm_calloc(1, sizeof(struct bufferevent_async)))) return NULL; bev = &bev_a->bev.bev; if (!(bev->input = evbuffer_overlapped_new(fd))) { mm_free(bev_a); return NULL; } if (!(bev->output = evbuffer_overlapped_new(fd))) { evbuffer_free(bev->input); mm_free(bev_a); return NULL; } if (bufferevent_init_common(&bev_a->bev, base, &bufferevent_ops_async, options)<0) goto err; evbuffer_add_cb(bev->input, be_async_inbuf_callback, bev); evbuffer_add_cb(bev->output, be_async_outbuf_callback, bev); event_overlapped_init(&bev_a->connect_overlapped, connect_complete); event_overlapped_init(&bev_a->read_overlapped, read_complete); event_overlapped_init(&bev_a->write_overlapped, write_complete); bev_a->ok = fd >= 0; if (bev_a->ok) _bufferevent_init_generic_timeout_cbs(bev); return bev; err: bufferevent_free(&bev_a->bev.bev); return NULL; }
struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef _WIN32 if (base && event_base_get_iocp_(base)) return bufferevent_async_new_(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); evbuffer_freeze(bufev->input, 0); evbuffer_freeze(bufev->output, 1); return bufev; }
struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef WIN32 if (base && event_base_get_iocp(base)) return bufferevent_async_new(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; //设置将evbuffer的数据向fd传 evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); //设置读写回调 event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); //设置evbuffer的回调函数,使得外界给写缓冲区添加数据时,能触发 //写操作,这个回调对于写事件的监听是很重要的 evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); /* 虽然这里冻结了,但实际上Libevent在读数据或者写数据之前会解冻的读完或者写完数据后,又会马上冻结。 * 这主要防止数据被意外修改。用户一般不会直接调用evbuffer_freeze或者evbuffer_unfreeze函数。 * 一切的冻结和解冻操作都由Libevent内部完成。还有一点要注意,因为这里只是把写缓冲区的头部冻结了。 * 所以还是可以往写缓冲区的尾部追加数据。同样,此时也是可以从读缓冲区读取数据。这个是必须的。 * 因为在Libevent内部不解冻的时候,用户需要从读缓冲区中获取数据(这相当于从socket fd中读取数据), * 用户也需要把数据写到写缓冲区中(这相当于把数据写入到socket fd中)。*/ //冻结读缓冲区的尾部,未解冻之前不能往读缓冲区追加数据 //也就是说不能从socket fd中读取数据 evbuffer_freeze(bufev->input, 0); //冻结写缓冲区的头部,未解冻之前不能把写缓冲区的头部数据删除 //也就是说不能把数据写到socket fd evbuffer_freeze(bufev->output, 1); return bufev; }
void bufferevent_setwatermark(struct bufferevent *bufev, short events, size_t lowmark, size_t highmark) { struct bufferevent_private *bufev_private = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); BEV_LOCK(bufev); if (events & EV_WRITE) { bufev->wm_write.low = lowmark; bufev->wm_write.high = highmark; } if (events & EV_READ) { bufev->wm_read.low = lowmark; bufev->wm_read.high = highmark; if (highmark) { /* There is now a new high-water mark for read. enable the callback if needed, and see if we should suspend/bufferevent_wm_unsuspend. */ if (bufev_private->read_watermarks_cb == NULL) { bufev_private->read_watermarks_cb = evbuffer_add_cb(bufev->input, bufferevent_inbuf_wm_cb, bufev); } evbuffer_cb_set_flags(bufev->input, bufev_private->read_watermarks_cb, EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER); if (evbuffer_get_length(bufev->input) > highmark) bufferevent_wm_suspend_read(bufev); else if (evbuffer_get_length(bufev->input) < highmark) bufferevent_wm_unsuspend_read(bufev); } else { /* There is now no high-water mark for read. */ if (bufev_private->read_watermarks_cb) evbuffer_cb_clear_flags(bufev->input, bufev_private->read_watermarks_cb, EVBUFFER_CB_ENABLED); bufferevent_wm_unsuspend_read(bufev); } } BEV_UNLOCK(bufev); }