1 | /* |
2 | * Copyright 2014-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 | |
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 <boost/noncopyable.hpp> |
38 | |
39 | #include <folly/Portability.h> |
40 | #include <folly/synchronization/SmallLocks.h> |
41 | |
42 | namespace folly { |
43 | |
44 | class SpinLock { |
45 | public: |
46 | FOLLY_ALWAYS_INLINE SpinLock() noexcept { |
47 | lock_.init(); |
48 | } |
49 | FOLLY_ALWAYS_INLINE void lock() const noexcept { |
50 | lock_.lock(); |
51 | } |
52 | FOLLY_ALWAYS_INLINE void unlock() const noexcept { |
53 | lock_.unlock(); |
54 | } |
55 | FOLLY_ALWAYS_INLINE bool try_lock() const noexcept { |
56 | return lock_.try_lock(); |
57 | } |
58 | |
59 | private: |
60 | mutable folly::MicroSpinLock lock_; |
61 | }; |
62 | |
63 | template <typename LOCK> |
64 | class SpinLockGuardImpl : private boost::noncopyable { |
65 | public: |
66 | FOLLY_ALWAYS_INLINE explicit SpinLockGuardImpl(LOCK& lock) noexcept( |
67 | noexcept(lock.lock())) |
68 | : lock_(lock) { |
69 | lock_.lock(); |
70 | } |
71 | FOLLY_ALWAYS_INLINE ~SpinLockGuardImpl() { |
72 | lock_.unlock(); |
73 | } |
74 | |
75 | private: |
76 | LOCK& lock_; |
77 | }; |
78 | |
79 | typedef SpinLockGuardImpl<SpinLock> SpinLockGuard; |
80 | |
81 | } // namespace folly |
82 | |