fix mem leak
authorAlecs King <int@fb.com>
Wed, 3 Jun 2015 00:04:25 +0000 (17:04 -0700)
committerNoam Lerner <noamler@fb.com>
Wed, 3 Jun 2015 16:55:12 +0000 (09:55 -0700)
Summary:
- use folly::ThreadLocal to work around GCC bug 57914 (with the benefit of accessAllThreads)
- clean up corresponding thread-local and global cache entries before eventbase gets destructed since there was a possible memory leak for short-term living eventbase.

Test Plan:
tests

Reviewed By: andrii@fb.com

Subscribers: smarlow, rushix, ilyam, trunkagent, folly-diffs@, yfeldblum, chalfant, jinfu

FB internal diff: D2116216

Tasks: 72910287279391

Signature: t1:2116216:1433212893:e57a7df90b15b89ccd9471469e669c6e7dc477bf

Blame Revision: D1941662

folly/experimental/fibers/FiberManagerMap.cpp
folly/io/async/EventBase.cpp
folly/io/async/EventBase.h

index 0f3e441ba559d30839b48adf44aaf7c494b16731..355facbcad39627bf5922f4f7a1142b14a142aaa 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <folly/experimental/fibers/FiberManagerMap.h>
+#include "FiberManagerMap.h"
 
+#include <cassert>
 #include <memory>
 #include <unordered_map>
 
+#include <folly/ThreadLocal.h>
+
 namespace folly { namespace fibers {
 
 namespace detail {
 
-thread_local std::unordered_map<folly::EventBase*, FiberManager*>
-    localFiberManagerMap;
+class LocalFiberManagerMapTag;
+folly::ThreadLocal<std::unordered_map<folly::EventBase*, FiberManager*>,
+  LocalFiberManagerMapTag> localFiberManagerMap;
 std::unordered_map<folly::EventBase*, std::unique_ptr<FiberManager>>
     fiberManagerMap;
 std::mutex fiberManagerMapMutex;
 
+class OnEventBaseDestructionCallback : public folly::EventBase::LoopCallback {
+ public:
+  explicit OnEventBaseDestructionCallback(folly::EventBase& evb)
+           : evb_(&evb) {}
+  void runLoopCallback() noexcept override {
+    for (auto& localMap : localFiberManagerMap.accessAllThreads()) {
+      localMap.erase(evb_);
+    }
+    std::unique_ptr<FiberManager> fm;
+    {
+      std::lock_guard<std::mutex> lg(fiberManagerMapMutex);
+      auto it = fiberManagerMap.find(evb_);
+      assert(it != fiberManagerMap.end());
+      fm = std::move(it->second);
+      fiberManagerMap.erase(it);
+    }
+    assert(fm.get() != nullptr);
+    fm->loopUntilNoReady();
+    delete this;
+  }
+ private:
+  folly::EventBase* evb_;
+};
+
 FiberManager* getFiberManagerThreadSafe(folly::EventBase& evb,
                                         const FiberManager::Options& opts) {
   std::lock_guard<std::mutex> lg(fiberManagerMapMutex);
@@ -42,6 +70,7 @@ FiberManager* getFiberManagerThreadSafe(folly::EventBase& evb,
   auto fiberManager =
       folly::make_unique<FiberManager>(std::move(loopController), opts);
   auto result = fiberManagerMap.emplace(&evb, std::move(fiberManager));
+  evb.runOnDestruction(new OnEventBaseDestructionCallback(evb));
   return result.first->second.get();
 }
 
@@ -49,13 +78,14 @@ FiberManager* getFiberManagerThreadSafe(folly::EventBase& evb,
 
 FiberManager& getFiberManager(folly::EventBase& evb,
                               const FiberManager::Options& opts) {
-  auto it = detail::localFiberManagerMap.find(&evb);
-  if (LIKELY(it != detail::localFiberManagerMap.end())) {
+  auto it = detail::localFiberManagerMap->find(&evb);
+  if (LIKELY(it != detail::localFiberManagerMap->end())) {
     return *(it->second);
   }
 
-  return *(detail::localFiberManagerMap[&evb] =
-               detail::getFiberManagerThreadSafe(evb, opts));
+  auto fm = detail::getFiberManagerThreadSafe(evb, opts);
+  detail::localFiberManagerMap->emplace(&evb, fm);
+  return *fm;
 }
 
 }}
index a3e5bdc92fd96b6b4bcd133e0f728d908310f069..d901650650fd59e6f70dd17dbd03f7de9e8fa844 100644 (file)
@@ -521,7 +521,7 @@ void EventBase::runInLoop(Cob&& cob, bool thisIteration) {
 }
 
 void EventBase::runOnDestruction(LoopCallback* callback) {
-  DCHECK(isInEventBaseThread());
+  std::lock_guard<std::mutex> lg(onDestructionCallbacksMutex_);
   callback->cancelLoopCallback();
   onDestructionCallbacks_.push_back(*callback);
 }
index 843ab464018bede18daeac0230f3721b7fcea2f8..9077b06cd34e3c082d1293a4794a148724018b3c 100644 (file)
@@ -725,6 +725,9 @@ bool runImmediatelyOrRunInEventBaseThreadAndWait(const Cob& fn);
 
   // Name of the thread running this EventBase
   std::string name_;
+
+  // allow runOnDestruction() to be called from any threads
+  std::mutex onDestructionCallbacksMutex_;
 };
 
 } // folly