2019-09-09 13:40:24 +03:00
|
|
|
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
|
2017-03-16 18:09:27 +03:00
|
|
|
|
|
|
|
/*
|
2019-02-03 12:28:01 +03:00
|
|
|
* Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
|
2017-03-16 18:09:27 +03:00
|
|
|
* 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>.
|
|
|
|
*/
|
|
|
|
|
2019-09-10 02:19:35 +03:00
|
|
|
#include "internals.h"
|
2017-03-16 18:09:27 +03:00
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-09-05 20:58:03 +03:00
|
|
|
|
2019-08-29 23:48:51 +03:00
|
|
|
#include <winioctl.h>
|
|
|
|
|
2017-03-30 18:54:57 +03:00
|
|
|
static int waitstatus2errcode(DWORD result) {
|
2017-03-16 18:09:27 +03:00
|
|
|
switch (result) {
|
|
|
|
case WAIT_OBJECT_0:
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
case WAIT_FAILED:
|
2017-06-21 01:41:25 +03:00
|
|
|
return GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
case WAIT_ABANDONED:
|
|
|
|
return ERROR_ABANDONED_WAIT_0;
|
|
|
|
case WAIT_IO_COMPLETION:
|
|
|
|
return ERROR_USER_APC;
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
return ERROR_TIMEOUT;
|
|
|
|
default:
|
|
|
|
return ERROR_UNHANDLED_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2017-06-06 21:20:16 +03:00
|
|
|
|
|
|
|
/* Map a result from an NTAPI call to WIN32 error code. */
|
|
|
|
static int ntstatus2errcode(NTSTATUS status) {
|
|
|
|
DWORD dummy;
|
2017-07-02 09:07:57 +03:00
|
|
|
OVERLAPPED ov;
|
|
|
|
memset(&ov, 0, sizeof(ov));
|
|
|
|
ov.Internal = status;
|
2017-06-06 21:20:16 +03:00
|
|
|
return GetOverlappedResult(NULL, &ov, &dummy, FALSE) ? MDBX_SUCCESS
|
|
|
|
: GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We use native NT APIs to setup the memory map, so that we can
|
|
|
|
* let the DB file grow incrementally instead of always preallocating
|
|
|
|
* the full size. These APIs are defined in <wdm.h> and <ntifs.h>
|
|
|
|
* but those headers are meant for driver-level development and
|
|
|
|
* conflict with the regular user-level headers, so we explicitly
|
|
|
|
* declare them here. Using these APIs also means we must link to
|
|
|
|
* ntdll.dll, which is not linked by default in user code. */
|
2017-06-21 01:34:56 +03:00
|
|
|
|
|
|
|
extern NTSTATUS NTAPI NtCreateSection(
|
|
|
|
OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
IN OPTIONAL PLARGE_INTEGER MaximumSize, IN ULONG SectionPageProtection,
|
|
|
|
IN ULONG AllocationAttributes, IN OPTIONAL HANDLE FileHandle);
|
|
|
|
|
2017-12-25 18:31:59 +03:00
|
|
|
typedef struct _SECTION_BASIC_INFORMATION {
|
|
|
|
ULONG Unknown;
|
|
|
|
ULONG SectionAttributes;
|
|
|
|
LARGE_INTEGER SectionSize;
|
|
|
|
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
|
|
|
|
|
|
|
typedef enum _SECTION_INFORMATION_CLASS {
|
|
|
|
SectionBasicInformation,
|
|
|
|
SectionImageInformation,
|
|
|
|
SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation
|
|
|
|
MaxSectionInfoClass
|
|
|
|
} SECTION_INFORMATION_CLASS;
|
|
|
|
|
|
|
|
extern NTSTATUS NTAPI NtQuerySection(
|
|
|
|
IN HANDLE SectionHandle, IN SECTION_INFORMATION_CLASS InformationClass,
|
|
|
|
OUT PVOID InformationBuffer, IN ULONG InformationBufferSize,
|
|
|
|
OUT PULONG ResultLength OPTIONAL);
|
|
|
|
|
2017-06-21 01:34:56 +03:00
|
|
|
extern NTSTATUS NTAPI NtExtendSection(IN HANDLE SectionHandle,
|
|
|
|
IN PLARGE_INTEGER NewSectionSize);
|
2017-06-06 21:20:16 +03:00
|
|
|
|
|
|
|
typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
|
|
|
|
|
2017-06-21 01:34:56 +03:00
|
|
|
extern NTSTATUS NTAPI NtMapViewOfSection(
|
|
|
|
IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
|
|
|
|
IN ULONG_PTR ZeroBits, IN SIZE_T CommitSize,
|
|
|
|
IN OUT OPTIONAL PLARGE_INTEGER SectionOffset, IN OUT PSIZE_T ViewSize,
|
|
|
|
IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType,
|
|
|
|
IN ULONG Win32Protect);
|
|
|
|
|
|
|
|
extern NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle,
|
|
|
|
IN OPTIONAL PVOID BaseAddress);
|
|
|
|
|
|
|
|
extern NTSTATUS NTAPI NtClose(HANDLE Handle);
|
2017-06-06 21:20:16 +03:00
|
|
|
|
2017-06-21 01:34:56 +03:00
|
|
|
extern NTSTATUS NTAPI NtAllocateVirtualMemory(
|
2018-01-14 18:36:25 +03:00
|
|
|
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG_PTR ZeroBits,
|
|
|
|
IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);
|
2017-06-21 01:34:56 +03:00
|
|
|
|
|
|
|
extern NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
|
|
|
IN PVOID *BaseAddress,
|
2018-01-14 18:36:25 +03:00
|
|
|
IN OUT PSIZE_T RegionSize,
|
2017-06-21 01:34:56 +03:00
|
|
|
IN ULONG FreeType);
|
2017-06-06 21:20:16 +03:00
|
|
|
|
2018-06-12 22:56:26 +03:00
|
|
|
#ifndef WOF_CURRENT_VERSION
|
|
|
|
typedef struct _WOF_EXTERNAL_INFO {
|
|
|
|
DWORD Version;
|
|
|
|
DWORD Provider;
|
|
|
|
} WOF_EXTERNAL_INFO, *PWOF_EXTERNAL_INFO;
|
|
|
|
#endif /* WOF_CURRENT_VERSION */
|
|
|
|
|
|
|
|
#ifndef WIM_PROVIDER_CURRENT_VERSION
|
|
|
|
#define WIM_PROVIDER_HASH_SIZE 20
|
|
|
|
|
|
|
|
typedef struct _WIM_PROVIDER_EXTERNAL_INFO {
|
|
|
|
DWORD Version;
|
|
|
|
DWORD Flags;
|
|
|
|
LARGE_INTEGER DataSourceId;
|
|
|
|
BYTE ResourceHash[WIM_PROVIDER_HASH_SIZE];
|
|
|
|
} WIM_PROVIDER_EXTERNAL_INFO, *PWIM_PROVIDER_EXTERNAL_INFO;
|
|
|
|
#endif /* WIM_PROVIDER_CURRENT_VERSION */
|
|
|
|
|
2017-07-21 15:49:05 +03:00
|
|
|
#ifndef FILE_PROVIDER_CURRENT_VERSION
|
2017-07-11 19:05:40 +03:00
|
|
|
typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 {
|
|
|
|
ULONG Version;
|
|
|
|
ULONG Algorithm;
|
|
|
|
ULONG Flags;
|
|
|
|
} FILE_PROVIDER_EXTERNAL_INFO_V1, *PFILE_PROVIDER_EXTERNAL_INFO_V1;
|
2018-06-12 22:56:26 +03:00
|
|
|
#endif /* FILE_PROVIDER_CURRENT_VERSION */
|
2017-07-11 19:05:40 +03:00
|
|
|
|
|
|
|
#ifndef STATUS_OBJECT_NOT_EXTERNALLY_BACKED
|
|
|
|
#define STATUS_OBJECT_NOT_EXTERNALLY_BACKED ((NTSTATUS)0xC000046DL)
|
|
|
|
#endif
|
|
|
|
#ifndef STATUS_INVALID_DEVICE_REQUEST
|
|
|
|
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L)
|
|
|
|
#endif
|
|
|
|
|
2018-10-06 19:28:16 +03:00
|
|
|
#ifndef FILE_DEVICE_FILE_SYSTEM
|
|
|
|
#define FILE_DEVICE_FILE_SYSTEM 0x00000009
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef FSCTL_GET_EXTERNAL_BACKING
|
|
|
|
#define FSCTL_GET_EXTERNAL_BACKING \
|
|
|
|
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 196, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
|
|
|
#endif
|
|
|
|
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif /* _WIN32 || _WIN64 */
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-07-13 20:07:24 +03:00
|
|
|
#if _POSIX_C_SOURCE > 200212 && \
|
2019-03-04 14:41:29 +03:00
|
|
|
/* workaround for avoid musl libc wrong prototype */ ( \
|
|
|
|
defined(__GLIBC__) || defined(__GNU_LIBRARY__))
|
|
|
|
/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 1.x-3.x */
|
2019-08-25 03:05:58 +03:00
|
|
|
__extern_C void __assert_fail(const char *assertion, const char *file,
|
|
|
|
unsigned line, const char *function)
|
|
|
|
#ifdef __THROW
|
|
|
|
__THROW
|
|
|
|
#else
|
|
|
|
__nothrow
|
|
|
|
#endif /* __THROW */
|
|
|
|
__noreturn;
|
|
|
|
|
2019-08-13 02:07:10 +03:00
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
2019-08-25 03:05:58 +03:00
|
|
|
__extern_C void __assert_rtn(const char *function, const char *file, int line,
|
|
|
|
const char *assertion) /* __nothrow */
|
|
|
|
#ifdef __dead2
|
|
|
|
__dead2
|
|
|
|
#else
|
|
|
|
__noreturn
|
|
|
|
#endif /* __dead2 */
|
|
|
|
#ifdef __disable_tail_calls
|
|
|
|
__disable_tail_calls
|
|
|
|
#endif /* __disable_tail_calls */
|
|
|
|
;
|
|
|
|
|
2019-08-13 02:07:10 +03:00
|
|
|
#define __assert_fail(assertion, file, line, function) \
|
|
|
|
__assert_rtn(function, file, line, assertion)
|
|
|
|
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
|
|
|
defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \
|
|
|
|
defined(__DragonFly__)
|
2019-08-25 03:05:58 +03:00
|
|
|
__extern_C void __assert(const char *function, const char *file, int line,
|
|
|
|
const char *assertion) /* __nothrow */
|
|
|
|
#ifdef __dead2
|
|
|
|
__dead2
|
|
|
|
#else
|
|
|
|
__noreturn
|
|
|
|
#endif /* __dead2 */
|
|
|
|
#ifdef __disable_tail_calls
|
|
|
|
__disable_tail_calls
|
|
|
|
#endif /* __disable_tail_calls */
|
|
|
|
;
|
2019-07-13 20:07:24 +03:00
|
|
|
#define __assert_fail(assertion, file, line, function) \
|
|
|
|
__assert(function, file, line, assertion)
|
|
|
|
|
|
|
|
#endif /* __assert_fail */
|
2017-03-16 18:09:27 +03:00
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC void __cold mdbx_assert_fail(const MDBX_env *env,
|
|
|
|
const char *msg,
|
|
|
|
const char *func, int line) {
|
2017-05-24 01:42:10 +03:00
|
|
|
#if MDBX_DEBUG
|
2017-03-16 18:09:27 +03:00
|
|
|
if (env && env->me_assert_func) {
|
|
|
|
env->me_assert_func(env, msg, func, line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
(void)env;
|
2017-05-24 01:42:10 +03:00
|
|
|
#endif /* MDBX_DEBUG */
|
2017-03-16 18:09:27 +03:00
|
|
|
|
|
|
|
if (mdbx_debug_logger)
|
2019-09-24 02:07:00 +03:00
|
|
|
mdbx_debug_log(MDBX_LOG_FATAL, func, line, "assert: %s\n", msg);
|
2018-10-14 01:11:14 +03:00
|
|
|
else {
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
char *message = nullptr;
|
|
|
|
const int num = mdbx_asprintf(&message, "\r\nMDBX-ASSERTION: %s, %s:%u",
|
2018-10-21 15:42:26 +03:00
|
|
|
msg, func ? func : "unknown", line);
|
2018-10-14 01:11:14 +03:00
|
|
|
if (num < 1 || !message)
|
|
|
|
message = "<troubles with assertion-message preparation>";
|
|
|
|
OutputDebugStringA(message);
|
|
|
|
if (IsDebuggerPresent())
|
|
|
|
DebugBreak();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2018-10-14 01:11:14 +03:00
|
|
|
__assert_fail(msg, "mdbx", line, func);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
FatalExit(ERROR_UNHANDLED_ERROR);
|
|
|
|
#else
|
|
|
|
abort();
|
|
|
|
#endif
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC __cold void mdbx_panic(const char *fmt, ...) {
|
2017-03-16 18:09:27 +03:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2018-10-14 01:11:14 +03:00
|
|
|
|
|
|
|
char *message = nullptr;
|
|
|
|
const int num = mdbx_vasprintf(&message, fmt, ap);
|
2017-03-16 18:09:27 +03:00
|
|
|
va_end(ap);
|
2019-10-25 22:56:25 +03:00
|
|
|
const char *const const_message =
|
|
|
|
(num < 1 || !message) ? "<troubles with panic-message preparation>"
|
|
|
|
: message;
|
2018-10-14 01:11:14 +03:00
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
OutputDebugStringA("\r\nMDBX-PANIC: ");
|
2019-10-25 22:56:25 +03:00
|
|
|
OutputDebugStringA(const_message);
|
2018-10-14 01:11:14 +03:00
|
|
|
if (IsDebuggerPresent())
|
|
|
|
DebugBreak();
|
|
|
|
FatalExit(ERROR_UNHANDLED_ERROR);
|
|
|
|
#else
|
2019-10-25 22:56:25 +03:00
|
|
|
__assert_fail(const_message, "mdbx", 0, "panic");
|
2017-03-16 18:09:27 +03:00
|
|
|
abort();
|
2018-10-14 01:11:14 +03:00
|
|
|
#endif
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2018-10-05 15:41:27 +03:00
|
|
|
#ifndef mdbx_vasprintf
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt,
|
|
|
|
va_list ap) {
|
2018-10-05 15:41:27 +03:00
|
|
|
va_list ones;
|
2017-03-16 18:09:27 +03:00
|
|
|
va_copy(ones, ap);
|
|
|
|
int needed = vsnprintf(nullptr, 0, fmt, ap);
|
|
|
|
|
|
|
|
if (unlikely(needed < 0 || needed >= INT_MAX)) {
|
2017-07-26 12:23:01 +03:00
|
|
|
*strp = nullptr;
|
2017-03-16 18:09:27 +03:00
|
|
|
va_end(ones);
|
|
|
|
return needed;
|
|
|
|
}
|
|
|
|
|
2018-10-12 22:01:36 +03:00
|
|
|
*strp = mdbx_malloc(needed + 1);
|
2017-07-26 12:23:01 +03:00
|
|
|
if (unlikely(*strp == nullptr)) {
|
2017-03-16 18:09:27 +03:00
|
|
|
va_end(ones);
|
2018-10-05 15:41:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-04-24 19:37:01 +03:00
|
|
|
SetLastError(MDBX_ENOMEM);
|
2018-10-05 15:41:27 +03:00
|
|
|
#else
|
|
|
|
errno = MDBX_ENOMEM;
|
|
|
|
#endif
|
2017-04-24 19:37:01 +03:00
|
|
|
return -1;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int actual = vsnprintf(*strp, needed + 1, fmt, ones);
|
|
|
|
va_end(ones);
|
|
|
|
|
|
|
|
assert(actual == needed);
|
|
|
|
if (unlikely(actual < 0)) {
|
2018-10-12 22:01:36 +03:00
|
|
|
mdbx_free(*strp);
|
2017-07-26 12:23:01 +03:00
|
|
|
*strp = nullptr;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
return actual;
|
|
|
|
}
|
2018-10-05 15:41:27 +03:00
|
|
|
#endif /* mdbx_vasprintf */
|
|
|
|
|
|
|
|
#ifndef mdbx_asprintf
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_asprintf(char **strp, const char *fmt, ...) {
|
2018-10-05 15:41:27 +03:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
int rc = mdbx_vasprintf(strp, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return rc;
|
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif /* mdbx_asprintf */
|
|
|
|
|
|
|
|
#ifndef mdbx_memalign_alloc
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
|
|
|
|
void **result) {
|
2018-10-14 11:14:14 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
(void)alignment;
|
|
|
|
*result = VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
2017-05-24 01:42:10 +03:00
|
|
|
return *result ? MDBX_SUCCESS : MDBX_ENOMEM /* ERROR_OUTOFMEMORY */;
|
2019-07-13 20:07:42 +03:00
|
|
|
#elif defined(_ISOC11_SOURCE)
|
|
|
|
*result = aligned_alloc(alignment, bytes);
|
2017-05-24 01:42:10 +03:00
|
|
|
return *result ? MDBX_SUCCESS : errno;
|
2017-03-16 18:09:27 +03:00
|
|
|
#elif _POSIX_VERSION >= 200112L
|
2017-07-26 12:23:01 +03:00
|
|
|
*result = nullptr;
|
2017-03-16 18:09:27 +03:00
|
|
|
return posix_memalign(result, alignment, bytes);
|
2019-07-13 20:07:42 +03:00
|
|
|
#elif __GLIBC_PREREQ(2, 16) || __STDC_VERSION__ >= 201112L
|
|
|
|
*result = memalign(alignment, bytes);
|
|
|
|
return *result ? MDBX_SUCCESS : errno;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
|
|
|
#error FIXME
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif /* mdbx_memalign_alloc */
|
|
|
|
|
|
|
|
#ifndef mdbx_memalign_free
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr) {
|
2018-10-14 11:14:14 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
VirtualFree(ptr, 0, MEM_RELEASE);
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2018-10-12 22:01:36 +03:00
|
|
|
mdbx_free(ptr);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif /* mdbx_memalign_free */
|
|
|
|
|
2018-10-14 11:24:59 +03:00
|
|
|
#ifndef mdbx_strdup
|
|
|
|
char *mdbx_strdup(const char *str) {
|
|
|
|
if (!str)
|
|
|
|
return NULL;
|
|
|
|
size_t bytes = strlen(str) + 1;
|
|
|
|
char *dup = mdbx_malloc(bytes);
|
|
|
|
if (dup)
|
|
|
|
memcpy(dup, str, bytes);
|
|
|
|
return dup;
|
|
|
|
}
|
|
|
|
#endif /* mdbx_strdup */
|
|
|
|
|
2017-03-16 18:09:27 +03:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_init(mdbx_condmutex_t *condmutex) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-05-24 01:42:10 +03:00
|
|
|
int rc = MDBX_SUCCESS;
|
2017-05-23 18:40:21 +03:00
|
|
|
condmutex->event = NULL;
|
|
|
|
condmutex->mutex = CreateMutex(NULL, FALSE, NULL);
|
|
|
|
if (!condmutex->mutex)
|
2017-06-21 01:41:25 +03:00
|
|
|
return GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
|
2017-05-23 18:40:21 +03:00
|
|
|
condmutex->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (!condmutex->event) {
|
2017-06-21 01:41:25 +03:00
|
|
|
rc = GetLastError();
|
2017-05-23 18:40:21 +03:00
|
|
|
(void)CloseHandle(condmutex->mutex);
|
|
|
|
condmutex->mutex = NULL;
|
|
|
|
}
|
|
|
|
return rc;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
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;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-05-23 18:40:21 +03:00
|
|
|
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;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_destroy(mdbx_condmutex_t *condmutex) {
|
2017-05-23 18:40:21 +03:00
|
|
|
int rc = MDBX_EINVAL;
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-05-23 18:40:21 +03:00
|
|
|
if (condmutex->event) {
|
2017-06-21 01:41:25 +03:00
|
|
|
rc = CloseHandle(condmutex->event) ? MDBX_SUCCESS : GetLastError();
|
2017-05-24 01:42:10 +03:00
|
|
|
if (rc == MDBX_SUCCESS)
|
2017-05-23 18:40:21 +03:00
|
|
|
condmutex->event = NULL;
|
|
|
|
}
|
|
|
|
if (condmutex->mutex) {
|
2017-06-21 01:41:25 +03:00
|
|
|
rc = CloseHandle(condmutex->mutex) ? MDBX_SUCCESS : GetLastError();
|
2017-05-24 01:42:10 +03:00
|
|
|
if (rc == MDBX_SUCCESS)
|
2017-05-23 18:40:21 +03:00
|
|
|
condmutex->mutex = NULL;
|
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
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));
|
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2017-05-23 18:40:21 +03:00
|
|
|
return rc;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_lock(mdbx_condmutex_t *condmutex) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-05-23 18:40:21 +03:00
|
|
|
DWORD code = WaitForSingleObject(condmutex->mutex, INFINITE);
|
|
|
|
return waitstatus2errcode(code);
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
return pthread_mutex_lock(&condmutex->mutex);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_unlock(mdbx_condmutex_t *condmutex) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-06-21 01:41:25 +03:00
|
|
|
return ReleaseMutex(condmutex->mutex) ? MDBX_SUCCESS : GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
return pthread_mutex_unlock(&condmutex->mutex);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_signal(mdbx_condmutex_t *condmutex) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-06-21 01:41:25 +03:00
|
|
|
return SetEvent(condmutex->event) ? MDBX_SUCCESS : GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
return pthread_cond_signal(&condmutex->cond);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_condmutex_wait(mdbx_condmutex_t *condmutex) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-05-23 18:40:21 +03:00
|
|
|
DWORD code =
|
|
|
|
SignalObjectAndWait(condmutex->mutex, condmutex->event, INFINITE, FALSE);
|
2017-03-16 18:09:27 +03:00
|
|
|
if (code == WAIT_OBJECT_0)
|
2017-05-23 18:40:21 +03:00
|
|
|
code = WaitForSingleObject(condmutex->mutex, INFINITE);
|
2017-03-30 18:54:57 +03:00
|
|
|
return waitstatus2errcode(code);
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-23 18:40:21 +03:00
|
|
|
return pthread_cond_wait(&condmutex->cond, &condmutex->mutex);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex) {
|
2017-05-23 21:54:06 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
InitializeCriticalSection(fastmutex);
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-05-23 21:54:06 +03:00
|
|
|
#else
|
|
|
|
return pthread_mutex_init(fastmutex, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex) {
|
2017-05-23 21:54:06 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
DeleteCriticalSection(fastmutex);
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-05-23 21:54:06 +03:00
|
|
|
#else
|
|
|
|
return pthread_mutex_destroy(fastmutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex) {
|
2017-05-23 21:54:06 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
EnterCriticalSection(fastmutex);
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-05-23 21:54:06 +03:00
|
|
|
#else
|
|
|
|
return pthread_mutex_lock(fastmutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) {
|
2017-05-23 21:54:06 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
LeaveCriticalSection(fastmutex);
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-05-23 21:54:06 +03:00
|
|
|
#else
|
|
|
|
return pthread_mutex_unlock(fastmutex);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
|
2018-06-30 14:20:55 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
return DeleteFileA(pathname) ? MDBX_SUCCESS : GetLastError();
|
|
|
|
#else
|
|
|
|
return unlink(pathname) ? errno : MDBX_SUCCESS;
|
|
|
|
#endif
|
|
|
|
}
|
2019-08-31 17:10:04 +03:00
|
|
|
|
|
|
|
MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
|
|
|
|
mode_t mode, mdbx_filehandle_t *fd,
|
|
|
|
bool exclusive) {
|
2017-03-16 18:09:27 +03:00
|
|
|
*fd = INVALID_HANDLE_VALUE;
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
(void)mode;
|
|
|
|
|
2018-06-13 17:02:31 +03:00
|
|
|
DWORD DesiredAccess, ShareMode;
|
2017-03-16 18:09:27 +03:00
|
|
|
DWORD FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
|
|
|
|
default:
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
case O_RDONLY:
|
|
|
|
DesiredAccess = GENERIC_READ;
|
2018-06-13 17:02:31 +03:00
|
|
|
ShareMode =
|
|
|
|
exclusive ? FILE_SHARE_READ : (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
2017-03-16 18:09:27 +03:00
|
|
|
break;
|
2017-05-24 01:42:10 +03:00
|
|
|
case O_WRONLY: /* assume for MDBX_env_copy() and friends output */
|
2017-03-16 18:09:27 +03:00
|
|
|
DesiredAccess = GENERIC_WRITE;
|
|
|
|
ShareMode = 0;
|
|
|
|
FlagsAndAttributes |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
|
|
|
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
|
2018-06-13 17:02:31 +03:00
|
|
|
ShareMode = exclusive ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
2017-03-16 18:09:27 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD CreationDisposition;
|
|
|
|
switch (flags & (O_EXCL | O_CREAT)) {
|
|
|
|
default:
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
case 0:
|
|
|
|
CreationDisposition = OPEN_EXISTING;
|
|
|
|
break;
|
|
|
|
case O_EXCL | O_CREAT:
|
|
|
|
CreationDisposition = CREATE_NEW;
|
|
|
|
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
|
|
|
break;
|
|
|
|
case O_CREAT:
|
|
|
|
CreationDisposition = OPEN_ALWAYS;
|
|
|
|
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*fd = CreateFileA(pathname, DesiredAccess, ShareMode, NULL,
|
|
|
|
CreationDisposition, FlagsAndAttributes, NULL);
|
|
|
|
|
|
|
|
if (*fd == INVALID_HANDLE_VALUE)
|
2017-06-21 01:41:25 +03:00
|
|
|
return GetLastError();
|
|
|
|
if ((flags & O_CREAT) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
2017-03-16 18:09:27 +03:00
|
|
|
/* set FILE_ATTRIBUTE_NOT_CONTENT_INDEXED for new file */
|
|
|
|
DWORD FileAttributes = GetFileAttributesA(pathname);
|
|
|
|
if (FileAttributes == INVALID_FILE_ATTRIBUTES ||
|
|
|
|
!SetFileAttributesA(pathname, FileAttributes |
|
|
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {
|
2017-06-21 01:41:25 +03:00
|
|
|
int rc = GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
CloseHandle(*fd);
|
|
|
|
*fd = INVALID_HANDLE_VALUE;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2018-06-13 17:02:31 +03:00
|
|
|
(void)exclusive;
|
2017-03-16 18:09:27 +03:00
|
|
|
#ifdef O_CLOEXEC
|
|
|
|
flags |= O_CLOEXEC;
|
2019-08-11 01:06:59 +03:00
|
|
|
#endif /* O_CLOEXEC */
|
2017-03-16 18:09:27 +03:00
|
|
|
*fd = open(pathname, flags, mode);
|
|
|
|
if (*fd < 0)
|
|
|
|
return errno;
|
2019-08-11 01:06:59 +03:00
|
|
|
|
|
|
|
#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
|
|
|
|
int fd_flags = fcntl(*fd, F_GETFD);
|
|
|
|
if (fd_flags != -1)
|
|
|
|
(void)fcntl(*fd, F_SETFD, fd_flags | FD_CLOEXEC);
|
|
|
|
#endif /* FD_CLOEXEC && !O_CLOEXEC */
|
|
|
|
|
|
|
|
if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY) {
|
|
|
|
/* assume for MDBX_env_copy() and friends output */
|
|
|
|
#if defined(O_DIRECT)
|
|
|
|
int fd_flags = fcntl(*fd, F_GETFD);
|
|
|
|
if (fd_flags != -1)
|
|
|
|
(void)fcntl(*fd, F_SETFL, fd_flags | O_DIRECT);
|
|
|
|
#endif /* O_DIRECT */
|
2019-08-13 02:07:10 +03:00
|
|
|
#if defined(F_NOCACHE)
|
|
|
|
(void)fcntl(*fd, F_NOCACHE, 1);
|
|
|
|
#endif /* F_NOCACHE */
|
2019-08-11 01:06:59 +03:00
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2019-08-11 01:06:59 +03:00
|
|
|
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-06-21 01:41:25 +03:00
|
|
|
return CloseHandle(fd) ? MDBX_SUCCESS : GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-24 01:42:10 +03:00
|
|
|
return (close(fd) == 0) ? MDBX_SUCCESS : errno;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t bytes,
|
|
|
|
uint64_t offset) {
|
2017-03-16 18:09:27 +03:00
|
|
|
if (bytes > MAX_WRITE)
|
2017-04-27 18:13:39 +03:00
|
|
|
return MDBX_EINVAL;
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-03-16 18:09:27 +03:00
|
|
|
OVERLAPPED ov;
|
|
|
|
ov.hEvent = 0;
|
|
|
|
ov.Offset = (DWORD)offset;
|
|
|
|
ov.OffsetHigh = HIGH_DWORD(offset);
|
|
|
|
|
2017-04-24 15:51:21 +03:00
|
|
|
DWORD read = 0;
|
2017-03-16 18:09:27 +03:00
|
|
|
if (unlikely(!ReadFile(fd, buf, (DWORD)bytes, &read, &ov))) {
|
2017-06-21 01:41:25 +03:00
|
|
|
int rc = GetLastError();
|
2017-05-24 01:42:10 +03:00
|
|
|
return (rc == MDBX_SUCCESS) ? /* paranoia */ ERROR_READ_FAULT : rc;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
#else
|
2017-05-26 17:11:48 +03:00
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
2017-07-26 18:32:46 +03:00
|
|
|
intptr_t read = pread(fd, buf, bytes, offset);
|
2017-04-25 19:58:00 +03:00
|
|
|
if (read < 0) {
|
|
|
|
int rc = errno;
|
2017-05-24 01:42:10 +03:00
|
|
|
return (rc == MDBX_SUCCESS) ? /* paranoia */ MDBX_EIO : rc;
|
2017-04-25 19:58:00 +03:00
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2017-05-24 01:42:10 +03:00
|
|
|
return (bytes == (size_t)read) ? MDBX_SUCCESS : MDBX_ENODATA;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
|
|
|
size_t bytes, uint64_t offset) {
|
2019-06-28 11:15:42 +03:00
|
|
|
while (true) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2019-06-28 11:15:42 +03:00
|
|
|
OVERLAPPED ov;
|
|
|
|
ov.hEvent = 0;
|
|
|
|
ov.Offset = (DWORD)offset;
|
|
|
|
ov.OffsetHigh = HIGH_DWORD(offset);
|
2017-03-16 18:09:27 +03:00
|
|
|
|
2019-06-28 11:15:42 +03:00
|
|
|
DWORD written;
|
2019-09-16 14:16:14 +03:00
|
|
|
if (unlikely(!WriteFile(
|
|
|
|
fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
|
|
|
|
&written, &ov)))
|
2019-06-28 11:15:42 +03:00
|
|
|
return GetLastError();
|
|
|
|
if (likely(bytes == written))
|
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-26 17:11:48 +03:00
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
2019-06-24 00:56:26 +03:00
|
|
|
const intptr_t written =
|
2019-09-16 14:16:14 +03:00
|
|
|
pwrite(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE, offset);
|
2017-03-16 18:09:27 +03:00
|
|
|
if (likely(bytes == (size_t)written))
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2019-06-24 00:56:26 +03:00
|
|
|
if (written < 0) {
|
|
|
|
const int rc = errno;
|
|
|
|
if (rc != EINTR)
|
|
|
|
return rc;
|
2019-06-28 11:15:42 +03:00
|
|
|
continue;
|
2019-06-24 00:56:26 +03:00
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2019-06-28 11:15:42 +03:00
|
|
|
bytes -= written;
|
|
|
|
offset += written;
|
|
|
|
buf = (char *)buf + written;
|
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-09-16 14:16:14 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
|
|
|
|
size_t bytes) {
|
|
|
|
while (true) {
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
DWORD written;
|
|
|
|
if (unlikely(!WriteFile(
|
|
|
|
fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
|
|
|
|
&written, nullptr)))
|
|
|
|
return GetLastError();
|
|
|
|
if (likely(bytes == written))
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
#else
|
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
|
|
|
const intptr_t written =
|
|
|
|
write(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE);
|
|
|
|
if (likely(bytes == (size_t)written))
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
if (written < 0) {
|
|
|
|
const int rc = errno;
|
|
|
|
if (rc != EINTR)
|
|
|
|
return rc;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
bytes -= written;
|
|
|
|
buf = (char *)buf + written;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:09:27 +03:00
|
|
|
int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt,
|
2017-05-24 18:50:24 +03:00
|
|
|
uint64_t offset, size_t expected_written) {
|
2019-08-13 02:07:10 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
|
2017-03-16 18:09:27 +03:00
|
|
|
size_t written = 0;
|
2017-04-15 22:44:48 +03:00
|
|
|
for (int i = 0; i < iovcnt; ++i) {
|
2017-03-16 18:09:27 +03:00
|
|
|
int rc = mdbx_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
|
2017-05-24 01:42:10 +03:00
|
|
|
if (unlikely(rc != MDBX_SUCCESS))
|
2017-03-16 18:09:27 +03:00
|
|
|
return rc;
|
|
|
|
written += iov[i].iov_len;
|
|
|
|
offset += iov[i].iov_len;
|
|
|
|
}
|
2017-05-24 01:42:10 +03:00
|
|
|
return (expected_written == written) ? MDBX_SUCCESS
|
2017-05-22 19:59:16 +03:00
|
|
|
: MDBX_EIO /* ERROR_WRITE_FAULT */;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
|
|
|
int rc;
|
2017-07-26 18:32:46 +03:00
|
|
|
intptr_t written;
|
2017-03-16 18:09:27 +03:00
|
|
|
do {
|
2017-05-26 17:11:48 +03:00
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
2017-03-16 18:09:27 +03:00
|
|
|
written = pwritev(fd, iov, iovcnt, offset);
|
|
|
|
if (likely(expected_written == (size_t)written))
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
rc = errno;
|
|
|
|
} while (rc == EINTR);
|
2017-05-22 19:59:16 +03:00
|
|
|
return (written < 0) ? rc : MDBX_EIO /* Use which error code? */;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_filesync(mdbx_filehandle_t fd,
|
|
|
|
enum mdbx_syncmode_bits mode_bits) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2019-08-20 00:17:28 +03:00
|
|
|
return ((mode_bits & (MDBX_SYNC_DATA | MDBX_SYNC_IODQ)) == 0 ||
|
|
|
|
FlushFileBuffers(fd))
|
|
|
|
? MDBX_SUCCESS
|
|
|
|
: GetLastError();
|
2019-03-04 13:34:38 +03:00
|
|
|
#else
|
2019-08-20 00:17:28 +03:00
|
|
|
|
2019-08-20 02:45:03 +03:00
|
|
|
#if defined(__APPLE__) && \
|
2019-08-20 15:04:32 +03:00
|
|
|
MDBX_OSX_SPEED_INSTEADOF_DURABILITY == MDBX_OSX_WANNA_DURABILITY
|
2019-08-20 00:17:28 +03:00
|
|
|
if (mode_bits & MDBX_SYNC_IODQ)
|
|
|
|
return likely(fcntl(fd, F_FULLFSYNC) != -1) ? MDBX_SUCCESS : errno;
|
|
|
|
#endif /* MacOS */
|
|
|
|
#if defined(__linux__) || defined(__gnu_linux__)
|
2019-08-23 21:38:33 +03:00
|
|
|
if (mode_bits == MDBX_SYNC_SIZE && mdbx_linux_kernel_version >= 0x03060000)
|
2019-08-20 00:17:28 +03:00
|
|
|
return MDBX_SUCCESS;
|
|
|
|
#endif /* Linux */
|
2019-03-04 13:53:05 +03:00
|
|
|
int rc;
|
|
|
|
do {
|
2019-03-04 13:39:33 +03:00
|
|
|
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
|
2019-03-04 13:53:05 +03:00
|
|
|
/* LY: This code is always safe and without appreciable performance
|
|
|
|
* degradation, even on a kernel with fdatasync's bug.
|
|
|
|
*
|
|
|
|
* For more info about of a corresponding fdatasync() bug
|
|
|
|
* see http://www.spinics.net/lists/linux-ext4/msg33714.html */
|
2019-08-20 00:17:28 +03:00
|
|
|
if ((mode_bits & MDBX_SYNC_SIZE) == 0) {
|
2019-03-04 13:53:05 +03:00
|
|
|
if (fdatasync(fd) == 0)
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
} else
|
2017-04-24 19:37:01 +03:00
|
|
|
#else
|
2019-08-20 00:17:28 +03:00
|
|
|
(void)mode_bits;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2019-03-04 13:53:05 +03:00
|
|
|
if (fsync(fd) == 0)
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2019-03-04 13:53:05 +03:00
|
|
|
rc = errno;
|
|
|
|
} while (rc == EINTR);
|
|
|
|
return rc;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-05-24 18:50:24 +03:00
|
|
|
int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
BY_HANDLE_FILE_INFORMATION info;
|
|
|
|
if (!GetFileInformationByHandle(fd, &info))
|
2017-06-21 01:41:25 +03:00
|
|
|
return GetLastError();
|
2017-05-25 09:26:03 +03:00
|
|
|
*length = info.nFileSizeLow | (uint64_t)info.nFileSizeHigh << 32;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
|
|
|
struct stat st;
|
|
|
|
|
2017-05-26 17:11:48 +03:00
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) <= sizeof(uint64_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
2017-03-16 18:09:27 +03:00
|
|
|
if (fstat(fd, &st))
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
*length = st.st_size;
|
|
|
|
#endif
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-09-16 14:16:14 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd) {
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
switch (GetFileType(fd)) {
|
|
|
|
case FILE_TYPE_DISK:
|
|
|
|
return MDBX_RESULT_FALSE;
|
|
|
|
case FILE_TYPE_CHAR:
|
|
|
|
case FILE_TYPE_PIPE:
|
|
|
|
return MDBX_RESULT_TRUE;
|
|
|
|
default:
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
struct stat info;
|
|
|
|
if (fstat(fd, &info))
|
|
|
|
return errno;
|
|
|
|
switch (info.st_mode & S_IFMT) {
|
|
|
|
case S_IFBLK:
|
|
|
|
case S_IFREG:
|
|
|
|
return MDBX_RESULT_FALSE;
|
|
|
|
case S_IFCHR:
|
|
|
|
case S_IFIFO:
|
|
|
|
case S_IFSOCK:
|
|
|
|
return MDBX_RESULT_TRUE;
|
|
|
|
case S_IFDIR:
|
|
|
|
case S_IFLNK:
|
|
|
|
default:
|
|
|
|
return MDBX_INCOMPATIBLE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2018-12-26 19:53:03 +03:00
|
|
|
if (mdbx_SetFileInformationByHandle) {
|
|
|
|
FILE_END_OF_FILE_INFO EndOfFileInfo;
|
|
|
|
EndOfFileInfo.EndOfFile.QuadPart = length;
|
|
|
|
return mdbx_SetFileInformationByHandle(fd, FileEndOfFileInfo,
|
|
|
|
&EndOfFileInfo,
|
|
|
|
sizeof(FILE_END_OF_FILE_INFO))
|
|
|
|
? MDBX_SUCCESS
|
|
|
|
: GetLastError();
|
|
|
|
} else {
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = length;
|
|
|
|
return (SetFilePointerEx(fd, li, NULL, FILE_BEGIN) && SetEndOfFile(fd))
|
|
|
|
? MDBX_SUCCESS
|
|
|
|
: GetLastError();
|
|
|
|
}
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-05-26 17:11:48 +03:00
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
2017-05-24 01:42:10 +03:00
|
|
|
return ftruncate(fd, length) == 0 ? MDBX_SUCCESS : errno;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos) {
|
2018-11-04 18:57:08 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = pos;
|
|
|
|
return SetFilePointerEx(fd, li, NULL, FILE_BEGIN) ? MDBX_SUCCESS
|
|
|
|
: GetLastError();
|
|
|
|
#else
|
|
|
|
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
|
|
|
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
|
|
|
return (lseek(fd, pos, SEEK_SET) < 0) ? errno : MDBX_SUCCESS;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:09:27 +03:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int
|
|
|
|
mdbx_thread_create(mdbx_thread_t *thread,
|
|
|
|
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
|
|
|
|
void *arg) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
*thread = CreateThread(NULL, 0, start_routine, arg, 0, NULL);
|
2017-06-21 01:41:25 +03:00
|
|
|
return *thread ? MDBX_SUCCESS : GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
|
|
|
return pthread_create(thread, NULL, start_routine, arg);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
DWORD code = WaitForSingleObject(thread, INFINITE);
|
2017-03-30 18:54:57 +03:00
|
|
|
return waitstatus2errcode(code);
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
|
|
|
void *unused_retval = &unused_retval;
|
|
|
|
return pthread_join(thread, &unused_retval);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
|
|
|
|
size_t length, int async) {
|
2017-07-11 14:10:24 +03:00
|
|
|
uint8_t *ptr = (uint8_t *)map->address + offset;
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-07-11 14:10:24 +03:00
|
|
|
if (FlushViewOfFile(ptr, length) && (async || FlushFileBuffers(map->fd)))
|
2017-05-24 01:42:10 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-07-11 14:10:24 +03:00
|
|
|
return GetLastError();
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2019-10-11 23:33:03 +03:00
|
|
|
#if defined(__linux__) || defined(__gnu_linux__)
|
2019-08-23 21:38:33 +03:00
|
|
|
if (async && mdbx_linux_kernel_version > 0x02061300)
|
2019-08-19 21:31:05 +03:00
|
|
|
/* Since Linux 2.6.19, MS_ASYNC is in fact a no-op,
|
|
|
|
since the kernel properly tracks dirty pages and flushes them to storage
|
|
|
|
as necessary. */
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
#endif /* Linux */
|
2017-05-26 15:39:58 +03:00
|
|
|
const int mode = async ? MS_ASYNC : MS_SYNC;
|
2019-08-20 02:45:03 +03:00
|
|
|
int rc = (msync(ptr, length, mode) == 0) ? MDBX_SUCCESS : errno;
|
|
|
|
#if defined(__APPLE__) && \
|
2019-08-20 15:04:32 +03:00
|
|
|
MDBX_OSX_SPEED_INSTEADOF_DURABILITY == MDBX_OSX_WANNA_DURABILITY
|
2019-08-20 02:45:03 +03:00
|
|
|
if (rc == MDBX_SUCCESS && mode == MS_SYNC)
|
|
|
|
rc = likely(fcntl(map->fd, F_FULLFSYNC) != -1) ? MDBX_SUCCESS : errno;
|
|
|
|
#endif /* MacOS */
|
|
|
|
return rc;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_check4nonlocal(mdbx_filehandle_t handle,
|
|
|
|
int flags) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2018-06-12 22:52:57 +03:00
|
|
|
if (GetFileType(handle) != FILE_TYPE_DISK)
|
2017-07-11 19:05:40 +03:00
|
|
|
return ERROR_FILE_OFFLINE;
|
|
|
|
|
2018-06-12 22:56:26 +03:00
|
|
|
if (mdbx_GetFileInformationByHandleEx) {
|
|
|
|
FILE_REMOTE_PROTOCOL_INFO RemoteProtocolInfo;
|
|
|
|
if (mdbx_GetFileInformationByHandleEx(handle, FileRemoteProtocolInfo,
|
|
|
|
&RemoteProtocolInfo,
|
|
|
|
sizeof(RemoteProtocolInfo))) {
|
2018-06-13 21:33:49 +03:00
|
|
|
|
|
|
|
if ((RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_OFFLINE) &&
|
|
|
|
!(flags & MDBX_RDONLY))
|
2018-06-12 22:56:26 +03:00
|
|
|
return ERROR_FILE_OFFLINE;
|
2018-06-13 21:33:49 +03:00
|
|
|
if (!(RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK) &&
|
|
|
|
!(flags & MDBX_EXCLUSIVE))
|
|
|
|
return ERROR_REMOTE_STORAGE_MEDIA_ERROR;
|
2018-06-12 22:56:26 +03:00
|
|
|
}
|
2017-07-11 19:05:40 +03:00
|
|
|
}
|
|
|
|
|
2018-06-12 22:56:26 +03:00
|
|
|
if (mdbx_NtFsControlFile) {
|
|
|
|
NTSTATUS rc;
|
|
|
|
struct {
|
|
|
|
WOF_EXTERNAL_INFO wof_info;
|
|
|
|
union {
|
|
|
|
WIM_PROVIDER_EXTERNAL_INFO wim_info;
|
|
|
|
FILE_PROVIDER_EXTERNAL_INFO_V1 file_info;
|
|
|
|
};
|
|
|
|
size_t reserved_for_microsoft_madness[42];
|
|
|
|
} GetExternalBacking_OutputBuffer;
|
|
|
|
IO_STATUS_BLOCK StatusBlock;
|
|
|
|
rc = mdbx_NtFsControlFile(handle, NULL, NULL, NULL, &StatusBlock,
|
|
|
|
FSCTL_GET_EXTERNAL_BACKING, NULL, 0,
|
|
|
|
&GetExternalBacking_OutputBuffer,
|
|
|
|
sizeof(GetExternalBacking_OutputBuffer));
|
2018-06-13 21:33:49 +03:00
|
|
|
if (NT_SUCCESS(rc)) {
|
|
|
|
if (!(flags & MDBX_EXCLUSIVE))
|
|
|
|
return ERROR_REMOTE_STORAGE_MEDIA_ERROR;
|
|
|
|
} else if (rc != STATUS_OBJECT_NOT_EXTERNALLY_BACKED &&
|
|
|
|
rc != STATUS_INVALID_DEVICE_REQUEST)
|
|
|
|
return ntstatus2errcode(rc);
|
2017-07-11 19:05:40 +03:00
|
|
|
}
|
|
|
|
|
2018-06-12 22:56:26 +03:00
|
|
|
if (mdbx_GetVolumeInformationByHandleW && mdbx_GetFinalPathNameByHandleW) {
|
2018-10-13 19:07:45 +03:00
|
|
|
WCHAR *PathBuffer = mdbx_malloc(sizeof(WCHAR) * INT16_MAX);
|
|
|
|
if (!PathBuffer)
|
|
|
|
return MDBX_ENOMEM;
|
|
|
|
|
|
|
|
int rc = MDBX_SUCCESS;
|
2018-06-12 22:56:26 +03:00
|
|
|
DWORD VolumeSerialNumber, FileSystemFlags;
|
|
|
|
if (!mdbx_GetVolumeInformationByHandleW(handle, PathBuffer, INT16_MAX,
|
|
|
|
&VolumeSerialNumber, NULL,
|
2018-10-13 19:07:45 +03:00
|
|
|
&FileSystemFlags, NULL, 0)) {
|
|
|
|
rc = GetLastError();
|
|
|
|
goto bailout;
|
|
|
|
}
|
2017-07-11 19:05:40 +03:00
|
|
|
|
2018-06-12 22:56:26 +03:00
|
|
|
if ((flags & MDBX_RDONLY) == 0) {
|
2018-10-13 19:07:45 +03:00
|
|
|
if (FileSystemFlags &
|
|
|
|
(FILE_SEQUENTIAL_WRITE_ONCE | FILE_READ_ONLY_VOLUME |
|
|
|
|
FILE_VOLUME_IS_COMPRESSED)) {
|
|
|
|
rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
|
|
|
|
goto bailout;
|
|
|
|
}
|
2017-07-11 19:05:40 +03:00
|
|
|
}
|
2018-06-12 22:56:26 +03:00
|
|
|
|
|
|
|
if (!mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX,
|
2018-10-13 19:07:45 +03:00
|
|
|
FILE_NAME_NORMALIZED |
|
|
|
|
VOLUME_NAME_NT)) {
|
|
|
|
rc = GetLastError();
|
|
|
|
goto bailout;
|
|
|
|
}
|
2018-06-12 22:56:26 +03:00
|
|
|
|
2018-06-13 21:33:49 +03:00
|
|
|
if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) {
|
2018-10-13 19:07:45 +03:00
|
|
|
if (!(flags & MDBX_EXCLUSIVE)) {
|
|
|
|
rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
|
|
|
|
goto bailout;
|
|
|
|
}
|
2018-06-13 21:33:49 +03:00
|
|
|
} else if (mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX,
|
|
|
|
FILE_NAME_NORMALIZED |
|
|
|
|
VOLUME_NAME_DOS)) {
|
2018-06-12 22:56:26 +03:00
|
|
|
UINT DriveType = GetDriveTypeW(PathBuffer);
|
|
|
|
if (DriveType == DRIVE_NO_ROOT_DIR &&
|
2018-10-14 11:25:26 +03:00
|
|
|
_wcsnicmp(PathBuffer, L"\\\\?\\", 4) == 0 &&
|
|
|
|
_wcsnicmp(PathBuffer + 5, L":\\", 2) == 0) {
|
2018-06-12 22:56:26 +03:00
|
|
|
PathBuffer[7] = 0;
|
|
|
|
DriveType = GetDriveTypeW(PathBuffer + 4);
|
|
|
|
}
|
|
|
|
switch (DriveType) {
|
|
|
|
case DRIVE_CDROM:
|
|
|
|
if (flags & MDBX_RDONLY)
|
|
|
|
break;
|
|
|
|
// fall through
|
|
|
|
case DRIVE_UNKNOWN:
|
|
|
|
case DRIVE_NO_ROOT_DIR:
|
|
|
|
case DRIVE_REMOTE:
|
|
|
|
default:
|
2018-06-13 21:33:49 +03:00
|
|
|
if (!(flags & MDBX_EXCLUSIVE))
|
2018-10-13 19:07:45 +03:00
|
|
|
rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
|
2018-06-13 21:33:49 +03:00
|
|
|
// fall through
|
2018-06-12 22:56:26 +03:00
|
|
|
case DRIVE_REMOVABLE:
|
|
|
|
case DRIVE_FIXED:
|
|
|
|
case DRIVE_RAMDISK:
|
|
|
|
break;
|
|
|
|
}
|
2017-07-11 19:05:40 +03:00
|
|
|
}
|
2018-10-13 19:07:45 +03:00
|
|
|
bailout:
|
|
|
|
mdbx_free(PathBuffer);
|
|
|
|
return rc;
|
2017-07-11 19:05:40 +03:00
|
|
|
}
|
2018-06-12 22:52:57 +03:00
|
|
|
#else
|
|
|
|
(void)handle;
|
|
|
|
/* TODO: check for NFS handle ? */
|
|
|
|
(void)flags;
|
|
|
|
#endif
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_mmap(int flags, mdbx_mmap_t *map, size_t size,
|
|
|
|
size_t limit) {
|
2018-06-12 22:52:57 +03:00
|
|
|
assert(size <= limit);
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
map->length = 0;
|
|
|
|
map->current = 0;
|
|
|
|
map->section = NULL;
|
|
|
|
map->address = nullptr;
|
|
|
|
|
2018-06-13 21:33:49 +03:00
|
|
|
NTSTATUS rc = mdbx_check4nonlocal(map->fd, flags);
|
2018-06-12 22:52:57 +03:00
|
|
|
if (rc != MDBX_SUCCESS)
|
|
|
|
return rc;
|
2017-07-11 19:05:40 +03:00
|
|
|
|
2018-01-07 14:37:38 +03:00
|
|
|
rc = mdbx_filesize(map->fd, &map->filesize);
|
|
|
|
if (rc != MDBX_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) {
|
|
|
|
rc = mdbx_ftruncate(map->fd, size);
|
|
|
|
if (rc == MDBX_SUCCESS)
|
|
|
|
map->filesize = size;
|
|
|
|
/* ignore error, because Windows unable shrink file
|
2018-01-14 21:02:08 +03:00
|
|
|
* that already mapped (by another process) */
|
2018-01-07 14:26:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
LARGE_INTEGER SectionSize;
|
2018-01-07 14:37:38 +03:00
|
|
|
SectionSize.QuadPart = size;
|
2017-07-11 19:05:40 +03:00
|
|
|
rc = NtCreateSection(
|
2017-06-21 01:34:56 +03:00
|
|
|
&map->section,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* DesiredAccess */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_WRITEMAP)
|
2017-12-25 18:31:59 +03:00
|
|
|
? SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE |
|
|
|
|
SECTION_MAP_WRITE
|
|
|
|
: SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE,
|
2018-01-07 14:26:20 +03:00
|
|
|
/* ObjectAttributes */ NULL, /* MaximumSize (InitialSize) */ &SectionSize,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* SectionPageProtection */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_RDONLY) ? PAGE_READONLY : PAGE_READWRITE,
|
2017-06-21 01:34:56 +03:00
|
|
|
/* AllocationAttributes */ SEC_RESERVE, map->fd);
|
2017-07-11 19:05:40 +03:00
|
|
|
if (!NT_SUCCESS(rc))
|
2017-06-21 01:34:56 +03:00
|
|
|
return ntstatus2errcode(rc);
|
|
|
|
|
2018-01-07 17:06:11 +03:00
|
|
|
SIZE_T ViewSize = (flags & MDBX_RDONLY) ? 0 : limit;
|
2017-06-21 01:34:56 +03:00
|
|
|
rc = NtMapViewOfSection(
|
|
|
|
map->section, GetCurrentProcess(), &map->address,
|
|
|
|
/* ZeroBits */ 0,
|
2018-01-07 14:26:20 +03:00
|
|
|
/* CommitSize */ 0,
|
2017-06-21 01:34:56 +03:00
|
|
|
/* SectionOffset */ NULL, &ViewSize,
|
|
|
|
/* InheritDisposition */ ViewUnmap,
|
|
|
|
/* AllocationType */ (flags & MDBX_RDONLY) ? 0 : MEM_RESERVE,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* Win32Protect */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_WRITEMAP) ? PAGE_READWRITE : PAGE_READONLY);
|
2017-06-21 01:34:56 +03:00
|
|
|
if (!NT_SUCCESS(rc)) {
|
|
|
|
NtClose(map->section);
|
|
|
|
map->section = 0;
|
2017-07-26 12:16:47 +03:00
|
|
|
map->address = nullptr;
|
2017-06-21 01:34:56 +03:00
|
|
|
return ntstatus2errcode(rc);
|
|
|
|
}
|
|
|
|
assert(map->address != MAP_FAILED);
|
2017-07-28 13:48:10 +03:00
|
|
|
|
2018-01-07 14:26:20 +03:00
|
|
|
map->current = (size_t)SectionSize.QuadPart;
|
2017-07-12 21:13:17 +03:00
|
|
|
map->length = ViewSize;
|
2017-06-21 01:34:56 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2019-08-31 17:10:04 +03:00
|
|
|
int err = mdbx_check4nonlocal(map->fd, flags);
|
|
|
|
if (unlikely(err != MDBX_SUCCESS))
|
|
|
|
return err;
|
2018-01-07 14:37:38 +03:00
|
|
|
(void)size;
|
2017-06-21 01:34:56 +03:00
|
|
|
map->address = mmap(
|
|
|
|
NULL, limit, (flags & MDBX_WRITEMAP) ? PROT_READ | PROT_WRITE : PROT_READ,
|
|
|
|
MAP_SHARED, map->fd, 0);
|
2017-07-12 21:13:17 +03:00
|
|
|
if (likely(map->address != MAP_FAILED)) {
|
|
|
|
map->length = limit;
|
|
|
|
return MDBX_SUCCESS;
|
|
|
|
}
|
|
|
|
map->length = 0;
|
2017-07-26 12:16:47 +03:00
|
|
|
map->address = nullptr;
|
2017-07-12 21:13:17 +03:00
|
|
|
return errno;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) {
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2017-06-21 01:34:56 +03:00
|
|
|
if (map->section)
|
|
|
|
NtClose(map->section);
|
|
|
|
NTSTATUS rc = NtUnmapViewOfSection(GetCurrentProcess(), map->address);
|
2017-07-12 21:13:17 +03:00
|
|
|
if (!NT_SUCCESS(rc))
|
|
|
|
ntstatus2errcode(rc);
|
2018-01-14 21:02:08 +03:00
|
|
|
|
2017-07-12 21:13:17 +03:00
|
|
|
map->length = 0;
|
|
|
|
map->current = 0;
|
|
|
|
map->address = nullptr;
|
2017-03-16 18:09:27 +03:00
|
|
|
#else
|
2017-07-12 21:13:17 +03:00
|
|
|
if (unlikely(munmap(map->address, map->length)))
|
|
|
|
return errno;
|
|
|
|
map->length = 0;
|
|
|
|
map->address = nullptr;
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
2017-07-12 21:13:17 +03:00
|
|
|
return MDBX_SUCCESS;
|
2017-03-16 18:09:27 +03:00
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size,
|
|
|
|
size_t limit) {
|
2018-01-07 14:37:38 +03:00
|
|
|
assert(size <= limit);
|
2017-03-16 18:09:27 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2018-01-09 21:18:33 +03:00
|
|
|
assert(size != map->current || limit != map->length || size < map->filesize);
|
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
NTSTATUS status;
|
|
|
|
LARGE_INTEGER SectionSize;
|
|
|
|
int err, rc = MDBX_SUCCESS;
|
|
|
|
|
2018-01-07 14:37:38 +03:00
|
|
|
if (!(flags & MDBX_RDONLY) && limit == map->length && size > map->current) {
|
|
|
|
/* growth rw-section */
|
2018-01-09 15:30:36 +03:00
|
|
|
SectionSize.QuadPart = size;
|
|
|
|
status = NtExtendSection(map->section, &SectionSize);
|
2018-06-15 02:54:41 +03:00
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
map->current = size;
|
|
|
|
if (map->filesize < size)
|
|
|
|
map->filesize = size;
|
|
|
|
}
|
2018-01-09 15:30:36 +03:00
|
|
|
return ntstatus2errcode(status);
|
2017-06-21 01:34:56 +03:00
|
|
|
}
|
2018-01-07 14:37:38 +03:00
|
|
|
|
2018-01-14 18:36:25 +03:00
|
|
|
if (limit > map->length) {
|
|
|
|
/* check ability of address space for growth before umnap */
|
|
|
|
PVOID BaseAddress = (PBYTE)map->address + map->length;
|
|
|
|
SIZE_T RegionSize = limit - map->length;
|
|
|
|
status = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0,
|
|
|
|
&RegionSize, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
return ntstatus2errcode(status);
|
|
|
|
|
|
|
|
status = NtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize,
|
|
|
|
MEM_RELEASE);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
return ntstatus2errcode(status);
|
|
|
|
}
|
|
|
|
|
2018-01-07 14:37:38 +03:00
|
|
|
/* Windows unable:
|
2018-06-18 21:29:12 +03:00
|
|
|
* - shrink a mapped file;
|
|
|
|
* - change size of mapped view;
|
|
|
|
* - extend read-only mapping;
|
|
|
|
* Therefore we should unmap/map entire section. */
|
2018-01-09 15:30:36 +03:00
|
|
|
status = NtUnmapViewOfSection(GetCurrentProcess(), map->address);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
return ntstatus2errcode(status);
|
|
|
|
status = NtClose(map->section);
|
2018-01-07 14:37:38 +03:00
|
|
|
map->section = NULL;
|
2018-01-14 19:48:07 +03:00
|
|
|
PVOID ReservedAddress = NULL;
|
|
|
|
SIZE_T ReservedSize = limit;
|
2018-01-07 14:37:38 +03:00
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
bailout_ntstatus:
|
|
|
|
err = ntstatus2errcode(status);
|
|
|
|
bailout:
|
|
|
|
map->address = NULL;
|
|
|
|
map->current = map->length = 0;
|
2018-01-14 19:48:07 +03:00
|
|
|
if (ReservedAddress)
|
|
|
|
(void)NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress,
|
|
|
|
&ReservedSize, MEM_RELEASE);
|
2018-01-09 15:30:36 +03:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-01-14 19:48:07 +03:00
|
|
|
/* resizing of the file may take a while,
|
|
|
|
* therefore we reserve address space to avoid occupy it by other threads */
|
|
|
|
ReservedAddress = map->address;
|
|
|
|
status = NtAllocateVirtualMemory(GetCurrentProcess(), &ReservedAddress, 0,
|
|
|
|
&ReservedSize, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ReservedAddress = NULL;
|
2018-10-20 17:17:31 +03:00
|
|
|
if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
|
2018-01-14 19:48:07 +03:00
|
|
|
goto bailout_ntstatus /* no way to recovery */;
|
|
|
|
|
2018-10-20 17:17:31 +03:00
|
|
|
/* assume we can change base address if mapping size changed or prev address
|
|
|
|
* couldn't be used */
|
2018-01-14 19:48:07 +03:00
|
|
|
map->address = NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
retry_file_and_section:
|
|
|
|
err = mdbx_filesize(map->fd, &map->filesize);
|
|
|
|
if (err != MDBX_SUCCESS)
|
|
|
|
goto bailout;
|
|
|
|
|
2018-01-07 14:37:38 +03:00
|
|
|
if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) {
|
2018-01-09 15:30:36 +03:00
|
|
|
err = mdbx_ftruncate(map->fd, size);
|
|
|
|
if (err == MDBX_SUCCESS)
|
2018-01-07 14:37:38 +03:00
|
|
|
map->filesize = size;
|
|
|
|
/* ignore error, because Windows unable shrink file
|
2018-01-14 21:02:08 +03:00
|
|
|
* that already mapped (by another process) */
|
2017-07-12 21:13:17 +03:00
|
|
|
}
|
2018-01-07 14:37:38 +03:00
|
|
|
|
|
|
|
SectionSize.QuadPart = size;
|
2018-01-09 15:30:36 +03:00
|
|
|
status = NtCreateSection(
|
2018-01-07 14:37:38 +03:00
|
|
|
&map->section,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* DesiredAccess */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_WRITEMAP)
|
2018-01-07 14:37:38 +03:00
|
|
|
? SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE |
|
|
|
|
SECTION_MAP_WRITE
|
|
|
|
: SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE,
|
|
|
|
/* ObjectAttributes */ NULL,
|
|
|
|
/* MaximumSize (InitialSize) */ &SectionSize,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* SectionPageProtection */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_RDONLY) ? PAGE_READONLY : PAGE_READWRITE,
|
2018-01-07 14:37:38 +03:00
|
|
|
/* AllocationAttributes */ SEC_RESERVE, map->fd);
|
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
goto bailout_ntstatus;
|
2018-01-07 14:37:38 +03:00
|
|
|
|
2018-01-14 19:48:07 +03:00
|
|
|
if (ReservedAddress) {
|
|
|
|
/* release reserved address space */
|
|
|
|
status = NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress,
|
|
|
|
&ReservedSize, MEM_RELEASE);
|
|
|
|
ReservedAddress = NULL;
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
goto bailout_ntstatus;
|
|
|
|
}
|
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
retry_mapview:;
|
2018-01-07 14:37:38 +03:00
|
|
|
SIZE_T ViewSize = (flags & MDBX_RDONLY) ? size : limit;
|
2018-01-09 15:30:36 +03:00
|
|
|
status = NtMapViewOfSection(
|
2018-01-07 14:37:38 +03:00
|
|
|
map->section, GetCurrentProcess(), &map->address,
|
|
|
|
/* ZeroBits */ 0,
|
|
|
|
/* CommitSize */ 0,
|
|
|
|
/* SectionOffset */ NULL, &ViewSize,
|
|
|
|
/* InheritDisposition */ ViewUnmap,
|
|
|
|
/* AllocationType */ (flags & MDBX_RDONLY) ? 0 : MEM_RESERVE,
|
2018-06-18 21:29:12 +03:00
|
|
|
/* Win32Protect */
|
2018-06-20 13:44:23 +03:00
|
|
|
(flags & MDBX_WRITEMAP) ? PAGE_READWRITE : PAGE_READONLY);
|
2018-01-07 14:37:38 +03:00
|
|
|
|
2018-01-09 15:30:36 +03:00
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (status == /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 &&
|
2018-10-20 17:17:31 +03:00
|
|
|
map->address) {
|
|
|
|
/* try remap at another base address */
|
2018-01-07 14:37:38 +03:00
|
|
|
map->address = NULL;
|
2018-01-09 15:30:36 +03:00
|
|
|
goto retry_mapview;
|
2018-01-07 14:37:38 +03:00
|
|
|
}
|
|
|
|
NtClose(map->section);
|
2018-01-09 15:30:36 +03:00
|
|
|
map->section = NULL;
|
|
|
|
|
|
|
|
if (map->address && (size != map->current || limit != map->length)) {
|
|
|
|
/* try remap with previously size and limit,
|
|
|
|
* but will return MDBX_RESULT_TRUE on success */
|
|
|
|
rc = MDBX_RESULT_TRUE;
|
|
|
|
size = map->current;
|
|
|
|
limit = map->length;
|
|
|
|
goto retry_file_and_section;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no way to recovery */
|
|
|
|
goto bailout_ntstatus;
|
2017-07-12 21:13:17 +03:00
|
|
|
}
|
2018-01-07 14:37:38 +03:00
|
|
|
assert(map->address != MAP_FAILED);
|
|
|
|
|
|
|
|
map->current = (size_t)SectionSize.QuadPart;
|
|
|
|
map->length = ViewSize;
|
2018-01-09 15:30:36 +03:00
|
|
|
return rc;
|
2017-06-21 01:34:56 +03:00
|
|
|
#else
|
2017-07-12 21:13:17 +03:00
|
|
|
if (limit != map->length) {
|
2019-10-06 14:59:53 +03:00
|
|
|
#if defined(_GNU_SOURCE) && (defined(__linux__) || defined(__gnu_linux__))
|
2019-07-14 00:39:17 +03:00
|
|
|
void *ptr = mremap(map->address, map->length, limit,
|
|
|
|
/* LY: in case changing the mapping size calling code
|
|
|
|
must guarantees the absence of competing threads, and
|
|
|
|
a willingness to another base address */
|
|
|
|
MREMAP_MAYMOVE);
|
|
|
|
if (ptr == MAP_FAILED) {
|
|
|
|
int err = errno;
|
|
|
|
return (err == EAGAIN || err == ENOMEM) ? MDBX_RESULT_TRUE : err;
|
|
|
|
}
|
2017-07-12 21:13:17 +03:00
|
|
|
map->address = ptr;
|
|
|
|
map->length = limit;
|
2019-07-14 00:39:17 +03:00
|
|
|
#else
|
|
|
|
return MDBX_RESULT_TRUE;
|
2019-10-06 14:59:53 +03:00
|
|
|
#endif /* _GNU_SOURCE && __linux__ */
|
2017-07-12 21:13:17 +03:00
|
|
|
}
|
2018-01-09 15:30:36 +03:00
|
|
|
return (flags & MDBX_RDONLY) ? MDBX_SUCCESS : mdbx_ftruncate(map->fd, size);
|
2017-03-16 18:09:27 +03:00
|
|
|
#endif
|
|
|
|
}
|
2017-04-27 15:18:33 +03:00
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC __cold void mdbx_osal_jitter(bool tiny) {
|
2017-04-27 15:18:33 +03:00
|
|
|
for (;;) {
|
|
|
|
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
|
|
|
|
defined(__x86_64__)
|
|
|
|
const unsigned salt = 277u * (unsigned)__rdtsc();
|
|
|
|
#else
|
|
|
|
const unsigned salt = rand();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const unsigned coin = salt % (tiny ? 29u : 43u);
|
|
|
|
if (coin < 43 / 3)
|
|
|
|
break;
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
SwitchToThread();
|
|
|
|
if (coin > 43 * 2 / 3)
|
|
|
|
Sleep(1);
|
|
|
|
#else
|
|
|
|
sched_yield();
|
|
|
|
if (coin > 43 * 2 / 3)
|
|
|
|
usleep(coin);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2019-08-23 13:13:20 +03:00
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
|
|
|
#include <mach/mach_time.h>
|
|
|
|
#elif defined(__linux__) || defined(__gnu_linux__)
|
2019-10-25 22:56:25 +03:00
|
|
|
static __cold clockid_t choice_monoclock(void) {
|
2019-08-23 13:13:20 +03:00
|
|
|
struct timespec probe;
|
|
|
|
#if defined(CLOCK_BOOTTIME)
|
|
|
|
if (clock_gettime(CLOCK_BOOTTIME, &probe) == 0)
|
|
|
|
return CLOCK_BOOTTIME;
|
|
|
|
#elif defined(CLOCK_MONOTONIC_RAW)
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC_RAW, &probe) == 0)
|
|
|
|
return CLOCK_MONOTONIC_RAW;
|
|
|
|
#elif defined(CLOCK_MONOTONIC_COARSE)
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &probe) == 0)
|
|
|
|
return CLOCK_MONOTONIC_COARSE;
|
|
|
|
#endif
|
|
|
|
return CLOCK_MONOTONIC;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-10-01 13:53:52 +03:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
static LARGE_INTEGER performance_frequency;
|
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
|
|
|
static uint64_t ratio_16dot16_to_monotine;
|
|
|
|
#endif
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC uint64_t
|
|
|
|
mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
|
2019-08-23 13:13:20 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
2019-10-01 13:53:52 +03:00
|
|
|
if (unlikely(performance_frequency.QuadPart == 0))
|
2019-08-23 13:13:20 +03:00
|
|
|
QueryPerformanceFrequency(&performance_frequency);
|
|
|
|
const uint64_t ratio = performance_frequency.QuadPart;
|
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
2019-10-01 13:53:52 +03:00
|
|
|
if (unlikely(ratio_16dot16_to_monotine == 0)) {
|
2019-08-23 13:13:20 +03:00
|
|
|
mach_timebase_info_data_t ti;
|
|
|
|
mach_timebase_info(&ti);
|
2019-10-01 13:53:52 +03:00
|
|
|
ratio_16dot16_to_monotine = UINT64_C(1000000000) * ti.denom / ti.numer;
|
2019-08-23 13:13:20 +03:00
|
|
|
}
|
2019-10-01 13:53:52 +03:00
|
|
|
const uint64_t ratio = ratio_16dot16_to_monotine;
|
2019-08-23 13:13:20 +03:00
|
|
|
#else
|
|
|
|
const uint64_t ratio = UINT64_C(1000000000);
|
|
|
|
#endif
|
|
|
|
return (ratio * seconds_16dot16 + 32768) >> 16;
|
|
|
|
}
|
|
|
|
|
2019-10-01 13:53:52 +03:00
|
|
|
MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime) {
|
|
|
|
static uint64_t limit;
|
|
|
|
if (unlikely(monotime > limit)) {
|
|
|
|
if (limit != 0)
|
|
|
|
return UINT32_MAX;
|
|
|
|
limit = mdbx_osal_16dot16_to_monotime(UINT32_MAX - 1);
|
|
|
|
if (monotime > limit)
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
return (uint32_t)((monotime << 16) / performance_frequency.QuadPart);
|
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
|
|
|
return (uint32_t)((monotime << 16) / ratio_16dot16_to_monotine);
|
|
|
|
#else
|
|
|
|
return (uint32_t)(monotime * 128 / 1953125);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-31 17:10:04 +03:00
|
|
|
MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void) {
|
2019-08-23 13:13:20 +03:00
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
LARGE_INTEGER counter;
|
|
|
|
counter.QuadPart = 0;
|
|
|
|
QueryPerformanceCounter(&counter);
|
|
|
|
return counter.QuadPart;
|
|
|
|
#elif defined(__APPLE__) || defined(__MACH__)
|
|
|
|
return mach_absolute_time();
|
|
|
|
#else
|
|
|
|
|
|
|
|
#if defined(__linux__) || defined(__gnu_linux__)
|
|
|
|
static clockid_t posix_clockid = -1;
|
|
|
|
if (unlikely(posix_clockid < 0))
|
2019-08-23 22:15:35 +03:00
|
|
|
posix_clockid = choice_monoclock();
|
2019-08-23 13:13:20 +03:00
|
|
|
#elif defined(CLOCK_MONOTONIC)
|
|
|
|
#define posix_clockid CLOCK_MONOTONIC
|
|
|
|
#else
|
|
|
|
#define posix_clockid CLOCK_REALTIME
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct timespec ts;
|
|
|
|
if (unlikely(clock_gettime(posix_clockid, &ts) != 0)) {
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
ts.tv_sec = 0;
|
|
|
|
}
|
|
|
|
return ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
|
|
|
|
#endif
|
|
|
|
}
|