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
40namespace folly {
41
42class 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
61template <typename LOCK>
62class 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
81typedef SpinLockGuardImpl<SpinLock> SpinLockGuard;
82
83} // namespace folly
84