Add posix semaphores support

There's still some bugs to work out on Windows and OpenBSD.
This commit is contained in:
Justine Tunney 2022-10-14 08:25:47 -07:00
parent f52f65b2e3
commit 8111462789
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
36 changed files with 779 additions and 59 deletions

View file

@ -46,7 +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 *);
int sys_umtx_timedwait_uint(_Atomic(int) *, int, bool, const struct timespec *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -86,7 +86,7 @@ wontreturn void pthread_exit(void *rc) {
// set_tid_address() upon every program startup which isn't possible
// on non-linux platforms anyway.
atomic_store_explicit(&__get_tls()->tib_tid, 0, memory_order_release);
nsync_futex_wake_((int *)&__get_tls()->tib_tid, INT_MAX, !IsWindows());
nsync_futex_wake_(&__get_tls()->tib_tid, INT_MAX, !IsWindows());
_Exit1(0);
}
}

View file

@ -45,7 +45,7 @@
* @raise ENOSYS on MacOS, Windows, FreeBSD, and OpenBSD
*/
errno_t pthread_getname_np(pthread_t thread, char *name, size_t size) {
int e, fd, rc, tid, len;
int fd, rc, tid, len, e = errno;
if (!size) return 0;
bzero(name, size);
@ -55,7 +55,6 @@ errno_t pthread_getname_np(pthread_t thread, char *name, size_t size) {
// TASK_COMM_LEN is 16 on Linux so we're just being paranoid.
char buf[256] = {0};
if (tid == gettid()) {
e = errno;
if (prctl(PR_GET_NAME, buf) == -1) {
rc = errno;
errno = e;
@ -66,7 +65,6 @@ errno_t pthread_getname_np(pthread_t thread, char *name, size_t size) {
p = stpcpy(p, "/proc/self/task/");
p = FormatUint32(p, tid);
p = stpcpy(p, "/comm");
e = errno;
if ((fd = sys_open(path, O_RDONLY | O_CLOEXEC, 0)) == -1) {
rc = errno;
errno = e;

View file

@ -53,14 +53,13 @@
*/
errno_t pthread_setname_np(pthread_t thread, const char *name) {
char path[128], *p;
int e, fd, rc, tid, len;
int fd, rc, tid, len, e = errno;
tid = ((struct PosixThread *)thread)->tid;
len = strlen(name);
if (IsLinux()) {
if (tid == gettid()) {
e = errno;
if (prctl(PR_SET_NAME, name) == -1) {
rc = errno;
errno = e;
@ -71,7 +70,6 @@ errno_t pthread_setname_np(pthread_t thread, const char *name) {
p = stpcpy(p, "/proc/self/task/");
p = FormatUint32(p, tid);
p = stpcpy(p, "/comm");
e = errno;
if ((fd = sys_open(path, O_WRONLY | O_CLOEXEC, 0)) == -1) {
rc = errno;
errno = e;

View file

@ -17,10 +17,20 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/errno.h"
/**
* Examines and/or changes blocked signals on current thread.
*
* @return 0 on success, or errno on error
*/
int pthread_sigmask(int how, const sigset_t *set, sigset_t *old) {
return sigprocmask(how, set, old);
int rc, e = errno;
if (!sigprocmask(how, set, old)) {
rc = 0;
} else {
rc = errno;
errno = e;
}
return rc;
}

32
libc/thread/sem_close.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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/assert.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/semaphore.h"
/**
* Closes named semaphore.
*
* @param sem was created with sem_open()
* @return 0 on success, or -1 w/ errno
*/
int sem_close(sem_t *sem) {
_npassert(!munmap(sem, FRAMESIZE));
return 0;
}

32
libc/thread/sem_destroy.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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/intrin/atomic.h"
#include "libc/limits.h"
#include "libc/thread/semaphore.h"
/**
* Destroys unnamed semaphore.
*
* @param sem was created by sem_init()
* @return 0 on success, or -1 w/ errno
*/
int sem_destroy(sem_t *sem) {
atomic_store_explicit(&sem->sem_value, INT_MIN, memory_order_relaxed);
return 0;
}

View file

@ -0,0 +1,32 @@
/*-*- 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/intrin/atomic.h"
#include "libc/thread/semaphore.h"
/**
* Destroys unnamed semaphore.
*
* @param sem was created by sem_init()
* @param sval receives output value
* @return 0 on success, or -1 w/ errno
*/
int sem_getvalue(sem_t *sem, int *sval) {
*sval = atomic_load_explicit(&sem->sem_value, memory_order_relaxed);
return 0;
}

39
libc/thread/sem_init.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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/intrin/atomic.h"
#include "libc/limits.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/semaphore.h"
#include "third_party/nsync/mu_semaphore.h"
/**
* Initializes unnamed semaphore.
*
* @param sem should make its way to sem_destroy() if this succeeds
* @param pshared if semaphore may be shared between processes
* @param value is initial count of semaphore
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `value` exceeds `SEM_VALUE_MAX`
*/
int sem_init(sem_t *sem, int pshared, unsigned value) {
if (value > SEM_VALUE_MAX) return einval();
atomic_store_explicit(&sem->sem_value, value, memory_order_relaxed);
sem->sem_pshared = pshared;
return 0;
}

34
libc/thread/sem_name.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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/runtime/runtime.h"
#include "libc/str/path.h"
#include "libc/str/str.h"
#include "libc/thread/semaphore.internal.h"
#include "libc/thread/thread.h"
const char *__sem_name(const char *name, char path[hasatleast PATH_MAX]) {
if (_isabspath(name)) {
return name;
} else {
strlcpy(path, kTmpPath, PATH_MAX);
strlcat(path, ".sem-", PATH_MAX);
strlcat(path, name, PATH_MAX);
return path;
}
}

72
libc/thread/sem_open.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/semaphore.h"
#include "libc/thread/semaphore.internal.h"
/**
* Initializes and opens named semaphore.
*
* @param name can be absolute path or should be component w/o slashes
* @param oflga can have `O_CREAT` and/or `O_EXCL`
* @return semaphore object which needs sem_close(), or SEM_FAILED w/ errno
* @raise ENOTDIR if a directory component in `name` exists as non-directory
* @raise ENAMETOOLONG if symlink-resolved `name` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `name` exists longer than `NAME_MAX`
* @raise ELOOP if `flags` had `O_NOFOLLOW` and `name` is a symbolic link
* @raise ENOSPC if file system is full when `name` would be `O_CREAT`ed
* @raise ELOOP if a loop was detected resolving components of `name`
* @raise EEXIST if `O_CREAT|O_EXCL` is used and semaphore exists
* @raise EACCES if we didn't have permission to create semaphore
* @raise EMFILE if process `RLIMIT_NOFILE` has been reached
* @raise ENFILE if system-wide file limit has been reached
* @raise EINTR if signal was delivered instead
*/
sem_t *sem_open(const char *name, int oflag, ...) {
int fd;
sem_t *sem;
va_list va;
unsigned mode;
char path[PATH_MAX];
va_start(va, oflag);
mode = va_arg(va, unsigned);
va_end(va);
oflag |= O_RDWR | O_CLOEXEC;
if ((fd = openat(AT_FDCWD, __sem_name(name, path), oflag, mode)) == -1) {
return SEM_FAILED;
}
if (ftruncate(fd, sizeof(sem_t)) == -1) {
_npassert(!close(fd));
return SEM_FAILED;
}
sem = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (sem != MAP_FAILED) sem->sem_pshared = true;
_npassert(!close(fd));
return sem;
}

44
libc/thread/sem_post.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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/assert.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/semaphore.h"
#include "third_party/nsync/futex.internal.h"
/**
* Unlocks semaphore.
*
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `sem` isn't valid
*/
int sem_post(sem_t *sem) {
int rc;
int old = atomic_fetch_add_explicit(&sem->sem_value, 1, memory_order_relaxed);
if (old >= 0) {
_npassert(nsync_futex_wake_(&sem->sem_value, 1, sem->sem_pshared) >= 0);
rc = 0;
} else {
rc = einval();
}
STRACE("sem_post(%p) → %d% m", sem, rc);
return rc;
}

113
libc/thread/sem_timedwait.c Normal file
View file

@ -0,0 +1,113 @@
/*-*- 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/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/semaphore.h"
#include "libc/thread/semaphore.internal.h"
#include "third_party/nsync/futex.internal.h"
static void sem_delay(int n) {
volatile int i;
for (i = 0; i != 1 << n; i++) donothing;
}
// TODO(jart): This should be abstracted by polyfill.
static struct timespec *sem_timeout(struct timespec *memory,
const struct timespec *abstime) {
struct timespec now;
if (!abstime) {
return 0;
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
*memory = *abstime;
return memory;
} else {
now = _timespec_real();
if (_timespec_cmp(now, *abstime) > 0) {
*memory = (struct timespec){0};
} else {
*memory = _timespec_sub(*abstime, now);
}
return memory;
}
}
/**
* Locks semaphore w/ deadline.
*
* @param abstime is absolute deadline or null to wait forever
* @return 0 on success, or -1 w/ errno
* @raise EINTR if signal was delivered instead
* @raise EDEADLK if deadlock was detected
* @raise ETIMEDOUT if deadline expired
* @raise EINVAL if `sem` is invalid
*/
int sem_timedwait(sem_t *sem, const struct timespec *abstime) {
int e, i, v, rc;
struct timespec ts;
e = errno;
for (i = 0; i < 7; ++i) {
rc = sem_trywait(sem);
if (!rc) {
return rc;
} else if (errno == EAGAIN) {
errno = e;
sem_delay(i);
} else {
return rc;
}
}
do {
if (!(v = atomic_load_explicit(&sem->sem_value, memory_order_relaxed))) {
rc = nsync_futex_wait_(&sem->sem_value, v, sem->sem_pshared,
sem_timeout(&ts, abstime));
if (rc == -EINTR) {
rc = eintr();
} else if (rc == -EAGAIN || rc == -EWOULDBLOCK) {
rc = 0;
} else if (rc == -ETIMEDOUT) {
_npassert(abstime);
if (_timespec_cmp(*abstime, _timespec_real()) <= 0) {
rc = etimedout();
} else {
rc = 0;
}
} else {
_npassert(!rc);
rc = 0;
}
} else if (v > 0) {
rc = 0;
} else {
rc = einval();
}
} while (!rc && (!v || !atomic_compare_exchange_weak_explicit(
&sem->sem_value, &v, v - 1, memory_order_acquire,
memory_order_relaxed)));
STRACE("sem_timedwait(%p, %s) → %d% m", sem, DescribeTimespec(0, abstime),
rc);
return rc;
}

42
libc/thread/sem_trywait.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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/assert.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/semaphore.h"
/**
* Locks semaphore only if it's currently not locked.
*
* @return 0 on success, or -1 w/ errno
* @raise EAGAIN if semaphore is locked
* @raise EDEADLK if deadlock was detected
* @raise EINVAL if `sem` is invalid
*/
int sem_trywait(sem_t *sem) {
int v;
v = atomic_load_explicit(&sem->sem_value, memory_order_relaxed);
do {
if (!v) return eagain();
if (v < 0) return einval();
} while (!atomic_compare_exchange_weak_explicit(
&sem->sem_value, &v, v - 1, memory_order_acquire, memory_order_relaxed));
return 0;
}

35
libc/thread/sem_unlink.c Normal file
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 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/calls.h"
#include "libc/thread/semaphore.h"
#include "libc/thread/semaphore.internal.h"
/**
* Removes named semaphore.
*
* @param name can be absolute path or should be component w/o slashes
* @return 0 on success, or -1 w/ errno
* @raise EPERM if pledge() is in play w/o `cpath` promise
* @raise ENOENT if named semaphore doesn't exist
* @raise EACCES if permission is denied
*/
int sem_unlink(const char *name) {
char path[PATH_MAX];
return unlink(__sem_name(name, path));
}

31
libc/thread/sem_wait.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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/thread/semaphore.h"
/**
* Locks semaphore.
*
* @return 0 on success, or -1 w/ errno
* @raise EINTR if signal was delivered instead
* @raise EDEADLK if deadlock was detected
* @raise EINVAL if `sem` is invalid
*/
int sem_wait(sem_t *sem) {
return sem_timedwait(sem, 0);
}

32
libc/thread/semaphore.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SEMAPHORE_H_
#define COSMOPOLITAN_LIBC_CALLS_SEMAPHORE_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define SEM_FAILED ((sem_t *)0)
typedef struct {
union {
struct {
_Atomic(int) sem_value;
bool sem_pshared;
};
void *sem_space[32];
};
} sem_t;
int sem_init(sem_t *, int, unsigned);
int sem_destroy(sem_t *);
int sem_post(sem_t *);
int sem_wait(sem_t *);
int sem_trywait(sem_t *);
int sem_timedwait(sem_t *, const struct timespec *);
int sem_getvalue(sem_t *, int *);
sem_t *sem_open(const char *, int, ...);
int sem_close(sem_t *);
int sem_unlink(const char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SEMAPHORE_H_ */

View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_SEMAPHORE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_THREAD_SEMAPHORE_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
const char *__sem_name(const char *, char[hasatleast PATH_MAX]) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_SEMAPHORE_INTERNAL_H_ */

View file

@ -200,8 +200,6 @@ void _pthread_cleanup_push(struct _pthread_cleanup_buffer *, void (*)(void *),
_pthread_cleanup_pop(&_buffer, (execute)); \
}
#define pthread_spin_init(pSpin, multiprocess) ((pSpin)->_lock = 0, 0)
#define pthread_spin_destroy(pSpin) ((pSpin)->_lock = -1, 0)
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 && \
!defined(__STRICT_ANSI__)
extern const errno_t EBUSY;
@ -222,6 +220,10 @@ extern const errno_t EBUSY;
pthread_spinlock_t *_s = pSpin; \
__atomic_test_and_set(&_s->_lock, __ATOMIC_ACQUIRE) ? EBUSY : 0; \
})
#define pthread_spin_init(pSpin, multiprocess) \
(__atomic_store_n(&(pSpin)->_lock, 0, __ATOMIC_RELAXED), 0)
#define pthread_spin_destroy(pSpin) \
(__atomic_store_n(&(pSpin)->_lock, -1, __ATOMIC_RELAXED), 0)
#endif /* GCC 4.7+ */
COSMOPOLITAN_C_END_

View file

@ -33,6 +33,6 @@
void _wait0(const atomic_int *ctid) {
int x;
while ((x = atomic_load_explicit(ctid, memory_order_relaxed))) {
nsync_futex_wait_((int *)ctid, x, !IsWindows(), 0);
nsync_futex_wait_(ctid, x, !IsWindows(), 0);
}
}