Synchronized.h 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755
  1. /*
  2. * Copyright 2011-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 implements a Synchronized abstraction useful in
  18. * mutex-based concurrency.
  19. *
  20. * The Synchronized<T, Mutex> class is the primary public API exposed by this
  21. * module. See folly/docs/Synchronized.md for a more complete explanation of
  22. * this class and its benefits.
  23. */
  24. #pragma once
  25. #include <folly/Function.h>
  26. #include <folly/Likely.h>
  27. #include <folly/LockTraits.h>
  28. #include <folly/Preprocessor.h>
  29. #include <folly/SharedMutex.h>
  30. #include <folly/Traits.h>
  31. #include <folly/Utility.h>
  32. #include <folly/container/Foreach.h>
  33. #include <folly/functional/ApplyTuple.h>
  34. #include <glog/logging.h>
  35. #include <array>
  36. #include <mutex>
  37. #include <tuple>
  38. #include <type_traits>
  39. #include <utility>
  40. namespace folly {
  41. template <class LockedType, class Mutex, class LockPolicy>
  42. class LockedPtrBase;
  43. template <class LockedType, class LockPolicy>
  44. class LockedPtr;
  45. /**
  46. * Public version of LockInterfaceDispatcher that contains the MutexLevel enum
  47. * for the passed in mutex type
  48. *
  49. * This is decoupled from MutexLevelValueImpl in LockTraits.h because this
  50. * ensures that a heterogenous mutex with a different API can be used. For
  51. * example - if a mutex does not have a lock_shared() method but the
  52. * LockTraits specialization for it supports a static non member
  53. * lock_shared(Mutex&) it can be used as a shared mutex and will provide
  54. * rlock() and wlock() functions.
  55. */
  56. template <class Mutex>
  57. using MutexLevelValue = detail::MutexLevelValueImpl<
  58. true,
  59. LockTraits<Mutex>::is_shared,
  60. LockTraits<Mutex>::is_upgrade>;
  61. /**
  62. * SynchronizedBase is a helper parent class for Synchronized<T>.
  63. *
  64. * It provides wlock() and rlock() methods for shared mutex types,
  65. * or lock() methods for purely exclusive mutex types.
  66. */
  67. template <class Subclass, detail::MutexLevel level>
  68. class SynchronizedBase;
  69. /**
  70. * SynchronizedBase specialization for shared mutex types.
  71. *
  72. * This class provides wlock() and rlock() methods for acquiring the lock and
  73. * accessing the data.
  74. */
  75. template <class Subclass>
  76. class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
  77. public:
  78. using LockedPtr = ::folly::LockedPtr<Subclass, LockPolicyExclusive>;
  79. using ConstWLockedPtr =
  80. ::folly::LockedPtr<const Subclass, LockPolicyExclusive>;
  81. using ConstLockedPtr = ::folly::LockedPtr<const Subclass, LockPolicyShared>;
  82. using TryWLockedPtr = ::folly::LockedPtr<Subclass, LockPolicyTryExclusive>;
  83. using ConstTryWLockedPtr =
  84. ::folly::LockedPtr<const Subclass, LockPolicyTryExclusive>;
  85. using TryRLockedPtr = ::folly::LockedPtr<const Subclass, LockPolicyTryShared>;
  86. /**
  87. * Acquire an exclusive lock, and return a LockedPtr that can be used to
  88. * safely access the datum.
  89. *
  90. * LockedPtr offers operator -> and * to provide access to the datum.
  91. * The lock will be released when the LockedPtr is destroyed.
  92. */
  93. LockedPtr wlock() {
  94. return LockedPtr(static_cast<Subclass*>(this));
  95. }
  96. /**
  97. * Attempts to acquire the lock in exclusive mode. If acquisition is
  98. * unsuccessful, the returned LockedPtr will be null.
  99. *
  100. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  101. * validity.)
  102. */
  103. TryWLockedPtr tryWLock() {
  104. return TryWLockedPtr{static_cast<Subclass*>(this)};
  105. }
  106. /**
  107. * Acquire a read lock, and return a ConstLockedPtr that can be used to
  108. * safely access the datum.
  109. */
  110. ConstLockedPtr rlock() const {
  111. return ConstLockedPtr(static_cast<const Subclass*>(this));
  112. }
  113. /**
  114. * Attempts to acquire the lock in shared mode. If acquisition is
  115. * unsuccessful, the returned LockedPtr will be null.
  116. *
  117. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  118. * validity.)
  119. */
  120. TryRLockedPtr tryRLock() const {
  121. return TryRLockedPtr{static_cast<const Subclass*>(this)};
  122. }
  123. /**
  124. * Attempts to acquire the lock, or fails if the timeout elapses first.
  125. * If acquisition is unsuccessful, the returned LockedPtr will be null.
  126. *
  127. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  128. * validity.)
  129. */
  130. template <class Rep, class Period>
  131. LockedPtr wlock(const std::chrono::duration<Rep, Period>& timeout) {
  132. return LockedPtr(static_cast<Subclass*>(this), timeout);
  133. }
  134. /**
  135. * Attempts to acquire the lock, or fails if the timeout elapses first.
  136. * If acquisition is unsuccessful, the returned LockedPtr will be null.
  137. *
  138. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  139. * validity.)
  140. */
  141. template <class Rep, class Period>
  142. ConstLockedPtr rlock(
  143. const std::chrono::duration<Rep, Period>& timeout) const {
  144. return ConstLockedPtr(static_cast<const Subclass*>(this), timeout);
  145. }
  146. /**
  147. * Invoke a function while holding the lock exclusively.
  148. *
  149. * A reference to the datum will be passed into the function as its only
  150. * argument.
  151. *
  152. * This can be used with a lambda argument for easily defining small critical
  153. * sections in the code. For example:
  154. *
  155. * auto value = obj.withWLock([](auto& data) {
  156. * data.doStuff();
  157. * return data.getValue();
  158. * });
  159. */
  160. template <class Function>
  161. auto withWLock(Function&& function) {
  162. return function(*wlock());
  163. }
  164. /**
  165. * Invoke a function while holding the lock exclusively.
  166. *
  167. * This is similar to withWLock(), but the function will be passed a
  168. * LockedPtr rather than a reference to the data itself.
  169. *
  170. * This allows scopedUnlock() to be called on the LockedPtr argument if
  171. * desired.
  172. */
  173. template <class Function>
  174. auto withWLockPtr(Function&& function) {
  175. return function(wlock());
  176. }
  177. /**
  178. * Invoke a function while holding an the lock in shared mode.
  179. *
  180. * A const reference to the datum will be passed into the function as its
  181. * only argument.
  182. */
  183. template <class Function>
  184. auto withRLock(Function&& function) const {
  185. return function(*rlock());
  186. }
  187. template <class Function>
  188. auto withRLockPtr(Function&& function) const {
  189. return function(rlock());
  190. }
  191. };
  192. /**
  193. * SynchronizedBase specialization for upgrade mutex types.
  194. *
  195. * This class provides all the functionality provided by the SynchronizedBase
  196. * specialization for shared mutexes and a ulock() method that returns an
  197. * upgradable lock RAII proxy
  198. */
  199. template <class Subclass>
  200. class SynchronizedBase<Subclass, detail::MutexLevel::UPGRADE>
  201. : public SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
  202. public:
  203. using UpgradeLockedPtr = ::folly::LockedPtr<Subclass, LockPolicyUpgrade>;
  204. using ConstUpgradeLockedPtr =
  205. ::folly::LockedPtr<const Subclass, LockPolicyUpgrade>;
  206. using TryUpgradeLockedPtr =
  207. ::folly::LockedPtr<Subclass, LockPolicyTryUpgrade>;
  208. using ConstTryUpgradeLockedPtr =
  209. ::folly::LockedPtr<const Subclass, LockPolicyTryUpgrade>;
  210. /**
  211. * Acquire an upgrade lock and return a LockedPtr that can be used to safely
  212. * access the datum
  213. *
  214. * And the const version
  215. */
  216. UpgradeLockedPtr ulock() {
  217. return UpgradeLockedPtr(static_cast<Subclass*>(this));
  218. }
  219. /**
  220. * Attempts to acquire the lock in upgrade mode. If acquisition is
  221. * unsuccessful, the returned LockedPtr will be null.
  222. *
  223. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  224. * validity.)
  225. */
  226. TryUpgradeLockedPtr tryULock() {
  227. return TryUpgradeLockedPtr{static_cast<Subclass*>(this)};
  228. }
  229. /**
  230. * Acquire an upgrade lock and return a LockedPtr that can be used to safely
  231. * access the datum
  232. *
  233. * And the const version
  234. */
  235. template <class Rep, class Period>
  236. UpgradeLockedPtr ulock(const std::chrono::duration<Rep, Period>& timeout) {
  237. return UpgradeLockedPtr(static_cast<Subclass*>(this), timeout);
  238. }
  239. /**
  240. * Invoke a function while holding the lock.
  241. *
  242. * A reference to the datum will be passed into the function as its only
  243. * argument.
  244. *
  245. * This can be used with a lambda argument for easily defining small critical
  246. * sections in the code. For example:
  247. *
  248. * auto value = obj.withULock([](auto& data) {
  249. * data.doStuff();
  250. * return data.getValue();
  251. * });
  252. *
  253. * This is probably not the function you want. If the intent is to read the
  254. * data object and determine whether you should upgrade to a write lock then
  255. * the withULockPtr() method should be called instead, since it gives access
  256. * to the LockedPtr proxy (which can be upgraded via the
  257. * moveFromUpgradeToWrite() method)
  258. */
  259. template <class Function>
  260. auto withULock(Function&& function) {
  261. return function(*ulock());
  262. }
  263. /**
  264. * Invoke a function while holding the lock exclusively.
  265. *
  266. * This is similar to withULock(), but the function will be passed a
  267. * LockedPtr rather than a reference to the data itself.
  268. *
  269. * This allows scopedUnlock() and getUniqueLock() to be called on the
  270. * LockedPtr argument.
  271. *
  272. * This also allows you to upgrade the LockedPtr proxy to a write state so
  273. * that changes can be made to the underlying data
  274. */
  275. template <class Function>
  276. auto withULockPtr(Function&& function) {
  277. return function(ulock());
  278. }
  279. };
  280. /**
  281. * SynchronizedBase specialization for non-shared mutex types.
  282. *
  283. * This class provides lock() methods for acquiring the lock and accessing the
  284. * data.
  285. */
  286. template <class Subclass>
  287. class SynchronizedBase<Subclass, detail::MutexLevel::UNIQUE> {
  288. public:
  289. using LockedPtr = ::folly::LockedPtr<Subclass, LockPolicyExclusive>;
  290. using ConstLockedPtr =
  291. ::folly::LockedPtr<const Subclass, LockPolicyExclusive>;
  292. using TryLockedPtr = ::folly::LockedPtr<Subclass, LockPolicyTryExclusive>;
  293. using ConstTryLockedPtr =
  294. ::folly::LockedPtr<const Subclass, LockPolicyTryExclusive>;
  295. /**
  296. * Acquire a lock, and return a LockedPtr that can be used to safely access
  297. * the datum.
  298. */
  299. LockedPtr lock() {
  300. return LockedPtr(static_cast<Subclass*>(this));
  301. }
  302. /**
  303. * Acquire a lock, and return a ConstLockedPtr that can be used to safely
  304. * access the datum.
  305. */
  306. ConstLockedPtr lock() const {
  307. return ConstLockedPtr(static_cast<const Subclass*>(this));
  308. }
  309. /**
  310. * Attempts to acquire the lock in exclusive mode. If acquisition is
  311. * unsuccessful, the returned LockedPtr will be null.
  312. *
  313. * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
  314. * validity.)
  315. */
  316. TryLockedPtr tryLock() {
  317. return TryLockedPtr{static_cast<Subclass*>(this)};
  318. }
  319. ConstTryLockedPtr tryLock() const {
  320. return ConstTryLockedPtr{static_cast<const Subclass*>(this)};
  321. }
  322. /**
  323. * Attempts to acquire the lock, or fails if the timeout elapses first.
  324. * If acquisition is unsuccessful, the returned LockedPtr will be null.
  325. */
  326. template <class Rep, class Period>
  327. LockedPtr lock(const std::chrono::duration<Rep, Period>& timeout) {
  328. return LockedPtr(static_cast<Subclass*>(this), timeout);
  329. }
  330. /**
  331. * Attempts to acquire the lock, or fails if the timeout elapses first.
  332. * If acquisition is unsuccessful, the returned LockedPtr will be null.
  333. */
  334. template <class Rep, class Period>
  335. ConstLockedPtr lock(const std::chrono::duration<Rep, Period>& timeout) const {
  336. return ConstLockedPtr(static_cast<const Subclass*>(this), timeout);
  337. }
  338. /**
  339. * Invoke a function while holding the lock.
  340. *
  341. * A reference to the datum will be passed into the function as its only
  342. * argument.
  343. *
  344. * This can be used with a lambda argument for easily defining small critical
  345. * sections in the code. For example:
  346. *
  347. * auto value = obj.withLock([](auto& data) {
  348. * data.doStuff();
  349. * return data.getValue();
  350. * });
  351. */
  352. template <class Function>
  353. auto withLock(Function&& function) {
  354. return function(*lock());
  355. }
  356. template <class Function>
  357. auto withLock(Function&& function) const {
  358. return function(*lock());
  359. }
  360. /**
  361. * Invoke a function while holding the lock exclusively.
  362. *
  363. * This is similar to withWLock(), but the function will be passed a
  364. * LockedPtr rather than a reference to the data itself.
  365. *
  366. * This allows scopedUnlock() and getUniqueLock() to be called on the
  367. * LockedPtr argument.
  368. */
  369. template <class Function>
  370. auto withLockPtr(Function&& function) {
  371. return function(lock());
  372. }
  373. template <class Function>
  374. auto withLockPtr(Function&& function) const {
  375. return function(lock());
  376. }
  377. };
  378. /**
  379. * Synchronized<T> encapsulates an object of type T (a "datum") paired
  380. * with a mutex. The only way to access the datum is while the mutex
  381. * is locked, and Synchronized makes it virtually impossible to do
  382. * otherwise. The code that would access the datum in unsafe ways
  383. * would look odd and convoluted, thus readily alerting the human
  384. * reviewer. In contrast, the code that uses Synchronized<T> correctly
  385. * looks simple and intuitive.
  386. *
  387. * The second parameter must be a mutex type. Any mutex type supported by
  388. * LockTraits<Mutex> can be used. By default any class with lock() and
  389. * unlock() methods will work automatically. LockTraits can be specialized to
  390. * teach Synchronized how to use other custom mutex types. See the
  391. * documentation in LockTraits.h for additional details.
  392. *
  393. * Supported mutexes that work by default include std::mutex,
  394. * std::recursive_mutex, std::timed_mutex, std::recursive_timed_mutex,
  395. * folly::SharedMutex, folly::RWSpinLock, and folly::SpinLock.
  396. * Include LockTraitsBoost.h to get additional LockTraits specializations to
  397. * support the following boost mutex types: boost::mutex,
  398. * boost::recursive_mutex, boost::shared_mutex, boost::timed_mutex, and
  399. * boost::recursive_timed_mutex.
  400. */
  401. template <class T, class Mutex = SharedMutex>
  402. struct Synchronized : public SynchronizedBase<
  403. Synchronized<T, Mutex>,
  404. MutexLevelValue<Mutex>::value> {
  405. private:
  406. using Base =
  407. SynchronizedBase<Synchronized<T, Mutex>, MutexLevelValue<Mutex>::value>;
  408. static constexpr bool nxCopyCtor{
  409. std::is_nothrow_copy_constructible<T>::value};
  410. static constexpr bool nxMoveCtor{
  411. std::is_nothrow_move_constructible<T>::value};
  412. // used to disable copy construction and assignment
  413. class NonImplementedType;
  414. public:
  415. using LockedPtr = typename Base::LockedPtr;
  416. using ConstLockedPtr = typename Base::ConstLockedPtr;
  417. using DataType = T;
  418. using MutexType = Mutex;
  419. /**
  420. * Default constructor leaves both members call their own default
  421. * constructor.
  422. */
  423. Synchronized() = default;
  424. public:
  425. /**
  426. * Copy constructor; deprecated
  427. *
  428. * Enabled only when the data type is copy-constructible.
  429. *
  430. * Takes a shared-or-exclusive lock on the source mutex while performing the
  431. * copy-construction of the destination data from the source data. No lock is
  432. * taken on the destination mutex.
  433. *
  434. * May throw even when the data type is is nothrow-copy-constructible because
  435. * acquiring a lock may throw.
  436. */
  437. /* implicit */ Synchronized(typename std::conditional<
  438. std::is_copy_constructible<T>::value,
  439. const Synchronized&,
  440. NonImplementedType>::type rhs) /* may throw */
  441. : Synchronized(rhs.copy()) {}
  442. /**
  443. * Move constructor; deprecated
  444. *
  445. * Move-constructs from the source data without locking either the source or
  446. * the destination mutex.
  447. *
  448. * Semantically, assumes that the source object is a true rvalue and therefore
  449. * that no synchronization is required for accessing it.
  450. */
  451. Synchronized(Synchronized&& rhs) noexcept(nxMoveCtor)
  452. : Synchronized(std::move(rhs.datum_)) {}
  453. /**
  454. * Constructor taking a datum as argument copies it. There is no
  455. * need to lock the constructing object.
  456. */
  457. explicit Synchronized(const T& rhs) noexcept(nxCopyCtor) : datum_(rhs) {}
  458. /**
  459. * Constructor taking a datum rvalue as argument moves it. Again,
  460. * there is no need to lock the constructing object.
  461. */
  462. explicit Synchronized(T&& rhs) noexcept(nxMoveCtor)
  463. : datum_(std::move(rhs)) {}
  464. /**
  465. * Lets you construct non-movable types in-place. Use the constexpr
  466. * instance `in_place` as the first argument.
  467. */
  468. template <typename... Args>
  469. explicit Synchronized(in_place_t, Args&&... args)
  470. : datum_(std::forward<Args>(args)...) {}
  471. /**
  472. * Lets you construct the synchronized object and also pass construction
  473. * parameters to the underlying mutex if desired
  474. */
  475. template <typename... DatumArgs, typename... MutexArgs>
  476. Synchronized(
  477. std::piecewise_construct_t,
  478. std::tuple<DatumArgs...> datumArgs,
  479. std::tuple<MutexArgs...> mutexArgs)
  480. : Synchronized{std::piecewise_construct,
  481. std::move(datumArgs),
  482. std::move(mutexArgs),
  483. make_index_sequence<sizeof...(DatumArgs)>{},
  484. make_index_sequence<sizeof...(MutexArgs)>{}} {}
  485. /**
  486. * Copy assignment operator; deprecated
  487. *
  488. * Enabled only when the data type is copy-constructible and move-assignable.
  489. *
  490. * Move-assigns from a copy of the source data.
  491. *
  492. * Takes a shared-or-exclusive lock on the source mutex while copying the
  493. * source data to a temporary. Takes an exclusive lock on the destination
  494. * mutex while move-assigning from the temporary.
  495. *
  496. * This technique consts an extra temporary but avoids the need to take locks
  497. * on both mutexes together.
  498. */
  499. Synchronized& operator=(typename std::conditional<
  500. std::is_copy_constructible<T>::value &&
  501. std::is_move_assignable<T>::value,
  502. const Synchronized&,
  503. NonImplementedType>::type rhs) {
  504. return *this = rhs.copy();
  505. }
  506. /**
  507. * Move assignment operator; deprecated
  508. *
  509. * Takes an exclusive lock on the destination mutex while move-assigning the
  510. * destination data from the source data. The source mutex is not locked or
  511. * otherwise accessed.
  512. *
  513. * Semantically, assumes that the source object is a true rvalue and therefore
  514. * that no synchronization is required for accessing it.
  515. */
  516. Synchronized& operator=(Synchronized&& rhs) {
  517. return *this = std::move(rhs.datum_);
  518. }
  519. /**
  520. * Lock object, assign datum.
  521. */
  522. Synchronized& operator=(const T& rhs) {
  523. if (&datum_ != &rhs) {
  524. auto guard = operator->();
  525. datum_ = rhs;
  526. }
  527. return *this;
  528. }
  529. /**
  530. * Lock object, move-assign datum.
  531. */
  532. Synchronized& operator=(T&& rhs) {
  533. if (&datum_ != &rhs) {
  534. auto guard = operator->();
  535. datum_ = std::move(rhs);
  536. }
  537. return *this;
  538. }
  539. /**
  540. * Acquire an appropriate lock based on the context.
  541. *
  542. * If the mutex is a shared mutex, and the Synchronized instance is const,
  543. * this acquires a shared lock. Otherwise this acquires an exclusive lock.
  544. *
  545. * In general, prefer using the explicit rlock() and wlock() methods
  546. * for read-write locks, and lock() for purely exclusive locks.
  547. *
  548. * contextualLock() is primarily intended for use in other template functions
  549. * that do not necessarily know the lock type.
  550. */
  551. LockedPtr contextualLock() {
  552. return LockedPtr(this);
  553. }
  554. ConstLockedPtr contextualLock() const {
  555. return ConstLockedPtr(this);
  556. }
  557. template <class Rep, class Period>
  558. LockedPtr contextualLock(const std::chrono::duration<Rep, Period>& timeout) {
  559. return LockedPtr(this, timeout);
  560. }
  561. template <class Rep, class Period>
  562. ConstLockedPtr contextualLock(
  563. const std::chrono::duration<Rep, Period>& timeout) const {
  564. return ConstLockedPtr(this, timeout);
  565. }
  566. /**
  567. * contextualRLock() acquires a read lock if the mutex type is shared,
  568. * or a regular exclusive lock for non-shared mutex types.
  569. *
  570. * contextualRLock() when you know that you prefer a read lock (if
  571. * available), even if the Synchronized<T> object itself is non-const.
  572. */
  573. ConstLockedPtr contextualRLock() const {
  574. return ConstLockedPtr(this);
  575. }
  576. template <class Rep, class Period>
  577. ConstLockedPtr contextualRLock(
  578. const std::chrono::duration<Rep, Period>& timeout) const {
  579. return ConstLockedPtr(this, timeout);
  580. }
  581. /**
  582. * This accessor offers a LockedPtr. In turn, LockedPtr offers
  583. * operator-> returning a pointer to T. The operator-> keeps
  584. * expanding until it reaches a pointer, so syncobj->foo() will lock
  585. * the object and call foo() against it.
  586. *
  587. * NOTE: This API is planned to be deprecated in an upcoming diff.
  588. * Prefer using lock(), wlock(), or rlock() instead.
  589. */
  590. LockedPtr operator->() {
  591. return LockedPtr(this);
  592. }
  593. /**
  594. * Obtain a ConstLockedPtr.
  595. *
  596. * NOTE: This API is planned to be deprecated in an upcoming diff.
  597. * Prefer using lock(), wlock(), or rlock() instead.
  598. */
  599. ConstLockedPtr operator->() const {
  600. return ConstLockedPtr(this);
  601. }
  602. /**
  603. * Attempts to acquire for a given number of milliseconds. If
  604. * acquisition is unsuccessful, the returned LockedPtr is nullptr.
  605. *
  606. * NOTE: This API is deprecated. Use lock(), wlock(), or rlock() instead.
  607. * In the future it will be marked with a deprecation attribute to emit
  608. * build-time warnings, and then it will be removed entirely.
  609. */
  610. LockedPtr timedAcquire(unsigned int milliseconds) {
  611. return LockedPtr(this, std::chrono::milliseconds(milliseconds));
  612. }
  613. /**
  614. * Attempts to acquire for a given number of milliseconds. If
  615. * acquisition is unsuccessful, the returned ConstLockedPtr is nullptr.
  616. *
  617. * NOTE: This API is deprecated. Use lock(), wlock(), or rlock() instead.
  618. * In the future it will be marked with a deprecation attribute to emit
  619. * build-time warnings, and then it will be removed entirely.
  620. */
  621. ConstLockedPtr timedAcquire(unsigned int milliseconds) const {
  622. return ConstLockedPtr(this, std::chrono::milliseconds(milliseconds));
  623. }
  624. /**
  625. * Swaps with another Synchronized. Protected against
  626. * self-swap. Only data is swapped. Locks are acquired in increasing
  627. * address order.
  628. */
  629. void swap(Synchronized& rhs) {
  630. if (this == &rhs) {
  631. return;
  632. }
  633. if (this > &rhs) {
  634. return rhs.swap(*this);
  635. }
  636. auto guard1 = operator->();
  637. auto guard2 = rhs.operator->();
  638. using std::swap;
  639. swap(datum_, rhs.datum_);
  640. }
  641. /**
  642. * Swap with another datum. Recommended because it keeps the mutex
  643. * held only briefly.
  644. */
  645. void swap(T& rhs) {
  646. LockedPtr guard(this);
  647. using std::swap;
  648. swap(datum_, rhs);
  649. }
  650. /**
  651. * Assign another datum and return the original value. Recommended
  652. * because it keeps the mutex held only briefly.
  653. */
  654. T exchange(T&& rhs) {
  655. swap(rhs);
  656. return std::move(rhs);
  657. }
  658. /**
  659. * Copies datum to a given target.
  660. */
  661. void copy(T* target) const {
  662. ConstLockedPtr guard(this);
  663. *target = datum_;
  664. }
  665. /**
  666. * Returns a fresh copy of the datum.
  667. */
  668. T copy() const {
  669. ConstLockedPtr guard(this);
  670. return datum_;
  671. }
  672. private:
  673. template <class LockedType, class MutexType, class LockPolicy>
  674. friend class folly::LockedPtrBase;
  675. template <class LockedType, class LockPolicy>
  676. friend class folly::LockedPtr;
  677. /**
  678. * Helper constructors to enable Synchronized for
  679. * non-default constructible types T.
  680. * Guards are created in actual public constructors and are alive
  681. * for the time required to construct the object
  682. */
  683. Synchronized(
  684. const Synchronized& rhs,
  685. const ConstLockedPtr& /*guard*/) noexcept(nxCopyCtor)
  686. : datum_(rhs.datum_) {}
  687. Synchronized(Synchronized&& rhs, const LockedPtr& /*guard*/) noexcept(
  688. nxMoveCtor)
  689. : datum_(std::move(rhs.datum_)) {}
  690. template <
  691. typename... DatumArgs,
  692. typename... MutexArgs,
  693. std::size_t... IndicesOne,
  694. std::size_t... IndicesTwo>
  695. Synchronized(
  696. std::piecewise_construct_t,
  697. std::tuple<DatumArgs...> datumArgs,
  698. std::tuple<MutexArgs...> mutexArgs,
  699. index_sequence<IndicesOne...>,
  700. index_sequence<IndicesTwo...>)
  701. : datum_{std::get<IndicesOne>(std::move(datumArgs))...},
  702. mutex_{std::get<IndicesTwo>(std::move(mutexArgs))...} {}
  703. // Synchronized data members
  704. T datum_;
  705. mutable Mutex mutex_;
  706. };
  707. template <class SynchronizedType, class LockPolicy>
  708. class ScopedUnlocker;
  709. namespace detail {
  710. /*
  711. * A helper alias that resolves to "const T" if the template parameter
  712. * is a const Synchronized<T>, or "T" if the parameter is not const.
  713. */
  714. template <class SynchronizedType>
  715. using SynchronizedDataType = typename std::conditional<
  716. std::is_const<SynchronizedType>::value,
  717. typename SynchronizedType::DataType const,
  718. typename SynchronizedType::DataType>::type;
  719. /*
  720. * A helper alias that resolves to a ConstLockedPtr if the template parameter
  721. * is a const Synchronized<T>, or a LockedPtr if the parameter is not const.
  722. */
  723. template <class SynchronizedType>
  724. using LockedPtrType = typename std::conditional<
  725. std::is_const<SynchronizedType>::value,
  726. typename SynchronizedType::ConstLockedPtr,
  727. typename SynchronizedType::LockedPtr>::type;
  728. template <
  729. typename Synchronized,
  730. typename LockFunc,
  731. typename TryLockFunc,
  732. typename... Args>
  733. class SynchronizedLocker {
  734. public:
  735. using LockedPtr = invoke_result_t<LockFunc&, Synchronized&, const Args&...>;
  736. template <typename LockFuncType, typename TryLockFuncType, typename... As>
  737. SynchronizedLocker(
  738. Synchronized& sync,
  739. LockFuncType&& lockFunc,
  740. TryLockFuncType tryLockFunc,
  741. As&&... as)
  742. : synchronized{sync},
  743. lockFunc_{std::forward<LockFuncType>(lockFunc)},
  744. tryLockFunc_{std::forward<TryLockFuncType>(tryLockFunc)},
  745. args_{std::forward<As>(as)...} {}
  746. auto lock() const {
  747. auto args = std::tuple<const Args&...>{args_};
  748. return apply(lockFunc_, std::tuple_cat(std::tie(synchronized), args));
  749. }
  750. auto tryLock() const {
  751. return tryLockFunc_(synchronized);
  752. }
  753. private:
  754. Synchronized& synchronized;
  755. LockFunc lockFunc_;
  756. TryLockFunc tryLockFunc_;
  757. std::tuple<Args...> args_;
  758. };
  759. template <
  760. typename Synchronized,
  761. typename LockFunc,
  762. typename TryLockFunc,
  763. typename... Args>
  764. auto makeSynchronizedLocker(
  765. Synchronized& synchronized,
  766. LockFunc&& lockFunc,
  767. TryLockFunc&& tryLockFunc,
  768. Args&&... args) {
  769. using LockFuncType = std::decay_t<LockFunc>;
  770. using TryLockFuncType = std::decay_t<TryLockFunc>;
  771. return SynchronizedLocker<
  772. Synchronized,
  773. LockFuncType,
  774. TryLockFuncType,
  775. std::decay_t<Args>...>{synchronized,
  776. std::forward<LockFunc>(lockFunc),
  777. std::forward<TryLockFunc>(tryLockFunc),
  778. std::forward<Args>(args)...};
  779. }
  780. /**
  781. * Acquire locks for multiple Synchronized<T> objects, in a deadlock-safe
  782. * manner.
  783. *
  784. * The function uses the "smart and polite" algorithm from this link
  785. * http://howardhinnant.github.io/dining_philosophers.html#Polite
  786. *
  787. * The gist of the algorithm is that it locks a mutex, then tries to lock the
  788. * other mutexes in a non-blocking manner. If all the locks succeed, we are
  789. * done, if not, we release the locks we have held, yield to allow other
  790. * threads to continue and then block on the mutex that we failed to acquire.
  791. *
  792. * This allows dynamically yielding ownership of all the mutexes but one, so
  793. * that other threads can continue doing work and locking the other mutexes.
  794. * See the benchmarks in folly/test/SynchronizedBenchmark.cpp for more.
  795. */
  796. template <typename... SynchronizedLocker>
  797. auto lock(SynchronizedLocker... lockersIn)
  798. -> std::tuple<typename SynchronizedLocker::LockedPtr...> {
  799. // capture the list of lockers as a tuple
  800. auto lockers = std::forward_as_tuple(lockersIn...);
  801. // make a list of null LockedPtr instances that we will return to the caller
  802. auto lockedPtrs = std::tuple<typename SynchronizedLocker::LockedPtr...>{};
  803. // start by locking the first thing in the list
  804. std::get<0>(lockedPtrs) = std::get<0>(lockers).lock();
  805. auto indexLocked = 0;
  806. while (true) {
  807. auto couldLockAll = true;
  808. for_each(lockers, [&](auto& locker, auto index) {
  809. // if we should try_lock on the current locker then do so
  810. if (index != indexLocked) {
  811. auto lockedPtr = locker.tryLock();
  812. // if we were unable to lock this mutex,
  813. //
  814. // 1. release all the locks,
  815. // 2. yield control to another thread to be nice
  816. // 3. block on the mutex we failed to lock, acquire the lock
  817. // 4. break out and set the index of the current mutex to indicate
  818. // which mutex we have locked
  819. if (!lockedPtr) {
  820. // writing lockedPtrs = decltype(lockedPtrs){} does not compile on
  821. // gcc, I believe this is a bug D7676798
  822. lockedPtrs = std::tuple<typename SynchronizedLocker::LockedPtr...>{};
  823. std::this_thread::yield();
  824. fetch(lockedPtrs, index) = locker.lock();
  825. indexLocked = index;
  826. couldLockAll = false;
  827. return loop_break;
  828. }
  829. // else store the locked mutex in the list we return
  830. fetch(lockedPtrs, index) = std::move(lockedPtr);
  831. }
  832. return loop_continue;
  833. });
  834. if (couldLockAll) {
  835. return lockedPtrs;
  836. }
  837. }
  838. }
  839. template <typename Synchronized, typename... Args>
  840. auto wlock(Synchronized& synchronized, Args&&... args) {
  841. return detail::makeSynchronizedLocker(
  842. synchronized,
  843. [](auto& s, auto&&... a) {
  844. return s.wlock(std::forward<decltype(a)>(a)...);
  845. },
  846. [](auto& s) { return s.tryWLock(); },
  847. std::forward<Args>(args)...);
  848. }
  849. template <typename Synchronized, typename... Args>
  850. auto rlock(Synchronized& synchronized, Args&&... args) {
  851. return detail::makeSynchronizedLocker(
  852. synchronized,
  853. [](auto& s, auto&&... a) {
  854. return s.rlock(std::forward<decltype(a)>(a)...);
  855. },
  856. [](auto& s) { return s.tryRLock(); },
  857. std::forward<Args>(args)...);
  858. }
  859. template <typename Synchronized, typename... Args>
  860. auto ulock(Synchronized& synchronized, Args&&... args) {
  861. return detail::makeSynchronizedLocker(
  862. synchronized,
  863. [](auto& s, auto&&... a) {
  864. return s.ulock(std::forward<decltype(a)>(a)...);
  865. },
  866. [](auto& s) { return s.tryULock(); },
  867. std::forward<Args>(args)...);
  868. }
  869. template <typename Synchronized, typename... Args>
  870. auto lock(Synchronized& synchronized, Args&&... args) {
  871. return detail::makeSynchronizedLocker(
  872. synchronized,
  873. [](auto& s, auto&&... a) {
  874. return s.lock(std::forward<decltype(a)>(a)...);
  875. },
  876. [](auto& s) { return s.tryLock(); },
  877. std::forward<Args>(args)...);
  878. }
  879. } // namespace detail
  880. /**
  881. * A helper base class for implementing LockedPtr.
  882. *
  883. * The main reason for having this as a separate class is so we can specialize
  884. * it for std::mutex, so we can expose a std::unique_lock to the caller
  885. * when std::mutex is being used. This allows callers to use a
  886. * std::condition_variable with the mutex from a Synchronized<T, std::mutex>.
  887. *
  888. * We don't use std::unique_lock with other Mutex types since it makes the
  889. * LockedPtr class slightly larger, and it makes the logic to support
  890. * ScopedUnlocker slightly more complicated. std::mutex is the only one that
  891. * really seems to benefit from the unique_lock. std::condition_variable
  892. * itself only supports std::unique_lock<std::mutex>, so there doesn't seem to
  893. * be any real benefit to exposing the unique_lock with other mutex types.
  894. *
  895. * Note that the SynchronizedType template parameter may or may not be const
  896. * qualified.
  897. */
  898. template <class SynchronizedType, class Mutex, class LockPolicy>
  899. class LockedPtrBase {
  900. public:
  901. using MutexType = Mutex;
  902. friend class folly::ScopedUnlocker<SynchronizedType, LockPolicy>;
  903. /**
  904. * Friend all instantiations of LockedPtr and LockedPtrBase
  905. */
  906. template <typename S, typename L>
  907. friend class folly::LockedPtr;
  908. template <typename S, typename M, typename L>
  909. friend class LockedPtrBase;
  910. /**
  911. * Destructor releases.
  912. */
  913. ~LockedPtrBase() {
  914. if (parent_) {
  915. LockPolicy::unlock(parent_->mutex_);
  916. }
  917. }
  918. /**
  919. * Unlock the synchronized data.
  920. *
  921. * The LockedPtr can no longer be dereferenced after unlock() has been
  922. * called. isValid() will return false on an unlocked LockedPtr.
  923. *
  924. * unlock() can only be called on a LockedPtr that is valid.
  925. */
  926. void unlock() {
  927. DCHECK(parent_ != nullptr);
  928. LockPolicy::unlock(parent_->mutex_);
  929. parent_ = nullptr;
  930. }
  931. protected:
  932. LockedPtrBase() {}
  933. explicit LockedPtrBase(SynchronizedType* parent) : parent_(parent) {
  934. DCHECK(parent);
  935. if (!LockPolicy::lock(parent_->mutex_)) {
  936. parent_ = nullptr;
  937. }
  938. }
  939. template <class Rep, class Period>
  940. LockedPtrBase(
  941. SynchronizedType* parent,
  942. const std::chrono::duration<Rep, Period>& timeout) {
  943. if (LockPolicy::try_lock_for(parent->mutex_, timeout)) {
  944. this->parent_ = parent;
  945. }
  946. }
  947. LockedPtrBase(LockedPtrBase&& rhs) noexcept
  948. : parent_{exchange(rhs.parent_, nullptr)} {}
  949. LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept {
  950. assignImpl(*this, rhs);
  951. return *this;
  952. }
  953. /**
  954. * Templated move construct and assignment operators
  955. *
  956. * These allow converting LockedPtr types that have the same unlocking
  957. * policy to each other. This allows us to write code like
  958. *
  959. * auto wlock = sync.wlock();
  960. * wlock.unlock();
  961. *
  962. * auto ulock = sync.ulock();
  963. * wlock = ulock.moveFromUpgradeToWrite();
  964. */
  965. template <typename LockPolicyType>
  966. LockedPtrBase(
  967. LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept
  968. : parent_{exchange(rhs.parent_, nullptr)} {}
  969. template <typename LockPolicyType>
  970. LockedPtrBase& operator=(
  971. LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept {
  972. assignImpl(*this, rhs);
  973. return *this;
  974. }
  975. /**
  976. * Implementation for the assignment operator
  977. */
  978. template <typename LockPolicyLhs, typename LockPolicyRhs>
  979. void assignImpl(
  980. LockedPtrBase<SynchronizedType, Mutex, LockPolicyLhs>& lhs,
  981. LockedPtrBase<SynchronizedType, Mutex, LockPolicyRhs>& rhs) noexcept {
  982. if (lhs.parent_) {
  983. LockPolicy::unlock(lhs.parent_->mutex_);
  984. }
  985. lhs.parent_ = exchange(rhs.parent_, nullptr);
  986. }
  987. using UnlockerData = SynchronizedType*;
  988. /**
  989. * Get a pointer to the Synchronized object from the UnlockerData.
  990. *
  991. * In the generic case UnlockerData is just the Synchronized pointer,
  992. * so we return it as is. (This function is more interesting in the
  993. * std::mutex specialization below.)
  994. */
  995. static SynchronizedType* getSynchronized(UnlockerData data) {
  996. return data;
  997. }
  998. UnlockerData releaseLock() {
  999. DCHECK(parent_ != nullptr);
  1000. auto current = parent_;
  1001. parent_ = nullptr;
  1002. LockPolicy::unlock(current->mutex_);
  1003. return current;
  1004. }
  1005. void reacquireLock(UnlockerData&& data) {
  1006. DCHECK(parent_ == nullptr);
  1007. parent_ = data;
  1008. LockPolicy::lock(parent_->mutex_);
  1009. }
  1010. SynchronizedType* parent_ = nullptr;
  1011. };
  1012. /**
  1013. * LockedPtrBase specialization for use with std::mutex.
  1014. *
  1015. * When std::mutex is used we use a std::unique_lock to hold the mutex.
  1016. * This makes it possible to use std::condition_variable with a
  1017. * Synchronized<T, std::mutex>.
  1018. */
  1019. template <class SynchronizedType, class LockPolicy>
  1020. class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
  1021. public:
  1022. using MutexType = std::mutex;
  1023. friend class folly::ScopedUnlocker<SynchronizedType, LockPolicy>;
  1024. /**
  1025. * Friend all instantiations of LockedPtr and LockedPtrBase
  1026. */
  1027. template <typename S, typename L>
  1028. friend class folly::LockedPtr;
  1029. template <typename S, typename M, typename L>
  1030. friend class LockedPtrBase;
  1031. /**
  1032. * Destructor releases.
  1033. */
  1034. ~LockedPtrBase() {
  1035. // The std::unique_lock will automatically release the lock when it is
  1036. // destroyed, so we don't need to do anything extra here.
  1037. }
  1038. LockedPtrBase(LockedPtrBase&& rhs) noexcept
  1039. : lock_{std::move(rhs.lock_)}, parent_{exchange(rhs.parent_, nullptr)} {}
  1040. LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept {
  1041. assignImpl(*this, rhs);
  1042. return *this;
  1043. }
  1044. /**
  1045. * Templated move construct and assignment operators
  1046. *
  1047. * These allow converting LockedPtr types that have the same unlocking
  1048. * policy to each other.
  1049. */
  1050. template <typename LockPolicyType>
  1051. LockedPtrBase(LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&&
  1052. other) noexcept
  1053. : lock_{std::move(other.lock_)},
  1054. parent_{exchange(other.parent_, nullptr)} {}
  1055. template <typename LockPolicyType>
  1056. LockedPtrBase& operator=(
  1057. LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&&
  1058. rhs) noexcept {
  1059. assignImpl(*this, rhs);
  1060. return *this;
  1061. }
  1062. /**
  1063. * Implementation for the assignment operator
  1064. */
  1065. template <typename LockPolicyLhs, typename LockPolicyRhs>
  1066. void assignImpl(
  1067. LockedPtrBase<SynchronizedType, std::mutex, LockPolicyLhs>& lhs,
  1068. LockedPtrBase<SynchronizedType, std::mutex, LockPolicyRhs>&
  1069. rhs) noexcept {
  1070. lhs.lock_ = std::move(rhs.lock_);
  1071. lhs.parent_ = exchange(rhs.parent_, nullptr);
  1072. }
  1073. /**
  1074. * Get a reference to the std::unique_lock.
  1075. *
  1076. * This is provided so that callers can use Synchronized<T, std::mutex>
  1077. * with a std::condition_variable.
  1078. *
  1079. * While this API could be used to bypass the normal Synchronized APIs and
  1080. * manually interact with the underlying unique_lock, this is strongly
  1081. * discouraged.
  1082. */
  1083. std::unique_lock<std::mutex>& getUniqueLock() {
  1084. return lock_;
  1085. }
  1086. /**
  1087. * Unlock the synchronized data.
  1088. *
  1089. * The LockedPtr can no longer be dereferenced after unlock() has been
  1090. * called. isValid() will return false on an unlocked LockedPtr.
  1091. *
  1092. * unlock() can only be called on a LockedPtr that is valid.
  1093. */
  1094. void unlock() {
  1095. DCHECK(parent_ != nullptr);
  1096. lock_.unlock();
  1097. parent_ = nullptr;
  1098. }
  1099. protected:
  1100. LockedPtrBase() {}
  1101. explicit LockedPtrBase(SynchronizedType* parent)
  1102. : lock_{parent->mutex_, std::adopt_lock}, parent_{parent} {
  1103. DCHECK(parent);
  1104. if (!LockPolicy::lock(parent_->mutex_)) {
  1105. parent_ = nullptr;
  1106. lock_.release();
  1107. }
  1108. }
  1109. using UnlockerData =
  1110. std::pair<std::unique_lock<std::mutex>, SynchronizedType*>;
  1111. static SynchronizedType* getSynchronized(const UnlockerData& data) {
  1112. return data.second;
  1113. }
  1114. UnlockerData releaseLock() {
  1115. DCHECK(parent_ != nullptr);
  1116. UnlockerData data(std::move(lock_), parent_);
  1117. parent_ = nullptr;
  1118. data.first.unlock();
  1119. return data;
  1120. }
  1121. void reacquireLock(UnlockerData&& data) {
  1122. lock_ = std::move(data.first);
  1123. lock_.lock();
  1124. parent_ = data.second;
  1125. }
  1126. // The specialization for std::mutex does have to store slightly more
  1127. // state than the default implementation.
  1128. std::unique_lock<std::mutex> lock_;
  1129. SynchronizedType* parent_ = nullptr;
  1130. };
  1131. /**
  1132. * This class temporarily unlocks a LockedPtr in a scoped manner.
  1133. */
  1134. template <class SynchronizedType, class LockPolicy>
  1135. class ScopedUnlocker {
  1136. public:
  1137. explicit ScopedUnlocker(LockedPtr<SynchronizedType, LockPolicy>* p)
  1138. : ptr_(p), data_(ptr_->releaseLock()) {}
  1139. ScopedUnlocker(const ScopedUnlocker&) = delete;
  1140. ScopedUnlocker& operator=(const ScopedUnlocker&) = delete;
  1141. ScopedUnlocker(ScopedUnlocker&& other) noexcept
  1142. : ptr_(exchange(other.ptr_, nullptr)), data_(std::move(other.data_)) {}
  1143. ScopedUnlocker& operator=(ScopedUnlocker&& other) = delete;
  1144. ~ScopedUnlocker() {
  1145. if (ptr_) {
  1146. ptr_->reacquireLock(std::move(data_));
  1147. }
  1148. }
  1149. /**
  1150. * Return a pointer to the Synchronized object used by this ScopedUnlocker.
  1151. */
  1152. SynchronizedType* getSynchronized() const {
  1153. return LockedPtr<SynchronizedType, LockPolicy>::getSynchronized(data_);
  1154. }
  1155. private:
  1156. using Data = typename LockedPtr<SynchronizedType, LockPolicy>::UnlockerData;
  1157. LockedPtr<SynchronizedType, LockPolicy>* ptr_{nullptr};
  1158. Data data_;
  1159. };
  1160. /**
  1161. * A LockedPtr keeps a Synchronized<T> object locked for the duration of
  1162. * LockedPtr's existence.
  1163. *
  1164. * It provides access the datum's members directly by using operator->() and
  1165. * operator*().
  1166. *
  1167. * The LockPolicy parameter controls whether or not the lock is acquired in
  1168. * exclusive or shared mode.
  1169. */
  1170. template <class SynchronizedType, class LockPolicy>
  1171. class LockedPtr : public LockedPtrBase<
  1172. SynchronizedType,
  1173. typename SynchronizedType::MutexType,
  1174. LockPolicy> {
  1175. private:
  1176. using Base = LockedPtrBase<
  1177. SynchronizedType,
  1178. typename SynchronizedType::MutexType,
  1179. LockPolicy>;
  1180. using UnlockerData = typename Base::UnlockerData;
  1181. // CDataType is the DataType with the appropriate const-qualification
  1182. using CDataType = detail::SynchronizedDataType<SynchronizedType>;
  1183. // Enable only if the unlock policy of the other LockPolicy is the same as
  1184. // ours
  1185. template <typename LockPolicyOther>
  1186. using EnableIfSameUnlockPolicy = std::enable_if_t<std::is_same<
  1187. typename LockPolicy::UnlockPolicy,
  1188. typename LockPolicyOther::UnlockPolicy>::value>;
  1189. // friend other LockedPtr types
  1190. template <typename SynchronizedTypeOther, typename LockPolicyOther>
  1191. friend class LockedPtr;
  1192. public:
  1193. using DataType = typename SynchronizedType::DataType;
  1194. using MutexType = typename SynchronizedType::MutexType;
  1195. using Synchronized = typename std::remove_const<SynchronizedType>::type;
  1196. friend class ScopedUnlocker<SynchronizedType, LockPolicy>;
  1197. /**
  1198. * Creates an uninitialized LockedPtr.
  1199. *
  1200. * Dereferencing an uninitialized LockedPtr is not allowed.
  1201. */
  1202. LockedPtr() {}
  1203. /**
  1204. * Takes a Synchronized<T> and locks it.
  1205. */
  1206. explicit LockedPtr(SynchronizedType* parent) : Base(parent) {}
  1207. /**
  1208. * Takes a Synchronized<T> and attempts to lock it, within the specified
  1209. * timeout.
  1210. *
  1211. * Blocks until the lock is acquired or until the specified timeout expires.
  1212. * If the timeout expired without acquiring the lock, the LockedPtr will be
  1213. * null, and LockedPtr::isNull() will return true.
  1214. */
  1215. template <class Rep, class Period>
  1216. LockedPtr(
  1217. SynchronizedType* parent,
  1218. const std::chrono::duration<Rep, Period>& timeout)
  1219. : Base(parent, timeout) {}
  1220. /**
  1221. * Move constructor.
  1222. */
  1223. LockedPtr(LockedPtr&& rhs) noexcept = default;
  1224. template <
  1225. typename LockPolicyType,
  1226. EnableIfSameUnlockPolicy<LockPolicyType>* = nullptr>
  1227. LockedPtr(LockedPtr<SynchronizedType, LockPolicyType>&& other) noexcept
  1228. : Base{std::move(other)} {}
  1229. /**
  1230. * Move assignment operator.
  1231. */
  1232. LockedPtr& operator=(LockedPtr&& rhs) noexcept = default;
  1233. template <
  1234. typename LockPolicyType,
  1235. EnableIfSameUnlockPolicy<LockPolicyType>* = nullptr>
  1236. LockedPtr& operator=(
  1237. LockedPtr<SynchronizedType, LockPolicyType>&& other) noexcept {
  1238. Base::operator=(std::move(other));
  1239. return *this;
  1240. }
  1241. /*
  1242. * Copy constructor and assignment operator are deleted.
  1243. */
  1244. LockedPtr(const LockedPtr& rhs) = delete;
  1245. LockedPtr& operator=(const LockedPtr& rhs) = delete;
  1246. /**
  1247. * Destructor releases.
  1248. */
  1249. ~LockedPtr() {}
  1250. /**
  1251. * Check if this LockedPtr is uninitialized, or points to valid locked data.
  1252. *
  1253. * This method can be used to check if a timed-acquire operation succeeded.
  1254. * If an acquire operation times out it will result in a null LockedPtr.
  1255. *
  1256. * A LockedPtr is always either null, or holds a lock to valid data.
  1257. * Methods such as scopedUnlock() reset the LockedPtr to null for the
  1258. * duration of the unlock.
  1259. */
  1260. bool isNull() const {
  1261. return this->parent_ == nullptr;
  1262. }
  1263. /**
  1264. * Explicit boolean conversion.
  1265. *
  1266. * Returns !isNull()
  1267. */
  1268. explicit operator bool() const {
  1269. return this->parent_ != nullptr;
  1270. }
  1271. /**
  1272. * Access the locked data.
  1273. *
  1274. * This method should only be used if the LockedPtr is valid.
  1275. */
  1276. CDataType* operator->() const {
  1277. return &this->parent_->datum_;
  1278. }
  1279. /**
  1280. * Access the locked data.
  1281. *
  1282. * This method should only be used if the LockedPtr is valid.
  1283. */
  1284. CDataType& operator*() const {
  1285. return this->parent_->datum_;
  1286. }
  1287. /**
  1288. * Temporarily unlock the LockedPtr, and reset it to null.
  1289. *
  1290. * Returns an helper object that will re-lock and restore the LockedPtr when
  1291. * the helper is destroyed. The LockedPtr may not be dereferenced for as
  1292. * long as this helper object exists.
  1293. */
  1294. ScopedUnlocker<SynchronizedType, LockPolicy> scopedUnlock() {
  1295. return ScopedUnlocker<SynchronizedType, LockPolicy>(this);
  1296. }
  1297. /***************************************************************************
  1298. * Upgradable lock methods.
  1299. * These are disabled via SFINAE when the mutex is not upgradable
  1300. **************************************************************************/
  1301. /**
  1302. * Move the locked ptr from an upgrade state to an exclusive state. The
  1303. * current lock is left in a null state.
  1304. */
  1305. template <
  1306. typename SyncType = SynchronizedType,
  1307. typename = typename std::enable_if<
  1308. LockTraits<typename SyncType::MutexType>::is_upgrade>::type>
  1309. LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive>
  1310. moveFromUpgradeToWrite() {
  1311. return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive>(
  1312. exchange(this->parent_, nullptr));
  1313. }
  1314. /**
  1315. * Move the locked ptr from an exclusive state to an upgrade state. The
  1316. * current lock is left in a null state.
  1317. */
  1318. template <
  1319. typename SyncType = SynchronizedType,
  1320. typename = typename std::enable_if<
  1321. LockTraits<typename SyncType::MutexType>::is_upgrade>::type>
  1322. LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade>
  1323. moveFromWriteToUpgrade() {
  1324. return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade>(
  1325. exchange(this->parent_, nullptr));
  1326. }
  1327. /**
  1328. * Move the locked ptr from an upgrade state to a shared state. The
  1329. * current lock is left in a null state.
  1330. */
  1331. template <
  1332. typename SyncType = SynchronizedType,
  1333. typename = typename std::enable_if<
  1334. LockTraits<typename SyncType::MutexType>::is_upgrade>::type>
  1335. LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared>
  1336. moveFromUpgradeToRead() {
  1337. return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared>(
  1338. exchange(this->parent_, nullptr));
  1339. }
  1340. /**
  1341. * Move the locked ptr from an exclusive state to a shared state. The
  1342. * current lock is left in a null state.
  1343. */
  1344. template <
  1345. typename SyncType = SynchronizedType,
  1346. typename = typename std::enable_if<
  1347. LockTraits<typename SyncType::MutexType>::is_upgrade>::type>
  1348. LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared>
  1349. moveFromWriteToRead() {
  1350. return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared>(
  1351. exchange(this->parent_, nullptr));
  1352. }
  1353. };
  1354. /**
  1355. * Helper functions that should be passed to either a lock() or synchronized()
  1356. * invocation, these return implementation defined structs that will be used
  1357. * to lock the synchronized instance appropriately.
  1358. *
  1359. * lock(wlock(one), rlock(two), wlock(three));
  1360. * synchronized([](auto one, two) { ... }, wlock(one), rlock(two));
  1361. *
  1362. * For example in the above rlock() produces an implementation defined read
  1363. * locking helper instance and wlock() a write locking helper
  1364. *
  1365. * Subsequent arguments passed to these locking helpers, after the first, will
  1366. * be passed by const-ref to the corresponding function on the synchronized
  1367. * instance. This means that if the function accepts these parameters by
  1368. * value, they will be copied. Note that it is not necessary that the primary
  1369. * locking function will be invoked at all (for eg. the implementation might
  1370. * just invoke the try*Lock() method)
  1371. *
  1372. * // Try to acquire the lock for one second
  1373. * synchronized([](auto) { ... }, wlock(one, 1s));
  1374. *
  1375. * // The timed lock acquire might never actually be called, if it is not
  1376. * // needed by the underlying deadlock avoiding algorithm
  1377. * synchronized([](auto, auto) { ... }, rlock(one), wlock(two, 1s));
  1378. *
  1379. * Note that the arguments passed to to *lock() calls will be passed by
  1380. * const-ref to the function invocation, as the implementation might use them
  1381. * many times
  1382. */
  1383. template <typename D, typename M, typename... Args>
  1384. auto wlock(Synchronized<D, M>& synchronized, Args&&... args) {
  1385. return detail::wlock(synchronized, std::forward<Args>(args)...);
  1386. }
  1387. template <typename Data, typename Mutex, typename... Args>
  1388. auto rlock(const Synchronized<Data, Mutex>& synchronized, Args&&... args) {
  1389. return detail::rlock(synchronized, std::forward<Args>(args)...);
  1390. }
  1391. template <typename D, typename M, typename... Args>
  1392. auto ulock(Synchronized<D, M>& synchronized, Args&&... args) {
  1393. return detail::ulock(synchronized, std::forward<Args>(args)...);
  1394. }
  1395. template <typename D, typename M, typename... Args>
  1396. auto lock(Synchronized<D, M>& synchronized, Args&&... args) {
  1397. return detail::lock(synchronized, std::forward<Args>(args)...);
  1398. }
  1399. template <typename D, typename M, typename... Args>
  1400. auto lock(const Synchronized<D, M>& synchronized, Args&&... args) {
  1401. return detail::lock(synchronized, std::forward<Args>(args)...);
  1402. }
  1403. /**
  1404. * Acquire locks for multiple Synchronized<> objects, in a deadlock-safe
  1405. * manner.
  1406. *
  1407. * Wrap the synchronized instances with the appropriate locking strategy by
  1408. * using one of the four strategies - folly::lock (exclusive acquire for
  1409. * exclusive only mutexes), folly::rlock (shared acquire for shareable
  1410. * mutexes), folly::wlock (exclusive acquire for shareable mutexes) or
  1411. * folly::ulock (upgrade acquire for upgrade mutexes) (see above)
  1412. *
  1413. * The locks will be acquired and the passed callable will be invoked with the
  1414. * LockedPtr instances in the order that they were passed to the function
  1415. */
  1416. template <typename Func, typename... SynchronizedLockers>
  1417. decltype(auto) synchronized(Func&& func, SynchronizedLockers&&... lockers) {
  1418. return apply(
  1419. std::forward<Func>(func),
  1420. lock(std::forward<SynchronizedLockers>(lockers)...));
  1421. }
  1422. /**
  1423. * Acquire locks on many lockables or synchronized instances in such a way
  1424. * that the sequence of calls within the function does not cause deadlocks.
  1425. *
  1426. * This can often result in a performance boost as compared to simply
  1427. * acquiring your locks in an ordered manner. Even for very simple cases.
  1428. * The algorithm tried to adjust to contention by blocking on the mutex it
  1429. * thinks is the best fit, leaving all other mutexes open to be locked by
  1430. * other threads. See the benchmarks in folly/test/SynchronizedBenchmark.cpp
  1431. * for more
  1432. *
  1433. * This works differently as compared to the locking algorithm in libstdc++
  1434. * and is the recommended way to acquire mutexes in a generic order safe
  1435. * manner. Performance benchmarks show that this does better than the one in
  1436. * libstdc++ even for the simple cases
  1437. *
  1438. * Usage is the same as std::lock() for arbitrary lockables
  1439. *
  1440. * folly::lock(one, two, three);
  1441. *
  1442. * To make it work with folly::Synchronized you have to specify how you want
  1443. * the locks to be acquired, use the folly::wlock(), folly::rlock(),
  1444. * folly::ulock() and folly::lock() helpers defined below
  1445. *
  1446. * auto [one, two] = lock(folly::wlock(a), folly::rlock(b));
  1447. *
  1448. * Note that you can/must avoid the folly:: namespace prefix on the lock()
  1449. * function if you use the helpers, ADL lookup is done to find the lock function
  1450. *
  1451. * This will execute the deadlock avoidance algorithm and acquire a write lock
  1452. * for a and a read lock for b
  1453. */
  1454. template <typename LockableOne, typename LockableTwo, typename... Lockables>
  1455. void lock(LockableOne& one, LockableTwo& two, Lockables&... lockables) {
  1456. auto locker = [](auto& lockable) {
  1457. using Lockable = std::remove_reference_t<decltype(lockable)>;
  1458. return detail::makeSynchronizedLocker(
  1459. lockable,
  1460. [](auto& l) { return std::unique_lock<Lockable>{l}; },
  1461. [](auto& l) {
  1462. auto lock = std::unique_lock<Lockable>{l, std::defer_lock};
  1463. lock.try_lock();
  1464. return lock;
  1465. });
  1466. };
  1467. auto locks = lock(locker(one), locker(two), locker(lockables)...);
  1468. // release ownership of the locks from the RAII lock wrapper returned by the
  1469. // function above
  1470. for_each(locks, [&](auto& lock) { lock.release(); });
  1471. }
  1472. /**
  1473. * Acquire locks for multiple Synchronized<T> objects, in a deadlock-safe
  1474. * manner.
  1475. *
  1476. * The locks are acquired in order from lowest address to highest address.
  1477. * (Note that this is not necessarily the same algorithm used by std::lock().)
  1478. * For parameters that are const and support shared locks, a read lock is
  1479. * acquired. Otherwise an exclusive lock is acquired.
  1480. *
  1481. * use lock() with folly::wlock(), folly::rlock() and folly::ulock() for
  1482. * arbitrary locking without causing a deadlock (as much as possible), with the
  1483. * same effects as std::lock()
  1484. */
  1485. template <class Sync1, class Sync2>
  1486. std::tuple<detail::LockedPtrType<Sync1>, detail::LockedPtrType<Sync2>>
  1487. acquireLocked(Sync1& l1, Sync2& l2) {
  1488. if (static_cast<const void*>(&l1) < static_cast<const void*>(&l2)) {
  1489. auto p1 = l1.contextualLock();
  1490. auto p2 = l2.contextualLock();
  1491. return std::make_tuple(std::move(p1), std::move(p2));
  1492. } else {
  1493. auto p2 = l2.contextualLock();
  1494. auto p1 = l1.contextualLock();
  1495. return std::make_tuple(std::move(p1), std::move(p2));
  1496. }
  1497. }
  1498. /**
  1499. * A version of acquireLocked() that returns a std::pair rather than a
  1500. * std::tuple, which is easier to use in many places.
  1501. */
  1502. template <class Sync1, class Sync2>
  1503. std::pair<detail::LockedPtrType<Sync1>, detail::LockedPtrType<Sync2>>
  1504. acquireLockedPair(Sync1& l1, Sync2& l2) {
  1505. auto lockedPtrs = acquireLocked(l1, l2);
  1506. return {std::move(std::get<0>(lockedPtrs)),
  1507. std::move(std::get<1>(lockedPtrs))};
  1508. }
  1509. /************************************************************************
  1510. * NOTE: All APIs below this line will be deprecated in upcoming diffs.
  1511. ************************************************************************/
  1512. // Non-member swap primitive
  1513. template <class T, class M>
  1514. void swap(Synchronized<T, M>& lhs, Synchronized<T, M>& rhs) {
  1515. lhs.swap(rhs);
  1516. }
  1517. /**
  1518. * Disambiguate the name var by concatenating the line number of the original
  1519. * point of expansion. This avoids shadowing warnings for nested
  1520. * SYNCHRONIZEDs. The name is consistent if used multiple times within
  1521. * another macro.
  1522. * Only for internal use.
  1523. */
  1524. #define SYNCHRONIZED_VAR(var) FB_CONCATENATE(SYNCHRONIZED_##var##_, __LINE__)
  1525. /**
  1526. * SYNCHRONIZED is the main facility that makes Synchronized<T>
  1527. * helpful. It is a pseudo-statement that introduces a scope where the
  1528. * object is locked. Inside that scope you get to access the unadorned
  1529. * datum.
  1530. *
  1531. * Example:
  1532. *
  1533. * Synchronized<vector<int>> svector;
  1534. * ...
  1535. * SYNCHRONIZED (svector) { ... use svector as a vector<int> ... }
  1536. * or
  1537. * SYNCHRONIZED (v, svector) { ... use v as a vector<int> ... }
  1538. *
  1539. * Refer to folly/docs/Synchronized.md for a detailed explanation and more
  1540. * examples.
  1541. */
  1542. #define SYNCHRONIZED(...) \
  1543. FOLLY_PUSH_WARNING \
  1544. FOLLY_GNU_DISABLE_WARNING("-Wshadow") \
  1545. FOLLY_MSVC_DISABLE_WARNING(4189) /* initialized but unreferenced */ \
  1546. FOLLY_MSVC_DISABLE_WARNING(4456) /* declaration hides local */ \
  1547. FOLLY_MSVC_DISABLE_WARNING(4457) /* declaration hides parameter */ \
  1548. FOLLY_MSVC_DISABLE_WARNING(4458) /* declaration hides member */ \
  1549. FOLLY_MSVC_DISABLE_WARNING(4459) /* declaration hides global */ \
  1550. FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS \
  1551. if (bool SYNCHRONIZED_VAR(state) = false) { \
  1552. } else \
  1553. for (auto SYNCHRONIZED_VAR(lockedPtr) = \
  1554. (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).operator->(); \
  1555. !SYNCHRONIZED_VAR(state); \
  1556. SYNCHRONIZED_VAR(state) = true) \
  1557. for (auto& FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \
  1558. *SYNCHRONIZED_VAR(lockedPtr).operator->(); \
  1559. !SYNCHRONIZED_VAR(state); \
  1560. SYNCHRONIZED_VAR(state) = true) \
  1561. FOLLY_POP_WARNING
  1562. #define TIMED_SYNCHRONIZED(timeout, ...) \
  1563. if (bool SYNCHRONIZED_VAR(state) = false) { \
  1564. } else \
  1565. for (auto SYNCHRONIZED_VAR(lockedPtr) = \
  1566. (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).timedAcquire(timeout); \
  1567. !SYNCHRONIZED_VAR(state); \
  1568. SYNCHRONIZED_VAR(state) = true) \
  1569. for (auto FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \
  1570. (!SYNCHRONIZED_VAR(lockedPtr) \
  1571. ? nullptr \
  1572. : SYNCHRONIZED_VAR(lockedPtr).operator->()); \
  1573. !SYNCHRONIZED_VAR(state); \
  1574. SYNCHRONIZED_VAR(state) = true)
  1575. /**
  1576. * Similar to SYNCHRONIZED, but only uses a read lock.
  1577. */
  1578. #define SYNCHRONIZED_CONST(...) \
  1579. SYNCHRONIZED( \
  1580. FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \
  1581. as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))))
  1582. /**
  1583. * Similar to TIMED_SYNCHRONIZED, but only uses a read lock.
  1584. */
  1585. #define TIMED_SYNCHRONIZED_CONST(timeout, ...) \
  1586. TIMED_SYNCHRONIZED( \
  1587. timeout, \
  1588. FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \
  1589. as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))))
  1590. /**
  1591. * Synchronizes two Synchronized objects (they may encapsulate
  1592. * different data). Synchronization is done in increasing address of
  1593. * object order, so there is no deadlock risk.
  1594. */
  1595. #define SYNCHRONIZED_DUAL(n1, e1, n2, e2) \
  1596. if (bool SYNCHRONIZED_VAR(state) = false) { \
  1597. } else \
  1598. for (auto SYNCHRONIZED_VAR(ptrs) = acquireLockedPair(e1, e2); \
  1599. !SYNCHRONIZED_VAR(state); \
  1600. SYNCHRONIZED_VAR(state) = true) \
  1601. for (auto& n1 = *SYNCHRONIZED_VAR(ptrs).first; !SYNCHRONIZED_VAR(state); \
  1602. SYNCHRONIZED_VAR(state) = true) \
  1603. for (auto& n2 = *SYNCHRONIZED_VAR(ptrs).second; \
  1604. !SYNCHRONIZED_VAR(state); \
  1605. SYNCHRONIZED_VAR(state) = true)
  1606. } /* namespace folly */