Clean up some sleep code

This commit is contained in:
Justine Tunney 2022-10-08 02:40:44 -07:00
parent 9849b4c7ba
commit 672ccda37c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
35 changed files with 310 additions and 598 deletions

View file

@ -1,5 +1,5 @@
#ifndef NSYNC_TESTING_ARRAY_H_
#define NSYNC_TESTING_ARRAY_H_
#ifndef NSYNC_ARRAY_H_
#define NSYNC_ARRAY_H_
/* clang-format off */
/* Return the number of elements in a C array a.
@ -58,4 +58,4 @@ struct a_hdr_ {
(a)->a_ = NULL; (a)->h_.max_ = 0; (a)->h_.len_ = 0; \
} while (0)
#endif /*NSYNC_TESTING_ARRAY_H_*/
#endif /*NSYNC_ARRAY_H_*/

View file

@ -41,3 +41,11 @@ nsync_time_ms:
nsync_time_us:
jmp _timespec_frommicros
.endfn nsync_time_us,globl
nsync_time_sleep:
jmp _timespec_sleep
.endfn nsync_time_us,globl
nsync_time_sleep_until:
jmp _timespec_sleep_until
.endfn nsync_time_us,globl

View file

@ -17,7 +17,9 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
@ -33,8 +35,10 @@
#include "libc/sysv/consts/timer.h"
#include "libc/thread/freebsd.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/common.internal.h"
#include "third_party/nsync/mu_semaphore.internal.h"
#include "third_party/nsync/time.h"
// clang-format off
/* futex() polyfill w/ sched_yield() fallback */
@ -51,15 +55,15 @@ bool FUTEX_TIMEOUT_IS_ABSOLUTE;
__attribute__((__constructor__)) static void nsync_futex_init_ (void) {
int x = 0;
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
FUTEX_WAIT_ = FUTEX_WAIT;
if (IsWindows ()) {
FUTEX_IS_SUPPORTED = true;
FUTEX_WAIT_ = FUTEX_WAIT;
return;
}
if (IsFreebsd ()) {
FUTEX_IS_SUPPORTED = true;
FUTEX_WAIT_ = FUTEX_WAIT;
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
return;
@ -105,44 +109,41 @@ __attribute__((__constructor__)) static void nsync_futex_init_ (void) {
}
static int nsync_futex_polyfill_ (int *p, int expect, struct timespec *timeout) {
int rc;
atomic_int *w;
int64_t max, nanos;
int64_t nanos, maxnanos;
nsync_atomic_uint32_ *w;
struct timespec ts, deadline;
w = (atomic_int *)p;
if (atomic_load_explicit (p, memory_order_relaxed) != expect) {
w = (nsync_atomic_uint32_ *)p;
if (ATM_LOAD (p) != expect) {
return -EAGAIN;
}
ts = _timespec_real ();
ts = nsync_time_now ();
if (!timeout) {
deadline = nsync_time_no_deadline;
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
deadline = *timeout;
} else {
deadline = _timespec_add (ts, *timeout);
deadline = nsync_time_add (ts, *timeout);
}
nanos = 100;
max = __SIG_POLLING_INTERVAL_MS * 1000L * 1000;
while (_timespec_gt (deadline, ts)) {
if (atomic_load_explicit (p, memory_order_relaxed) != expect) {
maxnanos = __SIG_POLLING_INTERVAL_MS * 1000L * 1000;
while (nsync_time_cmp (deadline, ts) > 0) {
if (ATM_LOAD (p) != expect) {
return 0;
}
ts = _timespec_add (ts, _timespec_fromnanos (nanos));
if (_timespec_gt (ts, deadline)) {
ts = nsync_time_add (ts, _timespec_fromnanos (nanos));
if (nsync_time_cmp (ts, deadline) > 0) {
ts = deadline;
}
rc = clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, &ts, 0);
if (rc) {
ASSERT (rc == EINTR);
if (nsync_time_sleep_until (ts)) {
return -EINTR;
}
if (nanos < max) {
if (nanos < maxnanos) {
nanos <<= 1;
if (nanos > max) {
nanos = max;
if (nanos > maxnanos) {
nanos = maxnanos;
}
}
}
@ -154,38 +155,42 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
uint32_t ms;
int rc, op, fop;
if (!FUTEX_IS_SUPPORTED) {
return nsync_futex_polyfill_ (p, expect, timeout);
}
op = FUTEX_WAIT_;
if (pshare == PTHREAD_PROCESS_PRIVATE) {
op |= FUTEX_PRIVATE_FLAG_;
}
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
// Windows 8 futexes don't support multiple processes :(
if (pshare) {
return nsync_futex_polyfill_ (p, expect, timeout);
}
if (timeout) {
ms = _timespec_tomillis (*timeout);
if (FUTEX_IS_SUPPORTED) {
if (IsWindows ()) {
// Windows 8 futexes don't support multiple processes :(
if (pshare) {
goto Polyfill;
}
if (timeout) {
ms = _timespec_tomillis (*timeout);
} else {
ms = -1;
}
if (WaitOnAddress (p, &expect, sizeof(int), ms)) {
rc = 0;
} else {
rc = -GetLastError ();
}
} else if (IsFreebsd ()) {
rc = sys_umtx_timedwait_uint (
p, expect, pshare, timeout);
} else {
ms = -1;
rc = _futex (p, op, expect, timeout, 0,
FUTEX_WAIT_BITS_);
if (IsOpenbsd() && rc > 0) {
rc = -rc;
}
}
if (WaitOnAddress (p, &expect, sizeof(int), ms)) {
rc = 0;
} else {
rc = -GetLastError ();
}
} else if (IsFreebsd ()) {
rc = sys_umtx_timedwait_uint (p, expect, pshare, timeout);
} else {
rc = _futex (p, op, expect, timeout, 0, FUTEX_WAIT_BITS_);
if (IsOpenbsd() && rc > 0) {
// [jart] openbsd does this without setting carry flag
rc = -rc;
}
Polyfill:
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
rc = nsync_futex_polyfill_ (p, expect, timeout);
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
}
STRACE ("futex(%t, %s, %d, %s) → %s",
@ -202,40 +207,40 @@ int nsync_futex_wake_ (int *p, int count, char pshare) {
ASSERT (count == 1 || count == INT_MAX);
if (!FUTEX_IS_SUPPORTED) {
nsync_yield_ ();
return 0;
}
op = FUTEX_WAKE;
if (pshare == PTHREAD_PROCESS_PRIVATE) {
op |= FUTEX_PRIVATE_FLAG_;
}
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
if (pshare) {
nsync_yield_ ();
return 0;
}
if (count == 1) {
WakeByAddressSingle (p);
if (FUTEX_IS_SUPPORTED) {
if (IsWindows ()) {
if (pshare) {
goto Polyfill;
}
if (count == 1) {
WakeByAddressSingle (p);
} else {
WakeByAddressAll (p);
}
rc = 0;
} else if (IsFreebsd ()) {
if (pshare) {
fop = UMTX_OP_WAKE;
} else {
fop = UMTX_OP_WAKE_PRIVATE;
}
rc = sys_umtx_op (p, fop, count, 0, 0);
} else {
WakeByAddressAll (p);
rc = wake (p, op, count);
}
rc = 0;
} else if (IsFreebsd ()) {
if (pshare) {
fop = UMTX_OP_WAKE;
} else {
fop = UMTX_OP_WAKE_PRIVATE;
}
rc = sys_umtx_op (p, fop, count, 0, 0);
} else {
rc = wake (p, op, count);
Polyfill:
sched_yield ();
rc = 0;
}
STRACE ("futex(%t, %s, %d) → %s", p,
DescribeFutexOp(op),
STRACE ("futex(%t, %s, %d) → %s",
p, DescribeFutexOp(op),
count, DescribeErrnoResult(rc));
return rc;

View file

@ -17,7 +17,7 @@
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/nsync/testing/array.h"
#include "third_party/nsync/array.internal.h"
// clang-format off
void a_ensure_ (void *v, int delta, int sz) {

View file

@ -1,56 +1,128 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
Copyright 2016 Google Inc.
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
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 "libc/dce.h"
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/futex.internal.h"
#include "third_party/nsync/mu_semaphore.h"
#include "third_party/nsync/mu_semaphore.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
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Check that atomic operations on nsync_atomic_uint32_ can be applied to int. */
static const int assert_int_size = 1 /
(sizeof (assert_int_size) == sizeof (uint32_t) &&
sizeof (nsync_atomic_uint32_) == sizeof (uint32_t));
struct futex {
int i; /* lo half=count; hi half=waiter count */
};
static nsync_semaphore *sem_big_enough_for_futex = (nsync_semaphore *) (uintptr_t)(1 /
(sizeof (struct futex) <= sizeof (*sem_big_enough_for_futex)));
/* Initialize *s; the initial value is 0. */
void nsync_mu_semaphore_init (nsync_semaphore *s) {
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_init_futex (s);
else
nsync_mu_semaphore_init_win32 (s);
struct futex *f = (struct futex *) s;
f->i = 0;
}
/* Wait until the count of *s exceeds 0, and decrement it. */
void nsync_mu_semaphore_p (nsync_semaphore *s) {
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_p_futex (s);
else
nsync_mu_semaphore_p_win32 (s);
struct futex *f = (struct futex *) s;
int i;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, NULL);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -EWOULDBLOCK);
}
} while (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i-1));
}
/* Wait until one of:
the count of *s is non-zero, in which case decrement *s and return 0;
or abs_deadline expires, in which case return ETIMEDOUT. */
int nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadline) {
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
return nsync_mu_semaphore_p_with_deadline_futex (s, abs_deadline);
else
return nsync_mu_semaphore_p_with_deadline_win32 (s, abs_deadline);
struct futex *f = (struct futex *)s;
int i;
int result = 0;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result;
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));
if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline);
} else {
nsync_time now;
now = nsync_time_now ();
if (nsync_time_cmp (now, abs_deadline) > 0) {
ts_buf.tv_sec = 0;
ts_buf.tv_nsec = 0;
} else {
nsync_time rel_deadline;
rel_deadline = nsync_time_sub (abs_deadline, now);
ts_buf.tv_sec = NSYNC_TIME_SEC (rel_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (rel_deadline);
}
}
ts = &ts_buf;
}
futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, ts);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -ETIMEDOUT ||
futex_result == -EWOULDBLOCK);
/* Some systems don't wait as long as they are told. */
if (futex_result == -ETIMEDOUT &&
nsync_time_cmp (abs_deadline, nsync_time_now ()) <= 0) {
result = ETIMEDOUT;
}
}
} while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i - 1)));
return (result);
}
/* Ensure that the count of *s is at least 1. */
void nsync_mu_semaphore_v (nsync_semaphore *s) {
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_v_futex (s);
else
nsync_mu_semaphore_v_win32 (s);
struct futex *f = (struct futex *) s;
uint32_t old_value;
do {
old_value = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
} while (!ATM_CAS_REL ((nsync_atomic_uint32_ *) &f->i, old_value, old_value+1));
ASSERT (nsync_futex_wake_ (&f->i, 1, PTHREAD_PROCESS_PRIVATE) >= 0);
}

