ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

os_win32.c (8744B)


      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 
     12 #define GENERIC_WRITE  0x40000000
     13 #define GENERIC_READ   0x80000000
     14 
     15 #define PIPE_TYPE_BYTE      0x00
     16 #define PIPE_ACCESS_INBOUND 0x01
     17 
     18 #define FILE_SHARE_READ            0x00000001
     19 #define FILE_MAP_ALL_ACCESS        0x000F001F
     20 #define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
     21 #define FILE_FLAG_OVERLAPPED       0x40000000
     22 
     23 #define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
     24 
     25 #define FILE_ACTION_MODIFIED 0x00000003
     26 
     27 #define CREATE_ALWAYS  2
     28 #define OPEN_EXISTING  3
     29 
     30 typedef struct {
     31 	u16  wProcessorArchitecture;
     32 	u16  _pad1;
     33 	u32  dwPageSize;
     34 	size lpMinimumApplicationAddress;
     35 	size lpMaximumApplicationAddress;
     36 	u64  dwActiveProcessorMask;
     37 	u32  dwNumberOfProcessors;
     38 	u32  dwProcessorType;
     39 	u32  dwAllocationGranularity;
     40 	u16  wProcessorLevel;
     41 	u16  wProcessorRevision;
     42 } w32_sys_info;
     43 
     44 /* NOTE: this is packed because the w32 api designers are dumb and ordered the members
     45  * incorrectly. They worked around it be making the ft* members a struct {u32, u32} which
     46  * is aligned on a 4-byte boundary. Then in their documentation they explicitly tell you not
     47  * to cast to u64 because "it can cause alignment faults on 64-bit Windows" - go figure */
     48 typedef struct __attribute__((packed)) {
     49 	u32 dwFileAttributes;
     50 	u64 ftCreationTime;
     51 	u64 ftLastAccessTime;
     52 	u64 ftLastWriteTime;
     53 	u32 dwVolumeSerialNumber;
     54 	u32 nFileSizeHigh;
     55 	u32 nFileSizeLow;
     56 	u32 nNumberOfLinks;
     57 	u32 nFileIndexHigh;
     58 	u32 nFileIndexLow;
     59 } w32_file_info;
     60 
     61 typedef struct {
     62 	u32 next_entry_offset;
     63 	u32 action;
     64 	u32 filename_size;
     65 	u16 filename[];
     66 } w32_file_notify_info;
     67 
     68 typedef struct {
     69 	uptr internal, internal_high;
     70 	union {
     71 		struct {u32 off, off_high;};
     72 		iptr pointer;
     73 	};
     74 	iptr event_handle;
     75 } w32_overlapped;
     76 
     77 #define W32(r) __declspec(dllimport) r __stdcall
     78 W32(b32)    CloseHandle(iptr);
     79 W32(b32)    CopyFileA(c8 *, c8 *, b32);
     80 W32(iptr)   CreateFileA(c8 *, u32, u32, void *, u32, u32, void *);
     81 W32(iptr)   CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *);
     82 W32(iptr)   CreateIoCompletionPort(iptr, iptr, uptr, u32);
     83 W32(iptr)   CreateNamedPipeA(c8 *, u32, u32, u32, u32, u32, u32, void *);
     84 W32(b32)    DeleteFileA(c8 *);
     85 W32(void)   ExitProcess(i32);
     86 W32(b32)    FreeLibrary(void *);
     87 W32(b32)    GetFileInformationByHandle(iptr, w32_file_info *);
     88 W32(i32)    GetLastError(void);
     89 W32(void *) GetProcAddress(void *, c8 *);
     90 W32(b32)    GetQueuedCompletionStatus(iptr, u32 *, uptr *, w32_overlapped **, u32);
     91 W32(iptr)   GetStdHandle(i32);
     92 W32(void)   GetSystemInfo(void *);
     93 W32(void *) LoadLibraryA(c8 *);
     94 W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64);
     95 W32(b32)    PeekNamedPipe(iptr, u8 *, i32, i32 *, i32 *, i32 *);
     96 W32(b32)    ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *);
     97 W32(b32)    ReadFile(iptr, u8 *, i32, i32 *, void *);
     98 W32(b32)    WriteFile(iptr, u8 *, i32, i32 *, void *);
     99 W32(void *) VirtualAlloc(u8 *, size, u32, u32);
    100 W32(b32)    VirtualFree(u8 *, size, u32);
    101 
    102 static iptr win32_stderr_handle;
    103 
    104 static PLATFORM_WRITE_FILE_FN(os_write_file)
    105 {
    106 	i32 wlen;
    107 	WriteFile(file, raw.data, raw.len, &wlen, 0);
    108 	return raw.len == wlen;
    109 }
    110 
    111 static void
    112 os_write_err_msg(s8 msg)
    113 {
    114 	if (!win32_stderr_handle)
    115 		win32_stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
    116 	os_write_file(win32_stderr_handle, msg);
    117 }
    118 
    119 static void __attribute__((noreturn))
    120 os_fatal(s8 msg)
    121 {
    122 	os_write_err_msg(msg);
    123 	ExitProcess(1);
    124 	unreachable();
    125 }
    126 
    127 static PLATFORM_ALLOC_ARENA_FN(os_alloc_arena)
    128 {
    129 	Arena result;
    130 	w32_sys_info Info;
    131 	GetSystemInfo(&Info);
    132 
    133 	if (capacity % Info.dwPageSize != 0)
    134 		capacity += (Info.dwPageSize - capacity % Info.dwPageSize);
    135 
    136 	size oldsize = old.end - old.beg;
    137 	if (oldsize > capacity)
    138 		return old;
    139 
    140 	if (old.beg)
    141 		VirtualFree(old.beg, oldsize, MEM_RELEASE);
    142 
    143 	result.beg = VirtualAlloc(0, capacity, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    144 	if (result.beg == NULL)
    145 		os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
    146 	result.end = result.beg + capacity;
    147 	return result;
    148 }
    149 
    150 static PLATFORM_CLOSE_FN(os_close)
    151 {
    152 	CloseHandle(file);
    153 }
    154 
    155 static PLATFORM_OPEN_FOR_WRITE_FN(os_open_for_write)
    156 {
    157 	iptr result = CreateFileA(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
    158 	return result;
    159 }
    160 
    161 static s8
    162 os_read_file(Arena *a, char *file, size filesize)
    163 {
    164 	s8 result = {0};
    165 
    166 	if (filesize > 0 && filesize <= (size)U32_MAX) {
    167 		result = s8alloc(a, filesize);
    168 		iptr h = CreateFileA(file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
    169 		if (h >= 0) {
    170 			i32 rlen;
    171 			if (!ReadFile(h, result.data, result.len, &rlen, 0) || rlen != result.len) {
    172 				result = (s8){0};
    173 			}
    174 			CloseHandle(h);
    175 		}
    176 	}
    177 
    178 	return result;
    179 }
    180 
    181 static PLATFORM_WRITE_NEW_FILE_FN(os_write_new_file)
    182 {
    183 	if (raw.len > (size)U32_MAX) {
    184 		os_write_err_msg(s8("os_write_file: files >4GB are not yet handled on win32\n"));
    185 		return 0;
    186 	}
    187 
    188 	iptr h = CreateFileA(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
    189 	if (h == INVALID_FILE)
    190 		return  0;
    191 
    192 	b32 ret = os_write_file(h, raw);
    193 	CloseHandle(h);
    194 
    195 	return ret;
    196 }
    197 
    198 static FileStats
    199 os_get_file_stats(char *fname)
    200 {
    201 	iptr h = CreateFileA(fname, 0, 0, 0, OPEN_EXISTING, 0, 0);
    202 	if (h == INVALID_FILE)
    203 		return ERROR_FILE_STATS;
    204 
    205 	w32_file_info fileinfo;
    206 	if (!GetFileInformationByHandle(h, &fileinfo)) {
    207 		os_write_err_msg(s8("os_get_file_stats: couldn't get file info\n"));
    208 		CloseHandle(h);
    209 		return ERROR_FILE_STATS;
    210 	}
    211 	CloseHandle(h);
    212 
    213 	size filesize = (size)fileinfo.nFileSizeHigh << 32;
    214 	filesize     |= (size)fileinfo.nFileSizeLow;
    215 
    216 	return (FileStats){.filesize  = filesize, .timestamp = fileinfo.ftLastWriteTime};
    217 }
    218 
    219 static Pipe
    220 os_open_named_pipe(char *name)
    221 {
    222 	iptr h = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE, 1,
    223 	                          0, 1 * MEGABYTE, 0, 0);
    224 	return (Pipe){.file = h, .name = name};
    225 }
    226 
    227 static PLATFORM_READ_PIPE_FN(os_read_pipe)
    228 {
    229 	i32 total_read = 0;
    230 	ReadFile(pipe, buf, len, &total_read, 0);
    231 	return total_read;
    232 }
    233 
    234 static void *
    235 os_open_shared_memory_area(char *name, size cap)
    236 {
    237 	iptr h = CreateFileMappingA(-1, 0, PAGE_READWRITE, 0, cap, name);
    238 	if (h == INVALID_FILE)
    239 		return NULL;
    240 
    241 	return MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, cap);
    242 }
    243 
    244 static void *
    245 os_load_library(char *name, char *temp_name, Stream *e)
    246 {
    247 	if (temp_name) {
    248 		if (CopyFileA(name, temp_name, 0))
    249 			name = temp_name;
    250 	}
    251 
    252 	void *res = LoadLibraryA(name);
    253 	if (!res && e) {
    254 		s8 errs[] = {s8("WARNING: os_load_library("), cstr_to_s8(name), s8("): ")};
    255 		stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
    256 		stream_append_i64(e, GetLastError());
    257 		stream_append_byte(e, '\n');
    258 		os_write_err_msg(stream_to_s8(e));
    259 		e->widx = 0;
    260 	}
    261 
    262 	if (temp_name)
    263 		DeleteFileA(temp_name);
    264 
    265 	return res;
    266 }
    267 
    268 static void *
    269 os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
    270 {
    271 	if (!h)
    272 		return 0;
    273 	void *res = GetProcAddress(h, name);
    274 	if (!res && e) {
    275 		s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), cstr_to_s8(name), s8("): ")};
    276 		stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
    277 		stream_append_i64(e, GetLastError());
    278 		stream_append_byte(e, '\n');
    279 		os_write_err_msg(stream_to_s8(e));
    280 		e->widx = 0;
    281 	}
    282 	return res;
    283 }
    284 
    285 static void
    286 os_unload_library(void *h)
    287 {
    288 	FreeLibrary(h);
    289 }
    290 
    291 static PLATFORM_ADD_FILE_WATCH_FN(os_add_file_watch)
    292 {
    293 	s8 directory  = path;
    294 	directory.len = s8_scan_backwards(path, '\\');
    295 	ASSERT(directory.len > 0);
    296 
    297 	u64 hash = s8_hash(directory);
    298 	FileWatchContext *fwctx = &platform->file_watch_context;
    299 	FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash);
    300 	if (!dir) {
    301 		ASSERT(path.data[directory.len] == '\\');
    302 
    303 		dir         = fwctx->directory_watches + fwctx->directory_watch_count++;
    304 		dir->hash   = hash;
    305 
    306 		dir->name   = push_s8(a, directory);
    307 		arena_commit(a, 1);
    308 		dir->name.data[dir->name.len] = 0;
    309 
    310 		dir->handle = CreateFileA((c8 *)dir->name.data, GENERIC_READ, FILE_SHARE_READ, 0,
    311 		                          OPEN_EXISTING,
    312 		                          FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0);
    313 
    314 		w32_context *ctx = (w32_context *)platform->os_context;
    315 		w32_io_completion_event *event = push_struct(a, typeof(*event));
    316 		event->tag     = W32_IO_FILE_WATCH;
    317 		event->context = (iptr)dir;
    318 		CreateIoCompletionPort(dir->handle, ctx->io_completion_handle, (uptr)event, 0);
    319 
    320 		dir->buffer = sub_arena(a, 4096 + sizeof(w32_overlapped), 64);
    321 		w32_overlapped *overlapped = (w32_overlapped *)(dir->buffer.beg + 4096);
    322 		zero_struct(overlapped);
    323 
    324 		ReadDirectoryChangesW(dir->handle, dir->buffer.beg, 4096, 0,
    325 		                      FILE_NOTIFY_CHANGE_LAST_WRITE, 0, overlapped, 0);
    326 	}
    327 
    328 	insert_file_watch(dir, s8_cut_head(path, dir->name.len + 1), user_data, callback);
    329 }