delete this;
}
+
+// The interface used to libevent is not thread-safe. Calls to
+// event_init() and event_base_free() directly modify an internal
+// global 'current_base', so a mutex is required to protect this.
+//
+// event_init() should only ever be called once. Subsequent calls
+// should be made to event_base_new(). We can recognise that
+// event_init() has already been called by simply inspecting current_base.
+static std::mutex libevent_mutex_;
+
/*
* EventBase methods
*/
: runOnceCallbacks_(nullptr)
, stop_(false)
, loopThread_(0)
- , evb_(static_cast<event_base*>(event_init()))
, queue_(nullptr)
, fnRunner_(nullptr)
, maxLatency_(0)
, startWork_(0)
, observer_(nullptr)
, observerSampleCount_(0) {
+ {
+ std::lock_guard<std::mutex> lock(libevent_mutex_);
+
+ // The value 'current_base' (libevent 1) or
+ // 'event_global_current_base_' (libevent 2) is filled in by event_set(),
+ // allowing examination of its value without an explicit reference here.
+ // If ev.ev_base is NULL, then event_init() must be called, otherwise
+ // call event_base_new().
+ struct event ev;
+ event_set(&ev, 0, 0, nullptr, nullptr);
+ evb_ = (ev.ev_base) ? event_base_new() : event_init();
+ }
if (UNLIKELY(evb_ == nullptr)) {
LOG(ERROR) << "EventBase(): Failed to init event base.";
folly::throwSystemError("error in EventBase::EventBase()");
// Stop consumer before deleting NotificationQueue
fnRunner_->stopConsuming();
- event_base_free(evb_);
+ {
+ std::lock_guard<std::mutex> lock(libevent_mutex_);
+ event_base_free(evb_);
+ }
VLOG(5) << "EventBase(): Destroyed.";
}