25
third_party/nsync/mu_semaphore.internal.h vendored Normal file → Executable file
View file

@ -1,25 +0,0 @@
#ifndef NSYNC_MU_SEMAPHORE_INTERNAL_H_
#define NSYNC_MU_SEMAPHORE_INTERNAL_H_
#include "third_party/nsync/mu_semaphore.h"
#include "third_party/nsync/time.h"
#ifndef NSYNC_FUTEX_WIN32
#define NSYNC_FUTEX_WIN32 1
#endif
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void nsync_mu_semaphore_init_futex(nsync_semaphore *);
void nsync_mu_semaphore_p_futex(nsync_semaphore *);
int nsync_mu_semaphore_p_with_deadline_futex(nsync_semaphore *, nsync_time);
void nsync_mu_semaphore_v_futex(nsync_semaphore *);
void nsync_mu_semaphore_init_win32(nsync_semaphore *);
void nsync_mu_semaphore_p_win32(nsync_semaphore *);
int nsync_mu_semaphore_p_with_deadline_win32(nsync_semaphore *, nsync_time);
void nsync_mu_semaphore_v_win32(nsync_semaphore *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* NSYNC_MU_SEMAPHORE_INTERNAL_H_ */

View file

@ -1,129 +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 "libc/assert.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/futex.internal.h"
#include "third_party/nsync/mu_semaphore.h"
#include "third_party/nsync/mu_semaphore.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
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Check that atomic operations on nsync_atomic_uint32_ can be applied to int. */
static const int assert_int_size = 1 /
(sizeof (assert_int_size) == sizeof (uint32_t) &&
sizeof (nsync_atomic_uint32_) == sizeof (uint32_t));
struct futex {
int i; /* lo half=count; hi half=waiter count */
};
static nsync_semaphore *sem_big_enough_for_futex = (nsync_semaphore *) (uintptr_t)(1 /
(sizeof (struct futex) <= sizeof (*sem_big_enough_for_futex)));
/* Initialize *s; the initial value is 0. */
void nsync_mu_semaphore_init_futex (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
f->i = 0;
}
/* Wait until the count of *s exceeds 0, and decrement it. */
void nsync_mu_semaphore_p_futex (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
int i;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, NULL);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -EWOULDBLOCK);
}
} while (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i-1));
}
/* Wait until one of:
the count of *s is non-zero, in which case decrement *s and return 0;
or abs_deadline expires, in which case return ETIMEDOUT. */
int nsync_mu_semaphore_p_with_deadline_futex (nsync_semaphore *s, nsync_time abs_deadline) {
struct futex *f = (struct futex *)s;
int i;
int result = 0;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result;
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));
if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline);
} else {
nsync_time now;
now = nsync_time_now ();
if (nsync_time_cmp (now, abs_deadline) > 0) {
ts_buf.tv_sec = 0;
ts_buf.tv_nsec = 0;
} else {
nsync_time rel_deadline;
rel_deadline = nsync_time_sub (abs_deadline, now);
ts_buf.tv_sec = NSYNC_TIME_SEC (rel_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (rel_deadline);
}
}
ts = &ts_buf;
}
futex_result = nsync_futex_wait_ (&f->i, i, PTHREAD_PROCESS_PRIVATE, ts);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -ETIMEDOUT ||
futex_result == -EWOULDBLOCK);
/* Some systems don't wait as long as they are told. */
if (futex_result == -ETIMEDOUT &&
nsync_time_cmp (abs_deadline, nsync_time_now ()) <= 0) {
result = ETIMEDOUT;
}
}
} while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i - 1)));
return (result);
}
/* Ensure that the count of *s is at least 1. */
void nsync_mu_semaphore_v_futex (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
uint32_t old_value;
do {
old_value = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
} while (!ATM_CAS_REL ((nsync_atomic_uint32_ *) &f->i, old_value, old_value+1));
ASSERT (nsync_futex_wake_ (&f->i, 1, PTHREAD_PROCESS_PRIVATE) >= 0);
}

View file

@ -1,85 +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 "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/synchronization.h"
#include "libc/runtime/runtime.h"
#include "third_party/nsync/mu_semaphore.h"
#include "third_party/nsync/mu_semaphore.internal.h"
#include "third_party/nsync/time.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 *s; the initial value is 0. */
void nsync_mu_semaphore_init_win32 (nsync_semaphore *s) {
int64_t *h = (int64_t *) s;
*h = CreateSemaphore (&kNtIsInheritable, 0, 1, NULL);
if (!*h) notpossible;
}
/* Wait until the count of *s exceeds 0, and decrement it. */
void nsync_mu_semaphore_p_win32 (nsync_semaphore *s) {
int64_t *h = (int64_t *) s;
WaitForSingleObject (*h, -1u);
}
/* Wait until one of:
the count of *s is non-zero, in which case decrement *s and return 0;
or abs_deadline expires, in which case return ETIMEDOUT. */
int nsync_mu_semaphore_p_with_deadline_win32 (nsync_semaphore *s, nsync_time abs_deadline) {
int64_t *h = (int64_t *) s;
int result;
if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) == 0) {
result = WaitForSingleObject (*h, -1u);
} else {
nsync_time now;
now = nsync_time_now ();
do {
if (nsync_time_cmp (abs_deadline, now) <= 0) {
result = WaitForSingleObject (*h, 0);
} else {
nsync_time delay;
delay = nsync_time_sub (abs_deadline, now);
if (NSYNC_TIME_SEC (delay) > 1000*1000) {
result = WaitForSingleObject (*h, 1000*1000);
} else {
result = WaitForSingleObject (*h,
(unsigned) (NSYNC_TIME_SEC (delay) * 1000 +
(NSYNC_TIME_NSEC (delay) + 999999) / (1000 * 1000)));
}
}
if (result == kNtWaitTimeout) {
now = nsync_time_now ();
}
} while (result == kNtWaitTimeout && /* Windows generates early wakeups. */
nsync_time_cmp (abs_deadline, now) > 0);
}
return (result == kNtWaitTimeout ? ETIMEDOUT : 0);
}
/* Ensure that the count of *s is at least 1. */
void nsync_mu_semaphore_v_win32 (nsync_semaphore *s) {
int64_t *h = (int64_t *) s;
ReleaseSemaphore(*h, 1, NULL);
}

