volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

os_win32.c (6621B)


      1 /* See LICENSE for license details. */
      2 #define OS_PATH_SEPARATOR_CHAR '\\'
      3 #define OS_PATH_SEPARATOR      "\\"
      4 
      5 #include "util.h"
      6 
      7 #define STD_INPUT_HANDLE  -10
      8 #define STD_OUTPUT_HANDLE -11
      9 #define STD_ERROR_HANDLE  -12
     10 
     11 #define PAGE_READWRITE 0x04
     12 #define MEM_COMMIT     0x1000
     13 #define MEM_RESERVE    0x2000
     14 #define MEM_RELEASE    0x8000
     15 
     16 #define GENERIC_WRITE  0x40000000
     17 #define GENERIC_READ   0x80000000
     18 
     19 #define FILE_SHARE_READ            0x00000001
     20 #define FILE_MAP_ALL_ACCESS        0x000F001F
     21 #define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
     22 #define FILE_FLAG_OVERLAPPED       0x40000000
     23 
     24 #define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
     25 
     26 #define FILE_ACTION_MODIFIED 0x00000003
     27 
     28 #define CREATE_ALWAYS  2
     29 #define OPEN_EXISTING  3
     30 
     31 #define THREAD_SET_LIMITED_INFORMATION 0x0400
     32 
     33 /* NOTE: this is packed because the w32 api designers are dumb and ordered the members
     34  * incorrectly. They worked around it be making the ft* members a struct {u32, u32} which
     35  * is aligned on a 4-byte boundary. Then in their documentation they explicitly tell you not
     36  * to cast to u64 because "it can cause alignment faults on 64-bit Windows" - go figure */
     37 typedef struct __attribute__((packed)) {
     38 	u32 dwFileAttributes;
     39 	u64 ftCreationTime;
     40 	u64 ftLastAccessTime;
     41 	u64 ftLastWriteTime;
     42 	u32 dwVolumeSerialNumber;
     43 	u32 nFileSizeHigh;
     44 	u32 nFileSizeLow;
     45 	u32 nNumberOfLinks;
     46 	u32 nFileIndexHigh;
     47 	u32 nFileIndexLow;
     48 } w32_file_info;
     49 
     50 typedef struct {
     51 	u32 next_entry_offset;
     52 	u32 action;
     53 	u32 filename_size;
     54 	u16 filename[];
     55 } w32_file_notify_info;
     56 
     57 typedef struct {
     58 	uptr internal, internal_high;
     59 	union {
     60 		struct {u32 off, off_high;};
     61 		sptr pointer;
     62 	};
     63 	sptr event_handle;
     64 } w32_overlapped;
     65 
     66 typedef struct {
     67 	sptr io_completion_handle;
     68 	u64  timer_start_time;
     69 	u64  timer_frequency;
     70 } w32_context;
     71 
     72 typedef enum {
     73 	W32_IO_FILE_WATCH,
     74 	W32_IO_PIPE,
     75 } W32_IO_Event;
     76 
     77 typedef struct {
     78 	u64  tag;
     79 	sptr context;
     80 } w32_io_completion_event;
     81 
     82 #define W32(r) __declspec(dllimport) r __stdcall
     83 W32(b32)    CloseHandle(sptr);
     84 W32(sptr)   CreateFileA(c8 *, u32, u32, void *, u32, u32, void *);
     85 W32(sptr)   CreateFileMappingA(sptr, void *, u32, u32, u32, c8 *);
     86 W32(sptr)   CreateIoCompletionPort(sptr, sptr, uptr, u32);
     87 W32(sptr)   CreateThread(sptr, uz, sptr, sptr, u32, u32 *);
     88 W32(void)   ExitProcess(s32);
     89 W32(b32)    GetFileInformationByHandle(sptr, void *);
     90 W32(s32)    GetLastError(void);
     91 W32(b32)    GetQueuedCompletionStatus(sptr, u32 *, uptr *, w32_overlapped **, u32);
     92 W32(sptr)   GetStdHandle(s32);
     93 W32(void)   GetSystemInfo(void *);
     94 W32(void *) MapViewOfFile(sptr, u32, u32, u32, u64);
     95 W32(b32)    ReadDirectoryChangesW(sptr, u8 *, u32, b32, u32, u32 *, void *, void *);
     96 W32(b32)    ReadFile(sptr, u8 *, s32, s32 *, void *);
     97 W32(b32)    ReleaseSemaphore(sptr, s64, s64 *);
     98 W32(s32)    SetThreadDescription(sptr, u16 *);
     99 W32(b32)    WaitOnAddress(void *, void *, uz, u32);
    100 W32(s32)    WakeByAddressAll(void *);
    101 W32(b32)    WriteFile(sptr, u8 *, s32, s32 *, void *);
    102 W32(void *) VirtualAlloc(u8 *, sz, u32, u32);
    103 W32(b32)    VirtualFree(u8 *, sz, u32);
    104 
    105 function OS_WRITE_FILE_FN(os_write_file)
    106 {
    107 	s32 wlen = 0;
    108 	if (raw.len > 0 && raw.len <= U32_MAX) WriteFile(file, raw.data, raw.len, &wlen, 0);
    109 	return raw.len == wlen;
    110 }
    111 
    112 function void __attribute__((noreturn))
    113 os_exit(s32 code)
    114 {
    115 	ExitProcess(code);
    116 	unreachable();
    117 }
    118 
    119 function void __attribute__((noreturn))
    120 os_fatal(str8 msg)
    121 {
    122 	os_write_file(GetStdHandle(STD_ERROR_HANDLE), msg);
    123 	os_exit(1);
    124 	unreachable();
    125 }
    126 
    127 function OS_ALLOC_ARENA_FN(os_alloc_arena)
    128 {
    129 	Arena result = {0};
    130 
    131 	struct {
    132 		u16  architecture;
    133 		u16  _pad1;
    134 		u32  page_size;
    135 		sz   minimum_application_address;
    136 		sz   maximum_application_address;
    137 		u64  active_processor_mask;
    138 		u32  number_of_processors;
    139 		u32  processor_type;
    140 		u32  allocation_granularity;
    141 		u16  processor_level;
    142 		u16  processor_revision;
    143 	} info;
    144 
    145 	GetSystemInfo(&info);
    146 
    147 	if (capacity % info.page_size != 0)
    148 		capacity += (info.page_size - capacity % info.page_size);
    149 
    150 	void *beg = VirtualAlloc(0, capacity, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    151 	if (beg) {
    152 		result.beg = beg;
    153 		result.end = result.beg + capacity;
    154 	}
    155 	return result;
    156 }
    157 
    158 function OS_READ_WHOLE_FILE_FN(os_read_whole_file)
    159 {
    160 	str8 result = str8("");
    161 
    162 	w32_file_info fileinfo;
    163 	sptr h = CreateFileA(file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
    164 	if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) {
    165 		sz filesize  = (sz)fileinfo.nFileSizeHigh << 32;
    166 		filesize    |= (sz)fileinfo.nFileSizeLow;
    167 		result       = str8_alloc(arena, filesize);
    168 
    169 		assert(filesize <= (sz)U32_MAX);
    170 
    171 		s32 rlen;
    172 		if (!ReadFile(h, result.data, result.len, &rlen, 0) || rlen != result.len)
    173 			result = str8("");
    174 	}
    175 	if (h >= 0) CloseHandle(h);
    176 
    177 	return result;
    178 }
    179 
    180 function OS_WRITE_NEW_FILE_FN(os_write_new_file)
    181 {
    182 	enum { CHUNK_SIZE = GB(2) };
    183 
    184 	b32 result = 0;
    185 	sptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
    186 	if (h >= 0) {
    187 		while (raw.len > 0) {
    188 			str8 chunk  = raw;
    189 			chunk.len = MIN(chunk.len, CHUNK_SIZE);
    190 			result    = os_write_file(h, chunk);
    191 			if (!result) break;
    192 			raw = str8_cut_head(raw, chunk.len);
    193 		}
    194 		CloseHandle(h);
    195 	}
    196 	return result;
    197 }
    198 
    199 function OS_ADD_FILE_WATCH_FN(os_add_file_watch)
    200 {
    201 	str8 directory  = path;
    202 	directory.len = str8_scan_backwards(path, '\\');
    203 	if (directory.len < 0) {
    204 		directory = str8(".");
    205 	} else {
    206 		path = str8_cut_head(path, directory.len + 1);
    207 	}
    208 
    209 	u64 hash = str8_hash(directory);
    210 	FileWatchContext *fwctx = &os->file_watch_context;
    211 	FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash);
    212 	if (!dir) {
    213 		dir = da_push(a, fwctx);
    214 		dir->hash   = hash;
    215 		dir->name   = push_str8_zero(a, directory);
    216 		dir->handle = CreateFileA((c8 *)dir->name.data, GENERIC_READ, FILE_SHARE_READ, 0,
    217 		                          OPEN_EXISTING,
    218 		                          FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0);
    219 
    220 		w32_context *ctx = (w32_context *)os->context;
    221 		w32_io_completion_event *event = push_struct(a, typeof(*event));
    222 		event->tag     = W32_IO_FILE_WATCH;
    223 		event->context = (sptr)dir;
    224 		CreateIoCompletionPort(dir->handle, ctx->io_completion_handle, (uptr)event, 0);
    225 
    226 		dir->buffer.beg = arena_alloc(a, 4096 + sizeof(w32_overlapped), 64, 1);
    227 		dir->buffer.end = dir->buffer.beg + 4096 + sizeof(w32_overlapped);
    228 		w32_overlapped *overlapped = (w32_overlapped *)(dir->buffer.beg + 4096);
    229 		zero_struct(overlapped);
    230 
    231 		ReadDirectoryChangesW(dir->handle, dir->buffer.beg, 4096, 0,
    232 		                      FILE_NOTIFY_CHANGE_LAST_WRITE, 0, overlapped, 0);
    233 	}
    234 
    235 	FileWatch *fw = da_push(a, dir);
    236 	fw->user_data = user_data;
    237 	fw->callback  = callback;
    238 	fw->hash      = str8_hash(path);
    239 }