ogl_beamforming

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

base_linux.c (7954B)


      1 /* See LICENSE for license details. */
      2 
      3 /* NOTE(rnp): provides the platform layer for everything in this repo. */
      4 
      5 #define OS_SHARED_MEMORY_NAME  "/ogl_beamformer_shared_memory"
      6 
      7 #define OS_PATH_SEPARATOR_CHAR '/'
      8 #define OS_PATH_SEPARATOR      "/"
      9 
     10 #include "base_platform.h"
     11 
     12 #include "util.h"
     13 
     14 #include <errno.h>
     15 #include <fcntl.h>
     16 #include <linux/futex.h>
     17 #include <poll.h>
     18 #include <pthread.h>
     19 #include <sys/auxv.h>
     20 #include <sys/inotify.h>
     21 #include <sys/mman.h>
     22 #include <sys/stat.h>
     23 #include <sys/syscall.h>
     24 #include <sys/sysinfo.h>
     25 #include <unistd.h>
     26 
     27 typedef struct OSLinuxEntity OSLinuxEntity;
     28 typedef struct {
     29 	void          *handle;
     30 	OSLinuxEntity *prev, *next;
     31 } OSLinuxWindow;
     32 
     33 typedef enum {
     34 	OSLinuxFileWatchKind_Platform,
     35 	OSLinuxFileWatchKind_User,
     36 } OSLinuxFileWatchKind;
     37 
     38 typedef struct OSLinuxFileWatchDirectory OSLinuxFileWatchDirectory;
     39 typedef struct OSLinuxFileWatch OSLinuxFileWatch;
     40 struct OSLinuxFileWatch {
     41 	OSLinuxFileWatchKind  kind;
     42 	u64                   hash;
     43 	u64                   update_time;
     44 	void                 *user_context;
     45 
     46 	OSLinuxFileWatchDirectory *parent;
     47 	OSLinuxFileWatch *prev, *next;
     48 };
     49 
     50 struct OSLinuxFileWatchDirectory {
     51 	u64  hash;
     52 	i64  handle;
     53 	str8 name;
     54 
     55 	OSLinuxFileWatch *first_child;
     56 	OSLinuxFileWatch *last_child;
     57 	OSLinuxFileWatchDirectory *prev, *next;
     58 };
     59 
     60 typedef enum {
     61 	OSLinuxEntityKind_Window,
     62 	OSLinuxEntityKind_FileWatch,
     63 	OSLinuxEntityKind_FileWatchDirectory,
     64 } OSLinuxEntityKind;
     65 
     66 struct OSLinuxEntity {
     67 	OSLinuxEntityKind kind;
     68 	union {
     69 		OSLinuxFileWatch          file_watch;
     70 		OSLinuxFileWatchDirectory file_watch_directory;
     71 		OSLinuxWindow             window;
     72 	} as;
     73 	OSLinuxEntity *next;
     74 };
     75 
     76 typedef struct {
     77 	OSSystemInfo  system_info;
     78 
     79 	Arena        *arena;
     80 	i32           arena_lock;
     81 
     82 	i32           inotify_handle;
     83 
     84 	struct {
     85 		OSLinuxFileWatchDirectory *first;
     86 		OSLinuxFileWatchDirectory *last;
     87 	} file_watch_directories;
     88 
     89 	struct {
     90 		OSLinuxEntity *first;
     91 		OSLinuxEntity *last;
     92 	} windows;
     93 
     94 	OSLinuxEntity *entity_freelist;
     95 } OSLinux_Context;
     96 global OSLinux_Context os_linux_context;
     97 
     98 function b32
     99 os_write_file(i32 file, void *data, i64 length)
    100 {
    101 	i64 offset = 0;
    102 	while (offset < length) {
    103 		i64 r = write(file, (u8 *)data + offset, (u64)(length - offset));
    104 		if (r < 0 && errno != EINTR) break;
    105 		if (r >= 0) offset += r;
    106 	}
    107 	return offset == length;
    108 }
    109 
    110 BASE_EXPORT no_return void
    111 os_exit(i32 code)
    112 {
    113 	_exit(code);
    114 	unreachable();
    115 }
    116 
    117 function u64
    118 os_timer_frequency(void)
    119 {
    120 	return 1000000000ULL;
    121 }
    122 
    123 BASE_EXPORT u64
    124 os_timer_count(void)
    125 {
    126 	struct timespec time = {0};
    127 	clock_gettime(CLOCK_MONOTONIC, &time);
    128 	u64 result = (u64)time.tv_sec * 1000000000ULL + (u64)time.tv_nsec;
    129 	return result;
    130 }
    131 
    132 function u64
    133 os_number_of_processors(void)
    134 {
    135 	u64 set[128 / sizeof(u64)] = {0};
    136 	syscall(SYS_sched_getaffinity, 0, sizeof(set), set);
    137 
    138 	u64 result = 0;
    139 	for EachElement(set, it)
    140 		result += popcount_u64(set[it]);
    141 	return result > 0 ? result : 1;
    142 }
    143 
    144 function void
    145 os_system_info_init(void)
    146 {
    147 	os_linux_context.system_info.timer_frequency         = os_timer_frequency();
    148 	os_linux_context.system_info.logical_processor_count = os_number_of_processors();
    149 	os_linux_context.system_info.page_size               = ARCH_X64? KB(4) : getauxval(AT_PAGESZ);
    150 	os_linux_context.system_info.path_separator_byte     = '/';
    151 }
    152 
    153 BASE_EXPORT OSSystemInfo *
    154 os_system_info(void)
    155 {
    156 	#if BASE_PLATFORM_NO_MAIN
    157 	if unlikely(os_linux_context.system_info.path_separator_byte == 0)
    158 		os_system_info_init();
    159 	#endif
    160 	return &os_linux_context.system_info;
    161 }
    162 
    163 BASE_EXPORT void *
    164 os_memory_reserve(u64 size)
    165 {
    166 	void *result = mmap(0, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    167 	if (result == MAP_FAILED)
    168 		result = 0;
    169 	return result;
    170 }
    171 
    172 BASE_EXPORT void
    173 os_memory_release(void *base, u64 size)
    174 {
    175 	munmap(base, size);
    176 }
    177 
    178 BASE_EXPORT b32
    179 os_memory_commit(void *base, u64 size)
    180 {
    181 	mprotect(base, size, PROT_READ|PROT_WRITE);
    182 	return 1;
    183 }
    184 
    185 BASE_EXPORT void
    186 os_memory_uncommit(void *base, u64 size)
    187 {
    188 	madvise(base, size, MADV_DONTNEED);
    189 	mprotect(base, size, PROT_NONE);
    190 }
    191 
    192 BASE_EXPORT void
    193 os_memory_seal(void *base, u64 size)
    194 {
    195 	mprotect(base, size, PROT_READ);
    196 }
    197 
    198 BASE_EXPORT str8
    199 os_read_entire_file(Arena *arena, const char *file)
    200 {
    201 	str8 result = {0};
    202 	struct stat sb;
    203 	i32 fd = open(file, O_RDONLY);
    204 	if (fd >= 0 && fstat(fd, &sb) >= 0) {
    205 		result.data = push_array(arena, u8, sb.st_size);
    206 		do {
    207 			i64 rlen = read(fd, result.data + result.length, (u64)(sb.st_size - result.length));
    208 			if (rlen > 0) result.length += rlen;
    209 		} while (result.length != sb.st_size && errno != EINTR);
    210 		if (result.length != sb.st_size) {
    211 			arena_pop(arena, sb.st_size);
    212 			zero_struct(&result);
    213 		}
    214 	}
    215 	if (fd >= 0) close(fd);
    216 
    217 	return result;
    218 }
    219 
    220 function b32
    221 os_write_new_file(char *fname, str8 raw)
    222 {
    223 	b32 result = 0;
    224 	i32 fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600);
    225 	if (fd != INVALID_FILE) {
    226 		result = os_write_file(fd, raw.data, raw.length);
    227 		close(fd);
    228 	}
    229 	return result;
    230 }
    231 
    232 function b32
    233 os_file_exists(char *path)
    234 {
    235 	struct stat st;
    236 	b32 result = stat(path, &st) == 0;
    237 	return result;
    238 }
    239 
    240 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */
    241 function b32
    242 os_copy_file(char *name, char *new)
    243 {
    244 	b32 result = 0;
    245 	struct stat sb;
    246 	if (stat(name, &sb) == 0) {
    247 		i32 fd_old = open(name, O_RDONLY);
    248 		i32 fd_new = open(new,  O_WRONLY|O_CREAT, sb.st_mode);
    249 		if (fd_old >= 0 && fd_new >= 0) {
    250 			u8 buf[4096];
    251 			i64 copied = 0;
    252 			while (copied != sb.st_size) {
    253 				i64 r = read(fd_old, buf, countof(buf));
    254 				if (r < 0) break;
    255 				i64 w = write(fd_new, buf, (u64)r);
    256 				if (w < 0) break;
    257 				copied += w;
    258 			}
    259 			result = copied == sb.st_size;
    260 		}
    261 		if (fd_old != -1) close(fd_old);
    262 		if (fd_new != -1) close(fd_new);
    263 	}
    264 	return result;
    265 }
    266 
    267 function OSLinuxEntity *
    268 os_entity_allocate(OSLinuxEntityKind kind)
    269 {
    270 	OSLinuxEntity *result = 0;
    271 	DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
    272 	{
    273 		result = SLLPopFreelist(os_linux_context.entity_freelist);
    274 		if (!result) result = push_struct_no_zero(os_linux_context.arena, OSLinuxEntity);
    275 	}
    276 
    277 	zero_struct(result);
    278 	result->kind = kind;
    279 	return result;
    280 }
    281 
    282 BASE_EXPORT OSThread
    283 os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn)
    284 {
    285 	pthread_t thread;
    286 	pthread_create(&thread, 0, (void *)fn, (void *)user_context);
    287 
    288 	if (name) {
    289 		char buffer[16];
    290 		str8 name_str = str8_from_c_str((char *)name);
    291 		u64  length   = (u64)Clamp(name_str.length, 0, countof(buffer) - 1);
    292 		memory_copy(buffer, (char *)name, length);
    293 		buffer[length] = 0;
    294 		pthread_setname_np(thread, buffer);
    295 	}
    296 
    297 	OSThread result = {(u64)thread};
    298 	return result;
    299 }
    300 
    301 BASE_EXPORT OSBarrier
    302 os_barrier_alloc(u32 count)
    303 {
    304 	OSBarrier result = {0};
    305 	DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
    306 	{
    307 		pthread_barrier_t *barrier = push_struct(os_linux_context.arena, pthread_barrier_t);
    308 		pthread_barrier_init(barrier, 0, count);
    309 		result.value[0] = (u64)barrier;
    310 	}
    311 	return result;
    312 }
    313 
    314 BASE_EXPORT void
    315 os_barrier_enter(OSBarrier barrier)
    316 {
    317 	pthread_barrier_t *b = (pthread_barrier_t *)barrier.value[0];
    318 	if (b) pthread_barrier_wait(b);
    319 }
    320 
    321 BASE_EXPORT b32
    322 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms)
    323 {
    324 	struct timespec *timeout = 0, timeout_value;
    325 	if (timeout_ms != (u32)-1) {
    326 		timeout_value.tv_sec  = timeout_ms / 1000;
    327 		timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000;
    328 		timeout = &timeout_value;
    329 	}
    330 	return syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0) == 0;
    331 }
    332 
    333 BASE_EXPORT void
    334 os_wake_all_waiters(i32 *sync)
    335 {
    336 	if (sync) {
    337 		atomic_store_u32(sync, 0);
    338 		syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0);
    339 	}
    340 }
    341 
    342 #if !BASE_PLATFORM_NO_MAIN
    343 BASE_IMPORT void entry_point(i32 argc, char *argv[]);
    344 
    345 extern i32
    346 main(i32 argc, char *argv[])
    347 {
    348 	os_system_info_init();
    349 	os_linux_context.arena = arena_create(.name = "Platform Arena");
    350 
    351 	entry_point(argc, argv);
    352 
    353 	return 0;
    354 }
    355 #endif