/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */ /* * Copyright 2015-2022 Leonid Yuriev * 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 * . */ #pragma once /*----------------------------------------------------------------------------*/ /* C11 Atomics */ #if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && __has_include() #include #define MDBX_HAVE_C11ATOMICS #elif !defined(__cplusplus) && \ (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) && \ !defined(__STDC_NO_ATOMICS__) && \ (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ !(defined(__GNUC__) || defined(__clang__))) #include #define MDBX_HAVE_C11ATOMICS #elif defined(__GNUC__) || defined(__clang__) #elif defined(_MSC_VER) #pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */ #pragma warning(disable : 4133) /* 'function': incompatible types - from \ 'size_t' to 'LONGLONG' */ #pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to \ 'std::size_t', possible loss of data */ #pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to \ 'long', possible loss of data */ #pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange) #pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64) #elif defined(__APPLE__) #include #else #error FIXME atomic-ops #endif /*----------------------------------------------------------------------------*/ /* Memory/Compiler barriers, cache coherence */ #if __has_include() #include #elif defined(__mips) || defined(__mips__) || defined(__mips64) || \ defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) || \ defined(__MWERKS__) || defined(__sgi) /* MIPS should have explicit cache control */ #include #endif MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) { #if defined(__clang__) || defined(__GNUC__) __asm__ __volatile__("" ::: "memory"); #elif defined(_MSC_VER) _ReadWriteBarrier(); #elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */ __memory_barrier(); #elif defined(__SUNPRO_C) || defined(__sun) || defined(sun) __compiler_barrier(); #elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \ (defined(HP_IA64) || defined(__ia64)) _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */); #elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) || \ defined(__ppc64__) || defined(__powerpc64__) __fence(); #else #error "Could not guess the kind of compiler, please report to us." #endif } MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) { #ifdef MDBX_HAVE_C11ATOMICS atomic_thread_fence(memory_order_seq_cst); #elif defined(__ATOMIC_SEQ_CST) #ifdef __clang__ __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); #else __atomic_thread_fence(__ATOMIC_SEQ_CST); #endif #elif defined(__clang__) || defined(__GNUC__) __sync_synchronize(); #elif defined(_WIN32) || defined(_WIN64) MemoryBarrier(); #elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */ #if defined(__ia32__) _mm_mfence(); #else __mf(); #endif #elif defined(__SUNPRO_C) || defined(__sun) || defined(sun) __machine_rw_barrier(); #elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \ (defined(HP_IA64) || defined(__ia64)) _Asm_mf(); #elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) || \ defined(__ppc64__) || defined(__powerpc64__) __lwsync(); #else #error "Could not guess the kind of compiler, please report to us." #endif } /*----------------------------------------------------------------------------*/ /* system-depended definitions */ #if defined(_WIN32) || defined(_WIN64) #define HAVE_SYS_STAT_H #define HAVE_SYS_TYPES_H typedef HANDLE mdbx_thread_t; typedef unsigned mdbx_thread_key_t; #define MAP_FAILED NULL #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[2]; } mdbx_condpair_t; typedef CRITICAL_SECTION mdbx_fastmutex_t; #if !defined(_MSC_VER) && !defined(__try) /* *INDENT-OFF* */ /* clang-format off */ #define __try #define __except(COND) if (false) /* *INDENT-ON* */ /* clang-format on */ #endif /* stub for MSVC's __try/__except */ #if MDBX_WITHOUT_MSVC_CRT #ifndef mdbx_malloc static inline void *mdbx_malloc(size_t bytes) { return HeapAlloc(GetProcessHeap(), 0, bytes); } #endif /* mdbx_malloc */ #ifndef mdbx_calloc static inline void *mdbx_calloc(size_t nelem, size_t size) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size); } #endif /* mdbx_calloc */ #ifndef mdbx_realloc static inline void *mdbx_realloc(void *ptr, size_t bytes) { return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes) : HeapAlloc(GetProcessHeap(), 0, bytes); } #endif /* mdbx_realloc */ #ifndef mdbx_free static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif /* mdbx_free */ #else /* MDBX_WITHOUT_MSVC_CRT */ #define mdbx_malloc malloc #define mdbx_calloc calloc #define mdbx_realloc realloc #define mdbx_free free #define mdbx_strdup _strdup #endif /* MDBX_WITHOUT_MSVC_CRT */ #ifndef snprintf #define snprintf _snprintf /* ntdll */ #endif #ifndef vsnprintf #define vsnprintf _vsnprintf /* ntdll */ #endif MDBX_INTERNAL_FUNC size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src, size_t src_n); #else /*----------------------------------------------------------------------*/ 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[2]; } mdbx_condpair_t; typedef pthread_mutex_t mdbx_fastmutex_t; #define mdbx_malloc malloc #define mdbx_calloc calloc #define mdbx_realloc realloc #define mdbx_free free #define mdbx_strdup strdup #endif /* Platform */ #if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size) /* malloc_usable_size() already provided */ #elif defined(__APPLE__) #define malloc_usable_size(ptr) malloc_size(ptr) #elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT #define malloc_usable_size(ptr) _msize(ptr) #endif /* malloc_usable_size */ /*----------------------------------------------------------------------------*/ /* OS abstraction layer stuff */ /* Get the size of a memory page for the system. * This is the basic size that the platform's memory manager uses, and is * fundamental to the use of memory-mapped files. */ MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t mdbx_syspagesize(void) { #if defined(_WIN32) || defined(_WIN64) SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; #else return sysconf(_SC_PAGE_SIZE); #endif } #if defined(_WIN32) || defined(_WIN64) typedef wchar_t pathchar_t; #else typedef char pathchar_t; #endif typedef struct mdbx_mmap_param { union { void *address; uint8_t *dxb; struct MDBX_lockinfo *lck; }; mdbx_filehandle_t fd; size_t limit; /* mapping length, but NOT a size of file nor DB */ size_t current; /* mapped region size, i.e. the size of file and DB */ uint64_t filesize /* in-process cache of a file size */; #if defined(_WIN32) || defined(_WIN64) HANDLE section; /* memory-mapped section handle */ #endif } mdbx_mmap_t; typedef union bin128 { __anonymous_struct_extension__ struct { uint64_t x, y; }; __anonymous_struct_extension__ struct { uint32_t a, b, c, d; }; } bin128_t; #if defined(_WIN32) || defined(_WIN64) typedef union MDBX_srwlock { __anonymous_struct_extension__ struct { long volatile readerCount; long volatile writerCount; }; RTL_SRWLOCK native; } MDBX_srwlock; #endif /* Windows */ #ifndef __cplusplus /*----------------------------------------------------------------------------*/ /* libc compatibility stuff */ #if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) && \ (defined(_GNU_SOURCE) || defined(_BSD_SOURCE)) #define mdbx_asprintf asprintf #define mdbx_vasprintf vasprintf #else MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...); MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap); #endif #if !defined(MADV_DODUMP) && defined(MADV_CORE) #define MADV_DODUMP MADV_CORE #endif /* MADV_CORE -> MADV_DODUMP */ #if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE) #define MADV_DONTDUMP MADV_NOCORE #endif /* MADV_NOCORE -> MADV_DONTDUMP */ MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny); MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny); /* max bytes to write in one call */ #if defined(_WIN32) || defined(_WIN64) #define MAX_WRITE UINT32_C(0x01000000) #else #define MAX_WRITE UINT32_C(0x3fff0000) #endif #if defined(__linux__) || defined(__gnu_linux__) MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version; MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */; #endif /* Linux */ #ifndef mdbx_strdup LIBMDBX_API char *mdbx_strdup(const char *str); #endif MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) { #if defined(_WIN32) || defined(_WIN64) DWORD rc = GetLastError(); #else int rc = errno; #endif return rc; } #ifndef mdbx_memalign_alloc MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes, void **result); #endif #ifndef mdbx_memalign_free MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr); #endif MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair); MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair); MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair); MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair, bool part); MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part); MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair); MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex); MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex); MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex); MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex); MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt, uint64_t offset, size_t expected_written); MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count, uint64_t offset); MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf, size_t count, uint64_t offset); MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf, size_t count); MDBX_INTERNAL_FUNC int mdbx_thread_create(mdbx_thread_t *thread, THREAD_RESULT(THREAD_CALL *start_routine)(void *), void *arg); MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread); enum mdbx_syncmode_bits { MDBX_SYNC_NONE = 0, MDBX_SYNC_DATA = 1, MDBX_SYNC_SIZE = 2, MDBX_SYNC_IODQ = 4 }; MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd, const enum mdbx_syncmode_bits mode_bits); MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length); MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos); MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length); enum mdbx_openfile_purpose { MDBX_OPEN_DXB_READ = 0, MDBX_OPEN_DXB_LAZY = 1, MDBX_OPEN_DXB_DSYNC = 2, MDBX_OPEN_LCK = 3, MDBX_OPEN_COPY = 4, MDBX_OPEN_DELETE = 5 }; MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, const MDBX_env *env, const pathchar_t *pathname, mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits); MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd); MDBX_INTERNAL_FUNC int mdbx_removefile(const pathchar_t *pathname); MDBX_INTERNAL_FUNC int mdbx_removedirectory(const pathchar_t *pathname); MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd); MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait); #define MMAP_OPTION_TRUNCATE 1 #define MMAP_OPTION_SEMAPHORE 2 MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map, const size_t must, const size_t limit, const unsigned options); MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map); #define MDBX_MRESIZE_MAY_MOVE 0x00000100 #define MDBX_MRESIZE_MAY_UNMAP 0x00000200 MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map, size_t size, size_t limit); #if defined(_WIN32) || defined(_WIN64) typedef struct { unsigned limit, count; HANDLE handles[31]; } mdbx_handle_array_t; MDBX_INTERNAL_FUNC int mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array); MDBX_INTERNAL_FUNC int mdbx_resume_threads_after_remap(mdbx_handle_array_t *array); #endif /* Windows */ MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset, size_t length, enum mdbx_syncmode_bits mode_bits); MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_t *pathname, int err); MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) { STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t)); #if defined(_WIN32) || defined(_WIN64) return GetCurrentProcessId(); #else STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t)); return getpid(); #endif } MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) { mdbx_tid_t thunk; STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk)); #if defined(_WIN32) || defined(_WIN64) thunk = GetCurrentThreadId(); #else thunk = pthread_self(); #endif return (uintptr_t)thunk; } #if !defined(_WIN32) && !defined(_WIN64) #if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC) MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void); #else static __inline int mdbx_check_tid4bionic(void) { return 0; } #endif /* __ANDROID_API__ || ANDROID) || BIONIC */ MDBX_MAYBE_UNUSED static __inline int mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) { int err = mdbx_check_tid4bionic(); return unlikely(err) ? err : pthread_mutex_lock(mutex); } #endif /* !Windows */ MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void); MDBX_INTERNAL_FUNC uint64_t mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16); MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime); MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void); /*----------------------------------------------------------------------------*/ /* lck stuff */ /// \brief Initialization of synchronization primitives linked with MDBX_env /// instance both in LCK-file and within the current process. /// \param /// global_uniqueness_flag = true - denotes that there are no other processes /// working with DB and LCK-file. Thus the function MUST initialize /// shared synchronization objects in memory-mapped LCK-file. /// global_uniqueness_flag = false - denotes that at least one process is /// already working with DB and LCK-file, including the case when DB /// has already been opened in the current process. Thus the function /// MUST NOT initialize shared synchronization objects in memory-mapped /// LCK-file that are already in use. /// \return Error code or zero on success. MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag); /// \brief Disconnects from shared interprocess objects and destructs /// synchronization objects linked with MDBX_env instance /// within the current process. /// \param /// inprocess_neighbor = NULL - if the current process does not have other /// instances of MDBX_env linked with the DB being closed. /// Thus the function MUST check for other processes working with DB or /// LCK-file, and keep or destroy shared synchronization objects in /// memory-mapped LCK-file depending on the result. /// inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env /// (anyone of there is several) working with DB or LCK-file within the /// current process. Thus the function MUST NOT try to acquire exclusive /// lock and/or try to destruct shared synchronization objects linked with /// DB or LCK-file. Moreover, the implementation MUST ensure correct work /// of other instances of MDBX_env within the current process, e.g. /// restore POSIX-fcntl locks after the closing of file descriptors. /// \return Error code (MDBX_PANIC) or zero on success. MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor); /// \brief Connects to shared interprocess locking objects and tries to acquire /// the maximum lock level (shared if exclusive is not available) /// Depending on implementation or/and platform (Windows) this function may /// acquire the non-OS super-level lock (e.g. for shared synchronization /// objects initialization), which will be downgraded to OS-exclusive or /// shared via explicit calling of mdbx_lck_downgrade(). /// \return /// MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus /// the current process is the first and only after the last use of DB. /// MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus /// DB has already been opened and now is used by other processes. /// Otherwise (not 0 and not -1) - error code. MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env); /// \brief Downgrades the level of initially acquired lock to /// operational level specified by argument. The reson for such downgrade: /// - unblocking of other processes that are waiting for access, i.e. /// if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes /// should be made aware that access is unavailable rather than /// wait for it. /// - freeing locks that interfere file operation (especially for Windows) /// (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock. /// (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive /// operational lock. /// \return Error code or zero on success MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env); /// \brief Locks LCK-file or/and table of readers for (de)registering. /// \return Error code or zero on success MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env); /// \brief Unlocks LCK-file or/and table of readers after (de)registering. MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env); /// \brief Acquires lock for DB change (on writing transaction start) /// Reading transactions will not be blocked. /// Declared as LIBMDBX_API because it is used in mdbx_chk. /// \return Error code or zero on success LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait); /// \brief Releases lock once DB changes is made (after writing transaction /// has finished). /// Declared as LIBMDBX_API because it is used in mdbx_chk. LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env); /// \brief Sets alive-flag of reader presence (indicative lock) for PID of /// the current process. The function does no more than needed for /// the correct working of mdbx_rpid_check() in other processes. /// \return Error code or zero on success MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env); /// \brief Resets alive-flag of reader presence (indicative lock) /// for PID of the current process. The function does no more than needed /// for the correct working of mdbx_rpid_check() in other processes. /// \return Error code or zero on success MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env); /// \brief Checks for reading process status with the given pid with help of /// alive-flag of presence (indicative lock) or using another way. /// \return /// MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive /// and working with DB (indicative lock is present). /// MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent /// or not working with DB (indicative lock is not present). /// Otherwise (not 0 and not -1) - error code. MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid); #if defined(_WIN32) || defined(_WIN64) #define MUSTDIE_MB2WIDE(FROM, TO) \ do { \ const char *const from_tmp = (FROM); \ const size_t from_mblen = strlen(from_tmp); \ const size_t to_wlen = mdbx_mb2w(nullptr, 0, from_tmp, from_mblen); \ if (to_wlen < 1 || to_wlen > /* MAX_PATH */ INT16_MAX) \ return ERROR_INVALID_NAME; \ wchar_t *const to_tmp = _alloca((to_wlen + 1) * sizeof(wchar_t)); \ if (to_wlen + 1 != \ mdbx_mb2w(to_tmp, to_wlen + 1, from_tmp, from_mblen + 1)) \ return ERROR_INVALID_NAME; \ (TO) = to_tmp; \ } while (0) typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *); MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared, mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive; #if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */ typedef enum _FILE_INFO_BY_HANDLE_CLASS { FileBasicInfo, FileStandardInfo, FileNameInfo, FileRenameInfo, FileDispositionInfo, FileAllocationInfo, FileEndOfFileInfo, FileStreamInfo, FileCompressionInfo, FileAttributeTagInfo, FileIdBothDirectoryInfo, FileIdBothDirectoryRestartInfo, FileIoPriorityHintInfo, FileRemoteProtocolInfo, MaximumFileInfoByHandleClass } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS; typedef struct _FILE_END_OF_FILE_INFO { LARGE_INTEGER EndOfFile; } FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO; #define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001 #define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002 typedef struct _FILE_REMOTE_PROTOCOL_INFO { USHORT StructureVersion; USHORT StructureSize; DWORD Protocol; USHORT ProtocolMajorVersion; USHORT ProtocolMinorVersion; USHORT ProtocolRevision; USHORT Reserved; DWORD Flags; struct { DWORD Reserved[8]; } GenericReserved; struct { DWORD Reserved[16]; } ProtocolSpecificReserved; } FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO; #endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */ typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)( _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize); MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx; typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)( _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer, _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber, _Out_opt_ LPDWORD lpMaximumComponentLength, _Out_opt_ LPDWORD lpFileSystemFlags, _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize); MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW mdbx_GetVolumeInformationByHandleW; typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile, _Out_ LPWSTR lpszFilePath, _In_ DWORD cchFilePath, _In_ DWORD dwFlags); MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW; typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)( _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize); MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle mdbx_SetFileInformationByHandle; typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)( IN HANDLE FileHandle, IN OUT HANDLE Event, IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode, IN OUT PVOID InputBuffer, IN ULONG InputBufferLength, OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength); MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile; typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void); MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64; #if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8 typedef struct _WIN32_MEMORY_RANGE_ENTRY { PVOID VirtualAddress; SIZE_T NumberOfBytes; } WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY; #endif /* Windows 8.x */ typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)( HANDLE hProcess, ULONG_PTR NumberOfEntries, PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags); MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory; typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle, IN PLARGE_INTEGER NewSectionSize); MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection; static __inline bool mdbx_RunningUnderWine(void) { return !mdbx_NtExtendSection; } typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey, LPCSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA; NTSYSAPI ULONG RtlRandomEx(PULONG Seed); #endif /* Windows */ #endif /* !__cplusplus */ /*----------------------------------------------------------------------------*/ #if defined(_MSC_VER) && _MSC_VER >= 1900 /* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros * for internal format-args checker. */ #undef PRIuPTR #undef PRIiPTR #undef PRIdPTR #undef PRIxPTR #define PRIuPTR "Iu" #define PRIiPTR "Ii" #define PRIdPTR "Id" #define PRIxPTR "Ix" #define PRIuSIZE "zu" #define PRIiSIZE "zi" #define PRIdSIZE "zd" #define PRIxSIZE "zx" #endif /* fix PRI*PTR for _MSC_VER */ #ifndef PRIuSIZE #define PRIuSIZE PRIuPTR #define PRIiSIZE PRIiPTR #define PRIdSIZE PRIdPTR #define PRIxSIZE PRIxPTR #endif /* PRI*SIZE macros for MSVC */ #ifdef _MSC_VER #pragma warning(pop) #endif