Get latest changes from LPP bot

This commit is contained in:
2025-06-03 16:26:40 +10:00
parent 2371297dda
commit b1394e6416
29 changed files with 2644 additions and 290 deletions
+35 -19
View File
@@ -1,5 +1,10 @@
#define DN_OS_CPP
#if defined(DN_PLATFORM_POSIX)
#include <sys/sysinfo.h> // get_nprocs
#include <unistd.h> // getpagesize
#endif
static DN_OSCore *g_dn_os_core_;
static void DN_OS_LOGEmitFromTypeTypeFV_(DN_LOGTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args)
@@ -86,34 +91,46 @@ DN_API void DN_OS_Init(DN_OSCore *os, DN_OSInitArgs *args)
#if defined(DN_PLATFORM_WIN32)
SYSTEM_INFO system_info = {};
GetSystemInfo(&system_info);
os->page_size = system_info.dwPageSize;
os->alloc_granularity = system_info.dwAllocationGranularity;
QueryPerformanceFrequency(&os->win32_qpc_frequency);
HMODULE module = LoadLibraryA("kernel32.dll");
os->win32_set_thread_description = DN_CAST(DN_WinSetThreadDescriptionFunc *) GetProcAddress(module, "SetThreadDescription");
FreeLibrary(module);
os->logical_processor_count = system_info.dwNumberOfProcessors;
os->page_size = system_info.dwPageSize;
os->alloc_granularity = system_info.dwAllocationGranularity;
#else
// TODO(doyle): Get the proper page size from the OS.
os->page_size = DN_Kilobytes(4);
os->alloc_granularity = DN_Kilobytes(64);
os->logical_processor_count = get_nprocs();
os->page_size = getpagesize();
os->alloc_granularity = os->page_size;
#endif
}
// NOTE: Setup logging
DN_OS_EmitLogsWithOSPrintFunctions(os);
#if defined(DN_PLATFORM_WIN32)
// NOTE: win32 bcrypt
{
os->arena = DN_Arena_InitFromOSVMem(DN_Megabytes(1), DN_Kilobytes(4), DN_ArenaFlags_NoAllocTrack);
#if defined(DN_PLATFORM_WIN32)
os->platform_context = DN_Arena_New(&os->arena, DN_W32Core, DN_ZeroMem_Yes);
#elif defined(DN_PLATFORM_POSIX)
os->platform_context = DN_Arena_New(&os->arena, DN_POSIXCore, DN_ZeroMem_Yes);
#endif
#if defined(DN_PLATFORM_WIN32)
DN_W32Core *w32 = DN_CAST(DN_W32Core *) os->platform_context;
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
HMODULE module = LoadLibraryA("kernel32.dll");
w32->set_thread_description = DN_CAST(DN_W32SetThreadDescriptionFunc *) GetProcAddress(module, "SetThreadDescription");
FreeLibrary(module);
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&os->win32_bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (os->win32_bcrypt_rng_handle && init_status == 0)
os->win32_bcrypt_init_success = true;
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LOG_ErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
#endif
}
#endif
// NOTE: Initialise tmem arenas which allocate memory and will be
// recorded to the now initialised allocation table. The initialisation
@@ -135,7 +152,6 @@ DN_API void DN_OS_Init(DN_OSCore *os, DN_OSInitArgs *args)
#define DN_CPU_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CPUFeature_##label] = {DN_CPUFeature_##label, DN_STR8(#label)};
DN_CPU_FEAT_XMACRO
#undef DN_CPU_FEAT_XENTRY
DN_Assert(g_dn_os_core_);
}
@@ -702,13 +718,13 @@ static void DN_OS_ThreadExecute_(void *user_context)
DN_API void DN_OS_ThreadSetName(DN_Str8 name)
{
DN_OSTLS *tls = DN_OS_TLSGet();
DN_OSTLS *tls = DN_OS_TLSGet();
tls->name_size = DN_CAST(uint8_t) DN_Min(name.size, sizeof(tls->name) - 1);
DN_Memcpy(tls->name, name.data, tls->name_size);
tls->name[tls->name_size] = 0;
#if defined(DN_PLATFORM_WIN32)
DN_Win_ThreadSetName(name);
DN_W32_ThreadSetName(name);
#else
DN_Posix_ThreadSetName(name);
#endif
@@ -717,7 +733,7 @@ DN_API void DN_OS_ThreadSetName(DN_Str8 name)
// NOTE: DN_OSHttp /////////////////////////////////////////////////////////////////////////////////
DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response)
{
if (response && DN_OS_SemaphoreIsValid(&response->on_complete_semaphore))
if (response && response->on_complete_semaphore.handle != 0)
DN_OS_SemaphoreWait(&response->on_complete_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
}
+34 -50
View File
@@ -1,11 +1,13 @@
#if !defined(DN_OS_H)
#define DN_OS_H
#include <new> // operator new
#if defined(DN_PLATFORM_EMSCRIPTEN) || defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_ARM64)
#include "dn_os_posix.h"
#elif defined(DN_PLATFORM_WIN32)
#include "dn_os_windows.h"
#include "dn_os_win32.h"
#include "dn_os_w32.h"
#else
#error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs
#endif
@@ -38,10 +40,6 @@
#include <emscripten/fetch.h> // emscripten_fetch (for DN_OSHttpResponse)
#endif
#if defined(DN_PLATFORM_WIN32)
typedef HRESULT DN_WinSetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription);
#endif
// NOTE: DN_OSDate /////////////////////////////////////////////////////////////////////////////////
struct DN_OSDateTimeStr8
{
@@ -178,11 +176,11 @@ struct DN_OSExecAsyncHandle
struct DN_OSExecResult
{
bool finished;
DN_Str8 stdout_text;
DN_Str8 stderr_text;
DN_U32 os_error_code;
DN_U32 exit_code;
bool finished;
DN_Str8 stdout_text;
DN_Str8 stderr_text;
DN_U32 os_error_code;
DN_U32 exit_code;
};
struct DN_OSExecArgs
@@ -192,18 +190,12 @@ struct DN_OSExecArgs
DN_Slice<DN_Str8> environment;
};
#if !defined(DN_NO_SEMAPHORE)
// NOTE: DN_OSSemaphore ////////////////////////////////////////////////////////////////////////////
DN_U32 const DN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX;
struct DN_OSSemaphore
{
#if defined(DN_OS_WIN32) && !defined(DN_OS_WIN32_USE_PTHREADS)
void *win32_handle;
#else
sem_t posix_handle;
bool posix_init;
#endif
DN_U64 handle;
};
enum DN_OSSemaphoreWaitResult
@@ -212,35 +204,31 @@ enum DN_OSSemaphoreWaitResult
DN_OSSemaphoreWaitResult_Success,
DN_OSSemaphoreWaitResult_Timeout,
};
#endif // !defined(DN_NO_SEMAPHORE)
// NOTE: DN_OSMutex ////////////////////////////////////////////////////////////////////////////////
struct DN_OSMutex
{
#if defined(DN_OS_WIN32) && !defined(DN_OS_WIN32_USE_PTHREADS)
char win32_handle[48];
#else
pthread_mutex_t posix_handle;
pthread_mutexattr_t posix_attribs;
#endif
DN_U64 handle;
};
struct DN_OSConditionVariable
{
DN_U64 handle;
};
// NOTE: DN_OSThread ///////////////////////////////////////////////////////////////////////////////
#if !defined(DN_NO_THREAD) && !defined(DN_NO_SEMAPHORE)
typedef int32_t(DN_OSThreadFunc)(struct DN_OSThread *);
typedef DN_I32(DN_OSThreadFunc)(struct DN_OSThread *);
struct DN_OSThread
{
DN_FStr8<64> name;
DN_OSTLS tls;
DN_OSTLSInitArgs tls_init_args;
DN_OSTLS tls;
DN_OSTLSInitArgs tls_init_args;
void *handle;
DN_U64 thread_id;
void *user_context;
DN_OSThreadFunc *func;
DN_OSSemaphore init_semaphore;
};
#endif // !defined(DN_NO_THREAD)
// NOTE: DN_OSHttp /////////////////////////////////////////////////////////////////////////////////
enum DN_OSHttpRequestSecure
@@ -272,9 +260,9 @@ struct DN_OSHttpResponse
#if defined(DN_PLATFORM_EMSCRIPTEN)
emscripten_fetch_t *em_handle;
#elif defined(DN_PLATFORM_WIN32)
HINTERNET win32_request_session;
HINTERNET win32_request_connection;
HINTERNET win32_request_handle;
HINTERNET w32_request_session;
HINTERNET w32_request_connection;
HINTERNET w32_request_handle;
#endif
};
@@ -300,6 +288,7 @@ struct DN_OSCore
bool log_no_colour; // Disable colours in the logging output
// NOTE: OS //////////////////////////////////////////////////////////////////////////////////////
DN_U32 logical_processor_count;
DN_U32 page_size;
DN_U32 alloc_granularity;
@@ -312,14 +301,8 @@ struct DN_OSCore
DN_U64 mem_allocs_total;
DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked
// NOTE: Win32 /////////////////////////////////////////////////////////////////////////////////
#if defined(DN_PLATFORM_WIN32)
DN_WinSetThreadDescriptionFunc *win32_set_thread_description;
LARGE_INTEGER win32_qpc_frequency;
void * win32_bcrypt_rng_handle;
bool win32_bcrypt_init_success;
bool win32_sym_initialised;
#endif
DN_Arena arena;
void *platform_context;
};
struct DN_OSDiskSpace
@@ -349,6 +332,8 @@ DN_API DN_OSDateTime DN_OS_DateLocalTimeNow ();
DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8Now(char date_separator = '-', char hms_separator = ':');
DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8 (DN_OSDateTime time, char date_separator = '-', char hms_separator = ':');
DN_API DN_U64 DN_OS_DateUnixTimeNs ();
#define DN_OS_DateUnixTimeUs() (DN_OS_DateUnixTimeNs() / 1000)
#define DN_OS_DateUnixTimeMs() (DN_OS_DateUnixTimeNs() / 1000 * 1000)
DN_API DN_U64 DN_OS_DateUnixTimeS ();
DN_API DN_OSDateTime DN_OS_DateUnixTimeSToDate (DN_U64 time);
DN_API DN_U64 DN_OS_DateLocalToUnixTimeS(DN_OSDateTime date);
@@ -451,31 +436,30 @@ DN_API DN_OSExecResult DN_OS_Exec (DN_Slice<DN_Str8> c
DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Slice<DN_Str8> cmd_line, DN_OSExecArgs *args, DN_Arena *arena);
#define DN_OS_ExecOrAbortFromTLS(...) DN_OS_ExecOrAbort(__VA_ARGS__, DN_OS_TLSTopArena())
// NOTE: DN_OSSemaphore ////////////////////////////////////////////////////////////////////////////
#if !defined(DN_NO_SEMAPHORE)
DN_API DN_OSSemaphore DN_OS_SemaphoreInit (DN_U32 initial_count);
DN_API bool DN_OS_SemaphoreIsValid (DN_OSSemaphore *semaphore);
DN_API void DN_OS_SemaphoreDeinit (DN_OSSemaphore *semaphore);
DN_API void DN_OS_SemaphoreIncrement(DN_OSSemaphore *semaphore, DN_U32 amount);
DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait (DN_OSSemaphore *semaphore, DN_U32 timeout_ms);
#endif // !defined(DN_NO_SEMAPHORE)
// NOTE: DN_OSMutex ////////////////////////////////////////////////////////////////////////////////
DN_API DN_OSMutex DN_OS_MutexInit ();
DN_API void DN_OS_MutexDeinit(DN_OSMutex *mutex);
DN_API void DN_OS_MutexLock (DN_OSMutex *mutex);
DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex);
#define DN_OS_Mutex(mutex) DN_DEFER_LOOP(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex))
#define DN_OS_MutexScope(mutex) DN_DeferLoop(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex))
DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit ();
DN_API void DN_OS_ConditionVariableDeinit (DN_OSConditionVariable *cv);
DN_API bool DN_OS_ConditionVariableWait (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms);
DN_API bool DN_OS_ConditionVariableWaitUntil(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms);
DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv);
DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv);
// NOTE: DN_OSThread ///////////////////////////////////////////////////////////////////////////////
#if !defined(DN_NO_THREAD) && !defined(DN_NO_SEMAPHORE)
DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context);
DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread);
DN_API DN_U32 DN_OS_ThreadID ();
DN_API void DN_OS_ThreadSetName(DN_Str8 name);
#endif // !defined(DN_NO_THREAD)
// NOTE: DN_OSHttp /////////////////////////////////////////////////////////////////////////////////
DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers);
DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response);
DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response);
+186 -85
View File
@@ -4,11 +4,11 @@
#include <sys/statvfs.h>
// NOTE: DN_OSMem //////////////////////////////////////////////////////////////////////////////////
static uint32_t DN_OS_MemConvertPageToOSFlags_(uint32_t protect)
static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect)
{
DN_Assert((protect & ~DN_MemPage_All) == 0);
DN_Assert(protect != 0);
uint32_t result = 0;
DN_U32 result = 0;
if (protect & (DN_MemPage_NoAccess | DN_MemPage_Guard)) {
result = PROT_NONE;
@@ -21,7 +21,7 @@ static uint32_t DN_OS_MemConvertPageToOSFlags_(uint32_t protect)
return result;
}
DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, uint32_t page_flags)
DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, DN_U32 page_flags)
{
unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags);
@@ -36,7 +36,7 @@ DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, uint32_t page_
return result;
}
DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, uint32_t page_flags)
DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, DN_U32 page_flags)
{
bool result = false;
if (!ptr || size == 0)
@@ -60,7 +60,7 @@ DN_API void DN_OS_MemRelease(void *ptr, DN_USize size)
munmap(ptr, size);
}
DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, uint32_t page_flags)
DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, DN_U32 page_flags)
{
if (!ptr || size == 0)
return 0;
@@ -162,7 +162,7 @@ DN_API DN_OSDateTime DN_OS_DateUnixTimeSToDate(uint64_t time)
return result;
}
DN_API bool DN_OS_SecureRNGBytes(void *buffer, uint32_t size)
DN_API bool DN_OS_SecureRNGBytes(void *buffer, DN_U32 size)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
(void)buffer;
@@ -182,7 +182,7 @@ DN_API bool DN_OS_SecureRNGBytes(void *buffer, uint32_t size)
// TODO(doyle):
// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
// TODO(doyle): https://man7.org/linux/man-pages/man2/getrandom.2.html
uint32_t read_bytes = 0;
DN_U32 read_bytes = 0;
do {
read_bytes =
getrandom(buffer, size, 0); // NOTE: EINTR can not be triggered if size <= 32 bytes
@@ -211,7 +211,7 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path)
return result;
result.success = true;
result.free = info.f_bavail * info.f_frsize;
result.avail = info.f_bavail * info.f_frsize;
result.size = info.f_blocks * info.f_frsize;
return result;
}
@@ -275,7 +275,7 @@ DN_API void DN_OS_SleepMs(DN_UInt milliseconds)
{
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000; // Convert remaining milliseconds to nanoseconds
ts.tv_nsec = (milliseconds % 1000) * 1'000'000; // Convert remaining milliseconds to nanoseconds
// nanosleep can fail if interrupted by a signal, so we loop until the full sleep time has passed
while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
;
@@ -916,8 +916,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Slice<DN_Str8> cmd_line,
return result;
}
DN_ForIndexU(arg_index, cmd_line.size)
{
for (DN_ForIndexU(arg_index, cmd_line.size)) {
DN_Str8 arg = cmd_line.data[arg_index];
argv[arg_index] = DN_Str8_Copy(tmem.arena, arg).data; // NOTE: Copy string to guarantee it is null-terminated
}
@@ -990,7 +989,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle,
size_t *stdout_size,
char *stderr_buffer,
size_t *stderr_size,
uint32_t timeout_ms,
DN_U32 timeout_ms,
DN_OSErrSink *err)
{
DN_InvalidCodePath;
@@ -998,75 +997,111 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle,
return result;
}
#if !defined(DN_NO_SEMAPHORE)
// NOTE: DN_OSSemaphore ////////////////////////////////////////////////////////////////////////////
DN_API DN_OSSemaphore DN_OS_SemaphoreInit(uint32_t initial_count)
static DN_POSIXCore *DN_OS_GetPOSIXCore_()
{
DN_OSSemaphore result = {};
int pshared = 0; // Share the semaphore across all threads in the process
if (sem_init(&result.posix_handle, pshared, initial_count) == 0)
result.posix_init = true;
DN_Assert(g_dn_os_core_ && g_dn_os_core_->platform_context);
DN_POSIXCore *result = DN_CAST(DN_POSIXCore *)g_dn_os_core_->platform_context;
return result;
}
DN_API bool DN_OS_SemaphoreIsValid(DN_OSSemaphore *semaphore)
static DN_POSIXSyncPrimitive *DN_OS_U64ToPOSIXSyncPrimitive_(DN_U64 u64)
{
bool result = false;
if (semaphore)
result = semaphore->posix_init;
DN_POSIXSyncPrimitive *result = nullptr;
DN_Memcpy(&result, &u64, sizeof(u64));
return result;
}
static DN_U64 DN_POSIX_SyncPrimitiveToU64(DN_POSIXSyncPrimitive *primitive)
{
DN_U64 result = 0;
static_assert(sizeof(result) == sizeof(primitive), "Pointer size mis-match");
DN_Memcpy(&result, &primitive, sizeof(result));
return result;
}
static DN_POSIXSyncPrimitive *DN_POSIX_AllocSyncPrimitive_()
{
DN_POSIXCore *posix = DN_OS_GetPOSIXCore_();
DN_POSIXSyncPrimitive *result = nullptr;
pthread_mutex_lock(&posix->sync_primitive_free_list_mutex);
{
if (posix->sync_primitive_free_list) {
result = posix->sync_primitive_free_list;
posix->sync_primitive_free_list = posix->sync_primitive_free_list->next;
result->next = nullptr;
} else {
DN_OSCore *os = g_dn_os_core_;
result = DN_Arena_New(&os->arena, DN_POSIXSyncPrimitive, DN_ZeroMem_Yes);
}
}
pthread_mutex_unlock(&posix->sync_primitive_free_list_mutex);
return result;
}
static void DN_POSIX_DeallocSyncPrimitive_(DN_POSIXSyncPrimitive *primitive)
{
if (primitive) {
DN_POSIXCore *posix = DN_OS_GetPOSIXCore_();
pthread_mutex_lock(&posix->sync_primitive_free_list_mutex);
primitive->next = posix->sync_primitive_free_list;
posix->sync_primitive_free_list = primitive;
pthread_mutex_unlock(&posix->sync_primitive_free_list_mutex);
}
}
// NOTE: DN_OSSemaphore ////////////////////////////////////////////////////////////////////////////
DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count)
{
DN_POSIXCore *posix = g_dn_os_core->posix_context;
DN_Assert(posix);
DN_OSSemaphore result = {};
DN_POSIXSyncPrimitive *primitive = DN_POSIX_AllocSyncPrimitive_();
if (primitive) {
int pshared = 0; // Share the semaphore across all threads in the process
if (sem_init(&primitive->sem, pshared, initial_count) == 0)
result.handle = DN_POSIX_SyncPrimitiveToU64(primitive);
else
DN_POSIX_DeallocSyncPrimitive_(primitive);
}
return result;
}
DN_API void DN_OS_SemaphoreDeinit(DN_OSSemaphore *semaphore)
{
if (!DN_OS_SemaphoreIsValid(semaphore))
return;
// TODO(doyle): Error handling?
if (semaphore->posix_init)
sem_destroy(&semaphore->posix_handle);
*semaphore = {};
if (semaphore.handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
sem_destroy(&primitive->sem);
DN_POSIX_DeallocSyncPrimitive_(posix_sem);
*semaphore = {};
}
}
// NOTE: These functions don't need semaphore to be passed by pointer, **BUT**
// the POSIX implementation disallows copies of sem_t. In particular:
//
// Source: The Open Group Base Specifications Issue 7, 2018 edition
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09
//
// 2.9.9 Synchronization Object Copies and Alternative Mappings
//
// For barriers, condition variables, mutexes, and read-write locks, [TSH]
// [Option Start] if the process-shared attribute is set to
// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the
// address used to initialize it can be used for performing synchronization. The
// effect of referring to another mapping of the same object when locking,
// unlocking, or destroying the object is undefined. [...] The effect of
// referring to a copy of the object when locking, unlocking, or destroying it
// is undefined.
DN_API void DN_OS_SemaphoreIncrement(DN_OSSemaphore *semaphore, uint32_t amount)
DN_API void DN_OS_SemaphoreIncrement(DN_OSSemaphore *semaphore, DN_U32 amount)
{
if (!DN_OS_SemaphoreIsValid(semaphore))
return;
#if defined(DN_OS_WIN32)
sem_post_multiple(&semaphore->posix_handle, amount); // mingw extension
#else
DN_ForIndexU(index, amount)
sem_post(&semaphore->posix_handle);
#endif // !defined(DN_OS_WIN32)
if (semaphore.handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
#if defined(DN_OS_WIN32)
sem_post_multiple(&primitive->sem, amount); // mingw extension
#else
for (DN_ForIndexU(index, amount))
sem_post(&primitive->sem);
#endif // !defined(DN_OS_WIN32)
}
}
DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore,
uint32_t timeout_ms)
DN_U32 timeout_ms)
{
DN_OSSemaphoreWaitResult result = {};
if (!DN_OS_SemaphoreIsValid(semaphore))
if (semaphore.handle == 0)
return result;
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
if (timeout_ms == DN_OS_SEMAPHORE_INFINITE_TIMEOUT) {
int wait_result = 0;
do {
wait_result = sem_wait(&semaphore->posix_handle);
wait_result = sem_wait(&primitive->sem);
} while (wait_result == -1 && errno == EINTR);
if (wait_result == 0)
@@ -1075,47 +1110,115 @@ DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore,
struct timespec abs_timeout = {};
abs_timeout.tv_sec = timeout_ms / 1000;
abs_timeout.tv_nsec = (timeout_ms % 1000) * 1'000'000;
if (sem_timedwait(&semaphore->posix_handle, &abs_timeout) == 0)
if (sem_timedwait(&primitive->sem) == 0)
result = DN_OSSemaphoreWaitResult_Success;
else if (errno == ETIMEDOUT)
result = DN_OSSemaphoreWaitResult_Timeout;
}
return result;
}
#endif // !defined(DN_NO_SEMAPHORE)
#if !defined(DN_NO_THREAD)
// NOTE: DN_OSMutex ////////////////////////////////////////////////////////////////////////////////
DN_API DN_OSMutex DN_OS_MutexInit()
{
DN_OSMutex result = {};
if (pthread_mutexattr_init(&result.posix_attribs) != 0)
return result;
if (pthread_mutex_init(&result.posix_handle, &result.posix_attribs) != 0)
return result;
DN_W32SyncPrimitive *primitive = DN_W32_AllocSyncPrimitive_();
DN_OSMutex result = {};
if (primitive) {
int pshared = 0; // Share the semaphore across all threads in the process
if (pthread_mutex_init(mutex, pshared, nullptr) == 0)
result.handle = DN_POSIX_SyncPrimitiveToU64(primitive);
else
DN_POSIX_DeallocSyncPrimitive_(primitive);
}
return result;
}
DN_API void DN_OS_MutexDeinit(DN_OSMutex *mutex)
{
if (!mutex)
return;
pthread_mutexattr_destroy(&mutex->posix_attribs);
pthread_mutex_destroy(&mutex->posix_handle);
if (mutex && mutex->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
pthread_mutex_destroy(&primitive->mutex);
DN_POSIX_DeallocSyncPrimitive_(primitive);
*mutex = {};
}
}
DN_API void DN_OS_MutexLock(DN_OSMutex *mutex)
{
if (!mutex)
return;
pthread_mutex_lock(&mutex->posix_handle);
if (mutex && mutex->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
pthread_mutex_lock(&primitive->mutex);
}
}
DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex)
{
if (!mutex)
return;
pthread_mutex_unlock(&mutex->posix_handle);
if (mutex && mutex->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle);
pthread_mutex_unlock(&primitive->mutex);
}
}
DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit()
{
DN_POSIXSyncPrimitive *primitive = DN_POSIX_AllocSyncPrimitive_();
DN_OSConditionVariable result = {};
if (primitive) {
if (pthread_cond_init(&primitive->cv) == 0)
result.handle = DN_POSIX_SyncPrimitiveToU64(primitive);
else
DN_POSIX_DeallocSyncPrimitive_(primitive);
}
return result;
}
DN_API bool DN_OS_ConditionVariableDeinit(DN_OSConditionVariable *cv)
{
if (cv && cv->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle);
pthread_cond_destroy(&primitive->cv);
DN_POSIX_DeallocSyncPrimitive_(primitive);
*cv = {};
}
}
DN_API bool DN_OS_ConditionVariableWaitUntil(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms)
{
bool result = false;
if (cv && mutex && mutex->handle != 0 && cv->handle != 0) {
DN_POSIXSyncPrimitive *cv_primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle);
DN_POSIXSyncPrimitive *mutex_primitive = DN_OS_U64ToPOSIXSyncPrimitive_(mutex->handle);
struct timespec time;
time.tv_sec = end_ts_ms / 1'000;
time.tv_nsec = 1'000'000 * (end_ts_ms - (end_ts_ms / 1'000) * 1'000);
int wait_result = pthread_cond_timedwait(&cv_primitive->cv, &mutex_primitive->mutex, &time);
result = (wait_result != ETIMEDOUT);
}
return result;
}
DN_API bool DN_OS_ConditionVariableWait(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms)
{
DN_U64 end_ts_ms = DN_OS_DateUnixTimeMs() + sleep_ms;
bool result = DN_OS_ConditionVariableWaitUntil(cv, mutex, end_ts_ms);
return result;
}
DN_API void DN_OS_ConditionVariableSignal(DN_OSConditionVariable *cv)
{
if (cv && cv->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle);
pthread_cond_signal(&primitive->cv);
}
}
DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv)
{
if (cv && cv->handle != 0) {
DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle);
pthread_cond_broadcast(&primitive->cv);
}
}
// NOTE: DN_OSThread ///////////////////////////////////////////////////////////////////////////////
@@ -1181,11 +1284,11 @@ DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread)
thread->thread_id = {};
}
DN_API uint32_t DN_OS_ThreadID()
DN_API DN_U32 DN_OS_ThreadID()
{
pid_t result = gettid();
DN_Assert(gettid() >= 0);
return DN_CAST(uint32_t) result;
return DN_CAST(DN_U32) result;
}
DN_API void DN_Posix_ThreadSetName(DN_Str8 name)
@@ -1195,7 +1298,6 @@ DN_API void DN_Posix_ThreadSetName(DN_Str8 name)
pthread_t thread = pthread_self();
pthread_setname_np(thread, (char *)copy.data);
}
#endif // !defined(DN_NO_THREAD)
DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus()
{
@@ -1230,7 +1332,7 @@ DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus()
DN_Str8 status_buf = DN_Str8Builder_BuildFromTLS(&builder);
DN_Slice<DN_Str8> lines = DN_Str8_SplitAllocFromTLS(status_buf, DN_STR8("\n"), DN_Str8SplitIncludeEmptyStrings_No);
DN_ForIt(line_it, DN_Str8, &lines) {
for (DN_ForIt(line_it, DN_Str8, &lines)) {
DN_Str8 line = DN_Str8_TrimWhitespaceAround(*line_it.data);
if (DN_Str8_StartsWith(line, NAME, DN_Str8EqCase_Insensitive)) {
DN_Str8 str8 = DN_Str8_TrimWhitespaceAround(DN_Str8_Slice(line, NAME.size, line.size));
@@ -1312,7 +1414,7 @@ static void DN_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch)
if (!DN_Check(response))
return;
response->http_status = DN_CAST(uint32_t) fetch->status;
response->http_status = DN_CAST(DN_U32) fetch->status;
response->body = DN_Str8_Alloc(response->arena, fetch->numBytes, DN_ZeroMem_No);
if (response->body.data)
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
@@ -1327,7 +1429,7 @@ static void DN_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch)
if (!DN_Check(response))
return;
response->http_status = DN_CAST(uint32_t) fetch->status;
response->http_status = DN_CAST(DN_U32) fetch->status;
response->body = DN_Str8_Alloc(response->arena, fetch->numBytes, DN_ZeroMem_No);
if (response->body.size)
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
@@ -1372,7 +1474,7 @@ DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response,
DN_CheckF(method.size < sizeof(fetch_attribs.requestMethod),
"%.*s",
DN_STR_FMT(response->error_msg));
response->error_code = DN_CAST(uint32_t) - 1;
response->error_code = DN_CAST(DN_U32) - 1;
DN_Atomic_AddU32(&response->done, 1);
return;
}
@@ -1409,7 +1511,6 @@ DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response)
#endif // #elif defined(DN_OS_WIN32)
DN_Arena_Deinit(&response->tmp_arena);
if (DN_OS_SemaphoreIsValid(&response->on_complete_semaphore))
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
*response = {};
}
+45
View File
@@ -1,5 +1,8 @@
#pragma once
#include <pthread.h>
#include <semaphore.h>
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
@@ -26,5 +29,47 @@ struct DN_POSIXProcSelfStatus
DN_U32 vm_size;
};
// NOTE: The POSIX implementation disallows copies of synchronisation objects in
// general hence we have to dynamically allocate these primitives to maintain a
// consistent address.
//
//
// Source: The Open Group Base Specifications Issue 7, 2018 edition
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09
//
// 2.9.9 Synchronization Object Copies and Alternative Mappings
//
// For barriers, condition variables, mutexes, and read-write locks, [TSH]
// [Option Start] if the process-shared attribute is set to
// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the
// address used to initialize it can be used for performing synchronization. The
// effect of referring to another mapping of the same object when locking,
// unlocking, or destroying the object is undefined. [...] The effect of
// referring to a copy of the object when locking, unlocking, or destroying it
// is undefined.
enum DN_POSIXSyncPrimitiveType
{
DN_OSPOSIXSyncPrimitiveType_Semaphore,
DN_OSPOSIXSyncPrimitiveType_Mutex,
DN_OSPOSIXSyncPrimitiveType_ConditionVariable,
};
struct DN_POSIXSyncPrimitive
{
union
{
sem_t sem;
pthread_mutex_t mutex;
pthread_cond_t cv;
};
DN_POSIXSyncPrimitive *next;
};
struct DN_POSIXCore
{
DN_POSIXSyncPrimitive *sync_primitive_free_list;
};
DN_API void DN_Posix_ThreadSetName(DN_Str8 name);
DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus();
+9 -11
View File
@@ -35,9 +35,9 @@ DN_API void DN_OS_TLSInit(DN_OSTLS *tls, DN_OSTLSInitArgs args)
// TODO: We shouldn't have the no alloc track flag here but the initial TLS
// init on OS init happens before CORE init. CORE init is the one responsible
// for setting up the alloc tracking data structures.
DN_ForIndexU(index, DN_OSTLSArena_Count) {
DN_Arena *arena = tls->arenas + index;
switch (DN_CAST(DN_OSTLSArena) index) {
for (DN_ForItCArray(it, DN_Arena, tls->arenas)) {
DN_Arena *arena = it.data;
switch (DN_CAST(DN_OSTLSArena) it.index) {
default: *arena = DN_Arena_InitFromOSVMem(reserve, commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); break;
case DN_OSTLSArena_ErrorSink: *arena = DN_Arena_InitFromOSVMem(err_sink_reserve, err_sink_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); break;
case DN_OSTLSArena_Count: DN_InvalidCodePath; break;
@@ -54,10 +54,8 @@ DN_API void DN_OS_TLSDeinit(DN_OSTLS *tls)
tls->init = false;
tls->err_sink = {};
tls->arena_stack_index = {};
DN_ForIndexU(index, DN_OSTLSArena_Count) {
DN_Arena *arena = tls->arenas + index;
DN_Arena_Deinit(arena);
}
for (DN_ForItCArray(it, DN_Arena, tls->arenas))
DN_Arena_Deinit(it.data);
}
DN_THREAD_LOCAL DN_OSTLS *g_dn_curr_thread_tls;
@@ -170,7 +168,7 @@ DN_API DN_OSErrSink *DN_OS_ErrSinkBegin_(DN_OSErrSinkMode mode, DN_CallSite call
if (tls->err_sink.stack_size == DN_ArrayCountU(err->stack)) {
DN_Str8Builder builder = DN_Str8Builder_InitFromTLS();
DN_USize counter = 0;
DN_ForItSize(it, DN_OSErrSinkNode, err->stack, err->stack_size) {
for (DN_ForItSize(it, DN_OSErrSinkNode, err->stack, err->stack_size)) {
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(4) when a string is required in call to 'DN_Str8Builder_AppendF' Actual type: 'struct DN_Str8'.
DN_Str8Builder_AppendF(&builder, " [%04zu] %S:%u %S\n", counter++, it.data->call_site.file, it.data->call_site.line, it.data->call_site.function);
@@ -185,9 +183,9 @@ DN_API DN_OSErrSink *DN_OS_ErrSinkBegin_(DN_OSErrSinkMode mode, DN_CallSite call
}
DN_OSErrSinkNode *node = tls->err_sink.stack + tls->err_sink.stack_size++;
node->arena_pos = arena_pos;
node->mode = mode;
node->call_site = call_site;
node->arena_pos = arena_pos;
node->mode = mode;
node->call_site = call_site;
DN_DLList_InitArena(node->msg_sentinel, DN_OSErrSinkMsg, result->arena);
// NOTE: Handle allocation error
+1843
View File
File diff suppressed because it is too large Load Diff
+71
View File
@@ -0,0 +1,71 @@
#if !defined(DN_OS_WIN32_H)
#define DN_OS_WIN32_H
struct DN_W32Error
{
unsigned long code;
DN_Str8 msg;
};
struct DN_W32FolderIteratorW
{
void *handle;
DN_Str16 file_name;
wchar_t file_name_buf[512];
};
enum DN_W32SyncPrimitiveType
{
DN_OSW32SyncPrimitiveType_Semaphore,
DN_OSW32SyncPrimitiveType_Mutex,
DN_OSW32SyncPrimitiveType_ConditionVariable,
};
struct DN_W32SyncPrimitive
{
union
{
void *sem;
CRITICAL_SECTION mutex;
CONDITION_VARIABLE cv;
};
DN_W32SyncPrimitive *next;
};
typedef HRESULT DN_W32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription);
struct DN_W32Core
{
DN_W32SetThreadDescriptionFunc *set_thread_description;
LARGE_INTEGER qpc_frequency;
void *bcrypt_rng_handle;
bool bcrypt_init_success;
bool sym_initialised;
CRITICAL_SECTION sync_primitive_free_list_mutex;
DN_W32SyncPrimitive *sync_primitive_free_list;
};
DN_API void DN_W32_ThreadSetName (DN_Str8 name);
DN_API DN_Str16 DN_W32_ErrorCodeToMsg16Alloc(uint32_t error_code);
DN_API DN_W32Error DN_W32_ErrorCodeToMsg (DN_Arena *arena, uint32_t error_code);
DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc (uint32_t error_code);
DN_API DN_W32Error DN_W32_LastError (DN_Arena *arena);
DN_API DN_W32Error DN_W32_LastErrorAlloc ();
DN_API void DN_W32_MakeProcessDPIAware ();
// NOTE: Windows Str8 <-> Str16 ////////////////////////////////////////////////////////////////////
DN_API DN_Str16 DN_W32_Str8ToStr16 (DN_Arena *arena, DN_Str8 src);
DN_API int DN_W32_Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size);
DN_API DN_Str8 DN_W32_Str16ToStr8 (DN_Arena *arena, DN_Str16 src);
DN_API int DN_W32_Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size);
DN_API DN_Str8 DN_W32_Str16ToStr8FromHeap(DN_Str16 src);
// NOTE: Path navigation ///////////////////////////////////////////////////////////////////////////
DN_API DN_Str16 DN_W32_EXEPathW (DN_Arena *arena);
DN_API DN_Str16 DN_W32_EXEDirW (DN_Arena *arena);
DN_API DN_Str8 DN_W32_WorkingDir (DN_Arena *arena, DN_Str8 suffix);
DN_API DN_Str16 DN_W32_WorkingDirW (DN_Arena *arena, DN_Str16 suffix);
DN_API bool DN_W32_DirWIterate (DN_Str16 path, DN_W32FolderIteratorW *it);
#endif // !defined(DN_OS_WIN32)
+12
View File
@@ -296,6 +296,10 @@
WORD Identifier;
} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG;
typedef struct _RTL_CONDITION_VARIABLE {
PVOID Ptr;
} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
#pragma pack(push, 8)
typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
@@ -1065,8 +1069,15 @@
}
// NOTE: um/synchapi.h /////////////////////////////////////////////////////////////////////////
typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
extern "C"
{
__declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable);
__declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable);
__declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable);
__declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds);
__declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection);
__declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection);
__declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection);
@@ -1075,6 +1086,7 @@
__declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount);
__declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection);
__declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection);
__declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds);
__declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount);
__declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds);