int bufferevent_enable_locking(struct bufferevent *bufev, void *lock) { #ifdef _EVENT_DISABLE_THREAD_SUPPORT return -1; #else struct bufferevent *underlying; if (BEV_UPCAST(bufev)->lock) return -1; underlying = bufferevent_get_underlying(bufev); if (!lock && underlying && BEV_UPCAST(underlying)->lock) { lock = BEV_UPCAST(underlying)->lock; BEV_UPCAST(bufev)->lock = lock; BEV_UPCAST(bufev)->own_lock = 0; } else if (!lock) { EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE); if (!lock) return -1; BEV_UPCAST(bufev)->lock = lock; BEV_UPCAST(bufev)->own_lock = 1; } else { BEV_UPCAST(bufev)->lock = lock; BEV_UPCAST(bufev)->own_lock = 0; } evbuffer_enable_locking(bufev->input, lock); evbuffer_enable_locking(bufev->output, lock); if (underlying && !BEV_UPCAST(underlying)->lock) bufferevent_enable_locking(underlying, lock); return 0; #endif }
static struct bufferevent * tor_get_root_bufferevent(struct bufferevent *bev) { struct bufferevent *u; while ((u = bufferevent_get_underlying(bev)) != NULL) bev = u; return bev; }
void _bufferevent_decref_and_unlock(struct bufferevent *bufev) { struct bufferevent_private *bufev_private = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct bufferevent *underlying; if (--bufev_private->refcnt) { BEV_UNLOCK(bufev); return; } underlying = bufferevent_get_underlying(bufev); /* Clean up the shared info */ if (bufev->be_ops->destruct) bufev->be_ops->destruct(bufev); /* XXX what happens if refcnt for these buffers is > 1? * The buffers can share a lock with this bufferevent object, * but the lock might be destroyed below. */ /* evbuffer will free the callbacks */ evbuffer_free(bufev->input); evbuffer_free(bufev->output); if (bufev_private->rate_limiting) { if (bufev_private->rate_limiting->group) bufferevent_remove_from_rate_limit_group(bufev); if (event_initialized(&bufev_private->rate_limiting->refill_bucket_event)) event_del(&bufev_private->rate_limiting->refill_bucket_event); event_debug_unassign(&bufev_private->rate_limiting->refill_bucket_event); mm_free(bufev_private->rate_limiting); bufev_private->rate_limiting = NULL; } event_debug_unassign(&bufev->ev_read); event_debug_unassign(&bufev->ev_write); BEV_UNLOCK(bufev); if (bufev_private->own_lock) EVTHREAD_FREE_LOCK(bufev_private->lock, EVTHREAD_LOCKTYPE_RECURSIVE); /* Free the actual allocated memory. */ mm_free(bufev - bufev->be_ops->mem_offset); /* release the reference to underlying now that we no longer need * the reference to it. This is mainly in case our lock is shared * with underlying. * XXX Should we/can we just refcount evbuffer/bufferevent locks? * It would probably save us some headaches. */ if (underlying) bufferevent_decref(underlying); }
static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_) { struct bufferevent *bufev = arg_; struct bufferevent *underlying; struct bufferevent_private *bufev_private = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); BEV_LOCK(bufev); underlying = bufferevent_get_underlying(bufev); /* Clean up the shared info */ if (bufev->be_ops->destruct) bufev->be_ops->destruct(bufev); /* XXX what happens if refcnt for these buffers is > 1? * The buffers can share a lock with this bufferevent object, * but the lock might be destroyed below. */ /* evbuffer will free the callbacks */ evbuffer_free(bufev->input); evbuffer_free(bufev->output); if (bufev_private->rate_limiting) { if (bufev_private->rate_limiting->group) bufferevent_remove_from_rate_limit_group_internal_(bufev,0); mm_free(bufev_private->rate_limiting); bufev_private->rate_limiting = NULL; } BEV_UNLOCK(bufev); if (bufev_private->own_lock) EVTHREAD_FREE_LOCK(bufev_private->lock, EVTHREAD_LOCKTYPE_RECURSIVE); /* Free the actual allocated memory. */ mm_free(((char*)bufev) - bufev->be_ops->mem_offset); /* Release the reference to underlying now that we no longer need the * reference to it. We wait this long mainly in case our lock is * shared with underlying. * * The 'destruct' function will also drop a reference to underlying * if BEV_OPT_CLOSE_ON_FREE is set. * * XXX Should we/can we just refcount evbuffer/bufferevent locks? * It would probably save us some headaches. */ if (underlying) bufferevent_decref_(underlying); }