ogl_beamforming

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

os_linux.c (6482B)


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