mirror of
https://github.com/isar/libmdbx.git
synced 2025-11-07 07:18:56 +08:00
mdbx: изменение лицензии и реструктуризация исходного кода.
This commit is contained in:
@@ -1,18 +1,7 @@
|
||||
/*
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2024
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) /* Windows LCK-implementation */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
/* PREAMBLE FOR WINDOWS:
|
||||
*
|
||||
@@ -22,91 +11,6 @@
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
static void mdbx_winnt_import(void);
|
||||
|
||||
#if MDBX_BUILD_SHARED_LIBRARY
|
||||
#if MDBX_WITHOUT_MSVC_CRT && defined(NDEBUG)
|
||||
/* DEBUG/CHECKED builds still require MSVC's CRT for runtime checks.
|
||||
*
|
||||
* Define dll's entry point only for Release build when NDEBUG is defined and
|
||||
* MDBX_WITHOUT_MSVC_CRT=ON. if the entry point isn't defined then MSVC's will
|
||||
* automatically use DllMainCRTStartup() from CRT library, which also
|
||||
* automatically call DllMain() from our mdbx.dll */
|
||||
#pragma comment(linker, "/ENTRY:DllMain")
|
||||
#endif /* MDBX_WITHOUT_MSVC_CRT */
|
||||
|
||||
BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved)
|
||||
#else
|
||||
#if !MDBX_MANUAL_MODULE_HANDLER
|
||||
static
|
||||
#endif /* !MDBX_MANUAL_MODULE_HANDLER */
|
||||
void NTAPI
|
||||
mdbx_module_handler(PVOID module, DWORD reason, PVOID reserved)
|
||||
#endif /* MDBX_BUILD_SHARED_LIBRARY */
|
||||
{
|
||||
(void)reserved;
|
||||
switch (reason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
mdbx_winnt_import();
|
||||
global_ctor();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
global_dtor();
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
thread_dtor(module);
|
||||
break;
|
||||
}
|
||||
#if MDBX_BUILD_SHARED_LIBRARY
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !MDBX_BUILD_SHARED_LIBRARY && !MDBX_MANUAL_MODULE_HANDLER
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
#if defined(_MSC_VER)
|
||||
# pragma const_seg(push)
|
||||
# pragma data_seg(push)
|
||||
|
||||
# ifndef _M_IX86
|
||||
/* kick a linker to create the TLS directory if not already done */
|
||||
# pragma comment(linker, "/INCLUDE:_tls_used")
|
||||
/* Force some symbol references. */
|
||||
# pragma comment(linker, "/INCLUDE:mdbx_tls_anchor")
|
||||
/* specific const-segment for WIN64 */
|
||||
# pragma const_seg(".CRT$XLB")
|
||||
const
|
||||
# else
|
||||
/* kick a linker to create the TLS directory if not already done */
|
||||
# pragma comment(linker, "/INCLUDE:__tls_used")
|
||||
/* Force some symbol references. */
|
||||
# pragma comment(linker, "/INCLUDE:_mdbx_tls_anchor")
|
||||
/* specific data-segment for WIN32 */
|
||||
# pragma data_seg(".CRT$XLB")
|
||||
# endif
|
||||
|
||||
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK mdbx_tls_anchor = mdbx_module_handler;
|
||||
# pragma data_seg(pop)
|
||||
# pragma const_seg(pop)
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
# ifndef _M_IX86
|
||||
const
|
||||
# endif
|
||||
PIMAGE_TLS_CALLBACK mdbx_tls_anchor __attribute__((__section__(".CRT$XLB"), used)) = mdbx_module_handler;
|
||||
#else
|
||||
# error FIXME
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
#endif /* !MDBX_BUILD_SHARED_LIBRARY && !MDBX_MANUAL_MODULE_HANDLER */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#define LCK_SHARED 0
|
||||
#define LCK_EXCLUSIVE LOCKFILE_EXCLUSIVE_LOCK
|
||||
#define LCK_WAITFOR 0
|
||||
@@ -145,17 +49,16 @@ static int flock_with_event(HANDLE fd, HANDLE event, unsigned flags,
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
static __inline int flock(HANDLE fd, unsigned flags, size_t offset,
|
||||
size_t bytes) {
|
||||
static inline int flock(HANDLE fd, unsigned flags, size_t offset,
|
||||
size_t bytes) {
|
||||
return flock_with_event(fd, 0, flags, offset, bytes);
|
||||
}
|
||||
|
||||
static __inline int flock_data(const MDBX_env *env, unsigned flags,
|
||||
size_t offset, size_t bytes) {
|
||||
static inline int flock_data(const MDBX_env *env, unsigned flags, size_t offset,
|
||||
size_t bytes) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
return flock_with_event(fd4data, env->me_data_lock_event, flags, offset,
|
||||
bytes);
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
return flock_with_event(fd4data, env->dxb_lock_event, flags, offset, bytes);
|
||||
}
|
||||
|
||||
static int funlock(mdbx_filehandle_t fd, size_t offset, size_t bytes) {
|
||||
@@ -175,16 +78,16 @@ static int funlock(mdbx_filehandle_t fd, size_t offset, size_t bytes) {
|
||||
#else
|
||||
#define DXB_MAXLEN UINT32_C(0x7ff00000)
|
||||
#endif
|
||||
#define DXB_BODY (env->me_psize * (size_t)NUM_METAS), DXB_MAXLEN
|
||||
#define DXB_BODY (env->ps * (size_t)NUM_METAS), DXB_MAXLEN
|
||||
#define DXB_WHOLE 0, DXB_MAXLEN
|
||||
|
||||
int osal_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
if (dontwait) {
|
||||
if (!TryEnterCriticalSection(&env->me_windowsbug_lock))
|
||||
if (!TryEnterCriticalSection(&env->windowsbug_lock))
|
||||
return MDBX_BUSY;
|
||||
} else {
|
||||
__try {
|
||||
EnterCriticalSection(&env->me_windowsbug_lock);
|
||||
EnterCriticalSection(&env->windowsbug_lock);
|
||||
}
|
||||
__except ((GetExceptionCode() ==
|
||||
0xC0000194 /* STATUS_POSSIBLE_DEADLOCK / EXCEPTION_POSSIBLE_DEADLOCK */)
|
||||
@@ -194,93 +97,93 @@ int osal_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
}
|
||||
|
||||
eASSERT(env, !env->me_txn0->mt_owner);
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
eASSERT(env, !env->basal_txn->owner);
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
goto done;
|
||||
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
int rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
int rc = flock_with_event(fd4data, env->dxb_lock_event,
|
||||
dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT)
|
||||
: (LCK_EXCLUSIVE | LCK_WAITFOR),
|
||||
DXB_BODY);
|
||||
if (rc == ERROR_LOCK_VIOLATION && dontwait) {
|
||||
SleepEx(0, true);
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
rc = flock_with_event(fd4data, env->dxb_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
if (rc == ERROR_LOCK_VIOLATION) {
|
||||
SleepEx(0, true);
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
rc = flock_with_event(fd4data, env->dxb_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
}
|
||||
}
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
done:
|
||||
/* Zap: Failing to release lock 'env->me_windowsbug_lock'
|
||||
/* Zap: Failing to release lock 'env->windowsbug_lock'
|
||||
* in function 'mdbx_txn_lock' */
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(26115);
|
||||
env->me_txn0->mt_owner = osal_thread_self();
|
||||
env->basal_txn->owner = osal_thread_self();
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&env->me_windowsbug_lock);
|
||||
LeaveCriticalSection(&env->windowsbug_lock);
|
||||
return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY;
|
||||
}
|
||||
|
||||
void osal_txn_unlock(MDBX_env *env) {
|
||||
eASSERT(env, env->me_txn0->mt_owner == osal_thread_self());
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) == 0) {
|
||||
void lck_txn_unlock(MDBX_env *env) {
|
||||
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
||||
if ((env->flags & MDBX_EXCLUSIVE) == 0) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
int err = funlock(fd4data, DXB_BODY);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
env->me_txn0->mt_owner = 0;
|
||||
LeaveCriticalSection(&env->me_windowsbug_lock);
|
||||
env->basal_txn->owner = 0;
|
||||
LeaveCriticalSection(&env->windowsbug_lock);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* global `read` lock for readers registration,
|
||||
* exclusive locking `mti_numreaders` (second) cacheline */
|
||||
* exclusive locking `rdt_length` (second) cacheline */
|
||||
|
||||
#define LCK_LO_OFFSET 0
|
||||
#define LCK_LO_LEN offsetof(MDBX_lockinfo, mti_numreaders)
|
||||
#define LCK_LO_LEN offsetof(lck_t, rdt_length)
|
||||
#define LCK_UP_OFFSET LCK_LO_LEN
|
||||
#define LCK_UP_LEN (sizeof(MDBX_lockinfo) - LCK_UP_OFFSET)
|
||||
#define LCK_UP_LEN (sizeof(lck_t) - LCK_UP_OFFSET)
|
||||
#define LCK_LOWER LCK_LO_OFFSET, LCK_LO_LEN
|
||||
#define LCK_UPPER LCK_UP_OFFSET, LCK_UP_LEN
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_rdt_lock(MDBX_env *env) {
|
||||
osal_srwlock_AcquireShared(&env->me_remap_guard);
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE)
|
||||
MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
||||
imports.srwl_AcquireShared(&env->remap_guard);
|
||||
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE)
|
||||
return MDBX_SUCCESS; /* readonly database in readonly filesystem */
|
||||
|
||||
/* transition from S-? (used) to S-E (locked),
|
||||
* e.g. exclusive lock upper-part */
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS;
|
||||
|
||||
int rc = flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER);
|
||||
int rc = flock(env->lck_mmap.fd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
return MDBX_SUCCESS;
|
||||
|
||||
osal_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
imports.srwl_ReleaseShared(&env->remap_guard);
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC void osal_rdt_unlock(MDBX_env *env) {
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE &&
|
||||
(env->me_flags & MDBX_EXCLUSIVE) == 0) {
|
||||
MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
if (env->lck_mmap.fd != INVALID_HANDLE_VALUE &&
|
||||
(env->flags & MDBX_EXCLUSIVE) == 0) {
|
||||
/* transition from S-E (locked) to S-? (used), e.g. unlock upper-part */
|
||||
int err = funlock(env->me_lfd, LCK_UPPER);
|
||||
int err = funlock(env->lck_mmap.fd, LCK_UPPER);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
osal_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
imports.srwl_ReleaseShared(&env->remap_guard);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return flock(
|
||||
fd, wait ? LCK_EXCLUSIVE | LCK_WAITFOR : LCK_EXCLUSIVE | LCK_DONTWAIT, 0,
|
||||
DXB_MAXLEN);
|
||||
@@ -293,7 +196,7 @@ static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
mdbx_handle_array_t *const ptr =
|
||||
osal_realloc((limit > ARRAY_LENGTH((*array)->handles))
|
||||
? *array
|
||||
: /* don't free initial array on the stack */ NULL,
|
||||
: /* don't free initial array on the stack */ nullptr,
|
||||
sizeof(mdbx_handle_array_t) +
|
||||
sizeof(HANDLE) * (limit * (size_t)2 -
|
||||
ARRAY_LENGTH((*array)->handles)));
|
||||
@@ -307,7 +210,7 @@ static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
|
||||
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
|
||||
FALSE, ThreadId);
|
||||
if (hThread == NULL)
|
||||
if (hThread == nullptr)
|
||||
return (int)GetLastError();
|
||||
|
||||
if (SuspendThread(hThread) == (DWORD)-1) {
|
||||
@@ -324,28 +227,27 @@ static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
MDBX_INTERNAL int
|
||||
osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
eASSERT(env, (env->me_flags & MDBX_NOSTICKYTHREADS) == 0);
|
||||
eASSERT(env, (env->flags & MDBX_NOSTICKYTHREADS) == 0);
|
||||
const uintptr_t CurrentTid = GetCurrentThreadId();
|
||||
int rc;
|
||||
if (env->me_lck_mmap.lck) {
|
||||
if (env->lck_mmap.lck) {
|
||||
/* Scan LCK for threads of the current process */
|
||||
const MDBX_reader *const begin = env->me_lck_mmap.lck->mti_readers;
|
||||
const MDBX_reader *const end =
|
||||
const reader_slot_t *const begin = env->lck_mmap.lck->rdt;
|
||||
const reader_slot_t *const end =
|
||||
begin +
|
||||
atomic_load32(&env->me_lck_mmap.lck->mti_numreaders, mo_AcquireRelease);
|
||||
const uintptr_t WriteTxnOwner = env->me_txn0 ? env->me_txn0->mt_owner : 0;
|
||||
for (const MDBX_reader *reader = begin; reader < end; ++reader) {
|
||||
if (reader->mr_pid.weak != env->me_pid || !reader->mr_tid.weak) {
|
||||
atomic_load32(&env->lck_mmap.lck->rdt_length, mo_AcquireRelease);
|
||||
const uintptr_t WriteTxnOwner = env->basal_txn ? env->basal_txn->owner : 0;
|
||||
for (const reader_slot_t *reader = begin; reader < end; ++reader) {
|
||||
if (reader->pid.weak != env->pid || !reader->tid.weak) {
|
||||
skip_lck:
|
||||
continue;
|
||||
}
|
||||
if (reader->mr_tid.weak == CurrentTid ||
|
||||
reader->mr_tid.weak == WriteTxnOwner)
|
||||
if (reader->tid.weak == CurrentTid || reader->tid.weak == WriteTxnOwner)
|
||||
goto skip_lck;
|
||||
|
||||
rc = suspend_and_append(array, (mdbx_tid_t)reader->mr_tid.weak);
|
||||
rc = suspend_and_append(array, (mdbx_tid_t)reader->tid.weak);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
bailout_lck:
|
||||
(void)osal_resume_threads_after_remap(*array);
|
||||
@@ -360,7 +262,7 @@ osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
} else {
|
||||
/* Without LCK (i.e. read-only mode).
|
||||
* Walk through a snapshot of all running threads */
|
||||
eASSERT(env, env->me_flags & (MDBX_EXCLUSIVE | MDBX_RDONLY));
|
||||
eASSERT(env, env->flags & (MDBX_EXCLUSIVE | MDBX_RDONLY));
|
||||
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
return (int)GetLastError();
|
||||
@@ -377,7 +279,7 @@ osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
}
|
||||
|
||||
do {
|
||||
if (entry.th32OwnerProcessID != env->me_pid ||
|
||||
if (entry.th32OwnerProcessID != env->pid ||
|
||||
entry.th32ThreadID == CurrentTid)
|
||||
continue;
|
||||
|
||||
@@ -396,8 +298,7 @@ osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
MDBX_INTERNAL int osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
int rc = MDBX_SUCCESS;
|
||||
for (unsigned i = 0; i < array->count; ++i) {
|
||||
const HANDLE hThread = array->handles[i];
|
||||
@@ -426,6 +327,7 @@ osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
* Only 6 states of FSM are used, which 2 of ones are transitive.
|
||||
*
|
||||
* States:
|
||||
* LO HI
|
||||
* ?-? = free, i.e. unlocked
|
||||
* S-? = used, i.e. shared lock
|
||||
* E-? = exclusive-read, i.e. operational exclusive
|
||||
@@ -436,39 +338,39 @@ osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
* E-S
|
||||
* E-E = exclusive-write, i.e. exclusive due (re)initialization
|
||||
*
|
||||
* The osal_lck_seize() moves the locking-FSM from the initial free/unlocked
|
||||
* The lck_seize() moves the locking-FSM from the initial free/unlocked
|
||||
* state to the "exclusive write" (and returns MDBX_RESULT_TRUE) if possible,
|
||||
* or to the "used" (and returns MDBX_RESULT_FALSE).
|
||||
*
|
||||
* The osal_lck_downgrade() moves the locking-FSM from "exclusive write"
|
||||
* The lck_downgrade() moves the locking-FSM from "exclusive write"
|
||||
* state to the "used" (i.e. shared) state.
|
||||
*
|
||||
* The osal_lck_upgrade() moves the locking-FSM from "used" (i.e. shared)
|
||||
* The lck_upgrade() moves the locking-FSM from "used" (i.e. shared)
|
||||
* state to the "exclusive write" state.
|
||||
*/
|
||||
|
||||
static void lck_unlock(MDBX_env *env) {
|
||||
int err;
|
||||
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE) {
|
||||
if (env->lck_mmap.fd != INVALID_HANDLE_VALUE) {
|
||||
/* double `unlock` for robustly remove overlapped shared/exclusive locks */
|
||||
do
|
||||
err = funlock(env->me_lfd, LCK_LOWER);
|
||||
err = funlock(env->lck_mmap.fd, LCK_LOWER);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(globals.running_under_Wine && err == ERROR_LOCK_VIOLATION));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
do
|
||||
err = funlock(env->me_lfd, LCK_UPPER);
|
||||
err = funlock(env->lck_mmap.fd, LCK_UPPER);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(globals.running_under_Wine && err == ERROR_LOCK_VIOLATION));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
if (fd4data != INVALID_HANDLE_VALUE) {
|
||||
/* explicitly unlock to avoid latency for other processes (windows kernel
|
||||
* releases such locks via deferred queues) */
|
||||
@@ -476,14 +378,14 @@ static void lck_unlock(MDBX_env *env) {
|
||||
err = funlock(fd4data, DXB_BODY);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(globals.running_under_Wine && err == ERROR_LOCK_VIOLATION));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
do
|
||||
err = funlock(fd4data, DXB_WHOLE);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(globals.running_under_Wine && err == ERROR_LOCK_VIOLATION));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
}
|
||||
}
|
||||
@@ -539,16 +441,16 @@ static int internal_seize_lck(HANDLE lfd) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_RESULT_TRUE /* nope since files were must be opened
|
||||
non-shareable */
|
||||
;
|
||||
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE) {
|
||||
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE) {
|
||||
/* LY: without-lck mode (e.g. on read-only filesystem) */
|
||||
jitter4testing(false);
|
||||
int rc = flock_data(env, LCK_SHARED | LCK_DONTWAIT, DXB_WHOLE);
|
||||
@@ -557,9 +459,9 @@ MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
int rc = internal_seize_lck(env->me_lfd);
|
||||
int rc = internal_seize_lck(env->lck_mmap.fd);
|
||||
jitter4testing(false);
|
||||
if (rc == MDBX_RESULT_TRUE && (env->me_flags & MDBX_RDONLY) == 0) {
|
||||
if (rc == MDBX_RESULT_TRUE && (env->flags & MDBX_RDONLY) == 0) {
|
||||
/* Check that another process don't operates in without-lck mode.
|
||||
* Doing such check by exclusive locking the body-part of db. Should be
|
||||
* noted:
|
||||
@@ -583,24 +485,24 @@ MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env) {
|
||||
MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
/* Transite from exclusive-write state (E-E) to used (S-?) */
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
|
||||
;
|
||||
/* 1) now at E-E (exclusive-write), transition to ?_E (middle) */
|
||||
int rc = funlock(env->me_lfd, LCK_LOWER);
|
||||
int rc = funlock(env->lck_mmap.fd, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"E-E(exclusive-write) >> ?-E(middle)", rc);
|
||||
|
||||
/* 2) now at ?-E (middle), transition to S-E (locked) */
|
||||
rc = flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER);
|
||||
rc = flock(env->lck_mmap.fd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
/* 3) something went wrong, give up */;
|
||||
ERROR("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
@@ -608,7 +510,7 @@ MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env) {
|
||||
}
|
||||
|
||||
/* 4) got S-E (locked), continue transition to S-? (used) */
|
||||
rc = funlock(env->me_lfd, LCK_UPPER);
|
||||
rc = funlock(env->lck_mmap.fd, LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> S-?(used)",
|
||||
rc);
|
||||
@@ -616,17 +518,17 @@ MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env) {
|
||||
return MDBX_SUCCESS /* 5) now at S-? (used), done */;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
/* Transite from used state (S-?) to exclusive-write (E-E) */
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
|
||||
;
|
||||
|
||||
/* 1) now on S-? (used), try S-E (locked) */
|
||||
jitter4testing(false);
|
||||
int rc = flock(env->me_lfd,
|
||||
int rc = flock(env->lck_mmap.fd,
|
||||
dont_wait ? LCK_EXCLUSIVE | LCK_DONTWAIT : LCK_EXCLUSIVE,
|
||||
LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
@@ -636,14 +538,14 @@ MDBX_INTERNAL_FUNC int osal_lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
}
|
||||
|
||||
/* 3) now on S-E (locked), transition to ?-E (middle) */
|
||||
rc = funlock(env->me_lfd, LCK_LOWER);
|
||||
rc = funlock(env->lck_mmap.fd, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> ?-E(middle)",
|
||||
rc);
|
||||
|
||||
/* 4) now on ?-E (middle), try E-E (exclusive-write) */
|
||||
jitter4testing(false);
|
||||
rc = flock(env->me_lfd,
|
||||
rc = flock(env->lck_mmap.fd,
|
||||
dont_wait ? LCK_EXCLUSIVE | LCK_DONTWAIT : LCK_EXCLUSIVE,
|
||||
LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
@@ -655,25 +557,24 @@ MDBX_INTERNAL_FUNC int osal_lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
return MDBX_SUCCESS /* 6) now at E-E (exclusive-write), done */;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor,
|
||||
int global_uniqueness_flag) {
|
||||
MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor,
|
||||
int global_uniqueness_flag) {
|
||||
(void)env;
|
||||
(void)inprocess_neighbor;
|
||||
(void)global_uniqueness_flag;
|
||||
if (mdbx_SetFileIoOverlappedRange && !(env->me_flags & MDBX_RDONLY)) {
|
||||
if (imports.SetFileIoOverlappedRange && !(env->flags & MDBX_RDONLY)) {
|
||||
HANDLE token = INVALID_HANDLE_VALUE;
|
||||
TOKEN_PRIVILEGES privileges;
|
||||
privileges.PrivilegeCount = 1;
|
||||
privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
|
||||
&token) ||
|
||||
!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
|
||||
!LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME,
|
||||
&privileges.Privileges[0].Luid) ||
|
||||
!AdjustTokenPrivileges(token, FALSE, &privileges, sizeof(privileges),
|
||||
nullptr, nullptr) ||
|
||||
GetLastError() != ERROR_SUCCESS)
|
||||
mdbx_SetFileIoOverlappedRange = NULL;
|
||||
imports.SetFileIoOverlappedRange = nullptr;
|
||||
|
||||
if (token != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(token);
|
||||
@@ -681,21 +582,21 @@ MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor,
|
||||
const uint32_t current_pid) {
|
||||
MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor,
|
||||
const uint32_t current_pid) {
|
||||
(void)current_pid;
|
||||
/* LY: should unmap before releasing the locks to avoid race condition and
|
||||
* STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */
|
||||
if (env->me_map)
|
||||
osal_munmap(&env->me_dxb_mmap);
|
||||
if (env->me_lck_mmap.lck) {
|
||||
const bool synced = env->me_lck_mmap.lck->mti_unsynced_pages.weak == 0;
|
||||
osal_munmap(&env->me_lck_mmap);
|
||||
if (synced && !inprocess_neighbor && env->me_lfd != INVALID_HANDLE_VALUE &&
|
||||
osal_lck_upgrade(env, true) == MDBX_SUCCESS)
|
||||
if (env->dxb_mmap.base)
|
||||
osal_munmap(&env->dxb_mmap);
|
||||
if (env->lck_mmap.lck) {
|
||||
const bool synced = env->lck_mmap.lck->unsynced_pages.weak == 0;
|
||||
osal_munmap(&env->lck_mmap);
|
||||
if (synced && !inprocess_neighbor &&
|
||||
env->lck_mmap.fd != INVALID_HANDLE_VALUE &&
|
||||
lck_upgrade(env, true) == MDBX_SUCCESS)
|
||||
/* this will fail if LCK is used/mmapped by other process(es) */
|
||||
osal_ftruncate(env->me_lfd, 0);
|
||||
osal_ftruncate(env->lck_mmap.fd, 0);
|
||||
}
|
||||
lck_unlock(env);
|
||||
return MDBX_SUCCESS;
|
||||
@@ -704,12 +605,12 @@ MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env,
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* reader checking (by pid) */
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_set(MDBX_env *env) {
|
||||
MDBX_INTERNAL int lck_rpid_set(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env) {
|
||||
MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
@@ -720,7 +621,7 @@ MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env) {
|
||||
* MDBX_RESULT_TRUE, if pid is live (unable to acquire lock)
|
||||
* MDBX_RESULT_FALSE, if pid is dead (lock acquired)
|
||||
* or otherwise the errcode. */
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
(void)env;
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
int rc;
|
||||
@@ -753,169 +654,4 @@ MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Stub for slim read-write lock
|
||||
// Copyright (C) 1995-2002 Brad Wilson
|
||||
|
||||
static void WINAPI stub_srwlock_Init(osal_srwlock_t *srwl) {
|
||||
srwl->readerCount = srwl->writerCount = 0;
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_AcquireShared(osal_srwlock_t *srwl) {
|
||||
while (true) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to the readers list
|
||||
_InterlockedIncrement(&srwl->readerCount);
|
||||
|
||||
// Check for writers again (we may have been preempted). If
|
||||
// there are no writers writing or waiting, then we're done.
|
||||
if (srwl->writerCount == 0)
|
||||
break;
|
||||
|
||||
// Remove from the readers list, spin, try again
|
||||
_InterlockedDecrement(&srwl->readerCount);
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_ReleaseShared(osal_srwlock_t *srwl) {
|
||||
assert(srwl->readerCount > 0);
|
||||
_InterlockedDecrement(&srwl->readerCount);
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_AcquireExclusive(osal_srwlock_t *srwl) {
|
||||
while (true) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if we can become the writer (expensive, because it inter-
|
||||
// locks the CPUs, so writing should be an infrequent process)
|
||||
if (_InterlockedExchange(&srwl->writerCount, 1) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Now we're the writer, but there may be outstanding readers.
|
||||
// Spin until there aren't any more; new readers will wait now
|
||||
// that we're the writer.
|
||||
while (srwl->readerCount != 0) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_ReleaseExclusive(osal_srwlock_t *srwl) {
|
||||
assert(srwl->writerCount == 1 && srwl->readerCount >= 0);
|
||||
srwl->writerCount = 0;
|
||||
}
|
||||
|
||||
static uint64_t WINAPI stub_GetTickCount64(void) {
|
||||
LARGE_INTEGER Counter, Frequency;
|
||||
return (QueryPerformanceFrequency(&Frequency) &&
|
||||
QueryPerformanceCounter(&Counter))
|
||||
? Counter.QuadPart * 1000ul / Frequency.QuadPart
|
||||
: 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef xMDBX_ALLOY
|
||||
osal_srwlock_t_function osal_srwlock_Init, osal_srwlock_AcquireShared,
|
||||
osal_srwlock_ReleaseShared, osal_srwlock_AcquireExclusive,
|
||||
osal_srwlock_ReleaseExclusive;
|
||||
|
||||
MDBX_NtExtendSection mdbx_NtExtendSection;
|
||||
MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx;
|
||||
MDBX_GetVolumeInformationByHandleW mdbx_GetVolumeInformationByHandleW;
|
||||
MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
|
||||
MDBX_SetFileInformationByHandle mdbx_SetFileInformationByHandle;
|
||||
MDBX_NtFsControlFile mdbx_NtFsControlFile;
|
||||
MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
|
||||
MDBX_GetTickCount64 mdbx_GetTickCount64;
|
||||
MDBX_RegGetValueA mdbx_RegGetValueA;
|
||||
MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange;
|
||||
#endif /* xMDBX_ALLOY */
|
||||
|
||||
#if __GNUC_PREREQ(8, 0)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
#endif /* GCC/MINGW */
|
||||
|
||||
static void mdbx_winnt_import(void) {
|
||||
#define GET_PROC_ADDR(dll, ENTRY) \
|
||||
mdbx_##ENTRY = (MDBX_##ENTRY)GetProcAddress(dll, #ENTRY)
|
||||
|
||||
const HINSTANCE hNtdll = GetModuleHandleA("ntdll.dll");
|
||||
if (hNtdll) {
|
||||
if (GetProcAddress(hNtdll, "wine_get_version")) {
|
||||
assert(mdbx_RunningUnderWine());
|
||||
} else {
|
||||
GET_PROC_ADDR(hNtdll, NtFsControlFile);
|
||||
GET_PROC_ADDR(hNtdll, NtExtendSection);
|
||||
assert(!mdbx_RunningUnderWine());
|
||||
}
|
||||
}
|
||||
|
||||
const HINSTANCE hKernel32dll = GetModuleHandleA("kernel32.dll");
|
||||
if (hKernel32dll) {
|
||||
GET_PROC_ADDR(hKernel32dll, GetFileInformationByHandleEx);
|
||||
GET_PROC_ADDR(hKernel32dll, GetTickCount64);
|
||||
if (!mdbx_GetTickCount64)
|
||||
mdbx_GetTickCount64 = stub_GetTickCount64;
|
||||
if (!mdbx_RunningUnderWine()) {
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileInformationByHandle);
|
||||
GET_PROC_ADDR(hKernel32dll, GetVolumeInformationByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, GetFinalPathNameByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, PrefetchVirtualMemory);
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileIoOverlappedRange);
|
||||
}
|
||||
}
|
||||
|
||||
const osal_srwlock_t_function init =
|
||||
(osal_srwlock_t_function)(hKernel32dll
|
||||
? GetProcAddress(hKernel32dll,
|
||||
"InitializeSRWLock")
|
||||
: nullptr);
|
||||
if (init != NULL) {
|
||||
osal_srwlock_Init = init;
|
||||
osal_srwlock_AcquireShared = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockShared");
|
||||
osal_srwlock_ReleaseShared = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockShared");
|
||||
osal_srwlock_AcquireExclusive = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockExclusive");
|
||||
osal_srwlock_ReleaseExclusive = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockExclusive");
|
||||
} else {
|
||||
osal_srwlock_Init = stub_srwlock_Init;
|
||||
osal_srwlock_AcquireShared = stub_srwlock_AcquireShared;
|
||||
osal_srwlock_ReleaseShared = stub_srwlock_ReleaseShared;
|
||||
osal_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive;
|
||||
osal_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive;
|
||||
}
|
||||
|
||||
const HINSTANCE hAdvapi32dll = GetModuleHandleA("advapi32.dll");
|
||||
if (hAdvapi32dll) {
|
||||
GET_PROC_ADDR(hAdvapi32dll, RegGetValueA);
|
||||
}
|
||||
#undef GET_PROC_ADDR
|
||||
}
|
||||
|
||||
#if __GNUC_PREREQ(8, 0)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif /* GCC/MINGW */
|
||||
|
||||
#endif /* Windows LCK-implementation */
|
||||
#endif /* Windows */
|
||||
|
||||
Reference in New Issue
Block a user