react-native-windows 0.81.34 → 0.81.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (928) hide show
  1. package/Directory.Build.props +1 -16
  2. package/Folly/ThreadNameStub.cpp +4 -6
  3. package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.cpp +1 -1
  4. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +27 -4
  5. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +8 -4
  6. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +7 -3
  7. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +48 -2
  8. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +40 -13
  9. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -7
  10. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -3
  11. package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -13
  12. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  13. package/PropertySheets/React.Cpp.props +3 -3
  14. package/ReactCommon/ReactCommon.vcxproj +0 -10
  15. package/ReactCommon/packages.lock.win32.json +0 -10
  16. package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +4 -37
  17. package/Scripts/creaternwlib.cmd +2 -2
  18. package/Shared/Shared.vcxitems +2 -0
  19. package/{Folly → external}/.clang-format +0 -1
  20. package/external/External.vcxitems +10 -0
  21. package/external/fast-float/.syncignore +10 -0
  22. package/external/fast-float/LICENSE-APACHE +190 -0
  23. package/external/fast-float/LICENSE-BOOST +23 -0
  24. package/external/fast-float/LICENSE-MIT +27 -0
  25. package/external/fast-float/README.md +545 -0
  26. package/external/fast-float/cgmanifest.json +15 -0
  27. package/external/fast-float/fast-float.vcxitems +14 -0
  28. package/external/fast-float/include/fast_float/ascii_number.h +588 -0
  29. package/external/fast-float/include/fast_float/bigint.h +638 -0
  30. package/external/fast-float/include/fast_float/constexpr_feature_detect.h +46 -0
  31. package/external/fast-float/include/fast_float/decimal_to_binary.h +212 -0
  32. package/external/fast-float/include/fast_float/digit_comparison.h +457 -0
  33. package/external/fast-float/include/fast_float/fast_float.h +59 -0
  34. package/external/fast-float/include/fast_float/fast_table.h +708 -0
  35. package/external/fast-float/include/fast_float/float_common.h +1240 -0
  36. package/external/fast-float/include/fast_float/parse_number.h +399 -0
  37. package/external/fast-float/sync-config.json +8 -0
  38. package/external/fmt/.syncignore +10 -0
  39. package/external/fmt/CONTRIBUTING.md +20 -0
  40. package/external/fmt/LICENSE +27 -0
  41. package/external/fmt/README.md +484 -0
  42. package/{fmt → external/fmt}/cgmanifest.json +1 -1
  43. package/external/fmt/doc/ChangeLog-old.md +3290 -0
  44. package/external/fmt/doc/api.md +650 -0
  45. package/external/fmt/doc/fmt.css +61 -0
  46. package/external/fmt/doc/fmt.js +4 -0
  47. package/external/fmt/doc/get-started.md +222 -0
  48. package/external/fmt/doc/index.md +151 -0
  49. package/external/fmt/doc/perf.svg +1 -0
  50. package/external/fmt/doc/python-license.txt +290 -0
  51. package/external/fmt/doc/syntax.md +887 -0
  52. package/external/fmt/fmt.vcxitems +28 -0
  53. package/external/fmt/include/fmt/args.h +228 -0
  54. package/{fmt/TEMP_UntilFmtUpdate/core.h → external/fmt/include/fmt/base.h} +1188 -1036
  55. package/external/fmt/include/fmt/chrono.h +2432 -0
  56. package/external/fmt/include/fmt/color.h +612 -0
  57. package/external/fmt/include/fmt/compile.h +529 -0
  58. package/external/fmt/include/fmt/core.h +5 -0
  59. package/external/fmt/include/fmt/format-inl.h +1928 -0
  60. package/external/fmt/include/fmt/format.h +4427 -0
  61. package/external/fmt/include/fmt/os.h +439 -0
  62. package/external/fmt/include/fmt/ostream.h +211 -0
  63. package/external/fmt/include/fmt/printf.h +656 -0
  64. package/external/fmt/include/fmt/ranges.h +882 -0
  65. package/external/fmt/include/fmt/std.h +699 -0
  66. package/external/fmt/include/fmt/xchar.h +322 -0
  67. package/external/fmt/src/fmt.cc +135 -0
  68. package/external/fmt/src/format.cc +43 -0
  69. package/external/fmt/src/os.cc +403 -0
  70. package/external/fmt/sync-config.json +8 -0
  71. package/external/folly/.syncignore +60 -0
  72. package/external/folly/LICENSE +200 -0
  73. package/external/folly/README.md +263 -0
  74. package/{fmt → external/folly/folly}/.clang-format +0 -1
  75. package/external/folly/folly/AtomicHashArray-inl.h +546 -0
  76. package/external/folly/folly/AtomicHashArray.h +431 -0
  77. package/external/folly/folly/AtomicHashMap-inl.h +653 -0
  78. package/external/folly/folly/AtomicHashMap.h +484 -0
  79. package/external/folly/folly/AtomicIntrusiveLinkedList.h +206 -0
  80. package/external/folly/folly/AtomicLinkedList.h +110 -0
  81. package/external/folly/folly/AtomicUnorderedMap.h +522 -0
  82. package/external/folly/folly/BUCK +1631 -0
  83. package/external/folly/folly/BUILD_MODE.bzl +72 -0
  84. package/external/folly/folly/Benchmark.cpp +986 -0
  85. package/external/folly/folly/Benchmark.h +680 -0
  86. package/external/folly/folly/BenchmarkUtil.h +47 -0
  87. package/external/folly/folly/Bits.h +17 -0
  88. package/external/folly/folly/CMakeLists.txt +110 -0
  89. package/external/folly/folly/CPortability.h +338 -0
  90. package/external/folly/folly/CancellationToken-inl.h +449 -0
  91. package/external/folly/folly/CancellationToken.cpp +250 -0
  92. package/external/folly/folly/CancellationToken.h +365 -0
  93. package/external/folly/folly/Chrono.h +132 -0
  94. package/external/folly/folly/ClockGettimeWrappers.cpp +93 -0
  95. package/external/folly/folly/ClockGettimeWrappers.h +29 -0
  96. package/external/folly/folly/ConcurrentBitSet.h +157 -0
  97. package/external/folly/folly/ConcurrentLazy.h +74 -0
  98. package/external/folly/folly/ConcurrentSkipList-inl.h +341 -0
  99. package/external/folly/folly/ConcurrentSkipList.h +824 -0
  100. package/external/folly/folly/ConstructorCallbackList.h +158 -0
  101. package/external/folly/folly/Conv.h +2026 -0
  102. package/external/folly/folly/CppAttributes.h +170 -0
  103. package/external/folly/folly/CpuId.h +297 -0
  104. package/external/folly/folly/DefaultKeepAliveExecutor.h +172 -0
  105. package/external/folly/folly/Demangle.cpp +255 -0
  106. package/external/folly/folly/Demangle.h +73 -0
  107. package/external/folly/folly/DiscriminatedPtr.h +236 -0
  108. package/external/folly/folly/DynamicConverter.h +17 -0
  109. package/external/folly/folly/Exception.h +150 -0
  110. package/external/folly/folly/ExceptionString.cpp +51 -0
  111. package/external/folly/folly/ExceptionString.h +33 -0
  112. package/external/folly/folly/ExceptionWrapper-inl.h +264 -0
  113. package/external/folly/folly/ExceptionWrapper.cpp +37 -0
  114. package/external/folly/folly/ExceptionWrapper.h +377 -0
  115. package/external/folly/folly/Executor.cpp +111 -0
  116. package/external/folly/folly/Executor.h +351 -0
  117. package/external/folly/folly/Expected.h +1725 -0
  118. package/external/folly/folly/FBString.h +2888 -0
  119. package/external/folly/folly/FBVector.h +17 -0
  120. package/external/folly/folly/File.cpp +180 -0
  121. package/external/folly/folly/File.h +177 -0
  122. package/external/folly/folly/FileUtil.cpp +378 -0
  123. package/external/folly/folly/FileUtil.h +332 -0
  124. package/external/folly/folly/Fingerprint.cpp +135 -0
  125. package/external/folly/folly/Fingerprint.h +289 -0
  126. package/external/folly/folly/FixedString.h +2965 -0
  127. package/external/folly/folly/FollyMemcpy.cpp +30 -0
  128. package/external/folly/folly/FollyMemcpy.h +23 -0
  129. package/external/folly/folly/FollyMemset.cpp +29 -0
  130. package/external/folly/folly/FollyMemset.h +25 -0
  131. package/external/folly/folly/Format-inl.h +1152 -0
  132. package/external/folly/folly/Format.cpp +429 -0
  133. package/external/folly/folly/Format.h +463 -0
  134. package/external/folly/folly/FormatArg.h +285 -0
  135. package/external/folly/folly/FormatTraits.h +65 -0
  136. package/external/folly/folly/Function.h +1159 -0
  137. package/external/folly/folly/GLog.h +85 -0
  138. package/external/folly/folly/GroupVarint.cpp +153 -0
  139. package/external/folly/folly/GroupVarint.h +630 -0
  140. package/external/folly/folly/Hash.h +20 -0
  141. package/external/folly/folly/IPAddress.cpp +490 -0
  142. package/external/folly/folly/IPAddress.h +667 -0
  143. package/external/folly/folly/IPAddressException.h +82 -0
  144. package/external/folly/folly/IPAddressV4.cpp +305 -0
  145. package/external/folly/folly/IPAddressV4.h +495 -0
  146. package/external/folly/folly/IPAddressV6.cpp +541 -0
  147. package/external/folly/folly/IPAddressV6.h +627 -0
  148. package/external/folly/folly/Indestructible.h +164 -0
  149. package/external/folly/folly/IndexedMemPool.h +550 -0
  150. package/external/folly/folly/IntrusiveList.h +17 -0
  151. package/external/folly/folly/Lazy.h +142 -0
  152. package/external/folly/folly/Likely.h +76 -0
  153. package/external/folly/folly/MPMCPipeline.h +280 -0
  154. package/external/folly/folly/MPMCQueue.h +1556 -0
  155. package/external/folly/folly/MacAddress.cpp +188 -0
  156. package/external/folly/folly/MacAddress.h +260 -0
  157. package/external/folly/folly/MapUtil.h +17 -0
  158. package/external/folly/folly/Math.h +258 -0
  159. package/external/folly/folly/MaybeManagedPtr.h +120 -0
  160. package/external/folly/folly/Memory.h +900 -0
  161. package/external/folly/folly/MicroLock.cpp +76 -0
  162. package/external/folly/folly/MicroLock.h +354 -0
  163. package/external/folly/folly/MicroSpinLock.h +17 -0
  164. package/external/folly/folly/MoveWrapper.h +76 -0
  165. package/external/folly/folly/ObserverContainer.h +1026 -0
  166. package/external/folly/folly/Optional.h +743 -0
  167. package/external/folly/folly/Overload.h +325 -0
  168. package/external/folly/folly/PackedSyncPtr.h +147 -0
  169. package/external/folly/folly/Padded.h +464 -0
  170. package/external/folly/folly/Poly-inl.h +230 -0
  171. package/external/folly/folly/Poly.h +1095 -0
  172. package/external/folly/folly/PolyException.h +43 -0
  173. package/external/folly/folly/Portability.h +644 -0
  174. package/external/folly/folly/Preprocessor.h +236 -0
  175. package/external/folly/folly/ProducerConsumerQueue.h +182 -0
  176. package/external/folly/folly/RWSpinLock.h +17 -0
  177. package/external/folly/folly/Random-inl.h +86 -0
  178. package/external/folly/folly/Random.cpp +184 -0
  179. package/external/folly/folly/Random.h +434 -0
  180. package/external/folly/folly/Range.h +1772 -0
  181. package/external/folly/folly/Replaceable.h +636 -0
  182. package/external/folly/folly/ScopeGuard.cpp +29 -0
  183. package/external/folly/folly/ScopeGuard.h +420 -0
  184. package/external/folly/folly/SharedMutex.cpp +81 -0
  185. package/external/folly/folly/SharedMutex.h +1751 -0
  186. package/external/folly/folly/Singleton-inl.h +332 -0
  187. package/external/folly/folly/Singleton.cpp +512 -0
  188. package/external/folly/folly/Singleton.h +891 -0
  189. package/external/folly/folly/SingletonThreadLocal.cpp +53 -0
  190. package/external/folly/folly/SingletonThreadLocal.h +263 -0
  191. package/external/folly/folly/SocketAddress.cpp +786 -0
  192. package/external/folly/folly/SocketAddress.h +768 -0
  193. package/external/folly/folly/SpinLock.h +55 -0
  194. package/external/folly/folly/String-inl.h +668 -0
  195. package/external/folly/folly/String.cpp +777 -0
  196. package/external/folly/folly/String.h +767 -0
  197. package/external/folly/folly/Subprocess.cpp +1142 -0
  198. package/external/folly/folly/Subprocess.h +1055 -0
  199. package/external/folly/folly/Synchronized.h +1833 -0
  200. package/external/folly/folly/SynchronizedPtr.h +106 -0
  201. package/external/folly/folly/ThreadCachedInt.h +175 -0
  202. package/external/folly/folly/ThreadLocal.h +478 -0
  203. package/external/folly/folly/TimeoutQueue.cpp +78 -0
  204. package/external/folly/folly/TimeoutQueue.h +123 -0
  205. package/external/folly/folly/TokenBucket.h +673 -0
  206. package/external/folly/folly/Traits.h +1442 -0
  207. package/external/folly/folly/Try-inl.h +372 -0
  208. package/external/folly/folly/Try.cpp +23 -0
  209. package/external/folly/folly/Try.h +728 -0
  210. package/external/folly/folly/UTF8String.h +56 -0
  211. package/external/folly/folly/Unicode.cpp +201 -0
  212. package/external/folly/folly/Unicode.h +94 -0
  213. package/external/folly/folly/Unit.h +65 -0
  214. package/external/folly/folly/Uri-inl.h +101 -0
  215. package/external/folly/folly/Uri.cpp +190 -0
  216. package/external/folly/folly/Uri.h +142 -0
  217. package/external/folly/folly/Utility.h +932 -0
  218. package/external/folly/folly/VERSION +1 -0
  219. package/external/folly/folly/Varint.h +230 -0
  220. package/external/folly/folly/VirtualExecutor.h +17 -0
  221. package/external/folly/folly/algorithm/simd/BUCK +47 -0
  222. package/external/folly/folly/algorithm/simd/Contains.cpp +42 -0
  223. package/external/folly/folly/algorithm/simd/Contains.h +116 -0
  224. package/external/folly/folly/algorithm/simd/FindFixed.h +301 -0
  225. package/external/folly/folly/algorithm/simd/Ignore.h +52 -0
  226. package/external/folly/folly/algorithm/simd/Movemask.h +207 -0
  227. package/external/folly/folly/algorithm/simd/detail/BUCK +70 -0
  228. package/external/folly/folly/algorithm/simd/detail/ContainsImpl.h +91 -0
  229. package/external/folly/folly/algorithm/simd/detail/SimdAnyOf.h +83 -0
  230. package/external/folly/folly/algorithm/simd/detail/SimdForEach.h +209 -0
  231. package/external/folly/folly/algorithm/simd/detail/SimdPlatform.h +445 -0
  232. package/external/folly/folly/algorithm/simd/detail/Traits.h +125 -0
  233. package/external/folly/folly/algorithm/simd/detail/UnrollUtils.h +126 -0
  234. package/external/folly/folly/base64.h +264 -0
  235. package/external/folly/folly/chrono/BUCK +29 -0
  236. package/external/folly/folly/chrono/Clock.h +65 -0
  237. package/external/folly/folly/chrono/Conv.h +712 -0
  238. package/external/folly/folly/chrono/test/BUCK +26 -0
  239. package/external/folly/folly/chrono/test/ClockTest.cpp +68 -0
  240. package/external/folly/folly/chrono/test/ConvTest.cpp +652 -0
  241. package/external/folly/folly/concurrency/AtomicSharedPtr.h +387 -0
  242. package/external/folly/folly/concurrency/BUCK +170 -0
  243. package/external/folly/folly/concurrency/CacheLocality.h +460 -0
  244. package/external/folly/folly/concurrency/ConcurrentHashMap.h +822 -0
  245. package/external/folly/folly/concurrency/CoreCachedSharedPtr.h +232 -0
  246. package/external/folly/folly/concurrency/DeadlockDetector.cpp +27 -0
  247. package/external/folly/folly/concurrency/DeadlockDetector.h +44 -0
  248. package/external/folly/folly/concurrency/DynamicBoundedQueue.h +751 -0
  249. package/external/folly/folly/concurrency/PriorityUnboundedQueueSet.h +207 -0
  250. package/external/folly/folly/concurrency/ProcessLocalUniqueId.cpp +46 -0
  251. package/external/folly/folly/concurrency/ProcessLocalUniqueId.h +38 -0
  252. package/external/folly/folly/concurrency/SingletonRelaxedCounter.h +325 -0
  253. package/external/folly/folly/concurrency/ThreadCachedSynchronized.h +227 -0
  254. package/external/folly/folly/concurrency/UnboundedQueue.h +891 -0
  255. package/external/folly/folly/concurrency/container/BUCK +77 -0
  256. package/external/folly/folly/concurrency/container/FlatCombiningPriorityQueue.h +426 -0
  257. package/external/folly/folly/concurrency/container/LockFreeRingBuffer.h +306 -0
  258. package/external/folly/folly/concurrency/container/RelaxedConcurrentPriorityQueue.h +1212 -0
  259. package/external/folly/folly/concurrency/container/SingleWriterFixedHashMap.h +322 -0
  260. package/external/folly/folly/concurrency/container/atomic_grow_array.h +564 -0
  261. package/external/folly/folly/concurrency/container/test/BUCK +75 -0
  262. package/external/folly/folly/concurrency/container/test/FlatCombiningPriorityQueueTest.cpp +570 -0
  263. package/external/folly/folly/concurrency/container/test/LockFreeRingBufferTest.cpp +276 -0
  264. package/external/folly/folly/concurrency/container/test/RelaxedConcurrentPriorityQueueTest.cpp +1570 -0
  265. package/external/folly/folly/concurrency/container/test/SingleWriterFixedHashMapTest.cpp +401 -0
  266. package/external/folly/folly/concurrency/container/test/atomic_grow_array_test.cpp +187 -0
  267. package/external/folly/folly/concurrency/detail/AtomicSharedPtr-detail.h +212 -0
  268. package/external/folly/folly/concurrency/detail/ConcurrentHashMap-detail.h +1911 -0
  269. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.cpp +43 -0
  270. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.h +190 -0
  271. package/external/folly/folly/concurrency/memory/BUCK +53 -0
  272. package/external/folly/folly/concurrency/memory/PrimaryPtr.h +338 -0
  273. package/external/folly/folly/concurrency/memory/ReadMostlySharedPtr.h +511 -0
  274. package/external/folly/folly/concurrency/memory/TLRefCount.h +228 -0
  275. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrBenchmark.cpp +56 -0
  276. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrTest.cpp +454 -0
  277. package/external/folly/folly/concurrency/memory/test/BUCK +95 -0
  278. package/external/folly/folly/concurrency/memory/test/PrimaryPtrTest.cpp +303 -0
  279. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrBenchmark.cpp +138 -0
  280. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrStressTest.cpp +75 -0
  281. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrTest.cpp +378 -0
  282. package/external/folly/folly/concurrency/memory/test/RefCountBenchmark.cpp +90 -0
  283. package/external/folly/folly/concurrency/memory/test/RefCountTest.cpp +168 -0
  284. package/external/folly/folly/concurrency/test/AtomicSharedPtrCounted.h +156 -0
  285. package/external/folly/folly/concurrency/test/AtomicSharedPtrPerformance.cpp +255 -0
  286. package/external/folly/folly/concurrency/test/AtomicSharedPtrTest.cpp +257 -0
  287. package/external/folly/folly/concurrency/test/BUCK +229 -0
  288. package/external/folly/folly/concurrency/test/CacheLocalityBenchmark.cpp +392 -0
  289. package/external/folly/folly/concurrency/test/CacheLocalityTest.cpp +1229 -0
  290. package/external/folly/folly/concurrency/test/ConcurrentHashMapBench.cpp +260 -0
  291. package/external/folly/folly/concurrency/test/ConcurrentHashMapTest.cpp +1242 -0
  292. package/external/folly/folly/concurrency/test/CoreCachedSharedPtrTest.cpp +408 -0
  293. package/external/folly/folly/concurrency/test/DynamicBoundedQueueTest.cpp +984 -0
  294. package/external/folly/folly/concurrency/test/PriorityUnboundedQueueSetTest.cpp +73 -0
  295. package/external/folly/folly/concurrency/test/ProcessLocalUniqueIdTest.cpp +66 -0
  296. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterBench.cpp +101 -0
  297. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterTest.cpp +185 -0
  298. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedBench.cpp +76 -0
  299. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedTest.cpp +93 -0
  300. package/external/folly/folly/concurrency/test/UnboundedQueueTest.cpp +1302 -0
  301. package/external/folly/folly/container/Access.h +57 -0
  302. package/external/folly/folly/container/Array.h +87 -0
  303. package/external/folly/folly/container/BUCK +353 -0
  304. package/external/folly/folly/container/BitIterator.h +203 -0
  305. package/external/folly/folly/container/Enumerate.h +162 -0
  306. package/external/folly/folly/container/EvictingCacheMap.h +730 -0
  307. package/external/folly/folly/container/F14.md +300 -0
  308. package/external/folly/folly/container/F14Map-fwd.h +113 -0
  309. package/external/folly/folly/container/F14Map.h +2108 -0
  310. package/external/folly/folly/container/F14Set-fwd.h +95 -0
  311. package/external/folly/folly/container/F14Set.h +1603 -0
  312. package/external/folly/folly/container/FBVector.h +1711 -0
  313. package/external/folly/folly/container/Foreach-inl.h +316 -0
  314. package/external/folly/folly/container/Foreach.h +209 -0
  315. package/external/folly/folly/container/HeterogeneousAccess-fwd.h +33 -0
  316. package/external/folly/folly/container/HeterogeneousAccess.h +171 -0
  317. package/external/folly/folly/container/IntrusiveHeap.h +268 -0
  318. package/external/folly/folly/container/IntrusiveList.h +131 -0
  319. package/external/folly/folly/container/Iterator.h +843 -0
  320. package/external/folly/folly/container/MapUtil.h +376 -0
  321. package/external/folly/folly/container/Merge.h +90 -0
  322. package/external/folly/folly/container/RegexMatchCache.cpp +521 -0
  323. package/external/folly/folly/container/RegexMatchCache.h +699 -0
  324. package/external/folly/folly/container/Reserve.h +109 -0
  325. package/external/folly/folly/container/SparseByteSet.h +123 -0
  326. package/external/folly/folly/container/View.h +81 -0
  327. package/external/folly/folly/container/WeightedEvictingCacheMap.h +651 -0
  328. package/external/folly/folly/container/detail/BUCK +115 -0
  329. package/external/folly/folly/container/detail/BitIteratorDetail.h +87 -0
  330. package/external/folly/folly/container/detail/F14Defaults.h +34 -0
  331. package/external/folly/folly/container/detail/F14IntrinsicsAvailability.h +67 -0
  332. package/external/folly/folly/container/detail/F14MapFallback.h +717 -0
  333. package/external/folly/folly/container/detail/F14Mask.h +235 -0
  334. package/external/folly/folly/container/detail/F14Policy.h +1523 -0
  335. package/external/folly/folly/container/detail/F14SetFallback.h +528 -0
  336. package/external/folly/folly/container/detail/F14Table.cpp +71 -0
  337. package/external/folly/folly/container/detail/F14Table.h +2680 -0
  338. package/external/folly/folly/container/detail/Util.h +303 -0
  339. package/external/folly/folly/container/detail/tape_detail.h +135 -0
  340. package/external/folly/folly/container/detail/test/BUCK +14 -0
  341. package/external/folly/folly/container/detail/test/F14DetailTest.cpp +47 -0
  342. package/external/folly/folly/container/heap_vector_types.h +1683 -0
  343. package/external/folly/folly/container/range_traits.h +81 -0
  344. package/external/folly/folly/container/small_vector.h +1476 -0
  345. package/external/folly/folly/container/sorted_vector_types.h +1652 -0
  346. package/external/folly/folly/container/span.h +408 -0
  347. package/external/folly/folly/container/tape.h +608 -0
  348. package/external/folly/folly/container/test/.clang-tidy +12 -0
  349. package/external/folly/folly/container/test/AccessTest.cpp +138 -0
  350. package/external/folly/folly/container/test/ArrayTest.cpp +84 -0
  351. package/external/folly/folly/container/test/BUCK +568 -0
  352. package/external/folly/folly/container/test/BitIteratorBench.cpp +112 -0
  353. package/external/folly/folly/container/test/BitIteratorTest.cpp +109 -0
  354. package/external/folly/folly/container/test/EnumerateTest.cpp +294 -0
  355. package/external/folly/folly/container/test/EvictingCacheMapBench.cpp +80 -0
  356. package/external/folly/folly/container/test/EvictingCacheMapTest.cpp +842 -0
  357. package/external/folly/folly/container/test/F14AsanSupportTest.cpp +143 -0
  358. package/external/folly/folly/container/test/F14FwdTest.cpp +37 -0
  359. package/external/folly/folly/container/test/F14InterprocessTest.cpp +404 -0
  360. package/external/folly/folly/container/test/F14MapTest.cpp +2543 -0
  361. package/external/folly/folly/container/test/F14PolicyTest.cpp +49 -0
  362. package/external/folly/folly/container/test/F14SetTest.cpp +1738 -0
  363. package/external/folly/folly/container/test/F14SmallOverheads.cpp +215 -0
  364. package/external/folly/folly/container/test/F14TestUtil.h +117 -0
  365. package/external/folly/folly/container/test/FBVectorBenchmark.cpp +380 -0
  366. package/external/folly/folly/container/test/FBVectorBenchmarks.cpp.h +100 -0
  367. package/external/folly/folly/container/test/FBVectorTest.cpp +326 -0
  368. package/external/folly/folly/container/test/FBVectorTests.cpp.h +304 -0
  369. package/external/folly/folly/container/test/ForeachBenchmark.cpp +388 -0
  370. package/external/folly/folly/container/test/ForeachTest.cpp +338 -0
  371. package/external/folly/folly/container/test/HashMapsBench.cpp +458 -0
  372. package/external/folly/folly/container/test/HeterogeneousAccessTest.cpp +242 -0
  373. package/external/folly/folly/container/test/IntrusiveHeapTest.cpp +262 -0
  374. package/external/folly/folly/container/test/IteratorTest.cpp +989 -0
  375. package/external/folly/folly/container/test/MapUtilTest.cpp +365 -0
  376. package/external/folly/folly/container/test/MergeTest.cpp +66 -0
  377. package/external/folly/folly/container/test/RegexMatchCacheTest.cpp +634 -0
  378. package/external/folly/folly/container/test/ReserveTest.cpp +173 -0
  379. package/external/folly/folly/container/test/SparseByteSetBenchmark.cpp +153 -0
  380. package/external/folly/folly/container/test/SparseByteSetTest.cpp +117 -0
  381. package/external/folly/folly/container/test/TrackingTypes.h +584 -0
  382. package/external/folly/folly/container/test/UtilTest.cpp +609 -0
  383. package/external/folly/folly/container/test/WeightedEvictingCacheMapTest.cpp +800 -0
  384. package/external/folly/folly/container/test/heap_vector_types_test.cpp +1774 -0
  385. package/external/folly/folly/container/test/range_traits_test.cpp +59 -0
  386. package/external/folly/folly/container/test/small_vector_test.cpp +1571 -0
  387. package/external/folly/folly/container/test/sorted_vector_test.cpp +1589 -0
  388. package/external/folly/folly/container/test/span_test.cpp +520 -0
  389. package/external/folly/folly/container/test/tape_bench.cpp +200 -0
  390. package/external/folly/folly/container/test/tape_test.cpp +590 -0
  391. package/external/folly/folly/defs.bzl +238 -0
  392. package/external/folly/folly/detail/AsyncTrace.cpp +36 -0
  393. package/external/folly/folly/detail/AsyncTrace.h +44 -0
  394. package/external/folly/folly/detail/AtomicHashUtils.h +42 -0
  395. package/external/folly/folly/detail/AtomicUnorderedMapUtils.h +80 -0
  396. package/external/folly/folly/detail/BUCK +406 -0
  397. package/external/folly/folly/detail/DiscriminatedPtrDetail.h +172 -0
  398. package/external/folly/folly/detail/FileUtilDetail.cpp +63 -0
  399. package/external/folly/folly/detail/FileUtilDetail.h +85 -0
  400. package/external/folly/folly/detail/FileUtilVectorDetail.h +81 -0
  401. package/external/folly/folly/detail/FingerprintPolynomial.h +132 -0
  402. package/external/folly/folly/detail/Futex-inl.h +123 -0
  403. package/external/folly/folly/detail/Futex.cpp +273 -0
  404. package/external/folly/folly/detail/Futex.h +109 -0
  405. package/external/folly/folly/detail/GroupVarintDetail.h +101 -0
  406. package/external/folly/folly/detail/IPAddress.cpp +37 -0
  407. package/external/folly/folly/detail/IPAddress.h +57 -0
  408. package/external/folly/folly/detail/IPAddressSource.h +278 -0
  409. package/external/folly/folly/detail/Iterators.h +156 -0
  410. package/external/folly/folly/detail/MPMCPipelineDetail.h +122 -0
  411. package/external/folly/folly/detail/MemoryIdler.cpp +233 -0
  412. package/external/folly/folly/detail/MemoryIdler.h +216 -0
  413. package/external/folly/folly/detail/PerfScoped.cpp +112 -0
  414. package/external/folly/folly/detail/PerfScoped.h +70 -0
  415. package/external/folly/folly/detail/PolyDetail.h +921 -0
  416. package/external/folly/folly/detail/RangeCommon.cpp +55 -0
  417. package/external/folly/folly/detail/RangeCommon.h +93 -0
  418. package/external/folly/folly/detail/RangeSse42.cpp +198 -0
  419. package/external/folly/folly/detail/RangeSse42.h +30 -0
  420. package/external/folly/folly/detail/SimpleSimdStringUtils.cpp +31 -0
  421. package/external/folly/folly/detail/SimpleSimdStringUtils.h +27 -0
  422. package/external/folly/folly/detail/SimpleSimdStringUtilsImpl.h +63 -0
  423. package/external/folly/folly/detail/Singleton.h +34 -0
  424. package/external/folly/folly/detail/SlowFingerprint.h +90 -0
  425. package/external/folly/folly/detail/SocketFastOpen.cpp +175 -0
  426. package/external/folly/folly/detail/SocketFastOpen.h +89 -0
  427. package/external/folly/folly/detail/SplitStringSimd.cpp +84 -0
  428. package/external/folly/folly/detail/SplitStringSimd.h +151 -0
  429. package/external/folly/folly/detail/SplitStringSimdImpl.h +149 -0
  430. package/external/folly/folly/detail/Sse.cpp +35 -0
  431. package/external/folly/folly/detail/Sse.h +45 -0
  432. package/external/folly/folly/detail/StaticSingletonManager.cpp +119 -0
  433. package/external/folly/folly/detail/StaticSingletonManager.h +298 -0
  434. package/external/folly/folly/detail/ThreadLocalDetail.cpp +492 -0
  435. package/external/folly/folly/detail/ThreadLocalDetail.h +800 -0
  436. package/external/folly/folly/detail/TrapOnAvx512.cpp +41 -0
  437. package/external/folly/folly/detail/TrapOnAvx512.h +21 -0
  438. package/external/folly/folly/detail/TurnSequencer.h +295 -0
  439. package/external/folly/folly/detail/TypeList.h +551 -0
  440. package/external/folly/folly/detail/UniqueInstance.cpp +136 -0
  441. package/external/folly/folly/detail/UniqueInstance.h +68 -0
  442. package/external/folly/folly/detail/base64_detail/BUCK +102 -0
  443. package/external/folly/folly/detail/base64_detail/Base64Api.cpp +40 -0
  444. package/external/folly/folly/detail/base64_detail/Base64Api.h +101 -0
  445. package/external/folly/folly/detail/base64_detail/Base64Common.h +80 -0
  446. package/external/folly/folly/detail/base64_detail/Base64Constants.h +79 -0
  447. package/external/folly/folly/detail/base64_detail/Base64HiddenConstants.h +129 -0
  448. package/external/folly/folly/detail/base64_detail/Base64SWAR.cpp +161 -0
  449. package/external/folly/folly/detail/base64_detail/Base64SWAR.h +32 -0
  450. package/external/folly/folly/detail/base64_detail/Base64Scalar.h +262 -0
  451. package/external/folly/folly/detail/base64_detail/Base64Simd.h +102 -0
  452. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.cpp +42 -0
  453. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.h +33 -0
  454. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2_Platform.h +167 -0
  455. package/external/folly/folly/detail/base64_detail/README.md +392 -0
  456. package/external/folly/folly/detail/base64_detail/tests/BUCK +36 -0
  457. package/external/folly/folly/detail/base64_detail/tests/Base64AgainstScalarTest.cpp +141 -0
  458. package/external/folly/folly/detail/base64_detail/tests/Base64PlatformTest.cpp +273 -0
  459. package/external/folly/folly/detail/base64_detail/tests/Base64SpecialCasesTest.cpp +555 -0
  460. package/external/folly/folly/detail/test/AsyncTraceTest.cpp +43 -0
  461. package/external/folly/folly/detail/test/BUCK +118 -0
  462. package/external/folly/folly/detail/test/FileUtilDetailTest.cpp +56 -0
  463. package/external/folly/folly/detail/test/PerfScopedTest.cpp +107 -0
  464. package/external/folly/folly/detail/test/SimpleSimdStringUtilsTest.cpp +92 -0
  465. package/external/folly/folly/detail/test/SplitStringSimdTest.cpp +242 -0
  466. package/external/folly/folly/detail/test/StaticSingletonManagerTest.cpp +121 -0
  467. package/external/folly/folly/detail/test/ThreadLocalBenchmark.cpp +116 -0
  468. package/external/folly/folly/detail/test/ThreadLocalDetailTest.cpp +194 -0
  469. package/external/folly/folly/detail/test/TrapOnAvx512TestNegative.cpp +29 -0
  470. package/external/folly/folly/detail/test/UniqueInstanceTest.cpp +60 -0
  471. package/external/folly/folly/detail/thread_local_globals.cpp +69 -0
  472. package/external/folly/folly/detail/thread_local_globals.h +36 -0
  473. package/external/folly/folly/docs/AtomicHashMap.md +134 -0
  474. package/external/folly/folly/docs/Benchmark.md +310 -0
  475. package/external/folly/folly/docs/Conv.md +291 -0
  476. package/external/folly/folly/docs/Dynamic.md +220 -0
  477. package/external/folly/folly/docs/DynamicConverter.md +71 -0
  478. package/external/folly/folly/docs/Executors.md +63 -0
  479. package/external/folly/folly/docs/FBString.md +46 -0
  480. package/external/folly/folly/docs/FBVector.md +200 -0
  481. package/external/folly/folly/docs/Fbvector--graphical_solutions.png +0 -0
  482. package/external/folly/folly/docs/Format.md +177 -0
  483. package/external/folly/folly/docs/Function.md +92 -0
  484. package/external/folly/folly/docs/Futures.md +263 -0
  485. package/external/folly/folly/docs/GroupVarint.md +46 -0
  486. package/external/folly/folly/docs/Histogram.md +104 -0
  487. package/external/folly/folly/docs/MapUtils.md +80 -0
  488. package/external/folly/folly/docs/Overview.md +263 -0
  489. package/external/folly/folly/docs/PackedSyncPtr.md +77 -0
  490. package/external/folly/folly/docs/Poly.md +500 -0
  491. package/external/folly/folly/docs/ProducerConsumerQueue.md +82 -0
  492. package/external/folly/folly/docs/Rcu.md +218 -0
  493. package/external/folly/folly/docs/SmallLocks.md +24 -0
  494. package/external/folly/folly/docs/Synchronized.md +793 -0
  495. package/external/folly/folly/docs/ThreadCachedInt.md +98 -0
  496. package/external/folly/folly/docs/ThreadLocal.md +105 -0
  497. package/external/folly/folly/docs/Traits.md +161 -0
  498. package/external/folly/folly/docs/small_vector.md +64 -0
  499. package/external/folly/folly/docs/style.css +23 -0
  500. package/external/folly/folly/dynamic-inl.h +17 -0
  501. package/external/folly/folly/dynamic.h +17 -0
  502. package/external/folly/folly/folly_extended_library.bzl +28 -0
  503. package/external/folly/folly/functional/ApplyTuple.h +204 -0
  504. package/external/folly/folly/functional/BUCK +57 -0
  505. package/external/folly/folly/functional/Invoke.h +880 -0
  506. package/external/folly/folly/functional/Partial.h +130 -0
  507. package/external/folly/folly/functional/protocol.h +203 -0
  508. package/external/folly/folly/functional/test/ApplyTupleTest.cpp +549 -0
  509. package/external/folly/folly/functional/test/BUCK +57 -0
  510. package/external/folly/folly/functional/test/InvokeTest.cpp +483 -0
  511. package/external/folly/folly/functional/test/PartialTest.cpp +141 -0
  512. package/external/folly/folly/functional/test/protocol_test.cpp +177 -0
  513. package/external/folly/folly/functional/test/traits_test.cpp +551 -0
  514. package/external/folly/folly/functional/traits.h +675 -0
  515. package/external/folly/folly/hash/BUCK +86 -0
  516. package/external/folly/folly/hash/Checksum.cpp +275 -0
  517. package/external/folly/folly/hash/Checksum.h +94 -0
  518. package/external/folly/folly/hash/FarmHash.h +46 -0
  519. package/external/folly/folly/hash/Hash.h +1045 -0
  520. package/external/folly/folly/hash/MurmurHash.h +86 -0
  521. package/external/folly/folly/hash/SpookyHashV1.cpp +391 -0
  522. package/external/folly/folly/hash/SpookyHashV1.h +307 -0
  523. package/external/folly/folly/hash/SpookyHashV2.cpp +392 -0
  524. package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/hash/SpookyHashV2.h +6 -1
  525. package/external/folly/folly/hash/detail/BUCK +26 -0
  526. package/external/folly/folly/hash/detail/ChecksumDetail.cpp +296 -0
  527. package/external/folly/folly/hash/detail/ChecksumDetail.h +137 -0
  528. package/external/folly/folly/hash/detail/Crc32CombineDetail.cpp +191 -0
  529. package/external/folly/folly/hash/detail/Crc32cDetail.cpp +303 -0
  530. package/external/folly/folly/hash/test/BUCK +132 -0
  531. package/external/folly/folly/hash/test/ChecksumBenchmark.cpp +91 -0
  532. package/external/folly/folly/hash/test/ChecksumTest.cpp +587 -0
  533. package/external/folly/folly/hash/test/FarmHashTest.cpp +41 -0
  534. package/external/folly/folly/hash/test/HashBenchmark.cpp +238 -0
  535. package/external/folly/folly/hash/test/HashTest.cpp +997 -0
  536. package/external/folly/folly/hash/test/MurmurHashTest.cpp +76 -0
  537. package/external/folly/folly/hash/test/SpookyHashV1Test.cpp +559 -0
  538. package/external/folly/folly/hash/test/SpookyHashV2Test.cpp +549 -0
  539. package/external/folly/folly/hash/test/traits_test.cpp +69 -0
  540. package/external/folly/folly/hash/traits.h +115 -0
  541. package/external/folly/folly/json/BUCK +155 -0
  542. package/external/folly/folly/json/DynamicConverter.h +464 -0
  543. package/external/folly/folly/json/DynamicParser-inl.h +316 -0
  544. package/external/folly/folly/json/DynamicParser.cpp +198 -0
  545. package/external/folly/folly/json/DynamicParser.h +394 -0
  546. package/external/folly/folly/json/JSONSchema.cpp +1030 -0
  547. package/external/folly/folly/json/JSONSchema.h +73 -0
  548. package/external/folly/folly/json/JsonMockUtil.h +73 -0
  549. package/external/folly/folly/json/JsonTestUtil.cpp +167 -0
  550. package/external/folly/folly/json/JsonTestUtil.h +88 -0
  551. package/external/folly/folly/json/bser/BUCK +24 -0
  552. package/external/folly/folly/json/bser/Bser.h +107 -0
  553. package/external/folly/folly/json/bser/Dump.cpp +253 -0
  554. package/external/folly/folly/json/bser/Load.cpp +246 -0
  555. package/external/folly/folly/json/bser/test/BUCK +14 -0
  556. package/external/folly/folly/json/bser/test/BserTest.cpp +149 -0
  557. package/external/folly/folly/json/dynamic.cpp +552 -0
  558. package/external/folly/folly/json/dynamic.h +1346 -0
  559. package/external/folly/folly/json/json.h +238 -0
  560. package/external/folly/folly/json/json_patch.cpp +325 -0
  561. package/external/folly/folly/json/json_patch.h +126 -0
  562. package/external/folly/folly/json/json_pointer.cpp +114 -0
  563. package/external/folly/folly/json/json_pointer.h +87 -0
  564. package/external/folly/folly/json/test/BUCK +147 -0
  565. package/external/folly/folly/json/test/DynamicBenchmark.cpp +146 -0
  566. package/external/folly/folly/json/test/DynamicConverterTest.cpp +518 -0
  567. package/external/folly/folly/json/test/DynamicOtherTest.cpp +344 -0
  568. package/external/folly/folly/json/test/DynamicParserTest.cpp +443 -0
  569. package/external/folly/folly/json/test/DynamicTest.cpp +1647 -0
  570. package/external/folly/folly/json/test/JSONSchemaTest.cpp +450 -0
  571. package/external/folly/folly/json/test/JsonBenchmark.cpp +264 -0
  572. package/external/folly/folly/json/test/JsonOtherTest.cpp +51 -0
  573. package/external/folly/folly/json/test/JsonTest.cpp +1153 -0
  574. package/external/folly/folly/json/test/JsonTestUtilTest.cpp +97 -0
  575. package/external/folly/folly/json/test/json_patch_test.cpp +361 -0
  576. package/external/folly/folly/json/test/json_pointer_test.cpp +58 -0
  577. package/external/folly/folly/json/tool/BUCK +13 -0
  578. package/external/folly/folly/json/tool/JSONSchemaTester.cpp +58 -0
  579. package/external/folly/folly/json.h +17 -0
  580. package/external/folly/folly/json_patch.h +17 -0
  581. package/external/folly/folly/json_pointer.h +17 -0
  582. package/external/folly/folly/lang/Access.h +29 -0
  583. package/external/folly/folly/lang/Align.h +240 -0
  584. package/external/folly/folly/lang/Aligned.h +92 -0
  585. package/external/folly/folly/lang/Assume.h +82 -0
  586. package/external/folly/folly/lang/BUCK +287 -0
  587. package/external/folly/folly/lang/Badge.h +108 -0
  588. package/external/folly/folly/lang/Bits.h +570 -0
  589. package/external/folly/folly/lang/BitsClass.h +312 -0
  590. package/external/folly/folly/lang/Builtin.h +74 -0
  591. package/external/folly/folly/lang/CArray.h +34 -0
  592. package/external/folly/folly/lang/CString.cpp +86 -0
  593. package/external/folly/folly/lang/CString.h +55 -0
  594. package/external/folly/folly/lang/Cast.h +51 -0
  595. package/external/folly/folly/lang/CheckedMath.h +253 -0
  596. package/external/folly/folly/lang/CustomizationPoint.h +58 -0
  597. package/external/folly/folly/lang/Exception.cpp +822 -0
  598. package/external/folly/folly/lang/Exception.h +716 -0
  599. package/external/folly/folly/lang/Extern.h +55 -0
  600. package/external/folly/folly/lang/Hint-inl.h +144 -0
  601. package/external/folly/folly/lang/Hint.h +238 -0
  602. package/external/folly/folly/lang/Keep.h +98 -0
  603. package/external/folly/folly/lang/New.h +124 -0
  604. package/external/folly/folly/lang/Ordering.h +140 -0
  605. package/external/folly/folly/lang/Pretty.h +159 -0
  606. package/external/folly/folly/lang/PropagateConst.h +413 -0
  607. package/external/folly/folly/lang/RValueReferenceWrapper.h +152 -0
  608. package/external/folly/folly/lang/SafeAssert.cpp +589 -0
  609. package/external/folly/folly/lang/StaticConst.h +33 -0
  610. package/external/folly/folly/lang/Thunk.h +100 -0
  611. package/external/folly/folly/lang/TypeInfo.h +58 -0
  612. package/external/folly/folly/lang/UncaughtExceptions.cpp +17 -0
  613. package/external/folly/folly/lang/UncaughtExceptions.h +19 -0
  614. package/external/folly/folly/lang/test/AlignTest.cpp +87 -0
  615. package/external/folly/folly/lang/test/AlignedTest.cpp +130 -0
  616. package/external/folly/folly/lang/test/BUCK +258 -0
  617. package/external/folly/folly/lang/test/BadgeTest.cpp +89 -0
  618. package/external/folly/folly/lang/test/BitsBenchmark.cpp +164 -0
  619. package/external/folly/folly/lang/test/BitsClassBenchmark.cpp +122 -0
  620. package/external/folly/folly/lang/test/BitsClassTest.cpp +379 -0
  621. package/external/folly/folly/lang/test/BitsTest.cpp +577 -0
  622. package/external/folly/folly/lang/test/CStringTest.cpp +60 -0
  623. package/external/folly/folly/lang/test/CastTest.cpp +47 -0
  624. package/external/folly/folly/lang/test/CheckedMathTest.cpp +394 -0
  625. package/external/folly/folly/lang/test/ExceptionBench.cpp +427 -0
  626. package/external/folly/folly/lang/test/ExceptionTest.cpp +413 -0
  627. package/external/folly/folly/lang/test/ExternTest.cpp +39 -0
  628. package/external/folly/folly/lang/test/HintTest.cpp +100 -0
  629. package/external/folly/folly/lang/test/NewTest.cpp +38 -0
  630. package/external/folly/folly/lang/test/OrderingTest.cpp +105 -0
  631. package/external/folly/folly/lang/test/PrettyTest.cpp +44 -0
  632. package/external/folly/folly/lang/test/PropagateConstTest.cpp +356 -0
  633. package/external/folly/folly/lang/test/RValueReferenceWrapperTest.cpp +85 -0
  634. package/external/folly/folly/lang/test/SafeAssertTest.cpp +75 -0
  635. package/external/folly/folly/lang/test/ThunkTest.cpp +105 -0
  636. package/external/folly/folly/lang/test/ToAsciiBench.cpp +466 -0
  637. package/external/folly/folly/lang/test/ToAsciiTest.cpp +266 -0
  638. package/external/folly/folly/lang/test/TypeInfoTest.cpp +56 -0
  639. package/external/folly/folly/memcpy.S +292 -0
  640. package/external/folly/folly/memcpy_select_aarch64.cpp +145 -0
  641. package/external/folly/folly/memory/Arena-inl.h +83 -0
  642. package/external/folly/folly/memory/Arena.h +325 -0
  643. package/external/folly/folly/memory/BUCK +191 -0
  644. package/external/folly/folly/memory/JemallocHugePageAllocator.cpp +449 -0
  645. package/external/folly/folly/memory/JemallocHugePageAllocator.h +105 -0
  646. package/external/folly/folly/memory/JemallocHugePageAllocatorTest.cpp +341 -0
  647. package/external/folly/folly/memory/JemallocNodumpAllocator.cpp +176 -0
  648. package/external/folly/folly/memory/JemallocNodumpAllocator.h +119 -0
  649. package/external/folly/folly/memory/JemallocNodumpAllocatorTest.cpp +61 -0
  650. package/external/folly/folly/memory/MallctlHelper.cpp +37 -0
  651. package/external/folly/folly/memory/MallctlHelper.h +167 -0
  652. package/external/folly/folly/memory/Malloc.h +551 -0
  653. package/external/folly/folly/memory/MemoryResource.h +57 -0
  654. package/external/folly/folly/memory/ReentrantAllocator.cpp +162 -0
  655. package/external/folly/folly/memory/ReentrantAllocator.h +261 -0
  656. package/external/folly/folly/memory/SanitizeAddress.cpp +75 -0
  657. package/external/folly/folly/memory/SanitizeAddress.h +117 -0
  658. package/external/folly/folly/memory/SanitizeLeak.cpp +119 -0
  659. package/external/folly/folly/memory/SanitizeLeak.h +108 -0
  660. package/external/folly/folly/memory/ThreadCachedArena.cpp +53 -0
  661. package/external/folly/folly/memory/ThreadCachedArena.h +90 -0
  662. package/external/folly/folly/memory/UninitializedMemoryHacks.h +426 -0
  663. package/external/folly/folly/memory/detail/BUCK +10 -0
  664. package/external/folly/folly/memory/detail/MallocImpl.cpp +52 -0
  665. package/external/folly/folly/memory/detail/MallocImpl.h +97 -0
  666. package/external/folly/folly/memory/not_null-inl.h +522 -0
  667. package/external/folly/folly/memory/not_null.h +449 -0
  668. package/external/folly/folly/memory/test/ArenaTest.cpp +354 -0
  669. package/external/folly/folly/memory/test/BUCK +146 -0
  670. package/external/folly/folly/memory/test/MallctlHelperTest.cpp +169 -0
  671. package/external/folly/folly/memory/test/MallocBenchmark.cpp +91 -0
  672. package/external/folly/folly/memory/test/MallocTest.cpp +78 -0
  673. package/external/folly/folly/memory/test/MemoryResourceTest.cpp +31 -0
  674. package/external/folly/folly/memory/test/ReentrantAllocatorTest.cpp +144 -0
  675. package/external/folly/folly/memory/test/SanitizeAddressTest.cpp +67 -0
  676. package/external/folly/folly/memory/test/SanitizeLeakTest.cpp +139 -0
  677. package/external/folly/folly/memory/test/ThreadCachedArenaTest.cpp +276 -0
  678. package/external/folly/folly/memory/test/UninitializedMemoryHacksODR.cpp +21 -0
  679. package/external/folly/folly/memory/test/UninitializedMemoryHacksTest.cpp +327 -0
  680. package/external/folly/folly/memory/test/not_null_test.cpp +608 -0
  681. package/external/folly/folly/memset.S +245 -0
  682. package/external/folly/folly/memset_select_aarch64.cpp +72 -0
  683. package/external/folly/folly/portability/Asm.h +50 -0
  684. package/external/folly/folly/portability/Atomic.h +31 -0
  685. package/external/folly/folly/portability/BUCK +456 -0
  686. package/external/folly/folly/portability/Builtins.cpp +31 -0
  687. package/external/folly/folly/portability/Builtins.h +161 -0
  688. package/external/folly/folly/portability/Config.h +43 -0
  689. package/external/folly/folly/portability/Constexpr.h +145 -0
  690. package/external/folly/folly/portability/Dirent.cpp +140 -0
  691. package/external/folly/folly/portability/Dirent.h +41 -0
  692. package/external/folly/folly/portability/Event.h +44 -0
  693. package/external/folly/folly/portability/Fcntl.cpp +120 -0
  694. package/external/folly/folly/portability/Fcntl.h +67 -0
  695. package/external/folly/folly/portability/Filesystem.cpp +67 -0
  696. package/external/folly/folly/portability/Filesystem.h +114 -0
  697. package/external/folly/folly/portability/FmtCompile.h +40 -0
  698. package/external/folly/folly/portability/GFlags.h +139 -0
  699. package/external/folly/folly/portability/GMock.h +35 -0
  700. package/external/folly/folly/portability/GTest.h +35 -0
  701. package/external/folly/folly/portability/IOVec.h +34 -0
  702. package/external/folly/folly/portability/Libgen.cpp +59 -0
  703. package/external/folly/folly/portability/Libgen.h +29 -0
  704. package/external/folly/folly/portability/Libunwind.h +21 -0
  705. package/external/folly/folly/portability/Malloc.cpp +31 -0
  706. package/external/folly/folly/portability/Malloc.h +53 -0
  707. package/external/folly/folly/portability/Math.h +90 -0
  708. package/external/folly/folly/portability/Memory.h +26 -0
  709. package/external/folly/folly/portability/OpenSSL.cpp +17 -0
  710. package/external/folly/folly/portability/OpenSSL.h +102 -0
  711. package/external/folly/folly/portability/PThread.cpp +697 -0
  712. package/external/folly/folly/portability/PThread.h +148 -0
  713. package/external/folly/folly/portability/README.md +21 -0
  714. package/external/folly/folly/portability/Sched.cpp +41 -0
  715. package/external/folly/folly/portability/Sched.h +45 -0
  716. package/external/folly/folly/portability/Sockets.cpp +245 -0
  717. package/external/folly/folly/portability/Sockets.h +155 -0
  718. package/external/folly/folly/portability/SourceLocation.h +49 -0
  719. package/external/folly/folly/portability/Stdio.cpp +77 -0
  720. package/external/folly/folly/portability/Stdio.h +32 -0
  721. package/external/folly/folly/portability/Stdlib.cpp +172 -0
  722. package/external/folly/folly/portability/Stdlib.h +64 -0
  723. package/external/folly/folly/portability/String.cpp +53 -0
  724. package/external/folly/folly/portability/String.h +39 -0
  725. package/external/folly/folly/portability/SysFile.cpp +46 -0
  726. package/external/folly/folly/portability/SysFile.h +27 -0
  727. package/external/folly/folly/portability/SysMembarrier.cpp +104 -0
  728. package/external/folly/folly/portability/SysMembarrier.h +26 -0
  729. package/external/folly/folly/portability/SysMman.cpp +242 -0
  730. package/external/folly/folly/portability/SysMman.h +68 -0
  731. package/external/folly/folly/portability/SysResource.cpp +108 -0
  732. package/external/folly/folly/portability/SysResource.h +71 -0
  733. package/external/folly/folly/portability/SysStat.cpp +66 -0
  734. package/external/folly/folly/portability/SysStat.h +52 -0
  735. package/external/folly/folly/portability/SysSyscall.h +73 -0
  736. package/external/folly/folly/portability/SysTime.cpp +62 -0
  737. package/external/folly/folly/portability/SysTime.h +50 -0
  738. package/external/folly/folly/portability/SysTypes.h +44 -0
  739. package/external/folly/folly/portability/SysUio.cpp +179 -0
  740. package/external/folly/folly/portability/SysUio.h +51 -0
  741. package/external/folly/folly/portability/Syslog.h +39 -0
  742. package/external/folly/folly/portability/Time.cpp +357 -0
  743. package/external/folly/folly/portability/Time.h +74 -0
  744. package/external/folly/folly/portability/Unistd.h +111 -0
  745. package/external/folly/folly/portability/Windows.h +108 -0
  746. package/external/folly/folly/portability/openat2.c +30 -0
  747. package/external/folly/folly/portability/openat2.h +39 -0
  748. package/external/folly/folly/portability/test/BUCK +59 -0
  749. package/external/folly/folly/portability/test/ConstexprTest.cpp +102 -0
  750. package/external/folly/folly/portability/test/FilesystemTest.cpp +35 -0
  751. package/external/folly/folly/portability/test/LibgenTest.cpp +35 -0
  752. package/external/folly/folly/portability/test/OpenSSLPortabilityTest.cpp +108 -0
  753. package/external/folly/folly/portability/test/PThreadTest.cpp +80 -0
  754. package/external/folly/folly/portability/test/TimeTest.cpp +90 -0
  755. package/external/folly/folly/small_vector.h +17 -0
  756. package/external/folly/folly/somerge_defs.bzl +399 -0
  757. package/external/folly/folly/sorted_vector_types.h +17 -0
  758. package/external/folly/folly/stop_watch.h +317 -0
  759. package/external/folly/folly/synchronization/AsymmetricThreadFence.cpp +91 -0
  760. package/external/folly/folly/synchronization/AsymmetricThreadFence.h +60 -0
  761. package/external/folly/folly/synchronization/AtomicNotification-inl.h +146 -0
  762. package/external/folly/folly/synchronization/AtomicNotification.cpp +34 -0
  763. package/external/folly/folly/synchronization/AtomicNotification.h +117 -0
  764. package/external/folly/folly/synchronization/AtomicRef.h +181 -0
  765. package/external/folly/folly/synchronization/AtomicStruct.h +150 -0
  766. package/external/folly/folly/synchronization/AtomicUtil-inl.h +482 -0
  767. package/external/folly/folly/synchronization/AtomicUtil.h +179 -0
  768. package/external/folly/folly/synchronization/BUCK +418 -0
  769. package/external/folly/folly/synchronization/Baton.h +419 -0
  770. package/external/folly/folly/synchronization/CallOnce.h +263 -0
  771. package/external/folly/folly/synchronization/DelayedInit.h +179 -0
  772. package/external/folly/folly/synchronization/DistributedMutex-inl.h +1744 -0
  773. package/external/folly/folly/synchronization/DistributedMutex.cpp +27 -0
  774. package/external/folly/folly/synchronization/DistributedMutex.h +342 -0
  775. package/external/folly/folly/synchronization/EventCount.h +200 -0
  776. package/external/folly/folly/synchronization/FlatCombining.h +629 -0
  777. package/external/folly/folly/synchronization/Hazptr-fwd.h +217 -0
  778. package/external/folly/folly/synchronization/Hazptr.cpp +36 -0
  779. package/external/folly/folly/synchronization/Hazptr.h +209 -0
  780. package/external/folly/folly/synchronization/HazptrDomain.cpp +68 -0
  781. package/external/folly/folly/synchronization/HazptrDomain.h +832 -0
  782. package/external/folly/folly/synchronization/HazptrHolder.h +431 -0
  783. package/external/folly/folly/synchronization/HazptrObj.h +533 -0
  784. package/external/folly/folly/synchronization/HazptrObjLinked.h +315 -0
  785. package/external/folly/folly/synchronization/HazptrRec.h +68 -0
  786. package/external/folly/folly/synchronization/HazptrThrLocal.h +180 -0
  787. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.cpp +46 -0
  788. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.h +25 -0
  789. package/external/folly/folly/synchronization/Latch.h +160 -0
  790. package/external/folly/folly/synchronization/LifoSem.h +767 -0
  791. package/external/folly/folly/synchronization/Lock.h +887 -0
  792. package/external/folly/folly/synchronization/MicroSpinLock.h +154 -0
  793. package/external/folly/folly/synchronization/NativeSemaphore.h +187 -0
  794. package/external/folly/folly/synchronization/ParkingLot.cpp +37 -0
  795. package/external/folly/folly/synchronization/ParkingLot.h +330 -0
  796. package/external/folly/folly/synchronization/PicoSpinLock.h +167 -0
  797. package/external/folly/folly/synchronization/RWSpinLock.h +549 -0
  798. package/external/folly/folly/synchronization/Rcu.cpp +26 -0
  799. package/external/folly/folly/synchronization/Rcu.h +553 -0
  800. package/external/folly/folly/synchronization/RelaxedAtomic.h +336 -0
  801. package/external/folly/folly/synchronization/SanitizeThread.cpp +141 -0
  802. package/external/folly/folly/synchronization/SanitizeThread.h +166 -0
  803. package/external/folly/folly/synchronization/SaturatingSemaphore.h +324 -0
  804. package/external/folly/folly/synchronization/SmallLocks.h +36 -0
  805. package/external/folly/folly/synchronization/ThrottledLifoSem.h +362 -0
  806. package/external/folly/folly/synchronization/WaitOptions.cpp +25 -0
  807. package/external/folly/folly/synchronization/WaitOptions.h +75 -0
  808. package/external/folly/folly/synchronization/detail/AtomicUtils.h +59 -0
  809. package/external/folly/folly/synchronization/detail/BUCK +104 -0
  810. package/external/folly/folly/synchronization/detail/Hardware.cpp +192 -0
  811. package/external/folly/folly/synchronization/detail/Hardware.h +75 -0
  812. package/external/folly/folly/synchronization/detail/HazptrUtils.h +339 -0
  813. package/external/folly/folly/synchronization/detail/InlineFunctionRef.h +229 -0
  814. package/external/folly/folly/synchronization/detail/Sleeper.cpp +27 -0
  815. package/external/folly/folly/synchronization/detail/Sleeper.h +62 -0
  816. package/external/folly/folly/synchronization/detail/Spin.h +96 -0
  817. package/external/folly/folly/synchronization/detail/ThreadCachedLists.h +174 -0
  818. package/external/folly/folly/synchronization/detail/ThreadCachedReaders.h +189 -0
  819. package/external/folly/folly/synchronization/detail/ThreadCachedTag.h +26 -0
  820. package/external/folly/folly/synchronization/detail/test/BUCK +28 -0
  821. package/external/folly/folly/synchronization/detail/test/HardwareTest.cpp +74 -0
  822. package/external/folly/folly/synchronization/detail/test/InlineFunctionRefTest.cpp +286 -0
  823. package/external/folly/folly/synchronization/example/BUCK +27 -0
  824. package/external/folly/folly/synchronization/example/HazptrLockFreeLIFO.h +88 -0
  825. package/external/folly/folly/synchronization/example/HazptrSWMRSet.h +133 -0
  826. package/external/folly/folly/synchronization/example/HazptrWideCAS.h +62 -0
  827. package/external/folly/folly/synchronization/test/AtomicNotificationTest.cpp +236 -0
  828. package/external/folly/folly/synchronization/test/AtomicRefTest.cpp +170 -0
  829. package/external/folly/folly/synchronization/test/AtomicStructTest.cpp +65 -0
  830. package/external/folly/folly/synchronization/test/AtomicUtilBench.cpp +457 -0
  831. package/external/folly/folly/synchronization/test/AtomicUtilTest.cpp +650 -0
  832. package/external/folly/folly/synchronization/test/BUCK +495 -0
  833. package/external/folly/folly/synchronization/test/Barrier.h +52 -0
  834. package/external/folly/folly/synchronization/test/BarrierTest.cpp +56 -0
  835. package/external/folly/folly/synchronization/test/BatonBenchmark.cpp +77 -0
  836. package/external/folly/folly/synchronization/test/BatonTest.cpp +164 -0
  837. package/external/folly/folly/synchronization/test/BatonTestHelpers.h +118 -0
  838. package/external/folly/folly/synchronization/test/CallOnceBenchmark.cpp +72 -0
  839. package/external/folly/folly/synchronization/test/CallOnceTest.cpp +153 -0
  840. package/external/folly/folly/synchronization/test/DelayedInitTest.cpp +281 -0
  841. package/external/folly/folly/synchronization/test/DistributedMutexTest.cpp +2074 -0
  842. package/external/folly/folly/synchronization/test/EventCountTest.cpp +124 -0
  843. package/external/folly/folly/synchronization/test/FlatCombiningBenchmark.cpp +1789 -0
  844. package/external/folly/folly/synchronization/test/FlatCombiningExamples.h +222 -0
  845. package/external/folly/folly/synchronization/test/FlatCombiningTest.cpp +121 -0
  846. package/external/folly/folly/synchronization/test/FlatCombiningTestHelpers.h +227 -0
  847. package/external/folly/folly/synchronization/test/HazptrTest.cpp +1689 -0
  848. package/external/folly/folly/synchronization/test/LatchTest.cpp +224 -0
  849. package/external/folly/folly/synchronization/test/LifoSemBench.cpp +185 -0
  850. package/external/folly/folly/synchronization/test/LifoSemTests.cpp +353 -0
  851. package/external/folly/folly/synchronization/test/LockTest.cpp +1239 -0
  852. package/external/folly/folly/synchronization/test/NativeSemaphoreTest.cpp +37 -0
  853. package/external/folly/folly/synchronization/test/ParkingLotBenchmark.cpp +239 -0
  854. package/external/folly/folly/synchronization/test/ParkingLotTest.cpp +170 -0
  855. package/external/folly/folly/synchronization/test/RWSpinLockTest.cpp +235 -0
  856. package/external/folly/folly/synchronization/test/RcuBench.cpp +66 -0
  857. package/external/folly/folly/synchronization/test/RcuTest.cpp +330 -0
  858. package/external/folly/folly/synchronization/test/RelaxedAtomicTest.cpp +389 -0
  859. package/external/folly/folly/synchronization/test/SaturatingSemaphoreTest.cpp +166 -0
  860. package/external/folly/folly/synchronization/test/Semaphore.h +242 -0
  861. package/external/folly/folly/synchronization/test/SemaphoreTest.cpp +271 -0
  862. package/external/folly/folly/synchronization/test/SmallLocksBenchmark.cpp +1296 -0
  863. package/external/folly/folly/synchronization/test/SmallLocksTest.cpp +510 -0
  864. package/external/folly/folly/synchronization/test/ThreadCachedEpochBench.h +67 -0
  865. package/external/folly/folly/synchronization/test/ThreadCachedReadersBench.cpp +42 -0
  866. package/external/folly/folly/synchronization/test/ThreadCachedReadersTest.cpp +52 -0
  867. package/external/folly/folly/synchronization/test/ThrottledLifoSemTest.cpp +243 -0
  868. package/external/folly/folly/system/AtFork.cpp +205 -0
  869. package/external/folly/folly/system/AtFork.h +116 -0
  870. package/external/folly/folly/system/AuxVector.h +198 -0
  871. package/external/folly/folly/system/BUCK +144 -0
  872. package/external/folly/folly/system/EnvUtil.cpp +93 -0
  873. package/external/folly/folly/system/EnvUtil.h +113 -0
  874. package/external/folly/folly/system/HardwareConcurrency.cpp +39 -0
  875. package/external/folly/folly/system/HardwareConcurrency.h +23 -0
  876. package/external/folly/folly/system/MemoryMapping.cpp +477 -0
  877. package/external/folly/folly/system/MemoryMapping.h +287 -0
  878. package/external/folly/folly/system/Pid.cpp +87 -0
  879. package/external/folly/folly/system/Pid.h +34 -0
  880. package/external/folly/folly/system/Shell.cpp +33 -0
  881. package/external/folly/folly/system/Shell.h +93 -0
  882. package/external/folly/folly/system/ThreadId.cpp +89 -0
  883. package/external/folly/folly/system/ThreadId.h +62 -0
  884. package/external/folly/folly/system/ThreadName.cpp +330 -0
  885. package/external/folly/folly/system/ThreadName.h +72 -0
  886. package/external/folly/folly/system/test/AtForkTest.cpp +309 -0
  887. package/external/folly/folly/system/test/AuxVectorTest.cpp +55 -0
  888. package/external/folly/folly/system/test/BUCK +120 -0
  889. package/external/folly/folly/system/test/EnvUtilSubprocess.cpp +26 -0
  890. package/external/folly/folly/system/test/EnvUtilTest.cpp +197 -0
  891. package/external/folly/folly/system/test/MemoryMappingTest.cpp +179 -0
  892. package/external/folly/folly/system/test/PidTest.cpp +46 -0
  893. package/external/folly/folly/system/test/ShellTest.cpp +66 -0
  894. package/external/folly/folly/system/test/ThreadIdTest.cpp +114 -0
  895. package/external/folly/folly/system/test/ThreadNameTest.cpp +85 -0
  896. package/external/folly/folly.vcxitems +164 -0
  897. package/external/folly/static/logo.svg +1 -0
  898. package/external/folly/sync-config.json +8 -0
  899. package/package.json +3 -3
  900. package/template/cpp-app/proj/MyApp.sln +0 -33
  901. package/template/cpp-lib/proj/MyLib.sln +0 -33
  902. package/template/cs-app/proj/MyApp.sln +0 -33
  903. package/template/cs-lib/proj/MyLib.sln +0 -33
  904. package/templates/cpp-app/windows/MyApp.sln +0 -33
  905. package/templates/cpp-lib/example/metro.config.js +31 -6
  906. package/templates/cpp-lib/windows/MyLib.sln +0 -33
  907. package/Folly/Folly.vcxproj +0 -383
  908. package/Folly/Folly.vcxproj.filters +0 -558
  909. package/Folly/Folly.win32.vcxproj +0 -11
  910. package/Folly/packages.lock.win32.json +0 -20
  911. package/Scripts/Warm-RnwFeedCache.ps1 +0 -413
  912. package/fmt/fmt.vcxproj +0 -163
  913. package/fmt/fmt.vcxproj.filters +0 -59
  914. package/fmt/fmt.win32.vcxproj +0 -10
  915. package/fmt/pch.cpp +0 -4
  916. package/fmt/pch.h +0 -2
  917. /package/{Folly → external/folly}/Folly.natvis +0 -0
  918. /package/{Folly → external/folly}/cgmanifest.json +0 -0
  919. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/ConstexprMath.h +0 -0
  920. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/Conv.cpp +0 -0
  921. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/chrono/Hardware.h +0 -0
  922. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/concurrency/CacheLocality.cpp +0 -0
  923. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/dynamic-inl.h +0 -0
  924. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/json.cpp +0 -0
  925. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/SafeAssert.h +0 -0
  926. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.cpp +0 -0
  927. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.h +0 -0
  928. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/portability/Unistd.cpp +0 -0
