1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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 | /* |
18 | * N.B. You most likely do _not_ want to use SpinLock or any other |
19 | * kind of spinlock. Use std::mutex instead. |
20 | * |
21 | * In short, spinlocks in preemptive multi-tasking operating systems |
22 | * have serious problems and fast mutexes like std::mutex are almost |
23 | * certainly the better choice, because letting the OS scheduler put a |
24 | * thread to sleep is better for system responsiveness and throughput |
25 | * than wasting a timeslice repeatedly querying a lock held by a |
26 | * thread that's blocked, and you can't prevent userspace |
27 | * programs blocking. |
28 | * |
29 | * Spinlocks in an operating system kernel make much more sense than |
30 | * they do in userspace. |
31 | */ |
32 | |
33 | #pragma once |
34 | |
35 | #include <type_traits> |
36 | |
37 | #include <folly/Portability.h> |
38 | #include <folly/synchronization/SmallLocks.h> |
39 | |
40 | namespace folly { |
41 | |
42 | class SpinLock { |
43 | public: |
44 | FOLLY_ALWAYS_INLINE SpinLock() noexcept { |
45 | lock_.init(); |
46 | } |
47 | FOLLY_ALWAYS_INLINE void lock() const noexcept { |
48 | lock_.lock(); |
49 | } |
50 | FOLLY_ALWAYS_INLINE void unlock() const noexcept { |
51 | lock_.unlock(); |
52 | } |
53 | FOLLY_ALWAYS_INLINE bool try_lock() const noexcept { |
54 | return lock_.try_lock(); |
55 | } |
56 | |
57 | private: |
58 | mutable folly::MicroSpinLock lock_; |
59 | }; |
60 | |
61 | template <typename LOCK> |
62 | class SpinLockGuardImpl { |
63 | public: |
64 | FOLLY_ALWAYS_INLINE explicit SpinLockGuardImpl(LOCK& lock) noexcept( |
65 | noexcept(lock.lock())) |
66 | : lock_(lock) { |
67 | lock_.lock(); |
68 | } |
69 | |
70 | SpinLockGuardImpl(const SpinLockGuardImpl&) = delete; |
71 | SpinLockGuardImpl& operator=(const SpinLockGuardImpl&) = delete; |
72 | |
73 | FOLLY_ALWAYS_INLINE ~SpinLockGuardImpl() { |
74 | lock_.unlock(); |
75 | } |
76 | |
77 | private: |
78 | LOCK& lock_; |
79 | }; |
80 | |
81 | typedef SpinLockGuardImpl<SpinLock> SpinLockGuard; |
82 | |
83 | } // namespace folly |
84 | |