mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 10:48:29 +00:00
Clean up more code
The *NSYNC linked list API is good enough that it deserves to be part of the C libray, so this change writes an improved version of it which uses that offsetof() trick from the Linux Kernel. We vendor all of the *NSYNC tests in third_party which helped confirm the needed refactoring is safe This change also deletes more old code that didn't pan out. My goal here is to work towards a vision where the Cosmopolitan core libraries become less experimental and more focused on curation. This better reflects the current level of quality we've managed to achieve.
This commit is contained in:
parent
88612a2cd7
commit
0a24b4fc3c
268 changed files with 632 additions and 8688 deletions
2
third_party/nsync/README.cosmo
vendored
2
third_party/nsync/README.cosmo
vendored
|
@ -19,3 +19,5 @@ LOCAL CHANGES
|
|||
- nsync_mu_semaphore uses Cosmopolitan Futexes
|
||||
- block pthread cancellations in nsync_mu_lock_slow_
|
||||
- support posix thread cancellations in nsync_cv_wait
|
||||
- timespec api was so good that it's now part of libc
|
||||
- linked list api was so good that it's now part of libc
|
||||
|
|
31
third_party/nsync/common.c
vendored
31
third_party/nsync/common.c
vendored
|
@ -15,6 +15,7 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -23,7 +24,6 @@
|
|||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -122,23 +122,24 @@ uint32_t nsync_spin_test_and_set_ (nsync_atomic_uint32_ *w, uint32_t test,
|
|||
|
||||
/* ====================================================================================== */
|
||||
|
||||
struct nsync_waiter_s *nsync_dll_nsync_waiter_ (nsync_dll_element_ *e) {
|
||||
struct nsync_waiter_s *nw = (struct nsync_waiter_s *) e->container;
|
||||
struct nsync_waiter_s *nsync_dll_nsync_waiter_ (struct Dll *e) {
|
||||
struct nsync_waiter_s *nw = DLL_CONTAINER(struct nsync_waiter_s, q, e);
|
||||
ASSERT (nw->tag == NSYNC_WAITER_TAG);
|
||||
ASSERT (e == &nw->q);
|
||||
return (nw);
|
||||
}
|
||||
waiter *nsync_dll_waiter_ (nsync_dll_element_ *e) {
|
||||
|
||||
waiter *nsync_dll_waiter_ (struct Dll *e) {
|
||||
struct nsync_waiter_s *nw = DLL_NSYNC_WAITER (e);
|
||||
waiter *w = CONTAINER (waiter, nw, nw);
|
||||
waiter *w = DLL_CONTAINER (waiter, nw, nw);
|
||||
ASSERT ((nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0);
|
||||
ASSERT (w->tag == WAITER_TAG);
|
||||
ASSERT (e == &w->nw.q);
|
||||
return (w);
|
||||
}
|
||||
|
||||
waiter *nsync_dll_waiter_samecond_ (nsync_dll_element_ *e) {
|
||||
waiter *w = (waiter *) e->container;
|
||||
waiter *nsync_dll_waiter_samecond_ (struct Dll *e) {
|
||||
waiter *w = DLL_CONTAINER (struct waiter_s, same_condition, e);
|
||||
ASSERT (w->tag == WAITER_TAG);
|
||||
ASSERT (e == &w->same_condition);
|
||||
return (w);
|
||||
|
@ -146,7 +147,7 @@ waiter *nsync_dll_waiter_samecond_ (nsync_dll_element_ *e) {
|
|||
|
||||
/* -------------------------------- */
|
||||
|
||||
static nsync_dll_list_ free_waiters = NULL;
|
||||
static struct Dll *free_waiters = NULL;
|
||||
|
||||
/* free_waiters points to a doubly-linked list of free waiter structs. */
|
||||
static nsync_atomic_uint32_ free_waiters_mu; /* spinlock; protects free_waiters */
|
||||
|
@ -165,7 +166,7 @@ static void waiter_destroy (void *v) {
|
|||
ASSERT ((w->flags & (WAITER_RESERVED|WAITER_IN_USE)) == WAITER_RESERVED);
|
||||
w->flags &= ~WAITER_RESERVED;
|
||||
nsync_spin_test_and_set_ (&free_waiters_mu, 1, 1, 0);
|
||||
free_waiters = nsync_dll_make_first_in_list_ (free_waiters, &w->nw.q);
|
||||
dll_make_first (&free_waiters, &w->nw.q);
|
||||
ATM_STORE_REL (&free_waiters_mu, 0); /* release store */
|
||||
IGNORE_RACES_END ();
|
||||
}
|
||||
|
@ -173,7 +174,7 @@ static void waiter_destroy (void *v) {
|
|||
/* Return a pointer to an unused waiter struct.
|
||||
Ensures that the enclosed timer is stopped and its channel drained. */
|
||||
waiter *nsync_waiter_new_ (void) {
|
||||
nsync_dll_element_ *q;
|
||||
struct Dll *q;
|
||||
waiter *tw;
|
||||
waiter *w;
|
||||
tw = waiter_for_thread;
|
||||
|
@ -181,9 +182,9 @@ waiter *nsync_waiter_new_ (void) {
|
|||
if (w == NULL || (w->flags & (WAITER_RESERVED|WAITER_IN_USE)) != WAITER_RESERVED) {
|
||||
w = NULL;
|
||||
nsync_spin_test_and_set_ (&free_waiters_mu, 1, 1, 0);
|
||||
q = nsync_dll_first_ (free_waiters);
|
||||
q = dll_first (free_waiters);
|
||||
if (q != NULL) { /* If free list is non-empty, dequeue an item. */
|
||||
free_waiters = nsync_dll_remove_ (free_waiters, q);
|
||||
dll_remove (&free_waiters, q);
|
||||
w = DLL_WAITER (q);
|
||||
}
|
||||
ATM_STORE_REL (&free_waiters_mu, 0); /* release store */
|
||||
|
@ -193,11 +194,11 @@ waiter *nsync_waiter_new_ (void) {
|
|||
w->nw.tag = NSYNC_WAITER_TAG;
|
||||
nsync_mu_semaphore_init (&w->sem);
|
||||
w->nw.sem = &w->sem;
|
||||
nsync_dll_init_ (&w->nw.q, &w->nw);
|
||||
dll_init (&w->nw.q);
|
||||
NSYNC_ATOMIC_UINT32_STORE_ (&w->nw.waiting, 0);
|
||||
w->nw.flags = NSYNC_WAITER_FLAG_MUCV;
|
||||
ATM_STORE (&w->remove_count, 0);
|
||||
nsync_dll_init_ (&w->same_condition, w);
|
||||
dll_init (&w->same_condition);
|
||||
w->flags = 0;
|
||||
}
|
||||
if (tw == NULL) {
|
||||
|
@ -216,7 +217,7 @@ void nsync_waiter_free_ (waiter *w) {
|
|||
w->flags &= ~WAITER_IN_USE;
|
||||
if ((w->flags & WAITER_RESERVED) == 0) {
|
||||
nsync_spin_test_and_set_ (&free_waiters_mu, 1, 1, 0);
|
||||
free_waiters = nsync_dll_make_first_in_list_ (free_waiters, &w->nw.q);
|
||||
dll_make_first (&free_waiters, &w->nw.q);
|
||||
ATM_STORE_REL (&free_waiters_mu, 0); /* release store */
|
||||
}
|
||||
}
|
||||
|
|
44
third_party/nsync/common.internal.h
vendored
44
third_party/nsync/common.internal.h
vendored
|
@ -1,10 +1,10 @@
|
|||
#ifndef NSYNC_COMMON_H_
|
||||
#define NSYNC_COMMON_H_
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/cv.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/note.h"
|
||||
|
@ -101,9 +101,9 @@ void nsync_panic_(const char *s);
|
|||
#define MU_ALL_FALSE \
|
||||
((uint32_t)(1 << 7)) /* all waiter conditions are false \
|
||||
*/
|
||||
#define MU_RLOCK \
|
||||
((uint32_t)( \
|
||||
1 << 8)) /* low-order bit of reader count, which uses rest of word */
|
||||
#define MU_RLOCK \
|
||||
((uint32_t)(1 << 8)) /* low-order bit of reader count, which uses rest of \
|
||||
word */
|
||||
|
||||
/* The constants below are derived from those above. */
|
||||
#define MU_RLOCK_FIELD \
|
||||
|
@ -202,7 +202,7 @@ struct wait_condition_s {
|
|||
Remove *w from the relevant queue then:
|
||||
ATM_STORE_REL (&w.waiting, 0);
|
||||
nsync_mu_semaphore_v (&w.sem); */
|
||||
typedef struct {
|
||||
typedef struct waiter_s {
|
||||
uint32_t tag; /* debug DLL_NSYNC_WAITER, DLL_WAITER, DLL_WAITER_SAMECOND */
|
||||
int flags; /* see WAITER_* bits below */
|
||||
nsync_semaphore sem; /* Thread waits on this semaphore. */
|
||||
|
@ -212,7 +212,7 @@ typedef struct {
|
|||
*l_type; /* Lock type of the mu, or nil if not associated with a mu. */
|
||||
nsync_atomic_uint32_ remove_count; /* count of removals from queue */
|
||||
struct wait_condition_s cond; /* A condition on which to acquire a mu. */
|
||||
nsync_dll_element_ same_condition; /* Links neighbours in nw.q with same
|
||||
struct Dll same_condition; /* Links neighbours in nw.q with same
|
||||
non-nil condition. */
|
||||
} waiter;
|
||||
static const uint32_t WAITER_TAG = 0x0590239f;
|
||||
|
@ -222,28 +222,27 @@ static const uint32_t NSYNC_WAITER_TAG = 0x726d2ba9;
|
|||
0x1 /* waiter reserved by a thread, even when not in use */
|
||||
#define WAITER_IN_USE 0x2 /* waiter in use by a thread */
|
||||
|
||||
#define CONTAINER(t_, f_, p_) ((t_ *)(((char *)(p_)) - offsetof(t_, f_)))
|
||||
|
||||
#define ASSERT(x) _npassert(x)
|
||||
|
||||
/* Return a pointer to the nsync_waiter_s containing nsync_dll_element_ *e. */
|
||||
/* Return a pointer to the nsync_waiter_s containing struct Dll *e. */
|
||||
#define DLL_NSYNC_WAITER(e) \
|
||||
(NSYNC_DEBUG ? nsync_dll_nsync_waiter_(e) \
|
||||
: ((struct nsync_waiter_s *)((e)->container)))
|
||||
struct nsync_waiter_s *nsync_dll_nsync_waiter_(nsync_dll_element_ *e);
|
||||
: DLL_CONTAINER(struct nsync_waiter_s, q, e))
|
||||
struct nsync_waiter_s *nsync_dll_nsync_waiter_(struct Dll *e);
|
||||
|
||||
/* Return a pointer to the waiter struct that *e is embedded in, where *e is an
|
||||
* nw.q field. */
|
||||
#define DLL_WAITER(e) \
|
||||
(NSYNC_DEBUG ? nsync_dll_waiter_(e) \
|
||||
: CONTAINER(waiter, nw, DLL_NSYNC_WAITER(e)))
|
||||
waiter *nsync_dll_waiter_(nsync_dll_element_ *e);
|
||||
: DLL_CONTAINER(waiter, nw, DLL_NSYNC_WAITER(e)))
|
||||
waiter *nsync_dll_waiter_(struct Dll *e);
|
||||
|
||||
/* Return a pointer to the waiter struct that *e is embedded in, where *e is a
|
||||
same_condition field. */
|
||||
#define DLL_WAITER_SAMECOND(e) \
|
||||
(NSYNC_DEBUG ? nsync_dll_waiter_samecond_(e) : ((waiter *)((e)->container)))
|
||||
waiter *nsync_dll_waiter_samecond_(nsync_dll_element_ *e);
|
||||
#define DLL_WAITER_SAMECOND(e) \
|
||||
(NSYNC_DEBUG ? nsync_dll_waiter_samecond_(e) \
|
||||
: DLL_CONTAINER(struct waiter_s, same_condition, e))
|
||||
waiter *nsync_dll_waiter_samecond_(struct Dll *e);
|
||||
|
||||
/* Return a pointer to an unused waiter struct.
|
||||
Ensures that the enclosed timer is stopped and its channel drained. */
|
||||
|
@ -257,8 +256,7 @@ void nsync_waiter_free_(waiter *w);
|
|||
/* The internals of an nync_note. See internal/note.c for details of locking
|
||||
discipline. */
|
||||
struct nsync_note_s_ {
|
||||
nsync_dll_element_
|
||||
parent_child_link; /* parent's children, under parent->note_mu */
|
||||
struct Dll parent_child_link; /* parent's children, under parent->note_mu */
|
||||
int expiry_time_valid; /* whether expiry_time is valid; r/o after init */
|
||||
nsync_time
|
||||
expiry_time; /* expiry time, if expiry_time_valid != 0; r/o after init */
|
||||
|
@ -267,8 +265,8 @@ struct nsync_note_s_ {
|
|||
uint32_t disconnecting; /* non-zero => node is being disconnected */
|
||||
nsync_atomic_uint32_ notified; /* non-zero if the note has been notified */
|
||||
struct nsync_note_s_ *parent; /* points to parent, if any */
|
||||
nsync_dll_element_ *children; /* list of children */
|
||||
nsync_dll_element_ *waiters; /* list of waiters */
|
||||
struct Dll *children; /* list of children */
|
||||
struct Dll *waiters; /* list of waiters */
|
||||
};
|
||||
|
||||
/* ---------- */
|
||||
|
@ -276,10 +274,8 @@ struct nsync_note_s_ {
|
|||
void nsync_mu_lock_slow_(nsync_mu *mu, waiter *w, uint32_t clear,
|
||||
lock_type *l_type);
|
||||
void nsync_mu_unlock_slow_(nsync_mu *mu, lock_type *l_type);
|
||||
nsync_dll_list_ nsync_remove_from_mu_queue_(nsync_dll_list_ mu_queue,
|
||||
nsync_dll_element_ *e);
|
||||
void nsync_maybe_merge_conditions_(nsync_dll_element_ *p,
|
||||
nsync_dll_element_ *n);
|
||||
struct Dll *nsync_remove_from_mu_queue_(struct Dll *mu_queue, struct Dll *e);
|
||||
void nsync_maybe_merge_conditions_(struct Dll *p, struct Dll *n);
|
||||
nsync_time nsync_note_notified_deadline_(nsync_note n);
|
||||
int nsync_sem_wait_with_cancel_(waiter *w, nsync_time abs_deadline,
|
||||
nsync_note cancel_note);
|
||||
|
|
2
third_party/nsync/counter.h
vendored
2
third_party/nsync/counter.h
vendored
|
@ -5,8 +5,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct nsync_dll_element_s_;
|
||||
|
||||
/* An nsync_counter represents an unsigned integer that can count up and down,
|
||||
and wake waiters when zero. */
|
||||
typedef struct nsync_counter_s_ *nsync_counter;
|
||||
|
|
4
third_party/nsync/cv.h
vendored
4
third_party/nsync/cv.h
vendored
|
@ -1,5 +1,6 @@
|
|||
#ifndef NSYNC_CV_H_
|
||||
#define NSYNC_CV_H_
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/time.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -8,7 +9,6 @@ COSMOPOLITAN_C_START_
|
|||
#define NSYNC_CV_INIT \
|
||||
{ NSYNC_ATOMIC_UINT32_INIT_, 0 }
|
||||
|
||||
struct nsync_dll_element_s_;
|
||||
struct nsync_note_s_;
|
||||
|
||||
/* An nsync_cv is a condition variable in the style of Mesa, Java,
|
||||
|
@ -92,7 +92,7 @@ typedef struct nsync_cv_s_ {
|
|||
/* see bits below */
|
||||
nsync_atomic_uint32_ word;
|
||||
/* points to tail of list of waiters; under mu. */
|
||||
struct nsync_dll_element_s_ *waiters;
|
||||
struct Dll *waiters;
|
||||
} nsync_cv;
|
||||
|
||||
/* An nsync_cv should be zeroed to initialize, which can be accomplished
|
||||
|
|
143
third_party/nsync/dll.c
vendored
143
third_party/nsync/dll.c
vendored
|
@ -1,143 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2016 Google Inc. │
|
||||
│ │
|
||||
│ Licensed under the Apache License, Version 2.0 (the "License"); │
|
||||
│ you may not use this file except in compliance with the License. │
|
||||
│ You may obtain a copy of the License at │
|
||||
│ │
|
||||
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
||||
│ │
|
||||
│ Unless required by applicable law or agreed to in writing, software │
|
||||
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
||||
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
||||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/dll.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
*NSYNC (Apache 2.0)\\n\
|
||||
Copyright 2016 Google, Inc.\\n\
|
||||
https://github.com/google/nsync\"");
|
||||
// clang-format off
|
||||
|
||||
/* Initialize *e. */
|
||||
void nsync_dll_init_ (nsync_dll_element_ *e, void *container) {
|
||||
e->next = e;
|
||||
e->prev = e;
|
||||
e->container = container;
|
||||
}
|
||||
|
||||
/* Return whether list is empty. */
|
||||
int nsync_dll_is_empty_ (nsync_dll_list_ list) {
|
||||
return (list == NULL);
|
||||
}
|
||||
|
||||
/* Remove *e from list, and returns the new list. */
|
||||
nsync_dll_list_ nsync_dll_remove_ (nsync_dll_list_ list, nsync_dll_element_ *e) {
|
||||
if (list == e) { /* removing tail of list */
|
||||
if (list->prev == list) {
|
||||
list = NULL; /* removing only element of list */
|
||||
} else {
|
||||
list = list->prev;
|
||||
}
|
||||
}
|
||||
e->next->prev = e->prev;
|
||||
e->prev->next = e->next;
|
||||
e->next = e;
|
||||
e->prev = e;
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* Cause element *n and its successors to come after element *p.
|
||||
Requires n and p are non-NULL and do not point at elements of the same list.
|
||||
|
||||
Unlike the other operations in this API, this operation acts on
|
||||
two circular lists of elements, rather than on a "head" location that points
|
||||
to such a circular list.
|
||||
|
||||
If the two lists are p->p_2nd->p_mid->p_last->p and n->n_2nd->n_mid->n_last->n,
|
||||
then after nsync_dll_splice_after_ (p, n), the p list would be:
|
||||
p->n->n_2nd->n_mid->n_last->p_2nd->p_mid->p_last->p. */
|
||||
void nsync_dll_splice_after_ (nsync_dll_element_ *p, nsync_dll_element_ *n) {
|
||||
nsync_dll_element_ *p_2nd = p->next;
|
||||
nsync_dll_element_ *n_last = n->prev;
|
||||
p->next = n; /* n follows p */
|
||||
n->prev = p;
|
||||
n_last->next = p_2nd; /* remainder of p-list follows last of n-list */
|
||||
p_2nd->prev = n_last;
|
||||
}
|
||||
|
||||
/* Make element *e the first element of list, and return
|
||||
the list. The resulting list will have *e as its first element, followed by
|
||||
any elements in the same list as *e, followed by the elements that were
|
||||
previously in list. Requires that *e not be in list. If e==NULL, list is
|
||||
returned unchanged.
|
||||
|
||||
Suppose the e list is e->e_2nd->e_mid->e_last->e.
|
||||
Recall that a head "list" points to the last element of its list.
|
||||
If list is initially null, then the outcome is:
|
||||
result = e_last->e->e_2nd->e_mid->e_last
|
||||
If list is initially list->list_last->list_1st->list_mid->list_last,
|
||||
then the outcome is:
|
||||
result = list_last->e->e_2nd->e_mid->e_last->list_1st->list_mid->list_last
|
||||
*/
|
||||
nsync_dll_list_ nsync_dll_make_first_in_list_ (nsync_dll_list_ list, nsync_dll_element_ *e) {
|
||||
if (e != NULL) {
|
||||
if (list == NULL) {
|
||||
list = e->prev; /*e->prev is e_last*/
|
||||
} else {
|
||||
nsync_dll_splice_after_ (list, e);
|
||||
}
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* Make element *e the last element of list, and return
|
||||
the list. The resulting list will have *e as its last element, preceded by
|
||||
any elements in the same list as *e, preceded by the elements that were
|
||||
previously in list. Requires that *e not be in list. If e==NULL, list is
|
||||
returned unchanged. */
|
||||
nsync_dll_list_ nsync_dll_make_last_in_list_ (nsync_dll_list_ list, nsync_dll_element_ *e) {
|
||||
if (e != NULL) {
|
||||
nsync_dll_make_first_in_list_ (list, e->next);
|
||||
list = e;
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* Return a pointer to the first element of list, or NULL if list is empty. */
|
||||
nsync_dll_element_ *nsync_dll_first_ (nsync_dll_list_ list) {
|
||||
nsync_dll_element_ *first = NULL;
|
||||
if (list != NULL) {
|
||||
first = list->next;
|
||||
}
|
||||
return (first);
|
||||
}
|
||||
|
||||
/* Return a pointer to the last element of list, or NULL if list is empty. */
|
||||
nsync_dll_element_ *nsync_dll_last_ (nsync_dll_list_ list) {
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* Return a pointer to the next element of list following *e,
|
||||
or NULL if there is no such element. */
|
||||
nsync_dll_element_ *nsync_dll_next_ (nsync_dll_list_ list, nsync_dll_element_ *e) {
|
||||
nsync_dll_element_ *next = NULL;
|
||||
if (e != list) {
|
||||
next = e->next;
|
||||
}
|
||||
return (next);
|
||||
}
|
||||
|
||||
/* Return a pointer to the previous element of list following *e,
|
||||
or NULL if there is no such element. */
|
||||
nsync_dll_element_ *nsync_dll_prev_ (nsync_dll_list_ list, nsync_dll_element_ *e) {
|
||||
nsync_dll_element_ *prev = NULL;
|
||||
if (e != list->next) {
|
||||
prev = e->prev;
|
||||
}
|
||||
return (prev);
|
||||
}
|
69
third_party/nsync/dll.h
vendored
69
third_party/nsync/dll.h
vendored
|
@ -1,69 +0,0 @@
|
|||
#ifndef NSYNC_DLL_H_
|
||||
#define NSYNC_DLL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* A nsync_dll_element_ represents an element of a doubly-linked list of
|
||||
waiters. */
|
||||
typedef struct nsync_dll_element_s_ {
|
||||
struct nsync_dll_element_s_ *next;
|
||||
struct nsync_dll_element_s_ *prev;
|
||||
/* points to the struct this nsync_dll struct is embedded in. */
|
||||
void *container;
|
||||
} nsync_dll_element_;
|
||||
|
||||
/* A nsync_dll_list_ represents a list of nsync_dll_elements_. */
|
||||
typedef nsync_dll_element_ *nsync_dll_list_; /* last elem of circular list; nil
|
||||
=> empty; first is x.next. */
|
||||
|
||||
/* Initialize *e. */
|
||||
void nsync_dll_init_(nsync_dll_element_ *e, void *container);
|
||||
|
||||
/* Return whether list is empty. */
|
||||
int nsync_dll_is_empty_(nsync_dll_list_ list);
|
||||
|
||||
/* Remove *e from list, and returns the new list. */
|
||||
nsync_dll_list_ nsync_dll_remove_(nsync_dll_list_ list, nsync_dll_element_ *e);
|
||||
|
||||
/* Cause element *n and its successors to come after element *p.
|
||||
Requires n and p are non-NULL and do not point at elements of the
|
||||
same list. */
|
||||
void nsync_dll_splice_after_(nsync_dll_element_ *p, nsync_dll_element_ *n);
|
||||
|
||||
/* Make element *e the first element of list, and return the list. The
|
||||
resulting list will have *e as its first element, followed by any
|
||||
elements in the same list as *e, followed by the elements that were
|
||||
previously in list. Requires that *e not be in list. If e==NULL, list
|
||||
is returned unchanged. */
|
||||
nsync_dll_list_ nsync_dll_make_first_in_list_(nsync_dll_list_ list,
|
||||
nsync_dll_element_ *e);
|
||||
|
||||
/* Make element *e the last element of list, and return the list. The
|
||||
resulting list will have *e as its last element, preceded by any
|
||||
elements in the same list as *e, preceded by the elements that were
|
||||
previously in list. Requires that *e not be in list. If e==NULL, list
|
||||
is returned unchanged. */
|
||||
nsync_dll_list_ nsync_dll_make_last_in_list_(nsync_dll_list_ list,
|
||||
nsync_dll_element_ *e);
|
||||
|
||||
/* Return a pointer to the first element of list, or NULL if list is
|
||||
* empty. */
|
||||
nsync_dll_element_ *nsync_dll_first_(nsync_dll_list_ list);
|
||||
|
||||
/* Return a pointer to the last element of list, or NULL if list is
|
||||
* empty. */
|
||||
nsync_dll_element_ *nsync_dll_last_(nsync_dll_list_ list);
|
||||
|
||||
/* Return a pointer to the next element of list following *e, or NULL if
|
||||
there is no such element. */
|
||||
nsync_dll_element_ *nsync_dll_next_(nsync_dll_list_ list,
|
||||
nsync_dll_element_ *e);
|
||||
|
||||
/* Return a pointer to the previous element of list following *e, or
|
||||
NULL if there is no such element. */
|
||||
nsync_dll_element_ *nsync_dll_prev_(nsync_dll_list_ list,
|
||||
nsync_dll_element_ *e);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* NSYNC_DLL_H_ */
|
2
third_party/nsync/mem/array.c
vendored
2
third_party/nsync/mem/array.c
vendored
|
@ -39,7 +39,7 @@ void a_ensure_ (void *v, int delta, int sz) {
|
|||
} else {
|
||||
na = realloc (a->a_, nmax*sz);
|
||||
}
|
||||
memset (omax *sz + (char *)na, 0, (nmax - omax) * sz);
|
||||
bzero (omax *sz + (char *)na, (nmax - omax) * sz);
|
||||
a->a_ = (void **) na;
|
||||
a->h_.max_ = nmax;
|
||||
}
|
||||
|
|
18
third_party/nsync/mem/nsync_counter.c
vendored
18
third_party/nsync/mem/nsync_counter.c
vendored
|
@ -15,13 +15,13 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/counter.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -38,13 +38,13 @@ struct nsync_counter_s_ {
|
|||
nsync_atomic_uint32_ waited; /* wait has been called */
|
||||
nsync_mu counter_mu; /* protects fields below except reads of "value" */
|
||||
nsync_atomic_uint32_ value; /* value of counter */
|
||||
struct nsync_dll_element_s_ *waiters; /* list of waiters */
|
||||
struct Dll *waiters; /* list of waiters */
|
||||
};
|
||||
|
||||
nsync_counter nsync_counter_new (uint32_t value) {
|
||||
nsync_counter c = (nsync_counter) malloc (sizeof (*c));
|
||||
if (c != NULL) {
|
||||
memset ((void *) c, 0, sizeof (*c));
|
||||
bzero ((void *) c, sizeof (*c));
|
||||
ATM_STORE (&c->value, value);
|
||||
}
|
||||
return (c);
|
||||
|
@ -52,7 +52,7 @@ nsync_counter nsync_counter_new (uint32_t value) {
|
|||
|
||||
void nsync_counter_free (nsync_counter c) {
|
||||
nsync_mu_lock (&c->counter_mu);
|
||||
ASSERT (nsync_dll_is_empty_ (c->waiters));
|
||||
ASSERT (dll_is_empty (c->waiters));
|
||||
nsync_mu_unlock (&c->counter_mu);
|
||||
free (c);
|
||||
}
|
||||
|
@ -77,10 +77,10 @@ uint32_t nsync_counter_add (nsync_counter c, int32_t delta) {
|
|||
ASSERT (value < value - delta); /* Crash on overflow. */
|
||||
}
|
||||
if (value == 0) {
|
||||
nsync_dll_element_ *p;
|
||||
while ((p = nsync_dll_first_ (c->waiters)) != NULL) {
|
||||
struct Dll *p;
|
||||
while ((p = dll_first (c->waiters)) != NULL) {
|
||||
struct nsync_waiter_s *nw = DLL_NSYNC_WAITER (p);
|
||||
c->waiters = nsync_dll_remove_ (c->waiters, p);
|
||||
dll_remove (&c->waiters, p);
|
||||
ATM_STORE_REL (&nw->waiting, 0);
|
||||
nsync_mu_semaphore_v (nw->sem);
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ static int counter_enqueue (void *v, struct nsync_waiter_s *nw) {
|
|||
nsync_mu_lock (&c->counter_mu);
|
||||
value = ATM_LOAD_ACQ (&c->value);
|
||||
if (value != 0) {
|
||||
c->waiters = nsync_dll_make_last_in_list_ (c->waiters, &nw->q);
|
||||
dll_make_last (&c->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 1);
|
||||
} else {
|
||||
ATM_STORE (&nw->waiting, 0);
|
||||
|
@ -142,7 +142,7 @@ static int counter_dequeue (void *v, struct nsync_waiter_s *nw) {
|
|||
nsync_mu_lock (&c->counter_mu);
|
||||
value = ATM_LOAD_ACQ (&c->value);
|
||||
if (ATM_LOAD_ACQ (&nw->waiting) != 0) {
|
||||
c->waiters = nsync_dll_remove_ (c->waiters, &nw->q);
|
||||
dll_remove (&c->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 0);
|
||||
}
|
||||
nsync_mu_unlock (&c->counter_mu);
|
||||
|
|
89
third_party/nsync/mem/nsync_cv.c
vendored
89
third_party/nsync/mem/nsync_cv.c
vendored
|
@ -16,12 +16,12 @@
|
|||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/cv.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
#include "third_party/nsync/waiter.h"
|
||||
|
@ -38,7 +38,7 @@ https://github.com/google/nsync\"");
|
|||
|
||||
/* Initialize *cv. */
|
||||
void nsync_cv_init (nsync_cv *cv) {
|
||||
memset ((void *) cv, 0, sizeof (*cv));
|
||||
bzero ((void *) cv, sizeof (*cv));
|
||||
}
|
||||
|
||||
/* Wake the cv waiters in the circular list pointed to by
|
||||
|
@ -46,10 +46,10 @@ void nsync_cv_init (nsync_cv *cv) {
|
|||
nsync_mu, the "wakeup" may consist of transferring the waiters to the nsync_mu's
|
||||
queue. Requires that every waiter is associated with the same mutex.
|
||||
all_readers indicates whether all the waiters on the list are readers. */
|
||||
static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
||||
nsync_dll_element_ *p = NULL;
|
||||
nsync_dll_element_ *next = NULL;
|
||||
nsync_dll_element_ *first_waiter = nsync_dll_first_ (to_wake_list);
|
||||
static void wake_waiters (struct Dll *to_wake_list, int all_readers) {
|
||||
struct Dll *p = NULL;
|
||||
struct Dll *next = NULL;
|
||||
struct Dll *first_waiter = dll_first (to_wake_list);
|
||||
struct nsync_waiter_s *first_nw = DLL_NSYNC_WAITER (first_waiter);
|
||||
waiter *first_w = NULL;
|
||||
nsync_mu *pmu = NULL;
|
||||
|
@ -71,7 +71,7 @@ static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
|||
*/
|
||||
uint32_t old_mu_word = ATM_LOAD (&pmu->word);
|
||||
int first_cant_acquire = ((old_mu_word & first_w->l_type->zero_to_acquire) != 0);
|
||||
next = nsync_dll_next_ (to_wake_list, first_waiter);
|
||||
next = dll_next (to_wake_list, first_waiter);
|
||||
if ((old_mu_word&MU_ANY_LOCK) != 0 &&
|
||||
(old_mu_word&MU_SPINLOCK) == 0 &&
|
||||
(first_cant_acquire || (next != NULL && !all_readers)) &&
|
||||
|
@ -88,8 +88,8 @@ static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
|||
int woke_areader = 0;
|
||||
/* Transfer the first waiter iff it can't acquire *pmu. */
|
||||
if (first_cant_acquire) {
|
||||
to_wake_list = nsync_dll_remove_ (to_wake_list, first_waiter);
|
||||
pmu->waiters = nsync_dll_make_last_in_list_ (pmu->waiters, first_waiter);
|
||||
dll_remove (&to_wake_list, first_waiter);
|
||||
dll_make_last (&pmu->waiters, first_waiter);
|
||||
/* tell nsync_cv_wait_with_deadline() that we
|
||||
moved the waiter to *pmu's queue. */
|
||||
first_w->cv_mu = NULL;
|
||||
|
@ -107,7 +107,7 @@ static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
|||
if ((p_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0) {
|
||||
p_w = DLL_WAITER (p);
|
||||
}
|
||||
next = nsync_dll_next_ (to_wake_list, p);
|
||||
next = dll_next (to_wake_list, p);
|
||||
p_is_writer = (p_w != NULL &&
|
||||
DLL_WAITER (p)->l_type == nsync_writer_type_);
|
||||
/* We transfer this element if any of:
|
||||
|
@ -117,8 +117,8 @@ static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
|||
if (p_w == NULL) {
|
||||
/* wake non-native waiter */
|
||||
} else if (first_cant_acquire || first_is_writer || p_is_writer) {
|
||||
to_wake_list = nsync_dll_remove_ (to_wake_list, p);
|
||||
pmu->waiters = nsync_dll_make_last_in_list_ (pmu->waiters, p);
|
||||
dll_remove (&to_wake_list, p);
|
||||
dll_make_last (&pmu->waiters, p);
|
||||
/* tell nsync_cv_wait_with_deadline()
|
||||
that we moved the waiter to *pmu's
|
||||
queue. */
|
||||
|
@ -147,10 +147,10 @@ static void wake_waiters (nsync_dll_list_ to_wake_list, int all_readers) {
|
|||
}
|
||||
|
||||
/* Wake any waiters we didn't manage to enqueue on the mu. */
|
||||
for (p = nsync_dll_first_ (to_wake_list); p != NULL; p = next) {
|
||||
for (p = dll_first (to_wake_list); p != NULL; p = next) {
|
||||
struct nsync_waiter_s *p_nw = DLL_NSYNC_WAITER (p);
|
||||
next = nsync_dll_next_ (to_wake_list, p);
|
||||
to_wake_list = nsync_dll_remove_ (to_wake_list, p);
|
||||
next = dll_next (to_wake_list, p);
|
||||
dll_remove (&to_wake_list, p);
|
||||
/* Wake the waiter. */
|
||||
ATM_STORE_REL (&p_nw->waiting, 0); /* release store */
|
||||
nsync_mu_semaphore_v (p_nw->sem);
|
||||
|
@ -239,7 +239,7 @@ int nsync_cv_wait_with_deadline_generic (nsync_cv *pcv, void *pmu,
|
|||
|
||||
/* acquire spinlock, set non-empty */
|
||||
old_word = nsync_spin_test_and_set_ (&pcv->word, CV_SPINLOCK, CV_SPINLOCK|CV_NON_EMPTY, 0);
|
||||
pcv->waiters = nsync_dll_make_last_in_list_ (pcv->waiters, &w->nw.q);
|
||||
dll_make_last (&pcv->waiters, &w->nw.q);
|
||||
remove_count = ATM_LOAD (&w->remove_count);
|
||||
/* Release the spin lock. */
|
||||
ATM_STORE_REL (&pcv->word, old_word|CV_NON_EMPTY); /* release store */
|
||||
|
@ -277,12 +277,11 @@ int nsync_cv_wait_with_deadline_generic (nsync_cv *pcv, void *pmu,
|
|||
queue, and declare a
|
||||
timeout/cancellation. */
|
||||
outcome = sem_outcome;
|
||||
pcv->waiters = nsync_dll_remove_ (pcv->waiters,
|
||||
&w->nw.q);
|
||||
dll_remove (&pcv->waiters, &w->nw.q);
|
||||
do {
|
||||
old_value = ATM_LOAD (&w->remove_count);
|
||||
} while (!ATM_CAS (&w->remove_count, old_value, old_value+1));
|
||||
if (nsync_dll_is_empty_ (pcv->waiters)) {
|
||||
if (dll_is_empty (pcv->waiters)) {
|
||||
old_word &= ~(CV_NON_EMPTY);
|
||||
}
|
||||
ATM_STORE_REL (&w->nw.waiting, 0); /* release store */
|
||||
|
@ -328,27 +327,26 @@ int nsync_cv_wait_with_deadline_generic (nsync_cv *pcv, void *pmu,
|
|||
void nsync_cv_signal (nsync_cv *pcv) {
|
||||
IGNORE_RACES_START ();
|
||||
if ((ATM_LOAD_ACQ (&pcv->word) & CV_NON_EMPTY) != 0) { /* acquire load */
|
||||
nsync_dll_list_ to_wake_list = NULL; /* waiters that we will wake */
|
||||
struct Dll *to_wake_list = NULL; /* waiters that we will wake */
|
||||
int all_readers = 0;
|
||||
/* acquire spinlock */
|
||||
uint32_t old_word = nsync_spin_test_and_set_ (&pcv->word, CV_SPINLOCK,
|
||||
CV_SPINLOCK, 0);
|
||||
if (!nsync_dll_is_empty_ (pcv->waiters)) {
|
||||
if (!dll_is_empty (pcv->waiters)) {
|
||||
/* Point to first waiter that enqueued itself, and
|
||||
detach it from all others. */
|
||||
struct nsync_waiter_s *first_nw;
|
||||
nsync_dll_element_ *first = nsync_dll_first_ (pcv->waiters);
|
||||
pcv->waiters = nsync_dll_remove_ (pcv->waiters, first);
|
||||
struct Dll *first = dll_first (pcv->waiters);
|
||||
dll_remove (&pcv->waiters, first);
|
||||
first_nw = DLL_NSYNC_WAITER (first);
|
||||
if ((first_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0) {
|
||||
uint32_t old_value;
|
||||
do {
|
||||
old_value =
|
||||
ATM_LOAD (&DLL_WAITER (first)->remove_count);
|
||||
old_value = ATM_LOAD (&DLL_WAITER (first)->remove_count);
|
||||
} while (!ATM_CAS (&DLL_WAITER (first)->remove_count,
|
||||
old_value, old_value+1));
|
||||
}
|
||||
to_wake_list = nsync_dll_make_last_in_list_ (to_wake_list, first);
|
||||
dll_make_last (&to_wake_list, first);
|
||||
if ((first_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0 &&
|
||||
DLL_WAITER (first)->l_type == nsync_reader_type_) {
|
||||
int woke_writer;
|
||||
|
@ -363,14 +361,14 @@ void nsync_cv_signal (nsync_cv *pcv) {
|
|||
the condition; the client is expecting only one writer to be
|
||||
able make use of the wakeup, or he would have called
|
||||
nsync_cv_broadcast(). */
|
||||
nsync_dll_element_ *p = NULL;
|
||||
nsync_dll_element_ *next = NULL;
|
||||
struct Dll *p = NULL;
|
||||
struct Dll *next = NULL;
|
||||
all_readers = 1;
|
||||
woke_writer = 0;
|
||||
for (p = nsync_dll_first_ (pcv->waiters); p != NULL; p = next) {
|
||||
for (p = dll_first (pcv->waiters); p != NULL; p = next) {
|
||||
struct nsync_waiter_s *p_nw = DLL_NSYNC_WAITER (p);
|
||||
int should_wake;
|
||||
next = nsync_dll_next_ (pcv->waiters, p);
|
||||
next = dll_next (pcv->waiters, p);
|
||||
should_wake = 0;
|
||||
if ((p_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0 &&
|
||||
DLL_WAITER (p)->l_type == nsync_reader_type_) {
|
||||
|
@ -381,7 +379,7 @@ void nsync_cv_signal (nsync_cv *pcv) {
|
|||
should_wake = 1;
|
||||
}
|
||||
if (should_wake) {
|
||||
pcv->waiters = nsync_dll_remove_ (pcv->waiters, p);
|
||||
dll_remove (&pcv->waiters, p);
|
||||
if ((p_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0) {
|
||||
uint32_t old_value;
|
||||
do {
|
||||
|
@ -390,18 +388,17 @@ void nsync_cv_signal (nsync_cv *pcv) {
|
|||
} while (!ATM_CAS (&DLL_WAITER (p)->remove_count,
|
||||
old_value, old_value+1));
|
||||
}
|
||||
to_wake_list = nsync_dll_make_last_in_list_ (
|
||||
to_wake_list, p);
|
||||
dll_make_last (&to_wake_list, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nsync_dll_is_empty_ (pcv->waiters)) {
|
||||
if (dll_is_empty (pcv->waiters)) {
|
||||
old_word &= ~(CV_NON_EMPTY);
|
||||
}
|
||||
}
|
||||
/* Release spinlock. */
|
||||
ATM_STORE_REL (&pcv->word, old_word); /* release store */
|
||||
if (!nsync_dll_is_empty_ (to_wake_list)) {
|
||||
if (!dll_is_empty (to_wake_list)) {
|
||||
wake_waiters (to_wake_list, all_readers);
|
||||
}
|
||||
}
|
||||
|
@ -412,22 +409,22 @@ void nsync_cv_signal (nsync_cv *pcv) {
|
|||
void nsync_cv_broadcast (nsync_cv *pcv) {
|
||||
IGNORE_RACES_START ();
|
||||
if ((ATM_LOAD_ACQ (&pcv->word) & CV_NON_EMPTY) != 0) { /* acquire load */
|
||||
nsync_dll_element_ *p;
|
||||
nsync_dll_element_ *next;
|
||||
struct Dll *p;
|
||||
struct Dll *next;
|
||||
int all_readers;
|
||||
nsync_dll_list_ to_wake_list = NULL; /* waiters that we will wake */
|
||||
struct Dll *to_wake_list = NULL; /* waiters that we will wake */
|
||||
/* acquire spinlock */
|
||||
nsync_spin_test_and_set_ (&pcv->word, CV_SPINLOCK, CV_SPINLOCK, 0);
|
||||
p = NULL;
|
||||
next = NULL;
|
||||
all_readers = 1;
|
||||
/* Wake entire waiter list, which we leave empty. */
|
||||
for (p = nsync_dll_first_ (pcv->waiters); p != NULL; p = next) {
|
||||
for (p = dll_first (pcv->waiters); p != NULL; p = next) {
|
||||
struct nsync_waiter_s *p_nw = DLL_NSYNC_WAITER (p);
|
||||
next = nsync_dll_next_ (pcv->waiters, p);
|
||||
next = dll_next (pcv->waiters, p);
|
||||
all_readers = all_readers && (p_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0 &&
|
||||
(DLL_WAITER (p)->l_type == nsync_reader_type_);
|
||||
pcv->waiters = nsync_dll_remove_ (pcv->waiters, p);
|
||||
dll_remove (&pcv->waiters, p);
|
||||
if ((p_nw->flags & NSYNC_WAITER_FLAG_MUCV) != 0) {
|
||||
uint32_t old_value;
|
||||
do {
|
||||
|
@ -435,11 +432,11 @@ void nsync_cv_broadcast (nsync_cv *pcv) {
|
|||
} while (!ATM_CAS (&DLL_WAITER (p)->remove_count,
|
||||
old_value, old_value+1));
|
||||
}
|
||||
to_wake_list = nsync_dll_make_last_in_list_ (to_wake_list, p);
|
||||
dll_make_last (&to_wake_list, p);
|
||||
}
|
||||
/* Release spinlock and mark queue empty. */
|
||||
ATM_STORE_REL (&pcv->word, 0); /* release store */
|
||||
if (!nsync_dll_is_empty_ (to_wake_list)) { /* Wake them. */
|
||||
if (!dll_is_empty (to_wake_list)) { /* Wake them. */
|
||||
wake_waiters (to_wake_list, all_readers);
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +474,7 @@ static int cv_enqueue (void *v, struct nsync_waiter_s *nw) {
|
|||
nsync_cv *pcv = (nsync_cv *) v;
|
||||
/* acquire spinlock */
|
||||
uint32_t old_word = nsync_spin_test_and_set_ (&pcv->word, CV_SPINLOCK, CV_SPINLOCK, 0);
|
||||
pcv->waiters = nsync_dll_make_last_in_list_ (pcv->waiters, &nw->q);
|
||||
dll_make_last (&pcv->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 1);
|
||||
/* Release spinlock. */
|
||||
ATM_STORE_REL (&pcv->word, old_word | CV_NON_EMPTY); /* release store */
|
||||
|
@ -490,11 +487,11 @@ static int cv_dequeue (void *v, struct nsync_waiter_s *nw) {
|
|||
/* acquire spinlock */
|
||||
uint32_t old_word = nsync_spin_test_and_set_ (&pcv->word, CV_SPINLOCK, CV_SPINLOCK, 0);
|
||||
if (ATM_LOAD_ACQ (&nw->waiting) != 0) {
|
||||
pcv->waiters = nsync_dll_remove_ (pcv->waiters, &nw->q);
|
||||
dll_remove (&pcv->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 0);
|
||||
was_queued = 1;
|
||||
}
|
||||
if (nsync_dll_is_empty_ (pcv->waiters)) {
|
||||
if (dll_is_empty (pcv->waiters)) {
|
||||
old_word &= ~(CV_NON_EMPTY);
|
||||
}
|
||||
/* Release spinlock. */
|
||||
|
|
10
third_party/nsync/mem/nsync_debug.c
vendored
10
third_party/nsync/mem/nsync_debug.c
vendored
|
@ -15,9 +15,9 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -142,9 +142,9 @@ static void emit_word (struct emit_buf *b, const struct bit_name *name, uint32_t
|
|||
}
|
||||
|
||||
/* Emit the waiter queue *q to *b. */
|
||||
static void emit_waiters (struct emit_buf *b, nsync_dll_list_ list) {
|
||||
nsync_dll_element_ *p = nsync_dll_first_ (list);
|
||||
nsync_dll_element_ *next;
|
||||
static void emit_waiters (struct emit_buf *b, struct Dll *list) {
|
||||
struct Dll *p = dll_first (list);
|
||||
struct Dll *next;
|
||||
if (p != NULL) {
|
||||
emit_print (b, "\nwaiters =\n");
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ static void emit_waiters (struct emit_buf *b, nsync_dll_list_ list) {
|
|||
emit_print (b, "bad WAITER_TAG %i",
|
||||
(uintptr_t) w->tag);
|
||||
} else {
|
||||
next = nsync_dll_next_ (list, p);
|
||||
next = dll_next (list, p);
|
||||
if (nw->tag != NSYNC_WAITER_TAG) {
|
||||
emit_print (b, " bad WAITER_TAG %i",
|
||||
(uintptr_t) nw->tag);
|
||||
|
|
12
third_party/nsync/mem/nsync_mu_wait.c
vendored
12
third_party/nsync/mem/nsync_mu_wait.c
vendored
|
@ -16,9 +16,9 @@
|
|||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -203,18 +203,16 @@ int nsync_mu_wait_with_deadline (nsync_mu *mu,
|
|||
had_waiters = ((old_word & (MU_DESIG_WAKER | MU_WAITING)) == MU_WAITING);
|
||||
/* Queue the waiter. */
|
||||
if (first_wait) {
|
||||
nsync_maybe_merge_conditions_ (nsync_dll_last_ (mu->waiters),
|
||||
nsync_maybe_merge_conditions_ (dll_last (mu->waiters),
|
||||
&w->nw.q);
|
||||
/* first wait goes to end of queue */
|
||||
mu->waiters = nsync_dll_make_last_in_list_ (mu->waiters,
|
||||
&w->nw.q);
|
||||
dll_make_last (&mu->waiters, &w->nw.q);
|
||||
first_wait = 0;
|
||||
} else {
|
||||
nsync_maybe_merge_conditions_ (&w->nw.q,
|
||||
nsync_dll_first_ (mu->waiters));
|
||||
dll_first (mu->waiters));
|
||||
/* subsequent waits go to front of queue */
|
||||
mu->waiters = nsync_dll_make_first_in_list_ (mu->waiters,
|
||||
&w->nw.q);
|
||||
dll_make_first (&mu->waiters, &w->nw.q);
|
||||
}
|
||||
/* Release spinlock and *mu. */
|
||||
do {
|
||||
|
|
55
third_party/nsync/mem/nsync_note.c
vendored
55
third_party/nsync/mem/nsync_note.c
vendored
|
@ -15,11 +15,11 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
|
@ -64,12 +64,12 @@ static void set_expiry_time (nsync_note n, nsync_time t) {
|
|||
n->expiry_time_valid = 1;
|
||||
}
|
||||
|
||||
/* Return a pointer to the note containing nsync_dll_element_ *e. */
|
||||
#define DLL_NOTE(e) ((nsync_note)((e)->container))
|
||||
/* Return a pointer to the note containing struct Dll *e. */
|
||||
#define DLL_NOTE(e) DLL_CONTAINER(struct nsync_note_s_, parent_child_link, e)
|
||||
|
||||
/* Return whether n->children is empty. Assumes n->note_mu held. */
|
||||
static int no_children (const void *v) {
|
||||
return (nsync_dll_is_empty_ (((nsync_note)v)->children));
|
||||
return (dll_is_empty (((nsync_note)v)->children));
|
||||
}
|
||||
|
||||
#define WAIT_FOR_NO_CHILDREN(pred_, n_) nsync_mu_wait (&(n_)->note_mu, &pred_, (n_), NULL)
|
||||
|
@ -91,18 +91,18 @@ static void note_notify_child (nsync_note n, nsync_note parent) {
|
|||
nsync_time t;
|
||||
t = NOTIFIED_TIME (n);
|
||||
if (nsync_time_cmp (t, nsync_time_zero) > 0) {
|
||||
nsync_dll_element_ *p;
|
||||
nsync_dll_element_ *next;
|
||||
struct Dll *p;
|
||||
struct Dll *next;
|
||||
ATM_STORE_REL (&n->notified, 1);
|
||||
while ((p = nsync_dll_first_ (n->waiters)) != NULL) {
|
||||
while ((p = dll_first (n->waiters)) != NULL) {
|
||||
struct nsync_waiter_s *nw = DLL_NSYNC_WAITER (p);
|
||||
n->waiters = nsync_dll_remove_ (n->waiters, p);
|
||||
dll_remove (&n->waiters, p);
|
||||
ATM_STORE_REL (&nw->waiting, 0);
|
||||
nsync_mu_semaphore_v (nw->sem);
|
||||
}
|
||||
for (p = nsync_dll_first_ (n->children); p != NULL; p = next) {
|
||||
for (p = dll_first (n->children); p != NULL; p = next) {
|
||||
nsync_note child = DLL_NOTE (p);
|
||||
next = nsync_dll_next_ (n->children, p);
|
||||
next = dll_next (n->children, p);
|
||||
nsync_mu_lock (&child->note_mu);
|
||||
if (child->disconnecting == 0) {
|
||||
note_notify_child (child, n);
|
||||
|
@ -111,8 +111,7 @@ static void note_notify_child (nsync_note n, nsync_note parent) {
|
|||
}
|
||||
WAIT_FOR_NO_CHILDREN (no_children, n);
|
||||
if (parent != NULL) {
|
||||
parent->children = nsync_dll_remove_ (parent->children,
|
||||
&n->parent_child_link);
|
||||
dll_remove (&parent->children, &n->parent_child_link);
|
||||
WAKEUP_NO_CHILDREN (parent);
|
||||
n->parent = NULL;
|
||||
}
|
||||
|
@ -178,8 +177,8 @@ nsync_note nsync_note_new (nsync_note parent,
|
|||
nsync_time abs_deadline) {
|
||||
nsync_note n = (nsync_note) malloc (sizeof (*n));
|
||||
if (n != NULL) {
|
||||
memset ((void *) n, 0, sizeof (*n));
|
||||
nsync_dll_init_ (&n->parent_child_link, n);
|
||||
bzero (n, sizeof (*n));
|
||||
dll_init (&n->parent_child_link);
|
||||
set_expiry_time (n, abs_deadline);
|
||||
if (!nsync_note_is_notified (n) && parent != NULL) {
|
||||
nsync_time parent_time;
|
||||
|
@ -190,8 +189,8 @@ nsync_note nsync_note_new (nsync_note parent,
|
|||
}
|
||||
if (nsync_time_cmp (parent_time, nsync_time_zero) > 0) {
|
||||
n->parent = parent;
|
||||
parent->children = nsync_dll_make_last_in_list_ (parent->children,
|
||||
&n->parent_child_link);
|
||||
dll_make_last (&parent->children,
|
||||
&n->parent_child_link);
|
||||
}
|
||||
nsync_mu_unlock (&parent->note_mu);
|
||||
}
|
||||
|
@ -201,28 +200,27 @@ nsync_note nsync_note_new (nsync_note parent,
|
|||
|
||||
void nsync_note_free (nsync_note n) {
|
||||
nsync_note parent;
|
||||
nsync_dll_element_ *p;
|
||||
nsync_dll_element_ *next;
|
||||
struct Dll *p;
|
||||
struct Dll *next;
|
||||
nsync_mu_lock (&n->note_mu);
|
||||
n->disconnecting++;
|
||||
ASSERT (nsync_dll_is_empty_ (n->waiters));
|
||||
ASSERT (dll_is_empty (n->waiters));
|
||||
parent = n->parent;
|
||||
if (parent != NULL && !nsync_mu_trylock (&parent->note_mu)) {
|
||||
nsync_mu_unlock (&n->note_mu);
|
||||
nsync_mu_lock (&parent->note_mu);
|
||||
nsync_mu_lock (&n->note_mu);
|
||||
}
|
||||
for (p = nsync_dll_first_ (n->children); p != NULL; p = next) {
|
||||
for (p = dll_first (n->children); p != NULL; p = next) {
|
||||
nsync_note child = DLL_NOTE (p);
|
||||
next = nsync_dll_next_ (n->children, p);
|
||||
next = dll_next (n->children, p);
|
||||
nsync_mu_lock (&child->note_mu);
|
||||
if (child->disconnecting == 0) {
|
||||
n->children = nsync_dll_remove_ (n->children,
|
||||
&child->parent_child_link);
|
||||
dll_remove (&n->children, &child->parent_child_link);
|
||||
if (parent != NULL) {
|
||||
child->parent = parent;
|
||||
parent->children = nsync_dll_make_last_in_list_ (
|
||||
parent->children, &child->parent_child_link);
|
||||
dll_make_last (&parent->children,
|
||||
&child->parent_child_link);
|
||||
} else {
|
||||
child->parent = NULL;
|
||||
}
|
||||
|
@ -231,8 +229,7 @@ void nsync_note_free (nsync_note n) {
|
|||
}
|
||||
WAIT_FOR_NO_CHILDREN (no_children, n);
|
||||
if (parent != NULL) {
|
||||
parent->children = nsync_dll_remove_ (parent->children,
|
||||
&n->parent_child_link);
|
||||
dll_remove (&parent->children, &n->parent_child_link);
|
||||
WAKEUP_NO_CHILDREN (parent);
|
||||
n->parent = NULL;
|
||||
nsync_mu_unlock (&parent->note_mu);
|
||||
|
@ -273,7 +270,7 @@ static int note_enqueue (void *v, struct nsync_waiter_s *nw) {
|
|||
nsync_mu_lock (&n->note_mu);
|
||||
ntime = NOTIFIED_TIME (n);
|
||||
if (nsync_time_cmp (ntime, nsync_time_zero) > 0) {
|
||||
n->waiters = nsync_dll_make_last_in_list_ (n->waiters, &nw->q);
|
||||
dll_make_last (&n->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 1);
|
||||
waiting = 1;
|
||||
} else {
|
||||
|
@ -292,7 +289,7 @@ static int note_dequeue (void *v, struct nsync_waiter_s *nw) {
|
|||
nsync_mu_lock (&n->note_mu);
|
||||
ntime = NOTIFIED_TIME (n);
|
||||
if (nsync_time_cmp (ntime, nsync_time_zero) > 0) {
|
||||
n->waiters = nsync_dll_remove_ (n->waiters, &nw->q);
|
||||
dll_remove (&n->waiters, &nw->q);
|
||||
ATM_STORE (&nw->waiting, 0);
|
||||
was_queued = 1;
|
||||
}
|
||||
|
|
1
third_party/nsync/mem/nsync_once.c
vendored
1
third_party/nsync/mem/nsync_once.c
vendored
|
@ -18,7 +18,6 @@
|
|||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/once.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
|
|
10
third_party/nsync/mem/nsync_sem_wait.c
vendored
10
third_party/nsync/mem/nsync_sem_wait.c
vendored
|
@ -16,11 +16,11 @@
|
|||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
||||
|
@ -47,7 +47,7 @@ int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline,
|
|||
struct nsync_waiter_s nw;
|
||||
nw.tag = NSYNC_WAITER_TAG;
|
||||
nw.sem = &w->sem;
|
||||
nsync_dll_init_ (&nw.q, &nw);
|
||||
dll_init (&nw.q);
|
||||
ATM_STORE (&nw.waiting, 1);
|
||||
nw.flags = 0;
|
||||
nsync_mu_lock (&cancel_note->note_mu);
|
||||
|
@ -55,8 +55,7 @@ int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline,
|
|||
if (nsync_time_cmp (cancel_time, nsync_time_zero) > 0) {
|
||||
nsync_time local_abs_deadline;
|
||||
int deadline_is_nearer = 0;
|
||||
cancel_note->waiters = nsync_dll_make_last_in_list_ (
|
||||
cancel_note->waiters, &nw.q);
|
||||
dll_make_last (&cancel_note->waiters, &nw.q);
|
||||
local_abs_deadline = cancel_time;
|
||||
if (nsync_time_cmp (abs_deadline, cancel_time) < 0) {
|
||||
local_abs_deadline = abs_deadline;
|
||||
|
@ -73,8 +72,7 @@ int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline,
|
|||
cancel_time = NOTIFIED_TIME (cancel_note);
|
||||
if (nsync_time_cmp (cancel_time,
|
||||
nsync_time_zero) > 0) {
|
||||
cancel_note->waiters = nsync_dll_remove_ (
|
||||
cancel_note->waiters, &nw.q);
|
||||
dll_remove (&cancel_note->waiters, &nw.q);
|
||||
}
|
||||
}
|
||||
nsync_mu_unlock (&cancel_note->note_mu);
|
||||
|
|
3
third_party/nsync/mem/nsync_wait.c
vendored
3
third_party/nsync/mem/nsync_wait.c
vendored
|
@ -20,7 +20,6 @@
|
|||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -58,7 +57,7 @@ int nsync_wait_n (void *mu, void (*lock) (void *), void (*unlock) (void *),
|
|||
for (i = 0; i != count && enqueued; i++) {
|
||||
nw[i].tag = NSYNC_WAITER_TAG;
|
||||
nw[i].sem = &w->sem;
|
||||
nsync_dll_init_ (&nw[i].q, &nw[i]);
|
||||
dll_init (&nw[i].q);
|
||||
ATM_STORE (&nw[i].waiting, 0);
|
||||
nw[i].flags = 0;
|
||||
enqueued = (*waitable[i]->funcs->enqueue) (waitable[i]->v, &nw[i]);
|
||||
|
|
79
third_party/nsync/mu.c
vendored
79
third_party/nsync/mu.c
vendored
|
@ -16,10 +16,10 @@
|
|||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu_semaphore.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
@ -32,7 +32,7 @@ https://github.com/google/nsync\"");
|
|||
|
||||
/* Initialize *mu. */
|
||||
void nsync_mu_init (nsync_mu *mu) {
|
||||
memset ((void *) mu, 0, sizeof (*mu));
|
||||
bzero ((void *) mu, sizeof (*mu));
|
||||
}
|
||||
|
||||
/* Release the mutex spinlock. */
|
||||
|
@ -88,12 +88,10 @@ void nsync_mu_lock_slow_ (nsync_mu *mu, waiter *w, uint32_t clear, lock_type *l_
|
|||
ATM_STORE (&w->nw.waiting, 1);
|
||||
if (wait_count == 0) {
|
||||
/* first wait goes to end of queue */
|
||||
mu->waiters = nsync_dll_make_last_in_list_ (mu->waiters,
|
||||
&w->nw.q);
|
||||
dll_make_last (&mu->waiters, &w->nw.q);
|
||||
} else {
|
||||
/* subsequent waits go to front of queue */
|
||||
mu->waiters = nsync_dll_make_first_in_list_ (mu->waiters,
|
||||
&w->nw.q);
|
||||
dll_make_first (&mu->waiters, &w->nw.q);
|
||||
}
|
||||
|
||||
/* Release spinlock. Cannot use a store here, because
|
||||
|
@ -202,32 +200,32 @@ void nsync_mu_rlock (nsync_mu *mu) {
|
|||
|
||||
/* Invoke the condition associated with *p, which is an element of
|
||||
a "waiter" list. */
|
||||
static int condition_true (nsync_dll_element_ *p) {
|
||||
static int condition_true (struct Dll *p) {
|
||||
return ((*DLL_WAITER (p)->cond.f) (DLL_WAITER (p)->cond.v));
|
||||
}
|
||||
|
||||
/* If *p is an element of waiter_list (a list of "waiter" structs(, return a
|
||||
pointer to the next element of the list that has a different condition. */
|
||||
static nsync_dll_element_ *skip_past_same_condition (
|
||||
nsync_dll_list_ waiter_list, nsync_dll_element_ *p) {
|
||||
nsync_dll_element_ *next;
|
||||
nsync_dll_element_ *last_with_same_condition =
|
||||
static struct Dll *skip_past_same_condition (
|
||||
struct Dll *waiter_list, struct Dll *p) {
|
||||
struct Dll *next;
|
||||
struct Dll *last_with_same_condition =
|
||||
&DLL_WAITER_SAMECOND (DLL_WAITER (p)->same_condition.prev)->nw.q;
|
||||
if (last_with_same_condition != p && last_with_same_condition != p->prev) {
|
||||
/* First in set with same condition, so skip to end. */
|
||||
next = nsync_dll_next_ (waiter_list, last_with_same_condition);
|
||||
next = dll_next (waiter_list, last_with_same_condition);
|
||||
} else {
|
||||
next = nsync_dll_next_ (waiter_list, p);
|
||||
next = dll_next (waiter_list, p);
|
||||
}
|
||||
return (next);
|
||||
}
|
||||
|
||||
/* Merge the same_condition lists of *p and *n if they have the same non-NULL
|
||||
condition. */
|
||||
void nsync_maybe_merge_conditions_ (nsync_dll_element_ *p, nsync_dll_element_ *n) {
|
||||
void nsync_maybe_merge_conditions_ (struct Dll *p, struct Dll *n) {
|
||||
if (p != NULL && n != NULL &&
|
||||
WAIT_CONDITION_EQ (&DLL_WAITER (p)->cond, &DLL_WAITER (n)->cond)) {
|
||||
nsync_dll_splice_after_ (&DLL_WAITER (p)->same_condition,
|
||||
dll_splice_after (&DLL_WAITER (p)->same_condition,
|
||||
&DLL_WAITER (n)->same_condition);
|
||||
}
|
||||
}
|
||||
|
@ -235,19 +233,19 @@ void nsync_maybe_merge_conditions_ (nsync_dll_element_ *p, nsync_dll_element_ *n
|
|||
/* Remove element *e from nsync_mu waiter queue mu_queue, fixing
|
||||
up the same_condition list by merging the lists on either side if possible.
|
||||
Also increment the waiter's remove_count. */
|
||||
nsync_dll_list_ nsync_remove_from_mu_queue_ (nsync_dll_list_ mu_queue, nsync_dll_element_ *e) {
|
||||
struct Dll *nsync_remove_from_mu_queue_ (struct Dll *mu_queue, struct Dll *e) {
|
||||
/* Record previous and next elements in the original queue. */
|
||||
nsync_dll_element_ *prev = e->prev;
|
||||
nsync_dll_element_ *next = e->next;
|
||||
struct Dll *prev = e->prev;
|
||||
struct Dll *next = e->next;
|
||||
uint32_t old_value;
|
||||
/* Remove. */
|
||||
mu_queue = nsync_dll_remove_ (mu_queue, e);
|
||||
dll_remove (&mu_queue, e);
|
||||
do {
|
||||
old_value = ATM_LOAD (&DLL_WAITER (e)->remove_count);
|
||||
} while (!ATM_CAS (&DLL_WAITER (e)->remove_count, old_value, old_value+1));
|
||||
if (!nsync_dll_is_empty_ (mu_queue)) {
|
||||
if (!dll_is_empty (mu_queue)) {
|
||||
/* Fix up same_condition. */
|
||||
nsync_dll_element_ *e_same_condition = &DLL_WAITER (e)->same_condition;
|
||||
struct Dll *e_same_condition = &DLL_WAITER (e)->same_condition;
|
||||
|
||||
if (e_same_condition->next != e_same_condition) {
|
||||
/* *e is linked to a same_condition neighbour---just remove it. */
|
||||
|
@ -255,7 +253,7 @@ nsync_dll_list_ nsync_remove_from_mu_queue_ (nsync_dll_list_ mu_queue, nsync_dll
|
|||
e_same_condition->prev->next = e_same_condition->next;
|
||||
e_same_condition->next = e_same_condition;
|
||||
e_same_condition->prev = e_same_condition;
|
||||
} else if (prev != nsync_dll_last_ (mu_queue)) {
|
||||
} else if (prev != dll_last (mu_queue)) {
|
||||
/* Merge the new neighbours together if we can. */
|
||||
nsync_maybe_merge_conditions_ (prev, next);
|
||||
}
|
||||
|
@ -301,7 +299,7 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
} else if ((old_word&MU_SPINLOCK) == 0 &&
|
||||
ATM_CAS_ACQ (&mu->word, old_word,
|
||||
(old_word-early_release_mu)|MU_SPINLOCK|MU_DESIG_WAKER)) {
|
||||
nsync_dll_list_ wake;
|
||||
struct Dll *wake;
|
||||
lock_type *wake_type;
|
||||
uint32_t clear_on_release;
|
||||
uint32_t set_on_release;
|
||||
|
@ -311,8 +309,8 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
there are conditions to check, the mutex itself is
|
||||
still held. */
|
||||
|
||||
nsync_dll_element_ *p = NULL;
|
||||
nsync_dll_element_ *next = NULL;
|
||||
struct Dll *p = NULL;
|
||||
struct Dll *next = NULL;
|
||||
|
||||
/* Swap the entire mu->waiters list into the local
|
||||
"new_waiters" list. This gives us exclusive access
|
||||
|
@ -321,8 +319,8 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
will grab more new waiters that arrived while we
|
||||
were checking conditions, and terminates only if no
|
||||
new waiters arrive in one loop iteration. */
|
||||
nsync_dll_list_ waiters = NULL;
|
||||
nsync_dll_list_ new_waiters = mu->waiters;
|
||||
struct Dll *waiters = NULL;
|
||||
struct Dll *new_waiters = mu->waiters;
|
||||
mu->waiters = NULL;
|
||||
|
||||
/* Remove a waiter from the queue, if possible. */
|
||||
|
@ -330,8 +328,8 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
wake_type = NULL; /* type of waiter(s) on wake, or NULL if wake is empty. */
|
||||
clear_on_release = MU_SPINLOCK;
|
||||
set_on_release = MU_ALL_FALSE;
|
||||
while (!nsync_dll_is_empty_ (new_waiters)) { /* some new waiters to consider */
|
||||
p = nsync_dll_first_ (new_waiters);
|
||||
while (!dll_is_empty (new_waiters)) { /* some new waiters to consider */
|
||||
p = dll_first (new_waiters);
|
||||
if (testing_conditions) {
|
||||
/* Should we continue to test conditions? */
|
||||
if (wake_type == nsync_writer_type_) {
|
||||
|
@ -357,12 +355,12 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
}
|
||||
|
||||
/* Process the new waiters picked up in this iteration of the
|
||||
"while (!nsync_dll_is_empty_ (new_waiters))" loop,
|
||||
"while (!dll_is_empty (new_waiters))" loop,
|
||||
and stop looking when we run out of waiters, or we find
|
||||
a writer to wake up. */
|
||||
while (p != NULL && wake_type != nsync_writer_type_) {
|
||||
int p_has_condition;
|
||||
next = nsync_dll_next_ (new_waiters, p);
|
||||
next = dll_next (new_waiters, p);
|
||||
p_has_condition = (DLL_WAITER (p)->cond.f != NULL);
|
||||
if (p_has_condition && !testing_conditions) {
|
||||
nsync_panic_ ("checking a waiter condition "
|
||||
|
@ -377,7 +375,7 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
/* Wake this thread. */
|
||||
new_waiters = nsync_remove_from_mu_queue_ (
|
||||
new_waiters, p);
|
||||
wake = nsync_dll_make_last_in_list_ (wake, p);
|
||||
dll_make_last (&wake, p);
|
||||
wake_type = DLL_WAITER (p)->l_type;
|
||||
} else {
|
||||
/* Failing to wake a writer
|
||||
|
@ -403,10 +401,9 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
}
|
||||
|
||||
/* add the new_waiters to the last of the waiters. */
|
||||
nsync_maybe_merge_conditions_ (nsync_dll_last_ (waiters),
|
||||
nsync_dll_first_ (new_waiters));
|
||||
waiters = nsync_dll_make_last_in_list_ (waiters,
|
||||
nsync_dll_last_ (new_waiters));
|
||||
nsync_maybe_merge_conditions_ (dll_last (waiters),
|
||||
dll_first (new_waiters));
|
||||
dll_make_last (&waiters, dll_last (new_waiters));
|
||||
/* Pick up the next set of new waiters. */
|
||||
new_waiters = mu->waiters;
|
||||
mu->waiters = NULL;
|
||||
|
@ -415,7 +412,7 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
/* Return the local waiter list to *mu. */
|
||||
mu->waiters = waiters;
|
||||
|
||||
if (nsync_dll_is_empty_ (wake)) {
|
||||
if (dll_is_empty (wake)) {
|
||||
/* not waking a waiter => no designated waker */
|
||||
clear_on_release |= MU_DESIG_WAKER;
|
||||
}
|
||||
|
@ -425,7 +422,7 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
clear_on_release |= MU_ALL_FALSE;
|
||||
}
|
||||
|
||||
if (nsync_dll_is_empty_ (mu->waiters)) {
|
||||
if (dll_is_empty (mu->waiters)) {
|
||||
/* no waiters left */
|
||||
clear_on_release |= MU_WAITING | MU_WRITER_WAITING |
|
||||
MU_CONDITION | MU_ALL_FALSE;
|
||||
|
@ -443,9 +440,9 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
|
|||
old_word = ATM_LOAD (&mu->word);
|
||||
}
|
||||
/* Wake the waiters. */
|
||||
for (p = nsync_dll_first_ (wake); p != NULL; p = next) {
|
||||
next = nsync_dll_next_ (wake, p);
|
||||
wake = nsync_dll_remove_ (wake, p);
|
||||
for (p = dll_first (wake); p != NULL; p = next) {
|
||||
next = dll_next (wake, p);
|
||||
dll_remove (&wake, p);
|
||||
ATM_STORE_REL (&DLL_NSYNC_WAITER (p)->waiting, 0);
|
||||
nsync_mu_semaphore_v (&DLL_WAITER (p)->sem);
|
||||
}
|
||||
|
|
9
third_party/nsync/mu.h
vendored
9
third_party/nsync/mu.h
vendored
|
@ -1,11 +1,10 @@
|
|||
#ifndef NSYNC_MU_H_
|
||||
#define NSYNC_MU_H_
|
||||
#include "libc/intrin/dll.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,
|
||||
|
@ -49,9 +48,9 @@ struct nsync_dll_element_s_;
|
|||
|
||||
*/
|
||||
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_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
|
||||
|
|
2
third_party/nsync/mu_semaphore_futex.c
vendored
2
third_party/nsync/mu_semaphore_futex.c
vendored
|
@ -88,7 +88,7 @@ errno_t nsync_mu_semaphore_p_with_deadline_futex (nsync_semaphore *s, nsync_time
|
|||
struct timespec ts_buf;
|
||||
const struct timespec *ts = NULL;
|
||||
if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) != 0) {
|
||||
memset (&ts_buf, 0, sizeof (ts_buf));
|
||||
bzero (&ts_buf, sizeof (ts_buf));
|
||||
ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline);
|
||||
ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline);
|
||||
ts = &ts_buf;
|
||||
|
|
2
third_party/nsync/mu_semaphore_gcd.c
vendored
2
third_party/nsync/mu_semaphore_gcd.c
vendored
|
@ -82,7 +82,7 @@ errno_t nsync_mu_semaphore_p_with_deadline_gcd (nsync_semaphore *s,
|
|||
DISPATCH_TIME_FOREVER);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
memset (&ts, 0, sizeof (ts));
|
||||
bzero (&ts, sizeof (ts));
|
||||
ts.tv_sec = NSYNC_TIME_SEC (abs_deadline);
|
||||
ts.tv_nsec = NSYNC_TIME_NSEC (abs_deadline);
|
||||
if (dispatch_semaphore_wait (*(dispatch_semaphore_t *)s,
|
||||
|
|
2
third_party/nsync/nsync.mk
vendored
2
third_party/nsync/nsync.mk
vendored
|
@ -48,7 +48,7 @@ $(THIRD_PARTY_NSYNC_A).pkg: \
|
|||
$(THIRD_PARTY_NSYNC_A_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_NSYNC_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(THIRD_PARTY_NSYNC_A_OBJS): private \
|
||||
#$(THIRD_PARTY_NSYNC_A_OBJS): private \
|
||||
CCFLAGS += \
|
||||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
|
|
@ -499,7 +499,7 @@ static void test_cv_timeout_stress (testing t) {
|
|||
nsync_time deadline;
|
||||
deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000));
|
||||
do {
|
||||
memset ((void *) &s, 0, sizeof (s));
|
||||
bzero ((void *) &s, sizeof (s));
|
||||
s.loop_count = loop_count;
|
||||
s.cv_threads_per_value = 4;
|
||||
s.cv_reader_threads_per_value = 2;
|
||||
|
@ -519,7 +519,7 @@ static void test_mu_timeout_stress (testing t) {
|
|||
nsync_time deadline;
|
||||
deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000));
|
||||
do {
|
||||
memset ((void *) &s, 0, sizeof (s));
|
||||
bzero ((void *) &s, sizeof (s));
|
||||
s.loop_count = loop_count;
|
||||
s.cv_threads_per_value = 0;
|
||||
s.cv_reader_threads_per_value = 0;
|
||||
|
@ -539,7 +539,7 @@ static void test_mu_cv_timeout_stress (testing t) {
|
|||
nsync_time deadline;
|
||||
deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (5000));
|
||||
do {
|
||||
memset ((void *) &s, 0, sizeof (s));
|
||||
bzero ((void *) &s, sizeof (s));
|
||||
s.loop_count = loop_count;
|
||||
s.cv_threads_per_value = 4;
|
||||
s.cv_reader_threads_per_value = 1;
|
||||
|
|
8
third_party/nsync/testing/cv_test.c
vendored
8
third_party/nsync/testing/cv_test.c
vendored
|
@ -15,12 +15,12 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/cv.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/cv.h"
|
||||
#include "third_party/nsync/debug.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
|
@ -51,7 +51,7 @@ static cv_queue *cv_queue_new (int limit) {
|
|||
cv_queue *q;
|
||||
int size = offsetof (struct cv_queue_s, data) + sizeof (q->data[0]) * limit;
|
||||
q = (cv_queue *) malloc (size);
|
||||
memset ((void *) q, 0, size);
|
||||
bzero ((void *) q, size);
|
||||
q->limit = limit;
|
||||
return (q);
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ static void test_cv_debug (testing t) {
|
|||
int buflen;
|
||||
struct debug_state xs;
|
||||
struct debug_state *s = &xs;
|
||||
memset ((void *) s, 0, sizeof (*s));
|
||||
bzero ((void *) s, sizeof (*s));
|
||||
|
||||
/* Use nsync_*_debugger to check that they work. */
|
||||
tmp = nsync_mu_debugger (&s->mu);
|
||||
|
@ -708,7 +708,7 @@ static void test_cv_transfer (testing t) {
|
|||
TEST_LOG (t, ("transfer waiters %d wakeup_type %d cv_writers %d ccs_reader %d\n",
|
||||
waiters, wakeup_type, cv_writers, ccs_reader));
|
||||
}
|
||||
memset ((void *) cvt, 0, sizeof (*cvt));
|
||||
bzero ((void *) cvt, sizeof (*cvt));
|
||||
|
||||
/* Start the waiter threads that use condition variables. */
|
||||
for (i = 0; i < waiters-1; i++) {
|
||||
|
|
|
@ -149,8 +149,8 @@ static void example_cv_wait (testing t) {
|
|||
"five\n"
|
||||
"timeout 1s\n";
|
||||
|
||||
memset ((void *) &q, 0, sizeof (q));
|
||||
memset (&output, 0, sizeof (output));
|
||||
bzero ((void *) &q, sizeof (q));
|
||||
bzero (&output, sizeof (output));
|
||||
|
||||
closure_fork (closure_add_and_wait_cv (&add_and_wait_cv, &q,
|
||||
nsync_time_ms (500), NELEM (input), input));
|
||||
|
|
124
third_party/nsync/testing/dll_test.c
vendored
124
third_party/nsync/testing/dll_test.c
vendored
|
@ -15,11 +15,12 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/array.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/testing/smprintf.h"
|
||||
#include "third_party/nsync/testing/testing.h"
|
||||
// clang-format off
|
||||
|
@ -80,25 +81,25 @@ static char *a_string (const a_int *a) {
|
|||
|
||||
/* A list item for use in the tests below */
|
||||
struct list_item_s {
|
||||
nsync_dll_element_ e;
|
||||
struct Dll e;
|
||||
int i;
|
||||
};
|
||||
/* Return a pointer to the struct list_item_s containing nsync_dll_element_ *e_. */
|
||||
#define LIST_ITEM(e_) ((struct list_item_s *) ((e_)->container))
|
||||
/* Return a pointer to the struct list_item_s containing struct Dll *e_. */
|
||||
#define LIST_ITEM(e_) DLL_CONTAINER(struct list_item_s, e, e_)
|
||||
|
||||
|
||||
/* Check that list l contains elements containing the values in
|
||||
expected, by scanning both forwards and backwards through the list. Also
|
||||
verify that nsync_dll_first_() and nsync_dll_last_() return the first and last element
|
||||
found during those iterations, and that nsync_dll_is_empty_() yields the right value. */
|
||||
static void verify_list (testing t, const char *label, nsync_dll_list_ l,
|
||||
verify that dll_first() and dll_last() return the first and last element
|
||||
found during those iterations, and that dll_is_empty() yields the right value. */
|
||||
static void verify_list (testing t, const char *label, struct Dll *l,
|
||||
const a_int *expected, const char *file, int line) {
|
||||
nsync_dll_element_ *first;
|
||||
nsync_dll_element_ *last = NULL;
|
||||
nsync_dll_element_ *p;
|
||||
struct Dll *first;
|
||||
struct Dll *last = NULL;
|
||||
struct Dll *p;
|
||||
int i = 0;
|
||||
char *expected_str = a_string (expected);
|
||||
for (p = nsync_dll_first_ (l); p != NULL; p = nsync_dll_next_ (l, p)) {
|
||||
for (p = dll_first (l); p != NULL; p = dll_next (l, p)) {
|
||||
if (A (expected, i) != LIST_ITEM (p)->i) {
|
||||
TEST_ERROR (t, ("%s:%d; %s:expected=%s: expected %d as "
|
||||
"value %d in list, but found %d\n",
|
||||
|
@ -108,10 +109,10 @@ static void verify_list (testing t, const char *label, nsync_dll_list_ l,
|
|||
last = p;
|
||||
i++;
|
||||
}
|
||||
if (last != nsync_dll_last_ (l)) {
|
||||
if (last != dll_last (l)) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected %p as "
|
||||
"last item in list, but found %p\n",
|
||||
file, line, label, expected_str, last, nsync_dll_last_ (l)));
|
||||
file, line, label, expected_str, last, dll_last (l)));
|
||||
}
|
||||
if (i != A_LEN (expected)) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected %d items in "
|
||||
|
@ -120,7 +121,7 @@ static void verify_list (testing t, const char *label, nsync_dll_list_ l,
|
|||
}
|
||||
|
||||
first = NULL;
|
||||
for (p = nsync_dll_last_ (l); p != NULL; p = nsync_dll_prev_ (l, p)) {
|
||||
for (p = dll_last (l); p != NULL; p = dll_prev (l, p)) {
|
||||
i--;
|
||||
if (A (expected, i) != LIST_ITEM (p)->i) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected %d as "
|
||||
|
@ -130,10 +131,10 @@ static void verify_list (testing t, const char *label, nsync_dll_list_ l,
|
|||
}
|
||||
first = p;
|
||||
}
|
||||
if (first != nsync_dll_first_ (l)) {
|
||||
if (first != dll_first (l)) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected %p as "
|
||||
"first item in list, but found %p\n",
|
||||
file, line, label, expected_str, first, nsync_dll_last_ (l)));
|
||||
file, line, label, expected_str, first, dll_last (l)));
|
||||
}
|
||||
if (i != 0) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected %d items "
|
||||
|
@ -142,43 +143,43 @@ static void verify_list (testing t, const char *label, nsync_dll_list_ l,
|
|||
A_LEN (expected), A_LEN (expected)-i));
|
||||
}
|
||||
|
||||
if ((A_LEN (expected) == 0) != nsync_dll_is_empty_ (l)) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected nsync_dll_is_empty_() "
|
||||
if ((A_LEN (expected) == 0) != dll_is_empty (l)) {
|
||||
TEST_ERROR (t, ("%s:%d: %s:expected=%s: expected dll_is_empty() "
|
||||
"to yield %d but got %d\n",
|
||||
file, line, label, expected_str,
|
||||
(A_LEN (expected) == 0), nsync_dll_is_empty_ (l)));
|
||||
(A_LEN (expected) == 0), dll_is_empty (l)));
|
||||
}
|
||||
free (expected_str);
|
||||
}
|
||||
|
||||
/* Return a new list containing the count integers from start to
|
||||
start+count-1 by appending successive elements to the list.
|
||||
This exercises nsync_dll_make_last_in_list_() using singleton elements. */
|
||||
static nsync_dll_list_ make_list (int start, int count) {
|
||||
nsync_dll_list_ l = NULL;
|
||||
This exercises dll_make_last() using singleton elements. */
|
||||
static struct Dll *make_list (int start, int count) {
|
||||
struct Dll *l = NULL;
|
||||
int i;
|
||||
for (i = start; i != start+count; i++) {
|
||||
struct list_item_s *item =
|
||||
(struct list_item_s *) malloc (sizeof (*item));
|
||||
nsync_dll_init_ (&item->e, item);
|
||||
dll_init (&item->e);
|
||||
item->i = i;
|
||||
l = nsync_dll_make_last_in_list_ (l, &item->e);
|
||||
dll_make_last (&l, &item->e);
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
/* Return a new list containing the count integers from start to
|
||||
start+count-1 by prefixing the list with elements, starting with the last.
|
||||
It exercises nsync_dll_make_first_in_list_() using singleton elements. */
|
||||
static nsync_dll_list_ make_rlist (int start, int count) {
|
||||
nsync_dll_list_ l = NULL;
|
||||
It exercises dll_make_first() using singleton elements. */
|
||||
static struct Dll *make_rlist (int start, int count) {
|
||||
struct Dll *l = NULL;
|
||||
int i;
|
||||
for (i = start + count - 1; i != start-1; i--) {
|
||||
struct list_item_s *item =
|
||||
(struct list_item_s *) malloc (sizeof (*item));
|
||||
nsync_dll_init_ (&item->e, item);
|
||||
dll_init (&item->e);
|
||||
item->i = i;
|
||||
l = nsync_dll_make_first_in_list_ (l, &item->e);
|
||||
dll_make_first (&l, &item->e);
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
@ -190,16 +191,16 @@ static void test_dll (testing t) {
|
|||
a_int expected;
|
||||
struct list_item_s *item;
|
||||
|
||||
nsync_dll_list_ empty = NULL;
|
||||
nsync_dll_list_ list = NULL;
|
||||
struct Dll *empty = NULL;
|
||||
struct Dll *list = NULL;
|
||||
|
||||
nsync_dll_list_ x10 = NULL;
|
||||
nsync_dll_list_ x20 = NULL;
|
||||
nsync_dll_list_ x30 = NULL;
|
||||
nsync_dll_list_ x40 = NULL;
|
||||
nsync_dll_list_ x50 = NULL;
|
||||
struct Dll *x10 = NULL;
|
||||
struct Dll *x20 = NULL;
|
||||
struct Dll *x30 = NULL;
|
||||
struct Dll *x40 = NULL;
|
||||
struct Dll *x50 = NULL;
|
||||
|
||||
memset (&expected, 0, sizeof (expected));
|
||||
bzero (&expected, sizeof (expected));
|
||||
|
||||
/* All lists are initially empty. */
|
||||
verify_list (t, "empty (0)", empty, &a_int_empty, __FILE__, __LINE__);
|
||||
|
@ -223,61 +224,60 @@ static void test_dll (testing t) {
|
|||
verify_list (t, "x50", x50, a_set (&expected, 50, 51, 52, -1), __FILE__, __LINE__);
|
||||
|
||||
/* Check that adding nothing to an empty list leaves it empty. */
|
||||
list = nsync_dll_make_first_in_list_ (list, NULL);
|
||||
dll_make_first (&list, NULL);
|
||||
verify_list (t, "list(1)", list, &a_int_empty, __FILE__, __LINE__);
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_first_ (empty));
|
||||
dll_make_first (&list, dll_first (empty));
|
||||
verify_list (t, "list(2)", list, &a_int_empty, __FILE__, __LINE__);
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_last_ (empty));
|
||||
dll_make_first (&list, dll_last (empty));
|
||||
verify_list (t, "list(3)", list, &a_int_empty, __FILE__, __LINE__);
|
||||
|
||||
/* Prefix an empty list with some elements. */
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_first_ (x10));
|
||||
dll_make_first (&list, dll_first (x10));
|
||||
verify_list (t, "list(4)", list, a_set (&expected, 10, 11, 12, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Check that adding nothing no a non-empty list leaves it unchanged. */
|
||||
list = nsync_dll_make_first_in_list_ (list, NULL);
|
||||
dll_make_first (&list, NULL);
|
||||
verify_list (t, "list(5)", list, a_set (&expected, 10, 11, 12, -1),
|
||||
__FILE__, __LINE__);
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_first_ (empty));
|
||||
dll_make_first (&list, dll_first (empty));
|
||||
verify_list (t, "list(6)", list, a_set (&expected, 10, 11, 12, -1),
|
||||
__FILE__, __LINE__);
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_last_ (empty));
|
||||
dll_make_first (&list, dll_last (empty));
|
||||
verify_list (t, "list(7)", list, a_set (&expected, 10, 11, 12, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Check prefixing the list with some elements. */
|
||||
list = nsync_dll_make_first_in_list_ (list, nsync_dll_first_ (x20));
|
||||
dll_make_first (&list, dll_first (x20));
|
||||
verify_list (t, "list(8)", list,
|
||||
a_set (&expected, 20, 21, 22, 10, 11, 12, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Check appending elements to list. */
|
||||
list = nsync_dll_make_last_in_list_ (list, nsync_dll_last_ (x30));
|
||||
dll_make_last (&list, dll_last (x30));
|
||||
verify_list (t, "list(9)", list,
|
||||
a_set (&expected, 20, 21, 22, 10, 11, 12, 30, 31, 32, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
||||
/* Remove the first element. */
|
||||
item = (struct list_item_s *) nsync_dll_first_ (list)->container;
|
||||
list = nsync_dll_remove_ (list, &item->e);
|
||||
item = (struct list_item_s *) LIST_ITEM (dll_first (list));
|
||||
dll_remove (&list, &item->e);
|
||||
verify_list (t, "list(10)", list,
|
||||
a_set (&expected, 21, 22, 10, 11, 12, 30, 31, 32, -1),
|
||||
__FILE__, __LINE__);
|
||||
free (item);
|
||||
|
||||
/* Remove the last element. */
|
||||
item = (struct list_item_s *) nsync_dll_last_ (list)->container;
|
||||
list = nsync_dll_remove_ (list, &item->e);
|
||||
item = (struct list_item_s *) LIST_ITEM (dll_last (list));
|
||||
dll_remove (&list, &item->e);
|
||||
verify_list (t, "list(11)", list,
|
||||
a_set (&expected, 21, 22, 10, 11, 12, 30, 31, -1),
|
||||
__FILE__, __LINE__);
|
||||
free (item);
|
||||
|
||||
/* Remove the third element. */
|
||||
item = (struct list_item_s *) nsync_dll_next_ (list,
|
||||
nsync_dll_next_ (list, nsync_dll_first_ (list)))->container;
|
||||
list = nsync_dll_remove_ (list, &item->e);
|
||||
item = LIST_ITEM (dll_next (list, dll_next (list, dll_first (list))));
|
||||
dll_remove (&list, &item->e);
|
||||
verify_list (t, "list(12)",
|
||||
list, a_set (&expected, 21, 22, 11, 12, 30, 31, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
@ -285,10 +285,10 @@ static void test_dll (testing t) {
|
|||
|
||||
/* Remove all elements. */
|
||||
a_set (&expected, 21, 22, 11, 12, 30, 31, -1);
|
||||
for (i = 0; !nsync_dll_is_empty_ (list); i++) {
|
||||
for (i = 0; !dll_is_empty (list); i++) {
|
||||
char buf[32];
|
||||
item = (struct list_item_s *) nsync_dll_first_ (list)->container;
|
||||
list = nsync_dll_remove_ (list, &item->e);
|
||||
item = LIST_ITEM (dll_first (list));
|
||||
dll_remove (&list, &item->e);
|
||||
a_remove_first (&expected);
|
||||
snprintf (buf, sizeof (buf), "list(13.%d)", i);
|
||||
verify_list (t, buf, list, &expected, __FILE__, __LINE__);
|
||||
|
@ -297,22 +297,22 @@ static void test_dll (testing t) {
|
|||
verify_list (t, "list(14)", list, &a_int_empty, __FILE__, __LINE__);
|
||||
|
||||
/* Append some elements to an empty list. */
|
||||
list = nsync_dll_make_last_in_list_ (list, nsync_dll_last_ (x40));
|
||||
dll_make_last (&list, dll_last (x40));
|
||||
verify_list (t, "list(15)", list,
|
||||
a_set (&expected, 40, 41, 42, -1), __FILE__, __LINE__);
|
||||
|
||||
/* Use nsync_dll_splice_after_() to put {50, 51, 52} just after 41, which is
|
||||
/* Use dll_splice_after() to put {50, 51, 52} just after 41, which is
|
||||
next (first (list)). */
|
||||
nsync_dll_splice_after_ (nsync_dll_next_ (list, nsync_dll_first_ (list)), nsync_dll_first_ (x50));
|
||||
dll_splice_after (dll_next (list, dll_first (list)), dll_first (x50));
|
||||
verify_list (t, "list(16)", list,
|
||||
a_set (&expected, 40, 41, 50, 51, 52, 42, -1),
|
||||
__FILE__, __LINE__);
|
||||
|
||||
A_FREE (&expected);
|
||||
|
||||
while (!nsync_dll_is_empty_ (list)) {
|
||||
item = (struct list_item_s *) nsync_dll_first_ (list)->container;
|
||||
list = nsync_dll_remove_ (list, &item->e);
|
||||
while (!dll_is_empty (list)) {
|
||||
item = LIST_ITEM (dll_first (list));
|
||||
dll_remove (&list, &item->e);
|
||||
free (item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct starve_data_s {
|
|||
|
||||
/* initialize *sd */
|
||||
static void starve_data_init (starve_data *sd, int threads) {
|
||||
memset ((void *) sd, 0, sizeof (*sd));
|
||||
bzero ((void *) sd, sizeof (*sd));
|
||||
sd->not_yet_started = threads;
|
||||
sd->not_yet_done = threads;
|
||||
sd->start = nsync_time_now ();
|
||||
|
|
18
third_party/nsync/testing/mu_test.c
vendored
18
third_party/nsync/testing/mu_test.c
vendored
|
@ -15,11 +15,11 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "third_party/nsync/cv.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
#include "third_party/nsync/testing/closure.h"
|
||||
#include "third_party/nsync/testing/smprintf.h"
|
||||
|
@ -116,7 +116,7 @@ static void test_mu_nthread (testing t) {
|
|||
do {
|
||||
int i;
|
||||
test_data td;
|
||||
memset ((void *) &td, 0, sizeof (td));
|
||||
bzero ((void *) &td, sizeof (td));
|
||||
td.t = t;
|
||||
td.n_threads = 5;
|
||||
td.loop_count = loop_count;
|
||||
|
@ -155,7 +155,7 @@ static void test_mutex_nthread (testing t) {
|
|||
do {
|
||||
int i;
|
||||
test_data td;
|
||||
memset ((void *) &td, 0, sizeof (td));
|
||||
bzero ((void *) &td, sizeof (td));
|
||||
td.t = t;
|
||||
td.n_threads = 5;
|
||||
td.loop_count = loop_count;
|
||||
|
@ -196,7 +196,7 @@ static void test_rwmutex_nthread (testing t) {
|
|||
do {
|
||||
int i;
|
||||
test_data td;
|
||||
memset ((void *) &td, 0, sizeof (td));
|
||||
bzero ((void *) &td, sizeof (td));
|
||||
td.t = t;
|
||||
td.n_threads = 5;
|
||||
td.loop_count = loop_count;
|
||||
|
@ -249,7 +249,7 @@ static void test_try_mu_nthread (testing t) {
|
|||
do {
|
||||
int i;
|
||||
test_data td;
|
||||
memset ((void *) &td, 0, sizeof (td));
|
||||
bzero ((void *) &td, sizeof (td));
|
||||
td.t = t;
|
||||
td.n_threads = 5;
|
||||
td.loop_count = loop_count;
|
||||
|
@ -281,7 +281,7 @@ typedef struct counter_s {
|
|||
/* Return a counter with initial value "initial". */
|
||||
static counter *counter_new (int initial) {
|
||||
counter *c = (counter *) malloc (sizeof (*c));
|
||||
memset ((void *) c, 0, sizeof (*c));
|
||||
bzero ((void *) c, sizeof (*c));
|
||||
c->value = initial;
|
||||
return (c);
|
||||
}
|
||||
|
@ -1023,7 +1023,7 @@ static void contended_state_run_test (contended_state *cs, testing t,
|
|||
nsync_mu locks, with small critical sections. */
|
||||
static void benchmark_mu_contended (testing t) {
|
||||
contended_state cs;
|
||||
memset ((void *) &cs, 0, sizeof (cs));
|
||||
bzero ((void *) &cs, sizeof (cs));
|
||||
contended_state_run_test (&cs, t, &cs.mu, (void (*) (void*))&nsync_mu_lock,
|
||||
(void (*) (void*))&nsync_mu_unlock);
|
||||
}
|
||||
|
@ -1032,7 +1032,7 @@ static void benchmark_mu_contended (testing t) {
|
|||
pthread_mutex_t locks, with small critical sections. */
|
||||
static void benchmark_mutex_contended (testing t) {
|
||||
contended_state cs;
|
||||
memset ((void *) &cs, 0, sizeof (cs));
|
||||
bzero ((void *) &cs, sizeof (cs));
|
||||
pthread_mutex_init (&cs.mutex, NULL);
|
||||
contended_state_run_test (&cs, t, &cs.mutex, &void_pthread_mutex_lock,
|
||||
&void_pthread_mutex_unlock);
|
||||
|
@ -1043,7 +1043,7 @@ static void benchmark_mutex_contended (testing t) {
|
|||
pthread_rwlock_t locks, with small critical sections. */
|
||||
static void benchmark_wmutex_contended (testing t) {
|
||||
contended_state cs;
|
||||
memset ((void *) &cs, 0, sizeof (cs));
|
||||
bzero ((void *) &cs, sizeof (cs));
|
||||
pthread_rwlock_init (&cs.rwmutex, NULL);
|
||||
contended_state_run_test (&cs, t, &cs.rwmutex, &void_pthread_rwlock_wrlock,
|
||||
&void_pthread_rwlock_unlock);
|
||||
|
|
|
@ -148,8 +148,8 @@ static void example_mu_wait (testing t) {
|
|||
"five\n"
|
||||
"timeout 1s\n";
|
||||
|
||||
memset ((void *) &q, 0, sizeof (q));
|
||||
memset (&output, 0, sizeof (output));
|
||||
bzero ((void *) &q, sizeof (q));
|
||||
bzero (&output, sizeof (output));
|
||||
|
||||
closure_fork (closure_add_and_wait_mu (&add_and_wait_mu, &q, nsync_time_ms (500),
|
||||
NELEM (input), input));
|
||||
|
|
4
third_party/nsync/testing/mu_wait_test.c
vendored
4
third_party/nsync/testing/mu_wait_test.c
vendored
|
@ -15,10 +15,10 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
#include "third_party/nsync/note.h"
|
||||
#include "third_party/nsync/testing/closure.h"
|
||||
#include "third_party/nsync/testing/smprintf.h"
|
||||
|
@ -44,7 +44,7 @@ static mu_queue *mu_queue_new (int limit) {
|
|||
mu_queue *q;
|
||||
int size = offsetof (struct mu_queue_s, data) + sizeof (q->data[0]) * limit;
|
||||
q = (mu_queue *) malloc (size);
|
||||
memset ((void *) q, 0, size);
|
||||
bzero ((void *) q, size);
|
||||
q->limit = limit;
|
||||
return (q);
|
||||
}
|
||||
|
|
4
third_party/nsync/testing/once_test.c
vendored
4
third_party/nsync/testing/once_test.c
vendored
|
@ -15,11 +15,11 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/once.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "third_party/nsync/counter.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/once.h"
|
||||
#include "third_party/nsync/testing/closure.h"
|
||||
#include "third_party/nsync/testing/smprintf.h"
|
||||
#include "third_party/nsync/testing/testing.h"
|
||||
|
@ -99,7 +99,7 @@ static void test_once_run (testing t) {
|
|||
for (i = 0; i != 250; i++) {
|
||||
struct once_test_s *s =
|
||||
(struct once_test_s *) malloc (sizeof (*s));
|
||||
memset ((void *) s, 0, sizeof (*s));
|
||||
bzero ((void *) s, sizeof (*s));
|
||||
s->counter = 0;
|
||||
s->done = nsync_counter_new (N);
|
||||
s->t = t;
|
||||
|
|
2
third_party/nsync/testing/pingpong_test.c
vendored
2
third_party/nsync/testing/pingpong_test.c
vendored
|
@ -53,7 +53,7 @@ typedef struct ping_pong_s {
|
|||
} ping_pong;
|
||||
|
||||
static void ping_pong_init (ping_pong *pp, int limit) {
|
||||
memset ((void *) pp, 0, sizeof (*pp));
|
||||
bzero ((void *) pp, sizeof (*pp));
|
||||
pthread_mutex_init (&pp->mutex, NULL);
|
||||
pthread_rwlock_init (&pp->rwmutex, NULL);
|
||||
pthread_cond_init (&pp->cond[0], NULL);
|
||||
|
|
19
third_party/nsync/testing/testing.c
vendored
19
third_party/nsync/testing/testing.c
vendored
|
@ -15,6 +15,7 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/nsync/testing/testing.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/limits.h"
|
||||
|
@ -25,14 +26,12 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "third_party/nsync/atomic.internal.h"
|
||||
#include "third_party/nsync/common.internal.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "third_party/nsync/mu_wait.h"
|
||||
#include "third_party/nsync/races.internal.h"
|
||||
#include "third_party/nsync/testing/atm_log.h"
|
||||
#include "third_party/nsync/testing/closure.h"
|
||||
#include "third_party/nsync/testing/smprintf.h"
|
||||
#include "third_party/nsync/testing/testing.h"
|
||||
#include "third_party/nsync/testing/time_extra.h"
|
||||
// clang-format off
|
||||
|
||||
|
@ -55,7 +54,7 @@ struct testing_base_s {
|
|||
|
||||
nsync_mu testing_mu; /* protects fields below */
|
||||
int is_uniprocessor; /* whether the system is a uniprocessor */
|
||||
nsync_dll_list_ children; /* list of testing_s structs whose base is this testing_base_s */
|
||||
struct Dll *children; /* list of testing_s structs whose base is this testing_base_s */
|
||||
int child_count; /* count of testing_s structs whose base is this testing_base_s */
|
||||
int exit_status; /* final exit status */
|
||||
};
|
||||
|
@ -70,7 +69,7 @@ struct testing_s {
|
|||
nsync_time stop_time; /* when the timer was stopped; for benchmarks */
|
||||
void (*f) (testing); /* test function to run */
|
||||
const char *name; /* name of test */
|
||||
nsync_dll_element_ siblings; /* part of list of siblings */
|
||||
struct Dll siblings; /* part of list of siblings */
|
||||
};
|
||||
|
||||
/* Output the header for benchmarks. */
|
||||
|
@ -147,7 +146,7 @@ testing_base testing_new (int argc, char *argv[], int flags) {
|
|||
int argn;
|
||||
testing_base tb = (testing_base)malloc (sizeof (*tb));
|
||||
ShowCrashReports ();
|
||||
memset ((void *) tb, 0, sizeof (*tb));
|
||||
bzero ((void *) tb, sizeof (*tb));
|
||||
tb->flags = flags;
|
||||
tb->fp = stderr;
|
||||
tb->argc = argc;
|
||||
|
@ -224,7 +223,7 @@ static void finish_run (testing t) {
|
|||
if (tb->exit_status < t->test_status) {
|
||||
tb->exit_status = t->test_status;
|
||||
}
|
||||
tb->children = nsync_dll_remove_ (tb->children, &t->siblings);
|
||||
dll_remove (&tb->children, &t->siblings);
|
||||
tb->child_count--;
|
||||
nsync_mu_unlock (&tb->testing_mu);
|
||||
free (t);
|
||||
|
@ -358,8 +357,8 @@ void testing_run_ (testing_base tb, void (*f) (testing t), const char *name, int
|
|||
(tb->include_pat == NULL || match (tb->include_pat, name)) &&
|
||||
(tb->exclude_pat == NULL || !match (tb->exclude_pat, name))) {
|
||||
testing t = (testing) malloc (sizeof (*t));
|
||||
memset ((void *) t, 0, sizeof (*t));
|
||||
nsync_dll_init_ (&t->siblings, t);
|
||||
bzero ((void *) t, sizeof (*t));
|
||||
dll_init (&t->siblings);
|
||||
t->base = tb;
|
||||
t->f = f;
|
||||
t->name = name;
|
||||
|
@ -378,7 +377,7 @@ void testing_run_ (testing_base tb, void (*f) (testing t), const char *name, int
|
|||
nsync_mu_lock (&tb->testing_mu);
|
||||
nsync_mu_wait (&tb->testing_mu, &spare_thread, tb, NULL);
|
||||
tb->child_count++;
|
||||
tb->children = nsync_dll_make_last_in_list_ (tb->children, &t->siblings);
|
||||
dll_make_last (&tb->children, &t->siblings);
|
||||
nsync_mu_unlock (&tb->testing_mu);
|
||||
closure_fork (closure_testing (&run_test, t));
|
||||
} else {
|
||||
|
@ -394,7 +393,7 @@ void testing_run_ (testing_base tb, void (*f) (testing t), const char *name, int
|
|||
nsync_mu_lock (&tb->testing_mu);
|
||||
nsync_mu_wait (&tb->testing_mu, &spare_thread, tb, NULL);
|
||||
tb->child_count++;
|
||||
tb->children = nsync_dll_make_last_in_list_ (tb->children, &t->siblings);
|
||||
dll_make_last (&tb->children, &t->siblings);
|
||||
nsync_mu_unlock (&tb->testing_mu);
|
||||
closure_fork (closure_testing (&run_benchmark, t));
|
||||
}
|
||||
|
|
4
third_party/nsync/testing/wait_test.c
vendored
4
third_party/nsync/testing/wait_test.c
vendored
|
@ -60,8 +60,8 @@ static void test_wait_n (testing t) {
|
|||
nsync_time deadline;
|
||||
a_waitable aw;
|
||||
a_pwaitable apw;
|
||||
memset (&aw, 0, sizeof (aw));
|
||||
memset (&apw, 0, sizeof (apw));
|
||||
bzero (&aw, sizeof (aw));
|
||||
bzero (&apw, sizeof (apw));
|
||||
now = nsync_time_now ();
|
||||
deadline = nsync_time_add (now, nsync_time_ms (100));
|
||||
for (j = A_LEN (&aw); A_LEN (&aw) < j+ncounter;) {
|
||||
|
|
4
third_party/nsync/wait_s.internal.h
vendored
4
third_party/nsync/wait_s.internal.h
vendored
|
@ -1,7 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_WAIT_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_WAIT_INTERNAL_H_
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "third_party/nsync/atomic.h"
|
||||
#include "third_party/nsync/dll.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -13,7 +13,7 @@ COSMOPOLITAN_C_START_
|
|||
struct nsync_waiter_s {
|
||||
uint32_t tag; /* used for debugging */
|
||||
uint32_t flags; /* see below */
|
||||
nsync_dll_element_ q; /* used to link children of parent */
|
||||
struct Dll q; /* used to link children of parent */
|
||||
nsync_atomic_uint32_ waiting; /* non-zero <=> the waiter is waiting */
|
||||
struct nsync_semaphore_s_ *sem; /* *sem will be Ved when waiter is woken */
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue