react-native-windows 0.84.0-preview.9 → 0.84.1

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 (954) hide show
  1. package/Common/unicode.cpp +36 -0
  2. package/Common/unicode.h +8 -0
  3. package/Directory.Build.props +2 -17
  4. package/Folly/ThreadNameStub.cpp +4 -6
  5. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +5 -0
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +91 -23
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +11 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +6 -4
  9. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +28 -6
  10. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +1 -1
  11. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +1 -1
  12. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +80 -0
  13. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.h +17 -0
  14. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp +1 -1
  15. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +4 -9
  16. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -3
  17. package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +33 -25
  18. package/Microsoft.ReactNative/Utils/LocalBundleReader.h +5 -3
  19. package/Microsoft.ReactNative/Utils/UwpScriptStore.cpp +2 -2
  20. package/Microsoft.ReactNative/Utils/UwpScriptStore.h +3 -2
  21. package/Microsoft.ReactNative.Managed/Microsoft.ReactNative.Managed.csproj +3 -3
  22. package/Microsoft.ReactNative.Managed.CodeGen/Microsoft.ReactNative.Managed.CodeGen.csproj +10 -10
  23. package/Microsoft.ReactNative.Managed.CodeGen/Properties/PublishProfiles/DeployAsTool-Debug.pubxml +1 -1
  24. package/Microsoft.ReactNative.Managed.CodeGen/Properties/PublishProfiles/DeployAsTool-Release.pubxml +1 -1
  25. package/PropertySheets/CIBuildOptimizations.props +2 -2
  26. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  27. package/PropertySheets/JSEngine.props +1 -1
  28. package/PropertySheets/NuGet.LockFile.props +10 -1
  29. package/PropertySheets/React.Cpp.props +7 -6
  30. package/PropertySheets/WinUI.props +2 -2
  31. package/ReactCommon/ReactCommon.vcxproj +0 -5
  32. package/Scripts/JustMyXaml.ps1 +8 -8
  33. package/Scripts/NuGetRestoreForceEvaluateAllSolutions.ps1 +61 -6
  34. package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +4 -37
  35. package/Scripts/UnitTest.ps1 +3 -1
  36. package/Scripts/UpdateNightlyDependencies.ps1 +47 -0
  37. package/Scripts/creaternwapp.cmd +5 -8
  38. package/Scripts/creaternwlib.cmd +10 -23
  39. package/Scripts/rnw-dependencies.ps1 +15 -16
  40. package/Shared/DevSupportManager.cpp +55 -48
  41. package/Shared/DevSupportManager.h +0 -1
  42. package/Shared/Modules/IWebSocketModuleContentHandler.h +15 -0
  43. package/Shared/Modules/WebSocketModule.cpp +8 -3
  44. package/Shared/Networking/DefaultBlobResource.cpp +37 -0
  45. package/Shared/Networking/DefaultBlobResource.h +12 -0
  46. package/Shared/Networking/WinRTWebSocketResource.h +5 -1
  47. package/Shared/Shared.vcxitems +2 -0
  48. package/{Folly → external}/.clang-format +0 -1
  49. package/external/External.vcxitems +10 -0
  50. package/external/fast-float/.syncignore +10 -0
  51. package/external/fast-float/LICENSE-APACHE +190 -0
  52. package/external/fast-float/LICENSE-BOOST +23 -0
  53. package/external/fast-float/LICENSE-MIT +27 -0
  54. package/external/fast-float/README.md +545 -0
  55. package/external/fast-float/cgmanifest.json +15 -0
  56. package/external/fast-float/fast-float.vcxitems +14 -0
  57. package/external/fast-float/include/fast_float/ascii_number.h +588 -0
  58. package/external/fast-float/include/fast_float/bigint.h +638 -0
  59. package/external/fast-float/include/fast_float/constexpr_feature_detect.h +46 -0
  60. package/external/fast-float/include/fast_float/decimal_to_binary.h +212 -0
  61. package/external/fast-float/include/fast_float/digit_comparison.h +457 -0
  62. package/external/fast-float/include/fast_float/fast_float.h +59 -0
  63. package/external/fast-float/include/fast_float/fast_table.h +708 -0
  64. package/external/fast-float/include/fast_float/float_common.h +1240 -0
  65. package/external/fast-float/include/fast_float/parse_number.h +399 -0
  66. package/external/fast-float/sync-config.json +8 -0
  67. package/external/fmt/.syncignore +10 -0
  68. package/external/fmt/CONTRIBUTING.md +20 -0
  69. package/external/fmt/LICENSE +27 -0
  70. package/external/fmt/README.md +484 -0
  71. package/external/fmt/doc/ChangeLog-old.md +3290 -0
  72. package/external/fmt/doc/api.md +650 -0
  73. package/external/fmt/doc/fmt.css +61 -0
  74. package/external/fmt/doc/fmt.js +4 -0
  75. package/external/fmt/doc/get-started.md +222 -0
  76. package/external/fmt/doc/index.md +151 -0
  77. package/external/fmt/doc/perf.svg +1 -0
  78. package/external/fmt/doc/python-license.txt +290 -0
  79. package/external/fmt/doc/syntax.md +887 -0
  80. package/external/fmt/fmt.vcxitems +28 -0
  81. package/external/fmt/include/fmt/args.h +228 -0
  82. package/external/fmt/include/fmt/base.h +3077 -0
  83. package/external/fmt/include/fmt/chrono.h +2432 -0
  84. package/external/fmt/include/fmt/color.h +612 -0
  85. package/external/fmt/include/fmt/compile.h +529 -0
  86. package/external/fmt/include/fmt/core.h +5 -0
  87. package/external/fmt/include/fmt/format-inl.h +1928 -0
  88. package/external/fmt/include/fmt/format.h +4427 -0
  89. package/external/fmt/include/fmt/os.h +439 -0
  90. package/external/fmt/include/fmt/ostream.h +211 -0
  91. package/external/fmt/include/fmt/printf.h +656 -0
  92. package/external/fmt/include/fmt/ranges.h +882 -0
  93. package/external/fmt/include/fmt/std.h +699 -0
  94. package/external/fmt/include/fmt/xchar.h +322 -0
  95. package/external/fmt/src/fmt.cc +135 -0
  96. package/external/fmt/src/format.cc +43 -0
  97. package/external/fmt/src/os.cc +403 -0
  98. package/external/fmt/sync-config.json +8 -0
  99. package/external/folly/.syncignore +60 -0
  100. package/external/folly/LICENSE +200 -0
  101. package/external/folly/README.md +263 -0
  102. package/{fmt → external/folly/folly}/.clang-format +0 -1
  103. package/external/folly/folly/AtomicHashArray-inl.h +546 -0
  104. package/external/folly/folly/AtomicHashArray.h +431 -0
  105. package/external/folly/folly/AtomicHashMap-inl.h +653 -0
  106. package/external/folly/folly/AtomicHashMap.h +484 -0
  107. package/external/folly/folly/AtomicIntrusiveLinkedList.h +206 -0
  108. package/external/folly/folly/AtomicLinkedList.h +110 -0
  109. package/external/folly/folly/AtomicUnorderedMap.h +522 -0
  110. package/external/folly/folly/BUCK +1631 -0
  111. package/external/folly/folly/BUILD_MODE.bzl +72 -0
  112. package/external/folly/folly/Benchmark.cpp +986 -0
  113. package/external/folly/folly/Benchmark.h +680 -0
  114. package/external/folly/folly/BenchmarkUtil.h +47 -0
  115. package/external/folly/folly/Bits.h +17 -0
  116. package/external/folly/folly/CMakeLists.txt +110 -0
  117. package/external/folly/folly/CPortability.h +338 -0
  118. package/external/folly/folly/CancellationToken-inl.h +449 -0
  119. package/external/folly/folly/CancellationToken.cpp +250 -0
  120. package/external/folly/folly/CancellationToken.h +365 -0
  121. package/external/folly/folly/Chrono.h +132 -0
  122. package/external/folly/folly/ClockGettimeWrappers.cpp +93 -0
  123. package/external/folly/folly/ClockGettimeWrappers.h +29 -0
  124. package/external/folly/folly/ConcurrentBitSet.h +157 -0
  125. package/external/folly/folly/ConcurrentLazy.h +74 -0
  126. package/external/folly/folly/ConcurrentSkipList-inl.h +341 -0
  127. package/external/folly/folly/ConcurrentSkipList.h +824 -0
  128. package/external/folly/folly/ConstructorCallbackList.h +158 -0
  129. package/external/folly/folly/Conv.h +2026 -0
  130. package/external/folly/folly/CppAttributes.h +170 -0
  131. package/external/folly/folly/CpuId.h +297 -0
  132. package/external/folly/folly/DefaultKeepAliveExecutor.h +172 -0
  133. package/external/folly/folly/Demangle.cpp +255 -0
  134. package/external/folly/folly/Demangle.h +73 -0
  135. package/external/folly/folly/DiscriminatedPtr.h +236 -0
  136. package/external/folly/folly/DynamicConverter.h +17 -0
  137. package/external/folly/folly/Exception.h +150 -0
  138. package/external/folly/folly/ExceptionString.cpp +51 -0
  139. package/external/folly/folly/ExceptionString.h +33 -0
  140. package/external/folly/folly/ExceptionWrapper-inl.h +264 -0
  141. package/external/folly/folly/ExceptionWrapper.cpp +37 -0
  142. package/external/folly/folly/ExceptionWrapper.h +377 -0
  143. package/external/folly/folly/Executor.cpp +111 -0
  144. package/external/folly/folly/Executor.h +351 -0
  145. package/external/folly/folly/Expected.h +1725 -0
  146. package/external/folly/folly/FBString.h +2888 -0
  147. package/external/folly/folly/FBVector.h +17 -0
  148. package/external/folly/folly/File.cpp +180 -0
  149. package/external/folly/folly/File.h +177 -0
  150. package/external/folly/folly/FileUtil.cpp +378 -0
  151. package/external/folly/folly/FileUtil.h +332 -0
  152. package/external/folly/folly/Fingerprint.cpp +135 -0
  153. package/external/folly/folly/Fingerprint.h +289 -0
  154. package/external/folly/folly/FixedString.h +2965 -0
  155. package/external/folly/folly/FollyMemcpy.cpp +30 -0
  156. package/external/folly/folly/FollyMemcpy.h +23 -0
  157. package/external/folly/folly/FollyMemset.cpp +29 -0
  158. package/external/folly/folly/FollyMemset.h +25 -0
  159. package/external/folly/folly/Format-inl.h +1152 -0
  160. package/external/folly/folly/Format.cpp +429 -0
  161. package/external/folly/folly/Format.h +463 -0
  162. package/external/folly/folly/FormatArg.h +285 -0
  163. package/external/folly/folly/FormatTraits.h +65 -0
  164. package/external/folly/folly/Function.h +1159 -0
  165. package/external/folly/folly/GLog.h +85 -0
  166. package/external/folly/folly/GroupVarint.cpp +153 -0
  167. package/external/folly/folly/GroupVarint.h +630 -0
  168. package/external/folly/folly/Hash.h +20 -0
  169. package/external/folly/folly/IPAddress.cpp +490 -0
  170. package/external/folly/folly/IPAddress.h +667 -0
  171. package/external/folly/folly/IPAddressException.h +82 -0
  172. package/external/folly/folly/IPAddressV4.cpp +305 -0
  173. package/external/folly/folly/IPAddressV4.h +495 -0
  174. package/external/folly/folly/IPAddressV6.cpp +541 -0
  175. package/external/folly/folly/IPAddressV6.h +627 -0
  176. package/external/folly/folly/Indestructible.h +164 -0
  177. package/external/folly/folly/IndexedMemPool.h +550 -0
  178. package/external/folly/folly/IntrusiveList.h +17 -0
  179. package/external/folly/folly/Lazy.h +142 -0
  180. package/external/folly/folly/Likely.h +76 -0
  181. package/external/folly/folly/MPMCPipeline.h +280 -0
  182. package/external/folly/folly/MPMCQueue.h +1556 -0
  183. package/external/folly/folly/MacAddress.cpp +188 -0
  184. package/external/folly/folly/MacAddress.h +260 -0
  185. package/external/folly/folly/MapUtil.h +17 -0
  186. package/external/folly/folly/Math.h +258 -0
  187. package/external/folly/folly/MaybeManagedPtr.h +120 -0
  188. package/external/folly/folly/Memory.h +900 -0
  189. package/external/folly/folly/MicroLock.cpp +76 -0
  190. package/external/folly/folly/MicroLock.h +354 -0
  191. package/external/folly/folly/MicroSpinLock.h +17 -0
  192. package/external/folly/folly/MoveWrapper.h +76 -0
  193. package/external/folly/folly/ObserverContainer.h +1026 -0
  194. package/external/folly/folly/Optional.h +743 -0
  195. package/external/folly/folly/Overload.h +325 -0
  196. package/external/folly/folly/PackedSyncPtr.h +147 -0
  197. package/external/folly/folly/Padded.h +464 -0
  198. package/external/folly/folly/Poly-inl.h +230 -0
  199. package/external/folly/folly/Poly.h +1095 -0
  200. package/external/folly/folly/PolyException.h +43 -0
  201. package/external/folly/folly/Portability.h +644 -0
  202. package/external/folly/folly/Preprocessor.h +236 -0
  203. package/external/folly/folly/ProducerConsumerQueue.h +182 -0
  204. package/external/folly/folly/RWSpinLock.h +17 -0
  205. package/external/folly/folly/Random-inl.h +86 -0
  206. package/external/folly/folly/Random.cpp +184 -0
  207. package/external/folly/folly/Random.h +434 -0
  208. package/external/folly/folly/Range.h +1772 -0
  209. package/external/folly/folly/Replaceable.h +636 -0
  210. package/external/folly/folly/ScopeGuard.cpp +29 -0
  211. package/external/folly/folly/ScopeGuard.h +420 -0
  212. package/external/folly/folly/SharedMutex.cpp +81 -0
  213. package/external/folly/folly/SharedMutex.h +1751 -0
  214. package/external/folly/folly/Singleton-inl.h +332 -0
  215. package/external/folly/folly/Singleton.cpp +512 -0
  216. package/external/folly/folly/Singleton.h +891 -0
  217. package/external/folly/folly/SingletonThreadLocal.cpp +53 -0
  218. package/external/folly/folly/SingletonThreadLocal.h +263 -0
  219. package/external/folly/folly/SocketAddress.cpp +786 -0
  220. package/external/folly/folly/SocketAddress.h +768 -0
  221. package/external/folly/folly/SpinLock.h +55 -0
  222. package/external/folly/folly/String-inl.h +668 -0
  223. package/external/folly/folly/String.cpp +777 -0
  224. package/external/folly/folly/String.h +767 -0
  225. package/external/folly/folly/Subprocess.cpp +1142 -0
  226. package/external/folly/folly/Subprocess.h +1055 -0
  227. package/external/folly/folly/Synchronized.h +1833 -0
  228. package/external/folly/folly/SynchronizedPtr.h +106 -0
  229. package/external/folly/folly/ThreadCachedInt.h +175 -0
  230. package/external/folly/folly/ThreadLocal.h +478 -0
  231. package/external/folly/folly/TimeoutQueue.cpp +78 -0
  232. package/external/folly/folly/TimeoutQueue.h +123 -0
  233. package/external/folly/folly/TokenBucket.h +673 -0
  234. package/external/folly/folly/Traits.h +1442 -0
  235. package/external/folly/folly/Try-inl.h +372 -0
  236. package/external/folly/folly/Try.cpp +23 -0
  237. package/external/folly/folly/Try.h +728 -0
  238. package/external/folly/folly/UTF8String.h +56 -0
  239. package/external/folly/folly/Unicode.cpp +201 -0
  240. package/external/folly/folly/Unicode.h +94 -0
  241. package/external/folly/folly/Unit.h +65 -0
  242. package/external/folly/folly/Uri-inl.h +101 -0
  243. package/external/folly/folly/Uri.cpp +190 -0
  244. package/external/folly/folly/Uri.h +142 -0
  245. package/external/folly/folly/Utility.h +932 -0
  246. package/external/folly/folly/VERSION +1 -0
  247. package/external/folly/folly/Varint.h +230 -0
  248. package/external/folly/folly/VirtualExecutor.h +17 -0
  249. package/external/folly/folly/algorithm/simd/BUCK +47 -0
  250. package/external/folly/folly/algorithm/simd/Contains.cpp +42 -0
  251. package/external/folly/folly/algorithm/simd/Contains.h +116 -0
  252. package/external/folly/folly/algorithm/simd/FindFixed.h +301 -0
  253. package/external/folly/folly/algorithm/simd/Ignore.h +52 -0
  254. package/external/folly/folly/algorithm/simd/Movemask.h +207 -0
  255. package/external/folly/folly/algorithm/simd/detail/BUCK +70 -0
  256. package/external/folly/folly/algorithm/simd/detail/ContainsImpl.h +91 -0
  257. package/external/folly/folly/algorithm/simd/detail/SimdAnyOf.h +83 -0
  258. package/external/folly/folly/algorithm/simd/detail/SimdForEach.h +209 -0
  259. package/external/folly/folly/algorithm/simd/detail/SimdPlatform.h +445 -0
  260. package/external/folly/folly/algorithm/simd/detail/Traits.h +125 -0
  261. package/external/folly/folly/algorithm/simd/detail/UnrollUtils.h +126 -0
  262. package/external/folly/folly/base64.h +264 -0
  263. package/external/folly/folly/chrono/BUCK +29 -0
  264. package/external/folly/folly/chrono/Clock.h +65 -0
  265. package/external/folly/folly/chrono/Conv.h +712 -0
  266. package/external/folly/folly/chrono/test/BUCK +26 -0
  267. package/external/folly/folly/chrono/test/ClockTest.cpp +68 -0
  268. package/external/folly/folly/chrono/test/ConvTest.cpp +652 -0
  269. package/external/folly/folly/concurrency/AtomicSharedPtr.h +387 -0
  270. package/external/folly/folly/concurrency/BUCK +170 -0
  271. package/external/folly/folly/concurrency/CacheLocality.h +460 -0
  272. package/external/folly/folly/concurrency/ConcurrentHashMap.h +822 -0
  273. package/external/folly/folly/concurrency/CoreCachedSharedPtr.h +232 -0
  274. package/external/folly/folly/concurrency/DeadlockDetector.cpp +27 -0
  275. package/external/folly/folly/concurrency/DeadlockDetector.h +44 -0
  276. package/external/folly/folly/concurrency/DynamicBoundedQueue.h +751 -0
  277. package/external/folly/folly/concurrency/PriorityUnboundedQueueSet.h +207 -0
  278. package/external/folly/folly/concurrency/ProcessLocalUniqueId.cpp +46 -0
  279. package/external/folly/folly/concurrency/ProcessLocalUniqueId.h +38 -0
  280. package/external/folly/folly/concurrency/SingletonRelaxedCounter.h +325 -0
  281. package/external/folly/folly/concurrency/ThreadCachedSynchronized.h +227 -0
  282. package/external/folly/folly/concurrency/UnboundedQueue.h +891 -0
  283. package/external/folly/folly/concurrency/container/BUCK +77 -0
  284. package/external/folly/folly/concurrency/container/FlatCombiningPriorityQueue.h +426 -0
  285. package/external/folly/folly/concurrency/container/LockFreeRingBuffer.h +306 -0
  286. package/external/folly/folly/concurrency/container/RelaxedConcurrentPriorityQueue.h +1212 -0
  287. package/external/folly/folly/concurrency/container/SingleWriterFixedHashMap.h +322 -0
  288. package/external/folly/folly/concurrency/container/atomic_grow_array.h +564 -0
  289. package/external/folly/folly/concurrency/container/test/BUCK +75 -0
  290. package/external/folly/folly/concurrency/container/test/FlatCombiningPriorityQueueTest.cpp +570 -0
  291. package/external/folly/folly/concurrency/container/test/LockFreeRingBufferTest.cpp +276 -0
  292. package/external/folly/folly/concurrency/container/test/RelaxedConcurrentPriorityQueueTest.cpp +1570 -0
  293. package/external/folly/folly/concurrency/container/test/SingleWriterFixedHashMapTest.cpp +401 -0
  294. package/external/folly/folly/concurrency/container/test/atomic_grow_array_test.cpp +187 -0
  295. package/external/folly/folly/concurrency/detail/AtomicSharedPtr-detail.h +212 -0
  296. package/external/folly/folly/concurrency/detail/ConcurrentHashMap-detail.h +1911 -0
  297. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.cpp +43 -0
  298. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.h +190 -0
  299. package/external/folly/folly/concurrency/memory/BUCK +53 -0
  300. package/external/folly/folly/concurrency/memory/PrimaryPtr.h +338 -0
  301. package/external/folly/folly/concurrency/memory/ReadMostlySharedPtr.h +511 -0
  302. package/external/folly/folly/concurrency/memory/TLRefCount.h +228 -0
  303. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrBenchmark.cpp +56 -0
  304. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrTest.cpp +454 -0
  305. package/external/folly/folly/concurrency/memory/test/BUCK +95 -0
  306. package/external/folly/folly/concurrency/memory/test/PrimaryPtrTest.cpp +303 -0
  307. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrBenchmark.cpp +138 -0
  308. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrStressTest.cpp +75 -0
  309. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrTest.cpp +378 -0
  310. package/external/folly/folly/concurrency/memory/test/RefCountBenchmark.cpp +90 -0
  311. package/external/folly/folly/concurrency/memory/test/RefCountTest.cpp +168 -0
  312. package/external/folly/folly/concurrency/test/AtomicSharedPtrCounted.h +156 -0
  313. package/external/folly/folly/concurrency/test/AtomicSharedPtrPerformance.cpp +255 -0
  314. package/external/folly/folly/concurrency/test/AtomicSharedPtrTest.cpp +257 -0
  315. package/external/folly/folly/concurrency/test/BUCK +229 -0
  316. package/external/folly/folly/concurrency/test/CacheLocalityBenchmark.cpp +392 -0
  317. package/external/folly/folly/concurrency/test/CacheLocalityTest.cpp +1229 -0
  318. package/external/folly/folly/concurrency/test/ConcurrentHashMapBench.cpp +260 -0
  319. package/external/folly/folly/concurrency/test/ConcurrentHashMapTest.cpp +1242 -0
  320. package/external/folly/folly/concurrency/test/CoreCachedSharedPtrTest.cpp +408 -0
  321. package/external/folly/folly/concurrency/test/DynamicBoundedQueueTest.cpp +984 -0
  322. package/external/folly/folly/concurrency/test/PriorityUnboundedQueueSetTest.cpp +73 -0
  323. package/external/folly/folly/concurrency/test/ProcessLocalUniqueIdTest.cpp +66 -0
  324. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterBench.cpp +101 -0
  325. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterTest.cpp +185 -0
  326. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedBench.cpp +76 -0
  327. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedTest.cpp +93 -0
  328. package/external/folly/folly/concurrency/test/UnboundedQueueTest.cpp +1302 -0
  329. package/external/folly/folly/container/Access.h +57 -0
  330. package/external/folly/folly/container/Array.h +87 -0
  331. package/external/folly/folly/container/BUCK +353 -0
  332. package/external/folly/folly/container/BitIterator.h +203 -0
  333. package/external/folly/folly/container/Enumerate.h +162 -0
  334. package/external/folly/folly/container/EvictingCacheMap.h +730 -0
  335. package/external/folly/folly/container/F14.md +300 -0
  336. package/external/folly/folly/container/F14Map-fwd.h +113 -0
  337. package/external/folly/folly/container/F14Map.h +2108 -0
  338. package/external/folly/folly/container/F14Set-fwd.h +95 -0
  339. package/external/folly/folly/container/F14Set.h +1603 -0
  340. package/external/folly/folly/container/FBVector.h +1711 -0
  341. package/external/folly/folly/container/Foreach-inl.h +316 -0
  342. package/external/folly/folly/container/Foreach.h +209 -0
  343. package/external/folly/folly/container/HeterogeneousAccess-fwd.h +33 -0
  344. package/external/folly/folly/container/HeterogeneousAccess.h +171 -0
  345. package/external/folly/folly/container/IntrusiveHeap.h +268 -0
  346. package/external/folly/folly/container/IntrusiveList.h +131 -0
  347. package/external/folly/folly/container/Iterator.h +843 -0
  348. package/external/folly/folly/container/MapUtil.h +376 -0
  349. package/external/folly/folly/container/Merge.h +90 -0
  350. package/external/folly/folly/container/RegexMatchCache.cpp +521 -0
  351. package/external/folly/folly/container/RegexMatchCache.h +699 -0
  352. package/external/folly/folly/container/Reserve.h +109 -0
  353. package/external/folly/folly/container/SparseByteSet.h +123 -0
  354. package/external/folly/folly/container/View.h +81 -0
  355. package/external/folly/folly/container/WeightedEvictingCacheMap.h +651 -0
  356. package/external/folly/folly/container/detail/BUCK +115 -0
  357. package/external/folly/folly/container/detail/BitIteratorDetail.h +87 -0
  358. package/external/folly/folly/container/detail/F14Defaults.h +34 -0
  359. package/external/folly/folly/container/detail/F14IntrinsicsAvailability.h +67 -0
  360. package/external/folly/folly/container/detail/F14MapFallback.h +717 -0
  361. package/external/folly/folly/container/detail/F14Mask.h +235 -0
  362. package/external/folly/folly/container/detail/F14Policy.h +1523 -0
  363. package/external/folly/folly/container/detail/F14SetFallback.h +528 -0
  364. package/external/folly/folly/container/detail/F14Table.cpp +71 -0
  365. package/external/folly/folly/container/detail/F14Table.h +2680 -0
  366. package/external/folly/folly/container/detail/Util.h +303 -0
  367. package/external/folly/folly/container/detail/tape_detail.h +135 -0
  368. package/external/folly/folly/container/detail/test/BUCK +14 -0
  369. package/external/folly/folly/container/detail/test/F14DetailTest.cpp +47 -0
  370. package/external/folly/folly/container/heap_vector_types.h +1683 -0
  371. package/external/folly/folly/container/range_traits.h +81 -0
  372. package/external/folly/folly/container/small_vector.h +1476 -0
  373. package/external/folly/folly/container/sorted_vector_types.h +1652 -0
  374. package/external/folly/folly/container/span.h +408 -0
  375. package/external/folly/folly/container/tape.h +608 -0
  376. package/external/folly/folly/container/test/.clang-tidy +12 -0
  377. package/external/folly/folly/container/test/AccessTest.cpp +138 -0
  378. package/external/folly/folly/container/test/ArrayTest.cpp +84 -0
  379. package/external/folly/folly/container/test/BUCK +568 -0
  380. package/external/folly/folly/container/test/BitIteratorBench.cpp +112 -0
  381. package/external/folly/folly/container/test/BitIteratorTest.cpp +109 -0
  382. package/external/folly/folly/container/test/EnumerateTest.cpp +294 -0
  383. package/external/folly/folly/container/test/EvictingCacheMapBench.cpp +80 -0
  384. package/external/folly/folly/container/test/EvictingCacheMapTest.cpp +842 -0
  385. package/external/folly/folly/container/test/F14AsanSupportTest.cpp +143 -0
  386. package/external/folly/folly/container/test/F14FwdTest.cpp +37 -0
  387. package/external/folly/folly/container/test/F14InterprocessTest.cpp +404 -0
  388. package/external/folly/folly/container/test/F14MapTest.cpp +2543 -0
  389. package/external/folly/folly/container/test/F14PolicyTest.cpp +49 -0
  390. package/external/folly/folly/container/test/F14SetTest.cpp +1738 -0
  391. package/external/folly/folly/container/test/F14SmallOverheads.cpp +215 -0
  392. package/external/folly/folly/container/test/F14TestUtil.h +117 -0
  393. package/external/folly/folly/container/test/FBVectorBenchmark.cpp +380 -0
  394. package/external/folly/folly/container/test/FBVectorBenchmarks.cpp.h +100 -0
  395. package/external/folly/folly/container/test/FBVectorTest.cpp +326 -0
  396. package/external/folly/folly/container/test/FBVectorTests.cpp.h +304 -0
  397. package/external/folly/folly/container/test/ForeachBenchmark.cpp +388 -0
  398. package/external/folly/folly/container/test/ForeachTest.cpp +338 -0
  399. package/external/folly/folly/container/test/HashMapsBench.cpp +458 -0
  400. package/external/folly/folly/container/test/HeterogeneousAccessTest.cpp +242 -0
  401. package/external/folly/folly/container/test/IntrusiveHeapTest.cpp +262 -0
  402. package/external/folly/folly/container/test/IteratorTest.cpp +989 -0
  403. package/external/folly/folly/container/test/MapUtilTest.cpp +365 -0
  404. package/external/folly/folly/container/test/MergeTest.cpp +66 -0
  405. package/external/folly/folly/container/test/RegexMatchCacheTest.cpp +634 -0
  406. package/external/folly/folly/container/test/ReserveTest.cpp +173 -0
  407. package/external/folly/folly/container/test/SparseByteSetBenchmark.cpp +153 -0
  408. package/external/folly/folly/container/test/SparseByteSetTest.cpp +117 -0
  409. package/external/folly/folly/container/test/TrackingTypes.h +584 -0
  410. package/external/folly/folly/container/test/UtilTest.cpp +609 -0
  411. package/external/folly/folly/container/test/WeightedEvictingCacheMapTest.cpp +800 -0
  412. package/external/folly/folly/container/test/heap_vector_types_test.cpp +1774 -0
  413. package/external/folly/folly/container/test/range_traits_test.cpp +59 -0
  414. package/external/folly/folly/container/test/small_vector_test.cpp +1571 -0
  415. package/external/folly/folly/container/test/sorted_vector_test.cpp +1589 -0
  416. package/external/folly/folly/container/test/span_test.cpp +520 -0
  417. package/external/folly/folly/container/test/tape_bench.cpp +200 -0
  418. package/external/folly/folly/container/test/tape_test.cpp +590 -0
  419. package/external/folly/folly/defs.bzl +238 -0
  420. package/external/folly/folly/detail/AsyncTrace.cpp +36 -0
  421. package/external/folly/folly/detail/AsyncTrace.h +44 -0
  422. package/external/folly/folly/detail/AtomicHashUtils.h +42 -0
  423. package/external/folly/folly/detail/AtomicUnorderedMapUtils.h +80 -0
  424. package/external/folly/folly/detail/BUCK +406 -0
  425. package/external/folly/folly/detail/DiscriminatedPtrDetail.h +172 -0
  426. package/external/folly/folly/detail/FileUtilDetail.cpp +63 -0
  427. package/external/folly/folly/detail/FileUtilDetail.h +85 -0
  428. package/external/folly/folly/detail/FileUtilVectorDetail.h +81 -0
  429. package/external/folly/folly/detail/FingerprintPolynomial.h +132 -0
  430. package/external/folly/folly/detail/Futex-inl.h +123 -0
  431. package/external/folly/folly/detail/Futex.cpp +273 -0
  432. package/external/folly/folly/detail/Futex.h +109 -0
  433. package/external/folly/folly/detail/GroupVarintDetail.h +101 -0
  434. package/external/folly/folly/detail/IPAddress.cpp +37 -0
  435. package/external/folly/folly/detail/IPAddress.h +57 -0
  436. package/external/folly/folly/detail/IPAddressSource.h +278 -0
  437. package/external/folly/folly/detail/Iterators.h +156 -0
  438. package/external/folly/folly/detail/MPMCPipelineDetail.h +122 -0
  439. package/external/folly/folly/detail/MemoryIdler.cpp +233 -0
  440. package/external/folly/folly/detail/MemoryIdler.h +216 -0
  441. package/external/folly/folly/detail/PerfScoped.cpp +112 -0
  442. package/external/folly/folly/detail/PerfScoped.h +70 -0
  443. package/external/folly/folly/detail/PolyDetail.h +921 -0
  444. package/external/folly/folly/detail/RangeCommon.cpp +55 -0
  445. package/external/folly/folly/detail/RangeCommon.h +93 -0
  446. package/external/folly/folly/detail/RangeSse42.cpp +198 -0
  447. package/external/folly/folly/detail/RangeSse42.h +30 -0
  448. package/external/folly/folly/detail/SimpleSimdStringUtils.cpp +31 -0
  449. package/external/folly/folly/detail/SimpleSimdStringUtils.h +27 -0
  450. package/external/folly/folly/detail/SimpleSimdStringUtilsImpl.h +63 -0
  451. package/external/folly/folly/detail/Singleton.h +34 -0
  452. package/external/folly/folly/detail/SlowFingerprint.h +90 -0
  453. package/external/folly/folly/detail/SocketFastOpen.cpp +175 -0
  454. package/external/folly/folly/detail/SocketFastOpen.h +89 -0
  455. package/external/folly/folly/detail/SplitStringSimd.cpp +84 -0
  456. package/external/folly/folly/detail/SplitStringSimd.h +151 -0
  457. package/external/folly/folly/detail/SplitStringSimdImpl.h +149 -0
  458. package/external/folly/folly/detail/Sse.cpp +35 -0
  459. package/external/folly/folly/detail/Sse.h +45 -0
  460. package/external/folly/folly/detail/StaticSingletonManager.cpp +119 -0
  461. package/external/folly/folly/detail/StaticSingletonManager.h +298 -0
  462. package/external/folly/folly/detail/ThreadLocalDetail.cpp +492 -0
  463. package/external/folly/folly/detail/ThreadLocalDetail.h +800 -0
  464. package/external/folly/folly/detail/TrapOnAvx512.cpp +41 -0
  465. package/external/folly/folly/detail/TrapOnAvx512.h +21 -0
  466. package/external/folly/folly/detail/TurnSequencer.h +295 -0
  467. package/external/folly/folly/detail/TypeList.h +551 -0
  468. package/external/folly/folly/detail/UniqueInstance.cpp +136 -0
  469. package/external/folly/folly/detail/UniqueInstance.h +68 -0
  470. package/external/folly/folly/detail/base64_detail/BUCK +102 -0
  471. package/external/folly/folly/detail/base64_detail/Base64Api.cpp +40 -0
  472. package/external/folly/folly/detail/base64_detail/Base64Api.h +101 -0
  473. package/external/folly/folly/detail/base64_detail/Base64Common.h +80 -0
  474. package/external/folly/folly/detail/base64_detail/Base64Constants.h +79 -0
  475. package/external/folly/folly/detail/base64_detail/Base64HiddenConstants.h +129 -0
  476. package/external/folly/folly/detail/base64_detail/Base64SWAR.cpp +161 -0
  477. package/external/folly/folly/detail/base64_detail/Base64SWAR.h +32 -0
  478. package/external/folly/folly/detail/base64_detail/Base64Scalar.h +262 -0
  479. package/external/folly/folly/detail/base64_detail/Base64Simd.h +102 -0
  480. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.cpp +42 -0
  481. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.h +33 -0
  482. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2_Platform.h +167 -0
  483. package/external/folly/folly/detail/base64_detail/README.md +392 -0
  484. package/external/folly/folly/detail/base64_detail/tests/BUCK +36 -0
  485. package/external/folly/folly/detail/base64_detail/tests/Base64AgainstScalarTest.cpp +141 -0
  486. package/external/folly/folly/detail/base64_detail/tests/Base64PlatformTest.cpp +273 -0
  487. package/external/folly/folly/detail/base64_detail/tests/Base64SpecialCasesTest.cpp +555 -0
  488. package/external/folly/folly/detail/test/AsyncTraceTest.cpp +43 -0
  489. package/external/folly/folly/detail/test/BUCK +118 -0
  490. package/external/folly/folly/detail/test/FileUtilDetailTest.cpp +56 -0
  491. package/external/folly/folly/detail/test/PerfScopedTest.cpp +107 -0
  492. package/external/folly/folly/detail/test/SimpleSimdStringUtilsTest.cpp +92 -0
  493. package/external/folly/folly/detail/test/SplitStringSimdTest.cpp +242 -0
  494. package/external/folly/folly/detail/test/StaticSingletonManagerTest.cpp +121 -0
  495. package/external/folly/folly/detail/test/ThreadLocalBenchmark.cpp +116 -0
  496. package/external/folly/folly/detail/test/ThreadLocalDetailTest.cpp +194 -0
  497. package/external/folly/folly/detail/test/TrapOnAvx512TestNegative.cpp +29 -0
  498. package/external/folly/folly/detail/test/UniqueInstanceTest.cpp +60 -0
  499. package/external/folly/folly/detail/thread_local_globals.cpp +69 -0
  500. package/external/folly/folly/detail/thread_local_globals.h +36 -0
  501. package/external/folly/folly/docs/AtomicHashMap.md +134 -0
  502. package/external/folly/folly/docs/Benchmark.md +310 -0
  503. package/external/folly/folly/docs/Conv.md +291 -0
  504. package/external/folly/folly/docs/Dynamic.md +220 -0
  505. package/external/folly/folly/docs/DynamicConverter.md +71 -0
  506. package/external/folly/folly/docs/Executors.md +63 -0
  507. package/external/folly/folly/docs/FBString.md +46 -0
  508. package/external/folly/folly/docs/FBVector.md +200 -0
  509. package/external/folly/folly/docs/Fbvector--graphical_solutions.png +0 -0
  510. package/external/folly/folly/docs/Format.md +177 -0
  511. package/external/folly/folly/docs/Function.md +92 -0
  512. package/external/folly/folly/docs/Futures.md +263 -0
  513. package/external/folly/folly/docs/GroupVarint.md +46 -0
  514. package/external/folly/folly/docs/Histogram.md +104 -0
  515. package/external/folly/folly/docs/MapUtils.md +80 -0
  516. package/external/folly/folly/docs/Overview.md +263 -0
  517. package/external/folly/folly/docs/PackedSyncPtr.md +77 -0
  518. package/external/folly/folly/docs/Poly.md +500 -0
  519. package/external/folly/folly/docs/ProducerConsumerQueue.md +82 -0
  520. package/external/folly/folly/docs/Rcu.md +218 -0
  521. package/external/folly/folly/docs/SmallLocks.md +24 -0
  522. package/external/folly/folly/docs/Synchronized.md +793 -0
  523. package/external/folly/folly/docs/ThreadCachedInt.md +98 -0
  524. package/external/folly/folly/docs/ThreadLocal.md +105 -0
  525. package/external/folly/folly/docs/Traits.md +161 -0
  526. package/external/folly/folly/docs/small_vector.md +64 -0
  527. package/external/folly/folly/docs/style.css +23 -0
  528. package/external/folly/folly/dynamic-inl.h +17 -0
  529. package/external/folly/folly/dynamic.h +17 -0
  530. package/external/folly/folly/folly_extended_library.bzl +28 -0
  531. package/external/folly/folly/functional/ApplyTuple.h +204 -0
  532. package/external/folly/folly/functional/BUCK +57 -0
  533. package/external/folly/folly/functional/Invoke.h +880 -0
  534. package/external/folly/folly/functional/Partial.h +130 -0
  535. package/external/folly/folly/functional/protocol.h +203 -0
  536. package/external/folly/folly/functional/test/ApplyTupleTest.cpp +549 -0
  537. package/external/folly/folly/functional/test/BUCK +57 -0
  538. package/external/folly/folly/functional/test/InvokeTest.cpp +483 -0
  539. package/external/folly/folly/functional/test/PartialTest.cpp +141 -0
  540. package/external/folly/folly/functional/test/protocol_test.cpp +177 -0
  541. package/external/folly/folly/functional/test/traits_test.cpp +551 -0
  542. package/external/folly/folly/functional/traits.h +675 -0
  543. package/external/folly/folly/hash/BUCK +86 -0
  544. package/external/folly/folly/hash/Checksum.cpp +275 -0
  545. package/external/folly/folly/hash/Checksum.h +94 -0
  546. package/external/folly/folly/hash/FarmHash.h +46 -0
  547. package/external/folly/folly/hash/Hash.h +1045 -0
  548. package/external/folly/folly/hash/MurmurHash.h +86 -0
  549. package/external/folly/folly/hash/SpookyHashV1.cpp +391 -0
  550. package/external/folly/folly/hash/SpookyHashV1.h +307 -0
  551. package/external/folly/folly/hash/SpookyHashV2.cpp +392 -0
  552. package/external/folly/folly/hash/SpookyHashV2.h +339 -0
  553. package/external/folly/folly/hash/detail/BUCK +26 -0
  554. package/external/folly/folly/hash/detail/ChecksumDetail.cpp +296 -0
  555. package/external/folly/folly/hash/detail/ChecksumDetail.h +137 -0
  556. package/external/folly/folly/hash/detail/Crc32CombineDetail.cpp +191 -0
  557. package/external/folly/folly/hash/detail/Crc32cDetail.cpp +303 -0
  558. package/external/folly/folly/hash/test/BUCK +132 -0
  559. package/external/folly/folly/hash/test/ChecksumBenchmark.cpp +91 -0
  560. package/external/folly/folly/hash/test/ChecksumTest.cpp +587 -0
  561. package/external/folly/folly/hash/test/FarmHashTest.cpp +41 -0
  562. package/external/folly/folly/hash/test/HashBenchmark.cpp +238 -0
  563. package/external/folly/folly/hash/test/HashTest.cpp +997 -0
  564. package/external/folly/folly/hash/test/MurmurHashTest.cpp +76 -0
  565. package/external/folly/folly/hash/test/SpookyHashV1Test.cpp +559 -0
  566. package/external/folly/folly/hash/test/SpookyHashV2Test.cpp +549 -0
  567. package/external/folly/folly/hash/test/traits_test.cpp +69 -0
  568. package/external/folly/folly/hash/traits.h +115 -0
  569. package/external/folly/folly/json/BUCK +155 -0
  570. package/external/folly/folly/json/DynamicConverter.h +464 -0
  571. package/external/folly/folly/json/DynamicParser-inl.h +316 -0
  572. package/external/folly/folly/json/DynamicParser.cpp +198 -0
  573. package/external/folly/folly/json/DynamicParser.h +394 -0
  574. package/external/folly/folly/json/JSONSchema.cpp +1030 -0
  575. package/external/folly/folly/json/JSONSchema.h +73 -0
  576. package/external/folly/folly/json/JsonMockUtil.h +73 -0
  577. package/external/folly/folly/json/JsonTestUtil.cpp +167 -0
  578. package/external/folly/folly/json/JsonTestUtil.h +88 -0
  579. package/external/folly/folly/json/bser/BUCK +24 -0
  580. package/external/folly/folly/json/bser/Bser.h +107 -0
  581. package/external/folly/folly/json/bser/Dump.cpp +253 -0
  582. package/external/folly/folly/json/bser/Load.cpp +246 -0
  583. package/external/folly/folly/json/bser/test/BUCK +14 -0
  584. package/external/folly/folly/json/bser/test/BserTest.cpp +149 -0
  585. package/external/folly/folly/json/dynamic.cpp +552 -0
  586. package/external/folly/folly/json/dynamic.h +1346 -0
  587. package/external/folly/folly/json/json.h +238 -0
  588. package/external/folly/folly/json/json_patch.cpp +325 -0
  589. package/external/folly/folly/json/json_patch.h +126 -0
  590. package/external/folly/folly/json/json_pointer.cpp +114 -0
  591. package/external/folly/folly/json/json_pointer.h +87 -0
  592. package/external/folly/folly/json/test/BUCK +147 -0
  593. package/external/folly/folly/json/test/DynamicBenchmark.cpp +146 -0
  594. package/external/folly/folly/json/test/DynamicConverterTest.cpp +518 -0
  595. package/external/folly/folly/json/test/DynamicOtherTest.cpp +344 -0
  596. package/external/folly/folly/json/test/DynamicParserTest.cpp +443 -0
  597. package/external/folly/folly/json/test/DynamicTest.cpp +1647 -0
  598. package/external/folly/folly/json/test/JSONSchemaTest.cpp +450 -0
  599. package/external/folly/folly/json/test/JsonBenchmark.cpp +264 -0
  600. package/external/folly/folly/json/test/JsonOtherTest.cpp +51 -0
  601. package/external/folly/folly/json/test/JsonTest.cpp +1153 -0
  602. package/external/folly/folly/json/test/JsonTestUtilTest.cpp +97 -0
  603. package/external/folly/folly/json/test/json_patch_test.cpp +361 -0
  604. package/external/folly/folly/json/test/json_pointer_test.cpp +58 -0
  605. package/external/folly/folly/json/tool/BUCK +13 -0
  606. package/external/folly/folly/json/tool/JSONSchemaTester.cpp +58 -0
  607. package/external/folly/folly/json.h +17 -0
  608. package/external/folly/folly/json_patch.h +17 -0
  609. package/external/folly/folly/json_pointer.h +17 -0
  610. package/external/folly/folly/lang/Access.h +29 -0
  611. package/external/folly/folly/lang/Align.h +240 -0
  612. package/external/folly/folly/lang/Aligned.h +92 -0
  613. package/external/folly/folly/lang/Assume.h +82 -0
  614. package/external/folly/folly/lang/BUCK +287 -0
  615. package/external/folly/folly/lang/Badge.h +108 -0
  616. package/external/folly/folly/lang/Bits.h +570 -0
  617. package/external/folly/folly/lang/BitsClass.h +312 -0
  618. package/external/folly/folly/lang/Builtin.h +74 -0
  619. package/external/folly/folly/lang/CArray.h +34 -0
  620. package/external/folly/folly/lang/CString.cpp +86 -0
  621. package/external/folly/folly/lang/CString.h +55 -0
  622. package/external/folly/folly/lang/Cast.h +51 -0
  623. package/external/folly/folly/lang/CheckedMath.h +253 -0
  624. package/external/folly/folly/lang/CustomizationPoint.h +58 -0
  625. package/external/folly/folly/lang/Exception.cpp +822 -0
  626. package/external/folly/folly/lang/Exception.h +716 -0
  627. package/external/folly/folly/lang/Extern.h +55 -0
  628. package/external/folly/folly/lang/Hint-inl.h +144 -0
  629. package/external/folly/folly/lang/Hint.h +238 -0
  630. package/external/folly/folly/lang/Keep.h +98 -0
  631. package/external/folly/folly/lang/New.h +124 -0
  632. package/external/folly/folly/lang/Ordering.h +140 -0
  633. package/external/folly/folly/lang/Pretty.h +159 -0
  634. package/external/folly/folly/lang/PropagateConst.h +413 -0
  635. package/external/folly/folly/lang/RValueReferenceWrapper.h +152 -0
  636. package/external/folly/folly/lang/SafeAssert.cpp +589 -0
  637. package/external/folly/folly/lang/StaticConst.h +33 -0
  638. package/external/folly/folly/lang/Thunk.h +100 -0
  639. package/external/folly/folly/lang/TypeInfo.h +58 -0
  640. package/external/folly/folly/lang/UncaughtExceptions.cpp +17 -0
  641. package/external/folly/folly/lang/UncaughtExceptions.h +19 -0
  642. package/external/folly/folly/lang/test/AlignTest.cpp +87 -0
  643. package/external/folly/folly/lang/test/AlignedTest.cpp +130 -0
  644. package/external/folly/folly/lang/test/BUCK +258 -0
  645. package/external/folly/folly/lang/test/BadgeTest.cpp +89 -0
  646. package/external/folly/folly/lang/test/BitsBenchmark.cpp +164 -0
  647. package/external/folly/folly/lang/test/BitsClassBenchmark.cpp +122 -0
  648. package/external/folly/folly/lang/test/BitsClassTest.cpp +379 -0
  649. package/external/folly/folly/lang/test/BitsTest.cpp +577 -0
  650. package/external/folly/folly/lang/test/CStringTest.cpp +60 -0
  651. package/external/folly/folly/lang/test/CastTest.cpp +47 -0
  652. package/external/folly/folly/lang/test/CheckedMathTest.cpp +394 -0
  653. package/external/folly/folly/lang/test/ExceptionBench.cpp +427 -0
  654. package/external/folly/folly/lang/test/ExceptionTest.cpp +413 -0
  655. package/external/folly/folly/lang/test/ExternTest.cpp +39 -0
  656. package/external/folly/folly/lang/test/HintTest.cpp +100 -0
  657. package/external/folly/folly/lang/test/NewTest.cpp +38 -0
  658. package/external/folly/folly/lang/test/OrderingTest.cpp +105 -0
  659. package/external/folly/folly/lang/test/PrettyTest.cpp +44 -0
  660. package/external/folly/folly/lang/test/PropagateConstTest.cpp +356 -0
  661. package/external/folly/folly/lang/test/RValueReferenceWrapperTest.cpp +85 -0
  662. package/external/folly/folly/lang/test/SafeAssertTest.cpp +75 -0
  663. package/external/folly/folly/lang/test/ThunkTest.cpp +105 -0
  664. package/external/folly/folly/lang/test/ToAsciiBench.cpp +466 -0
  665. package/external/folly/folly/lang/test/ToAsciiTest.cpp +266 -0
  666. package/external/folly/folly/lang/test/TypeInfoTest.cpp +56 -0
  667. package/external/folly/folly/memcpy.S +292 -0
  668. package/external/folly/folly/memcpy_select_aarch64.cpp +145 -0
  669. package/external/folly/folly/memory/Arena-inl.h +83 -0
  670. package/external/folly/folly/memory/Arena.h +325 -0
  671. package/external/folly/folly/memory/BUCK +191 -0
  672. package/external/folly/folly/memory/JemallocHugePageAllocator.cpp +449 -0
  673. package/external/folly/folly/memory/JemallocHugePageAllocator.h +105 -0
  674. package/external/folly/folly/memory/JemallocHugePageAllocatorTest.cpp +341 -0
  675. package/external/folly/folly/memory/JemallocNodumpAllocator.cpp +176 -0
  676. package/external/folly/folly/memory/JemallocNodumpAllocator.h +119 -0
  677. package/external/folly/folly/memory/JemallocNodumpAllocatorTest.cpp +61 -0
  678. package/external/folly/folly/memory/MallctlHelper.cpp +37 -0
  679. package/external/folly/folly/memory/MallctlHelper.h +167 -0
  680. package/external/folly/folly/memory/Malloc.h +551 -0
  681. package/external/folly/folly/memory/MemoryResource.h +57 -0
  682. package/external/folly/folly/memory/ReentrantAllocator.cpp +162 -0
  683. package/external/folly/folly/memory/ReentrantAllocator.h +261 -0
  684. package/external/folly/folly/memory/SanitizeAddress.cpp +75 -0
  685. package/external/folly/folly/memory/SanitizeAddress.h +117 -0
  686. package/external/folly/folly/memory/SanitizeLeak.cpp +119 -0
  687. package/external/folly/folly/memory/SanitizeLeak.h +108 -0
  688. package/external/folly/folly/memory/ThreadCachedArena.cpp +53 -0
  689. package/external/folly/folly/memory/ThreadCachedArena.h +90 -0
  690. package/external/folly/folly/memory/UninitializedMemoryHacks.h +426 -0
  691. package/external/folly/folly/memory/detail/BUCK +10 -0
  692. package/external/folly/folly/memory/detail/MallocImpl.cpp +52 -0
  693. package/external/folly/folly/memory/detail/MallocImpl.h +97 -0
  694. package/external/folly/folly/memory/not_null-inl.h +522 -0
  695. package/external/folly/folly/memory/not_null.h +449 -0
  696. package/external/folly/folly/memory/test/ArenaTest.cpp +354 -0
  697. package/external/folly/folly/memory/test/BUCK +146 -0
  698. package/external/folly/folly/memory/test/MallctlHelperTest.cpp +169 -0
  699. package/external/folly/folly/memory/test/MallocBenchmark.cpp +91 -0
  700. package/external/folly/folly/memory/test/MallocTest.cpp +78 -0
  701. package/external/folly/folly/memory/test/MemoryResourceTest.cpp +31 -0
  702. package/external/folly/folly/memory/test/ReentrantAllocatorTest.cpp +144 -0
  703. package/external/folly/folly/memory/test/SanitizeAddressTest.cpp +67 -0
  704. package/external/folly/folly/memory/test/SanitizeLeakTest.cpp +139 -0
  705. package/external/folly/folly/memory/test/ThreadCachedArenaTest.cpp +276 -0
  706. package/external/folly/folly/memory/test/UninitializedMemoryHacksODR.cpp +21 -0
  707. package/external/folly/folly/memory/test/UninitializedMemoryHacksTest.cpp +327 -0
  708. package/external/folly/folly/memory/test/not_null_test.cpp +608 -0
  709. package/external/folly/folly/memset.S +245 -0
  710. package/external/folly/folly/memset_select_aarch64.cpp +72 -0
  711. package/external/folly/folly/portability/Asm.h +50 -0
  712. package/external/folly/folly/portability/Atomic.h +31 -0
  713. package/external/folly/folly/portability/BUCK +456 -0
  714. package/external/folly/folly/portability/Builtins.cpp +31 -0
  715. package/external/folly/folly/portability/Builtins.h +161 -0
  716. package/external/folly/folly/portability/Config.h +43 -0
  717. package/external/folly/folly/portability/Constexpr.h +145 -0
  718. package/external/folly/folly/portability/Dirent.cpp +140 -0
  719. package/external/folly/folly/portability/Dirent.h +41 -0
  720. package/external/folly/folly/portability/Event.h +44 -0
  721. package/external/folly/folly/portability/Fcntl.cpp +120 -0
  722. package/external/folly/folly/portability/Fcntl.h +67 -0
  723. package/external/folly/folly/portability/Filesystem.cpp +67 -0
  724. package/external/folly/folly/portability/Filesystem.h +114 -0
  725. package/external/folly/folly/portability/FmtCompile.h +40 -0
  726. package/external/folly/folly/portability/GFlags.h +139 -0
  727. package/external/folly/folly/portability/GMock.h +35 -0
  728. package/external/folly/folly/portability/GTest.h +35 -0
  729. package/external/folly/folly/portability/IOVec.h +34 -0
  730. package/external/folly/folly/portability/Libgen.cpp +59 -0
  731. package/external/folly/folly/portability/Libgen.h +29 -0
  732. package/external/folly/folly/portability/Libunwind.h +21 -0
  733. package/external/folly/folly/portability/Malloc.cpp +31 -0
  734. package/external/folly/folly/portability/Malloc.h +53 -0
  735. package/external/folly/folly/portability/Math.h +90 -0
  736. package/external/folly/folly/portability/Memory.h +26 -0
  737. package/external/folly/folly/portability/OpenSSL.cpp +17 -0
  738. package/external/folly/folly/portability/OpenSSL.h +102 -0
  739. package/external/folly/folly/portability/PThread.cpp +697 -0
  740. package/external/folly/folly/portability/PThread.h +148 -0
  741. package/external/folly/folly/portability/README.md +21 -0
  742. package/external/folly/folly/portability/Sched.cpp +41 -0
  743. package/external/folly/folly/portability/Sched.h +45 -0
  744. package/external/folly/folly/portability/Sockets.cpp +245 -0
  745. package/external/folly/folly/portability/Sockets.h +155 -0
  746. package/external/folly/folly/portability/SourceLocation.h +49 -0
  747. package/external/folly/folly/portability/Stdio.cpp +77 -0
  748. package/external/folly/folly/portability/Stdio.h +32 -0
  749. package/external/folly/folly/portability/Stdlib.cpp +172 -0
  750. package/external/folly/folly/portability/Stdlib.h +64 -0
  751. package/external/folly/folly/portability/String.cpp +53 -0
  752. package/external/folly/folly/portability/String.h +39 -0
  753. package/external/folly/folly/portability/SysFile.cpp +46 -0
  754. package/external/folly/folly/portability/SysFile.h +27 -0
  755. package/external/folly/folly/portability/SysMembarrier.cpp +104 -0
  756. package/external/folly/folly/portability/SysMembarrier.h +26 -0
  757. package/external/folly/folly/portability/SysMman.cpp +242 -0
  758. package/external/folly/folly/portability/SysMman.h +68 -0
  759. package/external/folly/folly/portability/SysResource.cpp +108 -0
  760. package/external/folly/folly/portability/SysResource.h +71 -0
  761. package/external/folly/folly/portability/SysStat.cpp +66 -0
  762. package/external/folly/folly/portability/SysStat.h +52 -0
  763. package/external/folly/folly/portability/SysSyscall.h +73 -0
  764. package/external/folly/folly/portability/SysTime.cpp +62 -0
  765. package/external/folly/folly/portability/SysTime.h +50 -0
  766. package/external/folly/folly/portability/SysTypes.h +44 -0
  767. package/external/folly/folly/portability/SysUio.cpp +179 -0
  768. package/external/folly/folly/portability/SysUio.h +51 -0
  769. package/external/folly/folly/portability/Syslog.h +39 -0
  770. package/external/folly/folly/portability/Time.cpp +357 -0
  771. package/external/folly/folly/portability/Time.h +74 -0
  772. package/external/folly/folly/portability/Unistd.h +111 -0
  773. package/external/folly/folly/portability/Windows.h +108 -0
  774. package/external/folly/folly/portability/openat2.c +30 -0
  775. package/external/folly/folly/portability/openat2.h +39 -0
  776. package/external/folly/folly/portability/test/BUCK +59 -0
  777. package/external/folly/folly/portability/test/ConstexprTest.cpp +102 -0
  778. package/external/folly/folly/portability/test/FilesystemTest.cpp +35 -0
  779. package/external/folly/folly/portability/test/LibgenTest.cpp +35 -0
  780. package/external/folly/folly/portability/test/OpenSSLPortabilityTest.cpp +108 -0
  781. package/external/folly/folly/portability/test/PThreadTest.cpp +80 -0
  782. package/external/folly/folly/portability/test/TimeTest.cpp +90 -0
  783. package/external/folly/folly/small_vector.h +17 -0
  784. package/external/folly/folly/somerge_defs.bzl +399 -0
  785. package/external/folly/folly/sorted_vector_types.h +17 -0
  786. package/external/folly/folly/stop_watch.h +317 -0
  787. package/external/folly/folly/synchronization/AsymmetricThreadFence.cpp +91 -0
  788. package/external/folly/folly/synchronization/AsymmetricThreadFence.h +60 -0
  789. package/external/folly/folly/synchronization/AtomicNotification-inl.h +146 -0
  790. package/external/folly/folly/synchronization/AtomicNotification.cpp +34 -0
  791. package/external/folly/folly/synchronization/AtomicNotification.h +117 -0
  792. package/external/folly/folly/synchronization/AtomicRef.h +181 -0
  793. package/external/folly/folly/synchronization/AtomicStruct.h +150 -0
  794. package/external/folly/folly/synchronization/AtomicUtil-inl.h +482 -0
  795. package/external/folly/folly/synchronization/AtomicUtil.h +179 -0
  796. package/external/folly/folly/synchronization/BUCK +418 -0
  797. package/external/folly/folly/synchronization/Baton.h +419 -0
  798. package/external/folly/folly/synchronization/CallOnce.h +263 -0
  799. package/external/folly/folly/synchronization/DelayedInit.h +179 -0
  800. package/external/folly/folly/synchronization/DistributedMutex-inl.h +1744 -0
  801. package/external/folly/folly/synchronization/DistributedMutex.cpp +27 -0
  802. package/external/folly/folly/synchronization/DistributedMutex.h +342 -0
  803. package/external/folly/folly/synchronization/EventCount.h +200 -0
  804. package/external/folly/folly/synchronization/FlatCombining.h +629 -0
  805. package/external/folly/folly/synchronization/Hazptr-fwd.h +217 -0
  806. package/external/folly/folly/synchronization/Hazptr.cpp +36 -0
  807. package/external/folly/folly/synchronization/Hazptr.h +209 -0
  808. package/external/folly/folly/synchronization/HazptrDomain.cpp +68 -0
  809. package/external/folly/folly/synchronization/HazptrDomain.h +832 -0
  810. package/external/folly/folly/synchronization/HazptrHolder.h +431 -0
  811. package/external/folly/folly/synchronization/HazptrObj.h +533 -0
  812. package/external/folly/folly/synchronization/HazptrObjLinked.h +315 -0
  813. package/external/folly/folly/synchronization/HazptrRec.h +68 -0
  814. package/external/folly/folly/synchronization/HazptrThrLocal.h +180 -0
  815. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.cpp +46 -0
  816. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.h +25 -0
  817. package/external/folly/folly/synchronization/Latch.h +160 -0
  818. package/external/folly/folly/synchronization/LifoSem.h +767 -0
  819. package/external/folly/folly/synchronization/Lock.h +887 -0
  820. package/external/folly/folly/synchronization/MicroSpinLock.h +154 -0
  821. package/external/folly/folly/synchronization/NativeSemaphore.h +187 -0
  822. package/external/folly/folly/synchronization/ParkingLot.cpp +37 -0
  823. package/external/folly/folly/synchronization/ParkingLot.h +330 -0
  824. package/external/folly/folly/synchronization/PicoSpinLock.h +167 -0
  825. package/external/folly/folly/synchronization/RWSpinLock.h +549 -0
  826. package/external/folly/folly/synchronization/Rcu.cpp +26 -0
  827. package/external/folly/folly/synchronization/Rcu.h +553 -0
  828. package/external/folly/folly/synchronization/RelaxedAtomic.h +336 -0
  829. package/external/folly/folly/synchronization/SanitizeThread.cpp +141 -0
  830. package/external/folly/folly/synchronization/SanitizeThread.h +166 -0
  831. package/external/folly/folly/synchronization/SaturatingSemaphore.h +324 -0
  832. package/external/folly/folly/synchronization/SmallLocks.h +36 -0
  833. package/external/folly/folly/synchronization/ThrottledLifoSem.h +362 -0
  834. package/external/folly/folly/synchronization/WaitOptions.cpp +25 -0
  835. package/external/folly/folly/synchronization/WaitOptions.h +75 -0
  836. package/external/folly/folly/synchronization/detail/AtomicUtils.h +59 -0
  837. package/external/folly/folly/synchronization/detail/BUCK +104 -0
  838. package/external/folly/folly/synchronization/detail/Hardware.cpp +192 -0
  839. package/external/folly/folly/synchronization/detail/Hardware.h +75 -0
  840. package/external/folly/folly/synchronization/detail/HazptrUtils.h +339 -0
  841. package/external/folly/folly/synchronization/detail/InlineFunctionRef.h +229 -0
  842. package/external/folly/folly/synchronization/detail/Sleeper.cpp +27 -0
  843. package/external/folly/folly/synchronization/detail/Sleeper.h +62 -0
  844. package/external/folly/folly/synchronization/detail/Spin.h +96 -0
  845. package/external/folly/folly/synchronization/detail/ThreadCachedLists.h +174 -0
  846. package/external/folly/folly/synchronization/detail/ThreadCachedReaders.h +189 -0
  847. package/external/folly/folly/synchronization/detail/ThreadCachedTag.h +26 -0
  848. package/external/folly/folly/synchronization/detail/test/BUCK +28 -0
  849. package/external/folly/folly/synchronization/detail/test/HardwareTest.cpp +74 -0
  850. package/external/folly/folly/synchronization/detail/test/InlineFunctionRefTest.cpp +286 -0
  851. package/external/folly/folly/synchronization/example/BUCK +27 -0
  852. package/external/folly/folly/synchronization/example/HazptrLockFreeLIFO.h +88 -0
  853. package/external/folly/folly/synchronization/example/HazptrSWMRSet.h +133 -0
  854. package/external/folly/folly/synchronization/example/HazptrWideCAS.h +62 -0
  855. package/external/folly/folly/synchronization/test/AtomicNotificationTest.cpp +236 -0
  856. package/external/folly/folly/synchronization/test/AtomicRefTest.cpp +170 -0
  857. package/external/folly/folly/synchronization/test/AtomicStructTest.cpp +65 -0
  858. package/external/folly/folly/synchronization/test/AtomicUtilBench.cpp +457 -0
  859. package/external/folly/folly/synchronization/test/AtomicUtilTest.cpp +650 -0
  860. package/external/folly/folly/synchronization/test/BUCK +495 -0
  861. package/external/folly/folly/synchronization/test/Barrier.h +52 -0
  862. package/external/folly/folly/synchronization/test/BarrierTest.cpp +56 -0
  863. package/external/folly/folly/synchronization/test/BatonBenchmark.cpp +77 -0
  864. package/external/folly/folly/synchronization/test/BatonTest.cpp +164 -0
  865. package/external/folly/folly/synchronization/test/BatonTestHelpers.h +118 -0
  866. package/external/folly/folly/synchronization/test/CallOnceBenchmark.cpp +72 -0
  867. package/external/folly/folly/synchronization/test/CallOnceTest.cpp +153 -0
  868. package/external/folly/folly/synchronization/test/DelayedInitTest.cpp +281 -0
  869. package/external/folly/folly/synchronization/test/DistributedMutexTest.cpp +2074 -0
  870. package/external/folly/folly/synchronization/test/EventCountTest.cpp +124 -0
  871. package/external/folly/folly/synchronization/test/FlatCombiningBenchmark.cpp +1789 -0
  872. package/external/folly/folly/synchronization/test/FlatCombiningExamples.h +222 -0
  873. package/external/folly/folly/synchronization/test/FlatCombiningTest.cpp +121 -0
  874. package/external/folly/folly/synchronization/test/FlatCombiningTestHelpers.h +227 -0
  875. package/external/folly/folly/synchronization/test/HazptrTest.cpp +1689 -0
  876. package/external/folly/folly/synchronization/test/LatchTest.cpp +224 -0
  877. package/external/folly/folly/synchronization/test/LifoSemBench.cpp +185 -0
  878. package/external/folly/folly/synchronization/test/LifoSemTests.cpp +353 -0
  879. package/external/folly/folly/synchronization/test/LockTest.cpp +1239 -0
  880. package/external/folly/folly/synchronization/test/NativeSemaphoreTest.cpp +37 -0
  881. package/external/folly/folly/synchronization/test/ParkingLotBenchmark.cpp +239 -0
  882. package/external/folly/folly/synchronization/test/ParkingLotTest.cpp +170 -0
  883. package/external/folly/folly/synchronization/test/RWSpinLockTest.cpp +235 -0
  884. package/external/folly/folly/synchronization/test/RcuBench.cpp +66 -0
  885. package/external/folly/folly/synchronization/test/RcuTest.cpp +330 -0
  886. package/external/folly/folly/synchronization/test/RelaxedAtomicTest.cpp +389 -0
  887. package/external/folly/folly/synchronization/test/SaturatingSemaphoreTest.cpp +166 -0
  888. package/external/folly/folly/synchronization/test/Semaphore.h +242 -0
  889. package/external/folly/folly/synchronization/test/SemaphoreTest.cpp +271 -0
  890. package/external/folly/folly/synchronization/test/SmallLocksBenchmark.cpp +1296 -0
  891. package/external/folly/folly/synchronization/test/SmallLocksTest.cpp +510 -0
  892. package/external/folly/folly/synchronization/test/ThreadCachedEpochBench.h +67 -0
  893. package/external/folly/folly/synchronization/test/ThreadCachedReadersBench.cpp +42 -0
  894. package/external/folly/folly/synchronization/test/ThreadCachedReadersTest.cpp +52 -0
  895. package/external/folly/folly/synchronization/test/ThrottledLifoSemTest.cpp +243 -0
  896. package/external/folly/folly/system/AtFork.cpp +205 -0
  897. package/external/folly/folly/system/AtFork.h +116 -0
  898. package/external/folly/folly/system/AuxVector.h +198 -0
  899. package/external/folly/folly/system/BUCK +144 -0
  900. package/external/folly/folly/system/EnvUtil.cpp +93 -0
  901. package/external/folly/folly/system/EnvUtil.h +113 -0
  902. package/external/folly/folly/system/HardwareConcurrency.cpp +39 -0
  903. package/external/folly/folly/system/HardwareConcurrency.h +23 -0
  904. package/external/folly/folly/system/MemoryMapping.cpp +477 -0
  905. package/external/folly/folly/system/MemoryMapping.h +287 -0
  906. package/external/folly/folly/system/Pid.cpp +87 -0
  907. package/external/folly/folly/system/Pid.h +34 -0
  908. package/external/folly/folly/system/Shell.cpp +33 -0
  909. package/external/folly/folly/system/Shell.h +93 -0
  910. package/external/folly/folly/system/ThreadId.cpp +89 -0
  911. package/external/folly/folly/system/ThreadId.h +62 -0
  912. package/external/folly/folly/system/ThreadName.cpp +330 -0
  913. package/external/folly/folly/system/ThreadName.h +72 -0
  914. package/external/folly/folly/system/test/AtForkTest.cpp +309 -0
  915. package/external/folly/folly/system/test/AuxVectorTest.cpp +55 -0
  916. package/external/folly/folly/system/test/BUCK +120 -0
  917. package/external/folly/folly/system/test/EnvUtilSubprocess.cpp +26 -0
  918. package/external/folly/folly/system/test/EnvUtilTest.cpp +197 -0
  919. package/external/folly/folly/system/test/MemoryMappingTest.cpp +179 -0
  920. package/external/folly/folly/system/test/PidTest.cpp +46 -0
  921. package/external/folly/folly/system/test/ShellTest.cpp +66 -0
  922. package/external/folly/folly/system/test/ThreadIdTest.cpp +114 -0
  923. package/external/folly/folly/system/test/ThreadNameTest.cpp +85 -0
  924. package/external/folly/folly.vcxitems +164 -0
  925. package/external/folly/static/logo.svg +1 -0
  926. package/external/folly/sync-config.json +8 -0
  927. package/just-task.js +13 -2
  928. package/package.json +7 -7
  929. package/template/cpp-lib/proj/MyLib.sln +0 -33
  930. package/template/cs-lib/proj/MyLib.sln +0 -33
  931. package/templates/cpp-app/windows/MyApp/MyApp.vcxproj +1 -1
  932. package/templates/cpp-app/windows/MyApp.sln +0 -33
  933. package/templates/cpp-lib/example/metro.config.js +30 -4
  934. package/templates/cpp-lib/windows/MyLib/MyLib.vcxproj +1 -1
  935. package/templates/cpp-lib/windows/MyLib.sln +0 -33
  936. package/Folly/Folly.vcxproj +0 -378
  937. package/Folly/Folly.vcxproj.filters +0 -558
  938. package/fmt/fmt.vcxproj +0 -153
  939. package/fmt/fmt.vcxproj.filters +0 -59
  940. package/fmt/pch.cpp +0 -4
  941. package/fmt/pch.h +0 -2
  942. /package/{fmt → external/fmt}/cgmanifest.json +0 -0
  943. /package/{Folly → external/folly}/Folly.natvis +0 -0
  944. /package/{Folly → external/folly}/cgmanifest.json +0 -0
  945. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/ConstexprMath.h +0 -0
  946. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/Conv.cpp +0 -0
  947. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/chrono/Hardware.h +0 -0
  948. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/concurrency/CacheLocality.cpp +0 -0
  949. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/dynamic-inl.h +0 -0
  950. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/json.cpp +0 -0
  951. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/SafeAssert.h +0 -0
  952. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.cpp +0 -0
  953. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.h +0 -0
  954. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/portability/Unistd.cpp +0 -0
