base_win32.c (11138B)
1 /* See LICENSE for license details. */ 2 3 /* NOTE(rnp): provides the platform layer for everything in this repo. */ 4 5 #define OS_SHARED_MEMORY_NAME "Local\\ogl_beamformer_parameters" 6 7 #define OS_PATH_SEPARATOR_CHAR '\\' 8 #define OS_PATH_SEPARATOR "\\" 9 10 #include "base_platform.h" 11 12 #include "util.h" 13 14 #define STD_INPUT_HANDLE -10 15 #define STD_OUTPUT_HANDLE -11 16 #define STD_ERROR_HANDLE -12 17 18 #define PAGE_READONLY 0x02 19 #define PAGE_READWRITE 0x04 20 #define MEM_COMMIT 0x1000 21 #define MEM_RESERVE 0x2000 22 #define MEM_DECOMMIT 0x4000 23 #define MEM_RELEASE 0x8000 24 25 #define GENERIC_WRITE 0x40000000 26 #define GENERIC_READ 0x80000000 27 28 #define FILE_SHARE_READ 0x00000001 29 #define FILE_MAP_ALL_ACCESS 0x000F001F 30 #define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 31 #define FILE_FLAG_OVERLAPPED 0x40000000 32 33 #define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 34 35 #define FILE_ACTION_MODIFIED 0x00000003 36 37 #define CREATE_ALWAYS 2 38 #define OPEN_EXISTING 3 39 40 #define THREAD_SET_LIMITED_INFORMATION 0x0400 41 42 /* NOTE: this is packed because the w32 api designers are dumb and ordered the members 43 * incorrectly. They worked around it be making the ft* members a struct {u32, u32} which 44 * is aligned on a 4-byte boundary. Then in their documentation they explicitly tell you not 45 * to cast to u64 because "it can cause alignment faults on 64-bit Windows" - go figure */ 46 typedef struct w32_file_info w32_file_info; 47 pack_struct(struct w32_file_info { 48 u32 dwFileAttributes; 49 u64 ftCreationTime; 50 u64 ftLastAccessTime; 51 u64 ftLastWriteTime; 52 u32 dwVolumeSerialNumber; 53 u32 nFileSizeHigh; 54 u32 nFileSizeLow; 55 u32 nNumberOfLinks; 56 u32 nFileIndexHigh; 57 u32 nFileIndexLow; 58 }); 59 60 typedef struct { 61 u32 next_entry_offset; 62 u32 action; 63 u32 filename_size; 64 u16 filename[]; 65 } w32_file_notify_info; 66 67 typedef struct { 68 u16 architecture; 69 u16 _pad1; 70 u32 page_size; 71 i64 minimum_application_address; 72 i64 maximum_application_address; 73 u64 active_processor_mask; 74 u32 number_of_processors; 75 u32 processor_type; 76 u32 allocation_granularity; 77 u16 processor_level; 78 u16 processor_revision; 79 } w32_system_info; 80 81 typedef struct { 82 uptr internal, internal_high; 83 union { 84 struct {u32 off, off_high;}; 85 iptr pointer; 86 }; 87 iptr event_handle; 88 } w32_overlapped; 89 90 typedef struct { 91 u32 reserved1; 92 u32 reserved2; 93 u64 Reserved3[2]; 94 u32 reserved4; 95 u32 reserved5; 96 } w32_synchronization_barrier; 97 98 typedef enum { 99 W32IOEvent_FileWatch, 100 } W32IOEvent; 101 102 typedef struct { 103 u64 tag; 104 iptr context; 105 } w32_io_completion_event; 106 107 #define W32(r) __declspec(dllimport) r __stdcall 108 W32(b32) CloseHandle(iptr); 109 W32(b32) CopyFileA(c8 *, c8 *, b32); 110 W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *); 111 W32(iptr) CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *); 112 W32(iptr) CreateIoCompletionPort(iptr, iptr, uptr, u32); 113 W32(iptr) CreateSemaphoreA(iptr, i32, i32, c8 *); 114 W32(u64) CreateThread(iptr, u64, iptr, iptr, u32, u32 *); 115 W32(b32) DeleteFileA(c8 *); 116 W32(b32) EnterSynchronizationBarrier(w32_synchronization_barrier *, u32); 117 W32(void) ExitProcess(i32); 118 W32(i32) GetFileAttributesA(c8 *); 119 W32(b32) GetFileInformationByHandle(iptr, void *); 120 W32(i32) GetLastError(void); 121 W32(b32) GetQueuedCompletionStatus(iptr, u32 *, uptr *, w32_overlapped **, u32); 122 W32(iptr) GetStdHandle(i32); 123 W32(void) GetSystemInfo(w32_system_info *); 124 W32(b32) InitializeSynchronizationBarrier(w32_synchronization_barrier *, i32, i32); 125 W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64); 126 W32(b32) QueryPerformanceCounter(u64 *); 127 W32(b32) QueryPerformanceFrequency(u64 *); 128 W32(b32) ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *); 129 W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); 130 W32(b32) ReleaseSemaphore(iptr, i32, i32 *); 131 W32(i32) SetThreadDescription(u64, u16 *); 132 W32(u32) WaitForSingleObject(iptr, u32); 133 W32(b32) WaitOnAddress(void *, void *, u64, u32); 134 W32(i32) WakeByAddressAll(void *); 135 W32(b32) WriteFile(iptr, u8 *, i32, i32 *, void *); 136 W32(void *) VirtualAlloc(u8 *, i64, u32, u32); 137 W32(b32) VirtualFree(void *, u64, u32); 138 139 enum {OSW32_FileWatchDirectoryBufferSize = KB(4)}; 140 141 typedef struct OSW32Entity OSW32Entity; 142 typedef struct { 143 void *handle; 144 OSW32Entity *prev, *next; 145 } OSW32Window; 146 147 typedef enum { 148 OSW32FileWatchKind_Platform, 149 OSW32FileWatchKind_User, 150 } OSW32FileWatchKind; 151 152 typedef struct OSW32FileWatchDirectory OSW32FileWatchDirectory; 153 typedef struct OSW32FileWatch OSW32FileWatch; 154 struct OSW32FileWatch { 155 OSW32FileWatchKind kind; 156 u64 hash; 157 u64 update_time; 158 void *user_context; 159 160 OSW32FileWatchDirectory *parent; 161 OSW32FileWatch *prev, *next; 162 }; 163 164 struct OSW32FileWatchDirectory { 165 u64 hash; 166 i64 handle; 167 str8 name; 168 169 OSW32FileWatch *first_child; 170 OSW32FileWatch *last_child; 171 OSW32FileWatchDirectory *prev, *next; 172 173 w32_overlapped overlapped; 174 w32_io_completion_event event; 175 176 void *buffer; 177 }; 178 179 typedef enum { 180 OSW32EntityKind_Window, 181 OSW32EntityKind_FileWatch, 182 OSW32EntityKind_FileWatchDirectory, 183 } OSW32EntityKind; 184 185 struct OSW32Entity { 186 OSW32EntityKind kind; 187 union { 188 OSW32FileWatch file_watch; 189 OSW32FileWatchDirectory file_watch_directory; 190 OSW32Window window; 191 } as; 192 OSW32Entity *next; 193 }; 194 195 typedef struct { 196 OSSystemInfo system_info; 197 198 Arena *arena; 199 i32 arena_lock; 200 i64 error_handle; 201 i64 io_completion_handle; 202 203 struct { 204 OSW32FileWatchDirectory *first; 205 OSW32FileWatchDirectory *last; 206 } file_watch_directories; 207 208 struct { 209 OSW32Entity *first; 210 OSW32Entity *last; 211 } windows; 212 213 OSW32Entity *entity_freelist; 214 } OSW32_Context; 215 global OSW32_Context os_w32_context; 216 217 function b32 218 os_write_file(iptr file, void *data, i64 length) 219 { 220 i32 wlen = 0; 221 if (length > 0 && length <= (i64)U32_MAX) WriteFile(file, data, (i32)length, &wlen, 0); 222 return length == wlen; 223 } 224 225 BASE_EXPORT no_return void 226 os_exit(i32 code) 227 { 228 ExitProcess(code); 229 unreachable(); 230 } 231 232 function u64 233 os_timer_frequency(void) 234 { 235 u64 result; 236 QueryPerformanceFrequency(&result); 237 return result; 238 } 239 240 BASE_EXPORT u64 241 os_timer_count(void) 242 { 243 u64 result; 244 QueryPerformanceCounter(&result); 245 return result; 246 } 247 248 function void 249 os_system_info_init(void) 250 { 251 w32_system_info info = {0}; 252 GetSystemInfo(&info); 253 254 os_w32_context.system_info.timer_frequency = os_timer_frequency(); 255 os_w32_context.system_info.logical_processor_count = info.number_of_processors; 256 os_w32_context.system_info.page_size = info.page_size; 257 os_w32_context.system_info.path_separator_byte = '\\'; 258 } 259 260 BASE_EXPORT OSSystemInfo * 261 os_system_info(void) 262 { 263 #if BASE_PLATFORM_NO_MAIN 264 if unlikely(os_w32_context.system_info.path_separator_byte == 0) 265 os_system_info_init(); 266 #endif 267 return &os_w32_context.system_info; 268 } 269 270 BASE_EXPORT void * 271 os_memory_reserve(u64 size) 272 { 273 void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); 274 return result; 275 } 276 277 BASE_EXPORT void 278 os_memory_release(void *base, u64 size) 279 { 280 // NOTE(rnp): size must be 0 on w32, no partial releasing 281 VirtualFree(base, 0, MEM_RELEASE); 282 } 283 284 BASE_EXPORT b32 285 os_memory_commit(void *base, u64 size) 286 { 287 b32 result = VirtualAlloc(base, size, MEM_COMMIT, PAGE_READWRITE) != 0; 288 return result; 289 } 290 291 BASE_EXPORT OSW32Semaphore 292 os_w32_create_semaphore(const char *name, i32 initial_count, i32 maximum_count) 293 { 294 OSW32Semaphore result = {(u64)CreateSemaphoreA(0, initial_count, maximum_count, (c8 *)name)}; 295 return result; 296 } 297 298 BASE_EXPORT u32 299 os_w32_semaphore_wait(OSW32Semaphore handle, u32 timeout_ms) 300 { 301 b32 result = !WaitForSingleObject(handle.value[0], timeout_ms); 302 return result; 303 } 304 305 BASE_EXPORT void 306 os_w32_semaphore_release(OSW32Semaphore handle, i32 count) 307 { 308 ReleaseSemaphore(handle.value[0], count, 0); 309 } 310 311 BASE_EXPORT str8 312 os_read_entire_file(Arena *arena, const char *file) 313 { 314 str8 result = {0}; 315 w32_file_info fileinfo; 316 iptr h = CreateFileA((c8 *)file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 317 if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) { 318 i64 filesize = (i64)fileinfo.nFileSizeHigh << 32; 319 filesize |= (i64)fileinfo.nFileSizeLow; 320 result.data = push_array(arena, u8, filesize); 321 result.length = filesize; 322 i32 rlen; 323 if (!ReadFile(h, result.data, (i32)filesize, &rlen, 0) || rlen != filesize) { 324 arena_pop(arena, filesize); 325 zero_struct(&result); 326 } 327 } 328 if (h >= 0) CloseHandle(h); 329 330 return result; 331 } 332 333 function b32 334 os_write_new_file(char *fname, str8 raw) 335 { 336 b32 result = 0; 337 iptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); 338 if (h >= 0) { 339 while (raw.length > 0) { 340 i64 length = Min(raw.length, (i64)GB(2)); 341 result = os_write_file(h, raw.data, length); 342 if (!result) break; 343 raw = str8_cut_head(raw, length); 344 } 345 CloseHandle(h); 346 } 347 return result; 348 } 349 350 function b32 351 os_file_exists(char *path) 352 { 353 b32 result = GetFileAttributesA(path) != -1; 354 return result; 355 } 356 357 function b32 358 os_copy_file(char *name, char *new) 359 { 360 return CopyFileA(name, new, 0); 361 } 362 363 function OSW32Entity * 364 os_entity_allocate(OSW32EntityKind kind) 365 { 366 OSW32Entity *result = 0; 367 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 368 { 369 result = SLLPopFreelist(os_w32_context.entity_freelist); 370 if (!result) result = push_struct_no_zero(os_w32_context.arena, OSW32Entity); 371 } 372 373 zero_struct(result); 374 result->kind = kind; 375 return result; 376 } 377 378 BASE_EXPORT OSThread 379 os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) 380 { 381 OSThread result = {(u64)CreateThread(0, 0, (iptr)fn, (iptr)user_context, 0, 0)}; 382 if (result.value[0]) { 383 Temp scratch; 384 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 385 DeferLoop(scratch = temp_begin(os_w32_context.arena), temp_end(scratch)) 386 { 387 SetThreadDescription(result.value[0], str16_from_str8(scratch.arena, str8_from_c_str((c8 *)name)).data); 388 } 389 } else { 390 result.value[0] = OSInvalidHandleValue; 391 } 392 return result; 393 } 394 395 BASE_EXPORT OSBarrier 396 os_barrier_alloc(u32 count) 397 { 398 OSBarrier result = {0}; 399 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 400 { 401 w32_synchronization_barrier *barrier = push_struct(os_w32_context.arena, w32_synchronization_barrier); 402 InitializeSynchronizationBarrier(barrier, (i32)count, -1); 403 result.value[0] = (u64)barrier; 404 } 405 return result; 406 } 407 408 BASE_EXPORT void 409 os_barrier_enter(OSBarrier barrier) 410 { 411 w32_synchronization_barrier *b = (w32_synchronization_barrier *)barrier.value[0]; 412 if (b) EnterSynchronizationBarrier(b, 0); 413 } 414 415 BASE_EXPORT b32 416 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms) 417 { 418 return WaitOnAddress(value, ¤t, sizeof(*value), timeout_ms); 419 } 420 421 BASE_EXPORT void 422 os_wake_all_waiters(i32 *sync) 423 { 424 if (sync) { 425 atomic_store_u32(sync, 0); 426 WakeByAddressAll(sync); 427 } 428 } 429 430 #if !BASE_PLATFORM_NO_MAIN 431 BASE_IMPORT void entry_point(i32 argc, char *argv[]); 432 433 extern i32 434 main(i32 argc, char *argv[]) 435 { 436 os_system_info_init(); 437 os_w32_context.arena = arena_create(.name = "Platform Arena"); 438 os_w32_context.error_handle = GetStdHandle(STD_ERROR_HANDLE); 439 440 entry_point(argc, argv); 441 442 return 0; 443 } 444 #endif