Add *NSYNC unit test suite

This change also fixes the clock_nanosleep() api and polyfills futexes
on Windows, Mac, and NetBSD using exponential backoff.
This commit is contained in:
Justine Tunney 2022-10-07 21:29:40 -07:00
parent 3421b9a580
commit 9849b4c7ba
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
51 changed files with 5505 additions and 1060 deletions

View file

@ -17,11 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/state.internal.h"
#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/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
@ -69,7 +71,7 @@
* (1) it's non-null; (2) `flags` is 0; and (3) -1 w/ `EINTR` is
* returned; if this function returns 0 then `rem` is undefined;
* if flags is `TIMER_ABSTIME` then `rem` is ignored
* @return 0 on success, or -1 w/ errno
* @return 0 on success, or errno on error
* @raise EINTR when a signal got delivered while we were waiting
* @raise ENOTSUP if `clock` is known but we can't use it here
* @raise EINVAL if `clock` is unknown to current platform
@ -77,11 +79,12 @@
* @raise EINVAL if `req->tv_nsec [0,1000000000)`
* @raise EFAULT if bad memory was passed
* @raise ENOSYS on bare metal
* @returnserrno
* @norestart
*/
int clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int rc;
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int rc, e = errno;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
@ -103,9 +106,18 @@ int clock_nanosleep(int clock, int flags, const struct timespec *req,
rc = sys_clock_nanosleep_nt(clock, flags, req, rem);
}
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %d% m", DescribeClockName(clock),
DescribeSleepFlags(flags), flags, DescribeTimespec(0, req),
DescribeTimespec(rc, rem), rc);
if (rc == -1) {
rc = errno;
errno = e;
}
#if SYSDEBUG
if (!__time_critical) {
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req),
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
}
#endif
return rc;
}

View file

@ -21,11 +21,14 @@
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
// TODO(jart): Just delegate to clock_nanosleep()
/**
* Sleeps for relative amount of time.
*
@ -49,9 +52,10 @@ int nanosleep(const struct timespec *req, struct timespec *rem) {
} else if (req->tv_sec < 0 ||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = einval();
} else if (IsLinux()) {
} else if (IsLinux() || IsFreebsd() || IsNetbsd()) {
rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, req, rem);
} else if (IsOpenbsd() || IsFreebsd() || IsNetbsd()) {
if (rc > 0) errno = rc, rc = -1;
} else if (IsOpenbsd()) {
rc = sys_nanosleep(req, rem);
} else if (IsXnu()) {
rc = sys_nanosleep_xnu(req, rem);

View file

@ -41,6 +41,8 @@ int sys_fadvise_netbsd(int, int, int64_t, int64_t, int) asm("sys_fadvise");
* @raise EINVAL if `advice` is invalid or `len` is huge
* @raise ESPIPE if `fd` refers to a pipe
* @raise ENOSYS on XNU and OpenBSD
* @returnserrno
* @threadsafe
*/
errno_t posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
int rc, e = errno;

View file

