mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
fa20edc44d
- Remove most __ASSEMBLER__ __LINKER__ ifdefs - Rename libc/intrin/bits.h to libc/serialize.h - Block pthread cancelation in fchmodat() polyfill - Remove `clang-format off` statements in third_party
101 lines
3.7 KiB
C
101 lines
3.7 KiB
C
#ifndef NSYNC_MU_H_
|
|
#define NSYNC_MU_H_
|
|
#include "libc/intrin/dll.h"
|
|
#include "third_party/nsync/atomic.h"
|
|
COSMOPOLITAN_C_START_
|
|
|
|
/* 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 */
|
|
int _zero; /* c pthread_mutex_t */
|
|
struct Dll *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 /* NSYNC_MU_H_ */
|