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.
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/publish.yml +27 -0
- package/.gitmodules +3 -0
- package/CMakeLists.txt +53 -0
- package/LICENSE +201 -0
- package/README.md +639 -0
- package/build.js +11 -0
- package/deps/libmdbx/.clang-format +3 -0
- package/deps/libmdbx/.cmake-format.yaml +3 -0
- package/deps/libmdbx/.le.ini +40 -0
- package/deps/libmdbx/CMakeLists.txt +1269 -0
- package/deps/libmdbx/COPYRIGHT +159 -0
- package/deps/libmdbx/ChangeLog.md +2786 -0
- package/deps/libmdbx/GNUmakefile +950 -0
- package/deps/libmdbx/LICENSE +177 -0
- package/deps/libmdbx/Makefile +16 -0
- package/deps/libmdbx/NOTICE +39 -0
- package/deps/libmdbx/README.md +863 -0
- package/deps/libmdbx/TODO.md +43 -0
- package/deps/libmdbx/cmake/compiler.cmake +1221 -0
- package/deps/libmdbx/cmake/profile.cmake +58 -0
- package/deps/libmdbx/cmake/utils.cmake +524 -0
- package/deps/libmdbx/conanfile.py +323 -0
- package/deps/libmdbx/docs/Doxyfile.in +2734 -0
- package/deps/libmdbx/docs/_preface.md +47 -0
- package/deps/libmdbx/docs/_restrictions.md +248 -0
- package/deps/libmdbx/docs/_starting.md +245 -0
- package/deps/libmdbx/docs/_toc.md +34 -0
- package/deps/libmdbx/docs/header.html +96 -0
- package/deps/libmdbx/example/CMakeLists.txt +6 -0
- package/deps/libmdbx/example/README.md +1 -0
- package/deps/libmdbx/example/example-mdbx.c +154 -0
- package/deps/libmdbx/example/sample-bdb.txt +77 -0
- package/deps/libmdbx/mdbx.h +6655 -0
- package/deps/libmdbx/mdbx.h++ +6428 -0
- package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
- package/deps/libmdbx/src/alloy.c +54 -0
- package/deps/libmdbx/src/api-cold.c +543 -0
- package/deps/libmdbx/src/api-copy.c +912 -0
- package/deps/libmdbx/src/api-cursor.c +754 -0
- package/deps/libmdbx/src/api-dbi.c +315 -0
- package/deps/libmdbx/src/api-env.c +1434 -0
- package/deps/libmdbx/src/api-extra.c +165 -0
- package/deps/libmdbx/src/api-key-transform.c +197 -0
- package/deps/libmdbx/src/api-misc.c +286 -0
- package/deps/libmdbx/src/api-opts.c +575 -0
- package/deps/libmdbx/src/api-range-estimate.c +365 -0
- package/deps/libmdbx/src/api-txn-data.c +454 -0
- package/deps/libmdbx/src/api-txn.c +921 -0
- package/deps/libmdbx/src/atomics-ops.h +364 -0
- package/deps/libmdbx/src/atomics-types.h +97 -0
- package/deps/libmdbx/src/audit.c +109 -0
- package/deps/libmdbx/src/bits.md +34 -0
- package/deps/libmdbx/src/chk.c +1796 -0
- package/deps/libmdbx/src/cogs.c +309 -0
- package/deps/libmdbx/src/cogs.h +506 -0
- package/deps/libmdbx/src/coherency.c +170 -0
- package/deps/libmdbx/src/config.h.in +88 -0
- package/deps/libmdbx/src/cursor.c +2396 -0
- package/deps/libmdbx/src/cursor.h +391 -0
- package/deps/libmdbx/src/dbi.c +717 -0
- package/deps/libmdbx/src/dbi.h +142 -0
- package/deps/libmdbx/src/debug_begin.h +36 -0
- package/deps/libmdbx/src/debug_end.h +15 -0
- package/deps/libmdbx/src/dpl.c +486 -0
- package/deps/libmdbx/src/dpl.h +134 -0
- package/deps/libmdbx/src/dxb.c +1335 -0
- package/deps/libmdbx/src/env.c +607 -0
- package/deps/libmdbx/src/essentials.h +125 -0
- package/deps/libmdbx/src/gc-get.c +1345 -0
- package/deps/libmdbx/src/gc-put.c +970 -0
- package/deps/libmdbx/src/gc.h +40 -0
- package/deps/libmdbx/src/global.c +474 -0
- package/deps/libmdbx/src/internals.h +585 -0
- package/deps/libmdbx/src/layout-dxb.h +288 -0
- package/deps/libmdbx/src/layout-lck.h +289 -0
- package/deps/libmdbx/src/lck-posix.c +859 -0
- package/deps/libmdbx/src/lck-windows.c +607 -0
- package/deps/libmdbx/src/lck.c +174 -0
- package/deps/libmdbx/src/lck.h +110 -0
- package/deps/libmdbx/src/logging_and_debug.c +250 -0
- package/deps/libmdbx/src/logging_and_debug.h +159 -0
- package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
- package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
- package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
- package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
- package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
- package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
- package/deps/libmdbx/src/mdbx.c++ +1837 -0
- package/deps/libmdbx/src/meta.c +656 -0
- package/deps/libmdbx/src/meta.h +168 -0
- package/deps/libmdbx/src/mvcc-readers.c +414 -0
- package/deps/libmdbx/src/node.c +365 -0
- package/deps/libmdbx/src/node.h +102 -0
- package/deps/libmdbx/src/ntdll.def +1246 -0
- package/deps/libmdbx/src/options.h +534 -0
- package/deps/libmdbx/src/osal.c +3485 -0
- package/deps/libmdbx/src/osal.h +587 -0
- package/deps/libmdbx/src/page-get.c +483 -0
- package/deps/libmdbx/src/page-iov.c +185 -0
- package/deps/libmdbx/src/page-iov.h +34 -0
- package/deps/libmdbx/src/page-ops.c +744 -0
- package/deps/libmdbx/src/page-ops.h +142 -0
- package/deps/libmdbx/src/pnl.c +236 -0
- package/deps/libmdbx/src/pnl.h +146 -0
- package/deps/libmdbx/src/preface.h +990 -0
- package/deps/libmdbx/src/proto.h +105 -0
- package/deps/libmdbx/src/refund.c +212 -0
- package/deps/libmdbx/src/sort.h +484 -0
- package/deps/libmdbx/src/spill.c +431 -0
- package/deps/libmdbx/src/spill.h +74 -0
- package/deps/libmdbx/src/table.c +107 -0
- package/deps/libmdbx/src/tls.c +551 -0
- package/deps/libmdbx/src/tls.h +43 -0
- package/deps/libmdbx/src/tools/chk.c +673 -0
- package/deps/libmdbx/src/tools/copy.c +166 -0
- package/deps/libmdbx/src/tools/drop.c +199 -0
- package/deps/libmdbx/src/tools/dump.c +515 -0
- package/deps/libmdbx/src/tools/load.c +831 -0
- package/deps/libmdbx/src/tools/stat.c +516 -0
- package/deps/libmdbx/src/tools/wingetopt.c +87 -0
- package/deps/libmdbx/src/tools/wingetopt.h +30 -0
- package/deps/libmdbx/src/tree-ops.c +1554 -0
- package/deps/libmdbx/src/tree-search.c +140 -0
- package/deps/libmdbx/src/txl.c +99 -0
- package/deps/libmdbx/src/txl.h +26 -0
- package/deps/libmdbx/src/txn.c +1083 -0
- package/deps/libmdbx/src/unaligned.h +205 -0
- package/deps/libmdbx/src/utils.c +32 -0
- package/deps/libmdbx/src/utils.h +76 -0
- package/deps/libmdbx/src/version.c.in +44 -0
- package/deps/libmdbx/src/walk.c +290 -0
- package/deps/libmdbx/src/walk.h +20 -0
- package/deps/libmdbx/src/windows-import.c +152 -0
- package/deps/libmdbx/src/windows-import.h +128 -0
- package/deps/libmdbx/test/CMakeLists.txt +317 -0
- package/deps/libmdbx/test/append.c++ +237 -0
- package/deps/libmdbx/test/base.h++ +92 -0
- package/deps/libmdbx/test/battery-tmux.sh +64 -0
- package/deps/libmdbx/test/cases.c++ +118 -0
- package/deps/libmdbx/test/chrono.c++ +134 -0
- package/deps/libmdbx/test/chrono.h++ +85 -0
- package/deps/libmdbx/test/config.c++ +643 -0
- package/deps/libmdbx/test/config.h++ +334 -0
- package/deps/libmdbx/test/copy.c++ +62 -0
- package/deps/libmdbx/test/dead.c++ +39 -0
- package/deps/libmdbx/test/dump-load.sh +40 -0
- package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
- package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
- package/deps/libmdbx/test/extra/dbi.c++ +229 -0
- package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
- package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
- package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
- package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
- package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
- package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
- package/deps/libmdbx/test/extra/open.c++ +96 -0
- package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
- package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
- package/deps/libmdbx/test/extra/probe.c++ +10 -0
- package/deps/libmdbx/test/extra/txn.c++ +407 -0
- package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
- package/deps/libmdbx/test/fork.c++ +263 -0
- package/deps/libmdbx/test/hill.c++ +447 -0
- package/deps/libmdbx/test/jitter.c++ +197 -0
- package/deps/libmdbx/test/keygen.c++ +393 -0
- package/deps/libmdbx/test/keygen.h++ +130 -0
- package/deps/libmdbx/test/log.c++ +358 -0
- package/deps/libmdbx/test/log.h++ +91 -0
- package/deps/libmdbx/test/main.c++ +706 -0
- package/deps/libmdbx/test/nested.c++ +318 -0
- package/deps/libmdbx/test/osal-unix.c++ +647 -0
- package/deps/libmdbx/test/osal-windows.c++ +440 -0
- package/deps/libmdbx/test/osal.h++ +41 -0
- package/deps/libmdbx/test/stochastic.sh +690 -0
- package/deps/libmdbx/test/stub/LICENSE +24 -0
- package/deps/libmdbx/test/stub/README.md +8 -0
- package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
- package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
- package/deps/libmdbx/test/test.c++ +1551 -0
- package/deps/libmdbx/test/test.h++ +298 -0
- package/deps/libmdbx/test/tmux.conf +3 -0
- package/deps/libmdbx/test/try.c++ +30 -0
- package/deps/libmdbx/test/ttl.c++ +240 -0
- package/deps/libmdbx/test/utils.c++ +203 -0
- package/deps/libmdbx/test/utils.h++ +326 -0
- package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
- package/lib/mdbx_evn_async.js +211 -0
- package/lib/mdbx_worker.js +195 -0
- package/lib/nativemou.js +6 -0
- package/package.json +38 -0
- package/src/async/envmou_close.cpp +34 -0
- package/src/async/envmou_close.hpp +32 -0
- package/src/async/envmou_copy_to.cpp +29 -0
- package/src/async/envmou_copy_to.hpp +38 -0
- package/src/async/envmou_keys.cpp +201 -0
- package/src/async/envmou_keys.hpp +50 -0
- package/src/async/envmou_open.cpp +38 -0
- package/src/async/envmou_open.hpp +33 -0
- package/src/async/envmou_query.cpp +167 -0
- package/src/async/envmou_query.hpp +53 -0
- package/src/dbimou.cpp +522 -0
- package/src/dbimou.hpp +82 -0
- package/src/env_arg0.hpp +24 -0
- package/src/envmou.cpp +445 -0
- package/src/envmou.hpp +116 -0
- package/src/modulemou.cpp +113 -0
- package/src/querymou.cpp +177 -0
- package/src/querymou.hpp +93 -0
- package/src/txnmou.cpp +254 -0
- package/src/txnmou.hpp +122 -0
- package/src/typemou.hpp +239 -0
- package/src/valuemou.hpp +194 -0
- package/test/async.js +67 -0
- package/test/e3.js +38 -0
- package/test/e4.js +89 -0
- package/test/e5.js +162 -0
- package/test/test-batch-ops.js +243 -0
- package/test/test-cursor-mode.js +84 -0
- package/test/test-multi-mode.js +87 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#include "internals.h"
|
|
5
|
+
|
|
6
|
+
typedef struct rthc_entry {
|
|
7
|
+
MDBX_env *env;
|
|
8
|
+
} rthc_entry_t;
|
|
9
|
+
|
|
10
|
+
#if MDBX_DEBUG
|
|
11
|
+
#define RTHC_INITIAL_LIMIT 1
|
|
12
|
+
#else
|
|
13
|
+
#define RTHC_INITIAL_LIMIT 16
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
static unsigned rthc_count, rthc_limit = RTHC_INITIAL_LIMIT;
|
|
17
|
+
static rthc_entry_t rthc_table_static[RTHC_INITIAL_LIMIT];
|
|
18
|
+
static rthc_entry_t *rthc_table = rthc_table_static;
|
|
19
|
+
|
|
20
|
+
static int uniq_peek(const osal_mmap_t *pending, osal_mmap_t *scan) {
|
|
21
|
+
int rc;
|
|
22
|
+
uint64_t bait;
|
|
23
|
+
lck_t *const pending_lck = pending->lck;
|
|
24
|
+
lck_t *const scan_lck = scan->lck;
|
|
25
|
+
if (pending_lck) {
|
|
26
|
+
bait = atomic_load64(&pending_lck->bait_uniqueness, mo_AcquireRelease);
|
|
27
|
+
rc = MDBX_SUCCESS;
|
|
28
|
+
} else {
|
|
29
|
+
bait = 0 /* hush MSVC warning */;
|
|
30
|
+
rc = osal_msync(scan, 0, sizeof(lck_t), MDBX_SYNC_DATA);
|
|
31
|
+
if (rc == MDBX_SUCCESS)
|
|
32
|
+
rc = osal_pread(pending->fd, &bait, sizeof(scan_lck->bait_uniqueness), offsetof(lck_t, bait_uniqueness));
|
|
33
|
+
}
|
|
34
|
+
if (likely(rc == MDBX_SUCCESS) && bait == atomic_load64(&scan_lck->bait_uniqueness, mo_AcquireRelease))
|
|
35
|
+
rc = MDBX_RESULT_TRUE;
|
|
36
|
+
|
|
37
|
+
TRACE("uniq-peek: %s, bait 0x%016" PRIx64 ",%s rc %d", pending_lck ? "mem" : "file", bait,
|
|
38
|
+
(rc == MDBX_RESULT_TRUE) ? " found," : (rc ? " FAILED," : ""), rc);
|
|
39
|
+
return rc;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static int uniq_poke(const osal_mmap_t *pending, osal_mmap_t *scan, uint64_t *abra) {
|
|
43
|
+
if (*abra == 0) {
|
|
44
|
+
const uintptr_t tid = osal_thread_self();
|
|
45
|
+
uintptr_t uit = 0;
|
|
46
|
+
memcpy(&uit, &tid, (sizeof(tid) < sizeof(uit)) ? sizeof(tid) : sizeof(uit));
|
|
47
|
+
*abra = rrxmrrxmsx_0(osal_monotime() + UINT64_C(5873865991930747) * uit);
|
|
48
|
+
}
|
|
49
|
+
const uint64_t cadabra =
|
|
50
|
+
rrxmrrxmsx_0(*abra + UINT64_C(7680760450171793) * (unsigned)osal_getpid()) << 24 | *abra >> 40;
|
|
51
|
+
lck_t *const scan_lck = scan->lck;
|
|
52
|
+
atomic_store64(&scan_lck->bait_uniqueness, cadabra, mo_AcquireRelease);
|
|
53
|
+
*abra = *abra * UINT64_C(6364136223846793005) + 1;
|
|
54
|
+
return uniq_peek(pending, scan);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
__cold int rthc_uniq_check(const osal_mmap_t *pending, MDBX_env **found) {
|
|
58
|
+
*found = nullptr;
|
|
59
|
+
uint64_t salt = 0;
|
|
60
|
+
for (size_t i = 0; i < rthc_count; ++i) {
|
|
61
|
+
MDBX_env *const scan = rthc_table[i].env;
|
|
62
|
+
if (!scan->lck_mmap.lck || &scan->lck_mmap == pending)
|
|
63
|
+
continue;
|
|
64
|
+
int err = atomic_load64(&scan->lck_mmap.lck->bait_uniqueness, mo_AcquireRelease)
|
|
65
|
+
? uniq_peek(pending, &scan->lck_mmap)
|
|
66
|
+
: uniq_poke(pending, &scan->lck_mmap, &salt);
|
|
67
|
+
if (err == MDBX_ENODATA) {
|
|
68
|
+
uint64_t length = 0;
|
|
69
|
+
if (likely(osal_filesize(pending->fd, &length) == MDBX_SUCCESS && length == 0)) {
|
|
70
|
+
/* LY: skip checking since LCK-file is empty, i.e. just created. */
|
|
71
|
+
DEBUG("%s", "unique (new/empty lck)");
|
|
72
|
+
return MDBX_SUCCESS;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (err == MDBX_RESULT_TRUE)
|
|
76
|
+
err = uniq_poke(pending, &scan->lck_mmap, &salt);
|
|
77
|
+
if (err == MDBX_RESULT_TRUE) {
|
|
78
|
+
(void)osal_msync(&scan->lck_mmap, 0, sizeof(lck_t), MDBX_SYNC_KICK);
|
|
79
|
+
err = uniq_poke(pending, &scan->lck_mmap, &salt);
|
|
80
|
+
}
|
|
81
|
+
if (err == MDBX_RESULT_TRUE) {
|
|
82
|
+
err = uniq_poke(pending, &scan->lck_mmap, &salt);
|
|
83
|
+
*found = scan;
|
|
84
|
+
DEBUG("found %p", __Wpedantic_format_voidptr(*found));
|
|
85
|
+
return MDBX_SUCCESS;
|
|
86
|
+
}
|
|
87
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
88
|
+
DEBUG("failed rc %d", err);
|
|
89
|
+
return err;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
DEBUG("%s", "unique");
|
|
94
|
+
return MDBX_SUCCESS;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//------------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
100
|
+
static CRITICAL_SECTION rthc_critical_section;
|
|
101
|
+
#else
|
|
102
|
+
|
|
103
|
+
static pthread_mutex_t rthc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
104
|
+
static pthread_cond_t rthc_cond = PTHREAD_COND_INITIALIZER;
|
|
105
|
+
static osal_thread_key_t rthc_key;
|
|
106
|
+
static mdbx_atomic_uint32_t rthc_pending;
|
|
107
|
+
|
|
108
|
+
static inline uint64_t rthc_signature(const void *addr, uint8_t kind) {
|
|
109
|
+
uint64_t salt = osal_thread_self() * UINT64_C(0xA2F0EEC059629A17) ^ UINT64_C(0x01E07C6FDB596497) * (uintptr_t)(addr);
|
|
110
|
+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
111
|
+
return salt << 8 | kind;
|
|
112
|
+
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
113
|
+
return (uint64_t)kind << 56 | salt >> 8;
|
|
114
|
+
#else
|
|
115
|
+
#error "FIXME: Unsupported byte order"
|
|
116
|
+
#endif /* __BYTE_ORDER__ */
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#define MDBX_THREAD_RTHC_REGISTERED(addr) rthc_signature(addr, 0x0D)
|
|
120
|
+
#define MDBX_THREAD_RTHC_COUNTED(addr) rthc_signature(addr, 0xC0)
|
|
121
|
+
static __thread uint64_t rthc_thread_state
|
|
122
|
+
#if __has_attribute(tls_model) && (defined(__PIC__) || defined(__pic__) || MDBX_BUILD_SHARED_LIBRARY)
|
|
123
|
+
__attribute__((tls_model("local-dynamic")))
|
|
124
|
+
#endif
|
|
125
|
+
;
|
|
126
|
+
|
|
127
|
+
#if defined(__APPLE__) && defined(__SANITIZE_ADDRESS__) && !defined(MDBX_ATTRIBUTE_NO_SANITIZE_ADDRESS)
|
|
128
|
+
/* Avoid ASAN-trap due the target TLS-variable feed by Darwin's tlv_free() */
|
|
129
|
+
#define MDBX_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((__no_sanitize_address__, __noinline__))
|
|
130
|
+
#else
|
|
131
|
+
#define MDBX_ATTRIBUTE_NO_SANITIZE_ADDRESS inline
|
|
132
|
+
#endif
|
|
133
|
+
|
|
134
|
+
MDBX_ATTRIBUTE_NO_SANITIZE_ADDRESS static uint64_t rthc_read(const void *rthc) { return *(volatile uint64_t *)rthc; }
|
|
135
|
+
|
|
136
|
+
MDBX_ATTRIBUTE_NO_SANITIZE_ADDRESS static uint64_t rthc_compare_and_clean(const void *rthc, const uint64_t signature) {
|
|
137
|
+
#if MDBX_64BIT_CAS
|
|
138
|
+
return atomic_cas64((mdbx_atomic_uint64_t *)rthc, signature, 0);
|
|
139
|
+
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
140
|
+
return atomic_cas32((mdbx_atomic_uint32_t *)rthc, (uint32_t)signature, 0);
|
|
141
|
+
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
142
|
+
return atomic_cas32((mdbx_atomic_uint32_t *)rthc, (uint32_t)(signature >> 32), 0);
|
|
143
|
+
#else
|
|
144
|
+
#error "FIXME: Unsupported byte order"
|
|
145
|
+
#endif
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static inline int rthc_atexit(void (*dtor)(void *), void *obj, void *dso_symbol) {
|
|
149
|
+
#ifndef MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL
|
|
150
|
+
#if defined(LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) || defined(HAVE___CXA_THREAD_ATEXIT_IMPL) || \
|
|
151
|
+
__GLIBC_PREREQ(2, 18) || defined(BIONIC)
|
|
152
|
+
#define MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL 1
|
|
153
|
+
#else
|
|
154
|
+
#define MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL 0
|
|
155
|
+
#endif
|
|
156
|
+
#endif /* MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL */
|
|
157
|
+
|
|
158
|
+
#ifndef MDBX_HAVE_CXA_THREAD_ATEXIT
|
|
159
|
+
#if defined(LIBCXXABI_HAS_CXA_THREAD_ATEXIT) || defined(HAVE___CXA_THREAD_ATEXIT)
|
|
160
|
+
#define MDBX_HAVE_CXA_THREAD_ATEXIT 1
|
|
161
|
+
#elif !MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL && (defined(__linux__) || defined(__gnu_linux__))
|
|
162
|
+
#define MDBX_HAVE_CXA_THREAD_ATEXIT 1
|
|
163
|
+
#else
|
|
164
|
+
#define MDBX_HAVE_CXA_THREAD_ATEXIT 0
|
|
165
|
+
#endif
|
|
166
|
+
#endif /* MDBX_HAVE_CXA_THREAD_ATEXIT */
|
|
167
|
+
|
|
168
|
+
int rc = MDBX_ENOSYS;
|
|
169
|
+
#if MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL && !MDBX_HAVE_CXA_THREAD_ATEXIT
|
|
170
|
+
#define __cxa_thread_atexit __cxa_thread_atexit_impl
|
|
171
|
+
#endif
|
|
172
|
+
#if MDBX_HAVE_CXA_THREAD_ATEXIT || defined(__cxa_thread_atexit)
|
|
173
|
+
extern int __cxa_thread_atexit(void (*dtor)(void *), void *obj, void *dso_symbol) MDBX_WEAK_IMPORT_ATTRIBUTE;
|
|
174
|
+
if (&__cxa_thread_atexit)
|
|
175
|
+
rc = __cxa_thread_atexit(dtor, obj, dso_symbol);
|
|
176
|
+
#elif defined(__APPLE__) || defined(_DARWIN_C_SOURCE)
|
|
177
|
+
extern void _tlv_atexit(void (*termfunc)(void *objAddr), void *objAddr) MDBX_WEAK_IMPORT_ATTRIBUTE;
|
|
178
|
+
if (&_tlv_atexit) {
|
|
179
|
+
(void)dso_symbol;
|
|
180
|
+
_tlv_atexit(dtor, obj);
|
|
181
|
+
rc = 0;
|
|
182
|
+
}
|
|
183
|
+
#else
|
|
184
|
+
(void)dtor;
|
|
185
|
+
(void)obj;
|
|
186
|
+
(void)dso_symbol;
|
|
187
|
+
#endif
|
|
188
|
+
return rc;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
__cold void workaround_glibc_bug21031(void) {
|
|
192
|
+
/* Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=21031
|
|
193
|
+
*
|
|
194
|
+
* Due race between pthread_key_delete() and __nptl_deallocate_tsd()
|
|
195
|
+
* The destructor(s) of thread-local-storage object(s) may be running
|
|
196
|
+
* in another thread(s) and be blocked or not finished yet.
|
|
197
|
+
* In such case we get a SEGFAULT after unload this library DSO.
|
|
198
|
+
*
|
|
199
|
+
* So just by yielding a few timeslices we give a chance
|
|
200
|
+
* to such destructor(s) for completion and avoids segfault. */
|
|
201
|
+
sched_yield();
|
|
202
|
+
sched_yield();
|
|
203
|
+
sched_yield();
|
|
204
|
+
}
|
|
205
|
+
#endif /* !Windows */
|
|
206
|
+
|
|
207
|
+
void rthc_lock(void) {
|
|
208
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
209
|
+
EnterCriticalSection(&rthc_critical_section);
|
|
210
|
+
#else
|
|
211
|
+
ENSURE(nullptr, osal_pthread_mutex_lock(&rthc_mutex) == 0);
|
|
212
|
+
#endif
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
void rthc_unlock(void) {
|
|
216
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
217
|
+
LeaveCriticalSection(&rthc_critical_section);
|
|
218
|
+
#else
|
|
219
|
+
ENSURE(nullptr, pthread_mutex_unlock(&rthc_mutex) == 0);
|
|
220
|
+
#endif
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static inline int thread_key_create(osal_thread_key_t *key) {
|
|
224
|
+
int rc;
|
|
225
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
226
|
+
*key = TlsAlloc();
|
|
227
|
+
rc = (*key != TLS_OUT_OF_INDEXES) ? MDBX_SUCCESS : GetLastError();
|
|
228
|
+
#else
|
|
229
|
+
rc = pthread_key_create(key, nullptr);
|
|
230
|
+
#endif
|
|
231
|
+
TRACE("&key = %p, value %" PRIuPTR ", rc %d", __Wpedantic_format_voidptr(key), (uintptr_t)*key, rc);
|
|
232
|
+
return rc;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void thread_rthc_set(osal_thread_key_t key, const void *value) {
|
|
236
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
237
|
+
ENSURE(nullptr, TlsSetValue(key, (void *)value));
|
|
238
|
+
#else
|
|
239
|
+
const uint64_t sign_registered = MDBX_THREAD_RTHC_REGISTERED(&rthc_thread_state);
|
|
240
|
+
const uint64_t sign_counted = MDBX_THREAD_RTHC_COUNTED(&rthc_thread_state);
|
|
241
|
+
if (value && unlikely(rthc_thread_state != sign_registered && rthc_thread_state != sign_counted)) {
|
|
242
|
+
rthc_thread_state = sign_registered;
|
|
243
|
+
TRACE("thread registered 0x%" PRIxPTR, osal_thread_self());
|
|
244
|
+
if (rthc_atexit(rthc_thread_dtor, &rthc_thread_state, (void *)&mdbx_version /* dso_anchor */)) {
|
|
245
|
+
ENSURE(nullptr, pthread_setspecific(rthc_key, &rthc_thread_state) == 0);
|
|
246
|
+
rthc_thread_state = sign_counted;
|
|
247
|
+
const unsigned count_before = atomic_add32(&rthc_pending, 1);
|
|
248
|
+
ENSURE(nullptr, count_before < INT_MAX);
|
|
249
|
+
NOTICE("fallback to pthreads' tsd, key %" PRIuPTR ", count %u", (uintptr_t)rthc_key, count_before);
|
|
250
|
+
(void)count_before;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
ENSURE(nullptr, pthread_setspecific(key, value) == 0);
|
|
254
|
+
#endif
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* dtor called for thread, i.e. for all mdbx's environment objects */
|
|
258
|
+
__cold void rthc_thread_dtor(void *rthc) {
|
|
259
|
+
rthc_lock();
|
|
260
|
+
const uint32_t current_pid = osal_getpid();
|
|
261
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
262
|
+
TRACE(">> pid %d, thread 0x%" PRIxPTR ", module %p", current_pid, osal_thread_self(), rthc);
|
|
263
|
+
#else
|
|
264
|
+
TRACE(">> pid %d, thread 0x%" PRIxPTR ", rthc %p", current_pid, osal_thread_self(), rthc);
|
|
265
|
+
#endif
|
|
266
|
+
|
|
267
|
+
for (size_t i = 0; i < rthc_count; ++i) {
|
|
268
|
+
MDBX_env *const env = rthc_table[i].env;
|
|
269
|
+
if (env->pid != current_pid)
|
|
270
|
+
continue;
|
|
271
|
+
if (!(env->flags & ENV_TXKEY))
|
|
272
|
+
continue;
|
|
273
|
+
reader_slot_t *const reader = thread_rthc_get(env->me_txkey);
|
|
274
|
+
reader_slot_t *const begin = &env->lck_mmap.lck->rdt[0];
|
|
275
|
+
reader_slot_t *const end = &env->lck_mmap.lck->rdt[env->max_readers];
|
|
276
|
+
if (reader < begin || reader >= end)
|
|
277
|
+
continue;
|
|
278
|
+
#if !defined(_WIN32) && !defined(_WIN64)
|
|
279
|
+
if (pthread_setspecific(env->me_txkey, nullptr) != 0) {
|
|
280
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p: ignore race with tsd-key deletion", osal_thread_self(),
|
|
281
|
+
__Wpedantic_format_voidptr(reader));
|
|
282
|
+
continue /* ignore race with tsd-key deletion by mdbx_env_close() */;
|
|
283
|
+
}
|
|
284
|
+
#endif
|
|
285
|
+
|
|
286
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, [%zi], %p ... %p (%+i), rtch-pid %i, "
|
|
287
|
+
"current-pid %i",
|
|
288
|
+
osal_thread_self(), __Wpedantic_format_voidptr(reader), i, __Wpedantic_format_voidptr(begin),
|
|
289
|
+
__Wpedantic_format_voidptr(end), (int)(reader - begin), reader->pid.weak, current_pid);
|
|
290
|
+
if (atomic_load32(&reader->pid, mo_Relaxed) == current_pid) {
|
|
291
|
+
TRACE("==== thread 0x%" PRIxPTR ", rthc %p, cleanup", osal_thread_self(), __Wpedantic_format_voidptr(reader));
|
|
292
|
+
(void)atomic_cas32(&reader->pid, current_pid, 0);
|
|
293
|
+
atomic_store32(&env->lck->rdt_refresh_flag, true, mo_Relaxed);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
298
|
+
TRACE("<< thread 0x%" PRIxPTR ", module %p", osal_thread_self(), rthc);
|
|
299
|
+
rthc_unlock();
|
|
300
|
+
#else
|
|
301
|
+
const uint64_t sign_registered = MDBX_THREAD_RTHC_REGISTERED(rthc);
|
|
302
|
+
const uint64_t sign_counted = MDBX_THREAD_RTHC_COUNTED(rthc);
|
|
303
|
+
const uint64_t state = rthc_read(rthc);
|
|
304
|
+
if (state == sign_registered && rthc_compare_and_clean(rthc, sign_registered)) {
|
|
305
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(), rthc,
|
|
306
|
+
osal_getpid(), "registered", state);
|
|
307
|
+
} else if (state == sign_counted && rthc_compare_and_clean(rthc, sign_counted)) {
|
|
308
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(), rthc,
|
|
309
|
+
osal_getpid(), "counted", state);
|
|
310
|
+
ENSURE(nullptr, atomic_sub32(&rthc_pending, 1) > 0);
|
|
311
|
+
} else {
|
|
312
|
+
WARNING("thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(), rthc,
|
|
313
|
+
osal_getpid(), "wrong", state);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (atomic_load32(&rthc_pending, mo_AcquireRelease) == 0) {
|
|
317
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, wake", osal_thread_self(), rthc, osal_getpid());
|
|
318
|
+
ENSURE(nullptr, pthread_cond_broadcast(&rthc_cond) == 0);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
TRACE("<< thread 0x%" PRIxPTR ", rthc %p", osal_thread_self(), rthc);
|
|
322
|
+
/* Allow tail call optimization, i.e. gcc should generate the jmp instruction
|
|
323
|
+
* instead of a call for pthread_mutex_unlock() and therefore CPU could not
|
|
324
|
+
* return to current DSO's code section, which may be unloaded immediately
|
|
325
|
+
* after the mutex got released. */
|
|
326
|
+
pthread_mutex_unlock(&rthc_mutex);
|
|
327
|
+
#endif
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
__cold int rthc_register(MDBX_env *const env) {
|
|
331
|
+
TRACE(">> env %p, rthc_count %u, rthc_limit %u", __Wpedantic_format_voidptr(env), rthc_count, rthc_limit);
|
|
332
|
+
|
|
333
|
+
int rc = MDBX_SUCCESS;
|
|
334
|
+
for (size_t i = 0; i < rthc_count; ++i)
|
|
335
|
+
if (unlikely(rthc_table[i].env == env)) {
|
|
336
|
+
rc = MDBX_PANIC;
|
|
337
|
+
goto bailout;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
env->me_txkey = 0;
|
|
341
|
+
if (unlikely(rthc_count == rthc_limit)) {
|
|
342
|
+
rthc_entry_t *new_table =
|
|
343
|
+
osal_realloc((rthc_table == rthc_table_static) ? nullptr : rthc_table, sizeof(rthc_entry_t) * rthc_limit * 2);
|
|
344
|
+
if (unlikely(new_table == nullptr)) {
|
|
345
|
+
rc = MDBX_ENOMEM;
|
|
346
|
+
goto bailout;
|
|
347
|
+
}
|
|
348
|
+
if (rthc_table == rthc_table_static)
|
|
349
|
+
memcpy(new_table, rthc_table, sizeof(rthc_entry_t) * rthc_limit);
|
|
350
|
+
rthc_table = new_table;
|
|
351
|
+
rthc_limit *= 2;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if ((env->flags & MDBX_NOSTICKYTHREADS) == 0) {
|
|
355
|
+
rc = thread_key_create(&env->me_txkey);
|
|
356
|
+
if (unlikely(rc != MDBX_SUCCESS))
|
|
357
|
+
goto bailout;
|
|
358
|
+
env->flags |= ENV_TXKEY;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
rthc_table[rthc_count].env = env;
|
|
362
|
+
TRACE("== [%i] = env %p, key %" PRIuPTR, rthc_count, __Wpedantic_format_voidptr(env), (uintptr_t)env->me_txkey);
|
|
363
|
+
++rthc_count;
|
|
364
|
+
|
|
365
|
+
bailout:
|
|
366
|
+
TRACE("<< env %p, key %" PRIuPTR ", rthc_count %u, rthc_limit %u, rc %d", __Wpedantic_format_voidptr(env),
|
|
367
|
+
(uintptr_t)env->me_txkey, rthc_count, rthc_limit, rc);
|
|
368
|
+
return rc;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
__cold static int rthc_drown(MDBX_env *const env) {
|
|
372
|
+
const uint32_t current_pid = osal_getpid();
|
|
373
|
+
int rc = MDBX_SUCCESS;
|
|
374
|
+
MDBX_env *inprocess_neighbor = nullptr;
|
|
375
|
+
if (likely(env->lck_mmap.lck && current_pid == env->pid)) {
|
|
376
|
+
reader_slot_t *const begin = &env->lck_mmap.lck->rdt[0];
|
|
377
|
+
reader_slot_t *const end = &env->lck_mmap.lck->rdt[env->max_readers];
|
|
378
|
+
TRACE("== %s env %p pid %d, readers %p ...%p, current-pid %d", (current_pid == env->pid) ? "cleanup" : "skip",
|
|
379
|
+
__Wpedantic_format_voidptr(env), env->pid, __Wpedantic_format_voidptr(begin), __Wpedantic_format_voidptr(end),
|
|
380
|
+
current_pid);
|
|
381
|
+
bool cleaned = false;
|
|
382
|
+
for (reader_slot_t *r = begin; r < end; ++r) {
|
|
383
|
+
if (atomic_load32(&r->pid, mo_Relaxed) == current_pid) {
|
|
384
|
+
atomic_store32(&r->pid, 0, mo_AcquireRelease);
|
|
385
|
+
TRACE("== cleanup %p", __Wpedantic_format_voidptr(r));
|
|
386
|
+
cleaned = true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (cleaned)
|
|
390
|
+
atomic_store32(&env->lck_mmap.lck->rdt_refresh_flag, true, mo_Relaxed);
|
|
391
|
+
rc = rthc_uniq_check(&env->lck_mmap, &inprocess_neighbor);
|
|
392
|
+
if (!inprocess_neighbor && env->registered_reader_pid && env->lck_mmap.fd != INVALID_HANDLE_VALUE) {
|
|
393
|
+
int err = lck_rpid_clear(env);
|
|
394
|
+
rc = rc ? rc : err;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
int err = lck_destroy(env, inprocess_neighbor, current_pid);
|
|
398
|
+
env->pid = 0;
|
|
399
|
+
return rc ? rc : err;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
__cold int rthc_remove(MDBX_env *const env) {
|
|
403
|
+
TRACE(">>> env %p, key %zu, rthc_count %u, rthc_limit %u", __Wpedantic_format_voidptr(env), (uintptr_t)env->me_txkey,
|
|
404
|
+
rthc_count, rthc_limit);
|
|
405
|
+
|
|
406
|
+
int rc = MDBX_SUCCESS;
|
|
407
|
+
if (likely(env->pid))
|
|
408
|
+
rc = rthc_drown(env);
|
|
409
|
+
|
|
410
|
+
for (size_t i = 0; i < rthc_count; ++i) {
|
|
411
|
+
if (rthc_table[i].env == env) {
|
|
412
|
+
if (--rthc_count > 0)
|
|
413
|
+
rthc_table[i] = rthc_table[rthc_count];
|
|
414
|
+
else if (rthc_table != rthc_table_static) {
|
|
415
|
+
void *tmp = rthc_table;
|
|
416
|
+
rthc_table = rthc_table_static;
|
|
417
|
+
rthc_limit = RTHC_INITIAL_LIMIT;
|
|
418
|
+
osal_memory_barrier();
|
|
419
|
+
osal_free(tmp);
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
TRACE("<<< %p, key %zu, rthc_count %u, rthc_limit %u", __Wpedantic_format_voidptr(env), (uintptr_t)env->me_txkey,
|
|
426
|
+
rthc_count, rthc_limit);
|
|
427
|
+
return rc;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
#if !defined(_WIN32) && !defined(_WIN64)
|
|
431
|
+
__cold void rthc_afterfork(void) {
|
|
432
|
+
NOTICE("drown %d rthc entries", rthc_count);
|
|
433
|
+
for (size_t i = 0; i < rthc_count; ++i) {
|
|
434
|
+
MDBX_env *const env = rthc_table[i].env;
|
|
435
|
+
NOTICE("drown env %p", __Wpedantic_format_voidptr(env));
|
|
436
|
+
if (env->lck_mmap.lck)
|
|
437
|
+
osal_munmap(&env->lck_mmap);
|
|
438
|
+
if (env->dxb_mmap.base) {
|
|
439
|
+
osal_munmap(&env->dxb_mmap);
|
|
440
|
+
#ifdef ENABLE_MEMCHECK
|
|
441
|
+
VALGRIND_DISCARD(env->valgrind_handle);
|
|
442
|
+
env->valgrind_handle = -1;
|
|
443
|
+
#endif /* ENABLE_MEMCHECK */
|
|
444
|
+
}
|
|
445
|
+
env->lck = lckless_stub(env);
|
|
446
|
+
rthc_drown(env);
|
|
447
|
+
}
|
|
448
|
+
if (rthc_table != rthc_table_static)
|
|
449
|
+
osal_free(rthc_table);
|
|
450
|
+
rthc_count = 0;
|
|
451
|
+
rthc_table = rthc_table_static;
|
|
452
|
+
rthc_limit = RTHC_INITIAL_LIMIT;
|
|
453
|
+
rthc_pending.weak = 0;
|
|
454
|
+
}
|
|
455
|
+
#endif /* ! Windows */
|
|
456
|
+
|
|
457
|
+
__cold void rthc_ctor(void) {
|
|
458
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
459
|
+
InitializeCriticalSection(&rthc_critical_section);
|
|
460
|
+
#else
|
|
461
|
+
ENSURE(nullptr, pthread_atfork(nullptr, nullptr, rthc_afterfork) == 0);
|
|
462
|
+
ENSURE(nullptr, pthread_key_create(&rthc_key, rthc_thread_dtor) == 0);
|
|
463
|
+
TRACE("pid %d, &mdbx_rthc_key = %p, value 0x%x", osal_getpid(), __Wpedantic_format_voidptr(&rthc_key),
|
|
464
|
+
(unsigned)rthc_key);
|
|
465
|
+
#endif
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
__cold void rthc_dtor(const uint32_t current_pid) {
|
|
469
|
+
rthc_lock();
|
|
470
|
+
#if !defined(_WIN32) && !defined(_WIN64)
|
|
471
|
+
uint64_t *rthc = pthread_getspecific(rthc_key);
|
|
472
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status 0x%08" PRIx64 ", left %d", osal_thread_self(),
|
|
473
|
+
__Wpedantic_format_voidptr(rthc), current_pid, rthc ? rthc_read(rthc) : ~UINT64_C(0),
|
|
474
|
+
atomic_load32(&rthc_pending, mo_Relaxed));
|
|
475
|
+
if (rthc) {
|
|
476
|
+
const uint64_t sign_registered = MDBX_THREAD_RTHC_REGISTERED(rthc);
|
|
477
|
+
const uint64_t sign_counted = MDBX_THREAD_RTHC_COUNTED(rthc);
|
|
478
|
+
const uint64_t state = rthc_read(rthc);
|
|
479
|
+
if (state == sign_registered && rthc_compare_and_clean(rthc, sign_registered)) {
|
|
480
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(),
|
|
481
|
+
__Wpedantic_format_voidptr(rthc), current_pid, "registered", state);
|
|
482
|
+
} else if (state == sign_counted && rthc_compare_and_clean(rthc, sign_counted)) {
|
|
483
|
+
TRACE("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(),
|
|
484
|
+
__Wpedantic_format_voidptr(rthc), current_pid, "counted", state);
|
|
485
|
+
ENSURE(nullptr, atomic_sub32(&rthc_pending, 1) > 0);
|
|
486
|
+
} else {
|
|
487
|
+
WARNING("thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %s (0x%08" PRIx64 ")", osal_thread_self(),
|
|
488
|
+
__Wpedantic_format_voidptr(rthc), current_pid, "wrong", state);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
struct timespec abstime;
|
|
493
|
+
ENSURE(nullptr, clock_gettime(CLOCK_REALTIME, &abstime) == 0);
|
|
494
|
+
abstime.tv_nsec += 1000000000l / 10;
|
|
495
|
+
if (abstime.tv_nsec >= 1000000000l) {
|
|
496
|
+
abstime.tv_nsec -= 1000000000l;
|
|
497
|
+
abstime.tv_sec += 1;
|
|
498
|
+
}
|
|
499
|
+
#if MDBX_DEBUG > 0
|
|
500
|
+
abstime.tv_sec += 600;
|
|
501
|
+
#endif
|
|
502
|
+
|
|
503
|
+
for (unsigned left; (left = atomic_load32(&rthc_pending, mo_AcquireRelease)) > 0;) {
|
|
504
|
+
NOTICE("tls-cleanup: pid %d, pending %u, wait for...", current_pid, left);
|
|
505
|
+
const int rc = pthread_cond_timedwait(&rthc_cond, &rthc_mutex, &abstime);
|
|
506
|
+
if (rc && rc != EINTR)
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
thread_key_delete(rthc_key);
|
|
510
|
+
#endif
|
|
511
|
+
|
|
512
|
+
for (size_t i = 0; i < rthc_count; ++i) {
|
|
513
|
+
MDBX_env *const env = rthc_table[i].env;
|
|
514
|
+
if (env->pid != current_pid)
|
|
515
|
+
continue;
|
|
516
|
+
if (!(env->flags & ENV_TXKEY))
|
|
517
|
+
continue;
|
|
518
|
+
env->flags -= ENV_TXKEY;
|
|
519
|
+
reader_slot_t *const begin = &env->lck_mmap.lck->rdt[0];
|
|
520
|
+
reader_slot_t *const end = &env->lck_mmap.lck->rdt[env->max_readers];
|
|
521
|
+
thread_key_delete(env->me_txkey);
|
|
522
|
+
bool cleaned = false;
|
|
523
|
+
for (reader_slot_t *reader = begin; reader < end; ++reader) {
|
|
524
|
+
TRACE("== [%zi] = key %" PRIuPTR ", %p ... %p, rthc %p (%+i), "
|
|
525
|
+
"rthc-pid %i, current-pid %i",
|
|
526
|
+
i, (uintptr_t)env->me_txkey, __Wpedantic_format_voidptr(begin), __Wpedantic_format_voidptr(end),
|
|
527
|
+
__Wpedantic_format_voidptr(reader), (int)(reader - begin), reader->pid.weak, current_pid);
|
|
528
|
+
if (atomic_load32(&reader->pid, mo_Relaxed) == current_pid) {
|
|
529
|
+
(void)atomic_cas32(&reader->pid, current_pid, 0);
|
|
530
|
+
TRACE("== cleanup %p", __Wpedantic_format_voidptr(reader));
|
|
531
|
+
cleaned = true;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (cleaned)
|
|
535
|
+
atomic_store32(&env->lck->rdt_refresh_flag, true, mo_Relaxed);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
rthc_limit = rthc_count = 0;
|
|
539
|
+
if (rthc_table != rthc_table_static)
|
|
540
|
+
osal_free(rthc_table);
|
|
541
|
+
rthc_table = nullptr;
|
|
542
|
+
rthc_unlock();
|
|
543
|
+
|
|
544
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
545
|
+
DeleteCriticalSection(&rthc_critical_section);
|
|
546
|
+
#else
|
|
547
|
+
/* LY: yielding a few timeslices to give a more chance
|
|
548
|
+
* to racing destructor(s) for completion. */
|
|
549
|
+
workaround_glibc_bug21031();
|
|
550
|
+
#endif
|
|
551
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "essentials.h"
|
|
7
|
+
|
|
8
|
+
MDBX_INTERNAL void rthc_ctor(void);
|
|
9
|
+
MDBX_INTERNAL void rthc_dtor(const uint32_t current_pid);
|
|
10
|
+
MDBX_INTERNAL void rthc_lock(void);
|
|
11
|
+
MDBX_INTERNAL void rthc_unlock(void);
|
|
12
|
+
|
|
13
|
+
MDBX_INTERNAL int rthc_register(MDBX_env *const env);
|
|
14
|
+
MDBX_INTERNAL int rthc_remove(MDBX_env *const env);
|
|
15
|
+
MDBX_INTERNAL int rthc_uniq_check(const osal_mmap_t *pending, MDBX_env **found);
|
|
16
|
+
|
|
17
|
+
/* dtor called for thread, i.e. for all mdbx's environment objects */
|
|
18
|
+
MDBX_INTERNAL void rthc_thread_dtor(void *rthc);
|
|
19
|
+
|
|
20
|
+
static inline void *thread_rthc_get(osal_thread_key_t key) {
|
|
21
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
22
|
+
return TlsGetValue(key);
|
|
23
|
+
#else
|
|
24
|
+
return pthread_getspecific(key);
|
|
25
|
+
#endif
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
MDBX_INTERNAL void thread_rthc_set(osal_thread_key_t key, const void *value);
|
|
29
|
+
|
|
30
|
+
#if !defined(_WIN32) && !defined(_WIN64)
|
|
31
|
+
MDBX_INTERNAL void rthc_afterfork(void);
|
|
32
|
+
MDBX_INTERNAL void workaround_glibc_bug21031(void);
|
|
33
|
+
#endif /* !Windows */
|
|
34
|
+
|
|
35
|
+
static inline void thread_key_delete(osal_thread_key_t key) {
|
|
36
|
+
TRACE("key = %" PRIuPTR, (uintptr_t)key);
|
|
37
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
38
|
+
ENSURE(nullptr, TlsFree(key));
|
|
39
|
+
#else
|
|
40
|
+
ENSURE(nullptr, pthread_key_delete(key) == 0);
|
|
41
|
+
workaround_glibc_bug21031();
|
|
42
|
+
#endif
|
|
43
|
+
}
|