mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Introduce pthread_rwlock_try{rd,wr}lock
This also changes recursive mutexes to favor cpu over scheduler yield.
This commit is contained in:
parent
a1e1e821cb
commit
fadb64a2bf
13 changed files with 122 additions and 29 deletions
|
@ -145,6 +145,8 @@ o/$(MODE)/libc/calls/tailcontext.o: libc/calls/tailcontext.S
|
|||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/calls/stackjump.o: libc/calls/stackjump.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/calls/sched_yield.o: libc/calls/sched_yield.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
|
|
|
@ -119,8 +119,6 @@ o/$(MODE)/libc/intrin/ksockoptnames.o: libc/intrin/ksockoptnames.S
|
|||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/intrin/ktcpoptnames.o: libc/intrin/ktcpoptnames.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/intrin/sched_yield.o: libc/intrin/sched_yield.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/intrin/stackcall.o: libc/intrin/stackcall.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nexgen32e/yield.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
@ -64,7 +65,7 @@
|
|||
* @see pthread_spin_lock()
|
||||
* @vforksafe
|
||||
*/
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
errno_t pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int t;
|
||||
|
||||
LOCKTRACE("pthread_mutex_lock(%t)", mutex);
|
||||
|
@ -82,7 +83,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
|||
|
||||
if (mutex->_type == PTHREAD_MUTEX_NORMAL) {
|
||||
while (atomic_exchange_explicit(&mutex->_lock, 1, memory_order_acquire)) {
|
||||
pthread_yield();
|
||||
spin_yield();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
|||
}
|
||||
|
||||
while (atomic_exchange_explicit(&mutex->_lock, 1, memory_order_acquire)) {
|
||||
pthread_yield();
|
||||
spin_yield();
|
||||
}
|
||||
|
||||
mutex->_depth = 0;
|
||||
|
|
|
@ -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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 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 │
|
||||
|
@ -19,27 +19,29 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
|
||||
/**
|
||||
* Locks mutex if it isn't locked already.
|
||||
* Attempts acquiring lock.
|
||||
*
|
||||
* Unlike pthread_mutex_lock() this function won't block and instead
|
||||
* returns an error immediately if the lock couldn't be acquired.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EBUSY if lock is already held
|
||||
* @raise ENOTRECOVERABLE if `mutex` is corrupted
|
||||
* @return 0 if lock was acquired, otherwise an errno
|
||||
* @raise EAGAIN if maximum number of recursive locks is held
|
||||
* @raise EBUSY if lock is currently held in read or write mode
|
||||
* @raise EINVAL if `mutex` doesn't refer to an initialized lock
|
||||
* @raise EDEADLK if `mutex` is `PTHREAD_MUTEX_ERRORCHECK` and the
|
||||
* current thread already holds this mutex
|
||||
*/
|
||||
errno_t pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
||||
int t;
|
||||
|
||||
if (__tls_enabled && //
|
||||
mutex->_type == PTHREAD_MUTEX_NORMAL && //
|
||||
// delegate to *NSYNC if possible
|
||||
if (mutex->_type == PTHREAD_MUTEX_NORMAL &&
|
||||
mutex->_pshared == PTHREAD_PROCESS_PRIVATE && //
|
||||
_weaken(nsync_mu_trylock)) {
|
||||
if (_weaken(nsync_mu_trylock)((nsync_mu *)mutex)) {
|
||||
|
@ -49,6 +51,7 @@ errno_t pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
|||
}
|
||||
}
|
||||
|
||||
// handle normal mutexes
|
||||
if (mutex->_type == PTHREAD_MUTEX_NORMAL) {
|
||||
if (!atomic_exchange_explicit(&mutex->_lock, 1, memory_order_acquire)) {
|
||||
return 0;
|
||||
|
@ -57,6 +60,7 @@ errno_t pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
|||
}
|
||||
}
|
||||
|
||||
// handle recursive and error check mutexes
|
||||
t = gettid();
|
||||
if (mutex->_owner == t) {
|
||||
if (mutex->_type != PTHREAD_MUTEX_ERRORCHECK) {
|
||||
|
@ -67,15 +71,17 @@ errno_t pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
|||
return EAGAIN;
|
||||
}
|
||||
} else {
|
||||
return EBUSY;
|
||||
return EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!atomic_exchange_explicit(&mutex->_lock, 1, memory_order_acquire)) {
|
||||
mutex->_depth = 0;
|
||||
mutex->_owner = t;
|
||||
return 0;
|
||||
} else {
|
||||
if (atomic_exchange_explicit(&mutex->_lock, 1, memory_order_acquire)) {
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
mutex->_depth = 0;
|
||||
mutex->_owner = t;
|
||||
mutex->_pid = __pid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
* @raises EPERM if in error check mode and not owned by caller
|
||||
* @vforksafe
|
||||
*/
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
errno_t pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
int t;
|
||||
|
||||
LOCKTRACE("pthread_mutex_unlock(%t)", mutex);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/nexgen32e/yield.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
||||
intptr_t _pthread_syshand(struct PosixThread *pt) {
|
||||
|
@ -27,6 +28,6 @@ intptr_t _pthread_syshand(struct PosixThread *pt) {
|
|||
for (;;) {
|
||||
syshand = atomic_load_explicit(&pt->tib->tib_syshand, memory_order_acquire);
|
||||
if (syshand) return syshand;
|
||||
pthread_yield();
|
||||
spin_yield();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/nexgen32e/yield.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
||||
int _pthread_tid(struct PosixThread *pt) {
|
||||
int tid = 0;
|
||||
while (pt && !(tid = atomic_load_explicit(&pt->ptid, memory_order_acquire))) {
|
||||
pthread_yield();
|
||||
spin_yield();
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
__static_yoink("nsync_mu_lock");
|
||||
__static_yoink("nsync_mu_unlock");
|
||||
__static_yoink("nsync_mu_trylock");
|
||||
__static_yoink("nsync_mu_rlock");
|
||||
__static_yoink("nsync_mu_runlock");
|
||||
__static_yoink("_pthread_atfork");
|
||||
|
|
37
libc/thread/pthread_rwlock_tryrdlock.c
Normal file
37
libc/thread/pthread_rwlock_tryrdlock.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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 2023 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/thread/thread.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
|
||||
/**
|
||||
* Attempts acquiring read lock on read-write lock.
|
||||
*
|
||||
* @return 0 if lock was acquired, otherwise an errno
|
||||
* @raise EBUSY if lock is currently held in write mode
|
||||
* @raise EAGAIN if maximum number of read locks are held
|
||||
* @raise EINVAL if `rwlock` doesn't refer to an initialized r/w lock
|
||||
*/
|
||||
errno_t pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) {
|
||||
if (nsync_mu_rtrylock((nsync_mu *)rwlock)) {
|
||||
return 0;
|
||||
} else {
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
37
libc/thread/pthread_rwlock_trywrlock.c
Normal file
37
libc/thread/pthread_rwlock_trywrlock.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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 2023 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/thread/thread.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
|
||||
/**
|
||||
* Attempts acquiring write lock on read-write lock.
|
||||
*
|
||||
* @return 0 if lock was acquired, otherwise an errno
|
||||
* @raise EBUSY if lock is currently held in read or write mode
|
||||
* @raise EINVAL if `rwlock` doesn't refer to an initialized r/w lock
|
||||
*/
|
||||
errno_t pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) {
|
||||
if (nsync_mu_trylock((nsync_mu *)rwlock)) {
|
||||
rwlock->_iswrite = 1;
|
||||
return 0;
|
||||
} else {
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
|
@ -43,6 +43,8 @@
|
|||
#define THREADS 8
|
||||
#define ITERATIONS 512
|
||||
|
||||
#define MAX_RECURSIVE_LOCKS 64
|
||||
|
||||
int count;
|
||||
atomic_int started;
|
||||
atomic_int finished;
|
||||
|
@ -79,11 +81,18 @@ TEST(pthread_mutex_lock, recursive) {
|
|||
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_trylock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
for (int i = 0; i < MAX_RECURSIVE_LOCKS; ++i) {
|
||||
if (i & 1) {
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
} else {
|
||||
ASSERT_EQ(0, pthread_mutex_trylock(&lock));
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(EAGAIN, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(EAGAIN, pthread_mutex_trylock(&lock));
|
||||
for (int i = 0; i < MAX_RECURSIVE_LOCKS; ++i) {
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
}
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
|
@ -99,7 +108,7 @@ TEST(pthread_mutex_lock, errorcheck) {
|
|||
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(EDEADLK, pthread_mutex_lock(&lock));
|
||||
ASSERT_EQ(EBUSY, pthread_mutex_trylock(&lock));
|
||||
ASSERT_EQ(EDEADLK, pthread_mutex_trylock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue