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