mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-01 15:30:29 +00:00
Improve threading and i/o routines
- On Windows connect() can now be interrupted by a signal; connect() w/ O_NONBLOCK will now raise EINPROGRESS; and connect() with SO_SNDTIMEO will raise ETIMEDOUT after the interval has elapsed. - We now get the AcceptEx(), ConnectEx(), and TransmitFile() functions from the WIN32 API the officially blessed way, using WSAIoctl(). - Do nothing on Windows when fsync() is called on a directory handle. This was raising EACCES earlier becaues GENERIC_WRITE is required on the handle. It's possible to FlushFileBuffers() a directory handle if it's opened with write access but MSDN doesn't document what it does. If you have any idea, please let us know! - Prefer manual reset event objects for read() and write() on Windows. - Do some code cleanup on our dlmalloc customizations. - Fix errno type error in Windows blocking routines. - Make the futex polyfill simpler and faster.
This commit is contained in:
parent
f7343319cc
commit
49b0eaa69f
43 changed files with 528 additions and 425 deletions
11
third_party/dlmalloc/dlmalloc.c
vendored
11
third_party/dlmalloc/dlmalloc.c
vendored
|
@ -1,14 +1,17 @@
|
|||
#include "third_party/dlmalloc/dlmalloc.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/yield.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
|
@ -19,7 +22,9 @@
|
|||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "third_party/dlmalloc/vespene.internal.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
// clang-format off
|
||||
|
||||
#define FOOTERS 0
|
||||
|
@ -45,7 +50,11 @@
|
|||
#endif
|
||||
|
||||
#undef assert
|
||||
#define assert(x) npassert(x)
|
||||
#if IsTiny()
|
||||
#define assert(x) if(!(x)) __builtin_unreachable()
|
||||
#else
|
||||
#define assert(x) if(!(x)) ABORT
|
||||
#endif
|
||||
|
||||
#include "third_party/dlmalloc/platform.inc"
|
||||
#include "third_party/dlmalloc/locks.inc"
|
||||
|
|
2
third_party/dlmalloc/dlmalloc.h
vendored
2
third_party/dlmalloc/dlmalloc.h
vendored
|
@ -507,7 +507,7 @@ void mspace_inspect_all(mspace msp,
|
|||
void* arg);
|
||||
|
||||
void dlmalloc_atfork(void);
|
||||
void dlmalloc_abort(void);
|
||||
void dlmalloc_abort(void) relegated wontreturn;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.h"
|
||||
|
||||
#define MESSAGE "dlmalloc_abort()\n"
|
||||
|
||||
void dlmalloc_abort(void) {
|
||||
write(2, MESSAGE, strlen(MESSAGE));
|
||||
if (_weaken(__die)) _weaken(__die)();
|
||||
tinyprint(2,
|
||||
"error: dlmalloc aborted\n"
|
||||
"cosmoaddr2line ",
|
||||
program_invocation_name, " ",
|
||||
DescribeBacktrace(__builtin_frame_address(0)), "\n", NULL);
|
||||
_Exit(44);
|
||||
}
|
87
third_party/dlmalloc/locks.inc
vendored
87
third_party/dlmalloc/locks.inc
vendored
|
@ -1,9 +1,4 @@
|
|||
// clang-format off
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/* --------------------------- Lock preliminaries ------------------------ */
|
||||
|
||||
|
@ -35,52 +30,48 @@
|
|||
|
||||
*/
|
||||
|
||||
static int malloc_lock(atomic_int *lk) {
|
||||
if (!__threaded) return 0;
|
||||
while (atomic_exchange_explicit(lk, 1, memory_order_acquire)) {
|
||||
donothing;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int malloc_trylock(atomic_int *lk) {
|
||||
if (!__threaded) return 1;
|
||||
return !atomic_exchange_explicit(lk, 1, memory_order_acquire);
|
||||
}
|
||||
|
||||
static inline int malloc_unlock(atomic_int *lk) {
|
||||
atomic_store_explicit(lk, 0, memory_order_release);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !USE_LOCKS
|
||||
#define USE_LOCK_BIT (0U)
|
||||
#define INITIAL_LOCK(l) (0)
|
||||
#define DESTROY_LOCK(l) (0)
|
||||
#define ACQUIRE_MALLOC_GLOBAL_LOCK()
|
||||
#define RELEASE_MALLOC_GLOBAL_LOCK()
|
||||
#elif defined(TINY)
|
||||
#define MLOCK_T atomic_int
|
||||
#define ACQUIRE_LOCK(lk) malloc_lock(lk)
|
||||
#define RELEASE_LOCK(lk) malloc_unlock(lk)
|
||||
#define TRY_LOCK(lk) malloc_trylock(lk)
|
||||
#define INITIAL_LOCK(lk) (atomic_store_explicit(lk, 0, memory_order_relaxed), 0)
|
||||
#define DESTROY_LOCK(lk)
|
||||
#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
|
||||
#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
|
||||
static MLOCK_T malloc_global_mutex;
|
||||
#ifdef TINY
|
||||
#define MLOCK_T atomic_uint
|
||||
#else
|
||||
#define MLOCK_T nsync_mu
|
||||
#define ACQUIRE_LOCK(lk) (__threaded && (nsync_mu_lock(lk), 0))
|
||||
#define RELEASE_LOCK(lk) (__threaded && (nsync_mu_unlock(lk), 0))
|
||||
#define TRY_LOCK(lk) (__threaded ? nsync_mu_trylock(lk) : 1)
|
||||
#define INITIAL_LOCK(lk) memset(lk, 0, sizeof(*lk))
|
||||
#define DESTROY_LOCK(lk) memset(lk, -1, sizeof(*lk))
|
||||
#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
|
||||
#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
|
||||
static MLOCK_T malloc_global_mutex;
|
||||
#define MLOCK_T nsync_mu
|
||||
#endif
|
||||
|
||||
static int malloc_wipe(MLOCK_T *lk) {
|
||||
bzero(lk, sizeof(*lk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int malloc_lock(MLOCK_T *lk) {
|
||||
if (!__threaded) return 0;
|
||||
#ifdef TINY
|
||||
while (atomic_exchange_explicit(lk, 1, memory_order_acquire)) {
|
||||
spin_yield();
|
||||
}
|
||||
#else
|
||||
nsync_mu_lock(lk);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int malloc_unlock(MLOCK_T *lk) {
|
||||
if (!__threaded) return 0;
|
||||
#ifdef TINY
|
||||
atomic_store_explicit(lk, 0, memory_order_release);
|
||||
#else
|
||||
nsync_mu_unlock(lk);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ACQUIRE_LOCK(lk) malloc_lock(lk)
|
||||
#define RELEASE_LOCK(lk) malloc_unlock(lk)
|
||||
#define INITIAL_LOCK(lk) malloc_wipe(lk)
|
||||
#define DESTROY_LOCK(lk)
|
||||
#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
|
||||
#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
|
||||
|
||||
static MLOCK_T malloc_global_mutex;
|
||||
|
||||
#define USE_LOCK_BIT (2U)
|
||||
|
||||
struct malloc_chunk {
|
||||
|
|
45
third_party/nsync/futex.c
vendored
45
third_party/nsync/futex.c
vendored
|
@ -38,6 +38,7 @@
|
|||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -129,46 +130,19 @@ static void nsync_futex_init_ (void) {
|
|||
}
|
||||
|
||||
static int nsync_futex_polyfill_ (atomic_int *w, int expect, struct timespec *abstime) {
|
||||
int rc;
|
||||
int64_t nanos, maxnanos;
|
||||
struct timespec now, wait, remain, deadline;
|
||||
|
||||
if (!abstime) {
|
||||
deadline = timespec_max;
|
||||
} else {
|
||||
deadline = *abstime;
|
||||
}
|
||||
|
||||
nanos = 100;
|
||||
maxnanos = __SIG_LOCK_INTERVAL_MS * 1000L * 1000;
|
||||
for (;;) {
|
||||
if (atomic_load_explicit (w, memory_order_acquire) != expect) {
|
||||
return 0;
|
||||
}
|
||||
now = timespec_real ();
|
||||
if (atomic_load_explicit (w, memory_order_acquire) != expect) {
|
||||
return 0;
|
||||
if (_weaken (pthread_testcancel_np) &&
|
||||
_weaken (pthread_testcancel_np) ()) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (timespec_cmp (now, deadline) >= 0) {
|
||||
break;
|
||||
}
|
||||
wait = timespec_fromnanos (nanos);
|
||||
remain = timespec_sub (deadline, now);
|
||||
if (timespec_cmp(wait, remain) > 0) {
|
||||
wait = remain;
|
||||
}
|
||||
if ((rc = clock_nanosleep (CLOCK_REALTIME, 0, &wait, 0))) {
|
||||
return -rc;
|
||||
}
|
||||
if (nanos < maxnanos) {
|
||||
nanos <<= 1;
|
||||
if (nanos > maxnanos) {
|
||||
nanos = maxnanos;
|
||||
}
|
||||
if (abstime && timespec_cmp (timespec_real (), *abstime) >= 0) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
pthread_yield ();
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare,
|
||||
|
@ -189,7 +163,7 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare,
|
|||
return etimedout();
|
||||
}
|
||||
remain = timespec_sub (deadline, now);
|
||||
interval = timespec_frommillis (__SIG_LOCK_INTERVAL_MS);
|
||||
interval = timespec_frommillis (5000);
|
||||
wait = timespec_cmp (remain, interval) > 0 ? interval : remain;
|
||||
if (atomic_load_explicit (w, memory_order_acquire) != expect) {
|
||||
return 0;
|
||||
|
@ -274,7 +248,7 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, const struct time
|
|||
us = -1u;
|
||||
}
|
||||
rc = ulock_wait (op, w, expect, us);
|
||||
if (rc > 0) rc = 0; // TODO(jart): What does it mean?
|
||||
if (rc > 0) rc = 0; // don't care about #waiters
|
||||
} else if (IsFreebsd ()) {
|
||||
rc = sys_umtx_timedwait_uint (w, expect, pshare, timeout);
|
||||
} else {
|
||||
|
@ -356,6 +330,7 @@ int nsync_futex_wake_ (atomic_int *w, int count, char pshare) {
|
|||
op |= ULF_WAKE_ALL;
|
||||
}
|
||||
rc = ulock_wake (op, w, 0);
|
||||
ASSERT (!rc || rc == -ENOENT);
|
||||
if (!rc) {
|
||||
rc = 1;
|
||||
} else if (rc == -ENOENT) {
|
||||
|
|
2
third_party/nsync/mu_semaphore.c
vendored
2
third_party/nsync/mu_semaphore.c
vendored
|
@ -23,7 +23,7 @@
|
|||
/* Apple's ulock (part by Cosmo futexes) is an internal API, but:
|
||||
1. Unlike GCD it's cancellable, i.e. can be EINTR'd by signals
|
||||
2. We currently always use ulock anyway for joining threads */
|
||||
#define PREFER_GCD_OVER_ULOCK 0
|
||||
#define PREFER_GCD_OVER_ULOCK 1
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
*NSYNC (Apache 2.0)\\n\
|
||||
|
|
4
third_party/nsync/mu_semaphore_gcd.c
vendored
4
third_party/nsync/mu_semaphore_gcd.c
vendored
|
@ -20,6 +20,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
@ -116,8 +117,7 @@ errno_t nsync_mu_semaphore_p_with_deadline_gcd (nsync_semaphore *s,
|
|||
(pt->pt_flags & PT_NOCANCEL)) {
|
||||
result = nsync_dispatch_semaphore_wait (s, abs_deadline);
|
||||
} else {
|
||||
struct timespec now, until, slice;
|
||||
slice = timespec_frommillis (__SIG_LOCK_INTERVAL_MS);
|
||||
struct timespec now, until, slice = {0, 1000000000 / CLK_TCK};
|
||||
for (;;) {
|
||||
if (_weaken (pthread_testcancel_np) () == ECANCELED) {
|
||||
result = ECANCELED;
|
||||
|
|
11
third_party/nsync/panic.c
vendored
11
third_party/nsync/panic.c
vendored
|
@ -17,12 +17,17 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
// clang-format off
|
||||
|
||||
/* Aborts after printing the nul-terminated string s[]. */
|
||||
void nsync_panic_ (const char *s) {
|
||||
tinyprint (2, "nsync panic: ", s, NULL);
|
||||
notpossible;
|
||||
tinyprint(2, "error: nsync panic: ", s, "\n",
|
||||
"cosmoaddr2line ", program_invocation_name, " ",
|
||||
DescribeBacktrace (__builtin_frame_address (0)), "\n",
|
||||
NULL);
|
||||
_Exit (44);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue