mdbxmou 0.1.26

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 (220) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/.github/workflows/publish.yml +27 -0
  3. package/.gitmodules +3 -0
  4. package/CMakeLists.txt +53 -0
  5. package/LICENSE +201 -0
  6. package/README.md +639 -0
  7. package/build.js +11 -0
  8. package/deps/libmdbx/.clang-format +3 -0
  9. package/deps/libmdbx/.cmake-format.yaml +3 -0
  10. package/deps/libmdbx/.le.ini +40 -0
  11. package/deps/libmdbx/CMakeLists.txt +1269 -0
  12. package/deps/libmdbx/COPYRIGHT +159 -0
  13. package/deps/libmdbx/ChangeLog.md +2786 -0
  14. package/deps/libmdbx/GNUmakefile +950 -0
  15. package/deps/libmdbx/LICENSE +177 -0
  16. package/deps/libmdbx/Makefile +16 -0
  17. package/deps/libmdbx/NOTICE +39 -0
  18. package/deps/libmdbx/README.md +863 -0
  19. package/deps/libmdbx/TODO.md +43 -0
  20. package/deps/libmdbx/cmake/compiler.cmake +1221 -0
  21. package/deps/libmdbx/cmake/profile.cmake +58 -0
  22. package/deps/libmdbx/cmake/utils.cmake +524 -0
  23. package/deps/libmdbx/conanfile.py +323 -0
  24. package/deps/libmdbx/docs/Doxyfile.in +2734 -0
  25. package/deps/libmdbx/docs/_preface.md +47 -0
  26. package/deps/libmdbx/docs/_restrictions.md +248 -0
  27. package/deps/libmdbx/docs/_starting.md +245 -0
  28. package/deps/libmdbx/docs/_toc.md +34 -0
  29. package/deps/libmdbx/docs/header.html +96 -0
  30. package/deps/libmdbx/example/CMakeLists.txt +6 -0
  31. package/deps/libmdbx/example/README.md +1 -0
  32. package/deps/libmdbx/example/example-mdbx.c +154 -0
  33. package/deps/libmdbx/example/sample-bdb.txt +77 -0
  34. package/deps/libmdbx/mdbx.h +6655 -0
  35. package/deps/libmdbx/mdbx.h++ +6428 -0
  36. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
  37. package/deps/libmdbx/src/alloy.c +54 -0
  38. package/deps/libmdbx/src/api-cold.c +543 -0
  39. package/deps/libmdbx/src/api-copy.c +912 -0
  40. package/deps/libmdbx/src/api-cursor.c +754 -0
  41. package/deps/libmdbx/src/api-dbi.c +315 -0
  42. package/deps/libmdbx/src/api-env.c +1434 -0
  43. package/deps/libmdbx/src/api-extra.c +165 -0
  44. package/deps/libmdbx/src/api-key-transform.c +197 -0
  45. package/deps/libmdbx/src/api-misc.c +286 -0
  46. package/deps/libmdbx/src/api-opts.c +575 -0
  47. package/deps/libmdbx/src/api-range-estimate.c +365 -0
  48. package/deps/libmdbx/src/api-txn-data.c +454 -0
  49. package/deps/libmdbx/src/api-txn.c +921 -0
  50. package/deps/libmdbx/src/atomics-ops.h +364 -0
  51. package/deps/libmdbx/src/atomics-types.h +97 -0
  52. package/deps/libmdbx/src/audit.c +109 -0
  53. package/deps/libmdbx/src/bits.md +34 -0
  54. package/deps/libmdbx/src/chk.c +1796 -0
  55. package/deps/libmdbx/src/cogs.c +309 -0
  56. package/deps/libmdbx/src/cogs.h +506 -0
  57. package/deps/libmdbx/src/coherency.c +170 -0
  58. package/deps/libmdbx/src/config.h.in +88 -0
  59. package/deps/libmdbx/src/cursor.c +2396 -0
  60. package/deps/libmdbx/src/cursor.h +391 -0
  61. package/deps/libmdbx/src/dbi.c +717 -0
  62. package/deps/libmdbx/src/dbi.h +142 -0
  63. package/deps/libmdbx/src/debug_begin.h +36 -0
  64. package/deps/libmdbx/src/debug_end.h +15 -0
  65. package/deps/libmdbx/src/dpl.c +486 -0
  66. package/deps/libmdbx/src/dpl.h +134 -0
  67. package/deps/libmdbx/src/dxb.c +1335 -0
  68. package/deps/libmdbx/src/env.c +607 -0
  69. package/deps/libmdbx/src/essentials.h +125 -0
  70. package/deps/libmdbx/src/gc-get.c +1345 -0
  71. package/deps/libmdbx/src/gc-put.c +970 -0
  72. package/deps/libmdbx/src/gc.h +40 -0
  73. package/deps/libmdbx/src/global.c +474 -0
  74. package/deps/libmdbx/src/internals.h +585 -0
  75. package/deps/libmdbx/src/layout-dxb.h +288 -0
  76. package/deps/libmdbx/src/layout-lck.h +289 -0
  77. package/deps/libmdbx/src/lck-posix.c +859 -0
  78. package/deps/libmdbx/src/lck-windows.c +607 -0
  79. package/deps/libmdbx/src/lck.c +174 -0
  80. package/deps/libmdbx/src/lck.h +110 -0
  81. package/deps/libmdbx/src/logging_and_debug.c +250 -0
  82. package/deps/libmdbx/src/logging_and_debug.h +159 -0
  83. package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
  84. package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
  85. package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
  86. package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
  87. package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
  88. package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
  89. package/deps/libmdbx/src/mdbx.c++ +1837 -0
  90. package/deps/libmdbx/src/meta.c +656 -0
  91. package/deps/libmdbx/src/meta.h +168 -0
  92. package/deps/libmdbx/src/mvcc-readers.c +414 -0
  93. package/deps/libmdbx/src/node.c +365 -0
  94. package/deps/libmdbx/src/node.h +102 -0
  95. package/deps/libmdbx/src/ntdll.def +1246 -0
  96. package/deps/libmdbx/src/options.h +534 -0
  97. package/deps/libmdbx/src/osal.c +3485 -0
  98. package/deps/libmdbx/src/osal.h +587 -0
  99. package/deps/libmdbx/src/page-get.c +483 -0
  100. package/deps/libmdbx/src/page-iov.c +185 -0
  101. package/deps/libmdbx/src/page-iov.h +34 -0
  102. package/deps/libmdbx/src/page-ops.c +744 -0
  103. package/deps/libmdbx/src/page-ops.h +142 -0
  104. package/deps/libmdbx/src/pnl.c +236 -0
  105. package/deps/libmdbx/src/pnl.h +146 -0
  106. package/deps/libmdbx/src/preface.h +990 -0
  107. package/deps/libmdbx/src/proto.h +105 -0
  108. package/deps/libmdbx/src/refund.c +212 -0
  109. package/deps/libmdbx/src/sort.h +484 -0
  110. package/deps/libmdbx/src/spill.c +431 -0
  111. package/deps/libmdbx/src/spill.h +74 -0
  112. package/deps/libmdbx/src/table.c +107 -0
  113. package/deps/libmdbx/src/tls.c +551 -0
  114. package/deps/libmdbx/src/tls.h +43 -0
  115. package/deps/libmdbx/src/tools/chk.c +673 -0
  116. package/deps/libmdbx/src/tools/copy.c +166 -0
  117. package/deps/libmdbx/src/tools/drop.c +199 -0
  118. package/deps/libmdbx/src/tools/dump.c +515 -0
  119. package/deps/libmdbx/src/tools/load.c +831 -0
  120. package/deps/libmdbx/src/tools/stat.c +516 -0
  121. package/deps/libmdbx/src/tools/wingetopt.c +87 -0
  122. package/deps/libmdbx/src/tools/wingetopt.h +30 -0
  123. package/deps/libmdbx/src/tree-ops.c +1554 -0
  124. package/deps/libmdbx/src/tree-search.c +140 -0
  125. package/deps/libmdbx/src/txl.c +99 -0
  126. package/deps/libmdbx/src/txl.h +26 -0
  127. package/deps/libmdbx/src/txn.c +1083 -0
  128. package/deps/libmdbx/src/unaligned.h +205 -0
  129. package/deps/libmdbx/src/utils.c +32 -0
  130. package/deps/libmdbx/src/utils.h +76 -0
  131. package/deps/libmdbx/src/version.c.in +44 -0
  132. package/deps/libmdbx/src/walk.c +290 -0
  133. package/deps/libmdbx/src/walk.h +20 -0
  134. package/deps/libmdbx/src/windows-import.c +152 -0
  135. package/deps/libmdbx/src/windows-import.h +128 -0
  136. package/deps/libmdbx/test/CMakeLists.txt +317 -0
  137. package/deps/libmdbx/test/append.c++ +237 -0
  138. package/deps/libmdbx/test/base.h++ +92 -0
  139. package/deps/libmdbx/test/battery-tmux.sh +64 -0
  140. package/deps/libmdbx/test/cases.c++ +118 -0
  141. package/deps/libmdbx/test/chrono.c++ +134 -0
  142. package/deps/libmdbx/test/chrono.h++ +85 -0
  143. package/deps/libmdbx/test/config.c++ +643 -0
  144. package/deps/libmdbx/test/config.h++ +334 -0
  145. package/deps/libmdbx/test/copy.c++ +62 -0
  146. package/deps/libmdbx/test/dead.c++ +39 -0
  147. package/deps/libmdbx/test/dump-load.sh +40 -0
  148. package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
  149. package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
  150. package/deps/libmdbx/test/extra/dbi.c++ +229 -0
  151. package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
  152. package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
  153. package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
  154. package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
  155. package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
  156. package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
  157. package/deps/libmdbx/test/extra/open.c++ +96 -0
  158. package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
  159. package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
  160. package/deps/libmdbx/test/extra/probe.c++ +10 -0
  161. package/deps/libmdbx/test/extra/txn.c++ +407 -0
  162. package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
  163. package/deps/libmdbx/test/fork.c++ +263 -0
  164. package/deps/libmdbx/test/hill.c++ +447 -0
  165. package/deps/libmdbx/test/jitter.c++ +197 -0
  166. package/deps/libmdbx/test/keygen.c++ +393 -0
  167. package/deps/libmdbx/test/keygen.h++ +130 -0
  168. package/deps/libmdbx/test/log.c++ +358 -0
  169. package/deps/libmdbx/test/log.h++ +91 -0
  170. package/deps/libmdbx/test/main.c++ +706 -0
  171. package/deps/libmdbx/test/nested.c++ +318 -0
  172. package/deps/libmdbx/test/osal-unix.c++ +647 -0
  173. package/deps/libmdbx/test/osal-windows.c++ +440 -0
  174. package/deps/libmdbx/test/osal.h++ +41 -0
  175. package/deps/libmdbx/test/stochastic.sh +690 -0
  176. package/deps/libmdbx/test/stub/LICENSE +24 -0
  177. package/deps/libmdbx/test/stub/README.md +8 -0
  178. package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
  179. package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
  180. package/deps/libmdbx/test/test.c++ +1551 -0
  181. package/deps/libmdbx/test/test.h++ +298 -0
  182. package/deps/libmdbx/test/tmux.conf +3 -0
  183. package/deps/libmdbx/test/try.c++ +30 -0
  184. package/deps/libmdbx/test/ttl.c++ +240 -0
  185. package/deps/libmdbx/test/utils.c++ +203 -0
  186. package/deps/libmdbx/test/utils.h++ +326 -0
  187. package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
  188. package/lib/mdbx_evn_async.js +211 -0
  189. package/lib/mdbx_worker.js +195 -0
  190. package/lib/nativemou.js +6 -0
  191. package/package.json +38 -0
  192. package/src/async/envmou_close.cpp +34 -0
  193. package/src/async/envmou_close.hpp +32 -0
  194. package/src/async/envmou_copy_to.cpp +29 -0
  195. package/src/async/envmou_copy_to.hpp +38 -0
  196. package/src/async/envmou_keys.cpp +201 -0
  197. package/src/async/envmou_keys.hpp +50 -0
  198. package/src/async/envmou_open.cpp +38 -0
  199. package/src/async/envmou_open.hpp +33 -0
  200. package/src/async/envmou_query.cpp +167 -0
  201. package/src/async/envmou_query.hpp +53 -0
  202. package/src/dbimou.cpp +522 -0
  203. package/src/dbimou.hpp +82 -0
  204. package/src/env_arg0.hpp +24 -0
  205. package/src/envmou.cpp +445 -0
  206. package/src/envmou.hpp +116 -0
  207. package/src/modulemou.cpp +113 -0
  208. package/src/querymou.cpp +177 -0
  209. package/src/querymou.hpp +93 -0
  210. package/src/txnmou.cpp +254 -0
  211. package/src/txnmou.hpp +122 -0
  212. package/src/typemou.hpp +239 -0
  213. package/src/valuemou.hpp +194 -0
  214. package/test/async.js +67 -0
  215. package/test/e3.js +38 -0
  216. package/test/e4.js +89 -0
  217. package/test/e5.js +162 -0
  218. package/test/test-batch-ops.js +243 -0
  219. package/test/test-cursor-mode.js +84 -0
  220. package/test/test-multi-mode.js +87 -0
