mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-26 22:38:30 +00:00
Add *NSYNC to libc/isystem
This commit is contained in:
parent
6f7d0cb1c3
commit
22b63d0b98
32 changed files with 286 additions and 119 deletions
150
third_party/nsync/mem/nsync_once.c
vendored
Normal file
150
third_party/nsync/mem/nsync_once.c
vendored
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*-*- 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/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"
|
||||
#include "third_party/nsync/wait_s.internal.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
*NSYNC (Apache 2.0)\\n\
|
||||
Copyright 2016 Google, Inc.\\n\
|
||||
https://github.com/google/nsync\"");
|
||||
// clang-format off
|
||||
|
||||
/* An once_sync_s struct contains a lock, and a condition variable on which
|
||||
threads may wait for an nsync_once to be initialized by another thread.
|
||||
|
||||
A separate struct is used only to keep nsync_once small.
|
||||
|
||||
A given nsync_once can be associated with any once_sync_s struct, but cannot
|
||||
be associated with more than one. nsync_once instances are mapped to
|
||||
once_sync_s instances by a trivial hashing scheme implemented by
|
||||
NSYNC_ONCE_SYNC_().
|
||||
|
||||
The number of once_sync_s structs in the following array is greater than one
|
||||
only to reduce the probability of contention if a great many distinct
|
||||
nsync_once variables are initialized concurrently. */
|
||||
static struct once_sync_s {
|
||||
nsync_mu once_mu;
|
||||
nsync_cv once_cv;
|
||||
} once_sync[64];
|
||||
|
||||
/* Return a pointer to the once_sync_s struct associated with the nsync_once *p. */
|
||||
#define NSYNC_ONCE_SYNC_(p) &once_sync[(((uintptr_t) (p)) / sizeof (*(p))) % \
|
||||
(sizeof (once_sync) / sizeof (once_sync[0]))]
|
||||
|
||||
/* Implement nsync_run_once, nsync_run_once_arg, nsync_run_once_spin, or
|
||||
nsync_run_once_arg_spin, chosen as described below.
|
||||
|
||||
If s!=NULL, s is required to point to the once_sync_s associated with *once,
|
||||
and the semantics of nsync_run_once or nsync_run_once_arg are provided.
|
||||
If s==NULL, the semantics of nsync_run_once_spin, or nsync_run_once_arg_spin
|
||||
are provided.
|
||||
|
||||
If f!=NULL, the semantics of nsync_run_once or nsync_run_once_spin are
|
||||
provided. Otherwise, farg is required to be non-NULL, and the semantics of
|
||||
nsync_run_once_arg or nsync_run_once_arg_spin are provided. */
|
||||
static void nsync_run_once_impl (nsync_once *once, struct once_sync_s *s,
|
||||
void (*f) (void), void (*farg) (void *arg), void *arg) {
|
||||
uint32_t o = ATM_LOAD_ACQ (once);
|
||||
if (o != 2) {
|
||||
unsigned attempts = 0;
|
||||
if (s != NULL) {
|
||||
nsync_mu_lock (&s->once_mu);
|
||||
}
|
||||
while (o == 0 && !ATM_CAS_ACQ (once, 0, 1)) {
|
||||
o = ATM_LOAD (once);
|
||||
}
|
||||
if (o == 0) {
|
||||
if (s != NULL) {
|
||||
nsync_mu_unlock (&s->once_mu);
|
||||
}
|
||||
if (f != NULL) {
|
||||
(*f) ();
|
||||
} else {
|
||||
(*farg) (arg);
|
||||
}
|
||||
if (s != NULL) {
|
||||
nsync_mu_lock (&s->once_mu);
|
||||
nsync_cv_broadcast (&s->once_cv);
|
||||
}
|
||||
ATM_STORE_REL (once, 2);
|
||||
}
|
||||
while (ATM_LOAD_ACQ (once) != 2) {
|
||||
if (s != NULL) {
|
||||
nsync_time deadline;
|
||||
if (attempts < 50) {
|
||||
attempts += 10;
|
||||
}
|
||||
deadline = nsync_time_add (nsync_time_now (), nsync_time_ms (attempts));
|
||||
nsync_cv_wait_with_deadline (&s->once_cv, &s->once_mu, deadline, NULL);
|
||||
} else {
|
||||
attempts = nsync_spin_delay_ (attempts);
|
||||
}
|
||||
}
|
||||
if (s != NULL) {
|
||||
nsync_mu_unlock (&s->once_mu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsync_run_once (nsync_once *once, void (*f) (void)) {
|
||||
uint32_t o;
|
||||
IGNORE_RACES_START ();
|
||||
o = ATM_LOAD_ACQ (once);
|
||||
if (o != 2) {
|
||||
struct once_sync_s *s = NSYNC_ONCE_SYNC_ (once);
|
||||
nsync_run_once_impl (once, s, f, NULL, NULL);
|
||||
}
|
||||
IGNORE_RACES_END ();
|
||||
}
|
||||
|
||||
void nsync_run_once_arg (nsync_once *once, void (*farg) (void *arg), void *arg) {
|
||||
uint32_t o;
|
||||
IGNORE_RACES_START ();
|
||||
o = ATM_LOAD_ACQ (once);
|
||||
if (o != 2) {
|
||||
struct once_sync_s *s = NSYNC_ONCE_SYNC_ (once);
|
||||
nsync_run_once_impl (once, s, NULL, farg, arg);
|
||||
}
|
||||
IGNORE_RACES_END ();
|
||||
}
|
||||
|
||||
void nsync_run_once_spin (nsync_once *once, void (*f) (void)) {
|
||||
uint32_t o;
|
||||
IGNORE_RACES_START ();
|
||||
o = ATM_LOAD_ACQ (once);
|
||||
if (o != 2) {
|
||||
nsync_run_once_impl (once, NULL, f, NULL, NULL);
|
||||
}
|
||||
IGNORE_RACES_END ();
|
||||
}
|
||||
|
||||
void nsync_run_once_arg_spin (nsync_once *once, void (*farg) (void *arg), void *arg) {
|
||||
uint32_t o;
|
||||
IGNORE_RACES_START ();
|
||||
o = ATM_LOAD_ACQ (once);
|
||||
if (o != 2) {
|
||||
nsync_run_once_impl (once, NULL, NULL, farg, arg);
|
||||
}
|
||||
IGNORE_RACES_END ();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue