--- /dev/null
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/io/async/EventBaseManager.h>
+
+namespace folly {
+
+std::atomic<EventBaseManager*> globalManager(nullptr);
+
+EventBaseManager* EventBaseManager::get() {
+ EventBaseManager* mgr = globalManager;
+ if (mgr) {
+ return mgr;
+ }
+
+ EventBaseManager* new_mgr = new EventBaseManager;
+ bool exchanged = globalManager.compare_exchange_strong(mgr, new_mgr);
+ if (!exchanged) {
+ delete new_mgr;
+ return mgr;
+ } else {
+ return new_mgr;
+ }
+
+}
+
+/*
+ * EventBaseManager methods
+ */
+
+void EventBaseManager::setEventBase(EventBase *eventBase,
+ bool takeOwnership) {
+ EventBaseInfo *info = localStore_.get();
+ if (info != nullptr) {
+ throw std::runtime_error("EventBaseManager: cannot set a new EventBase "
+ "for this thread when one already exists");
+ }
+
+ info = new EventBaseInfo(eventBase, takeOwnership);
+ localStore_.reset(info);
+ this->trackEventBase(eventBase);
+}
+
+void EventBaseManager::clearEventBase() {
+ EventBaseInfo *info = localStore_.get();
+ if (info != nullptr) {
+ this->untrackEventBase(info->eventBase);
+ this->localStore_.reset(nullptr);
+ }
+}
+
+// XXX should this really be "const"?
+EventBase * EventBaseManager::getEventBase() const {
+ // have one?
+ auto *info = localStore_.get();
+ if (! info) {
+ info = new EventBaseInfo();
+ localStore_.reset(info);
+
+ if (observer_) {
+ info->eventBase->setObserver(observer_);
+ }
+
+ // start tracking the event base
+ // XXX
+ // note: ugly cast because this does something mutable
+ // even though this method is defined as "const".
+ // Simply removing the const causes trouble all over fbcode;
+ // lots of services build a const EventBaseManager and errors
+ // abound when we make this non-const.
+ (const_cast<EventBaseManager *>(this))->trackEventBase(info->eventBase);
+ }
+
+ return info->eventBase;
+}
+
+} // folly
--- /dev/null
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/ThreadLocal.h>
+#include <folly/io/async/EventBase.h>
+#include <set>
+#include <list>
+
+namespace folly {
+
+/**
+ * Manager for per-thread EventBase objects.
+ * This class will find or create a EventBase for the current
+ * thread, associated with thread-specific storage for that thread.
+ * Although a typical application will generally only have one
+ * EventBaseManager, there is no restriction on multiple instances;
+ * the EventBases belong to one instance are isolated from those of
+ * another.
+ */
+class EventBaseManager {
+ public:
+ // XXX Constructing a EventBaseManager directly is DEPRECATED and not
+ // encouraged. You should instead use the global singleton if possible.
+ EventBaseManager() {
+ }
+
+ ~EventBaseManager() {
+ }
+
+ explicit EventBaseManager(
+ const std::shared_ptr<EventBaseObserver>& observer
+ ) : observer_(observer) {}
+
+ /**
+ * Get the global EventBaseManager for this program. Ideally all users
+ * of EventBaseManager go through this interface and do not construct
+ * EventBaseManager directly.
+ */
+ static EventBaseManager* get();
+
+ /**
+ * Get the EventBase for this thread, or create one if none exists yet.
+ *
+ * If no EventBase exists for this thread yet, a new one will be created and
+ * returned. May throw std::bad_alloc if allocation fails.
+ */
+ EventBase* getEventBase() const;
+
+ /**
+ * Get the EventBase for this thread.
+ *
+ * Returns nullptr if no EventBase has been created for this thread yet.
+ */
+ EventBase* getExistingEventBase() const {
+ EventBaseInfo* info = localStore_.get();
+ if (info == nullptr) {
+ return nullptr;
+ }
+ return info->eventBase;
+ }
+
+ /**
+ * Set the EventBase to be used by this thread.
+ *
+ * This may only be called if no EventBase has been defined for this thread
+ * yet. If a EventBase is already defined for this thread, a
+ * std::runtime_error is thrown. std::bad_alloc may also be thrown if
+ * allocation fails while setting the EventBase.
+ *
+ * This should typically be invoked by the code that will call loop() on the
+ * EventBase, to make sure the EventBaseManager points to the correct
+ * EventBase that is actually running in this thread.
+ */
+ void setEventBase(EventBase *eventBase, bool takeOwnership);
+
+ /**
+ * Clear the EventBase for this thread.
+ *
+ * This can be used if the code driving the EventBase loop() has finished
+ * the loop and new events should no longer be added to the EventBase.
+ */
+ void clearEventBase();
+
+ /**
+ * Gives the caller all references to all assigned EventBase instances at
+ * this moment in time. Locks a mutex so that these EventBase set cannot
+ * be changed, and also the caller can rely on no instances being destructed.
+ */
+ template<typename FunctionType>
+ void withEventBaseSet(const FunctionType& runnable) {
+ // grab the mutex for the caller
+ std::lock_guard<std::mutex> g(*&eventBaseSetMutex_);
+ // give them only a const set to work with
+ const std::set<EventBase *>& constSet = eventBaseSet_;
+ runnable(constSet);
+ }
+
+
+ private:
+ struct EventBaseInfo {
+ EventBaseInfo(EventBase *evb, bool owned)
+ : eventBase(evb),
+ owned_(owned) {}
+
+ EventBaseInfo()
+ : eventBase(new EventBase)
+ , owned_(true) {}
+
+ EventBase *eventBase;
+ bool owned_;
+ ~EventBaseInfo() {
+ if (owned_) {
+ delete eventBase;
+ }
+ }
+ };
+
+ // Forbidden copy constructor and assignment opererator
+ EventBaseManager(EventBaseManager const &);
+ EventBaseManager& operator=(EventBaseManager const &);
+
+ void trackEventBase(EventBase *evb) {
+ std::lock_guard<std::mutex> g(*&eventBaseSetMutex_);
+ eventBaseSet_.insert(evb);
+ }
+
+ void untrackEventBase(EventBase *evb) {
+ std::lock_guard<std::mutex> g(*&eventBaseSetMutex_);
+ eventBaseSet_.erase(evb);
+ }
+
+ mutable folly::ThreadLocalPtr<EventBaseInfo> localStore_;
+
+ // set of "active" EventBase instances
+ // (also see the mutex "eventBaseSetMutex_" below
+ // which governs access to this).
+ mutable std::set<EventBase *> eventBaseSet_;
+
+ // a mutex to use as a guard for the above set
+ std::mutex eventBaseSetMutex_;
+
+ std::shared_ptr<folly::EventBaseObserver> observer_;
+};
+
+} // folly