os_win32.c (9419B)
1 /* See LICENSE for license details. */ 2 3 #define OS_SHARED_MEMORY_NAME "Local\\ogl_beamformer_parameters" 4 #define OS_EXPORT_PIPE_NAME "\\\\.\\pipe\\beamformer_output_pipe" 5 6 #include "util.h" 7 8 #define STD_INPUT_HANDLE -10 9 #define STD_OUTPUT_HANDLE -11 10 #define STD_ERROR_HANDLE -12 11 12 #define PAGE_READWRITE 0x04 13 #define MEM_COMMIT 0x1000 14 #define MEM_RESERVE 0x2000 15 #define MEM_RELEASE 0x8000 16 17 #define GENERIC_WRITE 0x40000000 18 #define GENERIC_READ 0x80000000 19 20 #define FILE_SHARE_READ 0x00000001 21 #define FILE_MAP_ALL_ACCESS 0x000F001F 22 #define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 23 #define FILE_FLAG_OVERLAPPED 0x40000000 24 25 #define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 26 27 #define FILE_ACTION_MODIFIED 0x00000003 28 29 #define CREATE_ALWAYS 2 30 #define OPEN_EXISTING 3 31 32 #define THREAD_SET_LIMITED_INFORMATION 0x0400 33 34 typedef struct { 35 u16 wProcessorArchitecture; 36 u16 _pad1; 37 u32 dwPageSize; 38 iz lpMinimumApplicationAddress; 39 iz lpMaximumApplicationAddress; 40 u64 dwActiveProcessorMask; 41 u32 dwNumberOfProcessors; 42 u32 dwProcessorType; 43 u32 dwAllocationGranularity; 44 u16 wProcessorLevel; 45 u16 wProcessorRevision; 46 } w32_sys_info; 47 48 /* NOTE: this is packed because the w32 api designers are dumb and ordered the members 49 * incorrectly. They worked around it be making the ft* members a struct {u32, u32} which 50 * is aligned on a 4-byte boundary. Then in their documentation they explicitly tell you not 51 * to cast to u64 because "it can cause alignment faults on 64-bit Windows" - go figure */ 52 typedef struct __attribute__((packed)) { 53 u32 dwFileAttributes; 54 u64 ftCreationTime; 55 u64 ftLastAccessTime; 56 u64 ftLastWriteTime; 57 u32 dwVolumeSerialNumber; 58 u32 nFileSizeHigh; 59 u32 nFileSizeLow; 60 u32 nNumberOfLinks; 61 u32 nFileIndexHigh; 62 u32 nFileIndexLow; 63 } w32_file_info; 64 65 typedef struct { 66 u32 next_entry_offset; 67 u32 action; 68 u32 filename_size; 69 u16 filename[]; 70 } w32_file_notify_info; 71 72 typedef struct { 73 uptr internal, internal_high; 74 union { 75 struct {u32 off, off_high;}; 76 iptr pointer; 77 }; 78 iptr event_handle; 79 } w32_overlapped; 80 81 typedef struct { 82 iptr io_completion_handle; 83 u64 timer_start_time; 84 u64 timer_frequency; 85 } w32_context; 86 87 typedef enum { 88 W32_IO_FILE_WATCH, 89 W32_IO_PIPE, 90 } W32_IO_Event; 91 92 typedef struct { 93 u64 tag; 94 iptr context; 95 } w32_io_completion_event; 96 97 #define W32(r) __declspec(dllimport) r __stdcall 98 W32(b32) CloseHandle(iptr); 99 W32(b32) CopyFileA(c8 *, c8 *, b32); 100 W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *); 101 W32(iptr) CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *); 102 W32(iptr) CreateIoCompletionPort(iptr, iptr, uptr, u32); 103 W32(iptr) CreateThread(iptr, uz, iptr, iptr, u32, u32 *); 104 W32(b32) DeleteFileA(c8 *); 105 W32(void) ExitProcess(i32); 106 W32(b32) FreeLibrary(void *); 107 W32(i32) GetFileAttributesA(c8 *); 108 W32(b32) GetFileInformationByHandle(iptr, w32_file_info *); 109 W32(i32) GetLastError(void); 110 W32(void *) GetModuleHandleA(c8 *); 111 W32(void *) GetProcAddress(void *, c8 *); 112 W32(b32) GetQueuedCompletionStatus(iptr, u32 *, uptr *, w32_overlapped **, u32); 113 W32(iptr) GetStdHandle(i32); 114 W32(void) GetSystemInfo(void *); 115 W32(void *) LoadLibraryA(c8 *); 116 W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64); 117 W32(b32) ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *); 118 W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); 119 W32(b32) ReleaseSemaphore(iptr, i64, i64 *); 120 W32(i32) SetThreadDescription(iptr, u16 *); 121 W32(b32) WaitOnAddress(void *, void *, uz, u32); 122 W32(i32) WakeByAddressAll(void *); 123 W32(b32) WriteFile(iptr, u8 *, i32, i32 *, void *); 124 W32(void *) VirtualAlloc(u8 *, iz, u32, u32); 125 W32(b32) VirtualFree(u8 *, iz, u32); 126 127 #ifdef _DEBUG 128 static void * 129 os_get_module(char *name, Stream *e) 130 { 131 void *result = GetModuleHandleA(name); 132 if (!result && e) { 133 stream_append_s8s(e, s8("os_get_module(\""), c_str_to_s8(name), s8("\"): ")); 134 stream_append_i64(e, GetLastError()); 135 stream_append_byte(e, '\n'); 136 } 137 return result; 138 } 139 #endif 140 141 static OS_WRITE_FILE_FN(os_write_file) 142 { 143 i32 wlen = 0; 144 if (raw.len) WriteFile(file, raw.data, raw.len, &wlen, 0); 145 return raw.len == wlen; 146 } 147 148 function void __attribute__((noreturn)) 149 os_exit(i32 code) 150 { 151 ExitProcess(1); 152 unreachable(); 153 } 154 155 function void __attribute__((noreturn)) 156 os_fatal(s8 msg) 157 { 158 os_write_file(GetStdHandle(STD_ERROR_HANDLE), msg); 159 os_exit(1); 160 unreachable(); 161 } 162 163 function OS_ALLOC_ARENA_FN(os_alloc_arena) 164 { 165 Arena result; 166 w32_sys_info Info; 167 GetSystemInfo(&Info); 168 169 if (capacity % Info.dwPageSize != 0) 170 capacity += (Info.dwPageSize - capacity % Info.dwPageSize); 171 172 iz oldsize = old.end - old.beg; 173 if (oldsize > capacity) 174 return old; 175 176 if (old.beg) 177 VirtualFree(old.beg, oldsize, MEM_RELEASE); 178 179 result.beg = VirtualAlloc(0, capacity, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 180 if (result.beg == NULL) 181 os_fatal(s8("os_alloc_arena: couldn't allocate memory\n")); 182 result.end = result.beg + capacity; 183 return result; 184 } 185 186 static OS_CLOSE_FN(os_close) 187 { 188 CloseHandle(file); 189 } 190 191 static OS_OPEN_FOR_WRITE_FN(os_open_for_write) 192 { 193 iptr result = CreateFileA(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 194 return result; 195 } 196 197 function OS_READ_WHOLE_FILE_FN(os_read_whole_file) 198 { 199 s8 result = s8(""); 200 201 w32_file_info fileinfo; 202 iptr h = CreateFileA(file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 203 if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) { 204 iz filesize = (iz)fileinfo.nFileSizeHigh << 32; 205 filesize |= (iz)fileinfo.nFileSizeLow; 206 result = s8_alloc(arena, filesize); 207 208 ASSERT(filesize <= (iz)U32_MAX); 209 210 i32 rlen; 211 if (!ReadFile(h, result.data, result.len, &rlen, 0) || rlen != result.len) 212 result = s8(""); 213 } 214 if (h >= 0) CloseHandle(h); 215 216 return result; 217 } 218 219 static OS_READ_FILE_FN(os_read_file) 220 { 221 i32 total_read = 0; 222 ReadFile(file, buf, size, &total_read, 0); 223 return total_read; 224 } 225 226 static OS_WRITE_NEW_FILE_FN(os_write_new_file) 227 { 228 if (raw.len > (iz)U32_MAX) { 229 os_write_file(GetStdHandle(STD_ERROR_HANDLE), 230 s8("os_write_file: files >4GB are not yet handled on win32\n")); 231 return 0; 232 } 233 234 iptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); 235 if (h == INVALID_FILE) 236 return 0; 237 238 b32 ret = os_write_file(h, raw); 239 CloseHandle(h); 240 241 return ret; 242 } 243 244 static b32 245 os_file_exists(char *path) 246 { 247 b32 result = GetFileAttributesA(path) != -1; 248 return result; 249 } 250 251 function void * 252 os_create_shared_memory_area(char *name, iz cap) 253 { 254 void *result = 0; 255 iptr h = CreateFileMappingA(-1, 0, PAGE_READWRITE, 0, cap, name); 256 if (h != INVALID_FILE) 257 result = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, cap); 258 return result; 259 } 260 261 function b32 262 os_copy_file(char *name, char *new) 263 { 264 return CopyFileA(name, new, 0); 265 } 266 267 function void * 268 os_load_library(char *name, char *temp_name, Stream *e) 269 { 270 if (temp_name && os_copy_file(name, temp_name)) 271 name = temp_name; 272 273 void *result = LoadLibraryA(name); 274 if (!result && e) { 275 stream_append_s8s(e, s8("os_load_library(\""), c_str_to_s8(name), s8("\"): ")); 276 stream_append_i64(e, GetLastError()); 277 stream_append_byte(e, '\n'); 278 } 279 280 if (temp_name) 281 DeleteFileA(temp_name); 282 283 return result; 284 } 285 286 static void * 287 os_lookup_dynamic_symbol(void *h, char *name, Stream *e) 288 { 289 void *result = 0; 290 if (h) { 291 result = GetProcAddress(h, name); 292 if (!result && e) { 293 stream_append_s8s(e, s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name), 294 s8("\"): ")); 295 stream_append_i64(e, GetLastError()); 296 stream_append_byte(e, '\n'); 297 } 298 } 299 return result; 300 } 301 302 static void 303 os_unload_library(void *h) 304 { 305 FreeLibrary(h); 306 } 307 308 static OS_ADD_FILE_WATCH_FN(os_add_file_watch) 309 { 310 s8 directory = path; 311 directory.len = s8_scan_backwards(path, '\\'); 312 ASSERT(directory.len > 0); 313 314 u64 hash = s8_hash(directory); 315 FileWatchContext *fwctx = &os->file_watch_context; 316 FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash); 317 if (!dir) { 318 ASSERT(path.data[directory.len] == '\\'); 319 320 dir = da_push(a, fwctx); 321 dir->hash = hash; 322 dir->name = push_s8_zero(a, directory); 323 dir->handle = CreateFileA((c8 *)dir->name.data, GENERIC_READ, FILE_SHARE_READ, 0, 324 OPEN_EXISTING, 325 FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0); 326 327 w32_context *ctx = (w32_context *)os->context; 328 w32_io_completion_event *event = push_struct(a, typeof(*event)); 329 event->tag = W32_IO_FILE_WATCH; 330 event->context = (iptr)dir; 331 CreateIoCompletionPort(dir->handle, ctx->io_completion_handle, (uptr)event, 0); 332 333 dir->buffer = sub_arena(a, 4096 + sizeof(w32_overlapped), 64); 334 w32_overlapped *overlapped = (w32_overlapped *)(dir->buffer.beg + 4096); 335 zero_struct(overlapped); 336 337 ReadDirectoryChangesW(dir->handle, dir->buffer.beg, 4096, 0, 338 FILE_NOTIFY_CHANGE_LAST_WRITE, 0, overlapped, 0); 339 } 340 341 FileWatch *fw = da_push(a, dir); 342 fw->user_data = user_data; 343 fw->callback = callback; 344 fw->hash = s8_hash(s8_cut_head(path, dir->name.len + 1)); 345 } 346 347 function iptr 348 os_create_thread(Arena arena, iptr user_context, s8 name, os_thread_entry_point_fn *fn) 349 { 350 iptr result = CreateThread(0, 0, (iptr)fn, user_context, 0, 0); 351 SetThreadDescription(result, s8_to_s16(&arena, name).data); 352 return result; 353 } 354 355 static OS_WAIT_ON_VALUE_FN(os_wait_on_value) 356 { 357 return WaitOnAddress(value, ¤t, sizeof(*value), timeout_ms); 358 } 359 360 static OS_WAKE_WAITERS_FN(os_wake_waiters) 361 { 362 if (sync) { 363 atomic_inc(sync, 1); 364 WakeByAddressAll(sync); 365 } 366 }