mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
6f7d0cb1c3
This makes breaking changes to add underscores to many non-standard function names provided by the c library. MODE=tiny is now tinier and we now use smaller locks that are better for tiny apps in this mode. Some headers have been renamed to be in the same folder as the build package, so it'll be easier to know which build dependency is needed. Certain old misguided interfaces have been removed. Intel intrinsics headers are now listed in libc/isystem (but not in the amalgamation) to help further improve open source compatibility. Header complexity has also been reduced. Lastly, more shell scripts are now available.
104 lines
3.9 KiB
C
104 lines
3.9 KiB
C
#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 */
|
|
int _zero; /* c pthread_mutex_t */
|
|
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_ */
|