@@ -0,0 +1,1744 @@
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
+ #include <array>
18
+ #include <atomic>
19
+ #include <cstdint>
20
+ #include <limits>
21
+ #include <new>
22
+ #include <stdexcept>
23
+ #include <thread>
24
+ #include <utility>
25
+
26
+ #include <glog/logging.h>
27
+
28
+ #include <folly/ConstexprMath.h>
29
+ #include <folly/Likely.h>
30
+ #include <folly/Portability.h>
31
+ #include <folly/ScopeGuard.h>
32
+ #include <folly/Utility.h>
33
+ #include <folly/chrono/Hardware.h>
34
+ #include <folly/detail/Futex.h>
35
+ #include <folly/functional/Invoke.h>
36
+ #include <folly/lang/Align.h>
37
+ #include <folly/lang/Bits.h>
38
+ #include <folly/lang/Exception.h>
39
+ #include <folly/portability/Asm.h>
40
+ #include <folly/synchronization/AtomicNotification.h>
41
+ #include <folly/synchronization/AtomicUtil.h>
42
+ #include <folly/synchronization/Lock.h>
43
+ #include <folly/synchronization/detail/InlineFunctionRef.h>
44
+ #include <folly/synchronization/detail/Sleeper.h>
45
+
46
+ namespace folly {
47
+ namespace detail {
48
+ namespace distributed_mutex {
49
+ // kUnlocked is used to show unlocked state
50
+ //
51
+ // When locking threads encounter kUnlocked in the underlying storage, they
52
+ // can just acquire the lock without any further effort
53
+ constexpr auto kUnlocked = std::uintptr_t{0b0};
54
+ // kLocked is used to show that the mutex is currently locked, and future
55
+ // attempts to lock the mutex should enqueue on the central storage
56
+ //
57
+ // Locking threads find this on central storage only when there is a
58
+ // contention chain that is undergoing wakeups, in every other case, a locker
59
+ // will either find kUnlocked or an arbitrary address with the kLocked bit set
60
+ constexpr auto kLocked = std::uintptr_t{0b1};
61
+ // kTimedWaiter is set when there is at least one timed waiter on the mutex
62
+ //
63
+ // Timed waiters do not follow the sleeping strategy employed by regular,
64
+ // non-timed threads. They sleep on the central mutex atomic through an
65
+ // extended futex() interface that allows sleeping with the same semantics for
66
+ // non-standard integer widths
67
+ //
68
+ // When a regular non-timed thread unlocks or enqueues on the mutex, and sees
69
+ // a timed waiter, it takes ownership of all the timed waiters. The thread
70
+ // that has taken ownership of the timed waiter releases the timed waiters
71
+ // when it gets a chance at the critical section. At which point it issues a
72
+ // wakeup to single timed waiter, timed waiters always issue wake() calls to
73
+ // other timed waiters
74
+ constexpr auto kTimedWaiter = std::uintptr_t{0b10};
75
+
76
+ // kUninitialized means that the thread has just enqueued, and has not yet
77
+ // gotten to initializing itself with the address of its successor
78
+ //
79
+ // this becomes significant for threads that are trying to wake up the
80
+ // uninitialized thread, if they see that the thread is not yet initialized,
81
+ // they can do nothing but spin, and wait for the thread to get initialized
82
+ //
83
+ // This also plays a role in the functioning of flat combining as implemented
84
+ // in DistributedMutex. When a thread owning the lock goes through the
85
+ // contention chain to either unlock the mutex or combine critical sections
86
+ // from the other end. The presence of kUninitialized means that the
87
+ // combining thread is not able to make progress after this point. So we
88
+ // transfer the lock.
89
+ constexpr auto kUninitialized = std::uint32_t{0b0};
90
+ // kWaiting will be set in the waiter's futex structs while they are spinning
91
+ // while waiting for the mutex
92
+ constexpr auto kWaiting = std::uint32_t{0b1};
93
+ // kWake will be set by threads that are waking up waiters that have enqueued
94
+ constexpr auto kWake = std::uint32_t{0b10};
95
+ // kSkipped will be set by a waker when they see that a waiter has been
96
+ // preempted away by the kernel, in this case the thread that got skipped will
97
+ // have to wake up and put itself back on the queue
98
+ constexpr auto kSkipped = std::uint32_t{0b11};
99
+ // kAboutToWait will be set by a waiter that enqueues itself with the purpose
100
+ // of waiting on a futex
101
+ constexpr auto kAboutToWait = std::uint32_t{0b100};
102
+ // kSleeping will be set by a waiter right before enqueueing on a futex. When
103
+ // a thread wants to wake up a waiter that has enqueued on a futex, it should
104
+ // set the futex to contain kWake
105
+ //
106
+ // a thread that is unlocking and wants to skip over a sleeping thread also
107
+ // calls futex_.exchange(kSleeping) on the sleeping thread's futex word. It
108
+ // does this to 1. detect whether the sleeping thread had actually gone to
109
+ // sleeping on the futex word so it can skip it, and 2. to synchronize with
110
+ // other non atomic writes in the sleeping thread's context (such as the write
111
+ // to track the next waiting thread).
112
+ //
113
+ // We reuse kSleeping instead of say using another constant kEarlyDelivery to
114
+ // avoid situations where a thread has to enter kernel mode due to calling
115
+ // futexWait() twice because of the presence of a waking thread. This
116
+ // situation can arise when an unlocking thread goes to skip over a sleeping
117
+ // thread, sees that the thread has slept and move on, but the sleeping thread
118
+ // had not yet entered futex(). This interleaving causes the thread calling
119
+ // futex() to return spuriously, as the futex word is not what it should be
120
+ constexpr auto kSleeping = std::uint32_t{0b101};
121
+ // kCombined is set by the lock holder to let the waiter thread know that its
122
+ // combine request was successfully completed by the lock holder. A
123
+ // successful combine means that the thread requesting the combine operation
124
+ // does not need to unlock the mutex; in fact, doing so would be an error.
125
+ constexpr auto kCombined = std::uint32_t{0b111};
126
+ // kCombineUninitialized is like kUninitialized but is set by a thread when it
127
+ // enqueues in hopes of getting its critical section combined with the lock
128
+ // holder
129
+ constexpr auto kCombineUninitialized = std::uint32_t{0b1000};
130
+ // kCombineWaiting is set by a thread when it is ready to have its combine
131
+ // record fulfilled by the lock holder. In particular, this signals to the
132
+ // lock holder that the thread has set its next_ pointer in the contention
133
+ // chain
134
+ constexpr auto kCombineWaiting = std::uint32_t{0b1001};
135
+ // kExceptionOccurred is set on the waiter futex when the remote task throws
136
+ // an exception. It is the caller's responsibility to retrieve the exception
137
+ // and rethrow it in their own context. Note that when the caller uses a
138
+ // noexcept function as their critical section, they can avoid checking for
139
+ // this value
140
+ //
141
+ // This allows us to avoid all cost of exceptions in the memory layout of the
142
+ // fast path (no errors) as exceptions are stored as an std::exception_ptr in
143
+ // the same union that stores the return value of the critical section. We
144
+ // also avoid all CPU overhead because the combiner uses a try-catch block
145
+ // without any additional branching to handle exceptions
146
+ constexpr auto kExceptionOccurred = std::uint32_t{0b1010};
147
+
148
+ // Alias for processor's time-stamp counter value to help distinguish it from
149
+ // other integers
150
+ using CpuTicks = std::uint64_t;
151
+ // The number of spins that we are allowed to do before we resort to marking a
152
+ // thread as having slept
153
+ //
154
+ // This is just a magic number from benchmarks
155
+ constexpr auto kScheduledAwaySpinThreshold = CpuTicks{200};
156
+ // The maximum time to spin before a thread starts yielding its processor
157
+ // in hopes of getting skipped
158
+ constexpr auto kMaxSpinTime = CpuTicks{40000};
159
+ // The maximum number of contention chains we can resolve with flat combining.
160
+ // After this number of contention chains, the mutex falls back to regular
161
+ // two-phased mutual exclusion to ensure that we don't starve the combiner
162
+ // thread
163
+ constexpr auto kMaxCombineIterations = 2;
164
+
165
+ /**
166
+ * Write only data that is available to the thread that is waking up another.
167
+ * Only the waking thread is allowed to write to this, the thread to be woken
168
+ * is allowed to read from this after a wakeup has been issued
169
+ */
170
+ template <template <typename> class Atomic>
171
+ class WakerMetadata {
172
+ public:
173
+ // This is the thread that initiated wakeups for the contention chain.
174
+ // There can only ever be one thread that initiates the wakeup for a
175
+ // chain in the spin only version of this mutex. When a thread that just
176
+ // woke up sees this as the next thread to wake up, it knows that it is the
177
+ // terminal node in the contention chain. This means that it was the one
178
+ // that took off the thread that had acquired the mutex off the centralized
179
+ // state. Therefore, the current thread is the last in its contention
180
+ // chain. It will fall back to centralized storage to pick up the next
181
+ // waiter or release the mutex
182
+ //
183
+ // When we move to a full sleeping implementation, this might need to change
184
+ // to a small_vector<> to account for failed wakeups, or we can put threads
185
+ // to sleep on the central futex, which is an easier implementation
186
+ // strategy. Although, since this is allocated on the stack, we can set a
187
+ // prohitively large threshold to avoid heap allocations, this strategy
188
+ // however, might cause increased cache misses on wakeup signalling
189
+ std::uintptr_t waker_{0};
190
+ // the list of threads that the waker had previously seen to be sleeping on
191
+ // a futex(),
192
+ //
193
+ // this is given to the current thread as a means to pass on
194
+ // information. When the current thread goes to unlock the mutex and does
195
+ // not see contention, it should go and wake up the head of this list. If
196
+ // the current thread sees a contention chain on the mutex, it should pass
197
+ // on this list to the next thread that gets woken up
198
+ std::uintptr_t waiters_{0};
199
+ // The futex that this waiter will sleep on
200
+ //
201
+ // how can we reuse futex_ from above for futex management?
202
+ Futex<Atomic> sleeper_{kUninitialized};
203
+ };
204
+
205
+ /**
206
+ * Type of the type-erased callable that is used for combining from the lock
207
+ * holder's end. This has 48 bytes of inline storage that can be used to
208
+ * minimize cache misses when combining
209
+ */
210
+ using CombineFunction = detail::InlineFunctionRef<void(), 48>;
211
+
212
+ /**
213
+ * Waiter encapsulates the state required for waiting on the mutex, this
214
+ * contains potentially heavy state and is intended to be allocated on the
215
+ * stack as part of a lock() function call
216
+ *
217
+ * To ensure that synchronization does not cause unintended side effects on
218
+ * the rest of the thread stack (eg. metadata in lockImplementation(), or any
219
+ * other data in the user's thread), we aggresively pad this struct and use
220
+ * custom alignment internally to ensure that the relevant data fits within a
221
+ * single cacheline. The added alignment here also gives us some room to
222
+ * wiggle in the bottom few bits of the mutex, where we store extra metadata
223
+ */
224
+ template <template <typename> class Atomic>
225
+ class Waiter {
226
+ public:
227
+ Waiter() {}
228
+ Waiter(Waiter&&) = delete;
229
+ Waiter(const Waiter&) = delete;
230
+ Waiter& operator=(Waiter&&) = delete;
231
+ Waiter& operator=(const Waiter&) = delete;
232
+
233
+ void initialize(std::uint64_t futex, CombineFunction task) {
234
+ // we only initialize the function if we were actually given a non-null
235
+ // task, otherwise
236
+ if (task) {
237
+ DCHECK_EQ(futex, kCombineUninitialized);
238
+ new (&function_) CombineFunction{task};
239
+ } else {
240
+ DCHECK((futex == kUninitialized) || (futex == kAboutToWait));
241
+ new (&metadata_) WakerMetadata<Atomic>{};
242
+ }
243
+
244
+ // this pedantic store is needed to ensure that the waking thread
245
+ // synchronizes with the state in the waiter struct when it loads the
246
+ // value of the futex word
247
+ //
248
+ // on x86, this gets optimized away to just a regular store, it might be
249
+ // needed on platforms where explicit acquire-release barriers are
250
+ // required for synchronization
251
+ //
252
+ // note that we release here at the end of the constructor because
253
+ // construction is complete here, any thread that acquires this release
254
+ // will see a well constructed wait node
255
+ futex_.store(futex, std::memory_order_release);
256
+ }
257
+
258
+ std::array<std::uint8_t, hardware_destructive_interference_size> padding1;
259
+ // the atomic that this thread will spin on while waiting for the mutex to
260
+ // be unlocked
261
+ alignas(hardware_destructive_interference_size) Atomic<std::uint64_t> futex_{
262
+ kUninitialized};
263
+ // The successor of this node. This will be the thread that had its address
264
+ // on the mutex previously
265
+ //
266
+ // We can do without making this atomic since the remote thread synchronizes
267
+ // on the futex variable above. If this were not atomic, the remote thread
268
+ // would only be allowed to read from it after the waiter has moved into the
269
+ // waiting state to avoid risk of a load racing with a write. However, it
270
+ // helps to make this atomic because we can use an unconditional load and make
271
+ // full use of the load buffer to coalesce both reads into a single clock
272
+ // cycle after the line arrives in the combiner core. This is a heavily
273
+ // contended line, so an RFO from the enqueueing thread is highly likely and
274
+ // has the potential to cause an immediate invalidation; blocking the combiner
275
+ // thread from making progress until the line is pulled back to read this
276
+ // value
277
+ //
278
+ // Further, making this atomic prevents the compiler from making an incorrect
279
+ // optimization where it does not load the value as written in the code, but
280
+ // rather dereferences it through a pointer whenever needed (since the value
281
+ // of the pointer to this is readily available on the stack). Doing this
282
+ // causes multiple invalidation requests from the enqueueing thread, blocking
283
+ // remote progress
284
+ //
285
+ // Note that we use relaxed loads and stores, so this should not have any
286
+ // additional overhead compared to a regular load on most architectures
287
+ std::atomic<std::uintptr_t> next_{0};
288
+ // We use an anonymous union for the combined critical section request and
289
+ // the metadata that will be filled in from the leader's end. Only one is
290
+ // active at a time - if a leader decides to combine the requested critical
291
+ // section into its execution, it will not touch the metadata field. If a
292
+ // leader decides to migrate the lock to the waiter, it will not touch the
293
+ // function
294
+ //
295
+ // this allows us to transfer more state when combining a critical section
296
+ // and reduce the cache misses originating from executing an arbitrary
297
+ // lambda
298
+ //
299
+ // note that this is an anonymous union, not an unnamed union, the members
300
+ // leak into the surrounding scope
301
+ union {
302
+ // metadata for the waker
303
+ WakerMetadata<Atomic> metadata_;
304
+ // The critical section that can potentially be combined into the critical
305
+ // section of the locking thread
306
+ //
307
+ // This is kept as a FunctionRef because the original function is preserved
308
+ // until the lock_combine() function returns. A consequence of using
309
+ // FunctionRef here is that we don't need to do any allocations and can
310
+ // allow users to capture unbounded state into the critical section. Flat
311
+ // combining means that the user does not have access to the thread
312
+ // executing the critical section, so assumptions about thread local
313
+ // references can be invalidated. Being able to capture arbitrary state
314
+ // allows the user to do thread local accesses right before the critical
315
+ // section and pass them as state to the callable being referenced here
316
+ CombineFunction function_;
317
+ // The user is allowed to use a combined critical section that returns a
318
+ // value. This buffer is used to implement the value transfer to the
319
+ // waiting thread. We reuse the same union because this helps us combine
320
+ // one synchronization operation with a material value transfer.
321
+ //
322
+ // The waker thread needs to synchronize on this cacheline to issue a
323
+ // wakeup to the waiter, meaning that the entire line needs to be pulled
324
+ // into the remote core in exclusive mode. So we reuse the coherence
325
+ // operation to transfer the return value in addition to the
326
+ // synchronization signal. In the case that the user's data item is
327
+ // small, the data is transferred all inline as part of the same line,
328
+ // which pretty much arrives into the CPU cache in the same clock cycle or
329
+ // two after a read-for-ownership request. This gives us a high chance of
330
+ // coalescing the entire transitive store buffer together into one cache
331
+ // coherence operation from the waker's end. This allows us to make use
332
+ // of the CPU bus bandwidth which would have otherwise gone to waste.
333
+ // Benchmarks prove this theory under a wide range of contention, value
334
+ // sizes, NUMA interactions and processor models
335
+ //
336
+ // The current version of the Intel optimization manual confirms this
337
+ // theory somewhat as well in section 2.3.5.1 (Load and Store Operation
338
+ // Overview)
339
+ //
340
+ // When an instruction writes data to a memory location [...], the
341
+ // processor ensures that it has the line containing this memory location
342
+ // is in its L1d cache [...]. If the cache line is not there, it fetches
343
+ // from the next levels using a RFO request [...] RFO and storing the
344
+ // data happens after instruction retirement. Therefore, the store
345
+ // latency usually does not affect the store instruction itself
346
+ //
347
+ // This gives the user the ability to input up to 48 bytes into the
348
+ // combined critical section through an InlineFunctionRef and output 48
349
+ // bytes from it basically without any cost. The type of the entity
350
+ // stored in the buffer has to be matched by the type erased callable that
351
+ // the caller has used. At this point, the caller is still in the
352
+ // template instantiation leading to the combine request, so it has
353
+ // knowledge of the return type and can apply the appropriate
354
+ // reinterpret_cast and launder operation to safely retrieve the data from
355
+ // this buffer
356
+ folly::aligned_storage_t<48, 8> storage_;
357
+ };
358
+ std::array<std::uint8_t, hardware_destructive_interference_size> padding2;
359
+ };
360
+
361
+ /**
362
+ * A template that helps us differentiate between the different ways to return
363
+ * a value from a combined critical section. A return value of type void
364
+ * cannot be stored anywhere, so we use specializations and pick the right one
365
+ * switched through std::conditional_t
366
+ *
367
+ * This is then used by CoalescedTask and its family of functions to implement
368
+ * efficient return value transfers to the waiting threads
369
+ */
370
+ template <typename Func>
371
+ class RequestWithReturn {
372
+ public:
373
+ using F = Func;
374
+ using ReturnType = folly::invoke_result_t<const Func&>;
375
+ explicit RequestWithReturn(Func func) : func_{std::move(func)} {}
376
+
377
+ /**
378
+ * We need to define the destructor here because C++ requires (with good
379
+ * reason) that a union with non-default destructor be explicitly destroyed
380
+ * from the surrounding class, as neither the runtime nor compiler have the
381
+ * knowledge of what to do with a union at the time of destruction
382
+ *
383
+ * Each request that has a valid return value set will have the value
384
+ * retrieved from the get() method, where the value is destroyed. So we
385
+ * don't need to destroy it here
386
+ */
387
+ ~RequestWithReturn() {}
388
+
389
+ /**
390
+ * This method can be used to return a value from the request. This returns
391
+ * the underlying value because return type of the function we were
392
+ * instantiated with is not void
393
+ */
394
+ ReturnType get() && {
395
+ // when the return value has been processed, we destroy the value
396
+ // contained in this request. Using a scope_exit means that we don't have
397
+ // to worry about storing the value somewhere and causing potentially an
398
+ // extra move
399
+ //
400
+ // note that the invariant here is that this function is only called if the
401
+ // requesting thread had it's critical section combined, and the value_
402
+ // member constructed through detach()
403
+ SCOPE_EXIT {
404
+ value_.~ReturnType();
405
+ };
406
+ return std::move(value_);
407
+ }
408
+
409
+ // this contains a copy of the function the waiter had requested to be
410
+ // executed as a combined critical section
411
+ Func func_;
412
+ // this stores the return value used in the request, we use a union here to
413
+ // avoid laundering and allow return types that are not default
414
+ // constructible to be propagated through the execution of the critical
415
+ // section
416
+ //
417
+ // note that this is an anonymous union, the member leaks into the
418
+ // surrounding scope as a member variable
419
+ union {
420
+ ReturnType value_;
421
+ };
422
+ };
423
+
424
+ template <typename Func>
425
+ class RequestWithoutReturn {
426
+ public:
427
+ using F = Func;
428
+ using ReturnType = void;
429
+ explicit RequestWithoutReturn(Func func) : func_{std::move(func)} {}
430
+
431
+ /**
432
+ * In this version of the request class, get() returns nothing as there is
433
+ * no stored value
434
+ */
435
+ void get() && {}
436
+
437
+ // this contains a copy of the function the waiter had requested to be
438
+ // executed as a combined critical section
439
+ Func func_;
440
+ };
441
+
442
+ // we need to use std::integral_constant::value here as opposed to
443
+ // std::integral_constant::operator T() because MSVC errors out with the
444
+ // implicit conversion
445
+ template <typename Func>
446
+ using Request = std::conditional_t<
447
+ std::is_void<folly::invoke_result_t<const Func&>>::value,
448
+ RequestWithoutReturn<Func>,
449
+ RequestWithReturn<Func>>;
450
+
451
+ /**
452
+ * A template that helps us to transform a callable returning a value to one
453
+ * that returns void so it can be type erased and passed on to the waker. If
454
+ * the return value is small enough, it gets coalesced into the wait struct
455
+ * for optimal data transfer. When it's not small enough to fit in the waiter
456
+ * storage buffer, we place it on it's own cacheline with isolation to prevent
457
+ * false-sharing with the on-stack metadata of the waiter thread
458
+ *
459
+ * This helps a combined critical section feel more normal in the case where
460
+ * the user wants to return a value, for example
461
+ *
462
+ * auto value = mutex_.lock_combine([&]() {
463
+ * return data_.value();
464
+ * });
465
+ *
466
+ * Without this, the user would typically create a dummy object that they
467
+ * would then assign to from within the lambda. With return value chaining,
468
+ * this pattern feels more natural
469
+ *
470
+ * Note that it is important to copy the entire callble into this class.
471
+ * Storing something like a reference instead is not desirable because it does
472
+ * not allow InlineFunctionRef to use inline storage to represent the user's
473
+ * callable without extra indirections
474
+ *
475
+ * We use std::conditional_t and switch to the right type of task with the
476
+ * CoalescedTask type alias
477
+ */
478
+ template <typename Func, typename Waiter>
479
+ class TaskWithCoalesce {
480
+ public:
481
+ using ReturnType = folly::invoke_result_t<const Func&>;
482
+ using StorageType = folly::Unit;
483
+ explicit TaskWithCoalesce(Func func, Waiter& waiter)
484
+ : func_{std::move(func)}, waiter_{waiter} {}
485
+
486
+ void operator()() const {
487
+ auto value = func_();
488
+ new (&waiter_.storage_) ReturnType{std::move(value)};
489
+ }
490
+
491
+ private:
492
+ Func func_;
493
+ Waiter& waiter_;
494
+
495
+ static_assert(!std::is_void<ReturnType>{}, "");
496
+ static_assert(alignof(decltype(waiter_.storage_)) >= alignof(ReturnType), "");
497
+ static_assert(sizeof(decltype(waiter_.storage_)) >= sizeof(ReturnType), "");
498
+ };
499
+
500
+ template <typename Func, typename Waiter>
501
+ class TaskWithoutCoalesce {
502
+ public:
503
+ using ReturnType = void;
504
+ using StorageType = folly::Unit;
505
+ explicit TaskWithoutCoalesce(Func func, Waiter&) : func_{std::move(func)} {}
506
+
507
+ void operator()() const { func_(); }
508
+
509
+ private:
510
+ Func func_;
511
+ };
512
+
513
+ template <typename Func, typename Waiter>
514
+ class TaskWithBigReturnValue {
515
+ public:
516
+ // Using storage that is aligned on the cacheline boundary helps us avoid a
517
+ // situation where the data ends up being allocated on two separate
518
+ // cachelines. This would require the remote thread to pull in both lines
519
+ // to issue a write.
520
+ //
521
+ // We also isolate the storage by appending some padding to the end to
522
+ // ensure we avoid false-sharing with the metadata used while the waiter
523
+ // waits
524
+ using ReturnType = folly::invoke_result_t<const Func&>;
525
+ static const auto kReturnValueAlignment = folly::constexpr_max(
526
+ alignof(ReturnType), folly::hardware_destructive_interference_size);
527
+ using StorageType =
528
+ folly::aligned_storage_t<sizeof(ReturnType), kReturnValueAlignment>;
529
+
530
+ explicit TaskWithBigReturnValue(Func func, Waiter&)
531
+ : func_{std::move(func)} {}
532
+
533
+ void operator()() const {
534
+ DCHECK(storage_);
535
+ auto value = func_();
536
+ new (storage_) ReturnType{std::move(value)};
537
+ }
538
+
539
+ void attach(StorageType* storage) {
540
+ DCHECK(!storage_);
541
+ storage_ = storage;
542
+ }
543
+
544
+ private:
545
+ Func func_;
546
+ StorageType* storage_{nullptr};
547
+
548
+ static_assert(!std::is_void<ReturnType>{}, "");
549
+ static_assert(sizeof(Waiter::storage_) < sizeof(ReturnType), "");
550
+ };
551
+
552
+ template <typename T, bool>
553
+ struct Sizeof_;
554
+ template <typename T>
555
+ struct Sizeof_<T, false> : index_constant<sizeof(T)> {};
556
+ template <typename T>
557
+ struct Sizeof_<T, true> : index_constant<0> {};
558
+ template <typename T>
559
+ struct Sizeof : Sizeof_<T, std::is_void<T>::value> {};
560
+
561
+ // we need to use std::integral_constant::value here as opposed to
562
+ // std::integral_constant::operator T() because MSVC errors out with the
563
+ // implicit conversion
564
+ template <typename Func, typename Waiter>
565
+ using CoalescedTask = std::conditional_t<
566
+ std::is_void<folly::invoke_result_t<const Func&>>::value,
567
+ TaskWithoutCoalesce<Func, Waiter>,
568
+ std::conditional_t<
569
+ Sizeof<folly::invoke_result_t<const Func&>>::value <=
570
+ sizeof(Waiter::storage_),
571
+ TaskWithCoalesce<Func, Waiter>,
572
+ TaskWithBigReturnValue<Func, Waiter>>>;
573
+
574
+ /**
575
+ * Given a request and a wait node, coalesce them into a CoalescedTask that
576
+ * coalesces the return value into the wait node when invoked from a remote
577
+ * thread
578
+ *
579
+ * When given a null request through nullptr_t, coalesce() returns null as well
580
+ */
581
+ template <typename Waiter>
582
+ std::nullptr_t coalesce(std::nullptr_t&, Waiter&) {
583
+ return nullptr;
584
+ }
585
+
586
+ template <
587
+ typename Request,
588
+ typename Waiter,
589
+ typename Func = typename Request::F>
590
+ CoalescedTask<Func, Waiter> coalesce(Request& request, Waiter& waiter) {
591
+ static_assert(!std::is_same<Request, std::nullptr_t>{}, "");
592
+ return CoalescedTask<Func, Waiter>{request.func_, waiter};
593
+ }
594
+
595
+ /**
596
+ * Given a task, create storage for the return value. When we get a type
597
+ * of CoalescedTask, this returns an instance of CoalescedTask::StorageType.
598
+ * std::nullptr_t otherwise
599
+ */
600
+ inline std::nullptr_t makeReturnValueStorageFor(std::nullptr_t&) {
601
+ return {};
602
+ }
603
+
604
+ template <
605
+ typename CoalescedTask,
606
+ typename StorageType = typename CoalescedTask::StorageType>
607
+ StorageType makeReturnValueStorageFor(CoalescedTask&) {
608
+ return {};
609
+ }
610
+
611
+ /**
612
+ * Given a task and storage, attach them together if needed. This only helps
613
+ * when we have a task that returns a value bigger than can be coalesced. In
614
+ * that case, we need to attach the storage with the task so the return value
615
+ * can be transferred to this thread from the remote thread
616
+ */
617
+ template <typename Task, typename Storage>
618
+ void attach(Task&, Storage&) {
619
+ static_assert(
620
+ std::is_same<Storage, std::nullptr_t>{} ||
621
+ std::is_same<Storage, folly::Unit>{},
622
+ "");
623
+ }
624
+
625
+ template <
626
+ typename R,
627
+ typename W,
628
+ typename StorageType = typename TaskWithBigReturnValue<R, W>::StorageType>
629
+ void attach(TaskWithBigReturnValue<R, W>& task, StorageType& storage) {
630
+ task.attach(&storage);
631
+ }
632
+
633
+ template <typename Request, typename Waiter>
634
+ void throwIfExceptionOccurred(Request&, Waiter& waiter, bool exception) {
635
+ using Storage = decltype(waiter.storage_);
636
+ using F = typename Request::F;
637
+ static_assert(sizeof(Storage) >= sizeof(std::exception_ptr), "");
638
+ static_assert(alignof(Storage) >= alignof(std::exception_ptr), "");
639
+
640
+ // we only need to check for an exception in the waiter struct if the passed
641
+ // callable is not noexcept
642
+ //
643
+ // we need to make another instance of the exception with automatic storage
644
+ // duration and destroy the exception held in the storage *before throwing* to
645
+ // avoid leaks. If we don't destroy the exception_ptr in storage, the
646
+ // refcount for the internal exception will never hit zero, thereby leaking
647
+ // memory
648
+ if (FOLLY_UNLIKELY(!folly::is_nothrow_invocable_v<const F&> && exception)) {
649
+ auto storage = &waiter.storage_;
650
+ auto exc = std::launder(reinterpret_cast<std::exception_ptr*>(storage));
651
+ auto copy = std::move(*exc);
652
+ exc->std::exception_ptr::~exception_ptr();
653
+ std::rethrow_exception(std::move(copy));
654
+ }
655
+ }
656
+
657
+ /**
658
+ * Given a CoalescedTask, a wait node and a request. Detach the return value
659
+ * into the request from the wait node and task.
660
+ */
661
+ template <typename Waiter>
662
+ void detach(std::nullptr_t&, Waiter&, bool exception, std::nullptr_t&) {
663
+ DCHECK(!exception);
664
+ }
665
+
666
+ template <typename Waiter, typename F>
667
+ void detach(
668
+ RequestWithoutReturn<F>& request,
669
+ Waiter& waiter,
670
+ bool exception,
671
+ folly::Unit&) {
672
+ throwIfExceptionOccurred(request, waiter, exception);
673
+ }
674
+
675
+ template <typename Waiter, typename F>
676
+ void detach(
677
+ RequestWithReturn<F>& request,
678
+ Waiter& waiter,
679
+ bool exception,
680
+ folly::Unit&) {
681
+ throwIfExceptionOccurred(request, waiter, exception);
682
+
683
+ using ReturnType = typename RequestWithReturn<F>::ReturnType;
684
+ static_assert(!std::is_same<ReturnType, void>{}, "");
685
+ static_assert(sizeof(waiter.storage_) >= sizeof(ReturnType), "");
686
+
687
+ auto& val = *std::launder(reinterpret_cast<ReturnType*>(&waiter.storage_));
688
+ new (&request.value_) ReturnType{std::move(val)};
689
+ val.~ReturnType();
690
+ }
691
+
692
+ template <typename Waiter, typename F, typename Storage>
693
+ void detach(
694
+ RequestWithReturn<F>& request,
695
+ Waiter& waiter,
696
+ bool exception,
697
+ Storage& storage) {
698
+ throwIfExceptionOccurred(request, waiter, exception);
699
+
700
+ using ReturnType = typename RequestWithReturn<F>::ReturnType;
701
+ static_assert(!std::is_same<ReturnType, void>{}, "");
702
+ static_assert(sizeof(storage) >= sizeof(ReturnType), "");
703
+
704
+ auto& val = *std::launder(reinterpret_cast<ReturnType*>(&storage));
705
+ new (&request.value_) ReturnType{std::move(val)};
706
+ val.~ReturnType();
707
+ }
708
+
709
+ /**
710
+ * Get the time since epoch in CPU cycles
711
+ *
712
+ * This is faster than std::chrono::steady_clock because it avoids a VDSO
713
+ * access to get the timestamp counter
714
+ *
715
+ * Note that the hardware timestamp counter on x86, like std::steady_clock is
716
+ * guaranteed to be monotonically increasing -
717
+ * https://c9x.me/x86/html/file_module_x86_id_278.html
718
+ */
719
+ inline CpuTicks time() {
720
+ return static_cast<CpuTicks>(hardware_timestamp());
721
+ }
722
+
723
+ /**
724
+ * Zero out the other bits used by the implementation and return just an
725
+ * address from a uintptr_t
726
+ */
727
+ template <typename Type>
728
+ Type* extractPtr(std::uintptr_t from) {
729
+ // shift one bit off the end, to get all 1s followed by a single 0
730
+ auto mask = std::numeric_limits<std::uintptr_t>::max();
731
+ mask >>= 1;
732
+ mask <<= 1;
733
+ CHECK(!(mask & 0b1));
734
+
735
+ return folly::bit_cast<Type*>(from & mask);
736
+ }
737
+
738
+ /**
739
+ * Strips the given CPU timestamp into only the least significant 56 bits by
740
+ * moving the least significant 56 bits over by 8 zeroing out the bottom 8
741
+ * bits to be used as a medium of information transfer for the thread wait
742
+ * nodes
743
+ */
744
+ inline std::uint64_t strip(CpuTicks time) {
745
+ return static_cast<std::uint64_t>(time) << 8;
746
+ }
747
+
748
+ /**
749
+ * Recover the timestamp value from an integer that has the timestamp encoded
750
+ * in it
751
+ */
752
+ inline std::uint64_t recover(std::uint64_t from) {
753
+ return from >> 8;
754
+ }
755
+
756
+ template <template <typename> class Atomic, bool TimePublishing>
757
+ class DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy {
758
+ public:
759
+ DistributedMutexStateProxy() = default;
760
+
761
+ DistributedMutexStateProxy(DistributedMutexStateProxy const&) = default;
762
+ DistributedMutexStateProxy& operator=(DistributedMutexStateProxy const&) =
763
+ default;
764
+
765
+ // The proxy is valid when a mutex acquisition attempt was successful,
766
+ // lock() is guaranteed to return a valid proxy, try_lock() is not
767
+ explicit operator bool() const { return expected_; }
768
+
769
+ // private:
770
+ // friend the mutex class, since that will be accessing state private to
771
+ // this class
772
+ friend class DistributedMutex<Atomic, TimePublishing>;
773
+
774
+ DistributedMutexStateProxy(
775
+ Waiter<Atomic>* next,
776
+ std::uintptr_t expected,
777
+ bool timedWaiter = false,
778
+ bool combined = false,
779
+ std::uintptr_t waker = 0,
780
+ Waiter<Atomic>* waiters = nullptr,
781
+ Waiter<Atomic>* ready = nullptr)
782
+ : next_{next},
783
+ expected_{expected},
784
+ timedWaiters_{timedWaiter},
785
+ combined_{combined},
786
+ waker_{waker},
787
+ waiters_{waiters},
788
+ ready_{ready} {}
789
+
790
+ // the next thread that is to be woken up, this being null at the time of
791
+ // unlock() shows that the current thread acquired the mutex without
792
+ // contention or it was the terminal thread in the queue of threads waking up
793
+ Waiter<Atomic>* next_{nullptr};
794
+ // this is the value that the current thread should expect to find on
795
+ // unlock, and if this value is not there on unlock, the current thread
796
+ // should assume that other threads are enqueued waiting for the mutex
797
+ //
798
+ // note that if the mutex has the same state set at unlock time, and this is
799
+ // set to an address (and not say kLocked in the case of a terminal waker)
800
+ // then it must have been the case that no other thread had enqueued itself,
801
+ // since threads in the domain of this mutex do not share stack space
802
+ //
803
+ // if we want to support stack sharing, we can solve the problem by looping
804
+ // at lock time, and setting a variable that says whether we have acquired
805
+ // the lock or not perhaps
806
+ std::uintptr_t expected_{0};
807
+ // a boolean that will be set when the mutex has timed waiters that the
808
+ // current thread is responsible for waking, in such a case, the current
809
+ // thread will issue an atomic_notify_one() call after unlocking the mutex
810
+ //
811
+ // note that a timed waiter will itself always have this flag set. This is
812
+ // done so we can avoid having to issue a atomic_notify_all() call (and
813
+ // subsequently a thundering herd) when waking up timed-wait threads
814
+ bool timedWaiters_{false};
815
+ // a boolean that contains true if the state proxy is not meant to be passed
816
+ // to the unlock() function. This is set only when there is contention and
817
+ // a thread had asked for its critical section to be combined
818
+ bool combined_{false};
819
+ // metadata passed along from the thread that woke this thread up
820
+ std::uintptr_t waker_{0};
821
+ // the list of threads that are waiting on a futex
822
+ //
823
+ // the current threads is meant to wake up this list of waiters if it is
824
+ // able to commit an unlock() on the mutex without seeing a contention chain
825
+ Waiter<Atomic>* waiters_{nullptr};
826
+ // after a thread has woken up from a futex() call, it will have the rest of
827
+ // the threads that it were waiting behind it in this list, a thread that
828
+ // unlocks has to wake up threads from this list if it has any, before it
829
+ // goes to sleep to prevent pathological unfairness
830
+ Waiter<Atomic>* ready_{nullptr};
831
+ };
832
+
833
+ template <template <typename> class Atomic, bool TimePublishing>
834
+ DistributedMutex<Atomic, TimePublishing>::DistributedMutex()
835
+ : state_{kUnlocked} {}
836
+
837
+ template <typename Waiter>
838
+ std::uint64_t publish(
839
+ std::uint64_t spins,
840
+ CpuTicks current,
841
+ CpuTicks previous,
842
+ CpuTicks elapsed,
843
+ bool& shouldPublish,
844
+ Waiter& waiter,
845
+ std::uint32_t waitMode) {
846
+ // time publishing has some overhead because it executes an atomic exchange on
847
+ // the futex word. If this line is in a remote thread (eg. the combiner),
848
+ // then each time we publish a timestamp, this thread has to submit an RFO to
849
+ // the remote core for the cacheline, blocking progress for both threads.
850
+ //
851
+ // the remote core uses a store in the fast path - why then does an RFO make a
852
+ // difference? The only educated guess we have here is that the added
853
+ // roundtrip delays draining of the store buffer, which essentially exerts
854
+ // backpressure on future stores, preventing parallelization
855
+ //
856
+ // if we have requested a combine, time publishing is less important as it
857
+ // only comes into play when the combiner has exhausted their max combine
858
+ // passes. So we defer time publishing to the point when the current thread
859
+ // gets preempted
860
+ if (previous != CpuTicks{0} &&
861
+ (current - previous) >= kScheduledAwaySpinThreshold) {
862
+ shouldPublish = true;
863
+ }
864
+
865
+ // if we have requested a combine, and this is the first iteration of the
866
+ // wait-loop, we publish a max timestamp to optimistically convey that we have
867
+ // not yet been preempted (the remote knows the meaning of max timestamps)
868
+ //
869
+ // then if we are under the maximum number of spins allowed before sleeping,
870
+ // we publish the exact timestamp, otherwise we publish the minimum possible
871
+ // timestamp to force the waking thread to skip us
872
+ auto now = ((waitMode == kCombineWaiting) && !spins)
873
+ ? std::numeric_limits<CpuTicks>::max()
874
+ : (elapsed < kMaxSpinTime) ? current
875
+ : CpuTicks{0};
876
+ // the wait mode information is published in the bottom 8 bits of the futex
877
+ // word, the rest contains time information as computed above. Overflows are
878
+ // not really a correctness concern because time publishing is only a
879
+ // heuristic. This leaves us 56 bits of nanoseconds (2 years) before we hit
880
+ // two consecutive wraparounds, so the lack of bits to respresent time is
881
+ // neither a performance nor correctness concern
882
+ auto data = strip(now) | waitMode;
883
+ auto signal = (shouldPublish || !spins || (waitMode != kCombineWaiting))
884
+ ? waiter.futex_.exchange(data, std::memory_order_acq_rel)
885
+ : waiter.futex_.load(std::memory_order_acquire);
886
+ return signal & std::numeric_limits<std::uint8_t>::max();
887
+ }
888
+
889
+ template <typename Waiter>
890
+ bool spin(Waiter& waiter, std::uint32_t& sig, std::uint32_t mode) {
891
+ auto spins = std::uint64_t{0};
892
+ auto waitMode = (mode == kCombineUninitialized) ? kCombineWaiting : kWaiting;
893
+ auto previous = CpuTicks{0};
894
+ auto shouldPublish = false;
895
+ // elapsed is unsigned and will intentionally underflows if time goes back
896
+ for (CpuTicks start = time(), current = start, elapsed = 0;;
897
+ previous = current, current = time(), elapsed = current - start) {
898
+ auto signal = publish(
899
+ spins++, current, previous, elapsed, shouldPublish, waiter, waitMode);
900
+
901
+ // if we got skipped, make a note of it and return if we got a skipped
902
+ // signal or a signal to wake up
903
+ auto skipped = (signal == kSkipped);
904
+ auto combined = (signal == kCombined);
905
+ auto exceptionOccurred = (signal == kExceptionOccurred);
906
+ auto woken = (signal == kWake);
907
+ if (skipped || woken || combined || exceptionOccurred) {
908
+ sig = static_cast<std::uint32_t>(signal);
909
+ return !skipped;
910
+ }
911
+
912
+ // if we are under the spin threshold, pause to allow the other
913
+ // hyperthread to run. If not, then sleep
914
+ if (elapsed < kMaxSpinTime) {
915
+ asm_volatile_pause();
916
+ } else {
917
+ std::this_thread::sleep_for(folly::detail::Sleeper::kMinYieldingSleep);
918
+ }
919
+ }
920
+ }
921
+
922
+ template <typename Waiter>
923
+ void doFutexWake(Waiter* waiter) {
924
+ if (waiter) {
925
+ // We can use a simple store operation here and not worry about checking
926
+ // to see if the thread had actually started waiting on the futex, that is
927
+ // already done in tryWake() when a sleeping thread is collected
928
+ //
929
+ // We now do not know whether the waiter had already enqueued on the futex
930
+ // or whether it had just stored kSleeping in its futex and was about to
931
+ // call futexWait(). We treat both these scenarios the same
932
+ //
933
+ // the below can theoretically cause a problem if we set the
934
+ // wake signal and the waiter was in between setting kSleeping in its
935
+ // futex and enqueueing on the futex. In this case the waiter will just
936
+ // return from futexWait() immediately. This leaves the address that the
937
+ // waiter was using for futexWait() possibly dangling, and the thread that
938
+ // we woke in the exchange above might have used that address for some
939
+ // other object
940
+ //
941
+ // however, even if the thread had indeed woken up simply becasue of the
942
+ // above exchange(), the futexWake() below is not incorrect. It is not
943
+ // incorrect because futexWake() does not actually change the memory of
944
+ // the futex word. It just uses the address to do a lookup in the kernel
945
+ // futex table. And even if we call futexWake() on some other address,
946
+ // and that address was being used to wait on futex() that thread will
947
+ // protect itself from spurious wakeups, check the value in the futex word
948
+ // and enqueue itself back on the futex
949
+ //
950
+ // this dangilng pointer possibility is why we use a pointer to the futex
951
+ // word, and avoid dereferencing after the store() operation
952
+ auto sleeper = &waiter->metadata_.sleeper_;
953
+ sleeper->store(kWake, std::memory_order_release);
954
+ futexWake(sleeper, 1);
955
+ }
956
+ }
957
+
958
+ template <typename Waiter>
959
+ bool doFutexWait(Waiter* waiter, Waiter*& next) {
960
+ // first we get ready to sleep by calling exchange() on the futex with a
961
+ // kSleeping value
962
+ DCHECK(waiter->futex_.load(std::memory_order_relaxed) == kAboutToWait);
963
+
964
+ // note the semantics of using a futex here, when we exchange the sleeper_
965
+ // with kSleeping, we are getting ready to sleep, but before sleeping we get
966
+ // ready to sleep, and we return from futexWait() when the value of
967
+ // sleeper_ might have changed. We can also wake up because of a spurious
968
+ // wakeup, so we always check against the value in sleeper_ after returning
969
+ // from futexWait(), if the value is not kWake, then we continue
970
+ auto pre =
971
+ waiter->metadata_.sleeper_.exchange(kSleeping, std::memory_order_acq_rel);
972
+
973
+ // Seeing a kSleeping on a futex word before we set it ourselves means only
974
+ // one thing - an unlocking thread caught us before we went to futex(), and
975
+ // we now have the lock, so we abort
976
+ //
977
+ // if we were given an early delivery, we can return from this function with
978
+ // a true, meaning that we now have the lock
979
+ if (pre == kSleeping) {
980
+ return true;
981
+ }
982
+
983
+ // if we reach here then were were not given an early delivery, and any
984
+ // thread that goes to wake us up will see a consistent view of the rest of
985
+ // the contention chain (since the next_ variable is set before the
986
+ // kSleeping exchange above)
987
+ while (pre != kWake) {
988
+ // before enqueueing on the futex, we wake any waiters that we were
989
+ // possibly responsible for
990
+ doFutexWake(std::exchange(next, nullptr));
991
+
992
+ // then we wait on the futex
993
+ //
994
+ // note that we have to protect ourselves against spurious wakeups here.
995
+ // Because the corresponding futexWake() above does not synchronize
996
+ // wakeups around the futex word. Because doing so would become
997
+ // inefficient
998
+ futexWait(&waiter->metadata_.sleeper_, kSleeping);
999
+ pre = waiter->metadata_.sleeper_.load(std::memory_order_acquire);
1000
+ DCHECK((pre == kSleeping) || (pre == kWake));
1001
+ }
1002
+
1003
+ // when coming out of a futex, we might have some other sleeping threads
1004
+ // that we were supposed to wake up, assign that to the next pointer
1005
+ DCHECK(next == nullptr);
1006
+ next = extractPtr<Waiter>(waiter->next_.load(std::memory_order_relaxed));
1007
+ return false;
1008
+ }
1009
+
1010
+ template <typename Waiter>
1011
+ bool wait(Waiter* waiter, std::uint32_t mode, Waiter*& next, uint32_t& signal) {
1012
+ if (mode == kAboutToWait) {
1013
+ return doFutexWait(waiter, next);
1014
+ }
1015
+
1016
+ return spin(*waiter, signal, mode);
1017
+ }
1018
+
1019
+ inline void recordTimedWaiterAndClearTimedBit(
1020
+ bool& timedWaiter, std::uintptr_t& previous) {
1021
+ // the previous value in the mutex can never be kTimedWaiter, timed waiters
1022
+ // always set (kTimedWaiter | kLocked) in the mutex word when they try and
1023
+ // acquire the mutex
1024
+ DCHECK(previous != kTimedWaiter);
1025
+
1026
+ if (FOLLY_UNLIKELY(previous & kTimedWaiter)) {
1027
+ // record whether there was a timed waiter in the previous mutex state, and
1028
+ // clear the timed bit from the previous state
1029
+ timedWaiter = true;
1030
+ previous = previous & (~kTimedWaiter);
1031
+ }
1032
+ }
1033
+
1034
+ template <typename Atomic>
1035
+ void wakeTimedWaiters(Atomic* state, bool timedWaiters) {
1036
+ if (FOLLY_UNLIKELY(timedWaiters)) {
1037
+ folly::atomic_notify_one(state); // evade ADL
1038
+ }
1039
+ }
1040
+
1041
+ template <template <typename> class Atomic, bool TimePublishing>
1042
+ template <typename Func>
1043
+ auto DistributedMutex<Atomic, TimePublishing>::lock_combine(Func func)
1044
+ -> folly::invoke_result_t<const Func&> {
1045
+ // invoke the lock implementation function and check whether we came out of
1046
+ // it with our task executed as a combined critical section. This usually
1047
+ // happens when the mutex is contended.
1048
+ //
1049
+ // In the absence of contention, we just return from the try_lock() function
1050
+ // with the lock acquired. So we need to invoke the task and unlock
1051
+ // the mutex before returning
1052
+ auto&& task = Request<Func>{func};
1053
+ auto&& state = lockImplementation(*this, state_, task);
1054
+ if (!state.combined_) {
1055
+ // to avoid having to play a return-value dance when the combinable
1056
+ // returns void, we use a scope exit to perform the unlock after the
1057
+ // function return has been processed
1058
+ SCOPE_EXIT {
1059
+ unlock(std::move(state));
1060
+ };
1061
+ return func();
1062
+ }
1063
+
1064
+ // if we are here, that means we were able to get our request combined, we
1065
+ // can return the value that was transferred to us
1066
+ //
1067
+ // each thread that enqueues as a part of a contention chain takes up the
1068
+ // responsibility of any timed waiter that had come immediately before it,
1069
+ // so we wake up timed waiters before exiting the lock function. Another
1070
+ // strategy might be to add the timed waiter information to the metadata and
1071
+ // let a single leader wake up a timed waiter for better concurrency. But
1072
+ // this has proven not to be useful in benchmarks beyond a small 5% delta,
1073
+ // so we avoid taking the complexity hit and branch to wake up timed waiters
1074
+ // from each thread
1075
+ wakeTimedWaiters(&state_, state.timedWaiters_);
1076
+ return std::move(task).get();
1077
+ }
1078
+
1079
+ template <template <typename> class Atomic, bool TimePublishing>
1080
+ typename DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy
1081
+ DistributedMutex<Atomic, TimePublishing>::lock() {
1082
+ auto null = nullptr;
1083
+ return lockImplementation(*this, state_, null);
1084
+ }
1085
+
1086
+ template <template <typename> class Atomic, bool TimePublishing>
1087
+ template <typename Rep, typename Period, typename Func>
1088
+ folly::Optional<invoke_result_t<Func&>>
1089
+ DistributedMutex<Atomic, TimePublishing>::try_lock_combine_for(
1090
+ const std::chrono::duration<Rep, Period>& duration, Func func) {
1091
+ auto state = try_lock_for(duration);
1092
+ if (state) {
1093
+ SCOPE_EXIT {
1094
+ unlock(std::move(state));
1095
+ };
1096
+ return func();
1097
+ }
1098
+
1099
+ return folly::none;
1100
+ }
1101
+
1102
+ template <template <typename> class Atomic, bool TimePublishing>
1103
+ template <typename Clock, typename Duration, typename Func>
1104
+ folly::Optional<invoke_result_t<Func&>>
1105
+ DistributedMutex<Atomic, TimePublishing>::try_lock_combine_until(
1106
+ const std::chrono::time_point<Clock, Duration>& deadline, Func func) {
1107
+ auto state = try_lock_until(deadline);
1108
+ if (state) {
1109
+ SCOPE_EXIT {
1110
+ unlock(std::move(state));
1111
+ };
1112
+ return func();
1113
+ }
1114
+
1115
+ return folly::none;
1116
+ }
1117
+
1118
+ template <typename Atomic, template <typename> class A, bool T>
1119
+ auto tryLockNoLoad(Atomic& atomic, DistributedMutex<A, T>&) {
1120
+ // Try and set the least significant bit of the centralized lock state to 1,
1121
+ // if this succeeds, it must have been the case that we had a kUnlocked (or
1122
+ // 0) in the central storage before, since that is the only case where a 0
1123
+ // can be found in the least significant bit
1124
+ //
1125
+ // If this fails, then it is a no-op
1126
+ using Proxy = typename DistributedMutex<A, T>::DistributedMutexStateProxy;
1127
+ auto previous = atomic_fetch_set(atomic, 0, std::memory_order_acquire);
1128
+ return Proxy{nullptr, previous ? 0 : kLocked};
1129
+ }
1130
+
1131
+ template <template <typename> class Atomic, bool TimePublishing>
1132
+ typename DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy
1133
+ DistributedMutex<Atomic, TimePublishing>::try_lock() {
1134
+ // The lock attempt below requires an expensive atomic fetch-and-mutate or
1135
+ // an even more expensive atomic compare-and-swap loop depending on the
1136
+ // platform. These operations require pulling the lock cacheline into the
1137
+ // current core in exclusive mode and are therefore hard to parallelize
1138
+ //
1139
+ // This probabilistically avoids the expense by first checking whether the
1140
+ // mutex is currently locked
1141
+ if (state_.load(std::memory_order_relaxed) != kUnlocked) {
1142
+ return DistributedMutexStateProxy{nullptr, 0};
1143
+ }
1144
+
1145
+ return tryLockNoLoad(state_, *this);
1146
+ }
1147
+
1148
+ template <
1149
+ template <typename>
1150
+ class Atomic,
1151
+ bool TimePublishing,
1152
+ typename State,
1153
+ typename Request>
1154
+ typename DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy
1155
+ lockImplementation(
1156
+ DistributedMutex<Atomic, TimePublishing>& mutex,
1157
+ State& atomic,
1158
+ Request& request) {
1159
+ // first try and acquire the lock as a fast path, the underlying
1160
+ // implementation is slightly faster than using std::atomic::exchange() as
1161
+ // is used in this function. So we get a small perf boost in the
1162
+ // uncontended case
1163
+ //
1164
+ // We only go through this fast path for the lock/unlock usage and avoid this
1165
+ // for combined critical sections. This check adds unnecessary overhead in
1166
+ // that case as it causes an extra cacheline bounce
1167
+ constexpr auto combineRequested = !std::is_same<Request, std::nullptr_t>{};
1168
+ if (!combineRequested) {
1169
+ if (auto state = tryLockNoLoad(atomic, mutex)) {
1170
+ return state;
1171
+ }
1172
+ }
1173
+
1174
+ auto previous = std::uintptr_t{0};
1175
+ auto waitMode = combineRequested ? kCombineUninitialized : kUninitialized;
1176
+ auto nextWaitMode = kAboutToWait;
1177
+ auto timedWaiter = false;
1178
+ Waiter<Atomic>* nextSleeper = nullptr;
1179
+ while (true) {
1180
+ // construct the state needed to wait
1181
+ //
1182
+ // We can't use auto here because MSVC errors out due to a missing copy
1183
+ // constructor
1184
+ Waiter<Atomic> state{};
1185
+ auto&& task = coalesce(request, state);
1186
+ auto&& storage = makeReturnValueStorageFor(task);
1187
+ auto&& address = folly::bit_cast<std::uintptr_t>(&state);
1188
+ attach(task, storage);
1189
+ state.initialize(waitMode, std::move(task));
1190
+ DCHECK(!(address & 0b1));
1191
+
1192
+ // set the locked bit in the address we will be persisting in the mutex
1193
+ address |= kLocked;
1194
+
1195
+ // attempt to acquire the mutex, mutex acquisition is successful if the
1196
+ // previous value is zeroed out
1197
+ //
1198
+ // we use memory_order_acq_rel here because we want the read-modify-write
1199
+ // operation to be both acquire and release. Acquire because if this is a
1200
+ // successful lock acquisition, we want to acquire state any other thread
1201
+ // has released from a prior unlock. We want release semantics because
1202
+ // other threads that read the address of this value should see the full
1203
+ // well-initialized node we are going to wait on if the mutex acquisition
1204
+ // was unsuccessful
1205
+ previous = atomic.exchange(address, std::memory_order_acq_rel);
1206
+ recordTimedWaiterAndClearTimedBit(timedWaiter, previous);
1207
+ state.next_.store(previous, std::memory_order_relaxed);
1208
+ if (previous == kUnlocked) {
1209
+ return {
1210
+ /* next */ nullptr,
1211
+ /* expected */ address,
1212
+ /* timedWaiter */ timedWaiter,
1213
+ /* combined */ false,
1214
+ /* waker */ 0,
1215
+ /* waiters */ nullptr,
1216
+ /* ready */ nextSleeper};
1217
+ }
1218
+ DCHECK(previous & kLocked);
1219
+
1220
+ // wait until we get a signal from another thread, if this returns false,
1221
+ // we got skipped and had probably been scheduled out, so try again
1222
+ auto signal = kUninitialized;
1223
+ if (!wait(&state, waitMode, nextSleeper, signal)) {
1224
+ std::swap(waitMode, nextWaitMode);
1225
+ continue;
1226
+ }
1227
+
1228
+ // at this point it is safe to access the other fields in the waiter state,
1229
+ // since the thread that woke us up is gone and nobody will be touching this
1230
+ // state again, note that this requires memory ordering, and this is why we
1231
+ // use memory_order_acquire (among other reasons) in the above wait
1232
+ //
1233
+ // first we see if the value we took off the mutex state was the thread that
1234
+ // initated the wakeups, if so, we are the terminal node of the current
1235
+ // contention chain. If we are the terminal node, then we should expect to
1236
+ // see a kLocked in the mutex state when we unlock, if we see that, we can
1237
+ // commit the unlock to the centralized mutex state. If not, we need to
1238
+ // continue wakeups
1239
+ //
1240
+ // a nice consequence of passing kLocked as the current address if we are
1241
+ // the terminal node is that it naturally just works with the algorithm. If
1242
+ // we get a contention chain when coming out of a contention chain, the tail
1243
+ // of the new contention chain will have kLocked set as the previous, which,
1244
+ // as it happens "just works", since we have now established a recursive
1245
+ // relationship until broken
1246
+ auto next = previous;
1247
+ auto expected = address;
1248
+ if (previous == state.metadata_.waker_) {
1249
+ next = 0;
1250
+ expected = kLocked;
1251
+ }
1252
+
1253
+ // if we were given a combine signal, detach the return value from the
1254
+ // wait struct into the request, so the current thread can access it
1255
+ // outside this function
1256
+ auto combined = (signal == kCombined);
1257
+ auto exceptionOccurred = (signal == kExceptionOccurred);
1258
+ if (combined || exceptionOccurred) {
1259
+ detach(request, state, exceptionOccurred, storage);
1260
+ }
1261
+
1262
+ // if we are just coming out of a futex call, then it means that the next
1263
+ // waiter we are responsible for is also a waiter waiting on a futex, so
1264
+ // we return that list in the list of ready threads. We wlil be waking up
1265
+ // the ready threads on unlock no matter what
1266
+ return {
1267
+ /* next */ extractPtr<Waiter<Atomic>>(next),
1268
+ /* expected */ expected,
1269
+ /* timedWaiter */ timedWaiter,
1270
+ /* combined */ combineRequested && (combined || exceptionOccurred),
1271
+ /* waker */ state.metadata_.waker_,
1272
+ /* waiters */ extractPtr<Waiter<Atomic>>(state.metadata_.waiters_),
1273
+ /* ready */ nextSleeper};
1274
+ }
1275
+ }
1276
+
1277
+ inline bool preempted(std::uint64_t value, CpuTicks now) {
1278
+ auto currentTime = recover(strip(now));
1279
+ auto nodeTime = recover(value);
1280
+ auto preempted = (currentTime > nodeTime + kScheduledAwaySpinThreshold) &&
1281
+ (nodeTime != recover(strip(std::numeric_limits<CpuTicks>::max())));
1282
+
1283
+ // we say that the thread has been preempted if its timestamp says so, and
1284
+ // also if it is neither uninitialized nor skipped
1285
+ DCHECK(value != kSkipped);
1286
+ return (preempted) && (value != kUninitialized) &&
1287
+ (value != kCombineUninitialized);
1288
+ }
1289
+
1290
+ inline bool isSleeper(std::uintptr_t value) {
1291
+ return (value == kAboutToWait);
1292
+ }
1293
+
1294
+ inline bool isInitialized(std::uintptr_t value) {
1295
+ return (value != kUninitialized) && (value != kCombineUninitialized);
1296
+ }
1297
+
1298
+ inline bool isCombiner(std::uintptr_t value) {
1299
+ auto mode = (value & 0xff);
1300
+ return (mode == kCombineWaiting) || (mode == kCombineUninitialized);
1301
+ }
1302
+
1303
+ inline bool isWaitingCombiner(std::uintptr_t value) {
1304
+ return (value & 0xff) == kCombineWaiting;
1305
+ }
1306
+
1307
+ template <typename Waiter>
1308
+ CombineFunction loadTask(Waiter* current, std::uintptr_t value) {
1309
+ // if we know that the waiter is a combiner of some sort, it is safe to read
1310
+ // and copy the value of the function in the waiter struct, since we know
1311
+ // that a waiter would have set it before enqueueing
1312
+ if (isCombiner(value)) {
1313
+ return current->function_;
1314
+ }
1315
+
1316
+ return nullptr;
1317
+ }
1318
+
1319
+ template <typename Waiter>
1320
+ [[FOLLY_ATTR_GNU_COLD]] void transferCurrentException(Waiter* waiter) {
1321
+ DCHECK(current_exception());
1322
+ new (&waiter->storage_) std::exception_ptr{current_exception()};
1323
+ waiter->futex_.store(kExceptionOccurred, std::memory_order_release);
1324
+ }
1325
+
1326
+ template <template <typename> class Atomic>
1327
+ FOLLY_ALWAYS_INLINE std::uintptr_t tryCombine(
1328
+ Waiter<Atomic>* waiter,
1329
+ std::uintptr_t value,
1330
+ std::uintptr_t next,
1331
+ std::uint64_t iteration,
1332
+ CpuTicks now,
1333
+ CombineFunction task) {
1334
+ // if the waiter has asked for a combine operation, we should combine its
1335
+ // critical section and move on to the next waiter
1336
+ //
1337
+ // the waiter is combinable if the following conditions are satisfied
1338
+ //
1339
+ // 1) the state in the futex word is not uninitialized (kUninitialized)
1340
+ // 2) it has a valid combine function
1341
+ // 3) we are not past the limit of the number of combines we can perform
1342
+ // or the waiter thread been preempted. If the waiter gets preempted,
1343
+ // its better to just execute their critical section before moving on.
1344
+ // As they will have to re-queue themselves after preemption anyway,
1345
+ // leading to further delays in critical section completion
1346
+ //
1347
+ // if all the above are satisfied, then we can combine the critical section.
1348
+ // Note that if the waiter is in a combineable state, that means that it had
1349
+ // finished its writes to both the task and the next_ value. And observing
1350
+ // a waiting state also means that we have acquired the writes to the other
1351
+ // members of the waiter struct, so it's fine to use those values here
1352
+ if (isWaitingCombiner(value) &&
1353
+ (iteration <= kMaxCombineIterations || preempted(value, now))) {
1354
+ catch_exception(
1355
+ [&] {
1356
+ task();
1357
+ waiter->futex_.store(kCombined, std::memory_order_release);
1358
+ },
1359
+ [&] { transferCurrentException(waiter); });
1360
+ return next;
1361
+ }
1362
+
1363
+ return 0;
1364
+ }
1365
+
1366
+ template <typename Waiter>
1367
+ FOLLY_ALWAYS_INLINE std::uintptr_t tryWake(
1368
+ bool publishing,
1369
+ Waiter* waiter,
1370
+ std::uintptr_t value,
1371
+ std::uintptr_t next,
1372
+ std::uintptr_t waker,
1373
+ Waiter*& sleepers,
1374
+ std::uint64_t iteration,
1375
+ CombineFunction task) {
1376
+ // try and combine the waiter's request first, if that succeeds that means
1377
+ // we have successfully executed their critical section and can move on to
1378
+ // the rest of the chain
1379
+ auto now = time();
1380
+ if (tryCombine(waiter, value, next, iteration, now, task)) {
1381
+ return next;
1382
+ }
1383
+
1384
+ // first we see if we can wake the current thread that is spinning
1385
+ if ((!publishing || !preempted(value, now)) && !isSleeper(value)) {
1386
+ // the Metadata class should be trivially destructible as we use placement
1387
+ // new to set the relevant metadata without calling any destructor. We
1388
+ // need to use placement new because the class contains a futex, which is
1389
+ // non-movable and non-copyable
1390
+ using Metadata = std::decay_t<decltype(waiter->metadata_)>;
1391
+ static_assert(std::is_trivially_destructible<Metadata>{}, "");
1392
+
1393
+ // we need release here because of the write to waker_ and also because we
1394
+ // are unlocking the mutex, the thread we do the handoff to here should
1395
+ // see the modified data
1396
+ new (&waiter->metadata_)
1397
+ Metadata{waker, folly::bit_cast<uintptr_t>(sleepers)};
1398
+ waiter->futex_.store(kWake, std::memory_order_release);
1399
+ return 0;
1400
+ }
1401
+
1402
+ // if the thread is not a sleeper, and we were not able to catch it before
1403
+ // preemption, we can just return a false, it is safe to read next_ because
1404
+ // the thread was preempted. Preemption signals can only come after the
1405
+ // thread has set the next_ pointer, since the timestamp writes only start
1406
+ // occurring after that point
1407
+ //
1408
+ // if a thread was preempted it must have stored next_ in the waiter struct,
1409
+ // as the store to futex_ that resets the value from kUninitialized happens
1410
+ // after the write to next
1411
+ CHECK(publishing);
1412
+ if (!isSleeper(value)) {
1413
+ // go on to the next one
1414
+ //
1415
+ // Also, we need a memory_order_release here to prevent missed wakeups. A
1416
+ // missed wakeup here can happen when we see that a thread had been
1417
+ // preempted and skip it. Then go on to release the lock, and then when
1418
+ // the thread which got skipped does an exchange on the central storage,
1419
+ // still sees the locked bit, and never gets woken up
1420
+ //
1421
+ // Can we relax this?
1422
+ DCHECK(preempted(value, now));
1423
+ DCHECK(!isCombiner(value));
1424
+ next = waiter->next_.load(std::memory_order_relaxed);
1425
+ waiter->futex_.store(kSkipped, std::memory_order_release);
1426
+ return next;
1427
+ }
1428
+
1429
+ // if we are here the thread is a sleeper
1430
+ //
1431
+ // we attempt to catch the thread before it goes to futex(). If we are able
1432
+ // to catch the thread before it sleeps on a futex, we are done, and don't
1433
+ // need to go any further
1434
+ //
1435
+ // if we are not able to catch the thread before it goes to futex, we
1436
+ // collect the current thread in the list of sleeping threads represented by
1437
+ // sleepers, and return the next thread in the list and return false along
1438
+ // with the previous next value
1439
+ //
1440
+ // it is safe to read the next_ pointer in the waiter struct if we were
1441
+ // unable to catch the thread before it went to futex() because we use
1442
+ // acquire-release ordering for the exchange operation below. And if we see
1443
+ // that the thread was already sleeping, we have synchronized with the write
1444
+ // to next_ in the context of the sleeping thread
1445
+ //
1446
+ // Also we need to set the value of waiters_ and waker_ in the thread before
1447
+ // doing the exchange because we need to pass on the list of sleepers in the
1448
+ // event that we were able to catch the thread before it went to futex().
1449
+ // If we were unable to catch the thread before it slept, these fields will
1450
+ // be ignored when the thread wakes up anyway
1451
+ DCHECK(isSleeper(value));
1452
+ waiter->metadata_.waker_ = waker;
1453
+ waiter->metadata_.waiters_ = folly::bit_cast<std::uintptr_t>(sleepers);
1454
+ auto pre =
1455
+ waiter->metadata_.sleeper_.exchange(kSleeping, std::memory_order_acq_rel);
1456
+
1457
+ // we were able to catch the thread before it went to sleep, return true
1458
+ if (pre != kSleeping) {
1459
+ return 0;
1460
+ }
1461
+
1462
+ // otherwise return false, with the value of next_, it is safe to read next
1463
+ // because of the same logic as when a thread was preempted
1464
+ //
1465
+ // we also need to collect this sleeper in the list of sleepers being built
1466
+ // up
1467
+ next = waiter->next_.load(std::memory_order_relaxed);
1468
+ auto head = folly::bit_cast<std::uintptr_t>(sleepers);
1469
+ waiter->next_.store(head, std::memory_order_relaxed);
1470
+ sleepers = waiter;
1471
+ return next;
1472
+ }
1473
+
1474
+ template <typename Waiter>
1475
+ bool wake(
1476
+ bool publishing,
1477
+ Waiter& waiter,
1478
+ std::uintptr_t waker,
1479
+ Waiter*& sleepers,
1480
+ std::uint64_t iter) {
1481
+ // loop till we find a node that is either at the end of the list (as
1482
+ // specified by waker) or we find a node that is active (as specified by
1483
+ // the last published timestamp of the node)
1484
+ auto current = &waiter;
1485
+ while (current) {
1486
+ // it is important that we load the value of function and next_ after the
1487
+ // initial acquire load. This is required because we need to synchronize
1488
+ // with the construction of the waiter struct before reading from it
1489
+ //
1490
+ // the load from the next_ variable is an optimistic load that assumes
1491
+ // that the waiting thread has probably gone to the waiting state. If the
1492
+ // waiitng thread is in the waiting state (as revealed by the acquire load
1493
+ // from the futex word), we will see a well formed next_ value because it
1494
+ // happens-before the release store to the futex word. The atomic load from
1495
+ // next_ is an optimization to avoid branching before loading and prevent
1496
+ // the compiler from eliding the load altogether (and using a pointer
1497
+ // dereference when needed)
1498
+ auto value = current->futex_.load(std::memory_order_acquire);
1499
+ auto next = current->next_.load(std::memory_order_relaxed);
1500
+ auto task = loadTask(current, value);
1501
+ next =
1502
+ tryWake(publishing, current, value, next, waker, sleepers, iter, task);
1503
+
1504
+ // if there is no next node, we have managed to wake someone up and have
1505
+ // successfully migrated the lock to another thread
1506
+ if (!next) {
1507
+ return true;
1508
+ }
1509
+
1510
+ // we need to read the value of the next node in the list before skipping
1511
+ // it, this is because after we skip it the node might wake up and enqueue
1512
+ // itself, and thereby gain a new next node
1513
+ CHECK(publishing);
1514
+ current = (next == waker) ? nullptr : extractPtr<Waiter>(next);
1515
+ }
1516
+
1517
+ return false;
1518
+ }
1519
+
1520
+ template <typename Atomic, typename Proxy, typename Sleepers>
1521
+ bool tryUnlockClean(Atomic& state, Proxy& proxy, Sleepers sleepers) {
1522
+ auto expected = proxy.expected_;
1523
+ while (true) {
1524
+ if (state.compare_exchange_strong(
1525
+ expected,
1526
+ kUnlocked,
1527
+ std::memory_order_release,
1528
+ std::memory_order_relaxed)) {
1529
+ // if we were able to commit an unlocked, we need to wake up the futex
1530
+ // waiters, if any
1531
+ doFutexWake(sleepers);
1532
+ return true;
1533
+ }
1534
+
1535
+ // if we failed the compare_exchange_strong() above, we check to see if
1536
+ // the failure was because of the presence of a timed waiter. If that
1537
+ // was the case then we try one more time with the kTimedWaiter bit set
1538
+ if (FOLLY_UNLIKELY(expected == (proxy.expected_ | kTimedWaiter))) {
1539
+ proxy.timedWaiters_ = true;
1540
+ continue;
1541
+ }
1542
+
1543
+ // otherwise break, we have a contention chain
1544
+ return false;
1545
+ }
1546
+ }
1547
+
1548
+ template <template <typename> class Atomic, bool Publish>
1549
+ void DistributedMutex<Atomic, Publish>::unlock(
1550
+ DistributedMutex::DistributedMutexStateProxy const& proxy_) {
1551
+ auto proxy = proxy_;
1552
+ // we always wake up ready threads and timed waiters if we saw either
1553
+ DCHECK(proxy) << "Invalid proxy passed to DistributedMutex::unlock()";
1554
+ DCHECK(!proxy.combined_) << "Cannot unlock mutex after a successful combine";
1555
+ SCOPE_EXIT {
1556
+ doFutexWake(proxy.ready_);
1557
+ wakeTimedWaiters(&state_, proxy.timedWaiters_);
1558
+ };
1559
+
1560
+ // if there is a wait queue we are responsible for, try and start wakeups,
1561
+ // don't bother with the mutex state
1562
+ auto sleepers = proxy.waiters_;
1563
+ if (proxy.next_) {
1564
+ if (wake(Publish, *proxy.next_, proxy.waker_, sleepers, 0)) {
1565
+ return;
1566
+ }
1567
+
1568
+ // At this point, if are in the if statement, we were not the terminal
1569
+ // node of the wakeup chain. Terminal nodes have the next_ pointer set to
1570
+ // null in lock()
1571
+ //
1572
+ // So we need to pretend we were the end of the contention chain. Coming
1573
+ // out of a contention chain always has the kLocked state set in the
1574
+ // mutex. Unless there is another contention chain lined up, which does
1575
+ // not matter since we are the terminal node anyway
1576
+ proxy.expected_ = kLocked;
1577
+ }
1578
+
1579
+ for (std::uint64_t i = 0; true; ++i) {
1580
+ // otherwise, since we don't have anyone we need to wake up, we try and
1581
+ // release the mutex just as is
1582
+ //
1583
+ // if this is successful, we can return, the unlock was successful, we have
1584
+ // committed a nice kUnlocked to the central storage, yay
1585
+ if (tryUnlockClean(state_, proxy, sleepers)) {
1586
+ return;
1587
+ }
1588
+
1589
+ // here we have a contention chain built up on the mutex. We grab the
1590
+ // wait queue and start executing wakeups. We leave a locked bit on the
1591
+ // centralized storage and handoff control to the head of the queue
1592
+ //
1593
+ // we use memory_order_acq_rel here because we want to see the
1594
+ // full well-initialized node that the other thread is waiting on
1595
+ //
1596
+ // If we are unable to wake the contention chain, it is possible that when
1597
+ // we come back to looping here, a new contention chain will form. In
1598
+ // that case we need to use kLocked as the waker_ value because the
1599
+ // terminal node of the new chain will see kLocked in the central storage
1600
+ auto head = state_.exchange(kLocked, std::memory_order_acq_rel);
1601
+ recordTimedWaiterAndClearTimedBit(proxy.timedWaiters_, head);
1602
+ auto next = extractPtr<Waiter<Atomic>>(head);
1603
+ auto expected = std::exchange(proxy.expected_, kLocked);
1604
+ DCHECK((head & kLocked) && (head != kLocked)) << "incorrect state " << head;
1605
+ if (wake(Publish, *next, expected, sleepers, i)) {
1606
+ break;
1607
+ }
1608
+ }
1609
+ }
1610
+
1611
+ template <typename Atomic, typename Deadline, typename MakeProxy>
1612
+ auto timedLock(Atomic& state, Deadline deadline, MakeProxy proxy) {
1613
+ while (true) {
1614
+ // we put a bit on the central state to show that there is a timed waiter
1615
+ // and go to sleep on the central state
1616
+ //
1617
+ // when this thread goes to unlock the mutex, it will expect a 0b1 in the
1618
+ // mutex state (0b1, not 0b11), but then it will see that the value in the
1619
+ // mutex state is 0b11 and not 0b1, meaning that there might have been
1620
+ // another timed waiter. Even though there might not have been another
1621
+ // timed waiter in the time being. This sort of missed wakeup is
1622
+ // desirable for timed waiters; it helps avoid thundering herds of timed
1623
+ // waiters. Because the mutex is packed in 8 bytes, and we need an
1624
+ // address to be stored in those 8 bytes, we don't have much room to play
1625
+ // with. The only other solution is to issue a futexWake(INT_MAX) to wake
1626
+ // up all waiters when a clean unlock is committed, when a thread saw a
1627
+ // timed waiter in the mutex previously.
1628
+ //
1629
+ // putting a 0b11 here works for a set of reasons that is a superset of
1630
+ // the set of reasons that make it okay to put a kLocked (0b1) in the
1631
+ // mutex state. Now that the thread has put (kTimedWaiter | kLocked)
1632
+ // (0b11) in the mutex state and it expects a kLocked (0b1), there are two
1633
+ // scenarios possible. The first being when there is no contention chain
1634
+ // formation in the mutex from the time a timed waiter got a lock to
1635
+ // unlock. In this case, the unlocker sees a 0b11 in the mutex state,
1636
+ // adjusts to the presence of a timed waiter and cleanly unlocks with a
1637
+ // kUnlocked (0b0). The second is when there is a contention chain.
1638
+ // When a thread puts its address in the mutex and sees the timed bit, it
1639
+ // records the presence of a timed waiter, and then pretends as if it
1640
+ // hadn't seen the timed bit. So future contention chain releases, will
1641
+ // terminate with a kLocked (0b1) and not a (kLocked | kTimedWaiter)
1642
+ // (0b11). This just works naturally with the rest of the algorithm
1643
+ // without incurring a perf hit for the regular non-timed case
1644
+ //
1645
+ // this strategy does however mean, that when threads try to acquire the
1646
+ // mutex and all time out, there will be a wasteful syscall to issue wakeups
1647
+ // to waiting threads. We don't do anything to try and minimize this
1648
+ //
1649
+ // we need to use a fetch_or() here because we need to convey two bits of
1650
+ // information - 1, whether the mutex is locked or not, and 2, whether
1651
+ // there is a timed waiter. The alternative here is to use the second bit
1652
+ // to convey information only, we can use a fetch_set() on the second bit
1653
+ // to make this faster, but that comes at the expense of requiring regular
1654
+ // fast path lock attempts. Which use a single bit read-modify-write for
1655
+ // better performance
1656
+ auto data = kTimedWaiter | kLocked;
1657
+ auto previous = state.fetch_or(data, std::memory_order_acquire);
1658
+ if (!(previous & 0b1)) {
1659
+ DCHECK(!previous);
1660
+ return proxy(nullptr, kLocked, true);
1661
+ }
1662
+
1663
+ // wait on the futex until signalled, if we get a timeout, the try_lock
1664
+ // fails
1665
+ auto result = folly::atomic_wait_until( // evade ADL
1666
+ &state,
1667
+ previous | data,
1668
+ deadline);
1669
+ if (result == std::cv_status::timeout) {
1670
+ return proxy(nullptr, std::uintptr_t{0}, false);
1671
+ }
1672
+ }
1673
+ }
1674
+
1675
+ template <template <typename> class Atomic, bool TimePublishing>
1676
+ template <typename Clock, typename Duration>
1677
+ typename DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy
1678
+ DistributedMutex<Atomic, TimePublishing>::try_lock_until(
1679
+ const std::chrono::time_point<Clock, Duration>& deadline) {
1680
+ // fast path for the uncontended case
1681
+ //
1682
+ // we get the time after trying to acquire the mutex because in the
1683
+ // uncontended case, the price of getting the time is about 1/3 of the
1684
+ // actual mutex acquisition. So we only pay the price of that extra bit of
1685
+ // latency when needed
1686
+ //
1687
+ // this is even higher when VDSO is involved on architectures that do not
1688
+ // offer a direct interface to the timestamp counter
1689
+ if (auto state = try_lock()) {
1690
+ return state;
1691
+ }
1692
+
1693
+ // fall back to the timed locking algorithm
1694
+ using Proxy = DistributedMutexStateProxy;
1695
+ return timedLock(state_, deadline, [](auto... as) { return Proxy{as...}; });
1696
+ }
1697
+
1698
+ template <template <typename> class Atomic, bool TimePublishing>
1699
+ template <typename Rep, typename Period>
1700
+ typename DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy
1701
+ DistributedMutex<Atomic, TimePublishing>::try_lock_for(
1702
+ const std::chrono::duration<Rep, Period>& duration) {
1703
+ // fast path for the uncontended case. Reasoning for doing this here is the
1704
+ // same as in try_lock_until()
1705
+ if (auto state = try_lock()) {
1706
+ return state;
1707
+ }
1708
+
1709
+ // fall back to the timed locking algorithm
1710
+ using Proxy = DistributedMutexStateProxy;
1711
+ auto deadline = std::chrono::steady_clock::now() + duration;
1712
+ return timedLock(state_, deadline, [](auto... as) { return Proxy{as...}; });
1713
+ }
1714
+ } // namespace distributed_mutex
1715
+ } // namespace detail
1716
+ } // namespace folly
1717
+
1718
+ namespace std {
1719
+
1720
+ template <template <typename> class Atom, bool TimePublishing>
1721
+ class unique_lock<
1722
+ ::folly::detail::distributed_mutex::DistributedMutex<Atom, TimePublishing>>
1723
+ : public ::folly::unique_lock_base<
1724
+ ::folly::detail::distributed_mutex::
1725
+ DistributedMutex<Atom, TimePublishing>> {
1726
+ public:
1727
+ using ::folly::unique_lock_base<
1728
+ ::folly::detail::distributed_mutex::
1729
+ DistributedMutex<Atom, TimePublishing>>::unique_lock_base;
1730
+ };
1731
+
1732
+ template <template <typename> class Atom, bool TimePublishing>
1733
+ class lock_guard<
1734
+ ::folly::detail::distributed_mutex::DistributedMutex<Atom, TimePublishing>>
1735
+ : public ::folly::unique_lock_guard_base<
1736
+ ::folly::detail::distributed_mutex::
1737
+ DistributedMutex<Atom, TimePublishing>> {
1738
+ public:
1739
+ using ::folly::unique_lock_guard_base<
1740
+ ::folly::detail::distributed_mutex::
1741
+ DistributedMutex<Atom, TimePublishing>>::unique_lock_guard_base;
1742
+ };
1743
+
1744
+ } // namespace std