ogl_beamforming

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

os_linux.c (6383B)


      1 /* See LICENSE for license details. */
      2 
      3 /* NOTE(rnp): provides the platform layer for the beamformer. This code must
      4  * be provided by any platform the beamformer is ported to. */
      5 
      6 #define OS_SHARED_MEMORY_NAME "/ogl_beamformer_shared_memory"
      7 #define OS_EXPORT_PIPE_NAME   "/tmp/beamformer_output_pipe"
      8 
      9 #include "util.h"
     10 
     11 #include <dlfcn.h>
     12 #include <fcntl.h>
     13 #include <linux/futex.h>
     14 #include <poll.h>
     15 #include <pthread.h>
     16 #include <sys/inotify.h>
     17 #include <sys/mman.h>
     18 #include <sys/stat.h>
     19 #include <sys/syscall.h>
     20 #include <unistd.h>
     21 
     22 /* NOTE(rnp): hidden behind feature flags -> screw compiler/standards idiots */
     23 i32 ftruncate(i32, i64);
     24 i64 syscall(i64, ...);
     25 
     26 #ifdef _DEBUG
     27 static void *
     28 os_get_module(char *name, Stream *e)
     29 {
     30 	void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD);
     31 	if (!result && e) {
     32 		stream_append_s8s(e, s8("os_get_module(\""), c_str_to_s8(name), s8("\"): "),
     33 		                  c_str_to_s8(dlerror()), s8("\n"));
     34 	}
     35 	return result;
     36 }
     37 #endif
     38 
     39 static OS_WRITE_FILE_FN(os_write_file)
     40 {
     41 	while (raw.len) {
     42 		iz r = write(file, raw.data, raw.len);
     43 		if (r < 0) return 0;
     44 		raw = s8_cut_head(raw, r);
     45 	}
     46 	return 1;
     47 }
     48 
     49 function void __attribute__((noreturn))
     50 os_exit(i32 code)
     51 {
     52 	_exit(code);
     53 	unreachable();
     54 }
     55 
     56 function void __attribute__((noreturn))
     57 os_fatal(s8 msg)
     58 {
     59 	os_write_file(STDERR_FILENO, msg);
     60 	os_exit(1);
     61 	unreachable();
     62 }
     63 
     64 function OS_ALLOC_ARENA_FN(os_alloc_arena)
     65 {
     66 	Arena result;
     67 	iz pagesize = sysconf(_SC_PAGESIZE);
     68 	if (capacity % pagesize != 0)
     69 		capacity += pagesize - capacity % pagesize;
     70 
     71 	iz oldsize = old.end - old.beg;
     72 	if (oldsize > capacity)
     73 		return old;
     74 
     75 	if (old.beg)
     76 		munmap(old.beg, oldsize);
     77 
     78 	result.beg = mmap(0, capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
     79 	if (result.beg == MAP_FAILED)
     80 		os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
     81 	result.end = result.beg + capacity;
     82 	return result;
     83 }
     84 
     85 static OS_CLOSE_FN(os_close)
     86 {
     87 	close(file);
     88 }
     89 
     90 static OS_OPEN_FOR_WRITE_FN(os_open_for_write)
     91 {
     92 	iptr result = open(fname, O_WRONLY|O_TRUNC);
     93 	if (result == -1)
     94 		result = INVALID_FILE;
     95 	return result;
     96 }
     97 
     98 function OS_READ_WHOLE_FILE_FN(os_read_whole_file)
     99 {
    100 	s8 result = s8("");
    101 
    102 	struct stat sb;
    103 	i32 fd = open(file, O_RDONLY);
    104 	if (fd >= 0 && fstat(fd, &sb) >= 0) {
    105 		result = s8_alloc(arena, sb.st_size);
    106 		iz rlen = read(fd, result.data, result.len);
    107 		if (rlen != result.len)
    108 			result = s8("");
    109 	}
    110 	if (fd >= 0) close(fd);
    111 
    112 	return result;
    113 }
    114 
    115 static OS_WRITE_NEW_FILE_FN(os_write_new_file)
    116 {
    117 	iptr fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600);
    118 	if (fd == INVALID_FILE)
    119 		return 0;
    120 	b32 ret = os_write_file(fd, raw);
    121 	close(fd);
    122 	return ret;
    123 }
    124 
    125 static b32
    126 os_file_exists(char *path)
    127 {
    128 	struct stat st;
    129 	b32 result = stat(path, &st) == 0;
    130 	return result;
    131 }
    132 
    133 static OS_READ_FILE_FN(os_read_file)
    134 {
    135 	iz r = 0, total_read = 0;
    136 	do {
    137 		if (r != -1)
    138 			total_read += r;
    139 		r = read(file, buf + total_read, size - total_read);
    140 	} while (r);
    141 	return total_read;
    142 }
    143 
    144 function void *
    145 os_create_shared_memory_area(char *name, iz cap)
    146 {
    147 	void *result = 0;
    148 	i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    149 	if (fd > 0 && ftruncate(fd, cap) != -1) {
    150 		void *new = mmap(NULL, cap, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    151 		if (new != MAP_FAILED)
    152 			result = new;
    153 	}
    154 	if (fd > 0) close(fd);
    155 	return result;
    156 }
    157 
    158 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */
    159 function b32
    160 os_copy_file(char *name, char *new)
    161 {
    162 	b32 result = 0;
    163 	struct stat sb;
    164 	if (stat(name, &sb) == 0) {
    165 		i32 fd_old = open(name, O_RDONLY);
    166 		i32 fd_new = open(new,  O_WRONLY|O_CREAT, sb.st_mode);
    167 		if (fd_old >= 0 && fd_new >= 0) {
    168 			u8 buf[4096];
    169 			iz copied = 0;
    170 			while (copied != sb.st_size) {
    171 				iz r = read(fd_old, buf, countof(buf));
    172 				if (r < 0) break;
    173 				iz w = write(fd_new, buf, r);
    174 				if (w < 0) break;
    175 				copied += w;
    176 			}
    177 			result = copied == sb.st_size;
    178 		}
    179 		if (fd_old != -1) close(fd_old);
    180 		if (fd_new != -1) close(fd_new);
    181 	}
    182 	return result;
    183 }
    184 
    185 function void *
    186 os_load_library(char *name, char *temp_name, Stream *e)
    187 {
    188 	if (temp_name) {
    189 		if (os_copy_file(name, temp_name))
    190 			name = temp_name;
    191 	}
    192 
    193 	void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL);
    194 	if (!result && e) {
    195 		stream_append_s8s(e, s8("os_load_library(\""), c_str_to_s8(name), s8("\"): "),
    196 		                  c_str_to_s8(dlerror()), s8("\n"));
    197 	}
    198 
    199 	if (temp_name)
    200 		unlink(temp_name);
    201 
    202 	return result;
    203 }
    204 
    205 static void *
    206 os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
    207 {
    208 	void *result = 0;
    209 	if (h) {
    210 		result = dlsym(h, name);
    211 		if (!result && e) {
    212 			stream_append_s8s(e, s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name),
    213 			                  s8("\"): "), c_str_to_s8(dlerror()), s8("\n"));
    214 		}
    215 	}
    216 	return result;
    217 }
    218 
    219 static void
    220 os_unload_library(void *h)
    221 {
    222 	/* NOTE: glibc is buggy gnuware so we need to check this */
    223 	if (h)
    224 		dlclose(h);
    225 }
    226 
    227 static OS_ADD_FILE_WATCH_FN(os_add_file_watch)
    228 {
    229 	s8 directory  = path;
    230 	directory.len = s8_scan_backwards(path, '/');
    231 	ASSERT(directory.len > 0);
    232 
    233 	u64 hash = s8_hash(directory);
    234 	FileWatchContext *fwctx = &os->file_watch_context;
    235 	FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash);
    236 	if (!dir) {
    237 		ASSERT(path.data[directory.len] == '/');
    238 		dir = da_push(a, fwctx);
    239 		dir->hash   = hash;
    240 		dir->name   = push_s8_zero(a, directory);
    241 		i32 mask    = IN_MOVED_TO|IN_CLOSE_WRITE;
    242 		dir->handle = inotify_add_watch(fwctx->handle, (c8 *)dir->name.data, mask);
    243 	}
    244 
    245 	FileWatch *fw = da_push(a, dir);
    246 	fw->user_data = user_data;
    247 	fw->callback  = callback;
    248 	fw->hash      = s8_hash(s8_cut_head(path, dir->name.len + 1));
    249 }
    250 
    251 i32 pthread_setname_np(pthread_t, char *);
    252 function iptr
    253 os_create_thread(Arena arena, iptr user_context, s8 name, os_thread_entry_point_fn *fn)
    254 {
    255 	pthread_t result;
    256 	pthread_create(&result, 0, (void *(*)(void *))fn, (void *)user_context);
    257 	pthread_setname_np(result, (char *)name.data);
    258 	return (iptr)result;
    259 }
    260 
    261 static OS_WAIT_ON_VALUE_FN(os_wait_on_value)
    262 {
    263 	struct timespec *timeout = 0, timeout_value;
    264 	if (timeout_ms != (u32)-1) {
    265 		timeout_value.tv_sec  = timeout_ms / 1000;
    266 		timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000;
    267 		timeout = &timeout_value;
    268 	}
    269 	return syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0) == 0;
    270 }
    271 
    272 static OS_WAKE_WAITERS_FN(os_wake_waiters)
    273 {
    274 	if (sync) {
    275 		atomic_inc(sync, 1);
    276 		syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0);
    277 	}
    278 }