#pragma once #include "dqn.h" /* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$\ // $$ __$$\ $$ __$$\ // $$ / $$ |$$ / \__| // $$ | $$ |\$$$$$$\ // $$ | $$ | \____$$\ // $$ | $$ |$$\ $$ | // $$$$$$ |\$$$$$$ | // \______/ \______/ // // dqn_os.h -- Common APIs/services provided by the operating system/platform layer // //////////////////////////////////////////////////////////////////////////////////////////////////// // // [$OMEM] Dqn_OSMem -- -- Memory allocation (typically virtual memory if supported) // [$DATE] Dqn_OSDate -- -- Date time APIs // [$FILE] Dqn_OSPathInfo/File -- -- File path info/reading/writing // [$PATH] Dqn_OSPath -- -- Construct native OS paths helpers // [$EXEC] Dqn_OSExec -- -- Execute programs programatically // [$SEMA] Dqn_OSSemaphore -- DQN_SEMAPHORE -- // [$MUTX] Dqn_OSMutex -- -- // [$THRD] Dqn_OSThread -- DQN_THREAD -- // [$HTTP] Dqn_OSHttp -- -- // //////////////////////////////////////////////////////////////////////////////////////////////////// */ // NOTE: [$OMEM] Dqn_OSMem ////////////////////////////////////////////////////////////////////////// enum Dqn_OSMemCommit { Dqn_OSMemCommit_No, Dqn_OSMemCommit_Yes, }; enum Dqn_OSMemPage { // Exception on read/write with a page. This flag overrides the read/write // access. Dqn_OSMemPage_NoAccess = 1 << 0, Dqn_OSMemPage_Read = 1 << 1, // Only read permitted on the page. // Only write permitted on the page. On Windows this is not supported and // will be promoted to read+write permissions. Dqn_OSMemPage_Write = 1 << 2, Dqn_OSMemPage_ReadWrite = Dqn_OSMemPage_Read | Dqn_OSMemPage_Write, // Modifier used in conjunction with previous flags. Raises exception on // first access to the page, then, the underlying protection flags are // active. This is supported on Windows, on other OS's using this flag will // set the OS equivalent of Dqn_OSMemPage_NoAccess. // This flag must only be used in Dqn_OSMem_Protect Dqn_OSMemPage_Guard = 1 << 3, // If leak tracing is enabled, this flag will allow the allocation recorded // from the reserve call to be leaked, e.g. not printed when leaks are // dumped to the console. Dqn_OSMemPage_AllocRecordLeakPermitted = 1 << 4, // If leak tracing is enabled this flag will prevent any allocation record // from being created in the allocation table at all. If this flag is // enabled, 'OSMemPage_AllocRecordLeakPermitted' has no effect since the // record will never be created. Dqn_OSMemPage_NoAllocRecordEntry = 1 << 5, // [INTERNAL] Do not use. All flags together do not constitute a correct // configuration of pages. Dqn_OSMemPage_All = Dqn_OSMemPage_NoAccess | Dqn_OSMemPage_ReadWrite | Dqn_OSMemPage_Guard | Dqn_OSMemPage_AllocRecordLeakPermitted | Dqn_OSMemPage_NoAllocRecordEntry, }; // NOTE: [$DATE] Dqn_OSDate //////////////////////////////////////////////////////////////////////// struct Dqn_OSDateTimeStr8 { char date[DQN_ARRAY_UCOUNT("YYYY-MM-SS")]; uint8_t date_size; char hms[DQN_ARRAY_UCOUNT("HH:MM:SS")]; uint8_t hms_size; }; struct Dqn_OSDateTime { uint8_t day; uint8_t month; uint16_t year; uint8_t hour; uint8_t minutes; uint8_t seconds; }; struct Dqn_OSTimer /// Record time between two time-points using the OS's performance counter. { uint64_t start; uint64_t end; }; #if !defined(DQN_NO_OS_FILE_API) // NOTE: [$FSYS] Dqn_OSFile //////////////////////////////////////////////////////////////////////// enum Dqn_OSPathInfoType { Dqn_OSPathInfoType_Unknown, Dqn_OSPathInfoType_Directory, Dqn_OSPathInfoType_File, }; struct Dqn_OSPathInfo { bool exists; Dqn_OSPathInfoType type; uint64_t create_time_in_s; uint64_t last_write_time_in_s; uint64_t last_access_time_in_s; uint64_t size; }; // NOTE: R/W Stream API //////////////////////////////////////////////////////////////////////////// struct Dqn_OSFile { bool error; void *handle; }; enum Dqn_OSFileOpen { Dqn_OSFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open Dqn_OSFileOpen_OpenIfExist, // Open file at path only if it exists Dqn_OSFileOpen_OpenAlways, // Open file at path, create file if it does not exist }; enum Dqn_OSFileAccess { Dqn_OSFileAccess_Read = 1 << 0, Dqn_OSFileAccess_Write = 1 << 1, Dqn_OSFileAccess_Execute = 1 << 2, Dqn_OSFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode Dqn_OSFileAccess_ReadWrite = Dqn_OSFileAccess_Read | Dqn_OSFileAccess_Write, Dqn_OSFileAccess_All = Dqn_OSFileAccess_ReadWrite | Dqn_OSFileAccess_Execute, }; #endif // DQN_NO_OS_FILE_API // NOTE: Dqn_OSPath //////////////////////////////////////////////////////////////////////////////// #if !defined(Dqn_OSPathSeperator) #if defined(DQN_OS_WIN32) #define Dqn_OSPathSeperator "\\" #else #define Dqn_OSPathSeperator "/" #endif #define Dqn_OSPathSeperatorString DQN_STR8(Dqn_OSPathSeperator) #endif struct Dqn_OSPathLink { Dqn_Str8 string; Dqn_OSPathLink *next; Dqn_OSPathLink *prev; }; struct Dqn_OSPath { bool has_prefix_path_separator; Dqn_OSPathLink *head; Dqn_OSPathLink *tail; Dqn_usize string_size; uint16_t links_size; }; // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// enum Dqn_OSExecFlag { Dqn_OSExecFlag_Nil = 0, Dqn_OSExecFlag_SaveStdout = 1 << 0, Dqn_OSExecFlag_SaveStderr = 1 << 1, Dqn_OSExecFlag_SaveOutput = Dqn_OSExecFlag_SaveStdout | Dqn_OSExecFlag_SaveStderr, Dqn_OSExecFlag_MergeStderrToStdout = 1 << 2 | Dqn_OSExecFlag_SaveOutput, }; struct Dqn_OSExecAsyncHandle { uint8_t exec_flags; uint32_t os_error_code; uint32_t exit_code; void *process; void *stdout_read; void *stdout_write; void *stderr_read; void *stderr_write; }; struct Dqn_OSExecResult { Dqn_Str8 stdout_text; Dqn_Str8 stderr_text; uint32_t os_error_code; uint32_t exit_code; }; #if !defined(DQN_NO_SEMAPHORE) // NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// uint32_t const DQN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX; struct Dqn_OSSemaphore { #if defined(DQN_OS_WIN32) && !defined(DQN_OS_WIN32_USE_PTHREADS) void *win32_handle; #else sem_t posix_handle; bool posix_init; #endif }; enum Dqn_OSSemaphoreWaitResult { Dqn_OSSemaphoreWaitResult_Failed, Dqn_OSSemaphoreWaitResult_Success, Dqn_OSSemaphoreWaitResult_Timeout, }; #endif // !defined(DQN_NO_SEMAPHORE) // NOTE: [$THRD] Dqn_OSThread ///////////////////////////////////////////////////////////////////// #if !defined(DQN_NO_THREAD) && !defined(DQN_NO_SEMAPHORE) typedef int32_t (Dqn_OSThreadFunc)(struct Dqn_OSThread*); struct Dqn_OSThread { void *handle; uint64_t thread_id; void *user_context; Dqn_OSThreadFunc *func; Dqn_OSSemaphore init_semaphore; }; #endif // !defined(DQN_NO_THREAD) // NOTE: [$HTTP] Dqn_OSHttp //////////////////////////////////////////////////////////////////////// enum Dqn_OSHttpRequestSecure { Dqn_OSHttpRequestSecure_No, Dqn_OSHttpRequestSecure_Yes, }; struct Dqn_OSHttpResponse { // NOTE: Response data uint32_t error_code; Dqn_Str8 error_msg; uint16_t http_status; Dqn_Str8 body; Dqn_b32 done; // NOTE: Book-keeping Dqn_Arena *arena; // Allocates memory for the response // NOTE: Async book-keeping // Synchronous HTTP response uses the TLS scratch arena whereas async // calls use their own dedicated arena. Dqn_Arena tmp_arena; Dqn_Arena *scratch_arena; Dqn_Str8Builder builder; Dqn_OSSemaphore on_complete_semaphore; #if defined(DQN_PLATFORM_EMSCRIPTEN) emscripten_fetch_t *em_handle; #elif defined(DQN_OS_WIN32) HINTERNET win32_request_session; HINTERNET win32_request_connection; HINTERNET win32_request_handle; #endif }; // NOTE: [$OMEM] Memory ////////////////////////////////////////////////////////////////////////// DQN_API void * Dqn_OS_MemReserve (Dqn_usize size, Dqn_OSMemCommit commit, uint32_t page_flags); DQN_API bool Dqn_OS_MemCommit (void *ptr, Dqn_usize size, uint32_t page_flags); DQN_API void Dqn_OS_MemDecommit(void *ptr, Dqn_usize size); DQN_API void Dqn_OS_MemRelease (void *ptr, Dqn_usize size); DQN_API int Dqn_OS_MemProtect (void *ptr, Dqn_usize size, uint32_t page_flags); // NOTE: [$DATE] Date ////////////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow (); DQN_API Dqn_OSDateTimeStr8 Dqn_OS_DateLocalTimeStr8Now(char date_separator = '-', char hms_separator = ':'); DQN_API Dqn_OSDateTimeStr8 Dqn_OS_DateLocalTimeStr8 (Dqn_OSDateTime time, char date_separator = '-', char hms_separator = ':'); DQN_API uint64_t Dqn_OS_DateUnixTime (); DQN_API Dqn_OSDateTime Dqn_OS_DateUnixTimeToDate (uint64_t time); DQN_API uint64_t Dqn_OS_DateToUnixTime (Dqn_OSDateTime date); DQN_API bool Dqn_OS_DateIsValid (Dqn_OSDateTime date); // NOTE: Other ///////////////////////////////////////////////////////////////////////////////////// DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size); DQN_API Dqn_Str8 Dqn_OS_EXEPath (Dqn_Arena *arena); DQN_API Dqn_Str8 Dqn_OS_EXEDir (Dqn_Arena *arena); DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds); // NOTE: Counters ////////////////////////////////////////////////////////////////////////////////// DQN_API uint64_t Dqn_OS_PerfCounterNow (); DQN_API uint64_t Dqn_OS_PerfCounterFrequency(); DQN_API Dqn_f64 Dqn_OS_PerfCounterS (uint64_t begin, uint64_t end); DQN_API Dqn_f64 Dqn_OS_PerfCounterMs (uint64_t begin, uint64_t end); DQN_API Dqn_f64 Dqn_OS_PerfCounterUs (uint64_t begin, uint64_t end); DQN_API Dqn_f64 Dqn_OS_PerfCounterNs (uint64_t begin, uint64_t end); DQN_API Dqn_OSTimer Dqn_OS_TimerBegin (); DQN_API void Dqn_OS_TimerEnd (Dqn_OSTimer *timer); DQN_API Dqn_f64 Dqn_OS_TimerS (Dqn_OSTimer timer); DQN_API Dqn_f64 Dqn_OS_TimerMs (Dqn_OSTimer timer); DQN_API Dqn_f64 Dqn_OS_TimerUs (Dqn_OSTimer timer); DQN_API Dqn_f64 Dqn_OS_TimerNs (Dqn_OSTimer timer); DQN_API uint64_t Dqn_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_tsc_frequency); #if !defined(DQN_NO_OS_FILE_API) // NOTE: File system paths ///////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSPathInfo Dqn_OS_PathInfo (Dqn_Str8 path); DQN_API bool Dqn_OS_PathDelete(Dqn_Str8 path); DQN_API bool Dqn_OS_FileExists(Dqn_Str8 path); DQN_API bool Dqn_OS_CopyFile (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_MoveFile (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_MakeDir (Dqn_Str8 path, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_DirExists (Dqn_Str8 path, Dqn_ErrorSink *error); // NOTE: R/W Stream API //////////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSFile Dqn_OS_FileOpen (Dqn_Str8 path, Dqn_OSFileOpen open_mode, uint32_t access, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_FileRead (Dqn_OSFile *file, void *buffer, Dqn_usize size, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_FileWritePtr(Dqn_OSFile *file, void const *data, Dqn_usize size, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_FileWrite (Dqn_OSFile *file, Dqn_Str8 buffer, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_FileWriteFV (Dqn_OSFile *file, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args); DQN_API bool Dqn_OS_FileWriteF (Dqn_OSFile *file, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API void Dqn_OS_FileClose (Dqn_OSFile *file); // NOTE: R/W Entire File /////////////////////////////////////////////////////////////////////////// DQN_API Dqn_Str8 Dqn_OS_ReadAll (Dqn_Str8 path, Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_WriteAll (Dqn_Str8 path, Dqn_Str8 buffer, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_WriteAllFV (Dqn_Str8 path, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args); DQN_API bool Dqn_OS_WriteAllF (Dqn_Str8 path, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API bool Dqn_OS_WriteAllSafe (Dqn_Str8 path, Dqn_Str8 buffer, Dqn_ErrorSink *error); DQN_API bool Dqn_OS_WriteAllSafeFV(Dqn_Str8 path, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args); DQN_API bool Dqn_OS_WriteAllSafeF (Dqn_Str8 path, Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...); #endif // !defined(DQN_NO_OS_FILE_API) // NOTE: File system paths ///////////////////////////////////////////////////////////////////////// DQN_API bool Dqn_OS_PathAddRef (Dqn_Arena *arena, Dqn_OSPath *fs_path, Dqn_Str8 path); DQN_API bool Dqn_OS_PathAdd (Dqn_Arena *arena, Dqn_OSPath *fs_path, Dqn_Str8 path); DQN_API bool Dqn_OS_PathAddF (Dqn_Arena *arena, Dqn_OSPath *fs_path, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API bool Dqn_OS_PathPop (Dqn_OSPath *fs_path); DQN_API Dqn_Str8 Dqn_OS_PathBuildWithSeparator(Dqn_Arena *arena, Dqn_OSPath const *fs_path, Dqn_Str8 path_separator); DQN_API Dqn_Str8 Dqn_OS_PathConvertTo (Dqn_Arena *arena, Dqn_Str8 path, Dqn_Str8 path_separtor); DQN_API Dqn_Str8 Dqn_OS_PathConvertToF (Dqn_Arena *arena, Dqn_Str8 path_separator, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API Dqn_Str8 Dqn_OS_PathConvert (Dqn_Arena *arena, Dqn_Str8 path); DQN_API Dqn_Str8 Dqn_OS_PathConvertF (Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...); #define Dqn_OS_PathBuildFwdSlash(allocator, fs_path) Dqn_OS_PathBuildWithSeparator(allocator, fs_path, DQN_STR8("/")) #define Dqn_OS_PathBuildBackSlash(allocator, fs_path) Dqn_OS_PathBuildWithSeparator(allocator, fs_path, DQN_STR8("\\")) #define Dqn_OS_PathBuild(allocator, fs_path) Dqn_OS_PathBuildWithSeparator(allocator, fs_path, Dqn_OSPathSeparatorString) // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// DQN_API void Dqn_OS_Exit (int32_t exit_code); DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle, Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_ErrorSink *error); DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena); // NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// #if !defined(DQN_NO_SEMAPHORE) DQN_API Dqn_OSSemaphore Dqn_OS_SemaphoreInit (uint32_t initial_count); DQN_API bool Dqn_OS_SemaphoreIsValid (Dqn_OSSemaphore *semaphore); DQN_API void Dqn_OS_SemaphoreDeinit (Dqn_OSSemaphore *semaphore); DQN_API void Dqn_OS_SemaphoreIncrement(Dqn_OSSemaphore *semaphore, uint32_t amount); DQN_API Dqn_OSSemaphoreWaitResult Dqn_OS_SemaphoreWait (Dqn_OSSemaphore *semaphore, uint32_t timeout_ms); #endif // !defined(DQN_NO_SEMAPHORE) // NOTE: [$MUTX] Dqn_OSMutex /////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSMutex Dqn_OS_MutexInit (); DQN_API void Dqn_OS_MutexDeinit(Dqn_OSMutex *mutex); DQN_API void Dqn_OS_MutexLock (Dqn_OSMutex *mutex); DQN_API void Dqn_OS_MutexUnlock(Dqn_OSMutex *mutex); // NOTE: [$THRD] Dqn_OSThread ///////////////////////////////////////////////////////////////////// #if !defined(DQN_NO_THREAD) && !defined(DQN_NO_SEMAPHORE) DQN_API bool Dqn_OS_ThreadInit (Dqn_OSThread *thread, Dqn_OSThreadFunc *func, void *user_context); DQN_API void Dqn_OS_ThreadDeinit(Dqn_OSThread thread); DQN_API uint32_t Dqn_OS_ThreadID (); #endif // !defined(DQN_NO_THREAD) // NOTE: [$HTTP] Dqn_OSHttp //////////////////////////////////////////////////////////////////////// DQN_API void Dqn_OS_HttpRequestAsync(Dqn_OSHttpResponse *response, Dqn_Arena *arena, Dqn_Str8 host, Dqn_Str8 path, Dqn_OSHttpRequestSecure secure, Dqn_Str8 method, Dqn_Str8 body, Dqn_Str8 headers); DQN_API void Dqn_OS_HttpRequestWait (Dqn_OSHttpResponse *response); DQN_API void Dqn_OS_HttpRequestFree (Dqn_OSHttpResponse *response); DQN_API Dqn_OSHttpResponse Dqn_OS_HttpRequest (Dqn_Arena *arena, Dqn_Str8 host, Dqn_Str8 path, Dqn_OSHttpRequestSecure secure, Dqn_Str8 method, Dqn_Str8 body, Dqn_Str8 headers);