Adds writer test case for RCU
[folly.git] / folly / io / async / EventBaseLocal.cpp
index c8533e6d97a60495236a8a855a96ea986253c316..8b21fc18b781bd48c43cc56b642749dc986a4776 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2015-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
-#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
-
 #include <folly/io/async/EventBaseLocal.h>
+#include <folly/MapUtil.h>
 #include <atomic>
 #include <thread>
 
 namespace folly { namespace detail {
 
 EventBaseLocalBase::~EventBaseLocalBase() {
-  // There's a race condition if an EventBase and an EventBaseLocal destruct
-  // at the same time (each will lock eventBases_ and localStorageMutex_
-  // in the opposite order), so we dance around it with a loop and try_lock.
-  while (true) {
-    SYNCHRONIZED(eventBases_) {
-      auto it = eventBases_.begin();
-      while (it != eventBases_.end()) {
-        auto evb = *it;
-        if (evb->localStorageMutex_.try_lock()) {
-          evb->localStorage_.erase(key_);
-          evb->localStorageToDtor_.erase(this);
-          it = eventBases_.erase(it);
-          evb->localStorageMutex_.unlock();
-        } else {
-          ++it;
-        }
-      }
-
-      if (eventBases_.empty()) {
-        return;
-      }
-    }
-    std::this_thread::yield(); // let the other thread take the eventBases_ lock
+  auto locked = eventBases_.rlock();
+  for (auto* evb : *locked) {
+    evb->runInEventBaseThread([ this, evb, key = key_ ] {
+      evb->localStorage_.erase(key);
+      evb->localStorageToDtor_.erase(this);
+    });
   }
 }
 
 void* EventBaseLocalBase::getVoid(EventBase& evb) {
-  std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
-  auto it2 = evb.localStorage_.find(key_);
-  if (UNLIKELY(it2 != evb.localStorage_.end())) {
-    return it2->second.get();
-  }
+  evb.dcheckIsInEventBaseThread();
 
-  return nullptr;
+  return folly::get_default(evb.localStorage_, key_, {}).get();
 }
 
 void EventBaseLocalBase::erase(EventBase& evb) {
-  std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
+  evb.dcheckIsInEventBaseThread();
+
   evb.localStorage_.erase(key_);
   evb.localStorageToDtor_.erase(this);
 
@@ -70,18 +49,15 @@ void EventBaseLocalBase::erase(EventBase& evb) {
 }
 
 void EventBaseLocalBase::onEventBaseDestruction(EventBase& evb) {
+  evb.dcheckIsInEventBaseThread();
+
   SYNCHRONIZED(eventBases_) {
     eventBases_.erase(&evb);
   }
 }
 
 void EventBaseLocalBase::setVoid(EventBase& evb, std::shared_ptr<void>&& ptr) {
-  std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
-  setVoidUnlocked(evb, std::move(ptr));
-}
-
-void EventBaseLocalBase::setVoidUnlocked(
-    EventBase& evb, std::shared_ptr<void>&& ptr) {
+  evb.dcheckIsInEventBaseThread();
 
   auto alreadyExists =
     evb.localStorage_.find(key_) != evb.localStorage_.end();
@@ -89,14 +65,11 @@ void EventBaseLocalBase::setVoidUnlocked(
   evb.localStorage_.emplace(key_, std::move(ptr));
 
   if (!alreadyExists) {
-    SYNCHRONIZED(eventBases_) {
-      eventBases_.insert(&evb);
-    }
+    eventBases_.wlock()->insert(&evb);
     evb.localStorageToDtor_.insert(this);
   }
 }
 
 std::atomic<uint64_t> EventBaseLocalBase::keyCounter_{0};
-}}
-
-#endif // !__ANDROID__ && !ANDROID && !__APPLE__
+} // namespace detail
+} // namespace folly