/* Callback to implement watermarks on the input buffer. Only enabled * if the watermark is set. */ static void bufferevent_inbuf_wm_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent *bufev = arg; size_t size; size = evbuffer_get_length(buf); if (size >= bufev->wm_read.high) bufferevent_wm_suspend_read(bufev); else bufferevent_wm_unsuspend_read(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); }
/* Callback to implement watermarks on the input buffer. Only enabled * if the watermark is set. */ static void bufferevent_inbuf_wm_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent *bufev = arg; size_t size; size = evbuffer_get_length(buf); if (cbinfo->n_added > cbinfo->n_deleted) { /* Data got added. If it put us over the watermark, stop * reading. */ if (size >= bufev->wm_read.high) bufferevent_wm_suspend_read(bufev); } else { /* Data got removed. If it puts us under the watermark, stop reading. */ if (size < bufev->wm_read.high) bufferevent_wm_unsuspend_read(bufev); } }
static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; bufferevent_incref_and_lock_(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_READ, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* we somehow lowered the watermark, stop reading */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } readmax = bufferevent_get_read_max_(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; bufferevent_decrement_read_buckets_(bufev_p, res); /* Invoke the user callback - must always be called last */ if (evbuffer_get_length(input) >= bufev->wm_read.low) bufferevent_run_readcb_(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); bufferevent_run_eventcb_(bufev, what); done: bufferevent_decref_and_unlock_(bufev); }
static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; _bufferevent_incref_and_lock(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_READ, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* 缓冲区超过高水位,挂起读。 */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } //因为用户可以限速,所以这么要检测最大的可读大小。 //如果没有限速的话,那么将返回16384字节,即16K //默认情况下是没有限速的。 readmax = _bufferevent_get_read_max(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) //EINTER or EAGAIN goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; _bufferevent_decrement_read_buckets(bufev_p, res); /* 数据大于低水平,调用用户设置的回调。 */ if (evbuffer_get_length(input) >= bufev->wm_read.low) _bufferevent_run_readcb(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); _bufferevent_run_eventcb(bufev, what); done: _bufferevent_decref_and_unlock(bufev); }