@@ -0,0 +1,647 @@
1
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
2
+ /// \copyright SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include "test.h++"
5
+
6
+ #if !(defined(_WIN32) || defined(_WIN64))
7
+
8
+ #include <atomic>
9
+ #include <pthread.h>
10
+ #include <signal.h>
11
+ #include <sys/mman.h>
12
+ #include <sys/types.h>
13
+ #include <sys/wait.h>
14
+ #include <unistd.h>
15
+
16
+ #include <atomic>
17
+
18
+ #ifndef MDBX_LOCKING
19
+ #error "Oops, MDBX_LOCKING is undefined!"
20
+ #endif
21
+
22
+ #if defined(__APPLE__) && (MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008)
23
+ #include "stub/pthread_barrier.c"
24
+ #endif /* __APPLE__ && MDBX_LOCKING >= MDBX_LOCKING_POSIX2001 */
25
+
26
+ #if defined(__ANDROID_API__) && __ANDROID_API__ < 24 && \
27
+ (MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008)
28
+ #include "stub/pthread_barrier.c"
29
+ #endif /* __ANDROID_API__ < 24 && MDBX_LOCKING >= MDBX_LOCKING_POSIX2001 */
30
+
31
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
32
+ #include <sys/ipc.h>
33
+ #include <sys/sem.h>
34
+ #endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
35
+
36
+ #if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
37
+ #include <semaphore.h>
38
+
39
+ #if __cplusplus >= 201103L
40
+ #include <atomic>
41
+ MDBX_MAYBE_UNUSED static inline int atomic_decrement(std::atomic_int *p) { return std::atomic_fetch_sub(p, 1) - 1; }
42
+ #else
43
+ MDBX_MAYBE_UNUSED static inline int atomic_decrement(volatile int *p) {
44
+ #if defined(__GNUC__) || defined(__clang__)
45
+ return __sync_sub_and_fetch(p, 1);
46
+ #elif defined(_MSC_VER)
47
+ STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile int));
48
+ return _InterlockedDecrement((volatile long *)p);
49
+ #elif defined(__APPLE__)
50
+ return OSAtomicDecrement32Barrier((volatile int *)p);
51
+ #else
52
+ #error FIXME: Unsupported compiler
53
+ #endif
54
+ }
55
+ #endif /* C++11 */
56
+ #endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX1988 */
57
+
58
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
59
+ static int ipc;
60
+ static pid_t ipc_overlord_pid;
61
+ static void ipc_remove(void) {
62
+ if (ipc_overlord_pid == getpid())
63
+ semctl(ipc, 0, IPC_RMID, nullptr);
64
+ }
65
+
66
+ #else
67
+ struct shared_t {
68
+ #if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
69
+ pthread_barrier_t barrier;
70
+ pthread_mutex_t mutex;
71
+ size_t count;
72
+ pthread_cond_t events[1];
73
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
74
+ struct {
75
+ #if __cplusplus >= 201103L
76
+ std::atomic_int countdown;
77
+ #else
78
+ volatile int countdown;
79
+ #endif /* C++11 */
80
+ sem_t sema;
81
+ } barrier;
82
+ size_t count;
83
+ sem_t events[1];
84
+ #else
85
+ #error "FIXME"
86
+ #endif /* MDBX_LOCKING */
87
+ };
88
+ static shared_t *shared;
89
+ #endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */
90
+
91
+ void osal_wait4barrier(void) {
92
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
93
+ struct sembuf op;
94
+ op.sem_num = 0;
95
+ op.sem_op = -1;
96
+ op.sem_flg = IPC_NOWAIT;
97
+ if (semop(ipc, &op, 1))
98
+ failure_perror("semop(dec)", errno);
99
+ op.sem_op = 0;
100
+ op.sem_flg = 0;
101
+ if (semop(ipc, &op, 1))
102
+ failure_perror("semop(wait)", errno);
103
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
104
+ assert(shared != nullptr && shared != MAP_FAILED);
105
+ int err = pthread_barrier_wait(&shared->barrier);
106
+ if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
107
+ failure_perror("pthread_barrier_wait(shared)", err);
108
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
109
+ assert(shared != nullptr && shared != MAP_FAILED);
110
+ int err = (atomic_decrement(&shared->barrier.countdown) > 0 && sem_wait(&shared->barrier.sema)) ? errno : 0;
111
+ if (err != 0)
112
+ failure_perror("sem_wait(shared)", err);
113
+ if (sem_post(&shared->barrier.sema))
114
+ failure_perror("sem_post(shared)", errno);
115
+ #else
116
+ #error "FIXME"
117
+ #endif /* MDBX_LOCKING */
118
+ }
119
+
120
+ void osal_setup(const std::vector<actor_config> &actors) {
121
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
122
+ if (ipc_overlord_pid)
123
+ failure("ipc already created by %ld pid", (long)ipc_overlord_pid);
124
+ ipc_overlord_pid = getpid();
125
+ #ifndef SEM_A
126
+ #define SEM_A S_IRUSR
127
+ #endif
128
+ #ifndef SEM_R
129
+ #define SEM_R S_IWUSR
130
+ #endif
131
+ ipc = semget(IPC_PRIVATE, actors.size() + 2, IPC_CREAT | SEM_A | SEM_R);
132
+ if (ipc < 0)
133
+ failure_perror("semget(IPC_PRIVATE, shared_sems)", errno);
134
+ if (atexit(ipc_remove))
135
+ failure_perror("atexit(ipc_remove)", errno);
136
+ if (semctl(ipc, 0, SETVAL, (int)(actors.size() + 1)))
137
+ failure_perror("semctl(SETVAL.0, shared_sems)", errno);
138
+ for (size_t i = 1; i < actors.size() + 2; ++i)
139
+ if (semctl(ipc, i, SETVAL, 1))
140
+ failure_perror("semctl(SETVAL.N, shared_sems)", errno);
141
+ #else
142
+ assert(shared == nullptr);
143
+ shared =
144
+ (shared_t *)mmap(nullptr, sizeof(shared_t) + actors.size() * sizeof(shared->events[0]), PROT_READ | PROT_WRITE,
145
+ MAP_SHARED | MAP_ANONYMOUS
146
+ #ifdef MAP_HASSEMAPHORE
147
+ | MAP_HASSEMAPHORE
148
+ #endif
149
+ ,
150
+ -1, 0);
151
+ if (MAP_FAILED == (void *)shared)
152
+ failure_perror("mmap(shared)", errno);
153
+
154
+ shared->count = actors.size() + 1;
155
+
156
+ #if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
157
+ pthread_barrierattr_t barrierattr;
158
+ int err = pthread_barrierattr_init(&barrierattr);
159
+ if (err)
160
+ failure_perror("pthread_barrierattr_init()", err);
161
+ err = pthread_barrierattr_setpshared(&barrierattr, PTHREAD_PROCESS_SHARED);
162
+ if (err)
163
+ failure_perror("pthread_barrierattr_setpshared()", err);
164
+
165
+ err = pthread_barrier_init(&shared->barrier, &barrierattr, unsigned(shared->count));
166
+ if (err)
167
+ failure_perror("pthread_barrier_init(shared)", err);
168
+ pthread_barrierattr_destroy(&barrierattr);
169
+
170
+ pthread_mutexattr_t mutexattr;
171
+ err = pthread_mutexattr_init(&mutexattr);
172
+ if (err)
173
+ failure_perror("pthread_mutexattr_init()", err);
174
+ err = pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
175
+ if (err)
176
+ failure_perror("pthread_mutexattr_setpshared()", err);
177
+
178
+ pthread_condattr_t condattr;
179
+ err = pthread_condattr_init(&condattr);
180
+ if (err)
181
+ failure_perror("pthread_condattr_init()", err);
182
+ err = pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);
183
+ if (err)
184
+ failure_perror("pthread_condattr_setpshared()", err);
185
+
186
+ err = pthread_mutex_init(&shared->mutex, &mutexattr);
187
+ if (err)
188
+ failure_perror("pthread_mutex_init(shared)", err);
189
+
190
+ for (size_t i = 0; i < shared->count; ++i) {
191
+ pthread_cond_t *event = &shared->events[i];
192
+ err = pthread_cond_init(event, &condattr);
193
+ if (err)
194
+ failure_perror("pthread_cond_init(shared)", err);
195
+ log_trace("osal_setup: event(shared pthread_cond) %" PRIuPTR " -> %p", i, __Wpedantic_format_voidptr(event));
196
+ }
197
+ pthread_condattr_destroy(&condattr);
198
+ pthread_mutexattr_destroy(&mutexattr);
199
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
200
+ shared->barrier.countdown = shared->count;
201
+ if (sem_init(&shared->barrier.sema, true, 1))
202
+ failure_perror("sem_init(shared.barrier)", errno);
203
+ for (size_t i = 0; i < shared->count; ++i) {
204
+ sem_t *event = &shared->events[i];
205
+ if (sem_init(event, true, 0))
206
+ failure_perror("sem_init(shared.event)", errno);
207
+ log_trace("osal_setup: event(shared sem_init) %" PRIuPTR " -> %p", i, __Wpedantic_format_voidptr(event));
208
+ }
209
+ #else
210
+ #error "FIXME"
211
+ #endif /* MDBX_LOCKING */
212
+ #endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */
213
+ }
214
+
215
+ void osal_broadcast(unsigned id) {
216
+ log_trace("osal_broadcast: event %u", id);
217
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
218
+ if (semctl(ipc, id + 1, SETVAL, 0))
219
+ failure_perror("semctl(SETVAL)", errno);
220
+ #else
221
+ assert(shared != nullptr && shared != MAP_FAILED);
222
+ if (id >= shared->count)
223
+ failure("osal_broadcast: id > limit");
224
+ #if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
225
+ int err = pthread_cond_broadcast(shared->events + id);
226
+ if (err)
227
+ failure_perror("pthread_cond_broadcast(shared)", err);
228
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
229
+ if (sem_post(shared->events + id))
230
+ failure_perror("sem_post(shared)", errno);
231
+ #else
232
+ #error "FIXME"
233
+ #endif /* MDBX_LOCKING */
234
+ #endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */
235
+ }
236
+
237
+ int osal_waitfor(unsigned id) {
238
+ log_trace("osal_waitfor: event %u", id);
239
+ #if MDBX_LOCKING == MDBX_LOCKING_SYSV
240
+ struct sembuf op;
241
+ memset(&op, 0, sizeof(op));
242
+ op.sem_num = (short)(id + 1);
243
+ int rc = semop(ipc, &op, 1) ? errno : MDBX_SUCCESS;
244
+ #else
245
+ assert(shared != nullptr && shared != MAP_FAILED);
246
+ if (id >= shared->count)
247
+ failure("osal_waitfor: id > limit");
248
+
249
+ #if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
250
+ int rc = pthread_mutex_lock(&shared->mutex);
251
+ if (rc != 0)
252
+ failure_perror("pthread_mutex_lock(shared)", rc);
253
+
254
+ rc = pthread_cond_wait(shared->events + id, &shared->mutex);
255
+ if (rc && rc != EINTR)
256
+ failure_perror("pthread_cond_wait(shared)", rc);
257
+
258
+ rc = pthread_mutex_unlock(&shared->mutex);
259
+ if (rc != 0)
260
+ failure_perror("pthread_mutex_unlock(shared)", rc);
261
+ #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
262
+ int rc = sem_wait(shared->events + id) ? errno : 0;
263
+ if (rc == 0 && sem_post(shared->events + id))
264
+ failure_perror("sem_post(shared)", errno);
265
+ #else
266
+ #error "FIXME"
267
+ #endif /* MDBX_LOCKING */
268
+ #endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */
269
+
270
+ return (rc == 0) ? true : false;
271
+ }
272
+
273
+ //-----------------------------------------------------------------------------
274
+
275
+ const std::string actor_config::osal_serialize(simple_checksum &checksum) const {
276
+ (void)checksum;
277
+ /* not used in workload, but just for testing */
278
+ return "unix.fork";
279
+ }
280
+
281
+ bool actor_config::osal_deserialize(const char *str, const char *end, simple_checksum &checksum) {
282
+ (void)checksum;
283
+ /* not used in workload, but just for testing */
284
+ return strncmp(str, "unix.fork", 9) == 0 && str + 9 == end;
285
+ }
286
+
287
+ //-----------------------------------------------------------------------------
288
+
289
+ static pid_t overlord_pid;
290
+
291
+ static std::atomic_int sigusr1_head, sigusr2_head;
292
+ static void handler_SIGUSR(int signum) {
293
+ switch (signum) {
294
+ case SIGUSR1:
295
+ ++sigusr1_head;
296
+ return;
297
+ case SIGUSR2:
298
+ ++sigusr2_head;
299
+ return;
300
+ default:
301
+ abort();
302
+ }
303
+ }
304
+
305
+ bool osal_multiactor_mode(void) { return overlord_pid != 0; }
306
+
307
+ bool osal_progress_push(bool active) {
308
+ if (overlord_pid) {
309
+ if (kill(overlord_pid, active ? SIGUSR1 : SIGUSR2))
310
+ failure_perror("osal_progress_push: kill(overload)", errno);
311
+ return true;
312
+ }
313
+
314
+ return false;
315
+ }
316
+
317
+ //-----------------------------------------------------------------------------
318
+
319
+ static std::unordered_map<pid_t, actor_status> children;
320
+
321
+ static std::atomic_int sigalarm_head;
322
+ static void handler_SIGCHLD(int signum) {
323
+ if (signum == SIGALRM)
324
+ ++sigalarm_head;
325
+ }
326
+
327
+ static std::atomic_int sigbreak;
328
+ static void handler_SIGBREAK(int signum) {
329
+ (void)signum;
330
+ ++sigbreak;
331
+ }
332
+
333
+ int osal_delay(unsigned seconds) { return sleep(seconds) ? errno : 0; }
334
+
335
+ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
336
+ static sigset_t mask;
337
+ if (children.empty()) {
338
+ struct sigaction act;
339
+ memset(&act, 0, sizeof(act));
340
+ act.sa_handler = handler_SIGBREAK;
341
+ sigaction(SIGTERM, &act, nullptr);
342
+ sigaction(SIGHUP, &act, nullptr);
343
+ sigaction(SIGINT, &act, nullptr);
344
+ sigaction(SIGQUIT, &act, nullptr);
345
+ #ifdef SIGXCPU
346
+ sigaction(SIGXCPU, &act, nullptr);
347
+ #endif
348
+ #ifdef SIGXFSZ
349
+ sigaction(SIGXFSZ, &act, nullptr);
350
+ #endif
351
+ act.sa_handler = handler_SIGCHLD;
352
+ sigaction(SIGCHLD, &act, nullptr);
353
+ sigaction(SIGALRM, &act, nullptr);
354
+ act.sa_handler = handler_SIGUSR;
355
+ sigaction(SIGUSR1, &act, nullptr);
356
+ sigaction(SIGUSR2, &act, nullptr);
357
+
358
+ sigemptyset(&mask);
359
+ sigaddset(&mask, SIGCHLD);
360
+ sigaddset(&mask, SIGUSR1);
361
+ sigaddset(&mask, SIGUSR2);
362
+ sigprocmask(SIG_UNBLOCK, &mask, nullptr);
363
+ }
364
+
365
+ pid = fork();
366
+
367
+ if (pid == 0) {
368
+ sigprocmask(SIG_BLOCK, &mask, nullptr);
369
+ overlord_pid = getppid();
370
+ const bool result = test_execute(config);
371
+ exit(result ? EXIT_SUCCESS : EXIT_FAILURE);
372
+ }
373
+
374
+ if (pid < 0)
375
+ return errno;
376
+
377
+ log_trace("osal_actor_start: fork pid %ld for %u", (long)pid, config.actor_id);
378
+ children[pid] = as_running;
379
+ return 0;
380
+ }
381
+
382
+ actor_status osal_actor_info(const mdbx_pid_t pid) { return children.at(pid); }
383
+
384
+ void osal_killall_actors(void) {
385
+ for (auto &pair : children) {
386
+ kill(pair.first, SIGKILL);
387
+ pair.second = as_killed;
388
+ }
389
+ }
390
+
391
+ const char *signal_name(const int sig) {
392
+ if (sig == SIGHUP)
393
+ return "HUP";
394
+ if (sig == SIGINT)
395
+ return "INT";
396
+ if (sig == SIGQUIT)
397
+ return "QUIT";
398
+ if (sig == SIGILL)
399
+ return "ILL";
400
+ if (sig == SIGTRAP)
401
+ return "TRAP";
402
+ if (sig == SIGABRT)
403
+ return "ABRT";
404
+ if (sig == SIGBUS)
405
+ return "BUS";
406
+ if (sig == SIGKILL)
407
+ return "KILL";
408
+ if (sig == SIGUSR1)
409
+ return "USR1";
410
+ if (sig == SIGSEGV)
411
+ return "SEGV";
412
+ if (sig == SIGUSR2)
413
+ return "USR2";
414
+ if (sig == SIGPIPE)
415
+ return "PIPE";
416
+ if (sig == SIGALRM)
417
+ return "ALRM";
418
+ if (sig == SIGTERM)
419
+ return "TERM";
420
+ if (sig == SIGCHLD)
421
+ return "CHLD";
422
+ if (sig == SIGCONT)
423
+ return "CONT";
424
+ if (sig == SIGSTOP)
425
+ return "STOP";
426
+ #ifdef SIGPOLL
427
+ if (sig == SIGPOLL)
428
+ return "POLL";
429
+ #endif
430
+ #ifdef SIGFPE
431
+ if (sig == SIGFPE)
432
+ return "FPE";
433
+ #endif
434
+ #ifdef SIGEMT
435
+ if (sig == SIGEMT)
436
+ return "EMT";
437
+ #endif
438
+ #ifdef SIGSTKFLT
439
+ if (sig == SIGSTKFLT)
440
+ return "STKFLT";
441
+ #endif
442
+ #ifdef SIGTSTP
443
+ if (sig == SIGTSTP)
444
+ return "TSTP";
445
+ #endif
446
+ #ifdef SIGTTIN
447
+ if (sig == SIGTTIN)
448
+ return "TTIN";
449
+ #endif
450
+ #ifdef SIGTTOU
451
+ if (sig == SIGTTOU)
452
+ return "TTOU";
453
+ #endif
454
+ #ifdef SIGURG
455
+ if (sig == SIGURG)
456
+ return "URG";
457
+ #endif
458
+ #ifdef SIGXCPU
459
+ if (sig == SIGXCPU)
460
+ return "XCPU";
461
+ #endif
462
+ #ifdef SIGXFSZ
463
+ if (sig == SIGXFSZ)
464
+ return "XFSZ";
465
+ #endif
466
+ #ifdef SIGVTALRM
467
+ if (sig == SIGVTALRM)
468
+ return "VTALRM";
469
+ #endif
470
+ #ifdef SIGPROF
471
+ if (sig == SIGPROF)
472
+ return "PROF";
473
+ #endif
474
+ #ifdef SIGWINCH
475
+ if (sig == SIGWINCH)
476
+ return "WINCH";
477
+ #endif
478
+ #ifdef SIGIO
479
+ if (sig == SIGIO)
480
+ return "IO";
481
+ #endif
482
+ #ifdef SIGPWR
483
+ if (sig == SIGPWR)
484
+ return "PWR";
485
+ #endif
486
+ #ifdef SIGSYS
487
+ if (sig == SIGSYS)
488
+ return "SYS";
489
+ #endif
490
+ static char buf[32];
491
+ snprintf(buf, sizeof(buf), "%u", sig);
492
+ return buf;
493
+ }
494
+
495
+ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
496
+ static sig_atomic_t sigalarm_tail;
497
+ alarm(0) /* cancel prev timeout */;
498
+ sigalarm_tail = sigalarm_head /* reset timeout flag */;
499
+
500
+ int options = WNOHANG;
501
+ if (timeout && !sigbreak) {
502
+ alarm((timeout > INT_MAX) ? INT_MAX : timeout);
503
+ options = 0;
504
+ }
505
+
506
+ #ifdef WUNTRACED
507
+ options |= WUNTRACED;
508
+ #endif
509
+ #ifdef WCONTINUED
510
+ options |= WCONTINUED;
511
+ #endif
512
+
513
+ pid = 0;
514
+ while (sigalarm_tail == sigalarm_head) {
515
+ int status;
516
+ pid = waitpid(0, &status, options);
517
+ const int err = errno;
518
+
519
+ if (pid > 0) {
520
+ if (WIFEXITED(status))
521
+ children[pid] = (WEXITSTATUS(status) == EXIT_SUCCESS) ? as_successful : as_failed;
522
+ else if (WIFSIGNALED(status)) {
523
+ int sig = WTERMSIG(status);
524
+ #ifdef WCOREDUMP
525
+ if (WCOREDUMP(status))
526
+ children[pid] = as_coredump;
527
+ else
528
+ #endif /* WCOREDUMP */
529
+ switch (sig) {
530
+ case SIGABRT:
531
+ case SIGBUS:
532
+ case SIGFPE:
533
+ case SIGILL:
534
+ case SIGSEGV:
535
+ log_notice("child pid %lu %s by SIG%s", (long)pid, "terminated", signal_name(sig));
536
+ children[pid] = as_coredump;
537
+ break;
538
+ default:
539
+ log_notice("child pid %lu %s by SIG%s", (long)pid, "killed", signal_name(sig));
540
+ children[pid] = as_killed;
541
+ }
542
+ } else if (WIFSTOPPED(status))
543
+ children[pid] = as_debugging;
544
+ else if (WIFCONTINUED(status))
545
+ children[pid] = as_running;
546
+ else {
547
+ assert(false);
548
+ }
549
+ return 0;
550
+ }
551
+
552
+ static sig_atomic_t sigusr1_tail, sigusr2_tail;
553
+ if (sigusr1_tail != sigusr1_head) {
554
+ sigusr1_tail = sigusr1_head;
555
+ logging::progress_canary(true);
556
+ if (pid < 0 && err == EINTR)
557
+ continue;
558
+ }
559
+ if (sigusr2_tail != sigusr2_head) {
560
+ sigusr2_tail = sigusr2_head;
561
+ logging::progress_canary(false);
562
+ if (pid < 0 && err == EINTR)
563
+ continue;
564
+ }
565
+
566
+ if (pid == 0 || sigbreak)
567
+ break;
568
+
569
+ if (err != EINTR)
570
+ return err;
571
+ }
572
+ return sigbreak ? EINTR : 0 /* timeout */;
573
+ }
574
+
575
+ void osal_yield(void) {
576
+ if (sched_yield())
577
+ failure_perror("sched_yield()", errno);
578
+ }
579
+
580
+ void osal_udelay(size_t us) {
581
+ chrono::time until, now = chrono::now_monotonic();
582
+ until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint;
583
+ struct timespec ts;
584
+
585
+ static size_t threshold_us;
586
+ if (threshold_us == 0) {
587
+ #if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME > -1 && defined(CLOCK_PROCESS_CPUTIME_ID)
588
+ if (clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts)) {
589
+ int rc = errno;
590
+ log_warning("clock_getres(CLOCK_PROCESS_CPUTIME_ID), failed errno %d", rc);
591
+ }
592
+ #endif /* CLOCK_PROCESS_CPUTIME_ID */
593
+ if (threshold_us == 0 && clock_getres(CLOCK_MONOTONIC, &ts)) {
594
+ int rc = errno;
595
+ failure_perror("clock_getres(CLOCK_MONOTONIC)", rc);
596
+ }
597
+ chrono::time threshold = chrono::from_timespec(ts);
598
+ assert(threshold.seconds() == 0);
599
+
600
+ threshold_us = chrono::fractional2us(threshold.fractional);
601
+ if (threshold_us < 1000)
602
+ threshold_us = 1000;
603
+ }
604
+
605
+ ts.tv_sec = ts.tv_nsec = 0;
606
+ if (us > threshold_us) {
607
+ ts.tv_sec = us / 1000000u;
608
+ ts.tv_nsec = (us % 1000000u) * 1000u;
609
+ }
610
+
611
+ do {
612
+ if (us > threshold_us) {
613
+ if (nanosleep(&ts, &ts)) {
614
+ int rc = errno;
615
+ /* if (rc == EINTR) { ... } ? */
616
+ failure_perror("usleep()", rc);
617
+ }
618
+ us = ts.tv_sec * 1000000u + ts.tv_nsec / 1000u;
619
+ }
620
+ cpu_relax();
621
+
622
+ now = chrono::now_monotonic();
623
+ } while (until.fixedpoint > now.fixedpoint);
624
+ }
625
+
626
+ bool osal_istty(int fd) { return isatty(fd) == 1; }
627
+
628
+ std::string osal_tempdir(void) {
629
+ const char *tempdir = getenv("TMPDIR");
630
+ if (!tempdir)
631
+ tempdir = getenv("TMP");
632
+ if (!tempdir)
633
+ tempdir = getenv("TEMPDIR");
634
+ if (!tempdir)
635
+ tempdir = getenv("TEMP");
636
+ if (tempdir && *tempdir) {
637
+ std::string dir(tempdir);
638
+ if (dir.back() != '/')
639
+ dir.append("/");
640
+ return dir;
641
+ }
642
+ if (access("/dev/shm/", R_OK | W_OK | X_OK) == 0)
643
+ return "/dev/shm/";
644
+ return "";
645
+ }
646
+
647
+ #endif /* !Windows */