ogl_beamforming

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

os_linux.c (6288B)


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