|
2 | 2 | // see mt.c |
3 | 3 |
|
4 | 4 | #if PYXES |
5 | | -#ifndef __APPLE__ |
| 5 | +#if !defined(__APPLE__) && !defined(__linux__) |
6 | 6 | #include <pthread.h> |
7 | 7 | typedef pthread_mutex_t jtpthread_mutex_t; |
8 | 8 | static inline void jtpthread_mutex_init(jtpthread_mutex_t *m,B recursive){ |
@@ -44,6 +44,53 @@ static inline C jtpthread_mutex_unlock(jtpthread_mutex_t *m,I self){ |
44 | 44 | if(r==EPERM)R EVCONCURRENCY; |
45 | 45 | R EVFACE;} |
46 | 46 | #else |
| 47 | +typedef struct { |
| 48 | + B recursive; |
| 49 | + I owner; //user-provided; task id |
| 50 | + UI4 v; |
| 51 | + UI4 ct; //for recursive locks |
| 52 | +}jtpthread_mutex_t;//todo should split into multiple cache lines? |
| 53 | + |
| 54 | +void jtpthread_mutex_init(jtpthread_mutex_t*,B recursive); |
| 55 | +C jtpthread_mutex_lock(J jt,jtpthread_mutex_t *m,I self); |
| 56 | +I jtpthread_mutex_timedlock(J jt,jtpthread_mutex_t*,UI ns,I self); //absolute timers suck; correct the interface. -1=failure; 0=success; positive=error |
| 57 | +I jtpthread_mutex_trylock(jtpthread_mutex_t*,I self); //0=success -1=failure positive=error |
| 58 | +C jtpthread_mutex_unlock(jtpthread_mutex_t*,I self); //0 or error code |
| 59 | + |
| 60 | +//note: self must be non-zero |
| 61 | +#if defined(__linux__) |
| 62 | +#include <linux/futex.h> |
| 63 | +#include <sys/syscall.h> |
| 64 | +static inline void jfutex_wake1(UI4 *p){ |
| 65 | + __asm__ volatile("syscall" :: "a" (SYS_futex), //eax: syscall# |
| 66 | + "D" (p), //rdi: ptr |
| 67 | + "S" (FUTEX_WAKE), //rsi: op |
| 68 | + "d" (1));} //rdx: count |
| 69 | +static inline void jfutex_wakea(UI4 *p){ |
| 70 | + __asm__ volatile("syscall" :: "a" (SYS_futex), //eax: syscall# |
| 71 | + "D" (p), //rdi: ptr |
| 72 | + "S" (FUTEX_WAKE), //rsi: op |
| 73 | + "d" (0xffffffff));} //rdx: count |
| 74 | +static inline int jfutex_wait(UI4 *p,UI4 v){ |
| 75 | + register struct timespec *pts asm("r10") = 0; |
| 76 | + int r;__asm__ volatile("syscall" : "=a"(r) //result in rax |
| 77 | + : "a" (SYS_futex), //eax: syscall# |
| 78 | + "D" (p), //rdi: ptr |
| 79 | + "S" (FUTEX_WAIT), //rsi: op |
| 80 | + "d" (v), //rdx: val, espected |
| 81 | + "r" (pts)); //r10: timeout (null=no timeout) |
| 82 | + return r;} |
| 83 | +static inline int _jfutex_waitn(UI4 *p,UI4 v,UI ns){ |
| 84 | + struct timespec ts={.tv_sec=ns/1000000000, .tv_nsec=ns%1000000000}; |
| 85 | + register struct timespec *pts asm("r10") = &ts; |
| 86 | + int r;__asm__ volatile("syscall" : "=a"(r) //result in rax |
| 87 | + : "a" (SYS_futex), //eax: syscall# |
| 88 | + "D" (p), //rdi: ptr |
| 89 | + "S" (FUTEX_WAIT), //rsi: op |
| 90 | + "d" (v), //rdx: val, espected |
| 91 | + "r" (pts)); //r10: timeout (relative!) |
| 92 | + R r;} |
| 93 | +#elif defined(__APPLE__) |
47 | 94 | // ulock (~futex) junk from xnu. timeout=0 means wait forever |
48 | 95 | extern int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout); // timeout in us |
49 | 96 | extern int __ulock_wait2(uint32_t operation, void *addr, uint64_t value, uint64_t timeout, uint64_t value2); // timeout in ns. only available as of macos 11? |
@@ -76,19 +123,32 @@ extern int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value); |
76 | 123 |
|
77 | 124 | //positive (or just 1?) result from wait means someone else is waiting on this too? |
78 | 125 |
|
79 | | -typedef struct { |
80 | | - B recursive; |
81 | | - I owner; //user-provided; task id |
82 | | - UI4 v; |
83 | | - UI4 ct; //for recursive locks |
84 | | -}jtpthread_mutex_t;//todo should split into multiple cache lines? |
85 | | - |
86 | | -void jtpthread_mutex_init(jtpthread_mutex_t*,B recursive); |
87 | | -struct JTTstruct; C jtpthread_mutex_lock(struct JTTstruct *jt,jtpthread_mutex_t *m,I self); |
88 | | -I jtpthread_mutex_timedlock(struct JTTstruct *jt,jtpthread_mutex_t*,UI ns,I self); //absolute timers suck; correct the interface. -1=failure; 0=success; positive=error |
89 | | -I jtpthread_mutex_trylock(jtpthread_mutex_t*,I self); //0=success -1=failure positive=error |
90 | | -C jtpthread_mutex_unlock(jtpthread_mutex_t*,I self); //0 or error code |
91 | | - |
92 | | -//note: self must be non-zero |
93 | | -#endif //__APPLE__ |
| 126 | +static inline void jfutex_wake1(UI4 *p){__ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO,p,0);} |
| 127 | +static inline void jfutex_wakea(UI4 *p){__ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO|ULF_WAKE_ALL,p,0);} |
| 128 | +static inline int jfutex_wait(UI4 *p,UI4 v){R __ulock_wait(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO,p,v,0);} |
| 129 | +#if __arm64__ |
| 130 | +// wait2 takes an ns timeout, but it's only available from macos 11 onward; coincidentally, arm macs only support macos 11+ |
| 131 | +// so we can count on having this |
| 132 | +static inline int _jfutex_waitn(UI4 *p,UI4 v,UI ns){R __ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO,p,v,ns,0);} |
| 133 | +#else |
| 134 | +// but for the x86 case, we keep compatibility with older macos. Revisit in the future |
| 135 | +// deal with >32 bits; 2^32us is just a little over an hour; just too close for comfort |
| 136 | +static inline int _jfutex_waitn(UI4 *p,UI4 v,UI ns){ |
| 137 | + UI us=ns/1000; |
| 138 | + while(us>0xfffffff){ |
| 139 | + I4 r=__ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO,p,v,0xffffffff,0); |
| 140 | + if(r!=-ETIMEDOUT)R r; |
| 141 | + us-=0xffffffff;} |
| 142 | + R __ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO,p,v,us,0);} |
| 143 | +#endif |
| 144 | +#elif defined(_WIN32) |
| 145 | +// untested windows path; make henry test it when he gets back from vacation |
| 146 | +#define WIN32_LEAN_AND_MEAN |
| 147 | +#include <windows.h> |
| 148 | +static inline int jfutex_wait(UI4 *p,UI4 v){R WaitOnAddress(p,&v,4,INFINITE);} //todo return wrong |
| 149 | +static inline int _jfutex_waitn(UI4 *p,UI4 v,UI ns){R WaitOnAddress(p,&v,4,ns/1000000);} //ditto |
| 150 | +static inline void jfutex_wake1(UI4 *p){WakeByAddressSingle(p);} |
| 151 | +static inline void jfutex_wakea(UI4 *p){WakeByAddressAll(p);} |
| 152 | +#endif //_WIN32 |
| 153 | +#endif //__APPLE__ || __linux__ |
94 | 154 | #endif //PYXES |
0 commit comments