LockTraits.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Copyright 2016-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. * This module provides a traits class for describing properties about mutex
  18. * classes.
  19. *
  20. * This is a primitive for building higher-level abstractions that can work
  21. * with a variety of mutex classes. For instance, this allows
  22. * folly::Synchronized to support a number of different mutex types.
  23. */
  24. #pragma once
  25. #include <chrono>
  26. #include <type_traits>
  27. #include <folly/functional/Invoke.h>
  28. // Android, OSX, and Cygwin don't have timed mutexes
  29. #if defined(ANDROID) || defined(__ANDROID__) || defined(__APPLE__) || \
  30. defined(__CYGWIN__)
  31. #define FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES 0
  32. #else
  33. #define FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES 1
  34. #endif
  35. namespace folly {
  36. namespace detail {
  37. namespace member {
  38. FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock, lock);
  39. FOLLY_CREATE_MEMBER_INVOKE_TRAITS(try_lock_for, try_lock_for);
  40. FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock_shared, lock_shared);
  41. FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock_upgrade, lock_upgrade);
  42. } // namespace member
  43. /**
  44. * An enum to describe the "level" of a mutex. The supported levels are
  45. * Unique - a normal mutex that supports only exclusive locking
  46. * Shared - a shared mutex which has shared locking and unlocking functions;
  47. * Upgrade - a mutex that has all the methods of the two above along with
  48. * support for upgradable locking
  49. */
  50. enum class MutexLevel { UNIQUE, SHARED, UPGRADE };
  51. /**
  52. * A template dispatch mechanism that is used to determine the level of the
  53. * mutex based on its interface. As decided by LockInterfaceDispatcher.
  54. */
  55. template <bool is_unique, bool is_shared, bool is_upgrade>
  56. struct MutexLevelValueImpl;
  57. template <>
  58. struct MutexLevelValueImpl<true, false, false> {
  59. static constexpr MutexLevel value = MutexLevel::UNIQUE;
  60. };
  61. template <>
  62. struct MutexLevelValueImpl<true, true, false> {
  63. static constexpr MutexLevel value = MutexLevel::SHARED;
  64. };
  65. template <>
  66. struct MutexLevelValueImpl<true, true, true> {
  67. static constexpr MutexLevel value = MutexLevel::UPGRADE;
  68. };
  69. /**
  70. * An internal helper class to help identify the interface supported by the
  71. * mutex. This is used in conjunction with the above MutexLevel
  72. * specializations and the LockTraitsImpl to determine what functions are
  73. * supported by objects of type Mutex
  74. */
  75. template <class Mutex>
  76. class LockInterfaceDispatcher {
  77. private:
  78. // assert that the mutex type has basic lock and unlock functions
  79. static_assert(
  80. member::lock::is_invocable<Mutex>::value,
  81. "The mutex type must support lock and unlock functions");
  82. using duration = std::chrono::milliseconds;
  83. public:
  84. static constexpr bool has_lock_unique = true;
  85. static constexpr bool has_lock_timed =
  86. member::try_lock_for::is_invocable<Mutex, duration>::value;
  87. static constexpr bool has_lock_shared =
  88. member::lock_shared::is_invocable<Mutex>::value;
  89. static constexpr bool has_lock_upgrade =
  90. member::lock_upgrade::is_invocable<Mutex>::value;
  91. };
  92. /**
  93. * LockTraitsImpl is the base that is used to desribe the interface used by
  94. * different mutex types. It accepts a MutexLevel argument and a boolean to
  95. * show whether the mutex is a timed mutex or not. The implementations are
  96. * partially specialized and inherit from the other implementations to get
  97. * similar functionality
  98. */
  99. template <class Mutex, MutexLevel level, bool is_timed>
  100. struct LockTraitsImpl;
  101. template <class Mutex>
  102. struct LockTraitsImpl<Mutex, MutexLevel::UNIQUE, false> {
  103. static constexpr bool is_timed{false};
  104. static constexpr bool is_shared{false};
  105. static constexpr bool is_upgrade{false};
  106. /**
  107. * Acquire the lock exclusively.
  108. */
  109. static void lock(Mutex& mutex) {
  110. mutex.lock();
  111. }
  112. /**
  113. * Release an exclusively-held lock.
  114. */
  115. static void unlock(Mutex& mutex) {
  116. mutex.unlock();
  117. }
  118. /**
  119. * Try to acquire the mutex
  120. */
  121. static bool try_lock(Mutex& mutex) {
  122. return mutex.try_lock();
  123. }
  124. };
  125. /**
  126. * Higher level mutexes have all the capabilities of the lower levels so
  127. * inherit
  128. */
  129. template <class Mutex>
  130. struct LockTraitsImpl<Mutex, MutexLevel::SHARED, false>
  131. : public LockTraitsImpl<Mutex, MutexLevel::UNIQUE, false> {
  132. static constexpr bool is_timed{false};
  133. static constexpr bool is_shared{true};
  134. static constexpr bool is_upgrade{false};
  135. /**
  136. * Acquire the lock in shared (read) mode.
  137. */
  138. static void lock_shared(Mutex& mutex) {
  139. mutex.lock_shared();
  140. }
  141. /**
  142. * Release a lock held in shared mode.
  143. */
  144. static void unlock_shared(Mutex& mutex) {
  145. mutex.unlock_shared();
  146. }
  147. /**
  148. * Try to acquire the mutex in shared mode
  149. */
  150. static bool try_lock_shared(Mutex& mutex) {
  151. return mutex.try_lock_shared();
  152. }
  153. };
  154. /**
  155. * The following methods are supported. There are a few methods
  156. *
  157. * m.lock_upgrade()
  158. * m.unlock_upgrade()
  159. * m.try_lock_upgrade()
  160. *
  161. * m.unlock_upgrade_and_lock()
  162. *
  163. * m.unlock_and_lock_upgrade()
  164. * m.unlock_and_lock_shared()
  165. * m.unlock_upgrade_and_lock_shared()
  166. *
  167. * m.try_lock_upgrade_for(rel_time)
  168. * m.try_unlock_upgrade_and_lock_for(rel_time)
  169. *
  170. * Upgrading a shared lock is likely to deadlock when there is more than one
  171. * thread performing an upgrade. This applies both to upgrading a shared lock
  172. * to an upgrade lock and to upgrading a shared lock to a unique lock.
  173. *
  174. * Therefore, none of the following methods is supported:
  175. * unlock_shared_and_lock_upgrade
  176. * unlock_shared_and_lock
  177. * try_unlock_shared_and_lock_upgrade
  178. * try_unlock_shared_and_lock
  179. * try_unlock_shared_and_lock_upgrade_for
  180. * try_unlock_shared_and_lock_for
  181. */
  182. template <class Mutex>
  183. struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, false>
  184. : public LockTraitsImpl<Mutex, MutexLevel::SHARED, false> {
  185. static constexpr bool is_timed{false};
  186. static constexpr bool is_shared{true};
  187. static constexpr bool is_upgrade{true};
  188. /**
  189. * Acquire the lock in upgradable mode.
  190. */
  191. static void lock_upgrade(Mutex& mutex) {
  192. mutex.lock_upgrade();
  193. }
  194. /**
  195. * Release the lock in upgrade mode
  196. */
  197. static void unlock_upgrade(Mutex& mutex) {
  198. mutex.unlock_upgrade();
  199. }
  200. /**
  201. * Try and acquire the lock in upgrade mode
  202. */
  203. static bool try_lock_upgrade(Mutex& mutex) {
  204. return mutex.try_lock_upgrade();
  205. }
  206. /**
  207. * Upgrade from an upgradable state to an exclusive state
  208. */
  209. static void unlock_upgrade_and_lock(Mutex& mutex) {
  210. mutex.unlock_upgrade_and_lock();
  211. }
  212. /**
  213. * Downgrade from an exclusive state to an upgrade state
  214. */
  215. static void unlock_and_lock_upgrade(Mutex& mutex) {
  216. mutex.unlock_and_lock_upgrade();
  217. }
  218. /**
  219. * Downgrade from an exclusive state to a shared state
  220. */
  221. static void unlock_and_lock_shared(Mutex& mutex) {
  222. mutex.unlock_and_lock_shared();
  223. }
  224. /**
  225. * Downgrade from an upgrade state to a shared state
  226. */
  227. static void unlock_upgrade_and_lock_shared(Mutex& mutex) {
  228. mutex.unlock_upgrade_and_lock_shared();
  229. }
  230. };
  231. template <class Mutex>
  232. struct LockTraitsImpl<Mutex, MutexLevel::UNIQUE, true>
  233. : public LockTraitsImpl<Mutex, MutexLevel::UNIQUE, false> {
  234. static constexpr bool is_timed{true};
  235. static constexpr bool is_shared{false};
  236. static constexpr bool is_upgrade{false};
  237. /**
  238. * Acquire the lock exclusively, with a timeout.
  239. *
  240. * Returns true or false indicating if the lock was acquired or not.
  241. */
  242. template <class Rep, class Period>
  243. static bool try_lock_for(
  244. Mutex& mutex,
  245. const std::chrono::duration<Rep, Period>& timeout) {
  246. return mutex.try_lock_for(timeout);
  247. }
  248. };
  249. /**
  250. * Note that there is no deadly diamond here because all the structs only have
  251. * static functions and static bools which are going to be overridden by the
  252. * lowest level implementation
  253. */
  254. template <class Mutex>
  255. struct LockTraitsImpl<Mutex, MutexLevel::SHARED, true>
  256. : public LockTraitsImpl<Mutex, MutexLevel::SHARED, false>,
  257. public LockTraitsImpl<Mutex, MutexLevel::UNIQUE, true> {
  258. static constexpr bool is_timed{true};
  259. static constexpr bool is_shared{true};
  260. static constexpr bool is_upgrade{false};
  261. /**
  262. * Acquire the lock exclusively, with a timeout.
  263. *
  264. * Returns true or false indicating if the lock was acquired or not.
  265. */
  266. template <class Rep, class Period>
  267. static bool try_lock_for(
  268. Mutex& mutex,
  269. const std::chrono::duration<Rep, Period>& timeout) {
  270. return mutex.try_lock_for(timeout);
  271. }
  272. /**
  273. * Acquire the lock in shared (read) mode, with a timeout.
  274. *
  275. * Returns true or false indicating if the lock was acquired or not.
  276. */
  277. template <class Rep, class Period>
  278. static bool try_lock_shared_for(
  279. Mutex& mutex,
  280. const std::chrono::duration<Rep, Period>& timeout) {
  281. return mutex.try_lock_shared_for(timeout);
  282. }
  283. };
  284. template <class Mutex>
  285. struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, true>
  286. : public LockTraitsImpl<Mutex, MutexLevel::UPGRADE, false>,
  287. public LockTraitsImpl<Mutex, MutexLevel::SHARED, true> {
  288. static constexpr bool is_timed{true};
  289. static constexpr bool is_shared{true};
  290. static constexpr bool is_upgrade{true};
  291. /**
  292. * Acquire the lock in upgrade mode with a timeout
  293. *
  294. * Returns true or false indicating whether the lock was acquired or not
  295. */
  296. template <class Rep, class Period>
  297. static bool try_lock_upgrade_for(
  298. Mutex& mutex,
  299. const std::chrono::duration<Rep, Period>& timeout) {
  300. return mutex.try_lock_upgrade_for(timeout);
  301. }
  302. /**
  303. * Try to upgrade from an upgradable state to an exclusive state.
  304. *
  305. * Returns true or false indicating whether the lock was acquired or not
  306. */
  307. template <class Rep, class Period>
  308. static bool try_unlock_upgrade_and_lock_for(
  309. Mutex& mutex,
  310. const std::chrono::duration<Rep, Period>& timeout) {
  311. return mutex.try_unlock_upgrade_and_lock_for(timeout);
  312. }
  313. };
  314. /**
  315. * Unlock helpers
  316. *
  317. * These help in determining whether it is safe for Synchronized::LockedPtr
  318. * instances to be move assigned from one another. It is safe if they both
  319. * have the same unlock policy, and it is not if they don't have the same
  320. * unlock policy. For example
  321. *
  322. * auto wlock = synchronized.wlock();
  323. * wlock.unlock();
  324. *
  325. * wlock = synchronized.rlock();
  326. *
  327. * This code would try to release the shared lock with a call to unlock(),
  328. * resulting in possibly undefined behavior. By allowing the LockPolicy
  329. * classes (defined below) to know what their unlocking behavior is, we can
  330. * prevent against this by disabling unsafe conversions to and from
  331. * incompatible LockedPtr types (they are incompatible if the underlying
  332. * LockPolicy has different unlock policies.
  333. */
  334. template <template <typename...> class LockTraits>
  335. struct UnlockPolicyExclusive {
  336. template <typename Mutex>
  337. static void unlock(Mutex& mutex) {
  338. LockTraits<Mutex>::unlock(mutex);
  339. }
  340. };
  341. template <template <typename...> class LockTraits>
  342. struct UnlockPolicyShared {
  343. template <typename Mutex>
  344. static void unlock(Mutex& mutex) {
  345. LockTraits<Mutex>::unlock_shared(mutex);
  346. }
  347. };
  348. template <template <typename...> class LockTraits>
  349. struct UnlockPolicyUpgrade {
  350. template <typename Mutex>
  351. static void unlock(Mutex& mutex) {
  352. LockTraits<Mutex>::unlock_upgrade(mutex);
  353. }
  354. };
  355. } // namespace detail
  356. /**
  357. * LockTraits describes details about a particular mutex type.
  358. *
  359. * The default implementation automatically attempts to detect traits
  360. * based on the presence of various member functions.
  361. *
  362. * You can specialize LockTraits to provide custom behavior for lock
  363. * classes that do not use the standard method names
  364. * (lock()/unlock()/lock_shared()/unlock_shared()/try_lock_for())
  365. *
  366. *
  367. * LockTraits contains the following members variables:
  368. * - static constexpr bool is_shared
  369. * True if the lock supports separate shared vs exclusive locking states.
  370. * - static constexpr bool is_timed
  371. * True if the lock supports acquiring the lock with a timeout.
  372. * - static constexpr bool is_upgrade
  373. * True if the lock supports an upgradable state
  374. *
  375. * The following static methods always exist:
  376. * - lock(Mutex& mutex)
  377. * - unlock(Mutex& mutex)
  378. * - try_lock(Mutex& mutex)
  379. *
  380. * The following static methods may exist, depending on is_shared, is_timed
  381. * and is_upgrade:
  382. * - lock_shared()
  383. * - try_lock_shared()
  384. *
  385. * - try_lock_for()
  386. * - try_lock_shared_for()
  387. *
  388. * - lock_upgrade()
  389. * - try_lock_upgrade()
  390. * - unlock_upgrade_and_lock()
  391. * - unlock_and_lock_upgrade()
  392. * - unlock_and_lock_shared()
  393. * - unlock_upgrade_and_lock_shared()
  394. *
  395. * - try_lock_upgrade_for()
  396. * - try_unlock_upgrade_and_lock_for()
  397. *
  398. * - unlock_shared()
  399. * - unlock_upgrade()
  400. */
  401. /**
  402. * Decoupling LockTraits and LockTraitsBase so that if people want to fully
  403. * specialize LockTraits then they can inherit from LockTraitsBase instead
  404. * of LockTraits with all the same goodies :)
  405. */
  406. template <class Mutex>
  407. struct LockTraitsBase
  408. : public detail::LockTraitsImpl<
  409. Mutex,
  410. detail::MutexLevelValueImpl<
  411. detail::LockInterfaceDispatcher<Mutex>::has_lock_unique,
  412. detail::LockInterfaceDispatcher<Mutex>::has_lock_shared,
  413. detail::LockInterfaceDispatcher<Mutex>::has_lock_upgrade>::value,
  414. detail::LockInterfaceDispatcher<Mutex>::has_lock_timed> {};
  415. template <class Mutex>
  416. struct LockTraits : public LockTraitsBase<Mutex> {};
  417. /*
  418. * Lock policy classes.
  419. *
  420. * These can be used as template parameters to provide compile-time
  421. * selection over the type of lock operation to perform.
  422. */
  423. /**
  424. * A lock policy that performs exclusive lock operations.
  425. */
  426. struct LockPolicyExclusive : detail::UnlockPolicyExclusive<LockTraits> {
  427. using UnlockPolicy = detail::UnlockPolicyExclusive<LockTraits>;
  428. template <class Mutex>
  429. static std::true_type lock(Mutex& mutex) {
  430. LockTraits<Mutex>::lock(mutex);
  431. return std::true_type{};
  432. }
  433. template <class Mutex, class Rep, class Period>
  434. static bool try_lock_for(
  435. Mutex& mutex,
  436. const std::chrono::duration<Rep, Period>& timeout) {
  437. return LockTraits<Mutex>::try_lock_for(mutex, timeout);
  438. }
  439. };
  440. /**
  441. * A lock policy that performs shared lock operations.
  442. * This policy only works with shared mutex types.
  443. */
  444. struct LockPolicyShared : detail::UnlockPolicyShared<LockTraits> {
  445. using UnlockPolicy = detail::UnlockPolicyShared<LockTraits>;
  446. template <class Mutex>
  447. static std::true_type lock(Mutex& mutex) {
  448. LockTraits<Mutex>::lock_shared(mutex);
  449. return std::true_type{};
  450. }
  451. template <class Mutex, class Rep, class Period>
  452. static bool try_lock_for(
  453. Mutex& mutex,
  454. const std::chrono::duration<Rep, Period>& timeout) {
  455. return LockTraits<Mutex>::try_lock_shared_for(mutex, timeout);
  456. }
  457. };
  458. /**
  459. * A lock policy with the following mapping
  460. *
  461. * lock() -> lock_upgrade()
  462. * unlock() -> unlock_upgrade()
  463. * try_lock_for -> try_lock_upgrade_for()
  464. */
  465. struct LockPolicyUpgrade : detail::UnlockPolicyUpgrade<LockTraits> {
  466. using UnlockPolicy = detail::UnlockPolicyUpgrade<LockTraits>;
  467. template <class Mutex>
  468. static std::true_type lock(Mutex& mutex) {
  469. LockTraits<Mutex>::lock_upgrade(mutex);
  470. return std::true_type{};
  471. }
  472. template <class Mutex, class Rep, class Period>
  473. static bool try_lock_for(
  474. Mutex& mutex,
  475. const std::chrono::duration<Rep, Period>& timeout) {
  476. return LockTraits<Mutex>::try_lock_upgrade_for(mutex, timeout);
  477. }
  478. };
  479. /*****************************************************************************
  480. * Policies for optional mutex locking
  481. ****************************************************************************/
  482. /**
  483. * A lock policy that tries to acquire write locks and returns true or false
  484. * based on whether the lock operation succeeds
  485. */
  486. struct LockPolicyTryExclusive : detail::UnlockPolicyExclusive<LockTraits> {
  487. using UnlockPolicy = detail::UnlockPolicyExclusive<LockTraits>;
  488. template <class Mutex>
  489. static bool lock(Mutex& mutex) {
  490. return LockTraits<Mutex>::try_lock(mutex);
  491. }
  492. };
  493. /**
  494. * A lock policy that tries to acquire a read lock and returns true or false
  495. * based on whether the lock operation succeeds
  496. */
  497. struct LockPolicyTryShared : detail::UnlockPolicyShared<LockTraits> {
  498. using UnlockPolicy = detail::UnlockPolicyShared<LockTraits>;
  499. template <class Mutex>
  500. static bool lock(Mutex& mutex) {
  501. return LockTraits<Mutex>::try_lock_shared(mutex);
  502. }
  503. };
  504. /**
  505. * A lock policy that tries to acquire an upgrade lock and returns true or
  506. * false based on whether the lock operation succeeds
  507. */
  508. struct LockPolicyTryUpgrade : detail::UnlockPolicyUpgrade<LockTraits> {
  509. using UnlockPolicy = detail::UnlockPolicyUpgrade<LockTraits>;
  510. template <class Mutex>
  511. static bool lock(Mutex& mutex) {
  512. return LockTraits<Mutex>::try_lock_upgrade(mutex);
  513. }
  514. };
  515. /*****************************************************************************
  516. * Policies for all the transitions from possible mutex levels
  517. ****************************************************************************/
  518. /**
  519. * A lock policy with the following mapping
  520. *
  521. * lock() -> unlock_upgrade_and_lock()
  522. * unlock() -> unlock()
  523. * try_lock_for -> try_unlock_upgrade_and_lock_for()
  524. */
  525. struct LockPolicyFromUpgradeToExclusive : LockPolicyExclusive {
  526. template <class Mutex>
  527. static std::true_type lock(Mutex& mutex) {
  528. LockTraits<Mutex>::unlock_upgrade_and_lock(mutex);
  529. return std::true_type{};
  530. }
  531. template <class Mutex, class Rep, class Period>
  532. static bool try_lock_for(
  533. Mutex& mutex,
  534. const std::chrono::duration<Rep, Period>& timeout) {
  535. return LockTraits<Mutex>::try_unlock_upgrade_and_lock_for(mutex, timeout);
  536. }
  537. };
  538. /**
  539. * A lock policy with the following mapping
  540. *
  541. * lock() -> unlock_and_lock_upgrade()
  542. * unlock() -> unlock_upgrade()
  543. * try_lock_for -> unlock_and_lock_upgrade()
  544. */
  545. struct LockPolicyFromExclusiveToUpgrade : LockPolicyUpgrade {
  546. template <class Mutex>
  547. static std::true_type lock(Mutex& mutex) {
  548. LockTraits<Mutex>::unlock_and_lock_upgrade(mutex);
  549. return std::true_type{};
  550. }
  551. template <class Mutex, class Rep, class Period>
  552. static bool try_lock_for(
  553. Mutex& mutex,
  554. const std::chrono::duration<Rep, Period>&) {
  555. LockTraits<Mutex>::unlock_and_lock_upgrade(mutex);
  556. // downgrade should be non blocking and should succeed
  557. return true;
  558. }
  559. };
  560. /**
  561. * A lock policy with the following mapping
  562. *
  563. * lock() -> unlock_upgrade_and_lock_shared()
  564. * unlock() -> unlock_shared()
  565. * try_lock_for -> unlock_upgrade_and_lock_shared()
  566. */
  567. struct LockPolicyFromUpgradeToShared : LockPolicyShared {
  568. template <class Mutex>
  569. static std::true_type lock(Mutex& mutex) {
  570. LockTraits<Mutex>::unlock_upgrade_and_lock_shared(mutex);
  571. return std::true_type{};
  572. }
  573. template <class Mutex, class Rep, class Period>
  574. static bool try_lock_for(
  575. Mutex& mutex,
  576. const std::chrono::duration<Rep, Period>&) {
  577. LockTraits<Mutex>::unlock_upgrade_and_lock_shared(mutex);
  578. // downgrade should be non blocking and should succeed
  579. return true;
  580. }
  581. };
  582. /**
  583. * A lock policy with the following mapping
  584. *
  585. * lock() -> unlock_and_lock_shared()
  586. * unlock() -> unlock_shared()
  587. * try_lock_for() -> unlock_and_lock_shared()
  588. */
  589. struct LockPolicyFromExclusiveToShared : LockPolicyShared {
  590. template <class Mutex>
  591. static std::true_type lock(Mutex& mutex) {
  592. LockTraits<Mutex>::unlock_and_lock_shared(mutex);
  593. return std::true_type{};
  594. }
  595. template <class Mutex, class Rep, class Period>
  596. static bool try_lock_for(
  597. Mutex& mutex,
  598. const std::chrono::duration<Rep, Period>&) {
  599. LockTraits<Mutex>::unlock_and_lock_shared(mutex);
  600. // downgrade should be non blocking and should succeed
  601. return true;
  602. }
  603. };
  604. } // namespace folly