@ -17,7 +17,21 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
int posix_madvise(void *addr, uint64_t len, int advice) {
return madvise(addr, len, advice);
/**
* Advises kernel about memory intentions, the POSIX way.
*
* @return 0 on success, or errno on error
* @returnserrno
* @threadsafe
*/
errno_t posix_madvise(void *addr, uint64_t len, int advice) {
int rc, e = errno;
rc = madvise(addr, len, advice);
if (rc == -1) {
rc = errno;
errno = e;
}
return rc;
}

View file

@ -74,7 +74,6 @@ kErrnoDocs:
.e ELOOP,"Too many symbolic links encountered"
.e ENOMSG,"No message of desired type"
.e EIDRM,"Identifier removed"
.e ETIME,"Timer expired"
.e EPROTO,"Protocol error"
.e EOVERFLOW,"Value too large for defined data type"
.e EILSEQ,"Illegal byte sequence"
@ -103,6 +102,7 @@ kErrnoDocs:
.e ESHUTDOWN,"Cannot send after transport endpoint shutdown"
.e ETOOMANYREFS,"Too many references: cannot splice"
.e ETIMEDOUT,"Connection timed out"
.e ETIME,"Timer expired"
.e ECONNREFUSED,"Connection refused"
.e EHOSTDOWN,"Host is down"
.e EHOSTUNREACH,"No route to host"

View file

@ -74,7 +74,6 @@ kErrnoNames:
.e ELOOP
.e ENOMSG
.e EIDRM
.e ETIME
.e EPROTO
.e EOVERFLOW
.e EILSEQ
@ -103,6 +102,7 @@ kErrnoNames:
.e ESHUTDOWN
.e ETOOMANYREFS
.e ETIMEDOUT
.e ETIME
.e ECONNREFUSED
.e EHOSTDOWN
.e EHOSTUNREACH

View file

@ -23,6 +23,7 @@
// Normalizes return value to Linux ABI -errno convention.
sys_umtx_op:
mov $0x1c6,%eax
mov %rcx,%r10
syscall
jc 1f
ret

View file

@ -0,0 +1,43 @@
/*-*- 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/sysv/consts/clock.h"
#include "libc/thread/freebsd.internal.h"
int sys_umtx_timedwait_uint(int *p, int expect, bool pshare,
const struct timespec *abstime) {
int op;
size_t size;
struct _umtx_time *tm_p, timo;
if (!abstime) {
tm_p = 0;
size = 0;
} else {
timo._clockid = CLOCK_REALTIME;
timo._flags = UMTX_ABSTIME;
timo._timeout = *abstime;
tm_p = &timo;
size = sizeof(timo);
}
if (pshare) {
op = UMTX_OP_WAIT_UINT;
} else {
op = UMTX_OP_WAIT_UINT_PRIVATE;
}
return sys_umtx_op(p, op, expect, (void *)size, tm_p);
}

View file

@ -66,7 +66,6 @@ syscon errno ENOTEMPTY 39 66 66 66 66 145 # directory not empty;
syscon errno ELOOP 40 62 62 62 62 1921 # too many levels of symbolic links; bsd consensus; kNtErrorCantResolveFilename; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), epoll_ctl(2), execve(2), execveat(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), open(2), open_by_handle_at(2), openat2(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), unlink(2), utimensat(2)
syscon errno ENOMSG 42 91 83 90 83 0 # raised by msgop(2)
syscon errno EIDRM 43 90 82 89 82 0 # identifier removed; raised by msgctl(2), msgget(2), msgop(2), semctl(2), semop(2), shmctl(2), shmget(2), shmop(2)
syscon errno ETIME 62 101 60 60 92 0 # timer expired; timer expired; raised by connect(2), futex(2), keyctl(2), mq_receive(2), mq_send(2), rtime(2), sem_wait(2)
syscon errno EPROTO 71 100 92 95 96 0 # raised by accept(2), connect(2), socket(2), socketpair(2)
syscon errno EOVERFLOW 75 84 84 87 84 0 # raised by aio_read(2), copy_file_range(2), ctime(2), fanotify_init(2), lseek(2), mmap(2), open(2), open_by_handle_at(2), sem_post(2), sendfile(2), shmctl(2), stat(2), statfs(2), statvfs(2), time(2), timegm(2)
syscon errno EILSEQ 84 92 86 84 85 0 # returned by fgetwc(3), fputwc(3), getwchar(3), putwchar(3), scanf(3), ungetwc(3)
@ -95,6 +94,7 @@ syscon errno ENOTCONN 107 57 57 57 57 10057 # socket is not conne
syscon errno ESHUTDOWN 108 58 58 58 58 10058 # cannot send after transport endpoint shutdown; note that shutdown write is an EPIPE; bsd consensus; WSAESHUTDOWN
syscon errno ETOOMANYREFS 109 59 59 59 59 10059 # too many references: cannot splice; bsd consensus; WSAETOOMANYREFS; raised by sendmsg(2), unix(7)
syscon errno ETIMEDOUT 110 60 60 60 60 1460 # connection timed out; kNtErrorTimeout; bsd consensus; WSAETIMEDOUT; raised by connect(2), futex(2), keyctl(2), tcp(7)
syscon errno ETIME 62 101 60 60 92 0 # timer expired (POSIX.1 XSI STREAMS)
syscon errno ECONNREFUSED 111 61 61 61 61 10061 # bsd consensus; WSAECONNREFUSED; raised by connect(2), listen(2), recv(2), unix(7), udp(7)system-imposed limit on the number of threads was encountered.
syscon errno EHOSTDOWN 112 64 64 64 64 10064 # bsd consensus; WSAEHOSTDOWN; raised by accept(2)
syscon errno EHOSTUNREACH 113 65 65 65 65 10065 # bsd consensus; WSAEHOSTUNREACH; raised by accept(2), ip(7)

View file

@ -46,6 +46,7 @@ struct _umtx_time {
};
int sys_umtx_op(void *, int, unsigned long, void *, void *);
int sys_umtx_timedwait_uint(int *, int, bool, const struct timespec *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/thread/thread.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
/**
* Destroys pthread attributes.

View file

@ -182,6 +182,7 @@ static int FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
* @raise EINVAL if `attr` was supplied and had unnaceptable data
* @raise EPERM if scheduling policy was requested and user account
* isn't authorized to use it
* @returnserrno
* @threadsafe
*/
errno_t pthread_create(pthread_t *thread, const pthread_attr_t *attr,

View file

@ -29,6 +29,8 @@
*
* @return 0 on success, or errno with error
* @raise EINVAL if thread is null or already detached
* @returnserrno
* @threadsafe
*/
int pthread_detach(pthread_t thread) {
struct PosixThread *pt;

View file

@ -26,6 +26,8 @@
*
* @return 0 on success, or errno with error
* @raise EDEADLK if thread is detached
* @returnserrno
* @threadsafe
*/
int pthread_join(pthread_t thread, void **value_ptr) {
struct PosixThread *pt;

View file

@ -25,6 +25,7 @@
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
@ -66,7 +67,7 @@ static void _wait0_futex(const atomic_int *a, int e) {
rc = -GetLastError();
}
} else if (IsFreebsd()) {
rc = sys_umtx_op(a, UMTX_OP_WAIT_UINT, 0, 0, 0);
rc = sys_umtx_op(a, UMTX_OP_WAIT_UINT, e, 0, 0);
} else {
rc = _futex(a, op, e, 0);
if (IsOpenbsd() && rc > 0) {