2747a4dbfbef86cb947eca95f1f19b93e08a7bf0
[folly.git] / folly / SpinLock.h
1 /*
2  * Copyright 2014 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 #pragma once
18
19 #include <boost/noncopyable.hpp>
20 #include <folly/Portability.h>
21
22 // This is a wrapper SpinLock implementation that works around the
23 // x64 limitation of the base folly MicroSpinLock. If that is available, this
24 // simply thinly wraps it. Otherwise, it uses the simplest analog available on
25 // iOS (or 32-bit Mac) or, failing that, POSIX (on Android et. al.)
26
27 #if __x86_64__
28 #include <folly/SmallLocks.h>
29
30 namespace folly {
31
32 class SpinLock {
33  public:
34   FOLLY_ALWAYS_INLINE SpinLock() {
35     lock_.init();
36   }
37   FOLLY_ALWAYS_INLINE void lock() const {
38     lock_.lock();
39   }
40   FOLLY_ALWAYS_INLINE void unlock() const {
41     lock_.unlock();
42   }
43   FOLLY_ALWAYS_INLINE bool trylock() const {
44     return lock_.try_lock();
45   }
46  private:
47   mutable folly::MicroSpinLock lock_;
48 };
49
50 }
51
52 #elif __APPLE__
53 #include <libkern/OSAtomic.h>
54
55 namespace folly {
56
57 class SpinLock {
58  public:
59   FOLLY_ALWAYS_INLINE SpinLock() : lock_(0) {}
60   FOLLY_ALWAYS_INLINE void lock() const {
61     OSSpinLockLock(&lock_);
62   }
63   FOLLY_ALWAYS_INLINE void unlock() const {
64     OSSpinLockUnlock(&lock_);
65   }
66   FOLLY_ALWAYS_INLINE bool trylock() const {
67     return OSSpinLockTry(&lock_);
68   }
69  private:
70   mutable OSSpinLock lock_;
71 };
72
73 }
74
75 #else
76 #include <pthread.h>
77 #include <glog/logging.h>
78
79 namespace folly {
80
81 class SpinLock {
82  public:
83   FOLLY_ALWAYS_INLINE SpinLock() {
84     pthread_mutex_init(&lock_, nullptr);
85   }
86   void lock() const {
87     int rc = pthread_mutex_lock(&lock_);
88     CHECK_EQ(0, rc);
89   }
90   FOLLY_ALWAYS_INLINE void unlock() const {
91     int rc = pthread_mutex_unlock(&lock_);
92     CHECK_EQ(0, rc);
93   }
94   FOLLY_ALWAYS_INLINE bool trylock() const {
95     int rc = pthread_mutex_trylock(&lock_);
96     CHECK_GE(rc, 0);
97     return rc == 0;
98   }
99  private:
100   mutable pthread_mutex_t lock_;
101 };
102
103 }
104
105 #endif
106
107 namespace folly {
108
109 class SpinLockGuard : private boost::noncopyable {
110  public:
111   FOLLY_ALWAYS_INLINE explicit SpinLockGuard(SpinLock& lock) :
112     lock_(lock) {
113     lock_.lock();
114   }
115   FOLLY_ALWAYS_INLINE ~SpinLockGuard() {
116     lock_.unlock();
117   }
118  private:
119   SpinLock& lock_;
120 };
121
122 }