base_linux.c (4912B)
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 global OSSystemInfo linux_system_info; 28 29 function b32 30 os_write_file(i32 file, void *data, i64 length) 31 { 32 i64 offset = 0; 33 while (offset < length) { 34 i64 r = write(file, (u8 *)data + offset, (u64)(length - offset)); 35 if (r < 0 && errno != EINTR) break; 36 if (r >= 0) offset += r; 37 } 38 return offset == length; 39 } 40 41 BASE_EXPORT no_return void 42 os_exit(i32 code) 43 { 44 _exit(code); 45 unreachable(); 46 } 47 48 function u64 49 os_timer_frequency(void) 50 { 51 return 1000000000ULL; 52 } 53 54 BASE_EXPORT u64 55 os_timer_count(void) 56 { 57 struct timespec time = {0}; 58 clock_gettime(CLOCK_MONOTONIC, &time); 59 u64 result = (u64)time.tv_sec * 1000000000ULL + (u64)time.tv_nsec; 60 return result; 61 } 62 63 function u64 64 os_number_of_processors(void) 65 { 66 u64 set[128 / sizeof(u64)] = {0}; 67 syscall(SYS_sched_getaffinity, 0, sizeof(set), set); 68 69 u64 result = 0; 70 for EachElement(set, it) 71 result += popcount_u64(set[it]); 72 return result > 0 ? result : 1; 73 } 74 75 function void 76 os_system_info_init(void) 77 { 78 linux_system_info.timer_frequency = os_timer_frequency(); 79 linux_system_info.logical_processor_count = os_number_of_processors(); 80 linux_system_info.page_size = ARCH_X64? KB(4) : getauxval(AT_PAGESZ); 81 linux_system_info.path_separator_byte = '/'; 82 } 83 84 BASE_EXPORT OSSystemInfo * 85 os_system_info(void) 86 { 87 #if BASE_PLATFORM_NO_MAIN 88 if unlikely(linux_system_info.path_separator_byte == 0) 89 os_system_info_init(); 90 #endif 91 return &linux_system_info; 92 } 93 94 BASE_EXPORT void * 95 os_memory_reserve(u64 size) 96 { 97 void *result = mmap(0, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 98 if (result == MAP_FAILED) 99 result = 0; 100 return result; 101 } 102 103 BASE_EXPORT void 104 os_memory_release(void *base, u64 size) 105 { 106 munmap(base, size); 107 } 108 109 BASE_EXPORT b32 110 os_memory_commit(void *base, u64 size) 111 { 112 mprotect(base, size, PROT_READ|PROT_WRITE); 113 return 1; 114 } 115 116 BASE_EXPORT void 117 os_memory_uncommit(void *base, u64 size) 118 { 119 madvise(base, size, MADV_DONTNEED); 120 mprotect(base, size, PROT_NONE); 121 } 122 123 BASE_EXPORT void 124 os_memory_seal(void *base, u64 size) 125 { 126 mprotect(base, size, PROT_READ); 127 } 128 129 BASE_EXPORT str8 130 os_read_entire_file(Arena *arena, const char *file) 131 { 132 str8 result = {0}; 133 struct stat sb; 134 i32 fd = open(file, O_RDONLY); 135 if (fd >= 0 && fstat(fd, &sb) >= 0) { 136 result.data = push_array(arena, u8, sb.st_size); 137 do { 138 i64 rlen = read(fd, result.data + result.length, (u64)(sb.st_size - result.length)); 139 if (rlen > 0) result.length += rlen; 140 } while (result.length != sb.st_size && errno != EINTR); 141 if (result.length != sb.st_size) { 142 arena_pop(arena, sb.st_size); 143 zero_struct(&result); 144 } 145 } 146 if (fd >= 0) close(fd); 147 148 return result; 149 } 150 151 function b32 152 os_write_new_file(char *fname, str8 raw) 153 { 154 b32 result = 0; 155 i32 fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600); 156 if (fd != INVALID_FILE) { 157 result = os_write_file(fd, raw.data, raw.length); 158 close(fd); 159 } 160 return result; 161 } 162 163 function b32 164 os_file_exists(char *path) 165 { 166 struct stat st; 167 b32 result = stat(path, &st) == 0; 168 return result; 169 } 170 171 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */ 172 function b32 173 os_copy_file(char *name, char *new) 174 { 175 b32 result = 0; 176 struct stat sb; 177 if (stat(name, &sb) == 0) { 178 i32 fd_old = open(name, O_RDONLY); 179 i32 fd_new = open(new, O_WRONLY|O_CREAT, sb.st_mode); 180 if (fd_old >= 0 && fd_new >= 0) { 181 u8 buf[4096]; 182 i64 copied = 0; 183 while (copied != sb.st_size) { 184 i64 r = read(fd_old, buf, countof(buf)); 185 if (r < 0) break; 186 i64 w = write(fd_new, buf, (u64)r); 187 if (w < 0) break; 188 copied += w; 189 } 190 result = copied == sb.st_size; 191 } 192 if (fd_old != -1) close(fd_old); 193 if (fd_new != -1) close(fd_new); 194 } 195 return result; 196 } 197 198 BASE_EXPORT b32 199 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms) 200 { 201 struct timespec *timeout = 0, timeout_value; 202 if (timeout_ms != (u32)-1) { 203 timeout_value.tv_sec = timeout_ms / 1000; 204 timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000; 205 timeout = &timeout_value; 206 } 207 return syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0) == 0; 208 } 209 210 BASE_EXPORT void 211 os_wake_all_waiters(i32 *sync) 212 { 213 if (sync) { 214 atomic_store_u32(sync, 0); 215 syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0); 216 } 217 } 218 219 #if !BASE_PLATFORM_NO_MAIN 220 BASE_IMPORT void entry_point(i32 argc, char *argv[]); 221 222 extern i32 223 main(i32 argc, char *argv[]) 224 { 225 os_system_info_init(); 226 227 entry_point(argc, argv); 228 229 return 0; 230 } 231 #endif