(folly) Add lock holder interface to flat combining. Change an assert to a static_assert.
authorMaged Michael <magedmichael@fb.com>
Sat, 25 Mar 2017 10:28:15 +0000 (03:28 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 25 Mar 2017 10:34:55 +0000 (03:34 -0700)
Summary:
Two changes:
- Add a lock holder interface to enable users to move exclusive access and implicitly release the held lock.
- Change an assert to a static_assert to check at compile time if a provided function fits in the Function structure without dynamic allocation.

Reviewed By: djwatson

Differential Revision: D4770229

fbshipit-source-id: 89408164c08d7660231a6ca4e37637dd688356cd

folly/experimental/flat_combining/FlatCombining.h
folly/experimental/flat_combining/test/FlatCombiningTestHelpers.h

index 9c03350..445d29a 100644 (file)
@@ -197,15 +197,16 @@ class FlatCombining {
 
     template <typename Func>
     void setFn(Func&& fn) {
+      static_assert(
+          std::is_nothrow_constructible<
+              folly::Function<void()>,
+              _t<std::decay<Func>>>::value,
+          "Try using a smaller function object that can fit in folly::Function "
+          "without allocation, or use the custom interface of requestFC() to "
+          "manage the requested function's arguments and results explicitly "
+          "in a custom request structure without allocation.");
       fn_ = std::forward<Func>(fn);
       assert(fn_);
-      // If the following assertion is triggered, the user should
-      // either change the provided function, i.e., fn, to fit in
-      // folly::Function without allocation or use the custom
-      // interface to request combining for fn and manage its
-      // arguments (and results, if any) explicitly in a custom
-      // request structure.
-      assert(!fn_.hasAllocatedMemory());
     }
 
     void clearFn() {
@@ -276,6 +277,13 @@ class FlatCombining {
     m_.lock();
   }
 
+  // Give the caller exclusive access through a lock holder.
+  // No need for explicit release.
+  template <typename LockHolder>
+  void acquireExclusive(LockHolder& l) {
+    l = LockHolder(m_);
+  }
+
   // Try to give the caller exclusive access. Returns true iff successful.
   bool tryExclusive() {
     return m_.try_lock();
index f9b4980..07742e1 100644 (file)
@@ -104,7 +104,21 @@ uint64_t fc_test(
       }
 
       if (excl) {
-        // test of unstructured exclusive access
+        // test of exclusive access through a lock holder
+        {
+          std::unique_lock<Mutex> l;
+          ex.acquireExclusive(l);
+          CHECK(!mutex);
+          mutex = true;
+          VLOG(2) << tid << " " << ex.getVal() << " ...........";
+          using namespace std::chrono_literals;
+          /* sleep override */ // for coverage
+          std::this_thread::sleep_for(10ms);
+          VLOG(2) << tid << " " << ex.getVal() << " ===========";
+          CHECK(mutex);
+          mutex = false;
+        }
+        // test of explicit acquisition and release of exclusive access
         ex.acquireExclusive();
         {
           CHECK(!mutex);