diff --git a/src/lck-posix.c b/src/lck-posix.c index 5aa818d8..f253c4f8 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -32,7 +32,7 @@ /*----------------------------------------------------------------------------*/ /* rthc */ -static mdbx_mutex_t mdbx_rthc_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mdbx_rthc_mutex = PTHREAD_MUTEX_INITIALIZER; void mdbx_rthc_lock(void) { mdbx_ensure(NULL, pthread_mutex_lock(&mdbx_rthc_mutex) == 0); @@ -273,7 +273,8 @@ int mdbx_lck_seize(MDB_env *env) { #define pthread_mutex_consistent(mutex) pthread_mutex_consistent_np(mutex) #endif -static int __cold mdbx_mutex_failed(MDB_env *env, mdbx_mutex_t *mutex, int rc) { +static int __cold mdbx_mutex_failed(MDB_env *env, pthread_mutex_t *mutex, + int rc) { #if MDB_USE_ROBUST if (rc == EOWNERDEAD) { /* We own the mutex. Clean up after dead previous owner. */ diff --git a/src/mdbx.c b/src/mdbx.c index 6c6941fa..c06485c1 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -8137,8 +8137,7 @@ int mdbx_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, typedef struct mdbx_copy { MDB_env *mc_env; MDB_txn *mc_txn; - mdbx_mutex_t mc_mutex; - mdbx_cond_t mc_cond; /* Condition variable for mc_new */ + mdbx_condmutex_t mc_condmutex; char *mc_wbuf[2]; char *mc_over[2]; int mc_wlen[2]; @@ -8158,10 +8157,10 @@ static THREAD_RESULT __cold THREAD_CALL mdbx_env_copythr(void *arg) { char *ptr; int toggle = 0, wsize; - mdbx_mutex_lock(&my->mc_mutex); + mdbx_condmutex_lock(&my->mc_condmutex); while (!my->mc_error) { while (!my->mc_new) - mdbx_cond_wait(&my->mc_cond, &my->mc_mutex); + mdbx_condmutex_wait(&my->mc_condmutex); if (my->mc_new == 0 + MDB_EOF) /* 0 buffers, just EOF */ break; wsize = my->mc_wlen[toggle]; @@ -8184,9 +8183,9 @@ static THREAD_RESULT __cold THREAD_CALL mdbx_env_copythr(void *arg) { toggle ^= 1; /* Return the empty buffer to provider */ my->mc_new--; - mdbx_cond_signal(&my->mc_cond); + mdbx_condmutex_signal(&my->mc_condmutex); } - mdbx_mutex_unlock(&my->mc_mutex); + mdbx_condmutex_unlock(&my->mc_condmutex); return (THREAD_RESULT)0; } @@ -8195,12 +8194,12 @@ static THREAD_RESULT __cold THREAD_CALL mdbx_env_copythr(void *arg) { * [in] my control structure. * [in] adjust (1 to hand off 1 buffer) | (MDB_EOF when ending). */ static int __cold mdbx_env_cthr_toggle(mdbx_copy *my, int adjust) { - mdbx_mutex_lock(&my->mc_mutex); + mdbx_condmutex_lock(&my->mc_condmutex); my->mc_new += adjust; - mdbx_cond_signal(&my->mc_cond); + mdbx_condmutex_signal(&my->mc_condmutex); while (my->mc_new & 2) /* both buffers in use */ - mdbx_cond_wait(&my->mc_cond, &my->mc_mutex); - mdbx_mutex_unlock(&my->mc_mutex); + mdbx_condmutex_wait(&my->mc_condmutex); + mdbx_condmutex_unlock(&my->mc_condmutex); my->mc_toggle ^= (adjust & 1); /* Both threads reset mc_wlen, to be safe from threading errors */ @@ -8376,10 +8375,8 @@ static int __cold mdbx_env_compact(MDB_env *env, mdbx_filehandle_t fd) { int rc; memset(&my, 0, sizeof(my)); - if ((rc = mdbx_mutex_init(&my.mc_mutex)) != 0) + if ((rc = mdbx_condmutex_init(&my.mc_condmutex)) != 0) return rc; - if ((rc = mdbx_cond_init(&my.mc_cond)) != 0) - goto done2; rc = mdbx_memalign_alloc(env->me_os_psize, MDB_WBUF * 2, (void **)&my.mc_wbuf[0]); if (rc != MDB_SUCCESS) @@ -8457,9 +8454,7 @@ finish: done: mdbx_memalign_free(my.mc_wbuf[0]); - mdbx_cond_destroy(&my.mc_cond); -done2: - mdbx_mutex_destroy(&my.mc_mutex); + mdbx_condmutex_destroy(&my.mc_condmutex); return rc ? rc : my.mc_error; } diff --git a/src/osal.c b/src/osal.c index 0e887dd4..5a0f4009 100644 --- a/src/osal.c +++ b/src/osal.c @@ -164,77 +164,104 @@ void mdbx_memalign_free(void *ptr) { /*----------------------------------------------------------------------------*/ -int mdbx_mutex_init(mdbx_mutex_t *mutex) { +int mdbx_condmutex_init(mdbx_condmutex_t *condmutex) { #if defined(_WIN32) || defined(_WIN64) - *mutex = CreateMutex(NULL, FALSE, NULL); - return *mutex ? MDB_SUCCESS : mdbx_get_errno_checked(); + int rc = MDB_SUCCESS; + condmutex->event = NULL; + condmutex->mutex = CreateMutex(NULL, FALSE, NULL); + if (!condmutex->mutex) + return mdbx_get_errno_checked(); + + condmutex->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!condmutex->event) { + rc = mdbx_get_errno_checked(); + (void)CloseHandle(condmutex->mutex); + condmutex->mutex = NULL; + } + return rc; #else - return pthread_mutex_init(mutex, NULL); + memset(condmutex, 0, sizeof(mdbx_condmutex_t)); + int rc = pthread_mutex_init(&condmutex->mutex, NULL); + if (rc == 0) { + rc = pthread_cond_init(&condmutex->cond, NULL); + if (rc != 0) + (void)pthread_mutex_destroy(&condmutex->mutex); + } + return rc; #endif } -int mdbx_mutex_destroy(mdbx_mutex_t *mutex) { -#if defined(_WIN32) || defined(_WIN64) - return CloseHandle(*mutex) ? MDB_SUCCESS : mdbx_get_errno_checked(); -#else - return pthread_mutex_destroy(mutex); -#endif +static bool is_allzeros(const void *ptr, size_t bytes) { + const uint8_t *u8 = ptr; + for (size_t i = 0; i < bytes; ++i) + if (u8[i] != 0) + return false; + return true; } -int mdbx_mutex_lock(mdbx_mutex_t *mutex) { +int mdbx_condmutex_destroy(mdbx_condmutex_t *condmutex) { + int rc = MDBX_EINVAL; #if defined(_WIN32) || defined(_WIN64) - DWORD code = WaitForSingleObject(*mutex, INFINITE); + if (condmutex->event) { + rc = CloseHandle(condmutex->event) ? MDB_SUCCESS : mdbx_get_errno_checked(); + if (rc == MDB_SUCCESS) + condmutex->event = NULL; + } + if (condmutex->mutex) { + rc = CloseHandle(condmutex->mutex) ? MDB_SUCCESS : mdbx_get_errno_checked(); + if (rc == MDB_SUCCESS) + condmutex->mutex = NULL; + } +#else + if (!is_allzeros(&condmutex->cond, sizeof(condmutex->cond))) { + rc = pthread_cond_destroy(&condmutex->cond); + if (rc == 0) + memset(&condmutex->cond, 0, sizeof(condmutex->cond)); + } + if (!is_allzeros(&condmutex->mutex, sizeof(condmutex->mutex))) { + rc = pthread_mutex_destroy(&condmutex->mutex); + if (rc == 0) + memset(&condmutex->mutex, 0, sizeof(condmutex->mutex)); + } +#endif + return rc; +} + +int mdbx_condmutex_lock(mdbx_condmutex_t *condmutex) { +#if defined(_WIN32) || defined(_WIN64) + DWORD code = WaitForSingleObject(condmutex->mutex, INFINITE); return waitstatus2errcode(code); #else - return pthread_mutex_lock(mutex); + return pthread_mutex_lock(&condmutex->mutex); #endif } -int mdbx_mutex_unlock(mdbx_mutex_t *mutex) { +int mdbx_condmutex_unlock(mdbx_condmutex_t *condmutex) { #if defined(_WIN32) || defined(_WIN64) - return ReleaseMutex(*mutex) ? MDB_SUCCESS : mdbx_get_errno_checked(); + return ReleaseMutex(condmutex->mutex) ? MDB_SUCCESS + : mdbx_get_errno_checked(); #else - return pthread_mutex_unlock(mutex); + return pthread_mutex_unlock(&condmutex->mutex); #endif } -/*----------------------------------------------------------------------------*/ - -int mdbx_cond_init(mdbx_cond_t *cond) { +int mdbx_condmutex_signal(mdbx_condmutex_t *condmutex) { #if defined(_WIN32) || defined(_WIN64) - *cond = CreateEvent(NULL, FALSE, FALSE, NULL); - return *cond ? MDB_SUCCESS : mdbx_get_errno_checked(); + return SetEvent(condmutex->event) ? MDB_SUCCESS : mdbx_get_errno_checked(); #else - return pthread_cond_init(cond, NULL); + return pthread_cond_signal(&condmutex->cond); #endif } -#ifndef mdbx_cond_destroy -int mdbx_cond_destroy(mdbx_cond_t *cond) { +int mdbx_condmutex_wait(mdbx_condmutex_t *condmutex) { #if defined(_WIN32) || defined(_WIN64) - return CloseHandle(*cond) ? MDB_SUCCESS : mdbx_get_errno_checked(); -#else - return pthread_cond_destroy(cond); -#endif -} -#endif /* mdbx_cond_destroy */ - -int mdbx_cond_signal(mdbx_cond_t *cond) { -#if defined(_WIN32) || defined(_WIN64) - return SetEvent(*cond) ? MDB_SUCCESS : mdbx_get_errno_checked(); -#else - return pthread_cond_signal(cond); -#endif -} - -int mdbx_cond_wait(mdbx_cond_t *cond, mdbx_mutex_t *mutex) { -#if defined(_WIN32) || defined(_WIN64) - DWORD code = SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); + DWORD code = + SignalObjectAndWait(condmutex->mutex, condmutex->event, INFINITE, FALSE); if (code == WAIT_OBJECT_0) - code = WaitForSingleObject(*mutex, INFINITE); + code = WaitForSingleObject(condmutex->mutex, INFINITE); return waitstatus2errcode(code); #else - return pthread_cond_wait(cond, mutex); + return pthread_cond_wait(&condmutex->cond, &condmutex->mutex); #endif } diff --git a/src/osal.h b/src/osal.h index 95037d85..661337ca 100644 --- a/src/osal.h +++ b/src/osal.h @@ -57,8 +57,6 @@ #include #define HAVE_SYS_STAT_H #define HAVE_SYS_TYPES_H -typedef HANDLE mdbx_mutex_t; -typedef HANDLE mdbx_cond_t; typedef HANDLE mdbx_thread_t; typedef unsigned mdbx_thread_key_t; typedef SSIZE_T ssize_t; @@ -66,6 +64,10 @@ typedef SSIZE_T ssize_t; #define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0)) #define THREAD_CALL WINAPI #define THREAD_RESULT DWORD +typedef struct { + HANDLE mutex; + HANDLE event; +} mdbx_condmutex_t; #else #include #include @@ -74,13 +76,15 @@ typedef SSIZE_T ssize_t; #include #include #include -typedef pthread_mutex_t mdbx_mutex_t; -typedef pthread_cond_t mdbx_cond_t; typedef pthread_t mdbx_thread_t; typedef pthread_key_t mdbx_thread_key_t; #define INVALID_HANDLE_VALUE (-1) #define THREAD_CALL #define THREAD_RESULT void * +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; +} mdbx_condmutex_t; #endif /* Platform */ #ifndef SSIZE_MAX @@ -384,15 +388,12 @@ static __inline int __mdbx_get_errno_checked(const char *file, unsigned line) { int mdbx_memalign_alloc(size_t alignment, size_t bytes, void **result); void mdbx_memalign_free(void *ptr); -int mdbx_mutex_init(mdbx_mutex_t *mutex); -int mdbx_mutex_destroy(mdbx_mutex_t *mutex); -int mdbx_mutex_lock(mdbx_mutex_t *mutex); -int mdbx_mutex_unlock(mdbx_mutex_t *mutex); - -int mdbx_cond_init(mdbx_cond_t *cond); -int mdbx_cond_destroy(mdbx_cond_t *cond); -int mdbx_cond_signal(mdbx_cond_t *cond); -int mdbx_cond_wait(mdbx_cond_t *cond, mdbx_mutex_t *mutex); +int mdbx_condmutex_init(mdbx_condmutex_t *condmutex); +int mdbx_condmutex_lock(mdbx_condmutex_t *condmutex); +int mdbx_condmutex_unlock(mdbx_condmutex_t *condmutex); +int mdbx_condmutex_signal(mdbx_condmutex_t *condmutex); +int mdbx_condmutex_wait(mdbx_condmutex_t *condmutex); +int mdbx_condmutex_destroy(mdbx_condmutex_t *condmutex); int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt, off_t offset, size_t expected_written);