View file

@ -17,11 +17,11 @@
*/
#include "libc/fmt/fmt.h"
#include "libc/str/str.h"
#include "third_party/nsync/array.internal.h"
#include "third_party/nsync/cv.h"
#include "third_party/nsync/heap.internal.h"
#include "third_party/nsync/mu.h"
#include "third_party/nsync/testing/array.h"
#include "third_party/nsync/testing/closure.h"
#include "third_party/nsync/testing/heap.h"
#include "third_party/nsync/testing/smprintf.h"
#include "third_party/nsync/testing/testing.h"
#include "third_party/nsync/testing/time_extra.h"

View file

@ -18,8 +18,8 @@
#include "libc/fmt/fmt.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/array.h"
#include "third_party/nsync/testing/smprintf.h"
#include "third_party/nsync/testing/testing.h"
// clang-format off

View file

@ -17,11 +17,11 @@
*/
#include "libc/fmt/fmt.h"
#include "libc/str/str.h"
#include "third_party/nsync/array.internal.h"
#include "third_party/nsync/heap.internal.h"
#include "third_party/nsync/mu.h"
#include "third_party/nsync/mu_wait.h"
#include "third_party/nsync/testing/array.h"
#include "third_party/nsync/testing/closure.h"
#include "third_party/nsync/testing/heap.h"
#include "third_party/nsync/testing/smprintf.h"
#include "third_party/nsync/testing/testing.h"
#include "third_party/nsync/testing/time_extra.h"

