Get threads working well on MacOS Arm64

- Now using 10x better GCD semaphores
- We now generate Linux-like thread ids
- We now use fast system clock / sleep libraries
- The APE M1 loader now generates Linux-like stacks
This commit is contained in:
Justine Tunney 2023-06-04 01:57:10 -07:00
parent b5eab2b0b7
commit bcf9af94bf
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
2037 changed files with 4664 additions and 4451 deletions

View file

@ -0,0 +1,26 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/runtime/syslib.internal.h"
int sys_clock_gettime_m1(int clock, struct timespec *ts) {
return _sysret(__syslib->clock_gettime(clock, ts));
}

View file

@ -110,8 +110,15 @@ clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) {
if (IsLinux() && (res = CGT_VDSO)) {
isfast = true;
} else if (IsXnu()) {
isfast = false;
#ifdef __x86_64__
res = sys_clock_gettime_xnu;
isfast = false;
#elif defined(__aarch64__)
res = sys_clock_gettime_m1;
isfast = true;
#else
#error "unsupported architecture"
#endif
} else if (IsWindows()) {
isfast = true;
res = sys_clock_gettime_nt;

View file

@ -16,10 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
@ -27,23 +30,38 @@
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int res;
struct timeval now, abs, rel;
#ifdef __x86_64__
struct timeval abs, now, rel;
if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) {
abs = timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0);
if (timeval_cmp(abs, now) > 0) {
rel = timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel);
return sys_select(0, 0, 0, 0, &rel);
} else {
res = 0;
return 0;
}
} else {
res = sys_nanosleep_xnu(req, rem);
return sys_nanosleep_xnu(req, rem);
}
} else {
res = enotsup();
return enotsup();
}
return res;
#else
long res;
struct timespec abs, now, rel;
if (flags & TIMER_ABSTIME) {
abs = *req;
if (!(res = __syslib->clock_gettime(clock, &now))) {
if (timespec_cmp(abs, now) > 0) {
rel = timespec_sub(abs, now);
res = __syslib->nanosleep(&rel, 0);
}
}
} else {
res = __syslib->nanosleep(req, rem);
}
return _sysret(res);
#endif
}

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/clock.h"
axdx_t sys_gettimeofday_m1(struct timeval *tv, struct timezone *tz, void *wut) {
axdx_t ad;
struct timespec ts;
ad.ax = _sysret(__syslib->clock_gettime(CLOCK_REALTIME, &ts));
ad.dx = 0;
if (!ad.ax && tv) {
*tv = timespec_totimeval(ts);
}
return ad;
}

View file

@ -82,8 +82,15 @@ gettimeofday_f *__gettimeofday_get(bool *opt_out_isfast) {
isfast = true;
res = sys_gettimeofday_nt;
} else if (IsXnu()) {
isfast = false;
#ifdef __x86_64__
res = sys_gettimeofday_xnu;
isfast = false;
#elif defined(__aarch64__)
res = sys_gettimeofday_m1;
isfast = true;
#else
#error "unsupported architecture"
#endif
} else if (IsMetal()) {
isfast = false;
res = sys_gettimeofday_metal;

View file

@ -20,33 +20,32 @@
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/errno.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sock/internal.h"
// nanosleep() on xnu: a bloodbath of a polyfill
// consider using clock_nanosleep(TIMER_ABSTIME)
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
#ifdef __x86_64__
int rc;
struct timeval wt, t1, t2, td;
if (rem) sys_gettimeofday_xnu(&t1, 0, 0);
wt = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &wt);
if (rem) {
if (!rc) {
if (rem && rc == -1 && errno == EINTR) {
sys_gettimeofday_xnu(&t2, 0, 0);
td = timeval_sub(t2, t1);
if (timeval_cmp(td, wt) >= 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else if (rc == -1 && errno == EINTR) {
// xnu select() doesn't modify timeout
// so we need, yet another system call
sys_gettimeofday_xnu(&t2, 0, 0);
td = timeval_sub(t2, t1);
if (timeval_cmp(td, wt) >= 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else {
*rem = timeval_totimespec(timeval_sub(wt, td));
}
} else {
*rem = timeval_totimespec(timeval_sub(wt, td));
}
}
return rc;
#else
return _sysret(__syslib->nanosleep(req, rem));
#endif
}

View file

@ -12,6 +12,7 @@ int __utimens(int, const char *, const struct timespec[2], int) _Hide;
int sys_clock_getres(int, struct timespec *) _Hide;
int sys_clock_gettime(int, struct timespec *) _Hide;
int sys_clock_gettime_nt(int, struct timespec *) _Hide;
int sys_clock_gettime_m1(int, struct timespec *) _Hide;
int sys_clock_gettime_xnu(int, struct timespec *) _Hide;
int sys_clock_nanosleep_nt(int, int, const struct timespec *, struct timespec *) _Hide;
int sys_clock_nanosleep_openbsd(int, int, const struct timespec *, struct timespec *) _Hide;

View file

@ -9,6 +9,7 @@ axdx_t sys_gettimeofday(struct timeval *, struct timezone *, void *) _Hide;
int sys_futimes(int, const struct timeval *) _Hide;
int sys_lutimes(const char *, const struct timeval *) _Hide;
int sys_utimes(const char *, const struct timeval *) _Hide;
axdx_t sys_gettimeofday_m1(struct timeval *, struct timezone *, void *) _Hide;
axdx_t sys_gettimeofday_xnu(struct timeval *, struct timezone *, void *) _Hide;
axdx_t sys_gettimeofday_nt(struct timeval *, struct timezone *, void *) _Hide;
int sys_utimes_nt(const char *, const struct timeval[2]) _Hide;