Not to use EventBaseLocal on mobile
[folly.git] / folly / io / async / EventBaseLocal.cpp
1 /*
2  * Copyright 2015 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 #if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
18
19 #include <folly/io/async/EventBaseLocal.h>
20 #include <atomic>
21 #include <thread>
22
23 namespace folly { namespace detail {
24
25 EventBaseLocalBase::~EventBaseLocalBase() {
26   // There's a race condition if an EventBase and an EventBaseLocal destruct
27   // at the same time (each will lock eventBases_ and localStorageMutex_
28   // in the opposite order), so we dance around it with a loop and try_lock.
29   while (true) {
30     SYNCHRONIZED(eventBases_) {
31       auto it = eventBases_.begin();
32       while (it != eventBases_.end()) {
33         auto evb = *it;
34         if (evb->localStorageMutex_.try_lock()) {
35           evb->localStorage_.erase(key_);
36           evb->localStorageToDtor_.erase(this);
37           it = eventBases_.erase(it);
38           evb->localStorageMutex_.unlock();
39         } else {
40           ++it;
41         }
42       }
43
44       if (eventBases_.empty()) {
45         return;
46       }
47     }
48     std::this_thread::yield(); // let the other thread take the eventBases_ lock
49   }
50 }
51
52 void* EventBaseLocalBase::getVoid(EventBase& evb) {
53   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
54   auto it2 = evb.localStorage_.find(key_);
55   if (UNLIKELY(it2 != evb.localStorage_.end())) {
56     return it2->second.get();
57   }
58
59   return nullptr;
60 }
61
62 void EventBaseLocalBase::erase(EventBase& evb) {
63   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
64   evb.localStorage_.erase(key_);
65   evb.localStorageToDtor_.erase(this);
66
67   SYNCHRONIZED(eventBases_) {
68     eventBases_.erase(&evb);
69   }
70 }
71
72 void EventBaseLocalBase::onEventBaseDestruction(EventBase& evb) {
73   SYNCHRONIZED(eventBases_) {
74     eventBases_.erase(&evb);
75   }
76 }
77
78 void EventBaseLocalBase::setVoid(EventBase& evb, std::shared_ptr<void>&& ptr) {
79   std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
80   setVoidUnlocked(evb, std::move(ptr));
81 }
82
83 void EventBaseLocalBase::setVoidUnlocked(
84     EventBase& evb, std::shared_ptr<void>&& ptr) {
85
86   auto alreadyExists =
87     evb.localStorage_.find(key_) != evb.localStorage_.end();
88
89   evb.localStorage_.emplace(key_, std::move(ptr));
90
91   if (!alreadyExists) {
92     SYNCHRONIZED(eventBases_) {
93       eventBases_.insert(&evb);
94     }
95     evb.localStorageToDtor_.insert(this);
96   }
97 }
98
99 std::atomic<uint64_t> EventBaseLocalBase::keyCounter_{0};
100 }}
101
102 #endif // !__ANDROID__ && !ANDROID && !__APPLE__