Switch to the try_wait_for and try_wait_until Baton APIs
[folly.git] / folly / MicroLock.cpp
1 /*
2  * Copyright 2017 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/MicroLock.h>
18 #include <thread>
19
20 #include <folly/portability/Asm.h>
21
22 namespace folly {
23
24 void MicroLockCore::lockSlowPath(uint32_t oldWord,
25                                  detail::Futex<>* wordPtr,
26                                  uint32_t slotHeldBit,
27                                  unsigned maxSpins,
28                                  unsigned maxYields) {
29   uint32_t newWord;
30   unsigned spins = 0;
31   uint32_t slotWaitBit = slotHeldBit << 1;
32
33 retry:
34   if ((oldWord & slotHeldBit) != 0) {
35     ++spins;
36     if (spins > maxSpins + maxYields) {
37       // Somebody appears to have the lock.  Block waiting for the
38       // holder to unlock the lock.  We set heldbit(slot) so that the
39       // lock holder knows to FUTEX_WAKE us.
40       newWord = oldWord | slotWaitBit;
41       if (newWord != oldWord) {
42         if (!wordPtr->compare_exchange_weak(oldWord,
43                                             newWord,
44                                             std::memory_order_relaxed,
45                                             std::memory_order_relaxed)) {
46           goto retry;
47         }
48       }
49       (void)wordPtr->futexWait(newWord, slotHeldBit);
50     } else if (spins > maxSpins) {
51       // sched_yield(), but more portable
52       std::this_thread::yield();
53     } else {
54       folly::asm_volatile_pause();
55     }
56     oldWord = wordPtr->load(std::memory_order_relaxed);
57     goto retry;
58   }
59
60   newWord = oldWord | slotHeldBit;
61   if (!wordPtr->compare_exchange_weak(oldWord,
62                                       newWord,
63                                       std::memory_order_acquire,
64                                       std::memory_order_relaxed)) {
65     goto retry;
66   }
67 }
68 } // namespace folly