mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 11:18:30 +00:00
Use *NSYNC for POSIX threads locking APIs
Condition variables, barriers, and r/w locks now work very well.
This commit is contained in:
parent
3de35e196c
commit
b5cb71ab84
197 changed files with 3734 additions and 3817 deletions
103
third_party/nsync/mu.h
vendored
Normal file
103
third_party/nsync/mu.h
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
#ifndef NSYNC_MU_H_
|
||||
#define NSYNC_MU_H_
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct nsync_dll_element_s_;
|
||||
|
||||
/* An nsync_mu is a lock. If initialized to zero, it's valid and unlocked.
|
||||
|
||||
An nsync_mu can be "free", held by a single thread (aka fiber,
|
||||
goroutine) in "write" (exclusive) mode, or by many threads in "read"
|
||||
(shared) mode. A thread that acquires it should eventually release
|
||||
it. It is illegal to acquire an nsync_mu in one thread and release it
|
||||
in another. It is illegal for a thread to reacquire an nsync_mu while
|
||||
holding it (even a second share of a "read" lock).
|
||||
|
||||
Example usage:
|
||||
|
||||
static struct foo {
|
||||
nsync_mu mu; // protects invariant a+b==0 on fields below.
|
||||
int a;
|
||||
int b;
|
||||
} p = { NSYNC_MU_INIT, 0, 0 };
|
||||
// ....
|
||||
nsync_mu_lock (&p.mu);
|
||||
// The current thread now has exclusive access to p.a and p.b;
|
||||
// invariant assumed true.
|
||||
p.a++;
|
||||
p.b--; // restore invariant p.a+p.b==0 before releasing p.mu
|
||||
nsync_mu_unlock (&p.mu)
|
||||
|
||||
Mutexes can be used with condition variables; see nsync_cv.h.
|
||||
|
||||
nsync_mu_wait() and nsync_mu_wait_with_deadline() can be used instead
|
||||
of condition variables. See nsync_mu_wait.h for more details. Example
|
||||
use of nsync_mu_wait() to wait for p.a==0, using definition above:
|
||||
|
||||
int a_is_zero (const void *condition_arg) {
|
||||
return (((const struct foo *)condition_arg)->a == 0);
|
||||
}
|
||||
...
|
||||
nsync_mu_lock (&p.mu);
|
||||
nsync_mu_wait (&p.mu, &a_is_zero, &p, NULL);
|
||||
// The current thread now has exclusive access to
|
||||
// p.a and p.b, and p.a==0.
|
||||
...
|
||||
nsync_mu_unlock (&p.mu);
|
||||
|
||||
*/
|
||||
typedef struct nsync_mu_s_ {
|
||||
nsync_atomic_uint32_ word; /* internal use only */
|
||||
struct nsync_dll_element_s_ *waiters; /* internal use only */
|
||||
} nsync_mu;
|
||||
|
||||
/* An nsync_mu should be zeroed to initialize, which can be accomplished
|
||||
by initializing with static initializer NSYNC_MU_INIT, or by setting
|
||||
the entire structure to all zeroes, or using nsync_mu_init(). */
|
||||
#define NSYNC_MU_INIT \
|
||||
{ NSYNC_ATOMIC_UINT32_INIT_, 0 }
|
||||
void nsync_mu_init(nsync_mu *mu);
|
||||
|
||||
/* Block until *mu is free and then acquire it in writer mode. Requires
|
||||
that the calling thread not already hold *mu in any mode. */
|
||||
void nsync_mu_lock(nsync_mu *mu);
|
||||
|
||||
/* Unlock *mu, which must have been acquired in write mode by the
|
||||
calling thread, and wake waiters, if appropriate. */
|
||||
void nsync_mu_unlock(nsync_mu *mu);
|
||||
|
||||
/* Attempt to acquire *mu in writer mode without blocking, and return
|
||||
non-zero iff successful. Return non-zero with high probability if *mu
|
||||
was free on entry. */
|
||||
int nsync_mu_trylock(nsync_mu *mu);
|
||||
|
||||
/* Block until *mu can be acquired in reader mode and then acquire it.
|
||||
Requires that the calling thread not already hold *mu in any mode. */
|
||||
void nsync_mu_rlock(nsync_mu *mu);
|
||||
|
||||
/* Unlock *mu, which must have been acquired in read mode by the calling
|
||||
thread, and wake waiters, if appropriate. */
|
||||
void nsync_mu_runlock(nsync_mu *mu);
|
||||
|
||||
/* Attempt to acquire *mu in reader mode without blocking, and return
|
||||
non-zero iff successful. Return non-zero with high probability if *mu
|
||||
was free on entry. Perhaps fail to acquire if a writer is waiting, to
|
||||
avoid starvation. */
|
||||
int nsync_mu_rtrylock(nsync_mu *mu);
|
||||
|
||||
/* May abort if *mu is not held in write mode by the calling thread. */
|
||||
void nsync_mu_assert_held(const nsync_mu *mu);
|
||||
|
||||
/* May abort if *mu is not held in read or write mode
|
||||
by the calling thread. */
|
||||
void nsync_mu_rassert_held(const nsync_mu *mu);
|
||||
|
||||
/* Return whether *mu is held in read mode.
|
||||
Requires that the calling thread holds *mu in some mode. */
|
||||
int nsync_mu_is_reader(const nsync_mu *mu);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* NSYNC_MU_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue