os_win32.c (7150B)
1 /* See LICENSE for license details. */ 2 #include "util.h" 3 4 #define STD_OUTPUT_HANDLE -11 5 #define STD_ERROR_HANDLE -12 6 7 #define PAGE_READWRITE 0x04 8 #define MEM_COMMIT 0x1000 9 #define MEM_RESERVE 0x2000 10 #define MEM_RELEASE 0x8000 11 #define GENERIC_WRITE 0x40000000 12 #define GENERIC_READ 0x80000000 13 14 #define PIPE_TYPE_BYTE 0x00 15 #define PIPE_ACCESS_INBOUND 0x01 16 17 #define FILE_MAP_ALL_ACCESS 0x000F001F 18 19 #define CREATE_ALWAYS 2 20 #define OPEN_EXISTING 3 21 22 typedef struct { 23 u16 wProcessorArchitecture; 24 u16 _pad1; 25 u32 dwPageSize; 26 size lpMinimumApplicationAddress; 27 size lpMaximumApplicationAddress; 28 u64 dwActiveProcessorMask; 29 u32 dwNumberOfProcessors; 30 u32 dwProcessorType; 31 u32 dwAllocationGranularity; 32 u16 wProcessorLevel; 33 u16 wProcessorRevision; 34 } w32_sys_info; 35 36 /* NOTE: this is packed because the w32 api designers are dumb and ordered the members 37 * incorrectly. They worked around it be making the ft* members a struct {u32, u32} which 38 * is aligned on a 4-byte boundary. Then in their documentation they explicitly tell you not 39 * to cast to u64 because "it can cause alignment faults on 64-bit Windows" - go figure */ 40 typedef struct __attribute__((packed)) { 41 u32 dwFileAttributes; 42 u64 ftCreationTime; 43 u64 ftLastAccessTime; 44 u64 ftLastWriteTime; 45 u32 dwVolumeSerialNumber; 46 u32 nFileSizeHigh; 47 u32 nFileSizeLow; 48 u32 nNumberOfLinks; 49 u32 nFileIndexHigh; 50 u32 nFileIndexLow; 51 } w32_file_info; 52 53 #define W32(r) __declspec(dllimport) r __stdcall 54 W32(b32) CloseHandle(iptr); 55 W32(b32) CopyFileA(c8 *, c8 *, b32); 56 W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *); 57 W32(iptr) CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *); 58 W32(iptr) CreateNamedPipeA(c8 *, u32, u32, u32, u32, u32, u32, void *); 59 W32(b32) DeleteFileA(c8 *); 60 W32(void) ExitProcess(i32); 61 W32(b32) FreeLibrary(void *); 62 W32(b32) GetFileInformationByHandle(iptr, w32_file_info *); 63 W32(i32) GetLastError(void); 64 W32(void *) GetProcAddress(void *, c8 *); 65 W32(iptr) GetStdHandle(i32); 66 W32(void) GetSystemInfo(void *); 67 W32(void *) LoadLibraryA(c8 *); 68 W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64); 69 W32(b32) PeekNamedPipe(iptr, u8 *, i32, i32 *, i32 *, i32 *); 70 W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); 71 W32(b32) WriteFile(iptr, u8 *, i32, i32 *, void *); 72 W32(void *) VirtualAlloc(u8 *, size, u32, u32); 73 W32(b32) VirtualFree(u8 *, size, u32); 74 75 static iptr win32_stderr_handle; 76 77 static PLATFORM_WRITE_FILE_FN(os_write_file) 78 { 79 i32 wlen; 80 WriteFile(file, raw.data, raw.len, &wlen, 0); 81 return raw.len == wlen; 82 } 83 84 static void 85 os_write_err_msg(s8 msg) 86 { 87 if (!win32_stderr_handle) 88 win32_stderr_handle = GetStdHandle(STD_ERROR_HANDLE); 89 os_write_file(win32_stderr_handle, msg); 90 } 91 92 static void __attribute__((noreturn)) 93 os_fatal(s8 msg) 94 { 95 os_write_err_msg(msg); 96 ExitProcess(1); 97 unreachable(); 98 } 99 100 static PLATFORM_ALLOC_ARENA_FN(os_alloc_arena) 101 { 102 Arena result; 103 w32_sys_info Info; 104 GetSystemInfo(&Info); 105 106 if (capacity % Info.dwPageSize != 0) 107 capacity += (Info.dwPageSize - capacity % Info.dwPageSize); 108 109 size oldsize = old.end - old.beg; 110 if (oldsize > capacity) 111 return old; 112 113 if (old.beg) 114 VirtualFree(old.beg, oldsize, MEM_RELEASE); 115 116 result.beg = VirtualAlloc(0, capacity, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 117 if (result.beg == NULL) 118 os_fatal(s8("os_alloc_arena: couldn't allocate memory\n")); 119 result.end = result.beg + capacity; 120 return result; 121 } 122 123 static PLATFORM_CLOSE_FN(os_close) 124 { 125 CloseHandle(file); 126 } 127 128 static PLATFORM_OPEN_FOR_WRITE_FN(os_open_for_write) 129 { 130 iptr result = CreateFileA(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 131 return result; 132 } 133 134 static s8 135 os_read_file(Arena *a, char *fname, size fsize) 136 { 137 if (fsize < 0) 138 return (s8){.len = -1}; 139 140 if (fsize > (size)U32_MAX) { 141 os_write_err_msg(s8("os_read_file: files >4GB are not yet handled on win32\n")); 142 return (s8){.len = -1}; 143 } 144 145 iptr h = CreateFileA(fname, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 146 if (h == INVALID_FILE) 147 return (s8){.len = -1}; 148 149 s8 ret = s8alloc(a, fsize); 150 151 i32 rlen = 0; 152 b32 error = !ReadFile(h, ret.data, ret.len, &rlen, 0) || rlen != ret.len; 153 CloseHandle(h); 154 if (error) 155 return (s8){.len = -1}; 156 157 return ret; 158 } 159 160 static PLATFORM_WRITE_NEW_FILE_FN(os_write_new_file) 161 { 162 if (raw.len > (size)U32_MAX) { 163 os_write_err_msg(s8("os_write_file: files >4GB are not yet handled on win32\n")); 164 return 0; 165 } 166 167 iptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); 168 if (h == INVALID_FILE) 169 return 0; 170 171 b32 ret = os_write_file(h, raw); 172 CloseHandle(h); 173 174 return ret; 175 } 176 177 static FileStats 178 os_get_file_stats(char *fname) 179 { 180 iptr h = CreateFileA(fname, 0, 0, 0, OPEN_EXISTING, 0, 0); 181 if (h == INVALID_FILE) 182 return ERROR_FILE_STATS; 183 184 w32_file_info fileinfo; 185 if (!GetFileInformationByHandle(h, &fileinfo)) { 186 os_write_err_msg(s8("os_get_file_stats: couldn't get file info\n")); 187 CloseHandle(h); 188 return ERROR_FILE_STATS; 189 } 190 CloseHandle(h); 191 192 size filesize = (size)fileinfo.nFileSizeHigh << 32; 193 filesize |= (size)fileinfo.nFileSizeLow; 194 195 return (FileStats){.filesize = filesize, .timestamp = fileinfo.ftLastWriteTime}; 196 } 197 198 static Pipe 199 os_open_named_pipe(char *name) 200 { 201 iptr h = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE, 1, 202 0, 1 * MEGABYTE, 0, 0); 203 return (Pipe){.file = h, .name = name}; 204 } 205 206 /* NOTE: win32 doesn't pollute the filesystem so no need to waste the user's time */ 207 static void 208 os_close_named_pipe(Pipe p) 209 { 210 } 211 212 static PLATFORM_POLL_PIPE_FN(os_poll_pipe) 213 { 214 i32 bytes_available = 0; 215 return PeekNamedPipe(p.file, 0, 1 * MEGABYTE, 0, &bytes_available, 0) && bytes_available; 216 } 217 218 static PLATFORM_READ_PIPE_FN(os_read_pipe) 219 { 220 i32 total_read = 0; 221 ReadFile(pipe, buf, len, &total_read, 0); 222 return total_read; 223 } 224 225 static void * 226 os_open_shared_memory_area(char *name, size cap) 227 { 228 iptr h = CreateFileMappingA(-1, 0, PAGE_READWRITE, 0, cap, name); 229 if (h == INVALID_FILE) 230 return NULL; 231 232 return MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, cap); 233 } 234 235 /* NOTE: closing the handle releases the memory and this happens when program terminates */ 236 static void 237 os_remove_shared_memory(char *name) 238 { 239 } 240 241 static void * 242 os_load_library(char *name, char *temp_name, Stream *e) 243 { 244 if (temp_name) { 245 if (CopyFileA(name, temp_name, 0)) 246 name = temp_name; 247 } 248 249 void *res = LoadLibraryA(name); 250 if (!res && e) { 251 s8 errs[] = {s8("WARNING: os_load_library("), cstr_to_s8(name), s8("): ")}; 252 stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); 253 stream_append_i64(e, GetLastError()); 254 stream_append_byte(e, '\n'); 255 os_write_err_msg(stream_to_s8(e)); 256 e->widx = 0; 257 } 258 259 if (temp_name) 260 DeleteFileA(temp_name); 261 262 return res; 263 } 264 265 static void * 266 os_lookup_dynamic_symbol(void *h, char *name, Stream *e) 267 { 268 if (!h) 269 return 0; 270 void *res = GetProcAddress(h, name); 271 if (!res && e) { 272 s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), cstr_to_s8(name), s8("): ")}; 273 stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); 274 stream_append_i64(e, GetLastError()); 275 stream_append_byte(e, '\n'); 276 os_write_err_msg(stream_to_s8(e)); 277 e->widx = 0; 278 } 279 return res; 280 } 281 282 static void 283 os_unload_library(void *h) 284 { 285 FreeLibrary(h); 286 }