| 1 | //------------------------------------------------------------------------------ |
| 2 | // Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st> |
| 3 | //------------------------------------------------------------------------------ |
| 4 | // This file is part of thread-bites. |
| 5 | // |
| 6 | // thread-bites is free software: you can redistribute it and/or modify |
| 7 | // it under the terms of the GNU General Public License as published by |
| 8 | // the Free Software Foundation, either version 3 of the License, or |
| 9 | // (at your option) any later version. |
| 10 | // |
| 11 | // thread-bites is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public License |
| 17 | // along with thread-bites. If not, see <http://www.gnu.org/licenses/>. |
| 18 | //------------------------------------------------------------------------------ |
| 19 | |
| 20 | #pragma once |
| 21 | |
| 22 | #include <stdint.h> |
| 23 | #include <asm/unistd_64.h> |
| 24 | #include <asm-generic/errno.h> |
| 25 | #include <stddef.h> |
| 26 | #include <asm/signal.h> |
| 27 | #include <asm-generic/siginfo.h> |
| 28 | #include <linux/sched.h> |
| 29 | |
| 30 | //------------------------------------------------------------------------------ |
| 31 | // Constants |
| 32 | //------------------------------------------------------------------------------ |
| 33 | #define TBTHREAD_MAX_KEYS 1024 |
| 34 | #define TBTHREAD_MUTEX_NORMAL 0 |
| 35 | #define TBTHREAD_MUTEX_ERRORCHECK 1 |
| 36 | #define TBTHREAD_MUTEX_RECURSIVE 2 |
| 37 | #define TBTHREAD_MUTEX_DEFAULT 0 |
| 38 | #define TBTHREAD_CREATE_DETACHED 0 |
| 39 | #define TBTHREAD_CREATE_JOINABLE 1 |
| 40 | #define TBTHREAD_CANCEL_ENABLE 1 |
| 41 | #define TBTHREAD_CANCEL_DISABLE 0 |
| 42 | #define TBTHREAD_CANCEL_DEFERRED 1 |
| 43 | #define TBTHREAD_CANCEL_ASYNCHRONOUS 0 |
| 44 | |
| 45 | #define TBTHREAD_CANCELED ((void*)-1) |
| 46 | |
| 47 | #define TBTHREAD_INHERIT_SCHED 1 |
| 48 | #define TBTHREAD_EXPLICIT_SCHED 0 |
| 49 | |
| 50 | #define TBTHREAD_PRIO_NONE 3 |
| 51 | #define TBTHREAD_PRIO_INHERIT 4 |
| 52 | #define TBTHREAD_PRIO_PROTECT 5 |
| 53 | |
| 54 | //------------------------------------------------------------------------------ |
| 55 | // List struct |
| 56 | //------------------------------------------------------------------------------ |
| 57 | typedef struct list { |
| 58 | struct list *next; |
| 59 | struct list *prev; |
| 60 | void *element; |
| 61 | } list_t; |
| 62 | |
| 63 | //------------------------------------------------------------------------------ |
| 64 | // Thread attirbutes |
| 65 | //------------------------------------------------------------------------------ |
| 66 | typedef struct |
| 67 | { |
| 68 | uint32_t stack_size; |
| 69 | uint8_t joinable; |
| 70 | uint8_t sched_inherit; |
| 71 | uint8_t sched_policy; |
| 72 | uint8_t sched_priority; |
| 73 | } tbthread_attr_t; |
| 74 | |
| 75 | //------------------------------------------------------------------------------ |
| 76 | // Thread descriptor |
| 77 | //------------------------------------------------------------------------------ |
| 78 | typedef struct tbthread |
| 79 | { |
| 80 | struct tbthread *self; |
| 81 | void *stack; |
| 82 | uint32_t stack_size; |
| 83 | uint32_t tid; |
| 84 | void *(*fn)(void *); |
| 85 | void *arg; |
| 86 | void *retval; |
| 87 | struct |
| 88 | { |
| 89 | uint64_t seq; |
| 90 | void *data; |
| 91 | } tls[TBTHREAD_MAX_KEYS]; |
| 92 | uint8_t join_status; |
| 93 | uint8_t cancel_status; |
| 94 | uint16_t sched_info; |
| 95 | uint16_t user_sched_info; |
| 96 | struct tbthread *joiner; |
| 97 | list_t cleanup_handlers; |
| 98 | list_t protect_mutexes; |
| 99 | list_t inherit_mutexes; |
| 100 | uint32_t start_status; |
| 101 | uint32_t lock; |
| 102 | } *tbthread_t; |
| 103 | |
| 104 | //------------------------------------------------------------------------------ |
| 105 | // Mutex attributes |
| 106 | //------------------------------------------------------------------------------ |
| 107 | typedef struct |
| 108 | { |
| 109 | uint8_t type; |
| 110 | uint8_t protocol; |
| 111 | uint8_t prioceiling; |
| 112 | } tbthread_mutexattr_t; |
| 113 | |
| 114 | //------------------------------------------------------------------------------ |
| 115 | // Mutex |
| 116 | //------------------------------------------------------------------------------ |
| 117 | typedef struct |
| 118 | { |
| 119 | int futex; |
| 120 | uint8_t type; |
| 121 | uint8_t protocol; |
| 122 | uint16_t sched_info; |
| 123 | tbthread_t owner; |
| 124 | uint64_t counter; |
| 125 | uint32_t internal_futex; |
| 126 | } tbthread_mutex_t; |
| 127 | |
| 128 | #define TBTHREAD_MUTEX_INITIALIZER {0, 0, TBTHREAD_PRIO_NONE, 0, 0, 0, 0} |
| 129 | |
| 130 | //------------------------------------------------------------------------------ |
| 131 | // Once |
| 132 | //------------------------------------------------------------------------------ |
| 133 | typedef int tbthread_once_t; |
| 134 | |
| 135 | #define TBTHREAD_ONCE_INIT 0 |
| 136 | |
| 137 | //------------------------------------------------------------------------------ |
| 138 | // RW lock |
| 139 | //------------------------------------------------------------------------------ |
| 140 | typedef struct { |
| 141 | int lock; |
| 142 | int writers_queued; |
| 143 | int rd_futex; |
| 144 | int wr_futex; |
| 145 | tbthread_t writer; |
| 146 | int readers; |
| 147 | } tbthread_rwlock_t; |
| 148 | |
| 149 | #define TBTHREAD_RWLOCK_INIT {0, 0, 0, 0, 0, 0} |
| 150 | |
| 151 | //------------------------------------------------------------------------------ |
| 152 | // Condvar |
| 153 | //------------------------------------------------------------------------------ |
| 154 | typedef struct { |
| 155 | int lock; |
| 156 | int futex; |
| 157 | uint64_t waiters; |
| 158 | uint64_t signal_num; |
| 159 | uint64_t broadcast_seq; |
| 160 | tbthread_mutex_t *mutex; |
| 161 | } tbthread_cond_t; |
| 162 | |
| 163 | #define TBTHREAD_COND_INITIALIZER {0, 0, 0, 0, 0, 0} |
| 164 | |
| 165 | //------------------------------------------------------------------------------ |
| 166 | // General threading |
| 167 | //------------------------------------------------------------------------------ |
| 168 | void tbthread_init(); |
| 169 | void tbthread_finit(); |
| 170 | void tbthread_attr_init(tbthread_attr_t *attr); |
| 171 | int tbthread_attr_setdetachstate(tbthread_attr_t *attr, int state); |
| 172 | int tbthread_create(tbthread_t *thread, const tbthread_attr_t *attrs, |
| 173 | void *(*f)(void *), void *arg); |
| 174 | void tbthread_exit(void *retval); |
| 175 | int tbthread_detach(tbthread_t thread); |
| 176 | int tbthread_join(tbthread_t thread, void **retval); |
| 177 | int tbthread_equal(tbthread_t t1, tbthread_t t2); |
| 178 | int tbthread_once(tbthread_once_t *once, void (*func)(void)); |
| 179 | int tbthread_cancel(tbthread_t thread); |
| 180 | void tbthread_cleanup_push(void (*func)(void *), void *arg); |
| 181 | void tbthread_cleanup_pop(int execute); |
| 182 | int tbthread_setcancelstate(int state, int *oldstate); |
| 183 | int tbthread_setcanceltype(int type, int *oldtype); |
| 184 | void tbthread_testcancel(); |
| 185 | |
| 186 | //------------------------------------------------------------------------------ |
| 187 | // TLS |
| 188 | //------------------------------------------------------------------------------ |
| 189 | typedef uint16_t tbthread_key_t; |
| 190 | tbthread_t tbthread_self(); |
| 191 | int tbthread_key_create(tbthread_key_t *key, void (*destructor)(void *)); |
| 192 | int tbthread_key_delete(tbthread_key_t key); |
| 193 | void *tbthread_getspecific(tbthread_key_t key); |
| 194 | int tbthread_setspecific(tbthread_key_t kay, void *value); |
| 195 | |
| 196 | //------------------------------------------------------------------------------ |
| 197 | // Mutexes |
| 198 | //------------------------------------------------------------------------------ |
| 199 | int tbthread_mutexattr_init(tbthread_mutexattr_t *attr); |
| 200 | int tbthread_mutexattr_destroy(tbthread_mutexattr_t *attr); |
| 201 | int tbthread_mutexattr_gettype(const tbthread_mutexattr_t *attr, int *type); |
| 202 | int tbthread_mutexattr_settype(tbthread_mutexattr_t *attr, int type); |
| 203 | |
| 204 | int tbthread_mutex_init(tbthread_mutex_t *mutex, |
| 205 | const tbthread_mutexattr_t *attr); |
| 206 | int tbthread_mutex_destroy(tbthread_mutex_t *mutex); |
| 207 | int tbthread_mutex_lock(tbthread_mutex_t *mutex); |
| 208 | int tbthread_mutex_trylock(tbthread_mutex_t *mutex); |
| 209 | int tbthread_mutex_unlock(tbthread_mutex_t *mutex); |
| 210 | |
| 211 | //------------------------------------------------------------------------------ |
| 212 | // Scheduling |
| 213 | //------------------------------------------------------------------------------ |
| 214 | int tbthread_setschedparam(tbthread_t thread, int policy, int priority); |
| 215 | int tbthread_getschedparam(tbthread_t thread, int *policy, int *priority); |
| 216 | |
| 217 | int tbthread_attr_setschedpolicy(tbthread_attr_t *attr, int policy); |
| 218 | int tbthread_attr_setschedpriority(tbthread_attr_t *attr, int priority); |
| 219 | int tbthread_attr_setinheritsched(tbthread_attr_t *attr, int inheritsched); |
| 220 | |
| 221 | int tbthread_mutexattr_setprioceiling(tbthread_mutexattr_t *attr, int ceiling); |
| 222 | int tbthread_mutexattr_setprotocol(tbthread_mutexattr_t *attr, int protocol); |
| 223 | |
| 224 | int tbthread_mutex_getprioceiling(const tbthread_mutex_t *mutex, int *ceiling); |
| 225 | int tbthread_mutex_setprioceiling(tbthread_mutex_t *mutex, int ceiling, |
| 226 | int *old_ceiling); |
| 227 | |
| 228 | //------------------------------------------------------------------------------ |
| 229 | // RW Lock |
| 230 | //----------------------------------------------------------------------------- |
| 231 | int tbthread_rwlock_init(tbthread_rwlock_t *rwlock); |
| 232 | int tbthread_rwlock_destroy(tbthread_rwlock_t *rwlock); |
| 233 | |
| 234 | int tbthread_rwlock_rdlock(tbthread_rwlock_t *rwlock); |
| 235 | int tbthread_rwlock_wrlock(tbthread_rwlock_t *rwlock); |
| 236 | int tbthread_rwlock_unlock(tbthread_rwlock_t *rwlock); |
| 237 | |
| 238 | int tbthread_rwlock_tryrdlock(tbthread_rwlock_t *rwlock); |
| 239 | int tbthread_rwlock_trywrlock(tbthread_rwlock_t *rwlock); |
| 240 | |
| 241 | //------------------------------------------------------------------------------ |
| 242 | // Condvar |
| 243 | //------------------------------------------------------------------------------ |
| 244 | int tbthread_cond_broadcast(tbthread_cond_t *cond); |
| 245 | int tbthread_cond_signal(tbthread_cond_t *cond); |
| 246 | int tbthread_cond_wait(tbthread_cond_t *cond, tbthread_mutex_t *mutex); |
| 247 | |
| 248 | //------------------------------------------------------------------------------ |
| 249 | // Utility functions |
| 250 | //------------------------------------------------------------------------------ |
| 251 | void *malloc(size_t size); |
| 252 | void free(void *ptr); |
| 253 | void *realloc(void *ptr, size_t size); |
| 254 | void *calloc(size_t nmemb, size_t size); |
| 255 | void tbprint(const char *format, ...); |
| 256 | int tbwrite(int fd, const char *buffer, unsigned long len); |
| 257 | void tbsleep(int secs); |
| 258 | void *tbmmap(void *addr, unsigned long length, int prot, int flags, int fd, |
| 259 | unsigned long offset); |
| 260 | int tbmunmap(void *addr, unsigned long length); |
| 261 | |
| 262 | int tbclone(int (*fn)(void *), void *arg, int flags, void *child_stack, ... |
| 263 | /* pid_t *ptid, pid_t *ctid, void *tls */ ); |
| 264 | |
| 265 | void *tbbrk(void *addr); |
| 266 | |
| 267 | uint64_t tbtime(); |
| 268 | uint32_t tbrandom(uint32_t *seed); |
| 269 | const char *tbstrerror(int errno); |
| 270 | |
| 271 | int tbsigaction(int signum, struct sigaction *act, struct sigaction *old); |
| 272 | |
| 273 | //------------------------------------------------------------------------------ |
| 274 | // Syscall interface |
| 275 | //------------------------------------------------------------------------------ |
| 276 | #define SYSCALL(name, a1, a2, a3, a4, a5, a6) \ |
| 277 | ({ \ |
| 278 | long result; \ |
| 279 | long __a1 = (long)(a1); \ |
| 280 | long __a2 = (long)(a2); \ |
| 281 | long __a3 = (long)(a3); \ |
| 282 | long __a4 = (long)(a4); \ |
| 283 | long __a5 = (long)(a5); \ |
| 284 | long __a6 = (long)(a6); \ |
| 285 | register long _a1 asm("rdi") = __a1; \ |
| 286 | register long _a2 asm("rsi") = __a2; \ |
| 287 | register long _a3 asm("rdx") = __a3; \ |
| 288 | register long _a4 asm("r10") = __a4; \ |
| 289 | register long _a5 asm("r8") = __a5; \ |
| 290 | register long _a6 asm("r9") = __a6; \ |
| 291 | asm volatile ( \ |
| 292 | "syscall\n\t" \ |
| 293 | : "=a" (result) \ |
| 294 | : "0" (name), "r" (_a1), "r" (_a2), "r" (_a3), \ |
| 295 | "r" (_a4), "r" (_a5), "r" (_a6) \ |
| 296 | : "memory", "cc", "r11", "cx"); \ |
| 297 | (long) result; }) |
| 298 | |
| 299 | #define SYSCALL0(name) \ |
| 300 | SYSCALL(name, 0, 0, 0, 0, 0, 0) |
| 301 | #define SYSCALL1(name, a1) \ |
| 302 | SYSCALL(name, a1, 0, 0, 0, 0, 0) |
| 303 | #define SYSCALL2(name, a1, a2) \ |
| 304 | SYSCALL(name, a1, a2, 0, 0, 0, 0) |
| 305 | #define SYSCALL3(name, a1, a2, a3) \ |
| 306 | SYSCALL(name, a1, a2, a3, 0, 0, 0) |
| 307 | #define SYSCALL4(name, a1, a2, a3, a4) \ |
| 308 | SYSCALL(name, a1, a2, a3, a4, 0, 0) |
| 309 | #define SYSCALL5(name, a1, a2, a3, a4, a5) \ |
| 310 | SYSCALL(name, a1, a2, a3, a4, a5, 0) |
| 311 | #define SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ |
| 312 | SYSCALL(name, a1, a2, a3, a4, a5, a6) |
| 313 | |
| 314 | //------------------------------------------------------------------------------ |
| 315 | // List ops |
| 316 | //------------------------------------------------------------------------------ |
| 317 | int list_add_elem(list_t *list, void *element, int front); |
| 318 | void list_add(list_t *list, list_t *node, int front); |
| 319 | void list_add_here(list_t *list, list_t *node, int (*here)(void*, void*)); |
| 320 | void list_rm(list_t *node); |
| 321 | list_t *list_find_elem(list_t *list, void *element); |
| 322 | list_t *list_find_elem_func(list_t *list, void *element, |
| 323 | int (*func)(void*, void*)); |
| 324 | void list_for_each_elem(list_t *list, void (*func)(void *)); |
| 325 | void list_clear(list_t *list); |
| 326 | |