This change solves an issue where many threads attempting to spawn forks at once would cause fork() performance to degrade with the thread count. Things got real nasty on NetBSD, which slowed down the whole test fleet, because there's no vfork() and we're forced to use fork() in our server. threads count task 1 1062 fork+exit+wait 2 668 fork+exit+wait 4 66 fork+exit+wait 8 19 fork+exit+wait 16 22 fork+exit+wait 32 16 fork+exit+wait Things are now much less bad on NetBSD, but not great, since it does not have futexes; we rely on its semaphore file descriptors to do conditions threads count task 1 1085 fork+exit+wait 2 842 fork+exit+wait 4 532 fork+exit+wait 8 400 fork+exit+wait 16 276 fork+exit+wait 32 66 fork+exit+wait With OpenBSD which also lacks vfork(), things were just as bad as NetBSD threads count task 1 584 fork+exit+wait 2 687 fork+exit+wait 4 206 fork+exit+wait 8 24 fork+exit+wait 16 33 fork+exit+wait 32 26 fork+exit+wait But since OpenBSD has futexes fork() works terrifically thanks to *NSYNC threads count task 1 525 fork+exit+wait 2 580 fork+exit+wait 4 451 fork+exit+wait 8 479 fork+exit+wait 16 408 fork+exit+wait 32 373 fork+exit+wait This issue would most likely only manifest itself, when pthread_atfork() callers manage to slip a spin lock into the outermost position of fork's list of locks. Since fork() is very slow, a spin lock can be devastating Needless to say vfork() rules and anyone who says differently is kidding themselves. Look at what a FreeBSD 14.1 virtual machine with equal specs can do over the course of three hundred milliseconds. threads count task 1 2559 vfork+exit+wait 2 5389 vfork+exit+wait 4 34933 vfork+exit+wait 8 43273 vfork+exit+wait 16 49648 vfork+exit+wait 32 40247 vfork+exit+wait So it's a shame that so few OSes support vfork(). It creates an unsavory situation, where someone wanting to build a server that spawns processes would be better served to not use threads and favor a multiprocess model |
||
---|---|---|
.. | ||
calls | ||
crt | ||
dlopen | ||
elf | ||
fmt | ||
integral | ||
intrin | ||
irq | ||
isystem | ||
log | ||
mem | ||
nexgen32e | ||
nt | ||
proc | ||
runtime | ||
sock | ||
stdio | ||
str | ||
sysv | ||
testlib | ||
thread | ||
tinymath | ||
vga | ||
x | ||
ar.h | ||
assert.h | ||
atomic.h | ||
BUILD.mk | ||
complex.h | ||
cosmo.h | ||
ctype.h | ||
cxxabi.h | ||
dce.h | ||
dos.internal.h | ||
empty.s | ||
errno.h | ||
imag.internal.h | ||
inttypes.h | ||
iso646.internal.h | ||
limits.h | ||
literal.h | ||
mach.internal.h | ||
macho.internal.h | ||
macros.internal.h | ||
math.h | ||
paths.h | ||
README.md | ||
serialize.h | ||
stdalign.internal.h | ||
stdbool.h | ||
stdckdint.h | ||
stdlib.h | ||
temp.h | ||
testlib-test.txt | ||
time.h | ||
unistd.h | ||
utime.h | ||
wctype.h | ||
zip.internal.h |
Cosmopolitan Standard Library
This directory defines static archives defining functions, like
printf()
, mmap()
, win32, etc. Please note that the Cosmopolitan
build configuration doesn't link any C/C++ library dependencies
by default, so you still have the flexibility to choose the one
provided by your system. If you'd prefer Cosmopolitan, just add
$(LIBC)
and $(CRT)
to your linker arguments.
Your library is compromised of many bite-sized static archives. We use the checkdeps tool to guarantee that the contents of the archives are organized in a logical way that's easy to use with or without our makefile infrastructure, since there's no cyclic dependencies.
The Cosmopolitan Library exports only the most stable canonical
system calls for all supported operating systems, regardless of
which platform is used for compilation. We polyfill many of the
APIs, e.g. read()
, write()
so they work consistently everywhere
while other apis, e.g. CreateWindowEx()
, might only work on one
platform, in which case they become no-op functions on others.
Cosmopolitan polyfill wrappers will usually use the dollar sign naming convention, so they may be bypassed when necessary. This same convention is used when multiple implementations of string library and other performance-critical function are provided to allow Cosmopolitan to go fast on both old and newer computers.
We take an approach to configuration that relies heavily on the
compiler's dead code elimination pass (libc/dce.h
). Most of the
code is written so that, for example, folks not wanting support
for OpenBSD can flip a bit in SUPPORT_VECTOR
and that code will
be omitted from the build. The same is true for builds that are
tuned using -march=native
which effectively asks the library to
not include runtime support hooks for x86 processors older than
what you use.
Please note that, unlike Cygwin or MinGW, Cosmopolitan does not achieve broad support by bolting on a POSIX emulation layer. We do nothing more than (in most cases) stateless API translations that get you 90% of the way there in a fast lightweight manner. We therefore can't address some of the subtle differences, such as the nuances of absolute paths on Windows. Our approach could be compared to something more along the lines of, "the Russians just used a pencil to write in space", versus spending millions researching a pen like NASA.