diff options
Diffstat (limited to 'plugins/Dbx_mdb/src/mdbx/lck-windows.c')
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/lck-windows.c | 452 |
1 files changed, 0 insertions, 452 deletions
diff --git a/plugins/Dbx_mdb/src/mdbx/lck-windows.c b/plugins/Dbx_mdb/src/mdbx/lck-windows.c deleted file mode 100644 index 672512a7e1..0000000000 --- a/plugins/Dbx_mdb/src/mdbx/lck-windows.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright 2015-2017 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>. - */ - -#include "./bits.h" - -/* PREAMBLE FOR WINDOWS: - * - * We are not concerned for performance here. - * If you are running Windows a performance could NOT be the goal. - * Otherwise please use Linux. - * - * Regards, - * LY - */ - -/*----------------------------------------------------------------------------*/ -/* rthc */ - -static CRITICAL_SECTION rthc_critical_section; - -static void NTAPI tls_callback(PVOID module, DWORD reason, PVOID reserved) { - (void)module; - (void)reserved; - switch (reason) { - case DLL_PROCESS_ATTACH: - InitializeCriticalSection(&rthc_critical_section); - break; - case DLL_PROCESS_DETACH: - DeleteCriticalSection(&rthc_critical_section); - break; - - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - mdbx_rthc_cleanup(); - break; - } -} - -void mdbx_rthc_lock(void) { EnterCriticalSection(&rthc_critical_section); } - -void mdbx_rthc_unlock(void) { LeaveCriticalSection(&rthc_critical_section); } - -/* *INDENT-OFF* */ -/* clang-format off */ -#if defined(_MSC_VER) -# pragma const_seg(push) -# pragma data_seg(push) - -# ifdef _WIN64 - /* 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_callback") - /* 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_callback") - /* specific data-segment for WIN32 */ -# pragma data_seg(".CRT$XLB") -# endif - - PIMAGE_TLS_CALLBACK mdbx_tls_callback = tls_callback; -# pragma data_seg(pop) -# pragma const_seg(pop) - -#elif defined(__GNUC__) -# ifdef _WIN64 - const -# endif - PIMAGE_TLS_CALLBACK mdbx_tls_callback __attribute__((section(".CRT$XLB"), used)) - = tls_callback; -#else -# error FIXME -#endif -/* *INDENT-ON* */ -/* clang-format on */ - -/*----------------------------------------------------------------------------*/ - -#define LCK_SHARED 0 -#define LCK_EXCLUSIVE LOCKFILE_EXCLUSIVE_LOCK -#define LCK_WAITFOR 0 -#define LCK_DONTWAIT LOCKFILE_FAIL_IMMEDIATELY - -static __inline BOOL flock(mdbx_filehandle_t fd, DWORD flags, uint64_t offset, - size_t bytes) { - OVERLAPPED ov; - ov.hEvent = 0; - ov.Offset = (DWORD)offset; - ov.OffsetHigh = HIGH_DWORD(offset); - return LockFileEx(fd, flags, 0, (DWORD)bytes, HIGH_DWORD(bytes), &ov); -} - -static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset, - size_t bytes) { - return UnlockFile(fd, (DWORD)offset, HIGH_DWORD(offset), (DWORD)bytes, - HIGH_DWORD(bytes)); -} - -/*----------------------------------------------------------------------------*/ -/* global `write` lock for write-txt processing, - * exclusive locking both meta-pages) */ - -#define LCK_MAXLEN (1u + (size_t)(MAXSSIZE_T)) -#define LCK_META_OFFSET 0 -#define LCK_META_LEN 0x10000u -#define LCK_BODY_OFFSET LCK_META_LEN -#define LCK_BODY_LEN (LCK_MAXLEN - LCK_BODY_OFFSET + 1u) -#define LCK_META LCK_META_OFFSET, LCK_META_LEN -#define LCK_BODY LCK_BODY_OFFSET, LCK_BODY_LEN -#define LCK_WHOLE 0, LCK_MAXLEN - -int mdbx_txn_lock(MDBX_env *env, bool dontwait) { - if (flock(env->me_fd, dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT) - : (LCK_EXCLUSIVE | LCK_WAITFOR), - LCK_BODY)) - return MDBX_SUCCESS; - int rc = GetLastError(); - return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY; -} - -void mdbx_txn_unlock(MDBX_env *env) { - if (!funlock(env->me_fd, LCK_BODY)) - mdbx_panic("%s failed: errcode %u", mdbx_func_, GetLastError()); -} - -/*----------------------------------------------------------------------------*/ -/* global `read` lock for readers registration, - * exclusive locking `mti_numreaders` (second) cacheline */ - -#define LCK_LO_OFFSET 0 -#define LCK_LO_LEN offsetof(MDBX_lockinfo, mti_numreaders) -#define LCK_UP_OFFSET LCK_LO_LEN -#define LCK_UP_LEN (MDBX_LOCKINFO_WHOLE_SIZE - LCK_UP_OFFSET) -#define LCK_LOWER LCK_LO_OFFSET, LCK_LO_LEN -#define LCK_UPPER LCK_UP_OFFSET, LCK_UP_LEN - -int mdbx_rdt_lock(MDBX_env *env) { - if (env->me_lfd == INVALID_HANDLE_VALUE) - return MDBX_SUCCESS; /* readonly database in readonly filesystem */ - - /* transite from S-? (used) to S-E (locked), e.g. exclusive lock upper-part */ - if (flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER)) - return MDBX_SUCCESS; - return GetLastError(); -} - -void mdbx_rdt_unlock(MDBX_env *env) { - if (env->me_lfd != INVALID_HANDLE_VALUE) { - /* transite from S-E (locked) to S-? (used), e.g. unlock upper-part */ - if (!funlock(env->me_lfd, LCK_UPPER)) - mdbx_panic("%s failed: errcode %u", mdbx_func_, GetLastError()); - } -} - -/*----------------------------------------------------------------------------*/ -/* global `initial` lock for lockfile initialization, - * exclusive/shared locking first cacheline */ - -/* FIXME: locking schema/algo descritpion. - ?-? = free - S-? = used - E-? = exclusive-read - ?-S - ?-E = middle - S-S - S-E = locked - E-S - E-E = exclusive-write -*/ - -int mdbx_lck_init(MDBX_env *env) { - (void)env; - return MDBX_SUCCESS; -} - -/* Seize state as 'exclusive-write' (E-E and returns MDBX_RESULT_TRUE) - * or as 'used' (S-? and returns MDBX_RESULT_FALSE), otherwise returns an error - */ -static int internal_seize_lck(HANDLE lfd) { - int rc; - assert(lfd != INVALID_HANDLE_VALUE); - - /* 1) now on ?-? (free), get ?-E (middle) */ - mdbx_jitter4testing(false); - if (!flock(lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER)) { - rc = GetLastError() /* 2) something went wrong, give up */; - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "?-?(free) >> ?-E(middle)", rc); - return rc; - } - - /* 3) now on ?-E (middle), try E-E (exclusive-write) */ - mdbx_jitter4testing(false); - if (flock(lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) - return MDBX_RESULT_TRUE /* 4) got E-E (exclusive-write), done */; - - /* 5) still on ?-E (middle) */ - rc = GetLastError(); - mdbx_jitter4testing(false); - if (rc != ERROR_SHARING_VIOLATION && rc != ERROR_LOCK_VIOLATION) { - /* 6) something went wrong, give up */ - if (!funlock(lfd, LCK_UPPER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> ?-?(free)", GetLastError()); - return rc; - } - - /* 7) still on ?-E (middle), try S-E (locked) */ - mdbx_jitter4testing(false); - rc = flock(lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER) ? MDBX_RESULT_FALSE - : GetLastError(); - - mdbx_jitter4testing(false); - if (rc != MDBX_RESULT_FALSE) - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> S-E(locked)", rc); - - /* 8) now on S-E (locked) or still on ?-E (middle), - * transite to S-? (used) or ?-? (free) */ - if (!funlock(lfd, LCK_UPPER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "X-E(locked/middle) >> X-?(used/free)", GetLastError()); - - /* 9) now on S-? (used, DONE) or ?-? (free, FAILURE) */ - return rc; -} - -int mdbx_lck_seize(MDBX_env *env) { - int rc; - - assert(env->me_fd != INVALID_HANDLE_VALUE); - if (env->me_lfd == INVALID_HANDLE_VALUE) { - /* LY: without-lck mode (e.g. on read-only filesystem) */ - mdbx_jitter4testing(false); - if (!flock(env->me_fd, LCK_SHARED | LCK_DONTWAIT, LCK_WHOLE)) { - rc = GetLastError(); - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, "without-lck", rc); - return rc; - } - return MDBX_RESULT_FALSE; - } - - rc = internal_seize_lck(env->me_lfd); - mdbx_jitter4testing(false); - if (rc == MDBX_RESULT_TRUE && (env->me_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: - * - we need an exclusive lock for do so; - * - we can't lock meta-pages, otherwise other process could get an error - * while opening db in valid (non-conflict) mode. */ - if (!flock(env->me_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY)) { - rc = GetLastError(); - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "lock-against-without-lck", rc); - mdbx_jitter4testing(false); - mdbx_lck_destroy(env); - } else { - mdbx_jitter4testing(false); - if (!funlock(env->me_fd, LCK_BODY)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "unlock-against-without-lck", GetLastError()); - } - } - - return rc; -} - -int mdbx_lck_downgrade(MDBX_env *env, bool complete) { - /* Transite from exclusive state (E-?) to used (S-?) */ - assert(env->me_fd != INVALID_HANDLE_VALUE); - assert(env->me_lfd != INVALID_HANDLE_VALUE); - - /* 1) must be at E-E (exclusive-write) */ - if (!complete) { - /* transite from E-E to E_? (exclusive-read) */ - if (!funlock(env->me_lfd, LCK_UPPER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "E-E(exclusive-write) >> E-?(exclusive-read)", GetLastError()); - return MDBX_SUCCESS /* 2) now at E-? (exclusive-read), done */; - } - - /* 3) now at E-E (exclusive-write), transite to ?_E (middle) */ - if (!funlock(env->me_lfd, LCK_LOWER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "E-E(exclusive-write) >> ?-E(middle)", GetLastError()); - - /* 4) now at ?-E (middle), transite to S-E (locked) */ - if (!flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER)) { - int rc = GetLastError() /* 5) something went wrong, give up */; - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> S-E(locked)", rc); - return rc; - } - - /* 6) got S-E (locked), continue transition to S-? (used) */ - if (!funlock(env->me_lfd, LCK_UPPER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "S-E(locked) >> S-?(used)", GetLastError()); - - return MDBX_SUCCESS /* 7) now at S-? (used), done */; -} - -int mdbx_lck_upgrade(MDBX_env *env) { - /* Transite from locked state (S-E) to exclusive-write (E-E) */ - assert(env->me_fd != INVALID_HANDLE_VALUE); - assert(env->me_lfd != INVALID_HANDLE_VALUE); - - /* 1) must be at S-E (locked), transite to ?_E (middle) */ - if (!funlock(env->me_lfd, LCK_LOWER)) - mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "S-E(locked) >> ?-E(middle)", GetLastError()); - - /* 3) now on ?-E (middle), try E-E (exclusive-write) */ - mdbx_jitter4testing(false); - if (flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) - return MDBX_RESULT_TRUE; /* 4) got E-E (exclusive-write), done */ - - /* 5) still on ?-E (middle) */ - int rc = GetLastError(); - mdbx_jitter4testing(false); - if (rc != ERROR_SHARING_VIOLATION && rc != ERROR_LOCK_VIOLATION) { - /* 6) something went wrong, report but continue */ - mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> E-E(exclusive-write)", rc); - } - - /* 7) still on ?-E (middle), try restore S-E (locked) */ - mdbx_jitter4testing(false); - rc = flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER) - ? MDBX_RESULT_FALSE - : GetLastError(); - - mdbx_jitter4testing(false); - if (rc != MDBX_RESULT_FALSE) { - mdbx_fatal("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> S-E(locked)", rc); - return rc; - } - - /* 8) now on S-E (locked) */ - return MDBX_RESULT_FALSE; -} - -void mdbx_lck_destroy(MDBX_env *env) { - int rc; - - if (env->me_lfd != INVALID_HANDLE_VALUE) { - /* double `unlock` for robustly remove overlapped shared/exclusive locks */ - while (funlock(env->me_lfd, LCK_LOWER)) - ; - rc = GetLastError(); - assert(rc == ERROR_NOT_LOCKED); - (void)rc; - SetLastError(ERROR_SUCCESS); - - while (funlock(env->me_lfd, LCK_UPPER)) - ; - rc = GetLastError(); - assert(rc == ERROR_NOT_LOCKED); - (void)rc; - SetLastError(ERROR_SUCCESS); - } - - if (env->me_fd != INVALID_HANDLE_VALUE) { - /* explicitly unlock to avoid latency for other processes (windows kernel - * releases such locks via deferred queues) */ - while (funlock(env->me_fd, LCK_BODY)) - ; - rc = GetLastError(); - assert(rc == ERROR_NOT_LOCKED); - (void)rc; - SetLastError(ERROR_SUCCESS); - - while (funlock(env->me_fd, LCK_META)) - ; - rc = GetLastError(); - assert(rc == ERROR_NOT_LOCKED); - (void)rc; - SetLastError(ERROR_SUCCESS); - - while (funlock(env->me_fd, LCK_WHOLE)) - ; - rc = GetLastError(); - assert(rc == ERROR_NOT_LOCKED); - (void)rc; - SetLastError(ERROR_SUCCESS); - } -} - -/*----------------------------------------------------------------------------*/ -/* reader checking (by pid) */ - -int mdbx_rpid_set(MDBX_env *env) { - (void)env; - return MDBX_SUCCESS; -} - -int mdbx_rpid_clear(MDBX_env *env) { - (void)env; - return MDBX_SUCCESS; -} - -/* Checks reader by pid. - * - * Returns: - * MDBX_RESULT_TRUE, if pid is live (unable to acquire lock) - * MDBX_RESULT_FALSE, if pid is dead (lock acquired) - * or otherwise the errcode. */ -int mdbx_rpid_check(MDBX_env *env, mdbx_pid_t pid) { - (void)env; - HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); - int rc; - if (hProcess) { - rc = WaitForSingleObject(hProcess, 0); - CloseHandle(hProcess); - } else { - rc = GetLastError(); - } - - switch (rc) { - case ERROR_INVALID_PARAMETER: - /* pid seem invalid */ - return MDBX_RESULT_FALSE; - case WAIT_OBJECT_0: - /* process just exited */ - return MDBX_RESULT_FALSE; - case WAIT_TIMEOUT: - /* pid running */ - return MDBX_RESULT_TRUE; - default: - /* failure */ - return rc; - } -} |