Change support vector to Windows 8+

Doing this makes binaries tinier, since we don't need to have all the
extra code for supporting a 32-bit address space. It also benefits us
because we're able to use WIN32 futexes, which makes locking simpler.

b69f3d2488 is what officially ended our
Windows 7 support. This change is merely a formalization. You can use
old versions of Cosmo now and forevermore if you need Windows 7 since
our repository is hermetic and vendors all its dependencies.

Won't fix #617
This commit is contained in:
Justine Tunney 2022-09-15 03:49:34 -07:00
parent 6c90f830d9
commit 134ffee519
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
25 changed files with 296 additions and 167 deletions

View file

@ -325,6 +325,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_NT_USER32 \
LIBC_NT_NTDLL \
LIBC_NT_ADVAPI32 \
LIBC_NT_SYNCHRONIZATION \
LIBC_FMT \
THIRD_PARTY_COMPILER_RT \
LIBC_TINYMATH \

View file

@ -245,11 +245,11 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
| :--- | ---: | ---: |
| AMD | K8 Venus | 2005 |
| Intel | Core | 2006 |
| Windows | Vista | 2006 |
| Linux | 2.6.18 | 2007 |
| Windows | 8 | 2012 |
| Mac OS X | 15.6 | 2018 |
| FreeBSD | 13 | 2020 |
| OpenBSD | 6.4 | 2018 |
| FreeBSD | 13 | 2020 |
| NetBSD | 9.2 | 2021 |
## Special Thanks

View file

@ -32,23 +32,23 @@
// @see ape/ape.lds
// @see winimp
.macro .imp dll:req fn:req actual:req hint
.dll \dll
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
.dll "\dll"
.section ".piro.data.sort.iat.2.\dll\().2.\actual","aw",@progbits
.type \fn,@object
.align __SIZEOF_POINTER__
\fn: .quad RVA((\dll\().\actual))
\fn: .quad RVA(("\dll\().\actual"))
.size \fn,.-\fn
.globl \fn
.hidden \fn
.previous
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
.Lidata.ilt.\dll\().\actual:
.quad RVA((\dll\().\actual))
.type .Lidata.ilt.\dll\().\actual,@object
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
.section ".idata.ro.ilt.\dll\().2.\actual","a",@progbits
".Lidata.ilt.\dll\().\actual":
.quad RVA("\dll\().\actual")
.type ".Lidata.ilt.\dll\().\actual",@object
.size ".Lidata.ilt.\dll\().\actual",.-".Lidata.ilt.\dll\().\actual"
.previous
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
\dll\().\actual:
.section ".idata.ro.hnt.\dll\().2.\actual","a",@progbits
"\dll\().\actual":
.ifnb \hint # hint i.e. guess function ordinal
.short \hint
.else
@ -56,55 +56,55 @@
.endif
.asciz "\actual"
.align 2 # documented requirement
.globl \dll\().\actual
.hidden \dll\().\actual
.type \dll\().\actual,@object
.size \dll\().\actual,.-\dll\().\actual
.globl "\dll\().\actual"
.hidden "\dll\().\actual"
.type "\dll\().\actual",@object
.size "\dll\().\actual",.-"\dll\().\actual"
.previous
.endm
// Defines DLL import.
// @note this is an implementation detail of .imp
.macro .dll name:req
.section .idata.ro.idt.2.\name,"aG",@progbits,\name,comdat
.equ .Lidata.idt.\name,.
.long RVA(idata.ilt.\name) # ImportLookupTable
.section ".idata.ro.idt.2.\name","aG",@progbits,"\name",comdat
.equ ".Lidata.idt.\name",.
.long RVA("idata.ilt.\name") # ImportLookupTable
.long 0 # TimeDateStamp
.long 0 # ForwarderChain
.long RVA(.Lidata.str.\name) # DllNameRva
.long RVA(idata.iat.\name) # ImportAddressTable
.type .Lidata.idt.\name,@object
.size .Lidata.idt.\name,.-.Lidata.idt.\name
.long RVA(".Lidata.str.\name") # DllNameRva
.long RVA("idata.iat.\name") # ImportAddressTable
.type ".Lidata.idt.\name",@object
.size ".Lidata.idt.\name",.-".Lidata.idt.\name"
.previous
.section .idata.ro.ilt.\name\().1,"aG",@progbits,\name,comdat
.section ".idata.ro.ilt.\name\().1","aG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.ilt.\name,@object
idata.ilt.\name:
.type "idata.ilt.\name",@object
"idata.ilt.\name":
.previous/*
...
decentralized content
...
*/.section .idata.ro.ilt.\name\().3,"aG",@progbits,\name,comdat
*/.section ".idata.ro.ilt.\name\().3","aG",@progbits,"\name",comdat
.quad 0
.previous
.section .idata.ro.hnt.\name\().1,"aG",@progbits,\name,comdat
.section ".idata.ro.hnt.\name\().1","aG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.hnt.\name,@object
.equ idata.hnt.\name,.
.type "idata.hnt.\name",@object
.equ "idata.hnt.\name",.
.previous
.section .piro.data.sort.iat.2.\name\().1,"awG",@progbits,\name,comdat
.section ".piro.data.sort.iat.2.\name\().1","awG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.iat.\name,@object
idata.iat.\name:
.type "idata.iat.\name",@object
"idata.iat.\name":
.previous/*
...
decentralized content
...
*/.section .piro.data.sort.iat.2.\name\().3,"awG",@progbits,\name,comdat
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
.quad 0
.previous
.section .rodata.str1.1,"aSM",@progbits,1
.Lidata.str.\name:
".Lidata.str.\name":
.asciz "\name\().dll"
.previous
.endm

