folly copyright 2015 -> copyright 2016
[folly.git] / folly / io / async / EventBaseLocal.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/io/async/EventBaseLocal.h>
18 #include <atomic>
19 #include <thread>
20
21 namespace folly { namespace detail {
22
23 EventBaseLocalBase::~EventBaseLocalBase() {
24   // There's a race condition if an EventBase and an EventBaseLocal destruct
25   // at the same time (each will lock eventBases_ and localStorageMutex_
26   // in the opposite order), so we dance around it with a loop and try_lock.
27   while (true) {
28     SYNCHRONIZED(eventBases_) {
29       auto it = eventBases_.begin();
30       while (it != eventBases_.end()) {
31         auto evb = *it;
32         if (evb->localStorageMutex_.try_lock()) {
33           evb->localStorage_.erase(key_);
34           evb->localStorageToDtor_.erase(this);
35           it = eventBases_.erase(it);
36           evb->localStorageMutex_.unlock();
37         } else {
38           ++it;
39         }
40       }
41
42       if (eventBases_.empty()) {
43         return;
44       }
45     }
46     std::this_thread::yield(); // let the other thread take the eventBases_ lock
47   }
48 }
49
50 void* EventBaseLocalBase::getVoid(EventBase& evb) {
51   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
52   auto it2 = evb.localStorage_.find(key_);
53   if (UNLIKELY(it2 != evb.localStorage_.end())) {
54     return it2->second.get();
55   }
56
57   return nullptr;
58 }
59
60 void EventBaseLocalBase::erase(EventBase& evb) {
61   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
62   evb.localStorage_.erase(key_);
63   evb.localStorageToDtor_.erase(this);
64
65   SYNCHRONIZED(eventBases_) {
66     eventBases_.erase(&evb);
67   }
68 }
69
70 void EventBaseLocalBase::onEventBaseDestruction(EventBase& evb) {
71   SYNCHRONIZED(eventBases_) {
72     eventBases_.erase(&evb);
73   }
74 }
75
76 void EventBaseLocalBase::setVoid(EventBase& evb, std::shared_ptr<void>&& ptr) {
77   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
78   setVoidUnlocked(evb, std::move(ptr));
79 }
80
81 void EventBaseLocalBase::setVoidUnlocked(
82     EventBase& evb, std::shared_ptr<void>&& ptr) {
83
84   auto alreadyExists =
85     evb.localStorage_.find(key_) != evb.localStorage_.end();
86
87   evb.localStorage_.emplace(key_, std::move(ptr));
88
89   if (!alreadyExists) {
90     SYNCHRONIZED(eventBases_) {
91       eventBases_.insert(&evb);
92     }
93     evb.localStorageToDtor_.insert(this);
94   }
95 }
96
97 std::atomic<uint64_t> EventBaseLocalBase::keyCounter_{0};
98 }}