mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-17 08:00:32 +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
138
third_party/nsync/waiter.h
vendored
Normal file
138
third_party/nsync/waiter.h
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
#ifndef NSYNC_WAITER_H_
|
||||
#define NSYNC_WAITER_H_
|
||||
#include "third_party/nsync/time.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* nsync_wait_n() allows the client to wait on multiple objects
|
||||
(condition variables, nsync_notes, nsync_counters, etc.) until at
|
||||
least one of them becomes ready, or a deadline expires.
|
||||
|
||||
It can be thought of as rather like Unix's select() or poll(), except
|
||||
the the objects being waited for are synchronization data structures,
|
||||
rather than file descriptors.
|
||||
|
||||
The client can construct new objects that can be waited for by
|
||||
implementing three routines.
|
||||
|
||||
Examples:
|
||||
|
||||
To wait on two nsync_notes n0, n1, and a nsync_counter c0, with a
|
||||
deadline of abs_deadline:
|
||||
|
||||
// Form an array of struct nsync_waitable_s, identifying the
|
||||
// objects and the corresponding descriptors. (Static
|
||||
// initialization syntax is used for brevity.)
|
||||
static struct nsync_waitable_s w[] = {
|
||||
{ &n0, &nsync_note_waitable_funcs },
|
||||
{ &n1, &nsync_note_waitable_funcs },
|
||||
{ &c0, &nsync_counter_waitable_funcs }
|
||||
};
|
||||
static struct nsync_waitable_s *pw[] = { &w[0], &w[1], &w[2] };
|
||||
int n = sizeof (w) / sizeof (w[0]);
|
||||
|
||||
// Wait. The mu, lock, and unlock arguments are NULL because no
|
||||
// condition variables are invovled.
|
||||
int i = nsync_wait_n (NULL, NULL, NULL, abs_deadline, n, pw);
|
||||
if (i == n) {
|
||||
// timeout
|
||||
} else {
|
||||
// w[i].v became ready.
|
||||
}
|
||||
|
||||
To wait on multiple condition variables, the mu/lock/unlock
|
||||
parameters are used. Imagine cv0 and cv1 are signalled when
|
||||
predicates pred0() (under lock mu0) and pred1() (under lock mu1)
|
||||
become true respectively. Assume that mu0 is acquired before mu1.
|
||||
|
||||
static void lock2 (void *v) { // lock two mutexes in order
|
||||
nsync_mu **mu = (nsync_mu **) v;
|
||||
nsync_mu_lock (mu[0]);
|
||||
nsync_mu_lock (mu[1]);
|
||||
}
|
||||
static void unlock2 (void *v) { // unlock two mutexes.
|
||||
nsync_mu **mu = (nsync_mu **) v;
|
||||
nsync_mu_unlock (mu[1]);
|
||||
nsync_mu_unlock (mu[0]);
|
||||
}
|
||||
|
||||
// Describe the condition variables and the locks.
|
||||
static struct nsync_waitable_s w[] = {
|
||||
{ &cv0, &nsync_cv_waitable_funcs },
|
||||
{ &cv1, &nsync_cv_waitable_funcs }
|
||||
};
|
||||
static struct nsync_waitable_s *pw[] = { &w[0], &w[1] };
|
||||
nsync_mu *lock_list[] = { &mu0, &mu1 };
|
||||
int n = sizeof (w) / sizeof (w[0]);
|
||||
|
||||
lock2 (list_list);
|
||||
while (!pred0 () && !pred1 ()) {
|
||||
// Wait for one of the condition variables to be signalled,
|
||||
// with no timeout.
|
||||
nsync_wait_n (lock_list, &lock2, &unlock2,
|
||||
nsync_time_no_deadline, n, pw);
|
||||
}
|
||||
if (pred0 ()) { ... }
|
||||
if (pred1 ()) { ... }
|
||||
unlock2 (list_list);
|
||||
|
||||
*/
|
||||
|
||||
/* forward declaration of struct that contains type dependent wait
|
||||
operations */
|
||||
struct nsync_waitable_funcs_s;
|
||||
|
||||
/* Clients wait on objects by forming an array of struct
|
||||
nsync_waitable_s. Each each element points to one object and its
|
||||
type-dependent functions. */
|
||||
struct nsync_waitable_s {
|
||||
/* pointer to object */
|
||||
void *v;
|
||||
/* pointer to type-dependent functions. Use
|
||||
&nsync_note_waitable_funcs for an nsync_note,
|
||||
&nsync_counternote_waitable_funcs for an nsync_counter,
|
||||
&nsync_cv_waitable_funcs for an nsync_cv. */
|
||||
const struct nsync_waitable_funcs_s *funcs;
|
||||
};
|
||||
|
||||
/* Wait until at least one of *waitable[0,..,count-1] is has been
|
||||
notified, or abs_deadline is reached. Return the index of the
|
||||
notified element of waitable[], or count if no such element exists.
|
||||
If mu!=NULL, (*unlock)(mu) is called after the thread is queued on
|
||||
the various waiters, and (*lock)(mu) is called before return;
|
||||
mu/lock/unlock are used to acquire and release the relevant locks
|
||||
whan waiting on condition variables. */
|
||||
int nsync_wait_n(void *mu, void (*lock)(void *), void (*unlock)(void *),
|
||||
nsync_time abs_deadline, int count,
|
||||
struct nsync_waitable_s *waitable[]);
|
||||
|
||||
/* A "struct nsync_waitable_s" implementation must implement these
|
||||
functions. Clients should ignore the internals. */
|
||||
struct nsync_waiter_s;
|
||||
struct nsync_waitable_funcs_s {
|
||||
|
||||
/* Return the time when *v will be ready (max time if unknown), or 0
|
||||
if it is already ready. The parameter nw may be passed as NULL, in
|
||||
which case the result should indicate whether the thread would
|
||||
block if it were to wait on *v. All calls with the same *v must
|
||||
report the same result until the object becomes ready, from which
|
||||
point calls must report 0. */
|
||||
nsync_time (*ready_time)(void *v, struct nsync_waiter_s *nw);
|
||||
|
||||
/* If *v is ready, return zero; otherwise enqueue *nw on *v and return
|
||||
non-zero. */
|
||||
int (*enqueue)(void *v, struct nsync_waiter_s *nw);
|
||||
|
||||
/* If nw has been previously dequeued, return zero; otherwise dequeue
|
||||
*nw from *v and return non-zero. */
|
||||
int (*dequeue)(void *v, struct nsync_waiter_s *nw);
|
||||
};
|
||||
|
||||
/* The "struct nsync_waitable_s" for nsync_note, nsync_counter, and nsync_cv. */
|
||||
extern const struct nsync_waitable_funcs_s nsync_note_waitable_funcs;
|
||||
extern const struct nsync_waitable_funcs_s nsync_counter_waitable_funcs;
|
||||
extern const struct nsync_waitable_funcs_s nsync_cv_waitable_funcs;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* NSYNC_WAITER_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue