mdbx: fix/rework rthc counting.

Change-Id: I97fd5bd6dc1a46658138d82db10e937c9595d81f
This commit is contained in:
Leo Yuriev 2018-04-03 18:38:04 +03:00
parent 571b50622e
commit 864be54f01

View File

@ -241,21 +241,26 @@ static void mdbx_thread_rthc_set(mdbx_thread_key_t key, const void *value) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
mdbx_ensure(nullptr, TlsSetValue(key, (void *)value)); mdbx_ensure(nullptr, TlsSetValue(key, (void *)value));
#else #else
static __thread bool thread_registered; #define MDBX_THREAD_RTHC_ZERO 0
if (value && unlikely(!thread_registered)) { #define MDBX_THREAD_RTHC_REGISTERD 1
thread_registered = true; #define MDBX_THREAD_RTHC_COUNTED 2
static __thread uint32_t thread_registration_state;
if (value && unlikely(thread_registration_state == MDBX_THREAD_RTHC_ZERO)) {
thread_registration_state = MDBX_THREAD_RTHC_REGISTERD;
mdbx_trace("thread registered 0x%" PRIxPTR, (uintptr_t)mdbx_thread_self());
if (&__cxa_thread_atexit_impl == nullptr || if (&__cxa_thread_atexit_impl == nullptr ||
__cxa_thread_atexit_impl(mdbx_rthc_thread_dtor, &thread_registered, __cxa_thread_atexit_impl(mdbx_rthc_thread_dtor,
&thread_registration_state,
(void *)&mdbx_version /* dso_anchor */)) { (void *)&mdbx_version /* dso_anchor */)) {
mdbx_ensure(nullptr, mdbx_ensure(nullptr, pthread_setspecific(
pthread_setspecific(mdbx_rthc_key, &thread_registered) == 0); mdbx_rthc_key, &thread_registration_state) == 0);
thread_registration_state = MDBX_THREAD_RTHC_COUNTED;
const unsigned count_before = mdbx_atomic_add32(&mdbx_rthc_pending, 1); const unsigned count_before = mdbx_atomic_add32(&mdbx_rthc_pending, 1);
mdbx_ensure(nullptr, count_before < INT_MAX); mdbx_ensure(nullptr, count_before < INT_MAX);
mdbx_trace("fallback to pthreads' tsd, key 0x%x, count %u", mdbx_trace("fallback to pthreads' tsd, key 0x%x, count %u",
(unsigned)mdbx_rthc_key, count_before); (unsigned)mdbx_rthc_key, count_before);
(void)count_before; (void)count_before;
} }
mdbx_trace("thread registered 0x%" PRIxPTR, (uintptr_t)mdbx_thread_self());
} }
mdbx_ensure(nullptr, pthread_setspecific(key, value) == 0); mdbx_ensure(nullptr, pthread_setspecific(key, value) == 0);
#endif #endif
@ -313,7 +318,14 @@ void mdbx_rthc_thread_dtor(void *ptr) {
ptr); ptr);
mdbx_rthc_unlock(); mdbx_rthc_unlock();
#else #else
mdbx_ensure(nullptr, mdbx_atomic_sub32(&mdbx_rthc_pending, 1) > 0); const char self_registration = *(char *)ptr;
*(char *)ptr = MDBX_THREAD_RTHC_ZERO;
mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %d",
(uintptr_t)mdbx_thread_self(), ptr, mdbx_getpid(),
self_registration);
if (self_registration == MDBX_THREAD_RTHC_COUNTED)
mdbx_ensure(nullptr, mdbx_atomic_sub32(&mdbx_rthc_pending, 1) > 0);
if (mdbx_rthc_pending == 0) { if (mdbx_rthc_pending == 0) {
mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, wake", mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, wake",
(uintptr_t)mdbx_thread_self(), ptr, mdbx_getpid()); (uintptr_t)mdbx_thread_self(), ptr, mdbx_getpid());
@ -337,13 +349,18 @@ __cold void mdbx_rthc_global_dtor(void) {
mdbx_getpid(), &mdbx_rthc_global_dtor, &mdbx_rthc_thread_dtor, mdbx_getpid(), &mdbx_rthc_global_dtor, &mdbx_rthc_thread_dtor,
&mdbx_rthc_remove); &mdbx_rthc_remove);
#if defined(_WIN32) || defined(_WIN64)
mdbx_rthc_lock();
#else
if (pthread_getspecific(mdbx_rthc_key) != nullptr)
mdbx_ensure(nullptr, mdbx_atomic_sub32(&mdbx_rthc_pending, 1) > 0);
mdbx_thread_key_delete(mdbx_rthc_key);
mdbx_rthc_lock(); mdbx_rthc_lock();
#if !defined(_WIN32) && !defined(_WIN64)
char *rthc = (char *)pthread_getspecific(mdbx_rthc_key);
mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %d",
(uintptr_t)mdbx_thread_self(), rthc, mdbx_getpid(),
rthc ? *rthc : -1);
if (rthc) {
const char self_registration = *(char *)rthc;
*rthc = MDBX_THREAD_RTHC_ZERO;
if (self_registration == MDBX_THREAD_RTHC_COUNTED)
mdbx_ensure(nullptr, mdbx_atomic_sub32(&mdbx_rthc_pending, 1) > 0);
}
struct timespec abstime; struct timespec abstime;
mdbx_ensure(nullptr, clock_gettime(CLOCK_REALTIME, &abstime) == 0); mdbx_ensure(nullptr, clock_gettime(CLOCK_REALTIME, &abstime) == 0);
@ -352,18 +369,18 @@ __cold void mdbx_rthc_global_dtor(void) {
abstime.tv_nsec -= 1000000000l; abstime.tv_nsec -= 1000000000l;
abstime.tv_sec += 1; abstime.tv_sec += 1;
} }
#if MDBX_DEBUG > 0
abstime.tv_sec += 600;
#endif
for (unsigned left; (left = mdbx_rthc_pending) > 0;) { for (unsigned left; (left = mdbx_rthc_pending) > 0;) {
mdbx_trace("pid %d, pending %u, wait for...", mdbx_getpid(), left); mdbx_trace("pid %d, pending %u, wait for...", mdbx_getpid(), left);
const int rc = const int rc =
pthread_cond_timedwait(&mdbx_rthc_cond, &mdbx_rthc_mutex, &abstime); pthread_cond_timedwait(&mdbx_rthc_cond, &mdbx_rthc_mutex, &abstime);
if (rc && rc != EINTR) { if (rc && rc != EINTR)
/* LY: yielding a few timeslices to give a more chance
* to racing destructor(s) for completion. */
mdbx_workaround_glibc_bug21031();
break; break;
}
} }
mdbx_thread_key_delete(mdbx_rthc_key);
#endif #endif
const mdbx_pid_t self_pid = mdbx_getpid(); const mdbx_pid_t self_pid = mdbx_getpid();