View file

@ -12,8 +12,8 @@ THIRD_PARTY_NSYNC_TESTING_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_NSYNC_TEST
THIRD_PARTY_NSYNC_TESTING_OBJS = $(THIRD_PARTY_NSYNC_TESTING_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_NSYNC_TESTING_COMS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com)
THIRD_PARTY_NSYNC_TESTING_BINS = $(THIRD_PARTY_NSYNC_TESTING_COMS) $(THIRD_PARTY_NSYNC_TESTING_COMS:%=%.dbg)
# THIRD_PARTY_NSYNC_TESTING_TESTS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
# THIRD_PARTY_NSYNC_TESTING_CHECKS = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
THIRD_PARTY_NSYNC_TESTING_TESTS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
THIRD_PARTY_NSYNC_TESTING_CHECKS_ = $(THIRD_PARTY_NSYNC_TESTING_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
THIRD_PARTY_NSYNC_TESTING_DIRECTDEPS = \
LIBC_CALLS \
@ -57,10 +57,10 @@ o/$(MODE)/third_party/nsync/testing/mu_test.com.runs: private QUOTA = -C64
.PHONY: o/$(MODE)/third_party/nsync/testing
o/$(MODE)/third_party/nsync/testing: \
$(THIRD_PARTY_NSYNC_TESTING_CHECKS) \
$(THIRD_PARTY_NSYNC_TESTING_BINS)
$(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \
$(THIRD_PARTY_NSYNC_TESTING_BINS_)
.PHONY: o/$(MODE)/third_party/nsync/test
o/$(MODE)/third_party/nsync/test: \
$(THIRD_PARTY_NSYNC_TESTING_CHECKS) \
$(THIRD_PARTY_NSYNC_TESTING_TESTS)
$(THIRD_PARTY_NSYNC_TESTING_CHECKS_) \
$(THIRD_PARTY_NSYNC_TESTING_TESTS_)

View file

@ -41,20 +41,6 @@ char *nsync_time_str (nsync_time t, int decimals) {
return (smprintf ("%.*f%s", decimals, s/scale[i].multiplier, scale[i].suffix));
}
int nsync_time_sleep_until (nsync_time abs_deadline) {
int result = 0;
nsync_time now;
now = nsync_time_now ();
if (nsync_time_cmp (abs_deadline, now) > 0) {
nsync_time remaining;
remaining = nsync_time_sleep (nsync_time_sub (abs_deadline, now));
if (nsync_time_cmp (remaining, nsync_time_zero) > 0) {
result = EINTR;
}
}
return (result);
}
double nsync_time_to_dbl (nsync_time t) {
return (((double) NSYNC_TIME_SEC (t)) + ((double) NSYNC_TIME_NSEC (t) * 1e-9));
}

View file

@ -6,10 +6,6 @@
"decimals" decimal places. */
char *nsync_time_str(nsync_time t, int decimals);
/* Sleep until the specified time. Returns 0 on success, and EINTR
if the call was interrupted. */
int nsync_time_sleep_until(nsync_time abs_deadline);
/* Return t as a double. */
double nsync_time_to_dbl(nsync_time t);

View file

@ -16,9 +16,9 @@
limitations under the License.
*/
#include "libc/str/str.h"
#include "third_party/nsync/array.internal.h"
#include "third_party/nsync/counter.h"
#include "third_party/nsync/note.h"
#include "third_party/nsync/testing/array.h"
#include "third_party/nsync/testing/closure.h"
#include "third_party/nsync/testing/smprintf.h"
#include "third_party/nsync/testing/testing.h"

View file

@ -1,54 +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 "libc/calls/struct/timespec.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "third_party/nsync/time.h"
asm(".ident\t\"\\n\\n\
*NSYNC (Apache 2.0)\\n\
Copyright 2016 Google, Inc.\\n\
https://github.com/google/nsync\"");
// clang-format off
#define NSYNC_NS_IN_S_ (1000 * 1000 * 1000)
/* Return the maximum t, assuming it's an integral
type, and the representation is not too strange. */
#define MAX_INT_TYPE(t) (((t)~(t)0) > 1? /*is t unsigned?*/ \
(t)~(t)0 : /*unsigned*/ \
(t) ((((uintmax_t)1) << (sizeof (t) * CHAR_BIT - 1)) - 1)) /*signed*/
const nsync_time nsync_time_no_deadline =
NSYNC_TIME_STATIC_INIT (MAX_INT_TYPE (int64_t), NSYNC_NS_IN_S_ - 1);
const nsync_time nsync_time_zero = NSYNC_TIME_STATIC_INIT (0, 0);
nsync_time nsync_time_sleep (nsync_time delay) {
struct timespec ts;
struct timespec remain;
memset (&ts, 0, sizeof (ts));
ts.tv_sec = NSYNC_TIME_SEC (delay);
ts.tv_nsec = NSYNC_TIME_NSEC (delay);
if (nanosleep (&ts, &remain) == 0) {
/* nanosleep() is not required to fill in "remain"
if it returns 0. */
memset (&remain, 0, sizeof (remain));
}
return (remain);
}

View file

@ -17,17 +17,21 @@ COSMOPOLITAN_C_START_
typedef struct timespec nsync_time;
/* A deadline infinitely far in the future. */
extern const nsync_time nsync_time_no_deadline;
#define nsync_time_no_deadline _timespec_max
/* The zero delay, or an expired deadline. */
extern const nsync_time nsync_time_zero;
#define nsync_time_zero _timespec_zero
/* Return the current time since the epoch. */
#define nsync_time_now() _timespec_real()
/* Sleep for the specified delay. Returns the unslept time which may be
non-zero if the call was interrupted. */
nsync_time nsync_time_sleep(nsync_time delay);
#define nsync_time_sleep(a) _timespec_sleep(a)
/* Sleep until the specified time. Returns 0 on success, and EINTR
if the call was interrupted. */
#define nsync_time_sleep_until(a) _timespec_sleep_until(a)
/* Return a+b */
#define nsync_time_add(a, b) _timespec_add(a, b)
@ -44,6 +48,9 @@ nsync_time nsync_time_sleep(nsync_time delay);
/* Return the specified number of microseconds as a time. */
#define nsync_time_us(a) _timespec_frommicros(a)
/* Return the specified number of nanoseconds as a time. */
#define nsync_time_ns(a) _timespec_fromnanos(a)
/* Return an nsync_time constructed from second and nanosecond
components */
#define nsync_time_s_ns(s, ns) ((nsync_time){(int64_t)(s), (unsigned)(ns)})