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 (7727B)


      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 str8
    186 os_read_entire_file(Arena *arena, const char *file)
    187 {
    188 	str8 result = {0};
    189 	struct stat sb;
    190 	i32 fd = open(file, O_RDONLY);
    191 	if (fd >= 0 && fstat(fd, &sb) >= 0) {
    192 		result.data = push_array(arena, u8, sb.st_size);
    193 		do {
    194 			i64 rlen = read(fd, result.data + result.length, (u64)(sb.st_size - result.length));
    195 			if (rlen > 0) result.length += rlen;
    196 		} while (result.length != sb.st_size && errno != EINTR);
    197 		if (result.length != sb.st_size) {
    198 			arena_pop(arena, sb.st_size);
    199 			zero_struct(&result);
    200 		}
    201 	}
    202 	if (fd >= 0) close(fd);
    203 
    204 	return result;
    205 }
    206 
    207 function b32
    208 os_write_new_file(char *fname, str8 raw)
    209 {
    210 	b32 result = 0;
    211 	i32 fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600);
    212 	if (fd != INVALID_FILE) {
    213 		result = os_write_file(fd, raw.data, raw.length);
    214 		close(fd);
    215 	}
    216 	return result;
    217 }
    218 
    219 function b32
    220 os_file_exists(char *path)
    221 {
    222 	struct stat st;
    223 	b32 result = stat(path, &st) == 0;
    224 	return result;
    225 }
    226 
    227 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */
    228 function b32
    229 os_copy_file(char *name, char *new)
    230 {
    231 	b32 result = 0;
    232 	struct stat sb;
    233 	if (stat(name, &sb) == 0) {
    234 		i32 fd_old = open(name, O_RDONLY);
    235 		i32 fd_new = open(new,  O_WRONLY|O_CREAT, sb.st_mode);
    236 		if (fd_old >= 0 && fd_new >= 0) {
    237 			u8 buf[4096];
    238 			i64 copied = 0;
    239 			while (copied != sb.st_size) {
    240 				i64 r = read(fd_old, buf, countof(buf));
    241 				if (r < 0) break;
    242 				i64 w = write(fd_new, buf, (u64)r);
    243 				if (w < 0) break;
    244 				copied += w;
    245 			}
    246 			result = copied == sb.st_size;
    247 		}
    248 		if (fd_old != -1) close(fd_old);
    249 		if (fd_new != -1) close(fd_new);
    250 	}
    251 	return result;
    252 }
    253 
    254 function OSLinuxEntity *
    255 os_entity_allocate(OSLinuxEntityKind kind)
    256 {
    257 	OSLinuxEntity *result = 0;
    258 	DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
    259 	{
    260 		result = SLLPopFreelist(os_linux_context.entity_freelist);
    261 		if (!result) result = push_struct_no_zero(os_linux_context.arena, OSLinuxEntity);
    262 	}
    263 
    264 	zero_struct(result);
    265 	result->kind = kind;
    266 	return result;
    267 }
    268 
    269 BASE_EXPORT OSThread
    270 os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn)
    271 {
    272 	pthread_t thread;
    273 	pthread_create(&thread, 0, (void *)fn, (void *)user_context);
    274 
    275 	if (name) {
    276 		char buffer[16];
    277 		str8 name_str = str8_from_c_str((char *)name);
    278 		u64  length   = (u64)Clamp(name_str.length, 0, countof(buffer) - 1);
    279 		memory_copy(buffer, (char *)name, length);
    280 		buffer[length] = 0;
    281 		pthread_setname_np(thread, buffer);
    282 	}
    283 
    284 	OSThread result = {(u64)thread};
    285 	return result;
    286 }
    287 
    288 BASE_EXPORT OSBarrier
    289 os_barrier_alloc(u32 count)
    290 {
    291 	OSBarrier result = {0};
    292 	DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
    293 	{
    294 		pthread_barrier_t *barrier = push_struct(os_linux_context.arena, pthread_barrier_t);
    295 		pthread_barrier_init(barrier, 0, count);
    296 		result.value[0] = (u64)barrier;
    297 	}
    298 	return result;
    299 }
    300 
    301 BASE_EXPORT void
    302 os_barrier_enter(OSBarrier barrier)
    303 {
    304 	pthread_barrier_t *b = (pthread_barrier_t *)barrier.value[0];
    305 	if (b) pthread_barrier_wait(b);
    306 }
    307 
    308 BASE_EXPORT b32
    309 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms)
    310 {
    311 	struct timespec *timeout = 0, timeout_value;
    312 	if (timeout_ms != (u32)-1) {
    313 		timeout_value.tv_sec  = timeout_ms / 1000;
    314 		timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000;
    315 		timeout = &timeout_value;
    316 	}
    317 	return syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0) == 0;
    318 }
    319 
    320 BASE_EXPORT void
    321 os_wake_all_waiters(i32 *sync)
    322 {
    323 	if (sync) {
    324 		atomic_store_u32(sync, 0);
    325 		syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0);
    326 	}
    327 }
    328 
    329 #if !BASE_PLATFORM_NO_MAIN
    330 BASE_IMPORT void entry_point(i32 argc, char *argv[]);
    331 
    332 extern i32
    333 main(i32 argc, char *argv[])
    334 {
    335 	os_system_info_init();
    336 	os_linux_context.arena = arena_create(.name = "Platform Arena");
    337 
    338 	entry_point(argc, argv);
    339 
    340 	return 0;
    341 }
    342 #endif