ogl_beamforming

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

os_win32.c (10828B)


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