base_win32.c (11425B)
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 W32(b32) VirtualProtect(void *, u64, u32, u32 *); 139 140 enum {OSW32_FileWatchDirectoryBufferSize = KB(4)}; 141 142 typedef struct OSW32Entity OSW32Entity; 143 typedef struct { 144 void *handle; 145 OSW32Entity *prev, *next; 146 } OSW32Window; 147 148 typedef enum { 149 OSW32FileWatchKind_Platform, 150 OSW32FileWatchKind_User, 151 } OSW32FileWatchKind; 152 153 typedef struct OSW32FileWatchDirectory OSW32FileWatchDirectory; 154 typedef struct OSW32FileWatch OSW32FileWatch; 155 struct OSW32FileWatch { 156 OSW32FileWatchKind kind; 157 u64 hash; 158 u64 update_time; 159 void *user_context; 160 161 OSW32FileWatchDirectory *parent; 162 OSW32FileWatch *prev, *next; 163 }; 164 165 struct OSW32FileWatchDirectory { 166 u64 hash; 167 i64 handle; 168 str8 name; 169 170 OSW32FileWatch *first_child; 171 OSW32FileWatch *last_child; 172 OSW32FileWatchDirectory *prev, *next; 173 174 w32_overlapped overlapped; 175 w32_io_completion_event event; 176 177 void *buffer; 178 }; 179 180 typedef enum { 181 OSW32EntityKind_Window, 182 OSW32EntityKind_FileWatch, 183 OSW32EntityKind_FileWatchDirectory, 184 } OSW32EntityKind; 185 186 struct OSW32Entity { 187 OSW32EntityKind kind; 188 union { 189 OSW32FileWatch file_watch; 190 OSW32FileWatchDirectory file_watch_directory; 191 OSW32Window window; 192 } as; 193 OSW32Entity *next; 194 }; 195 196 typedef struct { 197 OSSystemInfo system_info; 198 199 Arena *arena; 200 i32 arena_lock; 201 i64 error_handle; 202 i64 io_completion_handle; 203 204 struct { 205 OSW32FileWatchDirectory *first; 206 OSW32FileWatchDirectory *last; 207 } file_watch_directories; 208 209 struct { 210 OSW32Entity *first; 211 OSW32Entity *last; 212 } windows; 213 214 OSW32Entity *entity_freelist; 215 } OSW32_Context; 216 global OSW32_Context os_w32_context; 217 218 function b32 219 os_write_file(iptr file, void *data, i64 length) 220 { 221 i32 wlen = 0; 222 if (length > 0 && length <= (i64)U32_MAX) WriteFile(file, data, (i32)length, &wlen, 0); 223 return length == wlen; 224 } 225 226 BASE_EXPORT no_return void 227 os_exit(i32 code) 228 { 229 ExitProcess(code); 230 unreachable(); 231 } 232 233 function u64 234 os_timer_frequency(void) 235 { 236 u64 result; 237 QueryPerformanceFrequency(&result); 238 return result; 239 } 240 241 BASE_EXPORT u64 242 os_timer_count(void) 243 { 244 u64 result; 245 QueryPerformanceCounter(&result); 246 return result; 247 } 248 249 function void 250 os_system_info_init(void) 251 { 252 w32_system_info info = {0}; 253 GetSystemInfo(&info); 254 255 os_w32_context.system_info.timer_frequency = os_timer_frequency(); 256 os_w32_context.system_info.logical_processor_count = info.number_of_processors; 257 os_w32_context.system_info.page_size = info.page_size; 258 os_w32_context.system_info.path_separator_byte = '\\'; 259 } 260 261 BASE_EXPORT OSSystemInfo * 262 os_system_info(void) 263 { 264 #if BASE_PLATFORM_NO_MAIN 265 if unlikely(os_w32_context.system_info.path_separator_byte == 0) 266 os_system_info_init(); 267 #endif 268 return &os_w32_context.system_info; 269 } 270 271 BASE_EXPORT void * 272 os_memory_reserve(u64 size) 273 { 274 void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); 275 return result; 276 } 277 278 BASE_EXPORT void 279 os_memory_release(void *base, u64 size) 280 { 281 // NOTE(rnp): size must be 0 on w32, no partial releasing 282 VirtualFree(base, 0, MEM_RELEASE); 283 } 284 285 BASE_EXPORT b32 286 os_memory_commit(void *base, u64 size) 287 { 288 b32 result = VirtualAlloc(base, size, MEM_COMMIT, PAGE_READWRITE) != 0; 289 return result; 290 } 291 292 BASE_EXPORT void 293 os_memory_uncommit(void *base, u64 size) 294 { 295 VirtualFree(base, size, MEM_DECOMMIT); 296 } 297 298 BASE_EXPORT void 299 os_memory_seal(void *base, u64 size) 300 { 301 u32 w32_dummy; 302 VirtualProtect(base, size, PAGE_READONLY, &w32_dummy); 303 } 304 305 BASE_EXPORT OSW32Semaphore 306 os_w32_create_semaphore(const char *name, i32 initial_count, i32 maximum_count) 307 { 308 OSW32Semaphore result = {(u64)CreateSemaphoreA(0, initial_count, maximum_count, (c8 *)name)}; 309 return result; 310 } 311 312 BASE_EXPORT u32 313 os_w32_semaphore_wait(OSW32Semaphore handle, u32 timeout_ms) 314 { 315 b32 result = !WaitForSingleObject(handle.value[0], timeout_ms); 316 return result; 317 } 318 319 BASE_EXPORT void 320 os_w32_semaphore_release(OSW32Semaphore handle, i32 count) 321 { 322 ReleaseSemaphore(handle.value[0], count, 0); 323 } 324 325 BASE_EXPORT str8 326 os_read_entire_file(Arena *arena, const char *file) 327 { 328 str8 result = {0}; 329 w32_file_info fileinfo; 330 iptr h = CreateFileA((c8 *)file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 331 if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) { 332 i64 filesize = (i64)fileinfo.nFileSizeHigh << 32; 333 filesize |= (i64)fileinfo.nFileSizeLow; 334 result.data = push_array(arena, u8, filesize); 335 result.length = filesize; 336 i32 rlen; 337 if (!ReadFile(h, result.data, (i32)filesize, &rlen, 0) || rlen != filesize) { 338 arena_pop(arena, filesize); 339 zero_struct(&result); 340 } 341 } 342 if (h >= 0) CloseHandle(h); 343 344 return result; 345 } 346 347 function b32 348 os_write_new_file(char *fname, str8 raw) 349 { 350 b32 result = 0; 351 iptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); 352 if (h >= 0) { 353 while (raw.length > 0) { 354 i64 length = Min(raw.length, (i64)GB(2)); 355 result = os_write_file(h, raw.data, length); 356 if (!result) break; 357 raw = str8_cut_head(raw, length); 358 } 359 CloseHandle(h); 360 } 361 return result; 362 } 363 364 function b32 365 os_file_exists(char *path) 366 { 367 b32 result = GetFileAttributesA(path) != -1; 368 return result; 369 } 370 371 function b32 372 os_copy_file(char *name, char *new) 373 { 374 return CopyFileA(name, new, 0); 375 } 376 377 function OSW32Entity * 378 os_entity_allocate(OSW32EntityKind kind) 379 { 380 OSW32Entity *result = 0; 381 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 382 { 383 result = SLLPopFreelist(os_w32_context.entity_freelist); 384 if (!result) result = push_struct_no_zero(os_w32_context.arena, OSW32Entity); 385 } 386 387 zero_struct(result); 388 result->kind = kind; 389 return result; 390 } 391 392 BASE_EXPORT OSThread 393 os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) 394 { 395 OSThread result = {(u64)CreateThread(0, 0, (iptr)fn, (iptr)user_context, 0, 0)}; 396 if (result.value[0]) { 397 Temp scratch; 398 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 399 DeferLoop(scratch = temp_begin(os_w32_context.arena), temp_end(scratch)) 400 { 401 SetThreadDescription(result.value[0], str16_from_str8(scratch.arena, str8_from_c_str((c8 *)name)).data); 402 } 403 } else { 404 result.value[0] = OSInvalidHandleValue; 405 } 406 return result; 407 } 408 409 BASE_EXPORT OSBarrier 410 os_barrier_alloc(u32 count) 411 { 412 OSBarrier result = {0}; 413 DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) 414 { 415 w32_synchronization_barrier *barrier = push_struct(os_w32_context.arena, w32_synchronization_barrier); 416 InitializeSynchronizationBarrier(barrier, (i32)count, -1); 417 result.value[0] = (u64)barrier; 418 } 419 return result; 420 } 421 422 BASE_EXPORT void 423 os_barrier_enter(OSBarrier barrier) 424 { 425 w32_synchronization_barrier *b = (w32_synchronization_barrier *)barrier.value[0]; 426 if (b) EnterSynchronizationBarrier(b, 0); 427 } 428 429 BASE_EXPORT b32 430 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms) 431 { 432 return WaitOnAddress(value, ¤t, sizeof(*value), timeout_ms); 433 } 434 435 BASE_EXPORT void 436 os_wake_all_waiters(i32 *sync) 437 { 438 if (sync) { 439 atomic_store_u32(sync, 0); 440 WakeByAddressAll(sync); 441 } 442 } 443 444 #if !BASE_PLATFORM_NO_MAIN 445 BASE_IMPORT void entry_point(i32 argc, char *argv[]); 446 447 extern i32 448 main(i32 argc, char *argv[]) 449 { 450 os_system_info_init(); 451 os_w32_context.arena = arena_create(.name = "Platform Arena"); 452 os_w32_context.error_handle = GetStdHandle(STD_ERROR_HANDLE); 453 454 entry_point(argc, argv); 455 456 return 0; 457 } 458 #endif