EventBase::runImediatelyOrRunInEventBaseThreadAndWait.
authorYedidya Feldblum <yfeldblum@fb.com>
Tue, 31 Mar 2015 01:17:31 +0000 (18:17 -0700)
committerafrind <afrind@fb.com>
Thu, 2 Apr 2015 19:00:46 +0000 (12:00 -0700)
Summary:
[Folly] EventBase::runImediatelyOrRunInEventBaseThreadAndWait.

When you have code that you need to run in the event loop and wait for it to finish, and you yourself might be in the event loop but might be in another thread instead.

Test Plan:
Unit tests:
* `folly/io/async/test/EventBaseTest.cpp`.

Reviewed By: davejwatson@fb.com

Subscribers: folly-diffs@, yfeldblum, chalfant, agallagher, njormrod, ldbrandy, brettp, dougw

FB internal diff: D1953110

Signature: t1:1953110:1427751076:ad2c9f4d5b65ef952cba94b06be887672ee44583

folly/io/async/EventBase.cpp
folly/io/async/EventBase.h
folly/io/async/test/EventBaseTest.cpp

index 8bc09523d05b1fba5f608df5abfefe4bc7f18fe3..5ff171eb2c3f7c043ceb04ee03b7df8793cf4e42 100644 (file)
@@ -610,6 +610,15 @@ bool EventBase::runInEventBaseThreadAndWait(const Cob& fn) {
   return true;
 }
 
+bool EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(const Cob& fn) {
+  if (inRunningEventBaseThread()) {
+    fn();
+    return true;
+  } else {
+    return runInEventBaseThreadAndWait(fn);
+  }
+}
+
 void EventBase::runAfterDelay(const Cob& cob,
                               int milliseconds,
                               TimeoutManager::InternalEnum in) {
index ca895c3a5025e5460e6ccaff5801ad75f7b72389..0bdc428ad39956015e046c29ed61affd1afb4764 100644 (file)
@@ -382,6 +382,31 @@ class EventBase : private boost::noncopyable,
    */
   bool runInEventBaseThreadAndWait(const Cob& fn);
 
+  /*
+   * Like runInEventBaseThreadAndWait, except if the caller is already in the
+   * event base thread, the functor is simply run inline.
+   */
+  template<typename T>
+  bool runImmediatelyOrRunInEventBaseThreadAndWait(void (*fn)(T*), T* arg) {
+    return runImmediatelyOrRunInEventBaseThreadAndWait(
+        reinterpret_cast<void (*)(void*)>(fn), reinterpret_cast<void*>(arg));
+  }
+
+  /*
+   * Like runInEventBaseThreadAndWait, except if the caller is already in the
+   * event base thread, the functor is simply run inline.
+   */
+  bool runImmediatelyOrRunInEventBaseThreadAndWait(
+      void (*fn)(void*), void* arg) {
+    return runImmediatelyOrRunInEventBaseThreadAndWait(std::bind(fn, arg));
+  }
+
+    /*
+   * Like runInEventBaseThreadAndWait, except if the caller is already in the
+   * event base thread, the functor is simply run inline.
+   */
+bool runImmediatelyOrRunInEventBaseThreadAndWait(const Cob& fn);
+
   /**
    * Runs the given Cob at some time after the specified number of
    * milliseconds.  (No guarantees exactly when.)
index a5fbcad53c7a27c494619a2d7f2f8e7053fe5c97..b9716a7cc9d1bef9c18ed42aa961eec0ab7eafab 100644 (file)
@@ -1180,7 +1180,7 @@ TEST(EventBaseTest, RunInThread) {
 //  This test simulates some calls, and verifies that the waiting happens by
 //  triggering what otherwise would be race conditions, and trying to detect
 //  whether any of the race conditions happened.
-TEST(EventBaseTest, RunInEventLoopThreadAndWait) {
+TEST(EventBaseTest, RunInEventBaseThreadAndWait) {
   const size_t c = 256;
   vector<unique_ptr<atomic<size_t>>> atoms(c);
   for (size_t i = 0; i < c; ++i) {
@@ -1216,6 +1216,36 @@ TEST(EventBaseTest, RunInEventLoopThreadAndWait) {
   EXPECT_EQ(c, sum);
 }
 
+TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
+  EventBase eb;
+  thread th(&EventBase::loopForever, &eb);
+  SCOPE_EXIT {
+    eb.terminateLoopSoon();
+    th.join();
+  };
+  auto mutated = false;
+  eb.runImmediatelyOrRunInEventBaseThreadAndWait([&] {
+      mutated = true;
+  });
+  EXPECT_TRUE(mutated);
+}
+
+TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
+  EventBase eb;
+  thread th(&EventBase::loopForever, &eb);
+  SCOPE_EXIT {
+    eb.terminateLoopSoon();
+    th.join();
+  };
+  eb.runInEventBaseThreadAndWait([&] {
+      auto mutated = false;
+      eb.runImmediatelyOrRunInEventBaseThreadAndWait([&] {
+          mutated = true;
+      });
+      EXPECT_TRUE(mutated);
+  });
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Tests for runInLoop()
 ///////////////////////////////////////////////////////////////////////////