mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-02 23:18:44 +00:00
Clean up some of the threading code
This commit is contained in:
parent
0547eabcd6
commit
9f963dc597
62 changed files with 175 additions and 582 deletions
33
examples/thread.c
Normal file
33
examples/thread.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Basic POSIX Threads Example.
|
||||
*
|
||||
* $ make -j8 o//examples/thread.com
|
||||
* $ o//examples/thread.com
|
||||
* hi there
|
||||
*
|
||||
*/
|
||||
|
||||
void *worker(void *arg) {
|
||||
fputs(arg, stdout);
|
||||
return "there\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
void *result;
|
||||
pthread_t id;
|
||||
pthread_create(&id, 0, worker, "hi ");
|
||||
pthread_join(id, &result);
|
||||
fputs(result, stdout);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
||||
#include "libc/intrin/nopl.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -9,6 +10,7 @@ hidden extern int __vforked;
|
|||
hidden extern bool __time_critical;
|
||||
hidden extern unsigned __sighandrvas[NSIG];
|
||||
hidden extern unsigned __sighandflags[NSIG];
|
||||
hidden extern pthread_mutex_t __fds_lock_obj;
|
||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||
|
||||
void __fds_lock(void);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/once.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/symboliclink.h"
|
||||
|
@ -35,17 +35,20 @@
|
|||
|
||||
__msabi extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW;
|
||||
|
||||
static bool AllowedToCreateSymlinks(void) {
|
||||
static _Bool g_winlink_allowed;
|
||||
static pthread_once_t g_winlink_once;
|
||||
|
||||
static textwindows void InitializeWinlink(void) {
|
||||
int64_t tok;
|
||||
struct NtLuid id;
|
||||
struct NtTokenPrivileges tp;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), kNtTokenAllAccess, &tok)) return 0;
|
||||
if (!LookupPrivilegeValue(0, u"SeCreateSymbolicLinkPrivilege", &id)) return 0;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), kNtTokenAllAccess, &tok)) return;
|
||||
if (!LookupPrivilegeValue(0, u"SeCreateSymbolicLinkPrivilege", &id)) return;
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = id;
|
||||
tp.Privileges[0].Attributes = kNtSePrivilegeEnabled;
|
||||
if (!AdjustTokenPrivileges(tok, 0, &tp, sizeof(tp), 0, 0)) return 0;
|
||||
return GetLastError() != kNtErrorNotAllAssigned;
|
||||
if (!AdjustTokenPrivileges(tok, 0, &tp, sizeof(tp), 0, 0)) return;
|
||||
g_winlink_allowed = GetLastError() != kNtErrorNotAllAssigned;
|
||||
}
|
||||
|
||||
textwindows int sys_symlinkat_nt(const char *target, int newdirfd,
|
||||
|
@ -79,7 +82,8 @@ textwindows int sys_symlinkat_nt(const char *target, int newdirfd,
|
|||
|
||||
// windows only lets administrators do this
|
||||
// even then we're required to ask for permission
|
||||
if (!_once(AllowedToCreateSymlinks())) {
|
||||
pthread_once(&g_winlink_once, InitializeWinlink);
|
||||
if (!g_winlink_allowed) {
|
||||
return eperm();
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define HAVE_STDBOOL_H
|
||||
#define HAVE_STDBOOL_H 1
|
||||
#if __STDC_VERSION__ + 0 >= 201112
|
||||
typedef _Bool bool;
|
||||
#define true ((bool)+1)
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
/**
|
||||
* Returns thread descriptor of the current thread.
|
||||
*/
|
||||
cthread_t(cthread_self)(void) {
|
||||
return (cthread_t)__get_tls();
|
||||
void(__fds_lock)(void) {
|
||||
pthread_mutex_lock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
void(__fds_unlock)(void) {
|
||||
pthread_mutex_unlock(&__fds_lock_obj);
|
||||
}
|
|
@ -17,10 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/pushpop.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -28,15 +27,7 @@
|
|||
STATIC_YOINK("_init_g_fds");
|
||||
|
||||
struct Fds g_fds;
|
||||
static pthread_mutex_t __fds_lock_obj;
|
||||
|
||||
void(__fds_lock)(void) {
|
||||
pthread_mutex_lock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
void(__fds_unlock)(void) {
|
||||
pthread_mutex_unlock(&__fds_lock_obj);
|
||||
}
|
||||
pthread_mutex_t __fds_lock_obj;
|
||||
|
||||
static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
|
||||
int64_t h;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* Returns process id.
|
||||
*
|
||||
* This function does not need to issue a system call. The PID is
|
||||
* tracked by a global variable which is updated atfork(). The only
|
||||
* tracked by a global variable which is updated at fork(). The only
|
||||
* exception is when the process is vfork()'d in which case a system
|
||||
* call shall be issued.
|
||||
*
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/internal.h"
|
||||
|
|
|
@ -16,18 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
STATIC_YOINK("_init__mmi");
|
||||
|
||||
struct MemoryIntervals _mmi;
|
||||
pthread_mutex_t __mmi_lock_obj; // recursive :'(
|
||||
|
||||
void(__mmi_lock)(void) {
|
||||
pthread_mutex_lock(&__mmi_lock_obj);
|
||||
}
|
||||
|
||||
void(__mmi_unlock)(void) {
|
||||
pthread_mutex_unlock(&__mmi_lock_obj);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,28 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
int cthread_memory_wait32(int* addr, int val, const struct timespec* timeout) {
|
||||
size_t size;
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
return _futex_wait(addr, val, PTHREAD_PROCESS_SHARED, timeout);
|
||||
} else {
|
||||
return sched_yield();
|
||||
}
|
||||
extern pthread_mutex_t __mmi_lock_obj;
|
||||
|
||||
void(__mmi_lock)(void) {
|
||||
pthread_mutex_lock(&__mmi_lock_obj);
|
||||
}
|
||||
|
||||
int cthread_memory_wake32(int* addr, int n) {
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
return _futex_wake(addr, n, PTHREAD_PROCESS_SHARED);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
void(__mmi_unlock)(void) {
|
||||
pthread_mutex_unlock(&__mmi_lock_obj);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,47 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
static struct AtFork {
|
||||
volatile size_t i;
|
||||
struct AtForkCallback {
|
||||
void (*fn)(void *);
|
||||
void *arg;
|
||||
} p[ATEXIT_MAX];
|
||||
} g_atfork;
|
||||
|
||||
/**
|
||||
* Registers function to be called by fork() in child.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @note vfork() won't invoke callbacks
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int atfork(void *fn, void *arg) {
|
||||
size_t i;
|
||||
for (;;) {
|
||||
i = g_atfork.i;
|
||||
if (i == ARRAYLEN(g_atfork.p)) return enomem();
|
||||
if (_cmpxchg(&g_atfork.i, i, i + 1)) {
|
||||
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers callbacks registered by atfork().
|
||||
*
|
||||
* @note only fork() should call this
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void __onfork(void) {
|
||||
size_t i;
|
||||
for (i = 0; i < g_atfork.i; ++i) {
|
||||
g_atfork.p[i].fn(g_atfork.p[i].arg);
|
||||
}
|
||||
}
|
||||
pthread_mutex_t __mmi_lock_obj; // recursive :'(
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ONCE_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ONCE_H_
|
||||
#include "libc/intrin/spinlock.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
#define _once(x) \
|
||||
({ \
|
||||
typeof(x) oncerc; \
|
||||
static bool once; \
|
||||
static typeof(oncerc) onceresult; \
|
||||
_Alignas(64) static char oncelock; \
|
||||
_spinlock(&oncelock); \
|
||||
if (once) { \
|
||||
oncerc = onceresult; \
|
||||
} else { \
|
||||
oncerc = onceresult = x; \
|
||||
} \
|
||||
_spunlock(&oncelock); \
|
||||
oncerc; \
|
||||
})
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ONCE_H_ */
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
|
||||
|
||||
#define PTHREAD_ONCE_INIT 0
|
||||
|
||||
#define PTHREAD_KEYS_MAX 64
|
||||
#define PTHREAD_STACK_MIN FRAMESIZE
|
||||
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
@ -27,6 +25,7 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* clang-format off */
|
||||
#define PTHREAD_ONCE_INIT {0}
|
||||
#define PTHREAD_COND_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
#define PTHREAD_BARRIER_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
#define PTHREAD_RWLOCK_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
|
@ -34,16 +33,22 @@ COSMOPOLITAN_C_START_
|
|||
PTHREAD_PROCESS_DEFAULT}
|
||||
/* clang-format on */
|
||||
|
||||
typedef void *pthread_t;
|
||||
typedef uintptr_t pthread_t;
|
||||
typedef int pthread_id_np_t;
|
||||
typedef char pthread_condattr_t;
|
||||
typedef char pthread_rwlockattr_t;
|
||||
typedef char pthread_barrierattr_t;
|
||||
typedef unsigned pthread_key_t;
|
||||
typedef _Atomic(char) pthread_once_t;
|
||||
typedef _Atomic(char) pthread_spinlock_t;
|
||||
typedef void (*pthread_key_dtor)(void *);
|
||||
|
||||
typedef struct pthread_once_s {
|
||||
_Atomic(char) lock;
|
||||
} pthread_once_t;
|
||||
|
||||
typedef struct pthread_spinlock_s {
|
||||
_Atomic(char) lock;
|
||||
} pthread_spinlock_t;
|
||||
|
||||
typedef struct pthread_mutex_s {
|
||||
char type;
|
||||
char pshared;
|
||||
|
@ -167,45 +172,26 @@ int pthread_barrier_destroy(pthread_barrier_t *);
|
|||
int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *,
|
||||
unsigned);
|
||||
|
||||
#define pthread_spin_init(pSpin, multiprocess) (*(pSpin) = 0)
|
||||
#define pthread_spin_destroy(pSpin) (*(pSpin) = 0)
|
||||
#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
|
||||
extern const errno_t EBUSY;
|
||||
#define pthread_spin_unlock(pSpin) \
|
||||
(__atomic_store_n(pSpin, 0, __ATOMIC_RELAXED), 0)
|
||||
#define pthread_spin_trylock(pSpin) \
|
||||
(__atomic_test_and_set(pSpin, __ATOMIC_SEQ_CST) ? EBUSY : 0)
|
||||
#ifdef TINY
|
||||
#define pthread_spin_lock(pSpin) _pthread_spin_lock_tiny(pSpin)
|
||||
#else
|
||||
#define pthread_spin_lock(pSpin) _pthread_spin_lock_cooperative(pSpin)
|
||||
#endif
|
||||
#define _pthread_spin_lock_tiny(pSpin) \
|
||||
({ \
|
||||
while (__atomic_test_and_set(pSpin, __ATOMIC_SEQ_CST)) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
0; \
|
||||
#define pthread_spin_lock(pSpin) \
|
||||
({ \
|
||||
pthread_spinlock_t *_s = pSpin; \
|
||||
while (__atomic_test_and_set(&_s->lock, __ATOMIC_SEQ_CST)) donothing; \
|
||||
0; \
|
||||
})
|
||||
#define _pthread_spin_lock_cooperative(pSpin) \
|
||||
({ \
|
||||
char __x; \
|
||||
volatile int __i; \
|
||||
unsigned __tries = 0; \
|
||||
pthread_spinlock_t *__lock = pSpin; \
|
||||
for (;;) { \
|
||||
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
|
||||
if (!__x && !__atomic_test_and_set(__lock, __ATOMIC_SEQ_CST)) { \
|
||||
break; \
|
||||
} else if (__tries < 7) { \
|
||||
for (__i = 0; __i != 1 << __tries; __i++) { \
|
||||
} \
|
||||
__tries++; \
|
||||
} else { \
|
||||
pthread_yield(); \
|
||||
} \
|
||||
} \
|
||||
0; \
|
||||
#define pthread_spin_unlock(pSpin) \
|
||||
({ \
|
||||
pthread_spinlock_t *_s = pSpin; \
|
||||
__atomic_store_n(&_s->lock, 0, __ATOMIC_RELAXED); \
|
||||
0; \
|
||||
})
|
||||
#define pthread_spin_trylock(pSpin) \
|
||||
({ \
|
||||
pthread_spinlock_t *_s = pSpin; \
|
||||
__atomic_test_and_set(&_s->lock, __ATOMIC_SEQ_CST) ? EBUSY : 0; \
|
||||
})
|
||||
#endif /* GCC 4.7+ */
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/linux/futex.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
|
@ -85,20 +84,6 @@ static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int expect,
|
|||
* // do work...
|
||||
* pthread_mutex_unlock(&lock);
|
||||
*
|
||||
* Microbenchmarks for single-threaded lock + unlock:
|
||||
*
|
||||
* pthread_spinlock_t : 12c ( 4ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 37c ( 12ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 22c ( 7ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 27c ( 9ns)
|
||||
*
|
||||
* Microbenchmarks for multi-threaded lock + unlock:
|
||||
*
|
||||
* pthread_spinlock_t : 2,396c (774ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 535c (173ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 1,045c (338ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 917c (296ns)
|
||||
*
|
||||
* @return 0 on success, or error number on failure
|
||||
* @see pthread_spin_lock()
|
||||
*/
|
||||
|
|
|
@ -45,20 +45,21 @@
|
|||
*/
|
||||
int pthread_once(pthread_once_t *once, void init(void)) {
|
||||
char old;
|
||||
switch ((old = atomic_load_explicit(once, memory_order_relaxed))) {
|
||||
switch ((old = atomic_load_explicit(&once->lock, memory_order_relaxed))) {
|
||||
case INIT:
|
||||
if (atomic_compare_exchange_strong_explicit(once, &old, CALLING,
|
||||
if (atomic_compare_exchange_strong_explicit(&once->lock, &old, CALLING,
|
||||
memory_order_acquire,
|
||||
memory_order_relaxed)) {
|
||||
init();
|
||||
atomic_store(once, FINISHED);
|
||||
atomic_store(&once->lock, FINISHED);
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
case CALLING:
|
||||
do {
|
||||
pthread_yield();
|
||||
} while (atomic_load_explicit(once, memory_order_relaxed) == CALLING);
|
||||
} while (atomic_load_explicit(&once->lock, memory_order_relaxed) ==
|
||||
CALLING);
|
||||
break;
|
||||
case FINISHED:
|
||||
break;
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
/**
|
||||
* Acquires spin lock.
|
||||
*
|
||||
* spin l: 181,570c 58,646ns
|
||||
* mutex normal l: 297,965c 96,241ns
|
||||
* mutex recursive l: 1,112,166c 359,223ns
|
||||
* mutex errorcheck l: 1,449,723c 468,252ns
|
||||
*
|
||||
* If the lock is already held, this function will wait for it to become
|
||||
* available. No genuine error conditions are currently defined. This is
|
||||
* similar to pthread_mutex_lock() except spin locks are much simpler so
|
||||
|
@ -45,7 +40,7 @@
|
|||
*
|
||||
* Cosmopolitan permits succinct notation for spin locks:
|
||||
*
|
||||
* pthread_spinlock_t lock = 0;
|
||||
* pthread_spinlock_t lock = {0};
|
||||
* pthread_spin_lock(&lock);
|
||||
* // do work...
|
||||
* pthread_spin_unlock(&lock);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/_getauxval.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
void __releasefd(int fd) {
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
#ifdef TINY
|
||||
#define _spinlock(lock) _spinlock_tiny(lock)
|
||||
#else
|
||||
#define _spinlock(lock) _spinlock_cooperative(lock)
|
||||
#endif
|
||||
|
||||
#define _spunlock(lock) (__atomic_store_n(lock, 0, __ATOMIC_RELAXED), 0)
|
||||
|
||||
#define _seizelock(lock, value) \
|
||||
({ \
|
||||
autotype(lock) __lock = (lock); \
|
||||
typeof(*__lock) __x = (value); \
|
||||
__atomic_store(__lock, &__x, __ATOMIC_RELEASE); \
|
||||
})
|
||||
|
||||
#define _spinlock_tiny(lock) \
|
||||
({ \
|
||||
while (_trylock(lock)) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
0; \
|
||||
})
|
||||
|
||||
#define _spinlock_cooperative(lock) \
|
||||
({ \
|
||||
char __x; \
|
||||
volatile int __i; \
|
||||
unsigned __tries = 0; \
|
||||
char *__lock = (lock); \
|
||||
for (;;) { \
|
||||
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
|
||||
if (!__x && !_trylock(__lock)) { \
|
||||
break; \
|
||||
} else if (__tries < 7) { \
|
||||
for (__i = 0; __i != 1 << __tries; __i++) { \
|
||||
} \
|
||||
__tries++; \
|
||||
} else { \
|
||||
_spinlock_yield(); \
|
||||
} \
|
||||
} \
|
||||
0; \
|
||||
})
|
||||
|
||||
#define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST)
|
||||
|
||||
int _spinlock_yield(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */
|
|
@ -16,8 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -27,7 +25,8 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
|
@ -72,10 +71,7 @@ static void DeferFunction(struct StackFrame *frame, void *fn, void *arg) {
|
|||
if (!(g = malloc(sizeof(struct Garbages)))) notpossible;
|
||||
g->i = 0;
|
||||
g->n = 4;
|
||||
if (!(g->p = malloc(g->n * sizeof(struct Garbage)))) {
|
||||
kprintf("malloc failed\n");
|
||||
notpossible;
|
||||
}
|
||||
if (!(g->p = malloc(g->n * sizeof(struct Garbage)))) notpossible;
|
||||
tls->garbages = g;
|
||||
} else if (UNLIKELY(g->i == g->n)) {
|
||||
p2 = g->p;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
|
@ -63,7 +63,7 @@ struct CloneArgs {
|
|||
uint32_t utid;
|
||||
int64_t tid64;
|
||||
};
|
||||
char lock;
|
||||
pthread_spinlock_t lock;
|
||||
int *ptid;
|
||||
int *ctid;
|
||||
int *ztid;
|
||||
|
@ -163,7 +163,7 @@ XnuThreadMain(void *pthread, // rdi
|
|||
wt->tid = tid;
|
||||
*wt->ptid = tid;
|
||||
*wt->ctid = tid;
|
||||
_spunlock(&wt->lock);
|
||||
pthread_spin_unlock(&wt->lock);
|
||||
|
||||
if (wt->tls) {
|
||||
// XNU uses the same 0x30 offset as the WIN32 TIB x64. They told the
|
||||
|
@ -216,11 +216,11 @@ static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags,
|
|||
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
|
||||
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
|
||||
wt->tls = flags & CLONE_SETTLS ? tls : 0;
|
||||
wt->lock = 1;
|
||||
wt->lock.lock = 1;
|
||||
if ((rc = bsdthread_create(fn, arg, wt, 0, PTHREAD_START_CUSTOM_XNU)) != -1) {
|
||||
_spinlock(&wt->lock);
|
||||
pthread_spin_lock(&wt->lock);
|
||||
rc = wt->tid;
|
||||
_spunlock(&wt->lock);
|
||||
pthread_spin_unlock(&wt->lock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,18 +16,17 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Creates new process.
|
||||
|
@ -37,14 +36,17 @@
|
|||
*/
|
||||
int fork(void) {
|
||||
axdx_t ad;
|
||||
sigset_t old, all;
|
||||
int ax, dx, parent;
|
||||
sigfillset(&all);
|
||||
sigprocmask(SIG_BLOCK, &all, &old);
|
||||
if (!IsWindows()) {
|
||||
ad = sys_fork();
|
||||
ax = ad.ax;
|
||||
dx = ad.dx;
|
||||
if (IsXnu() && ax != -1) {
|
||||
/* eax always returned with childs pid */
|
||||
/* edx is 0 for parent and 1 for child */
|
||||
// eax always returned with childs pid
|
||||
// edx is 0 for parent and 1 for child
|
||||
ax &= dx - 1;
|
||||
}
|
||||
} else {
|
||||
|
@ -62,11 +64,10 @@ int fork(void) {
|
|||
*(int *)(__get_tls() + 0x38) = IsLinux() ? dx : sys_gettid();
|
||||
}
|
||||
STRACE("fork() → 0 (child of %d)", parent);
|
||||
if (weaken(__onfork)) {
|
||||
weaken(__onfork)();
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &old, 0);
|
||||
} else {
|
||||
STRACE("fork() → %d% m", ax);
|
||||
sigprocmask(SIG_SETMASK, &old, 0);
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -32,7 +32,7 @@
|
|||
#include "libc/zipos/zipos.internal.h"
|
||||
#include "third_party/zlib/puff.h"
|
||||
|
||||
static int g_lock;
|
||||
static pthread_spinlock_t g_lock;
|
||||
hidden struct SymbolTable *__symtab; // for kprintf
|
||||
|
||||
/**
|
||||
|
@ -125,7 +125,7 @@ static struct SymbolTable *GetSymbolTableFromElf(void) {
|
|||
*/
|
||||
struct SymbolTable *GetSymbolTable(void) {
|
||||
struct Zipos *z;
|
||||
if (_trylock(&g_lock)) return 0;
|
||||
if (pthread_spin_trylock(&g_lock)) return 0;
|
||||
if (!__symtab && !__isworker) {
|
||||
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
|
||||
if ((__symtab = GetSymbolTableFromZip(z))) {
|
||||
|
@ -139,7 +139,7 @@ struct SymbolTable *GetSymbolTable(void) {
|
|||
__symtab = GetSymbolTableFromElf();
|
||||
}
|
||||
}
|
||||
_spunlock(&g_lock);
|
||||
pthread_spin_unlock(&g_lock);
|
||||
return __symtab;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/memory.h"
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
|
|
@ -17,12 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sock/yoink.inc"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_getsockname_nt(struct Fd *fd, void *out_addr,
|
||||
uint32_t *out_addrsize) {
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/iphlpapi.h"
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/pushpop.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/stdio/fflush.internal.h"
|
||||
#include "libc/stdio/lock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
|
|
@ -32,7 +32,7 @@ struct lconv {
|
|||
|
||||
int wcwidth(wchar_t) pureconst;
|
||||
int wcswidth(const wchar_t *, size_t) strlenesque;
|
||||
int wcsnwidth(const wchar_t *, size_t, size_t) strlenesque;
|
||||
int wcsnwidth(const wchar_t *, size_t, int) strlenesque;
|
||||
struct lconv *localeconv(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* Returns monospace display width of wide character string.
|
||||
*/
|
||||
int wcsnwidth(const wchar_t *pwcs, size_t n, size_t o) {
|
||||
int wcsnwidth(const wchar_t *pwcs, size_t n, int o) {
|
||||
int w, width = 0;
|
||||
for (; *pwcs && n-- > 0; pwcs++) {
|
||||
if ((w = wcwidth(*pwcs)) < 0) {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/internal.h"
|
||||
|
@ -52,7 +52,7 @@ static int x;
|
|||
char g_testlib_olddir[PATH_MAX];
|
||||
char g_testlib_tmpdir[PATH_MAX];
|
||||
struct sigaction wanthandlers[31];
|
||||
static char testlib_error_lock;
|
||||
static pthread_spinlock_t testlib_error_lock;
|
||||
|
||||
void testlib_finish(void) {
|
||||
if (g_testlib_failed) {
|
||||
|
@ -64,7 +64,7 @@ void testlib_finish(void) {
|
|||
void testlib_error_enter(const char *file, const char *func) {
|
||||
atomic_fetch_sub_explicit(&__ftrace, 1, memory_order_relaxed);
|
||||
atomic_fetch_sub_explicit(&__strace, 1, memory_order_relaxed);
|
||||
if (!__vforked) _spinlock(&testlib_error_lock);
|
||||
if (!__vforked) pthread_spin_lock(&testlib_error_lock);
|
||||
if (!IsWindows()) sys_getpid(); /* make strace easier to read */
|
||||
if (!IsWindows()) sys_getpid();
|
||||
if (g_testlib_shoulddebugbreak) {
|
||||
|
@ -77,7 +77,7 @@ void testlib_error_enter(const char *file, const char *func) {
|
|||
void testlib_error_leave(void) {
|
||||
atomic_fetch_add_explicit(&__ftrace, 1, memory_order_relaxed);
|
||||
atomic_fetch_add_explicit(&__strace, 1, memory_order_relaxed);
|
||||
_spunlock(&testlib_error_lock);
|
||||
pthread_spin_unlock(&testlib_error_lock);
|
||||
}
|
||||
|
||||
wontreturn void testlib_abort(void) {
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*-*- 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/errno.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#define MIN_STACKSIZE (8 * PAGESIZE) // includes guard, rounds up to FRAMESIZE
|
||||
#define MIN_GUARDSIZE PAGESIZE
|
||||
|
||||
// CTOR/DTOR
|
||||
int cthread_attr_init(cthread_attr_t* attr) {
|
||||
attr->stacksize = GetStackSize();
|
||||
attr->guardsize = PAGESIZE;
|
||||
attr->mode = CTHREAD_CREATE_JOINABLE;
|
||||
return 0;
|
||||
}
|
||||
int cthread_attr_destroy(cthread_attr_t* attr) {
|
||||
(void)attr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// stacksize
|
||||
int cthread_attr_setstacksize(cthread_attr_t* attr, size_t size) {
|
||||
if (size & (PAGESIZE - 1)) return EINVAL;
|
||||
if (size < MIN_STACKSIZE) return EINVAL;
|
||||
attr->stacksize = size;
|
||||
return 0;
|
||||
}
|
||||
size_t cthread_attr_getstacksize(const cthread_attr_t* attr) {
|
||||
return attr->stacksize;
|
||||
}
|
||||
|
||||
// guardsize
|
||||
int cthread_attr_setguardsize(cthread_attr_t* attr, size_t size) {
|
||||
if (size & (PAGESIZE - 1)) return EINVAL;
|
||||
if (size < MIN_GUARDSIZE) return EINVAL;
|
||||
attr->guardsize = size;
|
||||
return 0;
|
||||
}
|
||||
size_t cthread_attr_getguardsize(const cthread_attr_t* attr) {
|
||||
return attr->guardsize;
|
||||
}
|
||||
|
||||
// detachstate
|
||||
int cthread_attr_setdetachstate(cthread_attr_t* attr, int mode) {
|
||||
if (mode & ~(CTHREAD_CREATE_JOINABLE | CTHREAD_CREATE_DETACHED))
|
||||
return EINVAL;
|
||||
attr->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
int cthread_attr_getdetachstate(const cthread_attr_t* attr) {
|
||||
return attr->mode;
|
||||
}
|
|
@ -53,7 +53,7 @@ static int PosixThread(void *arg, int tid) {
|
|||
struct PosixThread *pt = arg;
|
||||
enum PosixThreadStatus status;
|
||||
if (!setjmp(pt->exiter)) {
|
||||
((cthread_t)__get_tls())->pthread = pt;
|
||||
((cthread_t)__get_tls())->pthread = (pthread_t)pt;
|
||||
pt->rc = pt->start_routine(pt->arg);
|
||||
}
|
||||
if (weaken(_pthread_key_destruct)) {
|
||||
|
@ -72,7 +72,20 @@ static int PosixThread(void *arg, int tid) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates thread.
|
||||
* Creates thread, e.g.
|
||||
*
|
||||
* void *worker(void *arg) {
|
||||
* fputs(arg, stdout);
|
||||
* return "there\n";
|
||||
* }
|
||||
*
|
||||
* int main() {
|
||||
* void *result;
|
||||
* pthread_t id;
|
||||
* pthread_create(&id, 0, worker, "hi ");
|
||||
* pthread_join(id, &result);
|
||||
* fputs(result, stdout);
|
||||
* }
|
||||
*
|
||||
* Here's the OSI model of threads in Cosmopolitan:
|
||||
*
|
||||
|
@ -216,7 +229,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|||
}
|
||||
|
||||
if (thread) {
|
||||
*thread = pt;
|
||||
*thread = (pthread_t)pt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
int pthread_detach(pthread_t thread) {
|
||||
enum PosixThreadStatus status;
|
||||
struct PosixThread *pt = thread;
|
||||
struct PosixThread *pt = (struct PosixThread *)thread;
|
||||
for (;;) {
|
||||
status = atomic_load_explicit(&pt->status, memory_order_relaxed);
|
||||
if (status == kPosixThreadDetached || status == kPosixThreadZombie) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* @return nonzero if equal, otherwise zero
|
||||
*/
|
||||
int pthread_equal(pthread_t t1, pthread_t t2) {
|
||||
struct PosixThread *a = t1;
|
||||
struct PosixThread *b = t2;
|
||||
struct PosixThread *a = (struct PosixThread *)t1;
|
||||
struct PosixThread *b = (struct PosixThread *)t2;
|
||||
return a->spawn.ptid == b->spawn.ptid;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
wontreturn void pthread_exit(void *rc) {
|
||||
struct PosixThread *pt;
|
||||
if ((pt = ((cthread_t)__get_tls())->pthread)) {
|
||||
if ((pt = (struct PosixThread *)((cthread_t)__get_tls())->pthread)) {
|
||||
pt->rc = rc;
|
||||
_gclongjmp(pt->exiter, 1);
|
||||
} else {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "libc/thread/thread.h"
|
||||
|
||||
int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) {
|
||||
struct PosixThread *pt = thread;
|
||||
struct PosixThread *pt = (struct PosixThread *)thread;
|
||||
memcpy(attr, &pt->attr, sizeof(pt->attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
* Returns thread id of POSIX thread.
|
||||
*/
|
||||
int64_t pthread_getunique_np(pthread_t thread) {
|
||||
struct PosixThread *pt = thread;
|
||||
struct PosixThread *pt = (struct PosixThread *)thread;
|
||||
return pt->spawn.ptid;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* @raise EDEADLK if thread is detached
|
||||
*/
|
||||
int pthread_join(pthread_t thread, void **value_ptr) {
|
||||
struct PosixThread *pt = thread;
|
||||
struct PosixThread *pt = (struct PosixThread *)thread;
|
||||
if (pt->status == kPosixThreadDetached || //
|
||||
pt->status == kPosixThreadZombie) {
|
||||
assert(!"badjoin");
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
/*-*- 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/intrin/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#define CTHREAD_THREAD_VAL_BITS 32
|
||||
|
||||
static void Pause(int attempt) {
|
||||
if (attempt < 16) {
|
||||
for (int i = 0; i < (1 << attempt); ++i) {
|
||||
__builtin_ia32_pause();
|
||||
}
|
||||
} else {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes semaphore.
|
||||
*/
|
||||
int cthread_sem_init(cthread_sem_t* sem, int count) {
|
||||
sem->linux.count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys semaphore.
|
||||
*/
|
||||
int cthread_sem_destroy(cthread_sem_t* sem) {
|
||||
(void)sem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies a thread waiting on semaphore.
|
||||
*/
|
||||
int cthread_sem_signal(cthread_sem_t* sem) {
|
||||
uint64_t count;
|
||||
count = atomic_fetch_add(&sem->linux.count, 1);
|
||||
if ((count >> CTHREAD_THREAD_VAL_BITS)) {
|
||||
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
||||
void* wait_address = &sem->linux.count;
|
||||
cthread_memory_wake32(wait_address, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on semaphore with kernel assistance.
|
||||
*/
|
||||
int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) {
|
||||
uint64_t count;
|
||||
|
||||
// record current thread as waiter
|
||||
count = atomic_fetch_add(&sem->linux.count,
|
||||
(uint64_t)1 << CTHREAD_THREAD_VAL_BITS);
|
||||
|
||||
for (;;) {
|
||||
// try to acquire the semaphore, as well as remove itself from waiters
|
||||
while ((uint32_t)count > 0) {
|
||||
// without spin, we could miss a futex wake
|
||||
if (atomic_compare_exchange_weak(
|
||||
&sem->linux.count, &count,
|
||||
count - 1 - ((uint64_t)1 << CTHREAD_THREAD_VAL_BITS))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
||||
void* wait_address = &sem->linux.count;
|
||||
cthread_memory_wait32(wait_address, count, timeout);
|
||||
count = atomic_load(&sem->linux.count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on semaphore without kernel assistance.
|
||||
*/
|
||||
int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin,
|
||||
const struct timespec* timeout) {
|
||||
// spin on pause
|
||||
for (int attempt = 0; attempt < spin; ++attempt) {
|
||||
// if ((count >> CTHREAD_THREAD_VAL_BITS) != 0) break;
|
||||
while ((uint32_t)count > 0) {
|
||||
// spin is useful if multiple waiters can acquire the semaphore at the
|
||||
// same time
|
||||
if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Pause(attempt);
|
||||
}
|
||||
|
||||
return cthread_sem_wait_futex(sem, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on semaphore.
|
||||
*/
|
||||
int cthread_sem_wait(cthread_sem_t* sem, int spin,
|
||||
const struct timespec* timeout) {
|
||||
uint64_t count = atomic_load(&sem->linux.count);
|
||||
|
||||
// uncontended
|
||||
while ((uint32_t)count > 0) {
|
||||
// spin is useful if multiple waiters can acquire the semaphore at the same
|
||||
// time
|
||||
if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return cthread_sem_wait_spin(sem, count, spin, timeout);
|
||||
}
|
|
@ -1,23 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/locale.h"
|
||||
|
||||
#define CTHREAD_CREATE_DETACHED 1
|
||||
#define CTHREAD_CREATE_JOINABLE 0
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum cthread_state {
|
||||
cthread_started = 0,
|
||||
cthread_joining = 1,
|
||||
cthread_finished = 2,
|
||||
cthread_detached = 4,
|
||||
};
|
||||
|
||||
struct FtraceTls { /* 16 */
|
||||
bool once; /* 0 */
|
||||
bool noreentry; /* 1 */
|
||||
|
@ -38,32 +26,6 @@ struct cthread_descriptor_t {
|
|||
|
||||
typedef struct cthread_descriptor_t *cthread_t;
|
||||
|
||||
typedef union cthread_sem_t {
|
||||
struct {
|
||||
uint64_t count;
|
||||
} linux;
|
||||
} cthread_sem_t;
|
||||
|
||||
typedef struct cthread_attr_t {
|
||||
size_t stacksize, guardsize;
|
||||
int mode;
|
||||
} cthread_attr_t;
|
||||
|
||||
cthread_t cthread_self(void);
|
||||
int cthread_attr_init(cthread_attr_t *);
|
||||
int cthread_attr_destroy(cthread_attr_t *);
|
||||
int cthread_attr_setstacksize(cthread_attr_t *, size_t);
|
||||
size_t thread_attr_getstacksize(const cthread_attr_t *);
|
||||
int cthread_attr_setguardsize(cthread_attr_t *, size_t);
|
||||
size_t cthread_attr_getguardsize(const cthread_attr_t *);
|
||||
int cthread_attr_setdetachstate(cthread_attr_t *, int);
|
||||
int cthread_attr_getdetachstate(const cthread_attr_t *);
|
||||
int cthread_sem_init(cthread_sem_t *, int);
|
||||
int cthread_sem_destroy(cthread_sem_t *);
|
||||
int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *);
|
||||
int cthread_sem_signal(cthread_sem_t *);
|
||||
int cthread_memory_wait32(int *, int, const struct timespec *);
|
||||
int cthread_memory_wake32(int *, int);
|
||||
void cthread_ungarbage(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/nopl.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
|
|
|
@ -109,7 +109,7 @@ void BenchLockUnlock(pthread_mutex_t *m) {
|
|||
|
||||
BENCH(pthread_mutex_lock, bench_uncontended) {
|
||||
{
|
||||
pthread_spinlock_t s = 0;
|
||||
pthread_spinlock_t s = {0};
|
||||
EZBENCH2("spin 1x", donothing, BenchSpinUnspin(&s));
|
||||
}
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ int MutexContentionWorker(void *arg, int tid) {
|
|||
BENCH(pthread_mutex_lock, bench_contended) {
|
||||
struct spawn t;
|
||||
{
|
||||
pthread_spinlock_t s = 0;
|
||||
pthread_spinlock_t s = {0};
|
||||
struct SpinContentionArgs a = {&s};
|
||||
_spawn(SpinContentionWorker, &a, &t);
|
||||
while (!a.ready) sched_yield();
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
|
@ -29,10 +32,6 @@
|
|||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio proc", 0));
|
||||
}
|
||||
|
||||
TEST(fork, testPipes) {
|
||||
int a, b;
|
||||
int ws, pid;
|
||||
|
@ -142,5 +141,5 @@ void ForkInSerial(void) {
|
|||
}
|
||||
|
||||
BENCH(fork, bench) {
|
||||
EZBENCH2("fork", donothing, ForkInSerial());
|
||||
EZBENCH2("fork a", donothing, ForkInSerial());
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/calls/struct/sched_param.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
|
|
|
@ -16,27 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/bisectcarleft.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/sysparam.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/bisectcarleft.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -343,7 +343,7 @@ static struct Shared {
|
|||
#include "tool/net/counters.inc"
|
||||
#undef C
|
||||
} c;
|
||||
_Alignas(64) char montermlock;
|
||||
pthread_spinlock_t montermlock;
|
||||
} * shared;
|
||||
|
||||
static const char kCounterNames[] =
|
||||
|
@ -6257,7 +6257,7 @@ static int MemoryMonitor(void *arg, int tid) {
|
|||
sigaddset(&ss, SIGUSR2);
|
||||
sigprocmask(SIG_BLOCK, &ss, 0);
|
||||
|
||||
_spinlock(&shared->montermlock);
|
||||
pthread_spin_lock(&shared->montermlock);
|
||||
if (!id) {
|
||||
if ((tty = open(monitortty, O_RDWR | O_NOCTTY)) != -1) {
|
||||
ioctl(tty, TCGETS, &oldterm);
|
||||
|
@ -6273,7 +6273,7 @@ static int MemoryMonitor(void *arg, int tid) {
|
|||
WRITE(tty, "\e[?25l", 6);
|
||||
}
|
||||
}
|
||||
_spunlock(&shared->montermlock);
|
||||
pthread_spin_unlock(&shared->montermlock);
|
||||
|
||||
if (tty != -1) {
|
||||
for (gen = 0, mi = 0, b = 0; !terminatemonitor;) {
|
||||
|
@ -6355,11 +6355,11 @@ static int MemoryMonitor(void *arg, int tid) {
|
|||
" GEN=%ld\e[J",
|
||||
id, getpid(), ws.ws_col, ws.ws_row, workers, gen);
|
||||
|
||||
_spinlock(&shared->montermlock);
|
||||
pthread_spin_lock(&shared->montermlock);
|
||||
WRITE(tty, b, appendz(b).i);
|
||||
appendr(&b, 0);
|
||||
usleep(MONITOR_MICROS);
|
||||
_spunlock(&shared->montermlock);
|
||||
pthread_spin_unlock(&shared->montermlock);
|
||||
} else {
|
||||
// running out of memory temporarily is a real possibility here
|
||||
// the right thing to do, is stand aside and let lua try to fix
|
||||
|
|
Loading…
Add table
Reference in a new issue