proxygen
OpenSSLThreading.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 
18 
19 #include <memory>
20 #include <mutex>
21 
22 #include <folly/Portability.h>
23 #include <folly/SharedMutex.h>
24 #include <folly/SpinLock.h>
25 
26 #include <glog/logging.h>
27 
28 // We cannot directly use portability/openssl because it also depends on us.
29 // Therefore we directly use openssl includes. Order of includes is important
30 // here. See portability/openssl.h.
32 #include <openssl/crypto.h>
33 
34 #if !defined(OPENSSL_IS_BORINGSSL)
35 #define FOLLY_SSL_DETAIL_OPENSSL_IS_110 (OPENSSL_VERSION_NUMBER >= 0x10100000L)
36 #else
37 #define FOLLY_SSL_DETAIL_OPENSSL_IS_110 (false)
38 #endif
39 
40 // OpenSSL requires us to provide the implementation of CRYPTO_dynlock_value
41 // so it must be done in the global namespace.
44 };
45 
46 namespace folly {
47 namespace ssl {
48 namespace detail {
49 
50 static std::map<int, LockType>& lockTypes() {
51  static auto lockTypesInst = new std::map<int, LockType>();
52  return *lockTypesInst;
53 }
54 
55 void setLockTypes(std::map<int, LockType> inLockTypes) {
56 #if FOLLY_SSL_DETAIL_OPENSSL_IS_110
57  LOG(INFO) << "setLockTypes() is unsupported on OpenSSL >= 1.1.0. "
58  << "OpenSSL now uses platform native mutexes";
59 #endif
60 
61  lockTypes() = inLockTypes;
62 }
63 
64 bool isSSLLockDisabled(int lockId) {
65  const auto& sslLocks = lockTypes();
66  const auto it = sslLocks.find(lockId);
67  return it != sslLocks.end() && it->second == LockType::NONE;
68 }
69 
70 namespace {
71 struct SSLLock {
72  explicit SSLLock(LockType inLockType = LockType::MUTEX)
73  : lockType(inLockType) {}
74 
75  void lock(bool read) {
76  if (lockType == LockType::MUTEX) {
77  mutex.lock();
78  } else if (lockType == LockType::SPINLOCK) {
79  spinLock.lock();
80  } else if (lockType == LockType::SHAREDMUTEX) {
81  if (read) {
82  sharedMutex.lock_shared();
83  } else {
84  sharedMutex.lock();
85  }
86  }
87  // lockType == LOCK_NONE, no-op
88  }
89 
90  void unlock(bool read) {
91  if (lockType == LockType::MUTEX) {
92  mutex.unlock();
93  } else if (lockType == LockType::SPINLOCK) {
94  spinLock.unlock();
95  } else if (lockType == LockType::SHAREDMUTEX) {
96  if (read) {
97  sharedMutex.unlock_shared();
98  } else {
99  sharedMutex.unlock();
100  }
101  }
102  // lockType == LOCK_NONE, no-op
103  }
104 
109 };
110 } // namespace
111 
112 // Statics are unsafe in environments that call exit().
113 // If one thread calls exit() while another thread is
114 // references a member of SSLContext, bad things can happen.
115 // SSLContext runs in such environments.
116 // Instead of declaring a static member we "new" the static
117 // member so that it won't be destructed on exit().
118 static std::unique_ptr<SSLLock[]>& locks() {
119  static auto locksInst = new std::unique_ptr<SSLLock[]>();
120  return *locksInst;
121 }
122 
123 static void callbackLocking(int mode, int n, const char*, int) {
124  if (mode & CRYPTO_LOCK) {
125  locks()[size_t(n)].lock(mode & CRYPTO_READ);
126  } else {
127  locks()[size_t(n)].unlock(mode & CRYPTO_READ);
128  }
129 }
130 
131 static unsigned long callbackThreadID() {
132  return static_cast<unsigned long>(folly::getCurrentThreadID());
133 }
134 
135 static CRYPTO_dynlock_value* dyn_create(const char*, int) {
136  return new CRYPTO_dynlock_value;
137 }
138 
139 static void
140 dyn_lock(int mode, struct CRYPTO_dynlock_value* lock, const char*, int) {
141  if (lock != nullptr) {
142  if (mode & CRYPTO_LOCK) {
143  lock->mutex.lock();
144  } else {
145  lock->mutex.unlock();
146  }
147  }
148 }
149 
150 static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
151  delete lock;
152 }
153 
155  // static locking
156  locks() = std::make_unique<SSLLock[]>(size_t(CRYPTO_num_locks()));
157  for (auto it : lockTypes()) {
158  locks()[size_t(it.first)].lockType = it.second;
159  }
160  CRYPTO_set_id_callback(callbackThreadID);
161  CRYPTO_set_locking_callback(callbackLocking);
162  // dynamic locking
163  CRYPTO_set_dynlock_create_callback(dyn_create);
164  CRYPTO_set_dynlock_lock_callback(dyn_lock);
165  CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
166 }
167 
169  CRYPTO_set_id_callback(nullptr);
170  CRYPTO_set_locking_callback(nullptr);
171  CRYPTO_set_dynlock_create_callback(nullptr);
172  CRYPTO_set_dynlock_lock_callback(nullptr);
173  CRYPTO_set_dynlock_destroy_callback(nullptr);
174  locks().reset();
175 }
176 
177 } // namespace detail
178 } // namespace ssl
179 } // namespace folly
static CRYPTO_dynlock_value * dyn_create(const char *, int)
SharedMutex sharedMutex
static std::unique_ptr< SSLLock[]> & locks()
static std::map< int, LockType > & lockTypes()
static void dyn_destroy(struct CRYPTO_dynlock_value *lock, const char *, int)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
LockType lockType
FOLLY_ALWAYS_INLINE void unlock() const noexcept
Definition: SpinLock.h:52
folly::Optional< PskKeyExchangeMode > mode
static unsigned long callbackThreadID()
folly::SpinLock spinLock
std::mutex mutex
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
Definition: Synchronized.h:871
size_t read(T &out, folly::io::Cursor &cursor)
Definition: Types-inl.h:258
SharedMutexWritePriority SharedMutex
Definition: SharedMutex.h:1511
FOLLY_ALWAYS_INLINE void lock() const noexcept
Definition: SpinLock.h:49
static void callbackLocking(int mode, int n, const char *, int)
void setLockTypes(std::map< int, LockType > inLockTypes)
uint64_t getCurrentThreadID()
Definition: ThreadId.h:42
static void dyn_lock(int mode, struct CRYPTO_dynlock_value *lock, const char *, int)
bool isSSLLockDisabled(int lockId)