proxygen
Semaphore.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present 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 #include <folly/fibers/Semaphore.h>
17 
18 namespace folly {
19 namespace fibers {
20 
22  // If we signalled a release, notify the waitlist
23  auto waitListLock = waitList_.wlock();
24  auto& waitList = *waitListLock;
25 
26  auto testVal = tokens_.load(std::memory_order_acquire);
27  if (testVal != 0) {
28  return false;
29  }
30 
31  if (waitList.empty()) {
32  // If the waitlist is now empty, ensure the token count increments
33  // No need for CAS here as we will always be under the mutex
34  CHECK(tokens_.compare_exchange_strong(
35  testVal, testVal + 1, std::memory_order_relaxed));
36  } else {
37  // trigger waiter if there is one
38  waitList.front()->post();
39  waitList.pop();
40  }
41  return true;
42 }
43 
45  auto oldVal = tokens_.load(std::memory_order_acquire);
46  do {
47  if (oldVal == 0) {
48  if (signalSlow()) {
49  break;
50  }
51  }
52  } while (!tokens_.compare_exchange_weak(
53  oldVal,
54  oldVal + 1,
55  std::memory_order_release,
56  std::memory_order_acquire));
57 }
58 
60  // Slow path, create a baton and acquire a mutex to update the wait list
61  folly::fibers::Baton waitBaton;
62 
63  {
64  auto waitListLock = waitList_.wlock();
65  auto& waitList = *waitListLock;
66 
67  auto testVal = tokens_.load(std::memory_order_acquire);
68  if (testVal != 0) {
69  return false;
70  }
71  // prepare baton and add to queue
72  waitList.push(&waitBaton);
73  }
74  // If we managed to create a baton, wait on it
75  // This has to be done here so the mutex has been released
76  waitBaton.wait();
77  return true;
78 }
79 
81  auto oldVal = tokens_.load(std::memory_order_acquire);
82  do {
83  if (oldVal == 0) {
84  // If waitSlow fails it is because the token is non-zero by the time
85  // the lock is taken, so we can just continue round the loop
86  if (waitSlow()) {
87  break;
88  }
89  }
90  } while (!tokens_.compare_exchange_weak(
91  oldVal,
92  oldVal - 1,
93  std::memory_order_release,
94  std::memory_order_acquire));
95 }
96 
97 size_t Semaphore::getCapacity() const {
98  return capacity_;
99 }
100 
101 } // namespace fibers
102 } // namespace folly
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::atomic< int64_t > tokens_
Definition: Semaphore.h:56
size_t getCapacity() const
Definition: Semaphore.cpp:97
folly::Synchronized< std::queue< folly::fibers::Baton * > > waitList_
Definition: Semaphore.h:57