this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Workqueues with kevents (untested) implementation (#287)

+189 -15
+1
src/kernel/emulation/linux/CMakeLists.txt
··· 44 44 kqueue/kqueue.c 45 45 kqueue/kevent.c 46 46 kqueue/kevent64.c 47 + kqueue/kevent_qos.c 47 48 unistd/getsid.c 48 49 unistd/fsync.c 49 50 unistd/sync.c
+3 -1
src/kernel/emulation/linux/bsdthread/bsdthread_register.c
··· 8 8 bsdthread_entry_t pthread_entry_point; 9 9 bsdwqthread_entry_t wqueue_entry_point; 10 10 11 + #define WORKQ_FEATURE_KEVENT 0x40 12 + 11 13 long sys_bsdthread_register(void* thread_start, void* wqthread, int pthsize, 12 14 void* dummy, void* targetconc, unsigned long long dpq_offset) 13 15 { 14 16 pthread_obj_size = pthsize; 15 17 pthread_entry_point = (bsdthread_entry_t) thread_start; 16 18 wqueue_entry_point = (bsdwqthread_entry_t) wqthread; 17 - return 0; 19 + return WORKQ_FEATURE_KEVENT; 18 20 } 19 21
+3
src/kernel/emulation/linux/bsdthread/bsdthread_terminate.c
··· 3 3 #include "../base.h" 4 4 #include "../errno.h" 5 5 #include "../../../../../platform-include/sys/errno.h" 6 + #include "../../../../lkm/api.h" 6 7 #include <linux-syscalls/linux.h> 7 8 #include <stddef.h> 8 9 #include <stdint.h> ··· 22 23 // Implemented in libdyld 23 24 extern int __darling_thread_terminate(void* stackaddr, 24 25 unsigned long freesize, unsigned long pthobj_size); 26 + extern int lkm_call(int, void*); 25 27 26 28 semaphore_signal_trap(join_sem); 29 + lkm_call(NR_thread_death_announce, 0); 27 30 28 31 return __darling_thread_terminate(stackaddr, freesize, pthread_obj_size); 29 32 #else
+42 -7
src/kernel/emulation/linux/bsdthread/workq_kernreturn.c
··· 16 16 #define WQOPS_QUEUE_REMOVE 2 17 17 #define WQOPS_THREAD_RETURN 4 18 18 #define WQOPS_THREAD_SETCONC 8 19 + #define WQOPS_THREAD_KEVENT_RETURN 0x40 19 20 #define WQOPS_QUEUE_NEWSPISUPP 0x10 20 21 #define WQOPS_QUEUE_REQTHREADS 0x20 22 + #define WQOPS_QUEUE_REQTHREADS2 0x30 23 + 21 24 22 25 // Flags for the newly spawned thread: 23 26 // WQ_FLAG_THREAD_NEWSPI ··· 28 31 #define WQ_FLAG_THREAD_OVERCOMMIT 0x00010000 29 32 #define WQ_FLAG_THREAD_REUSE 0x00020000 30 33 #define WQ_FLAG_THREAD_NEWSPI 0x00040000 34 + #define WQ_FLAG_THREAD_KEVENT 0x00080000 /* thread is response to kevent req */ 31 35 32 36 static int workq_sem = WQ_MAX_THREADS; // max 64 threads in use 33 37 static int workq_parked_lock = 1; ··· 39 43 40 44 extern int thread_self_trap(void); 41 45 42 - extern void* __darwin_pthread_self(void); 43 46 extern void* pthread_get_stackaddr_np(void* pth); 47 + extern void* memmove(void* dest, const void* src, __SIZE_TYPE__ n); 44 48 45 - static int sem_down(int* sem, int timeout); 46 - static void sem_up(int* sem); 47 49 static void list_add(struct parked_thread* head, struct parked_thread* item); 48 50 static void list_remove(struct parked_thread* head, struct parked_thread* item); 49 51 ··· 52 54 long tv_sec; 53 55 long tv_nsec; 54 56 }; 57 + 58 + #define __PTK_DARLING_WQ_KEVENT_KEY 150 59 + 60 + void* __attribute__((weak)) __attribute__((visibility("default"))) pthread_getspecific(unsigned long key) { return NULL; } 61 + int __attribute__((weak)) __attribute__((visibility("default"))) pthread_setspecific(unsigned long key, const void* value) { return 1; } 55 62 56 63 long sys_workq_kernreturn(int options, void* item, int affinity, int prio) 57 64 { 58 65 #ifndef VARIANT_DYLD 66 + struct wq_kevent_data* wq_event = NULL; 67 + 59 68 // item is only used with WQOPS_QUEUE_ADD 60 69 switch (options) 61 70 { 71 + case WQOPS_THREAD_KEVENT_RETURN: 72 + { 73 + struct kevent_qos_s* keventlist = item; 74 + int nkevents = affinity; 75 + 76 + wq_event = (struct wq_kevent_data*) pthread_getspecific(__PTK_DARLING_WQ_KEVENT_KEY); 77 + 78 + if (wq_event != NULL) 79 + { 80 + pthread_setspecific(__PTK_DARLING_WQ_KEVENT_KEY, NULL); 81 + memmove(wq_event->events, keventlist, nkevents * sizeof(struct kevent_qos_s)); 82 + wq_event->nevents = nkevents; 83 + 84 + sem_up(&wq_event->sem); 85 + } 86 + } 62 87 case WQOPS_THREAD_RETURN: 63 88 { 64 89 // Signalizes that the thread has completed its job ··· 108 133 109 134 // reset stack and call entry point again with WQ_FLAG_THREAD_REUSE 110 135 thread_self = thread_self_trap(); 111 - //stack = pthread_get_stackaddr_np(__darwin_pthread_self()); 112 136 stack = __darling_thread_get_stack(); 113 137 114 138 #ifdef __x86_64__ ··· 142 166 } 143 167 case WQOPS_QUEUE_NEWSPISUPP: 144 168 return 0; 169 + case WQOPS_QUEUE_REQTHREAD_FOR_KEVENT: 170 + { 171 + wq_event = (struct wq_kevent_data*) item; 172 + pthread_setspecific(__PTK_DARLING_WQ_KEVENT_KEY, wq_event); 173 + } 174 + case WQOPS_QUEUE_REQTHREADS2: // with prop bucket 145 175 case WQOPS_QUEUE_REQTHREADS: 146 176 { 147 177 // affinity contains thread count ··· 150 180 151 181 flags = WQ_FLAG_THREAD_NEWSPI; 152 182 flags |= prio; 183 + 184 + if (wq_event != NULL) 185 + flags |= WQ_FLAG_THREAD_KEVENT; 153 186 154 187 // __simple_printf("Thread requested\n"); 155 188 ··· 185 218 sem_up(&workq_parked_lock); 186 219 187 220 // __simple_printf("Spawning a new thread\n"); 188 - ret = __darling_thread_create(512*1024, pthread_obj_size, wqueue_entry_point, 0, NULL, flags, 0, 221 + ret = __darling_thread_create(512*1024, pthread_obj_size, wqueue_entry_point, 0, 222 + (wq_event != NULL) ? wq_event->events : NULL, flags, 223 + (wq_event != NULL) ? wq_event->nevents : 0, 189 224 thread_self_trap); 190 225 191 226 if (ret < 0) ··· 201 236 #endif 202 237 } 203 238 204 - static int sem_down(int* sem, int timeout) 239 + int sem_down(int* sem, int timeout) 205 240 { 206 241 int result; 207 242 struct timespec ts = { timeout, 0 }; ··· 222 257 return 1; 223 258 } 224 259 225 - static void sem_up(int* sem) 260 + void sem_up(int* sem) 226 261 { 227 262 int result; 228 263 result = __sync_add_and_fetch(sem, 1);
+15
src/kernel/emulation/linux/bsdthread/workq_kernreturn.h
··· 1 1 #ifndef WORKQ_KERNRETURN_H 2 2 #define WORKQ_KERNRETURN_H 3 + #define PRIVATE 1 4 + #include <sys/event.h> 5 + 6 + // Darling specific 7 + #define WQOPS_QUEUE_REQTHREAD_FOR_KEVENT 0x100020 3 8 4 9 struct parked_thread 5 10 { ··· 8 13 }; 9 14 struct timespec; 10 15 16 + struct wq_kevent_data 17 + { 18 + struct kevent_qos_s* events; 19 + int nevents; 20 + int sem; 21 + }; 22 + 11 23 long sys_workq_kernreturn(int options, void* item, int affinity, int prio); 24 + 25 + int sem_down(int* sem, int timeout); 26 + void sem_up(int* sem); 12 27 13 28 #endif 14 29
+4 -4
src/kernel/emulation/linux/kqueue/kevent64.c
··· 1 - #include "kevent.h" 1 + #include "kevent64.h" 2 2 #include "../base.h" 3 3 #include "../errno.h" 4 4 #include <linux-syscalls/linux.h> ··· 7 7 8 8 int __attribute__((weak)) __attribute__((visibility("default"))) kevent64_impl(int kq, ...) { return -ENOSYS; } 9 9 10 - long sys_kevent64(int kq, const struct kevent64 *changelist, int nchanges, 11 - struct kevent64 *eventlist, int nevents, unsigned int flags, 12 - const struct timespec *timeout); 10 + long sys_kevent64(int kq, const struct kevent64_s *changelist, int nchanges, 11 + struct kevent64_s *eventlist, int nevents, unsigned int flags, 12 + const struct timespec *timeout) 13 13 { 14 14 return kevent64_impl(kq, changelist, nchanges, eventlist, nevents, flags, timeout); 15 15 }
+3 -3
src/kernel/emulation/linux/kqueue/kevent64.h
··· 1 1 #ifndef LINUX_KEVENT64_H 2 2 #define LINUX_KEVENT64_H 3 3 4 - struct kevent64; 4 + struct kevent64_s; 5 5 struct timespec; 6 6 7 - long sys_kevent64(int kq, const struct kevent64 *changelist, int nchanges, 8 - struct kevent64 *eventlist, int nevents, unsigned int flags, 7 + long sys_kevent64(int kq, const struct kevent64_s *changelist, int nchanges, 8 + struct kevent64_s *eventlist, int nevents, unsigned int flags, 9 9 const struct timespec *timeout); 10 10 11 11 #endif
+105
src/kernel/emulation/linux/kqueue/kevent_qos.c
··· 1 + #include "kevent_qos.h" 2 + #include "../base.h" 3 + #include "../errno.h" 4 + #include "../simple.h" 5 + #include "../fcntl/fcntl.h" 6 + #include <linux-syscalls/linux.h> 7 + #include <stddef.h> 8 + #include <sys/errno.h> 9 + #include <sys/fcntl.h> 10 + #include "kqueue.h" 11 + #include "../bsdthread/workq_kernreturn.h" 12 + 13 + static int default_kq = -1; 14 + 15 + extern void* memmove(void* dst, const void* src, __SIZE_TYPE__ n); 16 + 17 + static void kevent_qos_to_64(const struct kevent_qos_s *ev, struct kevent64_s* ev64); 18 + static void kevent_64_to_qos(const struct kevent64_s* ev64, struct kevent_qos_s *ev); 19 + 20 + long sys_kevent_qos(int kq, const struct kevent_qos_s *changelist, int nchanges, 21 + struct kevent_qos_s *eventlist, int nevents, 22 + void* data_out, unsigned long* data_available, unsigned int flags) 23 + { 24 + int rv; 25 + struct kevent64_s* changelist64 = NULL; 26 + struct kevent64_s* eventlist64 = NULL; 27 + struct wq_kevent_data wq_kevent; 28 + 29 + if ((kq == -1) != !!(flags & KEVENT_FLAG_WORKQ)) 30 + return -EINVAL; 31 + 32 + if (kq != -1) 33 + { 34 + __simple_printf("Dunno how to handle kevent_qos with a valid kq number\n"); 35 + return -ENOTSUP; 36 + } 37 + 38 + if (default_kq == -1) 39 + { 40 + default_kq = sys_kqueue(); 41 + sys_fcntl(default_kq, F_SETFD, FD_CLOEXEC); 42 + } 43 + 44 + if (changelist != NULL && nchanges > 0) 45 + { 46 + int i; 47 + 48 + changelist64 = (struct kevent64_s*) __builtin_alloca(nchanges * sizeof(struct kevent64_s)); 49 + for (i = 0; i < nchanges; i++) 50 + kevent_qos_to_64(&changelist[i], &changelist64[i]); 51 + } 52 + if (eventlist != NULL && nevents > 0) 53 + eventlist64 = (struct kevent64_s*) __builtin_alloca(nevents * sizeof(struct kevent64_s)); 54 + 55 + rv = kevent64(default_kq, changelist64, nchanges, eventlist64, nevents, flags, NULL); 56 + 57 + if (rv > 0) 58 + { 59 + int i; 60 + 61 + for (i = 0; i < rv; i++) 62 + kevent_64_to_qos(&eventlist64[i], &eventlist[i]); 63 + } 64 + 65 + // Pass to workqueue and wait 66 + wq_kevent.sem = 0; 67 + wq_kevent.events = eventlist; 68 + wq_kevent.nevents = rv; 69 + 70 + sys_workq_kernreturn(WQOPS_QUEUE_REQTHREAD_FOR_KEVENT, &wq_kevent, 1, 0); 71 + sem_down(&wq_kevent.sem, -1); 72 + 73 + rv = wq_kevent.nevents; 74 + memmove(eventlist, wq_kevent.events, rv * sizeof(struct kevent_qos_s)); 75 + 76 + return rv; 77 + } 78 + 79 + 80 + void kevent_qos_to_64(const struct kevent_qos_s *ev, struct kevent64_s* ev64) 81 + { 82 + ev64->ident = ev->ident; 83 + ev64->filter = ev->filter; 84 + ev64->flags = ev->flags; 85 + ev64->fflags = ev->fflags; 86 + ev64->data = ev->data; 87 + ev64->udata = ev->udata; 88 + ev64->ext[0] = ev->ext[0]; 89 + ev64->ext[1] = ev->ext[1]; 90 + } 91 + 92 + void kevent_64_to_qos(const struct kevent64_s* ev64, struct kevent_qos_s *ev) 93 + { 94 + ev->ident = ev64->ident; 95 + ev->filter = ev64->filter; 96 + ev->flags = ev64->flags; 97 + ev->qos = 0; 98 + ev->fflags = ev64->fflags; 99 + ev->data = ev64->data; 100 + ev->udata = ev64->udata; 101 + ev->ext[0] = ev64->ext[0]; 102 + ev->ext[1] = ev64->ext[1]; 103 + ev->ext[2] = ev->ext[3] = 0; 104 + } 105 +
+11
src/kernel/emulation/linux/kqueue/kevent_qos.h
··· 1 + #ifndef LINUX_KEVENT_QOS_H 2 + #define LINUX_KEVENT_QOS_H 3 + #define PRIVATE 1 4 + #include <sys/event.h> 5 + 6 + long sys_kevent_qos(int kq, const struct kevent_qos_s *changelist, int nchanges, 7 + struct kevent_qos_s *eventlist, int nevents, 8 + void* data_out, unsigned long* data_available, unsigned int flags); 9 + 10 + #endif 11 +
+2
src/kernel/emulation/linux/syscalls.c
··· 3 3 #include "kqueue/kqueue.h" 4 4 #include "kqueue/kevent.h" 5 5 #include "kqueue/kevent64.h" 6 + #include "kqueue/kevent_qos.h" 6 7 #include "unistd/write.h" 7 8 #include "unistd/read.h" 8 9 #include "guarded/guarded_open_np.h" ··· 342 343 [368] = sys_workq_kernreturn, 343 344 [369] = sys_kevent64, 344 345 [372] = sys_thread_selfid, 346 + [374] = sys_kevent_qos, 345 347 [394] = sys_pselect, 346 348 [395] = sys_pselect_nocancel, 347 349 [396] = sys_read_nocancel,