2 * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
3 * Copyright (c) 2007-2010 Niels Provos, Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
30 #include "event2/event-config.h"
32 #ifdef _EVENT_HAVE_SYS_TIME_H
40 #ifdef _EVENT_HAVE_STDARG_H
49 #include "event2/util.h"
50 #include "event2/buffer.h"
51 #include "event2/buffer_compat.h"
52 #include "event2/bufferevent.h"
53 #include "event2/bufferevent_struct.h"
54 #include "event2/bufferevent_compat.h"
55 #include "event2/event.h"
56 #include "log-internal.h"
57 #include "mm-internal.h"
58 #include "bufferevent-internal.h"
59 #include "evbuffer-internal.h"
60 #include "util-internal.h"
63 bufferevent_suspend_read(struct bufferevent
*bufev
, bufferevent_suspend_flags what
)
65 struct bufferevent_private
*bufev_private
=
66 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
68 if (!bufev_private
->read_suspended
)
69 bufev
->be_ops
->disable(bufev
, EV_READ
);
70 bufev_private
->read_suspended
|= what
;
75 bufferevent_unsuspend_read(struct bufferevent
*bufev
, bufferevent_suspend_flags what
)
77 struct bufferevent_private
*bufev_private
=
78 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
80 bufev_private
->read_suspended
&= ~what
;
81 if (!bufev_private
->read_suspended
&& (bufev
->enabled
& EV_READ
))
82 bufev
->be_ops
->enable(bufev
, EV_READ
);
87 bufferevent_suspend_write(struct bufferevent
*bufev
, bufferevent_suspend_flags what
)
89 struct bufferevent_private
*bufev_private
=
90 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
92 if (!bufev_private
->write_suspended
)
93 bufev
->be_ops
->disable(bufev
, EV_WRITE
);
94 bufev_private
->write_suspended
|= what
;
99 bufferevent_unsuspend_write(struct bufferevent
*bufev
, bufferevent_suspend_flags what
)
101 struct bufferevent_private
*bufev_private
=
102 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
104 bufev_private
->write_suspended
&= ~what
;
105 if (!bufev_private
->write_suspended
&& (bufev
->enabled
& EV_WRITE
))
106 bufev
->be_ops
->enable(bufev
, EV_WRITE
);
111 /* Callback to implement watermarks on the input buffer. Only enabled
112 * if the watermark is set. */
114 bufferevent_inbuf_wm_cb(struct evbuffer
*buf
,
115 const struct evbuffer_cb_info
*cbinfo
,
118 struct bufferevent
*bufev
= arg
;
121 size
= evbuffer_get_length(buf
);
123 if (size
>= bufev
->wm_read
.high
)
124 bufferevent_wm_suspend_read(bufev
);
126 bufferevent_wm_unsuspend_read(bufev
);
130 bufferevent_run_deferred_callbacks_locked(struct deferred_cb
*_
, void *arg
)
132 struct bufferevent_private
*bufev_private
= arg
;
133 struct bufferevent
*bufev
= &bufev_private
->bev
;
136 if ((bufev_private
->eventcb_pending
& BEV_EVENT_CONNECTED
) &&
138 /* The "connected" happened before any reads or writes, so
140 bufev_private
->eventcb_pending
&= ~BEV_EVENT_CONNECTED
;
141 bufev
->errorcb(bufev
, BEV_EVENT_CONNECTED
, bufev
->cbarg
);
143 if (bufev_private
->readcb_pending
&& bufev
->readcb
) {
144 bufev_private
->readcb_pending
= 0;
145 bufev
->readcb(bufev
, bufev
->cbarg
);
147 if (bufev_private
->writecb_pending
&& bufev
->writecb
) {
148 bufev_private
->writecb_pending
= 0;
149 bufev
->writecb(bufev
, bufev
->cbarg
);
151 if (bufev_private
->eventcb_pending
&& bufev
->errorcb
) {
152 short what
= bufev_private
->eventcb_pending
;
153 int err
= bufev_private
->errno_pending
;
154 bufev_private
->eventcb_pending
= 0;
155 bufev_private
->errno_pending
= 0;
156 EVUTIL_SET_SOCKET_ERROR(err
);
157 bufev
->errorcb(bufev
, what
, bufev
->cbarg
);
159 _bufferevent_decref_and_unlock(bufev
);
163 bufferevent_run_deferred_callbacks_unlocked(struct deferred_cb
*_
, void *arg
)
165 struct bufferevent_private
*bufev_private
= arg
;
166 struct bufferevent
*bufev
= &bufev_private
->bev
;
169 #define UNLOCKED(stmt) \
170 do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0)
172 if ((bufev_private
->eventcb_pending
& BEV_EVENT_CONNECTED
) &&
174 /* The "connected" happened before any reads or writes, so
176 bufferevent_event_cb errorcb
= bufev
->errorcb
;
177 void *cbarg
= bufev
->cbarg
;
178 bufev_private
->eventcb_pending
&= ~BEV_EVENT_CONNECTED
;
179 UNLOCKED(errorcb(bufev
, BEV_EVENT_CONNECTED
, cbarg
));
181 if (bufev_private
->readcb_pending
&& bufev
->readcb
) {
182 bufferevent_data_cb readcb
= bufev
->readcb
;
183 void *cbarg
= bufev
->cbarg
;
184 bufev_private
->readcb_pending
= 0;
185 UNLOCKED(readcb(bufev
, cbarg
));
187 if (bufev_private
->writecb_pending
&& bufev
->writecb
) {
188 bufferevent_data_cb writecb
= bufev
->writecb
;
189 void *cbarg
= bufev
->cbarg
;
190 bufev_private
->writecb_pending
= 0;
191 UNLOCKED(writecb(bufev
, cbarg
));
193 if (bufev_private
->eventcb_pending
&& bufev
->errorcb
) {
194 bufferevent_event_cb errorcb
= bufev
->errorcb
;
195 void *cbarg
= bufev
->cbarg
;
196 short what
= bufev_private
->eventcb_pending
;
197 int err
= bufev_private
->errno_pending
;
198 bufev_private
->eventcb_pending
= 0;
199 bufev_private
->errno_pending
= 0;
200 EVUTIL_SET_SOCKET_ERROR(err
);
201 UNLOCKED(errorcb(bufev
,what
,cbarg
));
203 _bufferevent_decref_and_unlock(bufev
);
207 #define SCHEDULE_DEFERRED(bevp) \
209 bufferevent_incref(&(bevp)->bev); \
210 event_deferred_cb_schedule( \
211 event_base_get_deferred_cb_queue((bevp)->bev.ev_base), \
212 &(bevp)->deferred); \
217 _bufferevent_run_readcb(struct bufferevent
*bufev
)
219 /* Requires that we hold the lock and a reference */
220 struct bufferevent_private
*p
=
221 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
222 if (bufev
->readcb
== NULL
)
224 if (p
->options
& BEV_OPT_DEFER_CALLBACKS
) {
225 p
->readcb_pending
= 1;
226 if (!p
->deferred
.queued
)
227 SCHEDULE_DEFERRED(p
);
229 bufev
->readcb(bufev
, bufev
->cbarg
);
234 _bufferevent_run_writecb(struct bufferevent
*bufev
)
236 /* Requires that we hold the lock and a reference */
237 struct bufferevent_private
*p
=
238 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
239 if (bufev
->writecb
== NULL
)
241 if (p
->options
& BEV_OPT_DEFER_CALLBACKS
) {
242 p
->writecb_pending
= 1;
243 if (!p
->deferred
.queued
)
244 SCHEDULE_DEFERRED(p
);
246 bufev
->writecb(bufev
, bufev
->cbarg
);
251 _bufferevent_run_eventcb(struct bufferevent
*bufev
, short what
)
253 /* Requires that we hold the lock and a reference */
254 struct bufferevent_private
*p
=
255 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
256 if (bufev
->errorcb
== NULL
)
258 if (p
->options
& BEV_OPT_DEFER_CALLBACKS
) {
259 p
->eventcb_pending
|= what
;
260 p
->errno_pending
= EVUTIL_SOCKET_ERROR();
261 if (!p
->deferred
.queued
)
262 SCHEDULE_DEFERRED(p
);
264 bufev
->errorcb(bufev
, what
, bufev
->cbarg
);
269 bufferevent_init_common(struct bufferevent_private
*bufev_private
,
270 struct event_base
*base
,
271 const struct bufferevent_ops
*ops
,
272 enum bufferevent_options options
)
274 struct bufferevent
*bufev
= &bufev_private
->bev
;
277 if ((bufev
->input
= evbuffer_new()) == NULL
)
281 if (!bufev
->output
) {
282 if ((bufev
->output
= evbuffer_new()) == NULL
) {
283 evbuffer_free(bufev
->input
);
288 bufev_private
->refcnt
= 1;
289 bufev
->ev_base
= base
;
291 /* Disable timeouts. */
292 evutil_timerclear(&bufev
->timeout_read
);
293 evutil_timerclear(&bufev
->timeout_write
);
298 * Set to EV_WRITE so that using bufferevent_write is going to
299 * trigger a callback. Reading needs to be explicitly enabled
300 * because otherwise no data will be available.
302 bufev
->enabled
= EV_WRITE
;
304 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
305 if (options
& BEV_OPT_THREADSAFE
) {
306 if (bufferevent_enable_locking(bufev
, NULL
) < 0) {
308 evbuffer_free(bufev
->input
);
309 evbuffer_free(bufev
->output
);
311 bufev
->output
= NULL
;
316 if ((options
& (BEV_OPT_DEFER_CALLBACKS
|BEV_OPT_UNLOCK_CALLBACKS
))
317 == BEV_OPT_UNLOCK_CALLBACKS
) {
318 event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
321 if (options
& BEV_OPT_DEFER_CALLBACKS
) {
322 if (options
& BEV_OPT_UNLOCK_CALLBACKS
)
323 event_deferred_cb_init(&bufev_private
->deferred
,
324 bufferevent_run_deferred_callbacks_unlocked
,
327 event_deferred_cb_init(&bufev_private
->deferred
,
328 bufferevent_run_deferred_callbacks_locked
,
332 bufev_private
->options
= options
;
334 evbuffer_set_parent(bufev
->input
, bufev
);
335 evbuffer_set_parent(bufev
->output
, bufev
);
341 bufferevent_setcb(struct bufferevent
*bufev
,
342 bufferevent_data_cb readcb
, bufferevent_data_cb writecb
,
343 bufferevent_event_cb eventcb
, void *cbarg
)
347 bufev
->readcb
= readcb
;
348 bufev
->writecb
= writecb
;
349 bufev
->errorcb
= eventcb
;
351 bufev
->cbarg
= cbarg
;
356 bufferevent_get_input(struct bufferevent
*bufev
)
362 bufferevent_get_output(struct bufferevent
*bufev
)
364 return bufev
->output
;
368 bufferevent_get_base(struct bufferevent
*bufev
)
370 return bufev
->ev_base
;
374 bufferevent_write(struct bufferevent
*bufev
, const void *data
, size_t size
)
376 if (evbuffer_add(bufev
->output
, data
, size
) == -1)
383 bufferevent_write_buffer(struct bufferevent
*bufev
, struct evbuffer
*buf
)
385 if (evbuffer_add_buffer(bufev
->output
, buf
) == -1)
392 bufferevent_read(struct bufferevent
*bufev
, void *data
, size_t size
)
394 return (evbuffer_remove(bufev
->input
, data
, size
));
398 bufferevent_read_buffer(struct bufferevent
*bufev
, struct evbuffer
*buf
)
400 return (evbuffer_add_buffer(buf
, bufev
->input
));
404 bufferevent_enable(struct bufferevent
*bufev
, short event
)
406 struct bufferevent_private
*bufev_private
=
407 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
408 short impl_events
= event
;
411 _bufferevent_incref_and_lock(bufev
);
412 if (bufev_private
->read_suspended
)
413 impl_events
&= ~EV_READ
;
414 if (bufev_private
->write_suspended
)
415 impl_events
&= ~EV_WRITE
;
417 bufev
->enabled
|= event
;
419 if (impl_events
&& bufev
->be_ops
->enable(bufev
, impl_events
) < 0)
422 _bufferevent_decref_and_unlock(bufev
);
427 bufferevent_set_timeouts(struct bufferevent
*bufev
,
428 const struct timeval
*tv_read
,
429 const struct timeval
*tv_write
)
434 bufev
->timeout_read
= *tv_read
;
436 evutil_timerclear(&bufev
->timeout_read
);
439 bufev
->timeout_write
= *tv_write
;
441 evutil_timerclear(&bufev
->timeout_write
);
444 if (bufev
->be_ops
->adj_timeouts
)
445 r
= bufev
->be_ops
->adj_timeouts(bufev
);
452 /* Obsolete; use bufferevent_set_timeouts */
454 bufferevent_settimeout(struct bufferevent
*bufev
,
455 int timeout_read
, int timeout_write
)
457 struct timeval tv_read
, tv_write
;
458 struct timeval
*ptv_read
= NULL
, *ptv_write
= NULL
;
460 memset(&tv_read
, 0, sizeof(tv_read
));
461 memset(&tv_write
, 0, sizeof(tv_write
));
464 tv_read
.tv_sec
= timeout_read
;
468 tv_write
.tv_sec
= timeout_write
;
469 ptv_write
= &tv_write
;
472 bufferevent_set_timeouts(bufev
, ptv_read
, ptv_write
);
477 bufferevent_disable(struct bufferevent
*bufev
, short event
)
482 bufev
->enabled
&= ~event
;
484 if (bufev
->be_ops
->disable(bufev
, event
) < 0)
492 * Sets the water marks
496 bufferevent_setwatermark(struct bufferevent
*bufev
, short events
,
497 size_t lowmark
, size_t highmark
)
499 struct bufferevent_private
*bufev_private
=
500 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
503 if (events
& EV_WRITE
) {
504 bufev
->wm_write
.low
= lowmark
;
505 bufev
->wm_write
.high
= highmark
;
508 if (events
& EV_READ
) {
509 bufev
->wm_read
.low
= lowmark
;
510 bufev
->wm_read
.high
= highmark
;
513 /* There is now a new high-water mark for read.
514 enable the callback if needed, and see if we should
515 suspend/bufferevent_wm_unsuspend. */
517 if (bufev_private
->read_watermarks_cb
== NULL
) {
518 bufev_private
->read_watermarks_cb
=
519 evbuffer_add_cb(bufev
->input
,
520 bufferevent_inbuf_wm_cb
,
523 evbuffer_cb_set_flags(bufev
->input
,
524 bufev_private
->read_watermarks_cb
,
525 EVBUFFER_CB_ENABLED
|EVBUFFER_CB_NODEFER
);
527 if (evbuffer_get_length(bufev
->input
) > highmark
)
528 bufferevent_wm_suspend_read(bufev
);
529 else if (evbuffer_get_length(bufev
->input
) < highmark
)
530 bufferevent_wm_unsuspend_read(bufev
);
532 /* There is now no high-water mark for read. */
533 if (bufev_private
->read_watermarks_cb
)
534 evbuffer_cb_clear_flags(bufev
->input
,
535 bufev_private
->read_watermarks_cb
,
536 EVBUFFER_CB_ENABLED
);
537 bufferevent_wm_unsuspend_read(bufev
);
544 bufferevent_flush(struct bufferevent
*bufev
,
546 enum bufferevent_flush_mode mode
)
550 if (bufev
->be_ops
->flush
)
551 r
= bufev
->be_ops
->flush(bufev
, iotype
, mode
);
557 _bufferevent_incref_and_lock(struct bufferevent
*bufev
)
559 struct bufferevent_private
*bufev_private
=
562 ++bufev_private
->refcnt
;
567 _bufferevent_transfer_lock_ownership(struct bufferevent
*donor
,
568 struct bufferevent
*recipient
)
570 struct bufferevent_private
*d
= BEV_UPCAST(donor
);
571 struct bufferevent_private
*r
= BEV_UPCAST(recipient
);
572 if (d
->lock
!= r
->lock
)
584 _bufferevent_decref_and_unlock(struct bufferevent
*bufev
)
586 struct bufferevent_private
*bufev_private
=
587 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
588 struct bufferevent
*underlying
;
590 EVUTIL_ASSERT(bufev_private
->refcnt
> 0);
592 if (--bufev_private
->refcnt
) {
597 underlying
= bufferevent_get_underlying(bufev
);
599 /* Clean up the shared info */
600 if (bufev
->be_ops
->destruct
)
601 bufev
->be_ops
->destruct(bufev
);
603 /* XXX what happens if refcnt for these buffers is > 1?
604 * The buffers can share a lock with this bufferevent object,
605 * but the lock might be destroyed below. */
606 /* evbuffer will free the callbacks */
607 evbuffer_free(bufev
->input
);
608 evbuffer_free(bufev
->output
);
610 if (bufev_private
->rate_limiting
) {
611 if (bufev_private
->rate_limiting
->group
)
612 bufferevent_remove_from_rate_limit_group_internal(bufev
,0);
613 if (event_initialized(&bufev_private
->rate_limiting
->refill_bucket_event
))
614 event_del(&bufev_private
->rate_limiting
->refill_bucket_event
);
615 event_debug_unassign(&bufev_private
->rate_limiting
->refill_bucket_event
);
616 mm_free(bufev_private
->rate_limiting
);
617 bufev_private
->rate_limiting
= NULL
;
620 event_debug_unassign(&bufev
->ev_read
);
621 event_debug_unassign(&bufev
->ev_write
);
624 if (bufev_private
->own_lock
)
625 EVTHREAD_FREE_LOCK(bufev_private
->lock
,
626 EVTHREAD_LOCKTYPE_RECURSIVE
);
628 /* Free the actual allocated memory. */
629 mm_free(((char*)bufev
) - bufev
->be_ops
->mem_offset
);
631 /* Release the reference to underlying now that we no longer need the
632 * reference to it. We wait this long mainly in case our lock is
633 * shared with underlying.
635 * The 'destruct' function will also drop a reference to underlying
636 * if BEV_OPT_CLOSE_ON_FREE is set.
638 * XXX Should we/can we just refcount evbuffer/bufferevent locks?
639 * It would probably save us some headaches.
642 bufferevent_decref(underlying
);
648 bufferevent_decref(struct bufferevent
*bufev
)
651 return _bufferevent_decref_and_unlock(bufev
);
655 bufferevent_free(struct bufferevent
*bufev
)
658 bufferevent_setcb(bufev
, NULL
, NULL
, NULL
, NULL
);
659 _bufferevent_decref_and_unlock(bufev
);
663 bufferevent_incref(struct bufferevent
*bufev
)
665 struct bufferevent_private
*bufev_private
=
666 EVUTIL_UPCAST(bufev
, struct bufferevent_private
, bev
);
669 ++bufev_private
->refcnt
;
674 bufferevent_enable_locking(struct bufferevent
*bufev
, void *lock
)
676 #ifdef _EVENT_DISABLE_THREAD_SUPPORT
679 struct bufferevent
*underlying
;
681 if (BEV_UPCAST(bufev
)->lock
)
683 underlying
= bufferevent_get_underlying(bufev
);
685 if (!lock
&& underlying
&& BEV_UPCAST(underlying
)->lock
) {
686 lock
= BEV_UPCAST(underlying
)->lock
;
687 BEV_UPCAST(bufev
)->lock
= lock
;
688 BEV_UPCAST(bufev
)->own_lock
= 0;
690 EVTHREAD_ALLOC_LOCK(lock
, EVTHREAD_LOCKTYPE_RECURSIVE
);
693 BEV_UPCAST(bufev
)->lock
= lock
;
694 BEV_UPCAST(bufev
)->own_lock
= 1;
696 BEV_UPCAST(bufev
)->lock
= lock
;
697 BEV_UPCAST(bufev
)->own_lock
= 0;
699 evbuffer_enable_locking(bufev
->input
, lock
);
700 evbuffer_enable_locking(bufev
->output
, lock
);
702 if (underlying
&& !BEV_UPCAST(underlying
)->lock
)
703 bufferevent_enable_locking(underlying
, lock
);
710 bufferevent_setfd(struct bufferevent
*bev
, evutil_socket_t fd
)
712 union bufferevent_ctrl_data d
;
716 if (bev
->be_ops
->ctrl
)
717 res
= bev
->be_ops
->ctrl(bev
, BEV_CTRL_SET_FD
, &d
);
723 bufferevent_getfd(struct bufferevent
*bev
)
725 union bufferevent_ctrl_data d
;
729 if (bev
->be_ops
->ctrl
)
730 res
= bev
->be_ops
->ctrl(bev
, BEV_CTRL_GET_FD
, &d
);
732 return (res
<0) ? -1 : d
.fd
;
736 bufferevent_get_enabled(struct bufferevent
*bufev
)
746 bufferevent_get_underlying(struct bufferevent
*bev
)
748 union bufferevent_ctrl_data d
;
752 if (bev
->be_ops
->ctrl
)
753 res
= bev
->be_ops
->ctrl(bev
, BEV_CTRL_GET_UNDERLYING
, &d
);
755 return (res
<0) ? NULL
: d
.ptr
;
759 bufferevent_generic_read_timeout_cb(evutil_socket_t fd
, short event
, void *ctx
)
761 struct bufferevent
*bev
= ctx
;
762 _bufferevent_incref_and_lock(bev
);
763 bufferevent_disable(bev
, EV_READ
);
764 _bufferevent_run_eventcb(bev
, BEV_EVENT_TIMEOUT
|BEV_EVENT_READING
);
765 _bufferevent_decref_and_unlock(bev
);
768 bufferevent_generic_write_timeout_cb(evutil_socket_t fd
, short event
, void *ctx
)
770 struct bufferevent
*bev
= ctx
;
771 _bufferevent_incref_and_lock(bev
);
772 bufferevent_disable(bev
, EV_WRITE
);
773 _bufferevent_run_eventcb(bev
, BEV_EVENT_TIMEOUT
|BEV_EVENT_WRITING
);
774 _bufferevent_decref_and_unlock(bev
);
778 _bufferevent_init_generic_timeout_cbs(struct bufferevent
*bev
)
780 evtimer_assign(&bev
->ev_read
, bev
->ev_base
,
781 bufferevent_generic_read_timeout_cb
, bev
);
782 evtimer_assign(&bev
->ev_write
, bev
->ev_base
,
783 bufferevent_generic_write_timeout_cb
, bev
);
787 _bufferevent_del_generic_timeout_cbs(struct bufferevent
*bev
)
790 r1
= event_del(&bev
->ev_read
);
791 r2
= event_del(&bev
->ev_write
);
798 _bufferevent_generic_adj_timeouts(struct bufferevent
*bev
)
800 const short enabled
= bev
->enabled
;
801 struct bufferevent_private
*bev_p
=
802 EVUTIL_UPCAST(bev
, struct bufferevent_private
, bev
);
804 if ((enabled
& EV_READ
) && !bev_p
->read_suspended
&&
805 evutil_timerisset(&bev
->timeout_read
))
806 r1
= event_add(&bev
->ev_read
, &bev
->timeout_read
);
808 r1
= event_del(&bev
->ev_read
);
810 if ((enabled
& EV_WRITE
) && !bev_p
->write_suspended
&&
811 evutil_timerisset(&bev
->timeout_write
) &&
812 evbuffer_get_length(bev
->output
))
813 r2
= event_add(&bev
->ev_write
, &bev
->timeout_write
);
815 r2
= event_del(&bev
->ev_write
);
816 if (r1
< 0 || r2
< 0)
822 _bufferevent_add_event(struct event
*ev
, const struct timeval
*tv
)
824 if (tv
->tv_sec
== 0 && tv
->tv_usec
== 0)
825 return event_add(ev
, NULL
);
827 return event_add(ev
, tv
);
830 /* For use by user programs only; internally, we should be calling
831 either _bufferevent_incref_and_lock(), or BEV_LOCK. */
833 bufferevent_lock(struct bufferevent
*bev
)
835 _bufferevent_incref_and_lock(bev
);
839 bufferevent_unlock(struct bufferevent
*bev
)
841 _bufferevent_decref_and_unlock(bev
);