@@ -0,0 +1,1751 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #pragma once
18
+
19
+ #include <stdint.h>
20
+
21
+ #include <atomic>
22
+ #include <chrono>
23
+ #include <memory>
24
+ #include <mutex>
25
+ #include <shared_mutex>
26
+ #include <thread>
27
+ #include <type_traits>
28
+ #include <utility>
29
+
30
+ #include <folly/CPortability.h>
31
+ #include <folly/CppAttributes.h>
32
+ #include <folly/Likely.h>
33
+ #include <folly/chrono/Hardware.h>
34
+ #include <folly/concurrency/CacheLocality.h>
35
+ #include <folly/detail/Futex.h>
36
+ #include <folly/portability/Asm.h>
37
+ #include <folly/synchronization/Lock.h>
38
+ #include <folly/synchronization/RelaxedAtomic.h>
39
+ #include <folly/synchronization/SanitizeThread.h>
40
+ #include <folly/system/ThreadId.h>
41
+
42
+ // SharedMutex is a reader-writer lock. It is small, very fast, scalable
43
+ // on multi-core, and suitable for use when readers or writers may block.
44
+ // Unlike most other reader-writer locks, its throughput with concurrent
45
+ // readers scales linearly; it is able to acquire and release the lock
46
+ // in shared mode without cache line ping-ponging. It is suitable for
47
+ // a wide range of lock hold times because it starts with spinning,
48
+ // proceeds to using sched_yield with a preemption heuristic, and then
49
+ // waits using futex and precise wakeups.
50
+ //
51
+ // SharedMutex provides all of the methods of folly::RWSpinLock,
52
+ // boost::shared_mutex, boost::upgrade_mutex, and C++14's
53
+ // std::shared_timed_mutex. All operations that can block are available
54
+ // in try, try-for, and try-until (system_clock or steady_clock) versions.
55
+ //
56
+ // SharedMutexReadPriority gives priority to readers,
57
+ // SharedMutexWritePriority gives priority to writers. SharedMutex is an
58
+ // alias for SharedMutexWritePriority, because writer starvation is more
59
+ // likely than reader starvation for the read-heavy workloads targeted
60
+ // by SharedMutex.
61
+ //
62
+ // In my tests SharedMutex is as good or better than the other
63
+ // reader-writer locks in use at Facebook for almost all use cases,
64
+ // sometimes by a wide margin. (If it is rare that there are actually
65
+ // concurrent readers then RWSpinLock can be a few nanoseconds faster.)
66
+ // I compared it to folly::RWSpinLock, folly::RWTicketSpinLock64,
67
+ // boost::shared_mutex, pthread_rwlock_t, and a RWLock that internally uses
68
+ // spinlocks to guard state and pthread_mutex_t+pthread_cond_t to block.
69
+ // (Thrift's ReadWriteMutex is based underneath on pthread_rwlock_t.)
70
+ // It is generally as good or better than the rest when evaluating size,
71
+ // speed, scalability, or latency outliers. In the corner cases where
72
+ // it is not the fastest (such as single-threaded use or heavy write
73
+ // contention) it is never very much worse than the best. See the bottom
74
+ // of folly/test/SharedMutexTest.cpp for lots of microbenchmark results.
75
+ //
76
+ // Comparison to folly::RWSpinLock:
77
+ //
78
+ // * SharedMutex is faster than RWSpinLock when there are actually
79
+ // concurrent read accesses (sometimes much faster), and ~5 nanoseconds
80
+ // slower when there is not actually any contention. SharedMutex is
81
+ // faster in every (benchmarked) scenario where the shared mode of
82
+ // the lock is actually useful.
83
+ //
84
+ // * Concurrent shared access to SharedMutex scales linearly, while total
85
+ // RWSpinLock throughput drops as more threads try to access the lock
86
+ // in shared mode. Under very heavy read contention SharedMutex can
87
+ // be two orders of magnitude faster than RWSpinLock (or any reader
88
+ // writer lock that doesn't use striping or deferral).
89
+ //
90
+ // * SharedMutex can safely protect blocking calls, because after an
91
+ // initial period of spinning it waits using futex().
92
+ //
93
+ // * RWSpinLock prioritizes readers, SharedMutex has both reader- and
94
+ // writer-priority variants, but defaults to write priority.
95
+ //
96
+ // * RWSpinLock's upgradeable mode blocks new readers, while SharedMutex's
97
+ // doesn't. Both semantics are reasonable. The boost documentation
98
+ // doesn't explicitly talk about this behavior (except by omitting
99
+ // any statement that those lock modes conflict), but the boost
100
+ // implementations do allow new readers while the upgradeable mode
101
+ // is held. See https://github.com/boostorg/thread/blob/master/
102
+ // include/boost/thread/pthread/shared_mutex.hpp
103
+ //
104
+ // Both SharedMutex and RWSpinLock provide "exclusive", "upgrade",
105
+ // and "shared" modes. At all times num_threads_holding_exclusive +
106
+ // num_threads_holding_upgrade <= 1, and num_threads_holding_exclusive ==
107
+ // 0 || num_threads_holding_shared == 0. RWSpinLock has the additional
108
+ // constraint that num_threads_holding_shared cannot increase while
109
+ // num_threads_holding_upgrade is non-zero.
110
+ //
111
+ // Comparison to the internal RWLock:
112
+ //
113
+ // * SharedMutex doesn't allow a maximum reader count to be configured,
114
+ // so it can't be used as a semaphore in the same way as RWLock.
115
+ //
116
+ // * SharedMutex is 4 bytes, RWLock is 256.
117
+ //
118
+ // * SharedMutex is as fast or faster than RWLock in all of my
119
+ // microbenchmarks, and has positive rather than negative scalability.
120
+ //
121
+ // * RWLock and SharedMutex are both writer priority locks.
122
+ //
123
+ // * SharedMutex avoids latency outliers as well as RWLock.
124
+ //
125
+ // * SharedMutex uses different names (t != 0 below):
126
+ //
127
+ // RWLock::lock(0) => SharedMutex::lock()
128
+ //
129
+ // RWLock::lock(t) => SharedMutex::try_lock_for(milliseconds(t))
130
+ //
131
+ // RWLock::tryLock() => SharedMutex::try_lock()
132
+ //
133
+ // RWLock::unlock() => SharedMutex::unlock()
134
+ //
135
+ // RWLock::enter(0) => SharedMutex::lock_shared()
136
+ //
137
+ // RWLock::enter(t) =>
138
+ // SharedMutex::try_lock_shared_for(milliseconds(t))
139
+ //
140
+ // RWLock::tryEnter() => SharedMutex::try_lock_shared()
141
+ //
142
+ // RWLock::leave() => SharedMutex::unlock_shared()
143
+ //
144
+ // * RWLock allows the reader count to be adjusted by a value other
145
+ // than 1 during enter() or leave(). SharedMutex doesn't currently
146
+ // implement this feature.
147
+ //
148
+ // * RWLock's methods are marked const, SharedMutex's aren't.
149
+ //
150
+ // Reader-writer locks have the potential to allow concurrent access
151
+ // to shared read-mostly data, but in practice they often provide no
152
+ // improvement over a mutex. The problem is the cache coherence protocol
153
+ // of modern CPUs. Coherence is provided by making sure that when a cache
154
+ // line is written it is present in only one core's cache. Since a memory
155
+ // write is required to acquire a reader-writer lock in shared mode, the
156
+ // cache line holding the lock is invalidated in all of the other caches.
157
+ // This leads to cache misses when another thread wants to acquire or
158
+ // release the lock concurrently. When the RWLock is colocated with the
159
+ // data it protects (common), cache misses can also continue occur when
160
+ // a thread that already holds the lock tries to read the protected data.
161
+ //
162
+ // Ideally, a reader-writer lock would allow multiple cores to acquire
163
+ // and release the lock in shared mode without incurring any cache misses.
164
+ // This requires that each core records its shared access in a cache line
165
+ // that isn't read or written by other read-locking cores. (Writers will
166
+ // have to check all of the cache lines.) Typical server hardware when
167
+ // this comment was written has 16 L1 caches and cache lines of 64 bytes,
168
+ // so a lock striped over all L1 caches would occupy a prohibitive 1024
169
+ // bytes. Nothing says that we need a separate set of per-core memory
170
+ // locations for each lock, however. Each SharedMutex instance is only
171
+ // 4 bytes, but all locks together share a 2K area in which they make a
172
+ // core-local record of lock acquisitions.
173
+ //
174
+ // SharedMutex's strategy of using a shared set of core-local stripes has
175
+ // a potential downside, because it means that acquisition of any lock in
176
+ // write mode can conflict with acquisition of any lock in shared mode.
177
+ // If a lock instance doesn't actually experience concurrency then this
178
+ // downside will outweight the upside of improved scalability for readers.
179
+ // To avoid this problem we dynamically detect concurrent accesses to
180
+ // SharedMutex, and don't start using the deferred mode unless we actually
181
+ // observe concurrency. See kNumSharedToStartDeferring.
182
+ //
183
+ // It is explicitly allowed to call unlock_shared() from a different
184
+ // thread than lock_shared(), so long as they are properly paired.
185
+ // unlock_shared() needs to find the location at which lock_shared()
186
+ // recorded the lock, which might be in the lock itself or in any of
187
+ // the shared slots. If you can conveniently pass state from lock
188
+ // acquisition to release then the fastest mechanism is to std::move
189
+ // the std::shared_lock instance or an SharedMutex::Token (using
190
+ // lock_shared(Token&) and unlock_shared(Token&)). The guard or token
191
+ // will tell unlock_shared where in deferredReaders[] to look for the
192
+ // deferred lock. The Token-less version of unlock_shared() works in all
193
+ // cases, but is optimized for the common (no inter-thread handoff) case.
194
+ //
195
+ // In both read- and write-priority mode, a waiting lock() (exclusive mode)
196
+ // only blocks readers after it has waited for an active upgrade lock to be
197
+ // released; until the upgrade lock is released (or upgraded or downgraded)
198
+ // readers will still be able to enter. Preferences about lock acquisition
199
+ // are not guaranteed to be enforced perfectly (even if they were, there
200
+ // is theoretically the chance that a thread could be arbitrarily suspended
201
+ // between calling lock() and SharedMutex code actually getting executed).
202
+ //
203
+ // try_*_for methods always try at least once, even if the duration
204
+ // is zero or negative. The duration type must be compatible with
205
+ // std::chrono::steady_clock. try_*_until methods also always try at
206
+ // least once. std::chrono::system_clock and std::chrono::steady_clock
207
+ // are supported.
208
+ //
209
+ // If you have observed by profiling that your SharedMutex-s are getting
210
+ // cache misses on deferredReaders[] due to another SharedMutex user, then
211
+ // you can use the tag type to create your own instantiation of the type.
212
+ // The contention threshold (see kNumSharedToStartDeferring) should make
213
+ // this unnecessary in all but the most extreme cases. Make sure to check
214
+ // that the increased icache and dcache footprint of the tagged result is
215
+ // worth it.
216
+
217
+ // SharedMutex's use of thread local storage is an optimization, so
218
+ // for the case where thread local storage is not supported, define it
219
+ // away.
220
+
221
+ // Note about TSAN (ThreadSanitizer): the SharedMutexWritePriority version
222
+ // (the default) of this mutex is annotated appropriately so that TSAN can
223
+ // perform lock inversion analysis. However, the SharedMutexReadPriority version
224
+ // is not annotated. This is because TSAN's lock order heuristic
225
+ // assumes that two calls to lock_shared must be ordered, which leads
226
+ // to too many false positives for the reader-priority case.
227
+ //
228
+ // Suppose thread A holds a SharedMutexWritePriority lock in shared mode and an
229
+ // independent thread B is waiting for exclusive access. Then a thread C's
230
+ // lock_shared can't proceed until A has released the lock. Discounting
231
+ // situations that never use exclusive mode (so no lock is necessary at all)
232
+ // this means that without higher-level reasoning it is not safe to ignore
233
+ // reader <-> reader interactions.
234
+ //
235
+ // This reasoning does not apply to SharedMutexReadPriority, because there are
236
+ // no actions by a thread B that can make C need to wait for A. Since the
237
+ // overwhelming majority of SharedMutex instances use write priority, we
238
+ // restrict the TSAN annotations to only SharedMutexWritePriority.
239
+
240
+ namespace folly {
241
+
242
+ struct SharedMutexToken {
243
+ enum class State : uint16_t {
244
+ Invalid = 0,
245
+ LockedShared, // May be inline or deferred.
246
+ LockedInlineShared,
247
+ LockedDeferredShared,
248
+ };
249
+
250
+ State state_{};
251
+ uint16_t slot_{};
252
+
253
+ constexpr SharedMutexToken() = default;
254
+
255
+ explicit operator bool() const { return state_ != State::Invalid; }
256
+ };
257
+
258
+ struct SharedMutexPolicyDefault {
259
+ static constexpr uint64_t max_spin_cycles = 4000;
260
+ static constexpr uint32_t max_soft_yield_count = 1;
261
+ static constexpr bool track_thread_id = false;
262
+ static constexpr bool skip_annotate_rwlock = false;
263
+ };
264
+
265
+ namespace shared_mutex_detail {
266
+
267
+ struct PolicyTracked : SharedMutexPolicyDefault {
268
+ static constexpr bool track_thread_id = true;
269
+ };
270
+ struct PolicySuppressTSAN : SharedMutexPolicyDefault {
271
+ static constexpr bool skip_annotate_rwlock = true;
272
+ };
273
+
274
+ // Returns a guard that gives permission for the current thread to
275
+ // annotate, and adjust the annotation bits in, the SharedMutex at ptr.
276
+ std::unique_lock<std::mutex> annotationGuard(void* ptr);
277
+
278
+ constexpr uint32_t kMaxDeferredReadersAllocated = 256 * 2;
279
+
280
+ [[FOLLY_ATTR_GNU_COLD]] uint32_t getMaxDeferredReadersSlow(
281
+ relaxed_atomic<uint32_t>& cache);
282
+
283
+ long getCurrentThreadInvoluntaryContextSwitchCount();
284
+
285
+ // kMaxDeferredReaders
286
+ FOLLY_EXPORT FOLLY_ALWAYS_INLINE uint32_t getMaxDeferredReaders() {
287
+ static relaxed_atomic<uint32_t> cache{0};
288
+ uint32_t const value = cache;
289
+ return FOLLY_LIKELY(!!value) ? value : getMaxDeferredReadersSlow(cache);
290
+ }
291
+
292
+ class NopOwnershipTracker {
293
+ public:
294
+ void beginThreadOwnership() {}
295
+
296
+ void maybeBeginThreadOwnership(bool) {}
297
+
298
+ void endThreadOwnership() {}
299
+ };
300
+
301
+ class ThreadIdOwnershipTracker {
302
+ public:
303
+ void beginThreadOwnership() {
304
+ assert(ownerTid_ == 0);
305
+ ownerTid_ = tid();
306
+ }
307
+
308
+ void maybeBeginThreadOwnership(bool own) {
309
+ if (own) {
310
+ beginThreadOwnership();
311
+ }
312
+ }
313
+
314
+ void endThreadOwnership() {
315
+ // if you want to check that unlock happens on the same thread as lock,
316
+ // assert that ownerTid_ == tid() here
317
+ ownerTid_ = 0;
318
+ }
319
+
320
+ private:
321
+ static unsigned tid() {
322
+ /* library-local */ static thread_local unsigned cached = 0;
323
+ auto z = cached;
324
+ if (z == 0) {
325
+ z = static_cast<unsigned>(getOSThreadID());
326
+ cached = z;
327
+ }
328
+ return z;
329
+ }
330
+
331
+ private:
332
+ // gettid() of thread holding the lock in U or E mode
333
+ unsigned ownerTid_ = 0;
334
+ };
335
+ } // namespace shared_mutex_detail
336
+
337
+ template <
338
+ bool ReaderPriority,
339
+ typename Tag_ = void,
340
+ template <typename> class Atom = std::atomic,
341
+ typename Policy = SharedMutexPolicyDefault>
342
+ class SharedMutexImpl : std::conditional_t<
343
+ Policy::track_thread_id,
344
+ shared_mutex_detail::ThreadIdOwnershipTracker,
345
+ shared_mutex_detail::NopOwnershipTracker> {
346
+ private:
347
+ static constexpr bool AnnotateForThreadSanitizer =
348
+ kIsSanitizeThread && !ReaderPriority && !Policy::skip_annotate_rwlock;
349
+
350
+ typedef std::conditional_t<
351
+ Policy::track_thread_id,
352
+ shared_mutex_detail::ThreadIdOwnershipTracker,
353
+ shared_mutex_detail::NopOwnershipTracker>
354
+ OwnershipTrackerBase;
355
+
356
+ public:
357
+ static constexpr bool kReaderPriority = ReaderPriority;
358
+ typedef Tag_ Tag;
359
+
360
+ typedef SharedMutexToken Token;
361
+
362
+ constexpr SharedMutexImpl() noexcept : state_(0) {}
363
+
364
+ SharedMutexImpl(const SharedMutexImpl&) = delete;
365
+ SharedMutexImpl(SharedMutexImpl&&) = delete;
366
+ SharedMutexImpl& operator=(const SharedMutexImpl&) = delete;
367
+ SharedMutexImpl& operator=(SharedMutexImpl&&) = delete;
368
+
369
+ // It is an error to destroy an SharedMutex that still has
370
+ // any outstanding locks. This is checked if NDEBUG isn't defined.
371
+ // SharedMutex's exclusive mode can be safely used to guard the lock's
372
+ // own destruction. If, for example, you acquire the lock in exclusive
373
+ // mode and then observe that the object containing the lock is no longer
374
+ // needed, you can unlock() and then immediately destroy the lock.
375
+ // See https://sourceware.org/bugzilla/show_bug.cgi?id=13690 for a
376
+ // description about why this property needs to be explicitly mentioned.
377
+ ~SharedMutexImpl() {
378
+ auto state = state_.load(std::memory_order_relaxed);
379
+ if (FOLLY_UNLIKELY((state & kHasS) != 0)) {
380
+ cleanupTokenlessSharedDeferred(state);
381
+ }
382
+
383
+ if (folly::kIsDebug) {
384
+ // These asserts check that everybody has released the lock before it
385
+ // is destroyed. If you arrive here while debugging that is likely
386
+ // the problem. (You could also have general heap corruption.)
387
+
388
+ // if a futexWait fails to go to sleep because the value has been
389
+ // changed, we don't necessarily clean up the wait bits, so it is
390
+ // possible they will be set here in a correct system
391
+ assert((state & ~(kWaitingAny | kMayDefer | kAnnotationCreated)) == 0);
392
+ if ((state & kMayDefer) != 0) {
393
+ const uint32_t maxDeferredReaders =
394
+ shared_mutex_detail::getMaxDeferredReaders();
395
+ for (uint32_t slot = 0; slot < maxDeferredReaders; ++slot) {
396
+ auto slotValue =
397
+ deferredReader(slot)->load(std::memory_order_relaxed);
398
+ assert(!slotValueIsThis(slotValue));
399
+ (void)slotValue;
400
+ }
401
+ }
402
+ }
403
+ annotateDestroy();
404
+ }
405
+
406
+ // Checks if an exclusive lock could succeed so that lock elision could be
407
+ // enabled. Different from the two eligible_for_lock_{upgrade|shared}_elision
408
+ // functions, this is a conservative check since kMayDefer indicates
409
+ // "may-existing" deferred readers.
410
+ bool eligible_for_lock_elision() const {
411
+ // We rely on the transaction for linearization. Wait bits are
412
+ // irrelevant because a successful transaction will be in and out
413
+ // without affecting the wakeup. kBegunE is also okay for a similar
414
+ // reason.
415
+ auto state = state_.load(std::memory_order_relaxed);
416
+ return (state & (kHasS | kMayDefer | kHasE | kHasU)) == 0;
417
+ }
418
+
419
+ // Checks if an upgrade lock could succeed so that lock elision could be
420
+ // enabled.
421
+ bool eligible_for_lock_upgrade_elision() const {
422
+ auto state = state_.load(std::memory_order_relaxed);
423
+ return (state & (kHasE | kHasU)) == 0;
424
+ }
425
+
426
+ // Checks if a shared lock could succeed so that lock elision could be
427
+ // enabled.
428
+ bool eligible_for_lock_shared_elision() const {
429
+ // No need to honor kBegunE because a transaction doesn't block anybody
430
+ auto state = state_.load(std::memory_order_relaxed);
431
+ return (state & kHasE) == 0;
432
+ }
433
+
434
+ void lock() {
435
+ WaitForever ctx;
436
+ (void)lockExclusiveImpl(kHasSolo, ctx);
437
+ OwnershipTrackerBase::beginThreadOwnership();
438
+ annotateAcquired(annotate_rwlock_level::wrlock);
439
+ }
440
+
441
+ bool try_lock() {
442
+ WaitNever ctx;
443
+ auto result = lockExclusiveImpl(kHasSolo, ctx);
444
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
445
+ annotateTryAcquired(result, annotate_rwlock_level::wrlock);
446
+ return result;
447
+ }
448
+
449
+ template <class Rep, class Period>
450
+ bool try_lock_for(const std::chrono::duration<Rep, Period>& duration) {
451
+ WaitForDuration<Rep, Period> ctx(duration);
452
+ auto result = lockExclusiveImpl(kHasSolo, ctx);
453
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
454
+ annotateTryAcquired(result, annotate_rwlock_level::wrlock);
455
+ return result;
456
+ }
457
+
458
+ template <class Clock, class Duration>
459
+ bool try_lock_until(
460
+ const std::chrono::time_point<Clock, Duration>& absDeadline) {
461
+ WaitUntilDeadline<Clock, Duration> ctx{absDeadline};
462
+ auto result = lockExclusiveImpl(kHasSolo, ctx);
463
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
464
+ annotateTryAcquired(result, annotate_rwlock_level::wrlock);
465
+ return result;
466
+ }
467
+
468
+ void unlock() {
469
+ annotateReleased(annotate_rwlock_level::wrlock);
470
+ OwnershipTrackerBase::endThreadOwnership();
471
+ // It is possible that we have a left-over kWaitingNotS if the last
472
+ // unlock_shared() that let our matching lock() complete finished
473
+ // releasing before lock()'s futexWait went to sleep. Clean it up now
474
+ auto state = (state_ &= ~(kWaitingNotS | kPrevDefer | kHasE));
475
+ assert((state & ~(kWaitingAny | kAnnotationCreated)) == 0);
476
+ wakeRegisteredWaiters(state, kWaitingE | kWaitingU | kWaitingS);
477
+ }
478
+
479
+ // Managing the token yourself makes unlock_shared a bit faster. If the
480
+ // tokenful version of lock_shared() is used, then it is required to pair the
481
+ // lock with the tokenful version of unlock_shared(); alternatively, the token
482
+ // can be invalidated with release_token(), which allows to use the tokenless
483
+ // unlock_shared().
484
+
485
+ void lock_shared() {
486
+ WaitForever ctx;
487
+ (void)lockSharedImpl(nullptr, ctx);
488
+ annotateAcquired(annotate_rwlock_level::rdlock);
489
+ }
490
+
491
+ void lock_shared(Token& token) {
492
+ WaitForever ctx;
493
+ (void)lockSharedImpl(&token, ctx);
494
+ annotateAcquired(annotate_rwlock_level::rdlock);
495
+ }
496
+
497
+ bool try_lock_shared() {
498
+ WaitNever ctx;
499
+ auto result = lockSharedImpl(nullptr, ctx);
500
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
501
+ return result;
502
+ }
503
+
504
+ bool try_lock_shared(Token& token) {
505
+ WaitNever ctx;
506
+ auto result = lockSharedImpl(&token, ctx);
507
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
508
+ return result;
509
+ }
510
+
511
+ template <class Rep, class Period>
512
+ bool try_lock_shared_for(const std::chrono::duration<Rep, Period>& duration) {
513
+ WaitForDuration<Rep, Period> ctx(duration);
514
+ auto result = lockSharedImpl(nullptr, ctx);
515
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
516
+ return result;
517
+ }
518
+
519
+ template <class Rep, class Period>
520
+ bool try_lock_shared_for(
521
+ const std::chrono::duration<Rep, Period>& duration, Token& token) {
522
+ WaitForDuration<Rep, Period> ctx(duration);
523
+ auto result = lockSharedImpl(&token, ctx);
524
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
525
+ return result;
526
+ }
527
+
528
+ template <class Clock, class Duration>
529
+ bool try_lock_shared_until(
530
+ const std::chrono::time_point<Clock, Duration>& absDeadline) {
531
+ WaitUntilDeadline<Clock, Duration> ctx{absDeadline};
532
+ auto result = lockSharedImpl(nullptr, ctx);
533
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
534
+ return result;
535
+ }
536
+
537
+ template <class Clock, class Duration>
538
+ bool try_lock_shared_until(
539
+ const std::chrono::time_point<Clock, Duration>& absDeadline,
540
+ Token& token) {
541
+ WaitUntilDeadline<Clock, Duration> ctx{absDeadline};
542
+ auto result = lockSharedImpl(&token, ctx);
543
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
544
+ return result;
545
+ }
546
+
547
+ void unlock_shared() {
548
+ annotateReleased(annotate_rwlock_level::rdlock);
549
+
550
+ auto state = state_.load(std::memory_order_acquire);
551
+
552
+ // kPrevDefer can only be set if HasE or BegunE is set
553
+ assert((state & (kPrevDefer | kHasE | kBegunE)) != kPrevDefer);
554
+
555
+ // lock() strips kMayDefer immediately, but then copies it to
556
+ // kPrevDefer so we can tell if the pre-lock() lock_shared() might
557
+ // have deferred
558
+ if ((state & (kMayDefer | kPrevDefer)) == 0 ||
559
+ !tryUnlockTokenlessSharedDeferred()) {
560
+ // Matching lock_shared() couldn't have deferred, or the deferred
561
+ // lock has already been inlined by applyDeferredReaders()
562
+ unlockSharedInline();
563
+ }
564
+ }
565
+
566
+ void unlock_shared(Token& token) {
567
+ if (token.state_ == Token::State::LockedShared) {
568
+ unlock_shared();
569
+ if (folly::kIsDebug) {
570
+ token.state_ = Token::State::Invalid;
571
+ }
572
+ return;
573
+ }
574
+
575
+ annotateReleased(annotate_rwlock_level::rdlock);
576
+
577
+ assert(
578
+ token.state_ == Token::State::LockedInlineShared ||
579
+ token.state_ == Token::State::LockedDeferredShared);
580
+
581
+ if (token.state_ != Token::State::LockedDeferredShared ||
582
+ !tryUnlockSharedDeferred(token.slot_)) {
583
+ unlockSharedInline();
584
+ }
585
+ if (folly::kIsDebug) {
586
+ token.state_ = Token::State::Invalid;
587
+ }
588
+ }
589
+
590
+ // Invalidates the given token so that the tokenless version of
591
+ // unlock_shared() can be called for a lock that was obtained from a tokenful
592
+ // lock_shared(). Note that this does not unlock the mutex at any point.
593
+ void release_token(Token& token) {
594
+ assert(token.state_ != Token::State::Invalid);
595
+ if (token.state_ != Token::State::LockedDeferredShared) {
596
+ return;
597
+ }
598
+
599
+ auto slot = token.slot_;
600
+ assert(slot < shared_mutex_detail::getMaxDeferredReaders());
601
+ auto slotValue = tokenfulSlotValue();
602
+ // Lock may have been inlined, in which case this will return false. We
603
+ // don't need to do anything in this case.
604
+ deferredReader(slot)->compare_exchange_strong(
605
+ slotValue, tokenlessSlotValue());
606
+
607
+ if (folly::kIsDebug) {
608
+ token.state_ = Token::State::Invalid;
609
+ }
610
+ }
611
+
612
+ void unlock_and_lock_shared() {
613
+ OwnershipTrackerBase::endThreadOwnership();
614
+ annotateReleased(annotate_rwlock_level::wrlock);
615
+ annotateAcquired(annotate_rwlock_level::rdlock);
616
+ // We can't use state_ -=, because we need to clear 2 bits (1 of which
617
+ // has an uncertain initial state) and set 1 other. We might as well
618
+ // clear the relevant wake bits at the same time. Note that since S
619
+ // doesn't block the beginning of a transition to E (writer priority
620
+ // can cut off new S, reader priority grabs BegunE and blocks deferred
621
+ // S) we need to wake E as well.
622
+ auto state = state_.load(std::memory_order_acquire);
623
+ do {
624
+ assert(
625
+ (state & ~(kWaitingAny | kPrevDefer | kAnnotationCreated)) == kHasE);
626
+ } while (!state_.compare_exchange_strong(
627
+ state, (state & ~(kWaitingAny | kPrevDefer | kHasE)) + kIncrHasS));
628
+ if ((state & (kWaitingE | kWaitingU | kWaitingS)) != 0) {
629
+ futexWakeAll(kWaitingE | kWaitingU | kWaitingS);
630
+ }
631
+ }
632
+
633
+ void unlock_and_lock_shared(Token& token) {
634
+ unlock_and_lock_shared();
635
+ token.state_ = Token::State::LockedInlineShared;
636
+ }
637
+
638
+ void lock_upgrade() {
639
+ WaitForever ctx;
640
+ (void)lockUpgradeImpl(ctx);
641
+ OwnershipTrackerBase::beginThreadOwnership();
642
+ // For TSAN: treat upgrade locks as equivalent to read locks
643
+ annotateAcquired(annotate_rwlock_level::rdlock);
644
+ }
645
+
646
+ bool try_lock_upgrade() {
647
+ WaitNever ctx;
648
+ auto result = lockUpgradeImpl(ctx);
649
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
650
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
651
+ return result;
652
+ }
653
+
654
+ template <class Rep, class Period>
655
+ bool try_lock_upgrade_for(
656
+ const std::chrono::duration<Rep, Period>& duration) {
657
+ WaitForDuration<Rep, Period> ctx(duration);
658
+ auto result = lockUpgradeImpl(ctx);
659
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
660
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
661
+ return result;
662
+ }
663
+
664
+ template <class Clock, class Duration>
665
+ bool try_lock_upgrade_until(
666
+ const std::chrono::time_point<Clock, Duration>& absDeadline) {
667
+ WaitUntilDeadline<Clock, Duration> ctx{absDeadline};
668
+ auto result = lockUpgradeImpl(ctx);
669
+ OwnershipTrackerBase::maybeBeginThreadOwnership(result);
670
+ annotateTryAcquired(result, annotate_rwlock_level::rdlock);
671
+ return result;
672
+ }
673
+
674
+ void unlock_upgrade() {
675
+ annotateReleased(annotate_rwlock_level::rdlock);
676
+ OwnershipTrackerBase::endThreadOwnership();
677
+ auto state = (state_ -= kHasU);
678
+ assert((state & (kWaitingNotS | kHasSolo)) == 0);
679
+ wakeRegisteredWaiters(state, kWaitingE | kWaitingU);
680
+ }
681
+
682
+ void unlock_upgrade_and_lock() {
683
+ // no waiting necessary, so waitMask is empty
684
+ WaitForever ctx;
685
+ (void)lockExclusiveImpl(0, ctx);
686
+ annotateReleased(annotate_rwlock_level::rdlock);
687
+ annotateAcquired(annotate_rwlock_level::wrlock);
688
+ }
689
+
690
+ void unlock_upgrade_and_lock_shared() {
691
+ // No need to annotate for TSAN here because we model upgrade and shared
692
+ // locks as the same.
693
+ OwnershipTrackerBase::endThreadOwnership();
694
+ auto state = (state_ -= kHasU - kIncrHasS);
695
+ assert((state & (kWaitingNotS | kHasSolo)) == 0);
696
+ wakeRegisteredWaiters(state, kWaitingE | kWaitingU);
697
+ }
698
+
699
+ void unlock_upgrade_and_lock_shared(Token& token) {
700
+ unlock_upgrade_and_lock_shared();
701
+ token.state_ = Token::State::LockedInlineShared;
702
+ }
703
+
704
+ void unlock_and_lock_upgrade() {
705
+ annotateReleased(annotate_rwlock_level::wrlock);
706
+ annotateAcquired(annotate_rwlock_level::rdlock);
707
+ // We can't use state_ -=, because we need to clear 2 bits (1 of
708
+ // which has an uncertain initial state) and set 1 other. We might
709
+ // as well clear the relevant wake bits at the same time.
710
+ auto state = state_.load(std::memory_order_acquire);
711
+ while (true) {
712
+ assert(
713
+ (state & ~(kWaitingAny | kPrevDefer | kAnnotationCreated)) == kHasE);
714
+ auto after =
715
+ (state & ~(kWaitingNotS | kWaitingS | kPrevDefer | kHasE)) + kHasU;
716
+ if (state_.compare_exchange_strong(state, after)) {
717
+ if ((state & kWaitingS) != 0) {
718
+ futexWakeAll(kWaitingS);
719
+ }
720
+ return;
721
+ }
722
+ }
723
+ }
724
+
725
+ private:
726
+ typedef typename folly::detail::Futex<Atom> Futex;
727
+
728
+ // Internally we use four kinds of wait contexts. These are structs
729
+ // that provide a doWait method that returns true if a futex wake
730
+ // was issued that intersects with the waitMask, false if there was a
731
+ // timeout and no more waiting should be performed. Spinning occurs
732
+ // before the wait context is invoked.
733
+
734
+ struct WaitForever {
735
+ bool canBlock() { return true; }
736
+ bool canTimeOut() { return false; }
737
+ bool shouldTimeOut() { return false; }
738
+
739
+ bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) {
740
+ detail::futexWait(&futex, expected, waitMask);
741
+ return true;
742
+ }
743
+ };
744
+
745
+ struct WaitNever {
746
+ bool canBlock() { return false; }
747
+ bool canTimeOut() { return true; }
748
+ bool shouldTimeOut() { return true; }
749
+
750
+ bool doWait(
751
+ Futex& /* futex */, uint32_t /* expected */, uint32_t /* waitMask */) {
752
+ return false;
753
+ }
754
+ };
755
+
756
+ template <class Rep, class Period>
757
+ struct WaitForDuration {
758
+ std::chrono::duration<Rep, Period> duration_;
759
+ bool deadlineComputed_;
760
+ std::chrono::steady_clock::time_point deadline_;
761
+
762
+ explicit WaitForDuration(const std::chrono::duration<Rep, Period>& duration)
763
+ : duration_(duration), deadlineComputed_(false) {}
764
+
765
+ std::chrono::steady_clock::time_point deadline() {
766
+ if (!deadlineComputed_) {
767
+ deadline_ = std::chrono::steady_clock::now() + duration_;
768
+ deadlineComputed_ = true;
769
+ }
770
+ return deadline_;
771
+ }
772
+
773
+ bool canBlock() { return duration_.count() > 0; }
774
+ bool canTimeOut() { return true; }
775
+
776
+ bool shouldTimeOut() {
777
+ return std::chrono::steady_clock::now() > deadline();
778
+ }
779
+
780
+ bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) {
781
+ auto result =
782
+ detail::futexWaitUntil(&futex, expected, deadline(), waitMask);
783
+ return result != folly::detail::FutexResult::TIMEDOUT;
784
+ }
785
+ };
786
+
787
+ template <class Clock, class Duration>
788
+ struct WaitUntilDeadline {
789
+ std::chrono::time_point<Clock, Duration> absDeadline_;
790
+
791
+ bool canBlock() { return true; }
792
+ bool canTimeOut() { return true; }
793
+ bool shouldTimeOut() { return Clock::now() > absDeadline_; }
794
+
795
+ bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) {
796
+ auto result =
797
+ detail::futexWaitUntil(&futex, expected, absDeadline_, waitMask);
798
+ return result != folly::detail::FutexResult::TIMEDOUT;
799
+ }
800
+ };
801
+
802
+ void annotateLazyCreate() {
803
+ if (AnnotateForThreadSanitizer &&
804
+ (state_.load() & kAnnotationCreated) == 0) {
805
+ auto guard = shared_mutex_detail::annotationGuard(this);
806
+ // check again
807
+ if ((state_.load() & kAnnotationCreated) == 0) {
808
+ state_.fetch_or(kAnnotationCreated);
809
+ annotate_benign_race_sized(
810
+ &state_, sizeof(state_), "init TSAN", __FILE__, __LINE__);
811
+ annotate_rwlock_create(this, __FILE__, __LINE__);
812
+ }
813
+ }
814
+ }
815
+
816
+ void annotateDestroy() {
817
+ if (AnnotateForThreadSanitizer) {
818
+ // call destroy only if the annotation was created
819
+ if (state_.load() & kAnnotationCreated) {
820
+ annotate_rwlock_destroy(this, __FILE__, __LINE__);
821
+ }
822
+ }
823
+ }
824
+
825
+ void annotateAcquired(annotate_rwlock_level w) {
826
+ if (AnnotateForThreadSanitizer) {
827
+ annotateLazyCreate();
828
+ annotate_rwlock_acquired(this, w, __FILE__, __LINE__);
829
+ }
830
+ }
831
+
832
+ void annotateTryAcquired(bool result, annotate_rwlock_level w) {
833
+ if (AnnotateForThreadSanitizer) {
834
+ annotateLazyCreate();
835
+ annotate_rwlock_try_acquired(this, w, result, __FILE__, __LINE__);
836
+ }
837
+ }
838
+
839
+ void annotateReleased(annotate_rwlock_level w) {
840
+ if (AnnotateForThreadSanitizer) {
841
+ assert((state_.load() & kAnnotationCreated) != 0);
842
+ annotate_rwlock_released(this, w, __FILE__, __LINE__);
843
+ }
844
+ }
845
+
846
+ // 32 bits of state
847
+ Futex state_{};
848
+
849
+ // S count needs to be on the end, because we explicitly allow it to
850
+ // underflow. This can occur while we are in the middle of applying
851
+ // deferred locks (we remove them from deferredReaders[] before
852
+ // inlining them), or during token-less unlock_shared() if a racing
853
+ // lock_shared();unlock_shared() moves the deferredReaders slot while
854
+ // the first unlock_shared() is scanning. The former case is cleaned
855
+ // up before we finish applying the locks. The latter case can persist
856
+ // until destruction, when it is cleaned up.
857
+ static constexpr uint32_t kIncrHasS = 1 << 11;
858
+ static constexpr uint32_t kHasS = ~(kIncrHasS - 1);
859
+
860
+ // Set if annotation has been completed for this instance. That annotation
861
+ // (and setting this bit afterward) must be guarded by one of the mutexes in
862
+ // annotationCreationGuards.
863
+ static constexpr uint32_t kAnnotationCreated = 1 << 10;
864
+
865
+ // If false, then there are definitely no deferred read locks for this
866
+ // instance. Cleared after initialization and when exclusively locked.
867
+ static constexpr uint32_t kMayDefer = 1 << 9;
868
+
869
+ // lock() cleared kMayDefer as soon as it starts draining readers (so
870
+ // that it doesn't have to do a second CAS once drain completes), but
871
+ // unlock_shared() still needs to know whether to scan deferredReaders[]
872
+ // or not. We copy kMayDefer to kPrevDefer when setting kHasE or
873
+ // kBegunE, and clear it when clearing those bits.
874
+ static constexpr uint32_t kPrevDefer = 1 << 8;
875
+
876
+ // Exclusive-locked blocks all read locks and write locks. This bit
877
+ // may be set before all readers have finished, but in that case the
878
+ // thread that sets it won't return to the caller until all read locks
879
+ // have been released.
880
+ static constexpr uint32_t kHasE = 1 << 7;
881
+
882
+ // Exclusive-draining means that lock() is waiting for existing readers
883
+ // to leave, but that new readers may still acquire shared access.
884
+ // This is only used in reader priority mode. New readers during
885
+ // drain must be inline. The difference between this and kHasU is that
886
+ // kBegunE prevents kMayDefer from being set.
887
+ static constexpr uint32_t kBegunE = 1 << 6;
888
+
889
+ // At most one thread may have either exclusive or upgrade lock
890
+ // ownership. Unlike exclusive mode, ownership of the lock in upgrade
891
+ // mode doesn't preclude other threads holding the lock in shared mode.
892
+ // boost's concept for this doesn't explicitly say whether new shared
893
+ // locks can be acquired one lock_upgrade has succeeded, but doesn't
894
+ // list that as disallowed. RWSpinLock disallows new read locks after
895
+ // lock_upgrade has been acquired, but the boost implementation doesn't.
896
+ // We choose the latter.
897
+ static constexpr uint32_t kHasU = 1 << 5;
898
+
899
+ // There are three states that we consider to be "solo", in that they
900
+ // cannot coexist with other solo states. These are kHasE, kBegunE,
901
+ // and kHasU. Note that S doesn't conflict with any of these, because
902
+ // setting the kHasE is only one of the two steps needed to actually
903
+ // acquire the lock in exclusive mode (the other is draining the existing
904
+ // S holders).
905
+ static constexpr uint32_t kHasSolo = kHasE | kBegunE | kHasU;
906
+
907
+ // Once a thread sets kHasE it needs to wait for the current readers
908
+ // to exit the lock. We give this a separate wait identity from the
909
+ // waiting to set kHasE so that we can perform partial wakeups (wake
910
+ // one instead of wake all).
911
+ static constexpr uint32_t kWaitingNotS = 1 << 4;
912
+
913
+ // When waking writers we can either wake them all, in which case we
914
+ // can clear kWaitingE, or we can call futexWake(1). futexWake tells
915
+ // us if anybody woke up, but even if we detect that nobody woke up we
916
+ // can't clear the bit after the fact without issuing another wakeup.
917
+ // To avoid thundering herds when there are lots of pending lock()
918
+ // without needing to call futexWake twice when there is only one
919
+ // waiter, kWaitingE actually encodes if we have observed multiple
920
+ // concurrent waiters. Tricky: ABA issues on futexWait mean that when
921
+ // we see kWaitingESingle we can't assume that there is only one.
922
+ static constexpr uint32_t kWaitingESingle = 1 << 2;
923
+ static constexpr uint32_t kWaitingEMultiple = 1 << 3;
924
+ static constexpr uint32_t kWaitingE = kWaitingESingle | kWaitingEMultiple;
925
+
926
+ // kWaitingU is essentially a 1 bit saturating counter. It always
927
+ // requires a wakeAll.
928
+ static constexpr uint32_t kWaitingU = 1 << 1;
929
+
930
+ // All blocked lock_shared() should be awoken, so it is correct (not
931
+ // suboptimal) to wakeAll if there are any shared readers.
932
+ static constexpr uint32_t kWaitingS = 1 << 0;
933
+
934
+ // kWaitingAny is a mask of all of the bits that record the state of
935
+ // threads, rather than the state of the lock. It is convenient to be
936
+ // able to mask them off during asserts.
937
+ static constexpr uint32_t kWaitingAny =
938
+ kWaitingNotS | kWaitingE | kWaitingU | kWaitingS;
939
+
940
+ // The reader count at which a reader will attempt to use the lock
941
+ // in deferred mode. If this value is 2, then the second concurrent
942
+ // reader will set kMayDefer and use deferredReaders[]. kMayDefer is
943
+ // cleared during exclusive access, so this threshold must be reached
944
+ // each time a lock is held in exclusive mode.
945
+ static constexpr uint32_t kNumSharedToStartDeferring = 2;
946
+
947
+ // Maximum time in cycles a thread will spin waiting for a state transition.
948
+ static constexpr uint64_t kMaxSpinCycles = Policy::max_spin_cycles;
949
+
950
+ // The maximum number of soft yields before falling back to futex.
951
+ // If the preemption heuristic is activated we will fall back before
952
+ // this. A soft yield takes ~900 nanos (two sched_yield plus a call
953
+ // to getrusage, with checks of the goal at each step). Soft yields
954
+ // aren't compatible with deterministic execution under test (unlike
955
+ // futexWaitUntil, which has a capricious but deterministic back end).
956
+ static constexpr uint32_t kMaxSoftYieldCount = Policy::max_soft_yield_count;
957
+
958
+ // If AccessSpreader assigns indexes from 0..k*n-1 on a system where some
959
+ // level of the memory hierarchy is symmetrically divided into k pieces
960
+ // (NUMA nodes, last-level caches, L1 caches, ...), then slot indexes
961
+ // that are the same after integer division by k share that resource.
962
+ // Our strategy for deferred readers is to probe up to numSlots/4 slots,
963
+ // using the full granularity of AccessSpreader for the start slot
964
+ // and then search outward. We can use AccessSpreader::current(n)
965
+ // without managing our own spreader if kMaxDeferredReaders <=
966
+ // AccessSpreader::kMaxCpus, which is currently 128.
967
+ //
968
+ // In order to give each L1 cache its own playground, we need
969
+ // kMaxDeferredReaders >= #L1 caches. We double it, making it
970
+ // essentially the number of cores, so it doesn't easily run
971
+ // out of deferred reader slots and start inlining the readers.
972
+ // We do not know the number of cores at compile time, as the code
973
+ // can be compiled from different server types than the one running
974
+ // the service. So we allocate the static storage large enough to
975
+ // hold all the slots (256).
976
+ //
977
+ // On x86_64 each DeferredReaderSlot is 8 bytes, so we need
978
+ // kMaxDeferredReaders
979
+ // * kDeferredSeparationFactor >= 64 * #L1 caches / 8 == 128. If
980
+ // kDeferredSearchDistance * kDeferredSeparationFactor <=
981
+ // 64 / 8 then we will search only within a single cache line, which
982
+ // guarantees we won't have inter-L1 contention.
983
+ public:
984
+ static constexpr uint32_t kDeferredSearchDistance = 2;
985
+ static constexpr uint32_t kDeferredSeparationFactor = 4;
986
+
987
+ private:
988
+ static_assert(
989
+ !(kDeferredSearchDistance & (kDeferredSearchDistance - 1)),
990
+ "kDeferredSearchDistance must be a power of 2");
991
+
992
+ // We need to make sure that if there is a lock_shared()
993
+ // and lock_shared(token) followed by unlock_shared() and
994
+ // unlock_shared(token), the token-less unlock doesn't null
995
+ // out deferredReaders[token.slot_]. If we allowed that, then
996
+ // unlock_shared(token) wouldn't be able to assume that its lock
997
+ // had been inlined by applyDeferredReaders when it finds that
998
+ // deferredReaders[token.slot_] no longer points to this. We accomplish
999
+ // this by stealing bit 0 from the pointer to record that the slot's
1000
+ // element has no token, hence our use of uintptr_t in deferredReaders[].
1001
+ static constexpr uintptr_t kTokenless = 0x1;
1002
+
1003
+ // This is the starting location for Token-less unlock_shared().
1004
+ FOLLY_EXPORT FOLLY_ALWAYS_INLINE static relaxed_atomic<uint32_t>&
1005
+ tls_lastTokenlessSlot() {
1006
+ static relaxed_atomic<uint32_t> non_tl{};
1007
+ static thread_local relaxed_atomic<uint32_t> tl{};
1008
+ return kIsMobile ? non_tl : tl;
1009
+ }
1010
+
1011
+ // Last deferred reader slot used.
1012
+ FOLLY_EXPORT FOLLY_ALWAYS_INLINE static relaxed_atomic<uint32_t>&
1013
+ tls_lastDeferredReaderSlot() {
1014
+ static relaxed_atomic<uint32_t> non_tl{};
1015
+ static thread_local relaxed_atomic<uint32_t> tl{};
1016
+ return kIsMobile ? non_tl : tl;
1017
+ }
1018
+
1019
+ // Only indexes divisible by kDeferredSeparationFactor are used.
1020
+ // If any of those elements points to a SharedMutexImpl, then it
1021
+ // should be considered that there is a shared lock on that instance.
1022
+ // See kTokenless.
1023
+ public:
1024
+ typedef Atom<uintptr_t> DeferredReaderSlot;
1025
+
1026
+ private:
1027
+ alignas(hardware_destructive_interference_size) static DeferredReaderSlot
1028
+ deferredReaders
1029
+ [shared_mutex_detail::kMaxDeferredReadersAllocated *
1030
+ kDeferredSeparationFactor];
1031
+
1032
+ // Performs an exclusive lock, waiting for state_ & waitMask to be
1033
+ // zero first
1034
+ template <class WaitContext>
1035
+ bool lockExclusiveImpl(uint32_t preconditionGoalMask, WaitContext& ctx) {
1036
+ uint32_t state = state_.load(std::memory_order_acquire);
1037
+ if (FOLLY_LIKELY(
1038
+ (state & (preconditionGoalMask | kMayDefer | kHasS)) == 0 &&
1039
+ state_.compare_exchange_strong(state, (state | kHasE) & ~kHasU))) {
1040
+ return true;
1041
+ } else {
1042
+ return lockExclusiveImpl(state, preconditionGoalMask, ctx);
1043
+ }
1044
+ }
1045
+
1046
+ template <class WaitContext>
1047
+ bool lockExclusiveImpl(
1048
+ uint32_t& state, uint32_t preconditionGoalMask, WaitContext& ctx) {
1049
+ while (true) {
1050
+ if (FOLLY_UNLIKELY((state & preconditionGoalMask) != 0) &&
1051
+ !waitForZeroBits(state, preconditionGoalMask, kWaitingE, ctx) &&
1052
+ ctx.canTimeOut()) {
1053
+ return false;
1054
+ }
1055
+
1056
+ uint32_t after = (state & kMayDefer) == 0 ? 0 : kPrevDefer;
1057
+ if (!kReaderPriority || (state & (kMayDefer | kHasS)) == 0) {
1058
+ // Block readers immediately, either because we are in write
1059
+ // priority mode or because we can acquire the lock in one
1060
+ // step. Note that if state has kHasU, then we are doing an
1061
+ // unlock_upgrade_and_lock() and we should clear it (reader
1062
+ // priority branch also does this).
1063
+ after |= (state | kHasE) & ~(kHasU | kMayDefer);
1064
+ } else {
1065
+ after |= (state | kBegunE) & ~(kHasU | kMayDefer);
1066
+ }
1067
+ if (state_.compare_exchange_strong(state, after)) {
1068
+ auto before = state;
1069
+ state = after;
1070
+
1071
+ // If we set kHasE (writer priority) then no new readers can
1072
+ // arrive. If we set kBegunE then they can still enter, but
1073
+ // they must be inline. Either way we need to either spin on
1074
+ // deferredReaders[] slots, or inline them so that we can wait on
1075
+ // kHasS to zero itself. deferredReaders[] is pointers, which on
1076
+ // x86_64 are bigger than futex() can handle, so we inline the
1077
+ // deferred locks instead of trying to futexWait on each slot.
1078
+ // Readers are responsible for rechecking state_ after recording
1079
+ // a deferred read to avoid atomicity problems between the state_
1080
+ // CAS and applyDeferredReader's reads of deferredReaders[].
1081
+ if (FOLLY_UNLIKELY((before & kMayDefer) != 0)) {
1082
+ applyDeferredReaders(state, ctx);
1083
+ }
1084
+ while (true) {
1085
+ assert((state & (kHasE | kBegunE)) != 0 && (state & kHasU) == 0);
1086
+ if (FOLLY_UNLIKELY((state & kHasS) != 0) &&
1087
+ !waitForZeroBits(state, kHasS, kWaitingNotS, ctx) &&
1088
+ ctx.canTimeOut()) {
1089
+ // Ugh. We blocked new readers and other writers for a while,
1090
+ // but were unable to complete. Move on. On the plus side
1091
+ // we can clear kWaitingNotS because nobody else can piggyback
1092
+ // on it.
1093
+ state = (state_ &= ~(kPrevDefer | kHasE | kBegunE | kWaitingNotS));
1094
+ wakeRegisteredWaiters(state, kWaitingE | kWaitingU | kWaitingS);
1095
+ return false;
1096
+ }
1097
+
1098
+ if (kReaderPriority && (state & kHasE) == 0) {
1099
+ assert((state & kBegunE) != 0);
1100
+ if (!state_.compare_exchange_strong(
1101
+ state, (state & ~kBegunE) | kHasE)) {
1102
+ continue;
1103
+ }
1104
+ }
1105
+
1106
+ return true;
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ template <class WaitContext>
1113
+ bool waitForZeroBits(
1114
+ uint32_t& state, uint32_t goal, uint32_t waitMask, WaitContext& ctx) {
1115
+ for (uint64_t start = hardware_timestamp();;) {
1116
+ state = state_.load(std::memory_order_acquire);
1117
+ if ((state & goal) == 0) {
1118
+ return true;
1119
+ }
1120
+ const uint64_t elapsed = hardware_timestamp() - start;
1121
+ // NOTE: This is also true if hardware_timestamp() goes back in time, as
1122
+ // elapsed underflows.
1123
+ if (FOLLY_UNLIKELY(elapsed >= kMaxSpinCycles)) {
1124
+ return ctx.canBlock() &&
1125
+ yieldWaitForZeroBits(state, goal, waitMask, ctx);
1126
+ }
1127
+ asm_volatile_pause();
1128
+ }
1129
+ }
1130
+
1131
+ template <class WaitContext>
1132
+ bool yieldWaitForZeroBits(
1133
+ uint32_t& state, uint32_t goal, uint32_t waitMask, WaitContext& ctx) {
1134
+ long thread_nivcsw = 0;
1135
+ long before = -1;
1136
+ for (uint32_t yieldCount = 0; yieldCount < kMaxSoftYieldCount;
1137
+ ++yieldCount) {
1138
+ for (int softState = 0; softState < 3; ++softState) {
1139
+ if (softState < 2) {
1140
+ std::this_thread::yield();
1141
+ } else {
1142
+ thread_nivcsw = shared_mutex_detail::
1143
+ getCurrentThreadInvoluntaryContextSwitchCount();
1144
+ }
1145
+ if (((state = state_.load(std::memory_order_acquire)) & goal) == 0) {
1146
+ return true;
1147
+ }
1148
+ if (ctx.shouldTimeOut()) {
1149
+ return false;
1150
+ }
1151
+ }
1152
+ if (before >= 0 && thread_nivcsw >= before + 2) {
1153
+ // One involuntary csw might just be occasional background work,
1154
+ // but if we get two in a row then we guess that there is someone
1155
+ // else who can profitably use this CPU. Fall back to futex
1156
+ break;
1157
+ }
1158
+ before = thread_nivcsw;
1159
+ }
1160
+ return futexWaitForZeroBits(state, goal, waitMask, ctx);
1161
+ }
1162
+
1163
+ template <class WaitContext>
1164
+ bool futexWaitForZeroBits(
1165
+ uint32_t& state, uint32_t goal, uint32_t waitMask, WaitContext& ctx) {
1166
+ assert(
1167
+ waitMask == kWaitingNotS || waitMask == kWaitingE ||
1168
+ waitMask == kWaitingU || waitMask == kWaitingS);
1169
+
1170
+ while (true) {
1171
+ state = state_.load(std::memory_order_acquire);
1172
+ if ((state & goal) == 0) {
1173
+ return true;
1174
+ }
1175
+
1176
+ auto after = state;
1177
+ if (waitMask == kWaitingE) {
1178
+ if ((state & kWaitingESingle) != 0) {
1179
+ after |= kWaitingEMultiple;
1180
+ } else {
1181
+ after |= kWaitingESingle;
1182
+ }
1183
+ } else {
1184
+ after |= waitMask;
1185
+ }
1186
+
1187
+ // CAS is better than atomic |= here, because it lets us avoid
1188
+ // setting the wait flag when the goal is concurrently achieved
1189
+ if (after != state && !state_.compare_exchange_strong(state, after)) {
1190
+ continue;
1191
+ }
1192
+
1193
+ if (!ctx.doWait(state_, after, waitMask)) {
1194
+ // timed out
1195
+ return false;
1196
+ }
1197
+ }
1198
+ }
1199
+
1200
+ // Wakes up waiters registered in state_ as appropriate, clearing the
1201
+ // awaiting bits for anybody that was awoken. Tries to perform direct
1202
+ // single wakeup of an exclusive waiter if appropriate
1203
+ void wakeRegisteredWaiters(uint32_t& state, uint32_t wakeMask) {
1204
+ if (FOLLY_UNLIKELY((state & wakeMask) != 0)) {
1205
+ wakeRegisteredWaitersImpl(state, wakeMask);
1206
+ }
1207
+ }
1208
+
1209
+ [[FOLLY_ATTR_GNU_USED]]
1210
+ void wakeRegisteredWaitersImpl(uint32_t& state, uint32_t wakeMask) {
1211
+ // If there are multiple lock() pending only one of them will actually
1212
+ // get to wake up, so issuing futexWakeAll will make a thundering herd.
1213
+ // There's nothing stopping us from issuing futexWake(1) instead,
1214
+ // so long as the wait bits are still an accurate reflection of
1215
+ // the waiters. If we notice (via futexWake's return value) that
1216
+ // nobody woke up then we can try again with the normal wake-all path.
1217
+ // Note that we can't just clear the bits at that point; we need to
1218
+ // clear the bits and then issue another wakeup.
1219
+ //
1220
+ // It is possible that we wake an E waiter but an outside S grabs the
1221
+ // lock instead, at which point we should wake pending U and S waiters.
1222
+ // Rather than tracking state to make the failing E regenerate the
1223
+ // wakeup, we just disable the optimization in the case that there
1224
+ // are waiting U or S that we are eligible to wake.
1225
+ if ((wakeMask & kWaitingE) == kWaitingE &&
1226
+ (state & wakeMask) == kWaitingE &&
1227
+ detail::futexWake(&state_, 1, kWaitingE) > 0) {
1228
+ // somebody woke up, so leave state_ as is and clear it later
1229
+ return;
1230
+ }
1231
+
1232
+ if ((state & wakeMask) != 0) {
1233
+ auto prev = state_.fetch_and(~wakeMask);
1234
+ if ((prev & wakeMask) != 0) {
1235
+ futexWakeAll(wakeMask);
1236
+ }
1237
+ state = prev & ~wakeMask;
1238
+ }
1239
+ }
1240
+
1241
+ void futexWakeAll(uint32_t wakeMask) {
1242
+ detail::futexWake(&state_, std::numeric_limits<int>::max(), wakeMask);
1243
+ }
1244
+
1245
+ DeferredReaderSlot* deferredReader(uint32_t slot) {
1246
+ return &deferredReaders[slot * kDeferredSeparationFactor];
1247
+ }
1248
+
1249
+ uintptr_t tokenfulSlotValue() { return reinterpret_cast<uintptr_t>(this); }
1250
+
1251
+ uintptr_t tokenlessSlotValue() { return tokenfulSlotValue() | kTokenless; }
1252
+
1253
+ bool slotValueIsThis(uintptr_t slotValue) {
1254
+ return (slotValue & ~kTokenless) == tokenfulSlotValue();
1255
+ }
1256
+
1257
+ // Clears any deferredReaders[] that point to this, adjusting the inline
1258
+ // shared lock count to compensate. Does some spinning and yielding
1259
+ // to avoid the work. Always finishes the application, even if ctx
1260
+ // times out.
1261
+ template <class WaitContext>
1262
+ void applyDeferredReaders(uint32_t& state, WaitContext& ctx) {
1263
+ uint32_t slot = 0;
1264
+
1265
+ const uint32_t maxDeferredReaders =
1266
+ shared_mutex_detail::getMaxDeferredReaders();
1267
+ for (uint64_t start = hardware_timestamp();;) {
1268
+ while (!slotValueIsThis(
1269
+ deferredReader(slot)->load(std::memory_order_acquire))) {
1270
+ if (++slot == maxDeferredReaders) {
1271
+ return;
1272
+ }
1273
+ }
1274
+ const uint64_t elapsed = hardware_timestamp() - start;
1275
+ // NOTE: This is also true if hardware_timestamp() goes back in time, as
1276
+ // elapsed underflows.
1277
+ if (FOLLY_UNLIKELY(elapsed >= kMaxSpinCycles)) {
1278
+ applyDeferredReaders(state, ctx, slot);
1279
+ return;
1280
+ }
1281
+ asm_volatile_pause();
1282
+ }
1283
+ }
1284
+
1285
+ template <class WaitContext>
1286
+ void applyDeferredReaders(uint32_t& state, WaitContext& ctx, uint32_t slot) {
1287
+ long thread_nivcsw = 0;
1288
+ long before = -1;
1289
+ const uint32_t maxDeferredReaders =
1290
+ shared_mutex_detail::getMaxDeferredReaders();
1291
+ for (uint32_t yieldCount = 0; yieldCount < kMaxSoftYieldCount;
1292
+ ++yieldCount) {
1293
+ for (int softState = 0; softState < 3; ++softState) {
1294
+ if (softState < 2) {
1295
+ std::this_thread::yield();
1296
+ } else {
1297
+ thread_nivcsw = shared_mutex_detail::
1298
+ getCurrentThreadInvoluntaryContextSwitchCount();
1299
+ }
1300
+ while (!slotValueIsThis(
1301
+ deferredReader(slot)->load(std::memory_order_acquire))) {
1302
+ if (++slot == maxDeferredReaders) {
1303
+ return;
1304
+ }
1305
+ }
1306
+ if (ctx.shouldTimeOut()) {
1307
+ // finish applying immediately on timeout
1308
+ break;
1309
+ }
1310
+ }
1311
+ if (before >= 0 && thread_nivcsw >= before + 2) {
1312
+ // heuristic says run queue is not empty
1313
+ break;
1314
+ }
1315
+ before = thread_nivcsw;
1316
+ }
1317
+
1318
+ uint32_t movedSlotCount = 0;
1319
+ for (; slot < maxDeferredReaders; ++slot) {
1320
+ auto slotPtr = deferredReader(slot);
1321
+ auto slotValue = slotPtr->load(std::memory_order_acquire);
1322
+ if (slotValueIsThis(slotValue) &&
1323
+ slotPtr->compare_exchange_strong(slotValue, 0)) {
1324
+ ++movedSlotCount;
1325
+ }
1326
+ }
1327
+
1328
+ if (movedSlotCount > 0) {
1329
+ state = (state_ += movedSlotCount * kIncrHasS);
1330
+ }
1331
+ assert((state & (kHasE | kBegunE)) != 0);
1332
+
1333
+ // if state + kIncrHasS overflows (off the end of state) then either
1334
+ // we have 2^(32-9) readers (almost certainly an application bug)
1335
+ // or we had an underflow (also a bug)
1336
+ assert(state < state + kIncrHasS);
1337
+ }
1338
+
1339
+ // It is straightforward to make a token-less lock_shared() and
1340
+ // unlock_shared() either by making the token-less version always use
1341
+ // LockedInlineShared mode or by removing the token version. Supporting
1342
+ // deferred operation for both types is trickier than it appears, because
1343
+ // the purpose of the token it so that unlock_shared doesn't have to
1344
+ // look in other slots for its deferred lock. Token-less unlock_shared
1345
+ // might place a deferred lock in one place and then release a different
1346
+ // slot that was originally used by the token-ful version. If this was
1347
+ // important we could solve the problem by differentiating the deferred
1348
+ // locks so that cross-variety release wouldn't occur. The best way
1349
+ // is probably to steal a bit from the pointer, making deferredLocks[]
1350
+ // an array of Atom<uintptr_t>.
1351
+
1352
+ template <class WaitContext>
1353
+ bool lockSharedImpl(Token* token, WaitContext& ctx) {
1354
+ uint32_t state = state_.load(std::memory_order_relaxed);
1355
+ if ((state & (kHasS | kMayDefer | kHasE)) == 0 &&
1356
+ state_.compare_exchange_strong(state, state + kIncrHasS)) {
1357
+ if (token != nullptr) {
1358
+ token->state_ = Token::State::LockedInlineShared;
1359
+ }
1360
+ return true;
1361
+ }
1362
+ return lockSharedImpl(state, token, ctx);
1363
+ }
1364
+
1365
+ template <class WaitContext>
1366
+ bool lockSharedImpl(uint32_t& state, Token* token, WaitContext& ctx);
1367
+
1368
+ // Updates the state in/out argument as if the locks were made inline,
1369
+ // but does not update state_
1370
+ void cleanupTokenlessSharedDeferred(uint32_t& state) {
1371
+ const uint32_t maxDeferredReaders =
1372
+ shared_mutex_detail::getMaxDeferredReaders();
1373
+ for (uint32_t i = 0; i < maxDeferredReaders; ++i) {
1374
+ auto slotPtr = deferredReader(i);
1375
+ auto slotValue = slotPtr->load(std::memory_order_relaxed);
1376
+ if (slotValue == tokenlessSlotValue()) {
1377
+ slotPtr->store(0, std::memory_order_relaxed);
1378
+ state += kIncrHasS;
1379
+ if ((state & kHasS) == 0) {
1380
+ break;
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+
1386
+ bool tryUnlockTokenlessSharedDeferred();
1387
+
1388
+ bool tryUnlockSharedDeferred(uint32_t slot) {
1389
+ assert(slot < shared_mutex_detail::getMaxDeferredReaders());
1390
+ auto slotValue = tokenfulSlotValue();
1391
+ return deferredReader(slot)->compare_exchange_strong(slotValue, 0);
1392
+ }
1393
+
1394
+ uint32_t unlockSharedInline() {
1395
+ uint32_t state = (state_ -= kIncrHasS);
1396
+ assert(
1397
+ (state & (kHasE | kBegunE | kMayDefer)) != 0 ||
1398
+ state < state + kIncrHasS);
1399
+ if ((state & kHasS) == 0) {
1400
+ // Only the second half of lock() can be blocked by a non-zero
1401
+ // reader count, so that's the only thing we need to wake
1402
+ wakeRegisteredWaiters(state, kWaitingNotS);
1403
+ }
1404
+ return state;
1405
+ }
1406
+
1407
+ template <class WaitContext>
1408
+ bool lockUpgradeImpl(WaitContext& ctx) {
1409
+ uint32_t state;
1410
+ do {
1411
+ if (!waitForZeroBits(state, kHasSolo, kWaitingU, ctx)) {
1412
+ return false;
1413
+ }
1414
+ } while (!state_.compare_exchange_strong(state, state | kHasU));
1415
+ return true;
1416
+ }
1417
+ };
1418
+
1419
+ using SharedMutexReadPriority = SharedMutexImpl<true>;
1420
+ using SharedMutexWritePriority = SharedMutexImpl<false>;
1421
+ using SharedMutex = SharedMutexWritePriority;
1422
+ using SharedMutexTracked = SharedMutexImpl<
1423
+ false,
1424
+ void,
1425
+ std::atomic,
1426
+ shared_mutex_detail::PolicyTracked>;
1427
+ using SharedMutexSuppressTSAN = SharedMutexImpl<
1428
+ false,
1429
+ void,
1430
+ std::atomic,
1431
+ shared_mutex_detail::PolicySuppressTSAN>;
1432
+
1433
+ // Prevent the compiler from instantiating these in other translation units.
1434
+ // They are instantiated once in SharedMutex.cpp
1435
+ extern template class SharedMutexImpl<true>;
1436
+ extern template class SharedMutexImpl<false>;
1437
+
1438
+ template <
1439
+ bool ReaderPriority,
1440
+ typename Tag_,
1441
+ template <typename>
1442
+ class Atom,
1443
+ typename Policy>
1444
+ alignas(hardware_destructive_interference_size)
1445
+ typename SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>::
1446
+ DeferredReaderSlot
1447
+ SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>::deferredReaders
1448
+ [shared_mutex_detail::kMaxDeferredReadersAllocated *
1449
+ kDeferredSeparationFactor] = {};
1450
+
1451
+ template <
1452
+ bool ReaderPriority,
1453
+ typename Tag_,
1454
+ template <typename>
1455
+ class Atom,
1456
+ typename Policy>
1457
+ bool SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>::
1458
+ tryUnlockTokenlessSharedDeferred() {
1459
+ uint32_t bestSlot = tls_lastTokenlessSlot();
1460
+ // use do ... while to avoid calling
1461
+ // shared_mutex_detail::getMaxDeferredReaders() unless necessary
1462
+ uint32_t i = 0;
1463
+ do {
1464
+ auto slotPtr = deferredReader(bestSlot ^ i);
1465
+ auto slotValue = slotPtr->load(std::memory_order_relaxed);
1466
+ if (slotValue == tokenlessSlotValue() &&
1467
+ slotPtr->compare_exchange_strong(slotValue, 0)) {
1468
+ tls_lastTokenlessSlot() = bestSlot ^ i;
1469
+ return true;
1470
+ }
1471
+ ++i;
1472
+ } while (i < shared_mutex_detail::getMaxDeferredReaders());
1473
+ return false;
1474
+ }
1475
+
1476
+ template <
1477
+ bool ReaderPriority,
1478
+ typename Tag_,
1479
+ template <typename>
1480
+ class Atom,
1481
+ typename Policy>
1482
+ template <class WaitContext>
1483
+ bool SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>::lockSharedImpl(
1484
+ uint32_t& state, Token* token, WaitContext& ctx) {
1485
+ const uint32_t maxDeferredReaders =
1486
+ shared_mutex_detail::getMaxDeferredReaders();
1487
+ while (true) {
1488
+ if (FOLLY_UNLIKELY((state & kHasE) != 0) &&
1489
+ !waitForZeroBits(state, kHasE, kWaitingS, ctx) && ctx.canTimeOut()) {
1490
+ return false;
1491
+ }
1492
+
1493
+ uint32_t slot = tls_lastDeferredReaderSlot();
1494
+ uintptr_t slotValue = 1; // any non-zero value will do
1495
+
1496
+ bool canAlreadyDefer = (state & kMayDefer) != 0;
1497
+ bool aboveDeferThreshold =
1498
+ (state & kHasS) >= (kNumSharedToStartDeferring - 1) * kIncrHasS;
1499
+ bool drainInProgress = ReaderPriority && (state & kBegunE) != 0;
1500
+ if (canAlreadyDefer || (aboveDeferThreshold && !drainInProgress)) {
1501
+ /* Try using the most recent slot first. */
1502
+ slotValue = deferredReader(slot)->load(std::memory_order_relaxed);
1503
+ if (slotValue != 0) {
1504
+ // starting point for our empty-slot search, can change after
1505
+ // calling waitForZeroBits
1506
+ uint32_t bestSlot =
1507
+ (uint32_t)folly::AccessSpreader<Atom>::current(maxDeferredReaders);
1508
+
1509
+ // deferred readers are already enabled, or it is time to
1510
+ // enable them if we can find a slot
1511
+ for (uint32_t i = 0; i < kDeferredSearchDistance; ++i) {
1512
+ slot = bestSlot ^ i;
1513
+ assert(slot < maxDeferredReaders);
1514
+ slotValue = deferredReader(slot)->load(std::memory_order_relaxed);
1515
+ if (slotValue == 0) {
1516
+ // found empty slot
1517
+ tls_lastDeferredReaderSlot() = slot;
1518
+ break;
1519
+ }
1520
+ }
1521
+ }
1522
+ }
1523
+
1524
+ if (slotValue != 0) {
1525
+ // not yet deferred, or no empty slots
1526
+ if (state_.compare_exchange_strong(state, state + kIncrHasS)) {
1527
+ // successfully recorded the read lock inline
1528
+ if (token != nullptr) {
1529
+ token->state_ = Token::State::LockedInlineShared;
1530
+ }
1531
+ return true;
1532
+ }
1533
+ // state is updated, try again
1534
+ continue;
1535
+ }
1536
+
1537
+ // record that deferred readers might be in use if necessary
1538
+ if ((state & kMayDefer) == 0) {
1539
+ if (!state_.compare_exchange_strong(state, state | kMayDefer)) {
1540
+ // keep going if CAS failed because somebody else set the bit
1541
+ // for us
1542
+ if ((state & (kHasE | kMayDefer)) != kMayDefer) {
1543
+ continue;
1544
+ }
1545
+ }
1546
+ // state = state | kMayDefer;
1547
+ }
1548
+
1549
+ // try to use the slot
1550
+ bool gotSlot = deferredReader(slot)->compare_exchange_strong(
1551
+ slotValue,
1552
+ token == nullptr ? tokenlessSlotValue() : tokenfulSlotValue());
1553
+
1554
+ // If we got the slot, we need to verify that an exclusive lock
1555
+ // didn't happen since we last checked. If we didn't get the slot we
1556
+ // need to recheck state_ anyway to make sure we don't waste too much
1557
+ // work. It is also possible that since we checked state_ someone
1558
+ // has acquired and released the write lock, clearing kMayDefer.
1559
+ // Both cases are covered by looking for the readers-possible bit,
1560
+ // because it is off when the exclusive lock bit is set.
1561
+ state = state_.load(std::memory_order_acquire);
1562
+
1563
+ if (!gotSlot) {
1564
+ continue;
1565
+ }
1566
+
1567
+ if (token == nullptr) {
1568
+ tls_lastTokenlessSlot() = slot;
1569
+ }
1570
+
1571
+ if ((state & kMayDefer) != 0) {
1572
+ assert((state & kHasE) == 0);
1573
+ // success
1574
+ if (token != nullptr) {
1575
+ token->state_ = Token::State::LockedDeferredShared;
1576
+ token->slot_ = (uint16_t)slot;
1577
+ }
1578
+ return true;
1579
+ }
1580
+
1581
+ // release the slot before retrying
1582
+ if (token == nullptr) {
1583
+ // We can't rely on slot. Token-less slot values can be freed by
1584
+ // any unlock_shared(), so we need to do the full deferredReader
1585
+ // search during unlock. Unlike unlock_shared(), we can't trust
1586
+ // kPrevDefer here. This deferred lock isn't visible to lock()
1587
+ // (that's the whole reason we're undoing it) so there might have
1588
+ // subsequently been an unlock() and lock() with no intervening
1589
+ // transition to deferred mode.
1590
+ if (!tryUnlockTokenlessSharedDeferred()) {
1591
+ unlockSharedInline();
1592
+ }
1593
+ } else {
1594
+ if (!tryUnlockSharedDeferred(slot)) {
1595
+ unlockSharedInline();
1596
+ }
1597
+ }
1598
+
1599
+ // We got here not because the lock was unavailable, but because
1600
+ // we lost a compare-and-swap. Try-lock is typically allowed to
1601
+ // have spurious failures, but there is no lock efficiency gain
1602
+ // from exploiting that freedom here.
1603
+ }
1604
+ }
1605
+
1606
+ namespace shared_mutex_detail {
1607
+
1608
+ [[noreturn]] void throwOperationNotPermitted();
1609
+
1610
+ [[noreturn]] void throwDeadlockWouldOccur();
1611
+
1612
+ } // namespace shared_mutex_detail
1613
+
1614
+ } // namespace folly
1615
+
1616
+ // std::shared_lock specialization for folly::SharedMutex to leverage tokenful
1617
+ // version of unlock_shared for faster unlocking.
1618
+ namespace std {
1619
+
1620
+ template <
1621
+ bool ReaderPriority,
1622
+ typename Tag_,
1623
+ template <typename>
1624
+ class Atom,
1625
+ typename Policy>
1626
+ class shared_lock<
1627
+ ::folly::SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>> {
1628
+ public:
1629
+ using mutex_type =
1630
+ ::folly::SharedMutexImpl<ReaderPriority, Tag_, Atom, Policy>;
1631
+ using token_type = typename mutex_type::Token;
1632
+
1633
+ shared_lock() noexcept = default;
1634
+
1635
+ FOLLY_NODISCARD explicit shared_lock(mutex_type& mutex)
1636
+ : mutex_(std::addressof(mutex)) {
1637
+ lock();
1638
+ }
1639
+
1640
+ shared_lock(mutex_type& mutex, std::defer_lock_t) noexcept
1641
+ : mutex_(std::addressof(mutex)) {}
1642
+
1643
+ FOLLY_NODISCARD shared_lock(mutex_type& mutex, std::try_to_lock_t)
1644
+ : mutex_(std::addressof(mutex)) {
1645
+ try_lock();
1646
+ }
1647
+
1648
+ FOLLY_NODISCARD shared_lock(mutex_type& mutex, std::adopt_lock_t)
1649
+ : mutex_(std::addressof(mutex)) {
1650
+ token_.state_ = token_type::State::LockedShared;
1651
+ }
1652
+
1653
+ template <typename Clock, typename Duration>
1654
+ FOLLY_NODISCARD shared_lock(
1655
+ mutex_type& mutex,
1656
+ const std::chrono::time_point<Clock, Duration>& deadline)
1657
+ : mutex_(std::addressof(mutex)) {
1658
+ try_lock_until(deadline);
1659
+ }
1660
+
1661
+ template <typename Rep, typename Period>
1662
+ FOLLY_NODISCARD shared_lock(
1663
+ mutex_type& mutex, const std::chrono::duration<Rep, Period>& timeout)
1664
+ : mutex_(std::addressof(mutex)) {
1665
+ try_lock_for(timeout);
1666
+ }
1667
+
1668
+ ~shared_lock() {
1669
+ if (owns_lock()) {
1670
+ mutex_->unlock_shared(token_);
1671
+ }
1672
+ }
1673
+
1674
+ shared_lock(const shared_lock&) = delete;
1675
+
1676
+ shared_lock& operator=(const shared_lock&) = delete;
1677
+
1678
+ shared_lock(shared_lock&& other) noexcept : shared_lock() { swap(other); }
1679
+
1680
+ shared_lock& operator=(shared_lock&& other) noexcept {
1681
+ shared_lock(std::move(other)).swap(*this);
1682
+ return *this;
1683
+ }
1684
+
1685
+ void lock() {
1686
+ error_if_not_lockable();
1687
+ mutex_->lock_shared(token_);
1688
+ }
1689
+
1690
+ bool try_lock() {
1691
+ error_if_not_lockable();
1692
+ return mutex_->try_lock_shared(token_);
1693
+ }
1694
+
1695
+ template <typename Rep, typename Period>
1696
+ bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout) {
1697
+ error_if_not_lockable();
1698
+ return mutex_->try_lock_shared_for(timeout, token_);
1699
+ }
1700
+
1701
+ template <typename Clock, typename Duration>
1702
+ bool try_lock_until(
1703
+ const std::chrono::time_point<Clock, Duration>& deadline) {
1704
+ error_if_not_lockable();
1705
+ return mutex_->try_lock_shared_until(deadline, token_);
1706
+ }
1707
+
1708
+ void unlock() {
1709
+ if (FOLLY_UNLIKELY(!owns_lock())) {
1710
+ ::folly::shared_mutex_detail::throwOperationNotPermitted();
1711
+ }
1712
+ mutex_->unlock_shared(token_);
1713
+ token_ = {};
1714
+ }
1715
+
1716
+ void swap(shared_lock& other) noexcept {
1717
+ std::swap(mutex_, other.mutex_);
1718
+ std::swap(token_, other.token_);
1719
+ }
1720
+
1721
+ mutex_type* release() noexcept {
1722
+ if (owns_lock()) {
1723
+ mutex_->release_token(token_);
1724
+ token_ = {};
1725
+ }
1726
+ return std::exchange(mutex_, nullptr);
1727
+ }
1728
+
1729
+ FOLLY_NODISCARD bool owns_lock() const noexcept {
1730
+ return static_cast<bool>(token_);
1731
+ }
1732
+
1733
+ explicit operator bool() const noexcept { return owns_lock(); }
1734
+
1735
+ FOLLY_NODISCARD mutex_type* mutex() const noexcept { return mutex_; }
1736
+
1737
+ private:
1738
+ void error_if_not_lockable() const {
1739
+ if (FOLLY_UNLIKELY(mutex_ == nullptr)) {
1740
+ ::folly::shared_mutex_detail::throwOperationNotPermitted();
1741
+ }
1742
+ if (FOLLY_UNLIKELY(owns_lock())) {
1743
+ ::folly::shared_mutex_detail::throwDeadlockWouldOccur();
1744
+ }
1745
+ }
1746
+
1747
+ mutex_type* mutex_ = nullptr;
1748
+ token_type token_;
1749
+ };
1750
+
1751
+ } // namespace std