View file

@ -22,6 +22,7 @@
#include "libc/calls/weirdtypes.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/nt/dll.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/nt/systeminfo.h"
@ -61,18 +62,6 @@ static unsigned GetCpuCountBsd(void) {
}
}
static textwindows unsigned GetCpuCountWindows(void) {
struct NtSystemInfo si;
uint32_t (*f)(uint16_t);
if ((f = GetProcAddress(GetModuleHandle("KERNEL32"),
"GetMaximumProcessorCount"))) {
return f(ALL_PROCESSOR_GROUPS);
} else {
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
}
static unsigned GetCpuCountImpl(void) {
if (!IsWindows()) {
if (!IsBsd()) {
@ -81,7 +70,7 @@ static unsigned GetCpuCountImpl(void) {
return GetCpuCountBsd();
}
} else {
return GetCpuCountWindows();
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
}
}

0
libc/intrin/intrin.h Executable file
View file

View file

@ -0,0 +1,12 @@
.include "o/libc/nt/codegen.inc"
.imp API-MS-Win-Core-Synch-l1-2-0,__imp_WaitOnAddress,WaitOnAddress,111
.text.windows
WaitOnAddress:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_WaitOnAddress(%rip),%rax
jmp __sysv2nt
.endfn WaitOnAddress,globl
.previous

View file

@ -0,0 +1,15 @@
.include "o/libc/nt/codegen.inc"
.imp API-MS-Win-Core-Synch-l1-2-0,__imp_WakeByAddressAll,WakeByAddressAll,113
.text.windows
WakeByAddressAll:
push %rbp
mov %rsp,%rbp
.profilable
mov %rdi,%rcx
sub $32,%rsp
call *__imp_WakeByAddressAll(%rip)
leave
ret
.endfn WakeByAddressAll,globl
.previous

View file

@ -0,0 +1,15 @@
.include "o/libc/nt/codegen.inc"
.imp API-MS-Win-Core-Synch-l1-2-0,__imp_WakeByAddressSingle,WakeByAddressSingle,116
.text.windows
WakeByAddressSingle:
push %rbp
mov %rsp,%rbp
.profilable
mov %rdi,%rcx
sub $32,%rsp
call *__imp_WakeByAddressSingle(%rip)
leave
ret
.endfn WakeByAddressSingle,globl
.previous

View file

@ -992,7 +992,7 @@
#define kNtErrorInvalidKeyboardHandle 1457
#define kNtErrorHookTypeNotAllowed 1458
#define kNtErrorRequiresInteractiveWindowstation 1459
#define kNtErrorTimeout 1460
#define kNtErrorTimeout 1460 /* ETIMEDOUT */
#define kNtErrorInvalidMonitorHandle 1461
#define kNtErrorIncorrectSize 1462
#define kNtErrorSymlinkClassDisabled 1463

View file

@ -3554,6 +3554,13 @@ imp 'InetIsOffline' InetIsOffline url 106
imp 'MIMEAssociationDialog' MIMEAssociationDialogW url 108
imp 'MailToProtocolHandler' MailToProtocolHandler url 109
# API-MS-Win-Core-Synch-l1-2-0.dll (Windows 8+)
#
# Name Actual DLL Hint Arity
imp 'WaitOnAddress' WaitOnAddress API-MS-Win-Core-Synch-l1-2-0 111 4
imp 'WakeByAddressAll' WakeByAddressAll API-MS-Win-Core-Synch-l1-2-0 113 1
imp 'WakeByAddressSingle' WakeByAddressSingle API-MS-Win-Core-Synch-l1-2-0 116 1
# NTDLL.DLL
# BEYOND THE PALE
#

View file

@ -167,6 +167,27 @@ $(LIBC_NT_URL_A).pkg: \
#───────────────────────────────────────────────────────────────────────────────
LIBC_NT_ARTIFACTS += LIBC_NT_SYNCHRONIZATION_A
LIBC_NT_SYNCHRONIZATION = $(LIBC_NT_SYNCHRONIZATION_A_DEPS) $(LIBC_NT_SYNCHRONIZATION_A)
LIBC_NT_SYNCHRONIZATION_A = o/$(MODE)/libc/nt/synchronization.a
LIBC_NT_SYNCHRONIZATION_A_SRCS := $(wildcard libc/nt/API-MS-Win-Core-Synch-l1-2-0/*.s)
LIBC_NT_SYNCHRONIZATION_A_OBJS = $(LIBC_NT_SYNCHRONIZATION_A_SRCS:%.s=o/$(MODE)/%.o)
LIBC_NT_SYNCHRONIZATION_A_CHECKS = $(LIBC_NT_SYNCHRONIZATION_A).pkg
LIBC_NT_SYNCHRONIZATION_A_DIRECTDEPS = LIBC_NT_KERNEL32
LIBC_NT_SYNCHRONIZATION_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_NT_SYNCHRONIZATION_A_DIRECTDEPS),$($(x))))
$(LIBC_NT_SYNCHRONIZATION_A): \
libc/nt/API-MS-Win-Core-Synch-l1-2-0/ \
$(LIBC_NT_SYNCHRONIZATION_A).pkg \
$(LIBC_NT_SYNCHRONIZATION_A_OBJS)
$(LIBC_NT_SYNCHRONIZATION_A).pkg: \
$(LIBC_NT_SYNCHRONIZATION_A_OBJS) \
$(foreach x,$(LIBC_NT_SYNCHRONIZATION_A_DIRECTDEPS),$($(x)_A).pkg)
#───────────────────────────────────────────────────────────────────────────────
LIBC_NT_ARTIFACTS += LIBC_NT_USER32_A
LIBC_NT_USER32 = $(LIBC_NT_USER32_A_DEPS) $(LIBC_NT_USER32_A)
LIBC_NT_USER32_A = o/$(MODE)/libc/nt/user32.a

View file

@ -54,6 +54,11 @@ typedef void (*NtTimerapcroutine)(void *lpArgToCompletionRoutine,
typedef void (*NtWaitOrTimerCallback)(void *lpParameter,
bool32 TimerOrWaitFired);
void WakeByAddressAll(void *Address);
void WakeByAddressSingle(void *Address);
bool32 WaitOnAddress(volatile void *Address, void *CompareAddress,
size_t AddressSize, uint32_t opt_dwMilliseconds);
void Sleep(uint32_t dwMilliseconds);
uint32_t SleepEx(uint32_t dwMilliseconds, bool32 bAlertable);

View file

@ -1,83 +0,0 @@
# -*- conf -*-
# Cosmopolitan Libc Legacy Memory Plan
00000000-0000001f 2048kb guard
00000020-0000003f 2048kb loader
00000040-000000ff 12mb image
00000100-000003ff 48mb free
00000400-000007ff 64mb free
00000800-00000bff 64mb free
00000c00-00000fff 64mb free
00001000-000013ff 64mb automap
00001400-000017ff 64mb automap
00001800-00001bff 64mb automap
00001c00-00001fff 64mb automap
00002000-000023ff 64mb automap
00002400-000027ff 64mb automap
00002800-00002bff 64mb automap
00002c00-00002fff 64mb automap
00003000-000033ff 64mb automap
00003400-000037ff 64mb automap
00003800-00003bff 64mb automap
00003c00-00003fe7 63mb automap
00003fe4-00003ffb 1536kb memtrack
00003ffc-00003fff 256kb free
00004000-000043ff 64mb fixedmap
00004400-000047ff 64mb fixedmap
00004800-00004bff 64mb fixedmap
00004c00-00004fff 64mb fixedmap
00005000-000053ff 64mb fixedmap
00005400-000057ff 64mb fixedmap
00005800-00005bff 64mb fixedmap
00005c00-00005fff 64mb fixedmap
00006000-000063ff 64mb fixedmap
00006400-000067ff 64mb fixedmap
00006800-00006bff 64mb fixedmap
00006c00-00006fff 64mb fixedmap
00005000-000053ff 64mb arena
00005400-000057ff 64mb arena
00005800-00005bff 64mb arena
00005c00-00005fff 64mb arena
00006000-000063ff 64mb arena
00006400-000067ff 64mb arena
00006800-00006bff 64mb fds
00006c00-00006fff 64mb zipos
00007000-000073ff 64mb zipos
00007400-000077ff 64mb zipos
00007800-00007bff 64mb zipos
00007c00-00007ffd 64mb arena
00007ffe-00007fff 128kb free
00008000-000083ff 64mb free
00008400-000087ff 64mb free
00008800-00008bff 64mb free
00008c00-00008fff 64mb free
00009000-000093ff 64mb free
00009400-000097ff 64mb free
00009800-00009bff 64mb free
00009c00-00009fff 64mb free
0000a000-0000a3ff 64mb free
0000a400-0000a7ff 64mb free
0000a800-0000abff 64mb free
0000ac00-0000afff 64mb free
0000b000-0000b3ff 64mb free
0000b400-0000b7ff 64mb free
0000b800-0000bbff 64mb free
0000bc00-0000bfff 64mb free
0000c000-0000c3ff 64mb free
0000c400-0000c7ff 64mb free
0000c800-0000cbff 64mb free
0000cc00-0000cfff 64mb free
0000d000-0000d3ff 64mb free
0000d400-0000d7ff 64mb free
0000d800-0000dbff 64mb free
0000dc00-0000dfff 64mb free
0000e000-0000e3ff 64mb free
0000e400-0000e7ff 64mb free
0000e800-0000ebff 64mb free
0000ec00-0000efff 64mb free
0000f000-0000f3ff 64mb free
0000f400-0000f7ff 64mb free
0000f800-0000fbff 64mb free
0000fc00-0000fffb 64mb free
0000fffc-0000fffd 128kb winargs
0000fffe-0000ffff 128kb stack

View file

@ -94,7 +94,7 @@ syscon errno EISCONN 106 56 56 56 56 10056 # socket is connected
syscon errno ENOTCONN 107 57 57 57 57 10057 # socket is not connected; bsd consensus; WSAENOTCONN; raised by getpeername(2), recv(2), send(2), shutdown(2), ip(7)
syscon errno ESHUTDOWN 108 58 58 58 58 10058 # cannot send after transport endpoint shutdown; note that shutdown write is an EPIPE; bsd consensus; WSAESHUTDOWN
syscon errno ETOOMANYREFS 109 59 59 59 59 10059 # too many references: cannot splice; bsd consensus; WSAETOOMANYREFS; raised by sendmsg(2), unix(7)
syscon errno ETIMEDOUT 110 60 60 60 60 10060 # connection timed out; bsd consensus; WSAETIMEDOUT; raised by connect(2), futex(2), keyctl(2), tcp(7)
syscon errno ETIMEDOUT 110 60 60 60 60 1460 # connection timed out; kNtErrorTimeout; bsd consensus; WSAETIMEDOUT; raised by connect(2), futex(2), keyctl(2), tcp(7)
syscon errno ECONNREFUSED 111 61 61 61 61 10061 # bsd consensus; WSAECONNREFUSED; raised by connect(2), listen(2), recv(2), unix(7), udp(7)system-imposed limit on the number of threads was encountered.
syscon errno EHOSTDOWN 112 64 64 64 64 10064 # bsd consensus; WSAEHOSTDOWN; raised by accept(2)
syscon errno EHOSTUNREACH 113 65 65 65 65 10065 # bsd consensus; WSAEHOSTUNREACH; raised by accept(2), ip(7)
@ -1316,7 +1316,7 @@ syscon rusage RUSAGE_BOTH -2 99 99 99 99 99 # woop
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon futex FUTEX_WAIT 0 0 0 1 0 0
syscon futex FUTEX_WAKE 1 0 0 2 0 0
syscon futex FUTEX_WAKE 1 0 0 2 0 1
syscon futex FUTEX_REQUEUE 3 0 0 3 0 0
syscon futex FUTEX_PRIVATE_FLAG 128 0 0 128 0 0

View file

@ -1,3 +1,3 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ETIMEDOUT,110,60,60,60,60,10060
.syscon errno,ETIMEDOUT,110,60,60,60,60,1460
.yoink kDos2Errno.ETIMEDOUT

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon futex,FUTEX_WAKE,1,0,0,2,0,0
.syscon futex,FUTEX_WAKE,1,0,0,2,0,1

View file

@ -84,7 +84,7 @@ dir=libc/sysv/dos2errno
# dos WSAENOTCONN ENOTCONN # in consts.sh
# dos WSAESHUTDOWN ESHUTDOWN # in consts.sh
# dos WSAETOOMANYREFS ETOOMANYREFS # in consts.sh
# dos WSAETIMEDOUT ETIMEDOUT # in consts.sh
# dos kNtErrorTimeout ETIMEDOUT # in consts.sh
# dos WSAECONNREFUSED ECONNREFUSED # in consts.sh
# dos WSAEHOSTDOWN EHOSTDOWN # in consts.sh
# dos WSAEHOSTUNREACH EHOSTUNREACH # in consts.sh
@ -170,3 +170,4 @@ dos WSAEPROCLIM ENOMEM
dos WSANOTINITIALISED ENETDOWN
dos WSASYSNOTREADY ENETDOWN
dos WSAVERNOTSUPPORTED ENOSYS
dos WSAETIMEDOUT ETIMEDOUT

View file

@ -9,3 +9,4 @@
.type kDos2Errno.ETIMEDOUT,@object
kDos2Errno.ETIMEDOUT:
.e kNtErrorSemTimeout,ETIMEDOUT
.e WSAETIMEDOUT,ETIMEDOUT

View file

@ -0,0 +1,87 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
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.
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.
*/
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/intrin.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
/**
* @fileoverview Lock Waiter Scalability Test
*
* This test can be run as follows:
*
* make o//test/libc/intrin/lockscale_test.com.runs V=5 TESTARGS=-b
*
* It's intended to demonstrate the importance of futexes. On systems
* that don't have them, this test consumes orders of a magnitude more
* cpu time, because there's a lot of waiters and they need to wait a
* very long time.
*/
#define WAITERS 100
#define ITERATIONS 10000
atomic_int x;
pthread_t t[WAITERS];
pthread_mutex_t lock;
pthread_barrier_t barrier;
void Worker(void) {
pthread_mutex_lock(&lock);
pthread_barrier_wait(&barrier);
for (x = 0; x < ITERATIONS; ++x) {
sched_yield();
}
pthread_mutex_unlock(&lock);
}
void *Waiter(void *arg) {
pthread_barrier_wait(&barrier);
pthread_mutex_lock(&lock);
ASSERT_EQ(ITERATIONS, x);
pthread_mutex_unlock(&lock);
return 0;
}
BENCH(lock, scalability) {
int i;
struct timespec t1, t2;
t1 = _timespec_real();
pthread_mutex_init(&lock, 0);
pthread_barrier_init(&barrier, 0, WAITERS + 1);
for (i = 0; i < WAITERS; ++i) {
ASSERT_EQ(0, pthread_create(t + i, 0, Waiter, 0));
}
Worker();
for (i = 0; i < WAITERS; ++i) {
ASSERT_EQ(0, pthread_join(t[i], 0));
}
pthread_barrier_destroy(&barrier);
pthread_mutex_destroy(&lock);
t2 = _timespec_real();
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
_timespec_tonanos(_timespec_sub(t2, t1)) / 1000000000.,
(double)clock() / CLOCKS_PER_SEC);
}

View file

@ -17,14 +17,19 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/futex.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/common.internal.h"
#include "third_party/nsync/futex.internal.h"
#include "third_party/nsync/mu_semaphore.internal.h"
// clang-format off
/* futex() polyfill w/ sched_yield() fallback */
@ -41,8 +46,18 @@ bool FUTEX_TIMEOUT_IS_ABSOLUTE;
__attribute__((__constructor__)) static void nsync_futex_init_ (void) {
int x = 0;
if (!(FUTEX_IS_SUPPORTED = IsLinux() || IsOpenbsd()))
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
FUTEX_IS_SUPPORTED = true;
FUTEX_WAIT_ = FUTEX_WAIT;
return;
}
if (!(FUTEX_IS_SUPPORTED = IsLinux () || IsOpenbsd ())) {
// we're using sched_yield() so let's
// avoid needless clock_gettime calls
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
return;
}
// In our testing, we found that the monotonic clock on various
// popular systems (such as Linux, and some BSD variants) was no
@ -78,8 +93,30 @@ __attribute__((__constructor__)) static void nsync_futex_init_ (void) {
int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout) {
int rc, op;
if (FUTEX_IS_SUPPORTED) {
op = FUTEX_WAIT_;
uint32_t ms;
if (!FUTEX_IS_SUPPORTED) {
nsync_yield_ ();
if (timeout) {
return -EINTR;
} else {
return 0;
}
}
op = FUTEX_WAIT_;
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
if (timeout) {
ms = _timespec_tomillis (*timeout);
} else {
ms = -1;
}
if (WaitOnAddress (p, &expect, sizeof(int), ms)) {
rc = 0;
} else {
rc = -GetLastError ();
}
} else {
if (pshare == PTHREAD_PROCESS_PRIVATE) {
op |= FUTEX_PRIVATE_FLAG_;
}
@ -88,35 +125,45 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
// [jart] openbsd does this without setting carry flag
rc = -rc;
}
STRACE("futex(%t, %s, %d, %s) → %s",
p, DescribeFutexOp(op), expect,
DescribeTimespec(0, timeout), DescribeFutexResult(rc));
} else {
nsync_yield_ ();
if (timeout) {
rc = -ETIMEDOUT;
} else {
rc = 0;
}
}
STRACE("futex(%t, %s, %d, %s) → %s",
p, DescribeFutexOp (op), expect,
DescribeTimespec (0, timeout),
DescribeFutexResult (rc));
return rc;
}
int nsync_futex_wake_ (int *p, int count, char pshare) {
int rc, op;
int wake (void *, int, int) asm ("_futex");
if (FUTEX_IS_SUPPORTED) {
op = FUTEX_WAKE;
ASSERT (count == 1 || count == INT_MAX);
if (!FUTEX_IS_SUPPORTED) {
nsync_yield_ ();
return 0;
}
op = FUTEX_WAKE;
if (NSYNC_FUTEX_WIN32 && IsWindows ()) {
if (count == 1) {
WakeByAddressSingle (p);
} else {
WakeByAddressAll (p);
}
rc = 0;
} else {
if (pshare == PTHREAD_PROCESS_PRIVATE) {
op |= FUTEX_PRIVATE_FLAG_;
}
rc = wake (p, op, count);
STRACE("futex(%t, %s, %d) → %s", p,
DescribeFutexOp(op),
count, DescribeFutexResult(rc));
} else {
nsync_yield_ ();
rc = 0;
}
STRACE("futex(%t, %s, %d) → %s", p,
DescribeFutexOp(op),
count, DescribeFutexResult(rc));
return rc;
}

View file

@ -23,7 +23,7 @@
/* Initialize *s; the initial value is 0. */
void nsync_mu_semaphore_init (nsync_semaphore *s) {
if (!IsWindows ())
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_init_futex (s);
else
nsync_mu_semaphore_init_win32 (s);
@ -31,7 +31,7 @@ void nsync_mu_semaphore_init (nsync_semaphore *s) {
/* Wait until the count of *s exceeds 0, and decrement it. */
void nsync_mu_semaphore_p (nsync_semaphore *s) {
if (!IsWindows ())
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_p_futex (s);
else
nsync_mu_semaphore_p_win32 (s);
@ -41,7 +41,7 @@ void nsync_mu_semaphore_p (nsync_semaphore *s) {
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 (!IsWindows ())
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);
@ -49,7 +49,7 @@ int nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadl
/* Ensure that the count of *s is at least 1. */
void nsync_mu_semaphore_v (nsync_semaphore *s) {
if (!IsWindows ())
if (NSYNC_FUTEX_WIN32 || !IsWindows ())
nsync_mu_semaphore_v_futex (s);
else
nsync_mu_semaphore_v_win32 (s);

View file

@ -2,6 +2,11 @@
#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_

View file

@ -15,6 +15,7 @@
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"
@ -32,14 +33,14 @@ https://github.com/google/nsync\"");
/* Initialize *s; the initial value is 0. */
void nsync_mu_semaphore_init_win32 (nsync_semaphore *s) {
int64_t *h = (int64_t *) s;
*h = CreateSemaphore(NULL, 0, 1, NULL);
*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);
WaitForSingleObject (*h, -1u);
}
/* Wait until one of:
@ -50,7 +51,7 @@ int nsync_mu_semaphore_p_with_deadline_win32 (nsync_semaphore *s, nsync_time abs
int result;
if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) == 0) {
result = WaitForSingleObject(*h, -1u);
result = WaitForSingleObject (*h, -1u);
} else {
nsync_time now;
now = nsync_time_now ();

View file

@ -27,6 +27,7 @@ THIRD_PARTY_NSYNC_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_NT_SYNCHRONIZATION \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \

View file

@ -1,5 +1,9 @@
#!/bin/sh
ASCII2UTF8=$(command -v ascii2utf8.com 2>/dev/null) || {
ASCII2UTF8=$(ls -1 o/*/tool/viz/ascii2utf8.com | head -n1)
}
for x; do
nroff -mandoc -rLL=80n -rLT=80n -Tutf8 <"$x" |
o//tool/viz/ascii2utf8.com
nroff -mandoc -rLL=80n -rLT=80n -Tutf8 <"$x" | $ASCII2UTF8
done