Compare commits

...

40 commits

Author SHA1 Message Date
Hugues Morisset
f1e83d5240
Add IPv6 support to getifaddrs() on Linux (#1415)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-05-21 01:20:22 -07:00
Steven Dee (Jōshin)
2fe8338f92
Better mtimes for github workflow build cache (#1421)
Saves and restores mtimes to a file, also covering the `o/` directory to
hopefully preserve make dependency information better.
2025-05-20 22:17:55 -07:00
ShalokShalom
4ca513cba2
Add C++ to README (#1407)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-04-25 15:47:50 -07:00
Steven Dee (Jōshin)
455910e8f2
Make more shared_ptr fixes (#1401)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
* Make refcount reads explicitly atomic
* Consistently put `const` in the same place
* Write the general `operator=` on `weak_ptr`
2025-04-21 05:36:50 -07:00
Steven Dee (Jōshin)
9c68bc19b5
Cache .cosmocc and o for github workflows (#1400)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
Uses GitHub’s actions/cache@v4 to store the cosmocc distribution and the
output directory between runs of the build workflow, with the version of
cosmocc as the cache key.

Upgrades to actions/checkout@v4.
2025-04-17 15:55:27 -07:00
Steven Dee (Jōshin)
66d1050af6
Correctly implement weak_ptr assignment/copy/moves (#1399) 2025-04-17 14:01:20 -07:00
Justine Tunney
fbc4fcbb71
Get GDB working
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
You can now say `gdb hello.com.dbg` and it'll work perfectly.
2025-03-30 15:25:55 -07:00
Steven Dee (Jōshin)
afc986f741
Fix shared_ptr<T>::owner_before (#1390)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
`!(a < b)` is not the same as `b < a`.

I think I originally wrote it this way to avoid making weak_ptr a friend
of shared_ptr, but weak_ptr already is a friend.
2025-03-25 01:49:34 -04:00
Derek
5eb7cd6643
Add support for getcpu() system call to pledge() (#1387)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This fixes redbean Lua tests which were failing with SIGSYS on Linux.
2025-03-21 16:08:25 -07:00
Brett Jia
a8ed4fdd09
Add NetBSD evbarm and fix segfault (#1384)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This change fixes a segmentation fault when comparing loaders that don't
have a target kernel set. Additionally, adds evbarm, which is the output
of uname -m on NetBSD on aarch64.
2025-03-12 17:37:46 -07:00
Brett Jia
7b69652854
Add -k OSNAME flag to apelink (#1383)
Let's say you pass the `-M blink-mips.elf` flag to apelink, so that your
ape binary will bundle a compressed build of blink, and the shell script
will extract that binary and launch your program under it, if running on
a MIPS system. However, for any given microprocessor architecture, we'll
need a separate loader for each operating system. The issue is ELF OSABI
isn't very useful. As an example, SerenityOS and Linux both have SYSV in
the OSABI field. So to tell their binaries apart we'd have to delve into
various other conventions, like special sections and PT_NOTE structures.

To make things simple this change introduces the `-k OS` flag to apelink
which generate shell script content that ensures `OS` matches `uname -s`
before attempting to execute a loader. For example, you could say:

    apelink -k Linux -M blink-linux-arm.elf -M blink-linux-mips.elf \
            -k Darwin -M blink-darwin-ppc.elf \
            ...

To introduce support for old 32-bit architectures on multiple OSes, when
building your cosmo binary.
2025-03-12 13:26:51 -07:00
Leal G.
b235492e71
Add usertrust certificate (#1382)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
Bundle USERTrust CA certificates to /usr/share/ssl/root for TLS verifies
2025-03-11 17:59:34 -07:00
Brett Jia
fc81fd8d16
Support additional architectures in apelink (#1381)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This updates apelink to support machine architectures not in the source
program input list by adding additional loaders, extracting the correct
one that matches the host uname machine. With this change, blink can be
supplied as the additional loader to run the program in x86_64 VMs. The
change has been verified against blink 1.0, powerpc64le and mips64el in
Docker using QEMU.
2025-03-06 10:26:31 -08:00
Gautham
38930de8e0
Make tool for replacing ELF strings (#1344)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-02-08 21:17:42 -08:00
Brett Jia
0e557d041d
Check downloaded gcc/clang checksums (#1367)
Check sha256 checksums of the downloaded gcc and clang toolchains. It'll
allow us to extend trust to external toolchains if building from source.
2025-02-08 17:46:09 -08:00
Brett Jia
1d676b36e6
Make cosmoranlib executable (#1366)
Fixes #1325
2025-02-08 17:38:00 -08:00
Brett Jia
10a92cee94
Support building cosmocc on MacOS (#1365)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
This updates the cosmocc toolchain packaging script to work on MacOS. It
has been tested on GitHub Actions macos-13 (x86_64) and macos-14 (arm64)
runners, and is verified to still work on Ubuntu (GitHub Actions runners
ubuntu-24.04 and ubuntu-24.04-arm). It'll help bring cosmocc to MacPorts
by running the packaging script. We favor `gmake` rather than the `make`
command because it distinguishes GNU Make from BSD Make, and Xcode Make.
Additionally, APE loader from the bootstrapper toolchain is used instead
of a system APE, which may not be available.
2025-02-08 12:45:45 -08:00
A2va
42a9ed0131
Adds some NT functions (#1358) 2025-02-08 08:08:08 -08:00
Björn Buckwalter
12cb0669fb
Clarify unix.mapshared versus file locks (#1355)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
2025-02-08 00:48:38 -08:00
rufeooo
7f6a7d6fff
Fix sigaction example code (#1363)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
2025-02-07 11:42:47 -08:00
Steven Dee (Jōshin)
9f6bf6ea71
tool/zsh/mkofs: doas 2025-01-13 16:48:55 -08:00
Steven Dee (Jōshin)
102edf4ea2
tool/zsh/mmake: style 2025-01-05 20:53:53 -08:00
Steven Dee (Jōshin)
21968acf99
Standard make path (#1353)
Modifies download-cosmocc.sh to maintain a .cosmocc/current symlink that
always points to the most recently downloaded version of cosmocc. We can
use this to point at a canonical make for a bootstrapped repository. For
first-time builds, we suggest: https://cosmo.zip/pub/cosmos/bin/make and
have updated the docs in a few places to mention this.

Fixes the other part of #1346.
2025-01-05 20:47:34 -08:00
Justine Tunney
98861b23fc
Make some style fixes to prng code 2025-01-05 20:18:05 -08:00
Steven Dee (Jōshin)
dab6d7a345
Resolve multiple definition of __sig (fixes #1346) (#1352) 2025-01-05 19:54:49 -08:00
Justine Tunney
90119c422c
Fix 404 url
Closes #1347
2025-01-05 17:04:37 -08:00
Justine Tunney
5907304049
Release Cosmopolitan v4.0.2 2025-01-05 14:05:49 -08:00
Justine Tunney
035b0e2a62
Attempt to fix MODE=dbg Windows execve() flake 2025-01-05 14:05:49 -08:00
Justine Tunney
7b67b20dae
Fix Windows MODE=tiny breakage 2025-01-05 14:05:49 -08:00
Himanshu Pal
f0b0f926bf
Enable sqlite3 serialization in redbean (#1349)
This fixes a failing demo page, that requires us to enable serialization
in the lsqlite3 library that's used by the redbean server.
2025-01-05 13:59:10 -08:00
Justine Tunney
29eb7e67bb
Fix fork() regression on Windows
Recent optimizations to fork() introduced a regression, that could cause
the subprocess to fail unexpectedly, when TlsAlloc() returns a different
index. This is because we were burning the indexes into the displacement
of x86 opcodes. So when fork() happened and the executable memory copied
it would use the old index. Right now the way this is being solved is to
not copy the executable on fork() and then re-apply code changes. If you
need to be able to preserve self-modified code on fork, reach out and we
can implement a better solution for you. This gets us unblocked quickly.
2025-01-05 09:25:23 -08:00
Justine Tunney
f71f61cd40
Add some temporary logging statements 2025-01-04 23:37:32 -08:00
Justine Tunney
53c6edfd18
Make correction to last change 2025-01-04 21:38:47 -08:00
Justine Tunney
42a3bb729a
Make execve() linger when it can't spoof parent
It's now possible to use execve() when the parent process isn't built by
cosmo. In such cases, the current process will kill all threads and then
linger around, waiting for the newly created process to die, and then we
propagate its exit code to the parent. This should help bazel and others

Allocating private anonymous memory is now 5x faster on Windows. This is
thanks to VirtualAlloc() which is faster than the file mapping APIs. The
fork() function also now goes 30% faster, since we are able to avoid the
VirtualProtect() calls on mappings in most cases now.

Fixes #1253
2025-01-04 21:13:37 -08:00
Justine Tunney
c97a858470
Remove missing definitions 2025-01-04 00:20:45 -08:00
Justine Tunney
4acd12a514
Release Cosmopolitan v4.0.1 2025-01-03 19:51:34 -08:00
Justine Tunney
b734eec836
Test restricting tests to single cpu 2025-01-03 19:51:09 -08:00
Justine Tunney
fe01642a20
Add missing lock to fork() on Windows 2025-01-03 19:01:58 -08:00
Justine Tunney
e939659b70
Fix ordering of pthread_create(pthread_t *thread)
This change fixes a bug where signal_latency_async_test would flake less
than 1/1000 of the time. What was happening was pthread_kill(sender_thr)
would return EFAULT. This was because pthread_create() was not returning
the thread object pointer until after clone() had been called. So it was
actually possible for the main thread to stall after calling clone() and
during that time the receiver would launch and receive a signal from the
sender thread, and then fail when it tried to send a pong. I thought I'd
use a barrier at first, in the test, to synchronize thread creation, but
I firmly believe that pthread_create() was to blame and now that's fixed
2025-01-03 17:34:29 -08:00
Justine Tunney
ed6d133a27
Use tgkill() on Linux and FreeBSD
This eliminates the chance of rare bugs when thread IDs are recycled.
2025-01-03 17:27:13 -08:00
131 changed files with 2247 additions and 1057 deletions

View file

@ -1,5 +1,8 @@
name: build
env:
COSMOCC_VERSION: 3.9.2
on:
push:
branches:
@ -19,13 +22,48 @@ jobs:
matrix:
mode: ["", tiny, rel, tinylinux, optlinux]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
# Full checkout needed for git-restore-mtime-bare.
fetch-depth: 0
# TODO(jart): fork this action.
- uses: chetan/git-restore-mtime-action@v2
- uses: actions/cache/restore@v4
id: cache
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
restore-keys: |
${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-
${{ env.COSMOCC_VERSION }}-
- name: Restore mtimes
if: steps.cache.outputs.cache-hit == 'true'
run: |
while read mtime file; do
[ -f "$file" ] && touch -d "@$mtime" "$file"
done < o/.mtimes
- name: support ape bins 1
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
- name: support ape bins 2
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
- name: make matrix
run: V=0 make -j2 MODE=${{ matrix.mode }}
- name: Save mtimes
run: |
find o -type f -exec stat -c "%Y %n" {} \; > o/.mtimes
- uses: actions/cache/save@v4
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}

View file

@ -77,7 +77,8 @@ COMMA := ,
PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran build/bootstrap/make, in which case make's working directory is in wsl
# - user ran .cosmocc/current/bin/make, in which case make's working directory
# is in wsl
# - user ran make, in which case cocmd's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
$(warning wsl2 interop is enabled)
@ -89,7 +90,7 @@ UNAME_S := $(shell uname -s)
# apple still distributes a 17 year old version of gnu make
ifeq ($(MAKE_VERSION), 3.81)
$(error please use build/bootstrap/make)
$(error please use https://cosmo.zip/pub/cosmos/bin/make)
endif
LC_ALL = C

View file

@ -3,7 +3,7 @@
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C/C++
a build-once run-anywhere language, like Java, except it doesn't need an
interpreter or virtual machine. Instead, it reconfigures stock GCC and
Clang to output a POSIX-approved polyglot format that runs natively on
@ -87,15 +87,22 @@ ape/apeinstall.sh
```
You can now build the mono repo with any modern version of GNU Make. To
make life easier, we've included one in the cosmocc toolchain, which is
guaranteed to be compatible and furthermore includes our extensions for
doing build system sandboxing.
bootstrap your build, you can install Cosmopolitan Make from this site:
https://cosmo.zip/pub/cosmos/bin/make
E.g.:
```sh
build/bootstrap/make -j8
curl -LO https://cosmo.zip/pub/cosmos/bin/make
./make -j8
o//examples/hello
```
After you've built the repo once, you can also use the make from your
cosmocc at `.cosmocc/current/bin/make`. You might even prefer to alias
make to `$COSMO/.cosmocc/current/bin/make`.
Since the Cosmopolitan repository is very large, you might only want to
build one particular thing. Here's an example of a target that can be
compiled relatively quickly, which is a simple POSIX test that only
@ -103,7 +110,7 @@ depends on core LIBC packages.
```sh
rm -rf o//libc o//test
build/bootstrap/make o//test/posix/signal_test
.cosmocc/current/bin/make o//test/posix/signal_test
o//test/posix/signal_test
```
@ -112,21 +119,21 @@ list out each individual one. For example if you wanted to build and run
all the unit tests in the `TEST_POSIX` package, you could say:
```sh
build/bootstrap/make o//test/posix
.cosmocc/current/bin/make o//test/posix
```
Cosmopolitan provides a variety of build modes. For example, if you want
really tiny binaries (as small as 12kb in size) then you'd say:
```sh
build/bootstrap/make m=tiny
.cosmocc/current/bin/make m=tiny
```
You can furthermore cut out the bloat of other operating systems, and
have Cosmopolitan become much more similar to Musl Libc.
```sh
build/bootstrap/make m=tinylinux
.cosmocc/current/bin/make m=tinylinux
```
For further details, see [//build/config.mk](build/config.mk).

View file

@ -259,6 +259,9 @@ SECTIONS {
.debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }

View file

@ -386,6 +386,13 @@ SECTIONS {
_tbss_end = .;
} :Tls
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
} :Ram
.data . : {
/*BEGIN: Read/Write Data */
#if SupportsWindows()
@ -426,11 +433,6 @@ SECTIONS {
KEEP(*(.dtors))
__fini_array_end = .;
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
/*BEGIN: Post-Initialization Read-Only */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
@ -439,7 +441,6 @@ SECTIONS {
KEEP(*(.piro.pad.data))
*(.igot.plt)
KEEP(*(.dataepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */
_edata = .;
@ -519,6 +520,9 @@ SECTIONS {
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
.GCC.command.line 0 : { *(.GCC.command.line) }
@ -582,11 +586,11 @@ ape_rom_memsz = ape_rom_filesz;
ape_rom_align = CONSTANT(COMMONPAGESIZE);
ape_rom_rva = RVA(ape_rom_vaddr);
ape_ram_vaddr = ADDR(.data);
ape_ram_vaddr = ADDR(.eh_frame);
ape_ram_offset = ape_ram_vaddr - __executable_start;
ape_ram_paddr = LOADADDR(.data);
ape_ram_filesz = ADDR(.bss) - ADDR(.data);
ape_ram_memsz = _end - ADDR(.data);
ape_ram_paddr = LOADADDR(.eh_frame);
ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
ape_ram_memsz = _end - ADDR(.eh_frame);
ape_ram_align = CONSTANT(COMMONPAGESIZE);
ape_ram_rva = RVA(ape_ram_vaddr);
@ -596,7 +600,7 @@ ape_stack_offset = 0;
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
ape_stack_filesz = 0;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 4 * 1024 * 1024;
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
ape_note_filesz = ape_note_end - ape_note;

View file

@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x build/bootstrap/make ]; then
MAKE=build/bootstrap/make
if [ -x .cosmocc/current/bin/make ]; then
MAKE=.cosmocc/current/bin/make
else
MAKE=make
fi

View file

@ -99,3 +99,8 @@ rm -f cosmocc.zip cosmocc.zip.sha256sum
# commit output directory
cd "${OLDPWD}" || die
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
# update current symlink
BASE=$(basename "${OUTPUT_DIR}")
DIR=$(dirname "${OUTPUT_DIR}")
ln -sfn "$BASE" "$DIR/current"

View file

@ -97,12 +97,12 @@ class shared_ref
size_t use_count() const noexcept
{
return shared + 1;
return __atomic_load_n(&shared, __ATOMIC_RELAXED) + 1;
}
size_t weak_count() const noexcept
{
return weak;
return __atomic_load_n(&weak, __ATOMIC_RELAXED);
}
private:
@ -349,7 +349,7 @@ class shared_ptr
template<typename U>
bool owner_before(const weak_ptr<U>& r) const noexcept
{
return !r.owner_before(*this);
return rc < r.rc;
}
private:
@ -382,6 +382,34 @@ class weak_ptr
rc->keep_weak();
}
weak_ptr(const weak_ptr& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(const weak_ptr<U>& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
weak_ptr(weak_ptr&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(weak_ptr<U>&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
~weak_ptr()
{
if (rc)
@ -410,6 +438,19 @@ class weak_ptr
swap(rc, r.rc);
}
weak_ptr& operator=(weak_ptr r) noexcept
{
swap(r);
return *this;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr& operator=(weak_ptr<U> r) noexcept
{
weak_ptr<T>(move(r)).swap(*this);
}
shared_ptr<T> lock() const noexcept
{
if (expired())

View file

@ -28,8 +28,8 @@
// @return rdi is rdi+edx
.text.startup
__getntsyspath:
push %rbp
mov %rsp,%rbp
beg
pro
push %rdx
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
sub $40,%rsp
@ -55,6 +55,7 @@ __getntsyspath:
jne 2f
movb $'/',-1(%rdi)
2: .loop 1b
leave
epi
ret
end
.endfn __getntsyspath,globl,hidden

View file

@ -114,7 +114,8 @@ static ssize_t GetDevUrandom(char *p, size_t n, unsigned f) {
ssize_t __getrandom(void *p, size_t n, unsigned f) {
ssize_t rc;
if (IsWindows()) {
rc = ProcessPrng(p, n) ? n : __winerr();
ProcessPrng(p, n); // never fails
rc = n;
} else if (have_getrandom) {
if (IsXnu() || IsOpenbsd()) {
rc = GetRandomBsd(p, n, GetRandomEntropy);
@ -184,9 +185,7 @@ ssize_t __getrandom(void *p, size_t n, unsigned f) {
* @raise EFAULT if the `n` bytes at `p` aren't valid memory
* @raise EINTR if we needed to block and a signal was delivered instead
* @cancelationpoint
* @asyncsignalsafe
* @restartable
* @vforksafe
*/
ssize_t getrandom(void *p, size_t n, unsigned f) {
ssize_t rc;

View file

@ -67,10 +67,9 @@ textstartup void InitializeMetalFile(void) {
size_t size = ROUNDUP(_ezip - __executable_start, 4096);
// TODO(jart): Restore support for ZIPOS on metal.
void *copied_base;
struct DirectMap dm;
dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0);
copied_base = dm.addr;
void *addr = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0);
copied_base = addr;
npassert(copied_base != (void *)-1);
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
__ape_com_base = copied_base;

View file

@ -39,12 +39,15 @@
#include "libc/nt/struct/procthreadattributelist.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/startupinfoex.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/proc/ntspawn.h"
#include "libc/stdalign.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
struct SpawnBlock {
char16_t path[PATH_MAX];
char16_t cmdline[32767];
@ -64,10 +67,12 @@ static textwindows ssize_t ntspawn_read(intptr_t fh, char *buf, size_t len) {
bool ok;
uint32_t got;
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)};
ok = (ReadFile(fh, buf, len, 0, &overlap) ||
ok = overlap.hEvent &&
(ReadFile(fh, buf, len, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(fh, &overlap, &got, true);
CloseHandle(overlap.hEvent);
if (overlap.hEvent)
__imp_CloseHandle(overlap.hEvent);
return ok ? got : -1;
}
@ -87,7 +92,7 @@ static textwindows int ntspawn2(struct NtSpawnArgs *a, struct SpawnBlock *sb) {
if (fh == -1)
return -1;
ssize_t got = ntspawn_read(fh, p, pe - p);
CloseHandle(fh);
__imp_CloseHandle(fh);
if (got < 3)
return enoexec();
pe = p + got;

View file

@ -49,11 +49,9 @@ int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
if ((fd = __reservefd(-1)) == -1)
return -1;
if (!_weaken(calloc) || !_weaken(free)) {
struct DirectMap dm;
dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,
0);
state = dm.addr;
state = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (state == (void *)-1)
return -1;
} else {

View file

@ -694,6 +694,7 @@ static const uint16_t kPledgeStdio[] = {
__NR_linux_sched_getaffinity, //
__NR_linux_sched_setaffinity, //
__NR_linux_sigtimedwait, //
__NR_linux_getcpu, //
};
static const uint16_t kPledgeFlock[] = {

View file

@ -997,8 +997,10 @@ textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
if (f->kind == kFdDevNull)
return 0;
if (f->kind == kFdDevRandom)
return ProcessPrng(data, size) ? size : __winerr();
if (f->kind == kFdDevRandom) {
ProcessPrng(data, size);
return size;
}
if (f->kind == kFdConsole)
return ReadFromConsole(f, data, size, waitmask);

View file

@ -423,7 +423,7 @@ static int __sigaction(int sig, const struct sigaction *act,
* }
*
* void ContinueOnCrash(void) {
* struct sigaction sa = {.sa_handler = OnSigSegv,
* struct sigaction sa = {.sa_sigaction = OnCrash,
* .sa_flags = SA_SIGINFO | SA_RESETHAND};
* sigaction(SIGSEGV, &sa, 0);
* sigaction(SIGFPE, &sa, 0);

View file

@ -2,6 +2,9 @@
#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_
COSMOPOLITAN_C_START_
extern int sys_getppid_nt_cosmo;
extern int sys_getppid_nt_win32;
bool32 sys_isatty(int);
int sys_chdir_nt(const char *);
int sys_dup_nt(int, int, int, int);
@ -37,6 +40,7 @@ int sys_unlinkat_nt(int, const char *, int);
int64_t sys_lseek_nt(int, int64_t, int);
ssize_t sys_read_nt_impl(int, void *, size_t, int64_t);
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t);
void sys_getppid_nt_wipe(int, int);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ */

View file

@ -80,7 +80,8 @@ textwindows int IsWindowsExecutable(int64_t handle, const char16_t *path) {
uint32_t got;
BLOCK_SIGNALS;
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)};
ok = (ReadFile(handle, buf, 2, 0, &overlap) ||
ok = overlap.hEvent &&
(ReadFile(handle, buf, 2, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(handle, &overlap, &got, true);
CloseHandle(overlap.hEvent);

View file

@ -47,7 +47,14 @@ __oops_win32:
// @note ape.S and ape-loader both set RCX to XNU on Darwin
// @noreturn
_start:
#ifdef __x86_64__
.cfi_startproc
#if defined(__x86_64__)
.cfi_undefined rip
#elif defined(__aarch64__)
.cfi_undefined x30
#endif /* __x86_64__ */
#if defined(__x86_64__)
#if SupportsFreebsd()
// detect free besiyata dishmaya
@ -159,4 +166,5 @@ _start:
#else
#error "architecture unsupported"
#endif /* __x86_64__ */
.cfi_endproc
.endfn _start,weak,hidden

View file

@ -68,6 +68,7 @@
#define EM_NONE 0
#define EM_M32 1
#define EM_386 3
#define EM_MIPS 8
#define EM_PPC64 21
#define EM_S390 22
#define EM_ARM 40

View file

@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 4
#define __COSMOPOLITAN_MINOR__ 0
#define __COSMOPOLITAN_PATCH__ 0
#define __COSMOPOLITAN_PATCH__ 2
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)

View file

@ -59,7 +59,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § Windows Time
//
QueryUnbiasedInterruptTimePrecise(&hectons);
*ts = timespec_fromnanos(hectons * 100);
*ts = WindowsDurationToTimeSpec(hectons);
return 0;
case _CLOCK_MONOTONIC_COARSE:
//
@ -83,7 +83,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § QueryUnbiasedInterruptTimePrecise
//
QueryUnbiasedInterruptTime(&hectons);
*ts = timespec_fromnanos(hectons * 100);
*ts = WindowsDurationToTimeSpec(hectons);
return 0;
case _CLOCK_BOOTTIME:
//
@ -95,7 +95,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § Interrupt Time
//
QueryInterruptTimePrecise(&hectons);
*ts = timespec_fromnanos(hectons * 100);
*ts = WindowsDurationToTimeSpec(hectons);
return 0;
case _CLOCK_PROCESS_CPUTIME_ID:
GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel,

View file

@ -21,16 +21,15 @@
.privileged
cosmo_futex_thunk:
beg
pro
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov %rcx,%r10
mov __NR_futex,%eax
clc
syscall
jnc 1f
neg %eax
1: pop %rbp
#elif defined(__aarch64__)
ldr x7,=__hostos
ldr w7,[x7]
@ -46,5 +45,7 @@ cosmo_futex_thunk:
#else
#error "unsupported architecture"
#endif /* __x86_64__ */
1: ret
1: epi
ret
end
.endfn cosmo_futex_thunk,globl,hidden

View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2024 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/intrin/describeflags.h"
#include "libc/macros.h"
#include "libc/nt/enum/memflags.h"
static const struct DescribeFlags kNtAllocationTypeFlags[] = {
{kNtMemCommit, "Commit"}, //
{kNtMemReserve, "Reserve"}, //
{kNtMemReset, "Reset"}, //
};
const char *_DescribeNtAllocationType(char buf[48], uint32_t x) {
return _DescribeFlags(buf, 48, kNtAllocationTypeFlags,
ARRAYLEN(kNtAllocationTypeFlags), "kNtMem", x);
}

View file

@ -29,6 +29,7 @@ const char *_DescribeMapping(char[8], int, int) libcesque;
const char *_DescribeMremapFlags(char[30], int) libcesque;
const char *_DescribeMsg(char[16], int) libcesque;
const char *_DescribeMsyncFlags(char[48], int) libcesque;
const char *_DescribeNtAllocationType(char[48], uint32_t);
const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque;
const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque;
const char *_DescribeNtCreationDisposition(uint32_t) libcesque;
@ -87,6 +88,7 @@ const char *_DescribeWhichPrio(char[12], int) libcesque;
#define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x)
#define DescribeMsg(x) _DescribeMsg(alloca(16), x)
#define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x)
#define DescribeNtAllocationType(x) _DescribeNtAllocationType(alloca(48), x)
#define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x)
#define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x)
#define DescribeNtFileAccessFlags(x) _DescribeNtFileAccessFlags(alloca(512), x)

View file

@ -19,7 +19,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/intrin/directmap.h"
#include "libc/macros.h"
#include "libc/runtime/pc.internal.h"
#include "libc/str/str.h"
@ -32,19 +31,11 @@
static uint64_t sys_mmap_metal_break;
static struct DirectMap bad_mmap(void) {
struct DirectMap res;
res.addr = (void *)-1;
res.maphandle = -1;
return res;
}
struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
int fd, int64_t off) {
void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
int64_t off) {
/* asan runtime depends on this function */
size_t i;
struct mman *mm;
struct DirectMap res;
uint64_t addr, faddr = 0, page, e, *pte, *fdpte, *pml4t;
mm = __get_mm();
pml4t = __get_pml4t();
@ -54,18 +45,18 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
struct Fd *sfd;
struct MetalFile *file;
if (off < 0 || fd < 0 || fd >= g_fds.n)
return bad_mmap();
return MAP_FAILED;
sfd = &g_fds.p[fd];
if (sfd->kind != kFdFile)
return bad_mmap();
return MAP_FAILED;
file = (struct MetalFile *)sfd->handle;
/* TODO: allow mapping partial page at end of file, if file size not
* multiple of page size */
if (off > file->size || size > file->size - off)
return bad_mmap();
return MAP_FAILED;
faddr = (uint64_t)file->base + off;
if (faddr % 4096 != 0)
return bad_mmap();
return MAP_FAILED;
}
if (!(flags & MAP_FIXED_linux)) {
if (!addr) {
@ -88,7 +79,7 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
if ((flags & MAP_ANONYMOUS_linux)) {
page = __new_page(mm);
if (!page)
return bad_mmap();
return MAP_FAILED;
__clear_page(BANE + page);
e = page | PAGE_RSRV | PAGE_U;
if ((prot & PROT_WRITE))
@ -114,9 +105,7 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
break;
}
}
res.addr = (void *)addr;
res.maphandle = -1;
return res;
return (void *)addr;
}
#endif /* __x86_64__ */

View file

@ -1,122 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/directmap.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
int flags, int fd, int64_t off) {
int64_t handle;
if (flags & MAP_ANONYMOUS) {
handle = kNtInvalidHandleValue;
} else {
handle = g_fds.p[fd].handle;
}
// mark map handle as inheritable if fork might need it
const struct NtSecurityAttributes *mapsec;
if ((flags & MAP_TYPE) == MAP_SHARED) {
mapsec = &kNtIsInheritable;
} else {
mapsec = 0;
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
int iscow = false;
struct ProtectNt fl;
if (handle != -1) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute};
iscow = true;
} else {
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
fl = (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
}
} else {
unassert(flags & MAP_ANONYMOUS);
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
int e = errno;
struct DirectMap dm;
TryAgain:
if ((dm.maphandle = CreateFileMapping(handle, mapsec, fl.flags1,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
size, addr))) {
uint32_t oldprot;
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot))
return dm;
UnmapViewOfFile(dm.addr);
}
CloseHandle(dm.maphandle);
} else if (!(prot & PROT_EXEC) && //
(fl.flags2 & kNtFileMapExecute) && //
GetLastError() == kNtErrorAccessDenied) {
// your file needs to have been O_CREAT'd with exec `mode` bits in
// order to be mapped with executable permission. we always try to
// get execute permission if the kernel will give it to us because
// win32 would otherwise forbid mprotect() from elevating later on
fl.flags2 &= ~kNtFileMapExecute;
switch (fl.flags1) {
case kNtPageExecuteWritecopy:
fl.flags1 = kNtPageWritecopy;
break;
case kNtPageExecuteReadwrite:
fl.flags1 = kNtPageReadwrite;
break;
case kNtPageExecuteRead:
fl.flags1 = kNtPageReadonly;
break;
default:
__builtin_unreachable();
}
errno = e;
goto TryAgain;
}
dm.maphandle = kNtInvalidHandleValue;
dm.addr = (void *)(intptr_t)-1;
return dm;
}

View file

@ -1,67 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/intrin/directmap.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Obtains memory mapping directly from system.
*
* The mmap() function needs to track memory mappings in order to
* support Windows NT and Address Sanitizer. That memory tracking can be
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*
* @asyncsignalsafe
*/
struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {
struct DirectMap d;
if ((__virtualsize += size) >= __virtualmax) {
d.maphandle = kNtInvalidHandleValue;
d.addr = (void *)enomem();
} else if (IsXnuSilicon()) {
long p = _sysret(__syslib->__mmap(addr, size, prot, flags, fd, off));
d.maphandle = kNtInvalidHandleValue;
d.addr = (void *)p;
} else if (!IsWindows() && !IsMetal()) {
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
d.maphandle = kNtInvalidHandleValue;
} else if (IsMetal()) {
d = sys_mmap_metal(addr, size, prot, flags, fd, off);
} else {
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
}
if (d.addr == MAP_FAILED)
__virtualsize -= size;
KERNTRACE("sys_mmap(%.12p, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off,
d.addr, d.maphandle);
return d;
}

View file

@ -2,19 +2,7 @@
#define COSMOPOLITAN_LIBC_INTRIN_DIRECTMAP_H_
COSMOPOLITAN_C_START_
struct ProtectNt {
uint32_t flags1;
uint32_t flags2;
};
struct DirectMap {
void *addr;
int64_t maphandle;
};
struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
void *sys_mmap_metal(void *, size_t, int, int, int, int64_t) libcesque;
int sys_munmap_metal(void *, size_t) libcesque;
int __prot2nt(int, int) libcesque;

View file

@ -46,14 +46,11 @@
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#define OPEN_MAX 16
#ifdef __x86_64__
__static_yoink("_init_fds");
#endif
struct Fds g_fds;
static struct Fd g_fds_static[OPEN_MAX];
static bool TokAtoi(const char **str, long *res) {
int c, d;
@ -92,15 +89,9 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
fds = &g_fds;
fds->n = 4;
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
if (_weaken(_extend)) {
fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->e =
_weaken(_extend)(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize);
} else {
fds->p = g_fds_static;
fds->e = g_fds_static + OPEN_MAX;
}
fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize);
// inherit standard i/o file descriptors
if (IsMetal()) {
@ -154,8 +145,7 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
break;
if (!TokAtoi(&fdspec, &protocol))
break;
if (_weaken(__ensurefds_unlocked))
_weaken(__ensurefds_unlocked)(fd);
__ensurefds_unlocked(fd);
struct Fd *f = fds->p + fd;
if (f->handle && f->handle != -1 && f->handle != handle) {
CloseHandle(f->handle);

View file

@ -26,7 +26,9 @@
// @see setcontext()
.ftrace1
getcontext:
beg
.ftrace2
#include "libc/intrin/getcontext.inc"
jmp __getcontextsig
end
.endfn getcontext,globl

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
@ -33,10 +34,14 @@
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/memflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/stdckdint.h"
#include "libc/stdio/sysparam.h"
@ -80,6 +85,11 @@
} while (0)
#endif
struct DirectMap {
void *addr;
int64_t hand;
};
int __maps_compare(const struct Tree *ra, const struct Tree *rb) {
const struct Map *a = (const struct Map *)MAP_TREE_CONTAINER(ra);
const struct Map *b = (const struct Map *)MAP_TREE_CONTAINER(rb);
@ -284,7 +294,6 @@ void __maps_free(struct Map *map) {
&__maps.freed, &tip, ABA(map, TAG(tip) + 1), memory_order_release,
memory_order_relaxed))
break;
pthread_pause_np();
}
}
@ -421,7 +430,7 @@ void __maps_insert(struct Map *map) {
__maps_check();
}
// adds interval to rbtree (no sys_mmap)
// adds interval to rbtree
bool __maps_track(char *addr, size_t size, int prot, int flags) {
struct Map *map;
if (!(map = __maps_alloc()))
@ -447,16 +456,132 @@ int __maps_untrack(char *addr, size_t size) {
return rc;
}
textwindows dontinline static struct DirectMap sys_mmap_nt(
void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
struct DirectMap dm;
// it's 5x faster
if ((flags & MAP_ANONYMOUS) && (flags & MAP_TYPE) != MAP_SHARED) {
if (!(dm.addr = VirtualAlloc(addr, size, kNtMemReserve | kNtMemCommit,
__prot2nt(prot, false)))) {
dm.addr = MAP_FAILED;
}
dm.hand = MAPS_VIRTUAL;
return dm;
}
int64_t file_handle;
if (flags & MAP_ANONYMOUS) {
file_handle = kNtInvalidHandleValue;
} else {
file_handle = g_fds.p[fd].handle;
}
// mark map handle as inheritable if fork might need it
const struct NtSecurityAttributes *mapsec;
if ((flags & MAP_TYPE) == MAP_SHARED) {
mapsec = &kNtIsInheritable;
} else {
mapsec = 0;
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
int iscow = 0;
int page_flags;
int file_flags;
if (file_handle != -1) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
page_flags = kNtPageExecuteWritecopy;
file_flags = kNtFileMapCopy | kNtFileMapExecute;
iscow = 1;
} else {
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
page_flags = kNtPageExecuteRead;
file_flags = kNtFileMapRead | kNtFileMapExecute;
} else {
page_flags = kNtPageExecuteReadwrite;
file_flags = kNtFileMapWrite | kNtFileMapExecute;
}
}
} else {
page_flags = kNtPageExecuteReadwrite;
file_flags = kNtFileMapWrite | kNtFileMapExecute;
}
int e = errno;
TryAgain:
if ((dm.hand = CreateFileMapping(file_handle, mapsec, page_flags,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.hand, file_flags, off >> 32, off, size,
addr))) {
uint32_t oldprot;
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot))
return dm;
UnmapViewOfFile(dm.addr);
}
CloseHandle(dm.hand);
} else if (!(prot & PROT_EXEC) && //
(file_flags & kNtFileMapExecute) && //
GetLastError() == kNtErrorAccessDenied) {
// your file needs to have been O_CREAT'd with exec `mode` bits in
// order to be mapped with executable permission. we always try to
// get execute permission if the kernel will give it to us because
// win32 would otherwise forbid mprotect() from elevating later on
file_flags &= ~kNtFileMapExecute;
switch (page_flags) {
case kNtPageExecuteWritecopy:
page_flags = kNtPageWritecopy;
break;
case kNtPageExecuteReadwrite:
page_flags = kNtPageReadwrite;
break;
case kNtPageExecuteRead:
page_flags = kNtPageReadonly;
break;
default:
__builtin_unreachable();
}
errno = e;
goto TryAgain;
}
dm.hand = kNtInvalidHandleValue;
dm.addr = (void *)(intptr_t)-1;
return dm;
}
static struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
struct DirectMap d;
if (IsXnuSilicon()) {
long p = _sysret(__syslib->__mmap(addr, size, prot, flags, fd, off));
d.hand = kNtInvalidHandleValue;
d.addr = (void *)p;
} else if (IsWindows()) {
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
} else if (IsMetal()) {
d.addr = sys_mmap_metal(addr, size, prot, flags, fd, off);
d.hand = kNtInvalidHandleValue;
} else {
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
d.hand = kNtInvalidHandleValue;
}
return d;
}
struct Map *__maps_alloc(void) {
struct Map *map;
uintptr_t tip = atomic_load_explicit(&__maps.freed, memory_order_relaxed);
while ((map = (struct Map *)PTR(tip))) {
while ((map = (struct Map *)PTR(tip)))
if (atomic_compare_exchange_weak_explicit(
&__maps.freed, &tip, ABA(map->freed, TAG(tip) + 1),
memory_order_acquire, memory_order_relaxed))
return map;
pthread_pause_np();
}
// we're creating sudden surprise memory. the user might be in the
// middle of carefully planning a fixed memory structure. we don't
// want the system allocator to put our surprise memory inside it,
@ -466,8 +591,6 @@ struct Map *__maps_alloc(void) {
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (sys.addr == MAP_FAILED)
return 0;
if (IsWindows())
CloseHandle(sys.maphandle);
struct MapSlab *slab = sys.addr;
while (!atomic_compare_exchange_weak(&__maps.slabs, &slab->next, slab)) {
}
@ -717,7 +840,7 @@ static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
map->off = off;
map->prot = prot;
map->flags = flags;
map->hand = res.maphandle;
map->hand = res.hand;
if (IsWindows()) {
map->iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1;
map->readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 &&

View file

@ -19,10 +19,8 @@
#include "libc/calls/syscall-nt.internal.h"
#include "libc/intrin/maps.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/errfuns.h"
@ -36,28 +34,17 @@ textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int rc = 0;
__maps_lock();
struct Map *next, *map;
struct Map *map;
if (!(map = __maps_floor(addr)))
map = __maps_first();
for (; map && map->addr <= addr + size; map = next) {
next = __maps_next(map);
if (!__maps_isalloc(map))
continue;
for (; map && map->addr <= addr + size; map = __maps_next(map)) {
if (map->flags & MAP_ANONYMOUS)
continue;
if (MAX(addr, map->addr) >= MIN(addr + size, map->addr + map->size))
continue; // msync() is about coherency between file and memory
char *beg = MAX(addr, map->addr);
char *end = MIN(addr + size, map->addr + map->size);
if (beg >= end)
continue; // didn't overlap mapping
// get true size of win32 allocation
size_t allocsize = map->size;
while (next && !__maps_isalloc(next) &&
next->addr + allocsize == next->addr) {
allocsize += next->size;
next = __maps_next(next);
}
// perform the flush
if (!FlushViewOfFile(map->addr, allocsize))
if (!FlushViewOfFile(beg, end - beg))
rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
}

View file

@ -68,23 +68,19 @@ int msync(void *addr, size_t size, int flags) {
} else {
sysflags = MS_ASYNC;
}
if (flags & MS_INVALIDATE) {
if (flags & MS_INVALIDATE)
sysflags |= MS_INVALIDATE;
}
// FreeBSD's manual says "The flags argument was both MS_ASYNC and
// MS_INVALIDATE. Only one of these flags is allowed." which makes
// following the POSIX recommendation somewhat difficult.
if (IsFreebsd()) {
if (sysflags == (MS_ASYNC | MS_INVALIDATE)) {
if (IsFreebsd())
if (sysflags == (MS_ASYNC | MS_INVALIDATE))
sysflags = MS_INVALIDATE;
}
}
// FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants
if (IsFreebsd()) {
if (IsFreebsd())
sysflags >>= 1;
}
BEGIN_CANCELATION_POINT;
if (!IsWindows()) {

View file

@ -41,8 +41,6 @@ int sys_munmap(void *p, size_t n) {
} else {
rc = __sys_munmap(p, n);
}
if (!rc)
__virtualsize -= n;
KERNTRACE("sys_munmap(%p, %'zu) → %d", p, n, rc);
return rc;
}

View file

@ -83,11 +83,11 @@ struct SignalFrame {
};
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
__msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__msabi extern typeof(VirtualQuery) *const __imp_VirtualQuery;
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
extern pthread_mutex_t __sig_worker_lock;
atomic_int __sig_worker_state;
textwindows static bool __sig_ignored_by_default(int sig) {
return sig == SIGURG || //
@ -566,8 +566,9 @@ textwindows wontreturn static void __sig_death(int sig, const char *thing) {
//
forceinline void __sig_reguard(void *page) {
uint32_t old_protect;
__imp_VirtualProtect((void *)((uintptr_t)page & -__pagesize), __pagesize,
kNtPageReadwrite | kNtPageGuard, &old_protect);
__imp_VirtualProtectEx(GetCurrentProcess(),
(void *)((uintptr_t)page & -__pagesize), __pagesize,
kNtPageReadwrite | kNtPageGuard, &old_protect);
}
// trampoline for calling signal handler when system reports crash
@ -741,39 +742,21 @@ HAIRY static uint32_t __sig_worker(void *arg) {
STKSZ, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK);
for (;;) {
_pthread_mutex_lock(&__sig_worker_lock);
// ok sys_execve_nt() might disable this worker
if (~__sig_worker_state & 2) {
// dequeue all pending signals and fire them off. if there's no
// thread that can handle them then __sig_generate will requeue
// those signals back to __sig.process; hence the need for xchg
unsigned long sigs =
atomic_exchange_explicit(__sig.process, 0, memory_order_acq_rel);
while (sigs) {
int sig = bsfl(sigs) + 1;
sigs &= ~(1ull << (sig - 1));
__sig_generate(sig, SI_KERNEL);
}
// dequeue all pending signals and fire them off. if there's no
// thread that can handle them then __sig_generate will requeue
// those signals back to __sig.process; hence the need for xchg
unsigned long sigs =
atomic_exchange_explicit(__sig.process, 0, memory_order_acq_rel);
while (sigs) {
int sig = bsfl(sigs) + 1;
sigs &= ~(1ull << (sig - 1));
__sig_generate(sig, SI_KERNEL);
}
// unblock stalled i/o signals in threads
_pthread_lock();
for (struct Dll *e = dll_first(_pthread_list); e;
e = dll_next(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >=
kPosixThreadTerminated)
break;
if (atomic_load_explicit(&pt->pt_blocker, memory_order_acquire) &&
(atomic_load_explicit(&pt->tib->tib_sigpending,
memory_order_acquire) &
~atomic_load_explicit(&pt->pt_blkmask, memory_order_acquire)))
__sig_wake(pt, 0);
}
_pthread_unlock();
// unblock stalled asynchronous signals in threads
for (;;) {
sigset_t pending, mask;
struct PosixThread *mark = 0;
// unblock stalled i/o signals in threads
_pthread_lock();
for (struct Dll *e = dll_first(_pthread_list); e;
e = dll_next(_pthread_list, e)) {
@ -781,34 +764,55 @@ HAIRY static uint32_t __sig_worker(void *arg) {
if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >=
kPosixThreadTerminated)
break;
pending = atomic_load_explicit(&pt->tib->tib_sigpending,
memory_order_acquire);
mask =
atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire);
if (pending & ~mask) {
_pthread_ref(pt);
mark = pt;
break;
}
if (atomic_load_explicit(&pt->pt_blocker, memory_order_acquire) &&
(atomic_load_explicit(&pt->tib->tib_sigpending,
memory_order_acquire) &
~atomic_load_explicit(&pt->pt_blkmask, memory_order_acquire)))
__sig_wake(pt, 0);
}
_pthread_unlock();
if (!mark)
break;
while (!atomic_compare_exchange_weak_explicit(
&mark->tib->tib_sigpending, &pending, pending & ~mask,
memory_order_acq_rel, memory_order_relaxed)) {
// unblock stalled asynchronous signals in threads
for (;;) {
sigset_t pending, mask;
struct PosixThread *mark = 0;
_pthread_lock();
for (struct Dll *e = dll_first(_pthread_list); e;
e = dll_next(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
if (atomic_load_explicit(&pt->pt_status, memory_order_acquire) >=
kPosixThreadTerminated)
break;
pending = atomic_load_explicit(&pt->tib->tib_sigpending,
memory_order_acquire);
mask =
atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire);
if (pending & ~mask) {
_pthread_ref(pt);
mark = pt;
break;
}
}
_pthread_unlock();
if (!mark)
break;
while (!atomic_compare_exchange_weak_explicit(
&mark->tib->tib_sigpending, &pending, pending & ~mask,
memory_order_acq_rel, memory_order_relaxed)) {
}
while ((pending = pending & ~mask)) {
int sig = bsfl(pending) + 1;
pending &= ~(1ull << (sig - 1));
__sig_killer(mark, sig, SI_KERNEL);
}
_pthread_unref(mark);
}
while ((pending = pending & ~mask)) {
int sig = bsfl(pending) + 1;
pending &= ~(1ull << (sig - 1));
__sig_killer(mark, sig, SI_KERNEL);
}
_pthread_unref(mark);
}
// wait until next scheduler quantum
_pthread_mutex_unlock(&__sig_worker_lock);
__sig_worker_state |= 1;
Sleep(POLL_INTERVAL_MS);
__sig_worker_state &= ~1;
}
__builtin_unreachable();
}

View file

@ -30,8 +30,6 @@
// usually better that sigprocmask only strace the user is calling it.
// plus, since we have a very specific use case, this code goes faster
struct Signals __sig;
sigset_t __sig_block(void) {
if (IsWindows() || IsMetal()) {
if (__tls_enabled)

View file

@ -492,7 +492,7 @@ relegated bool TellOpenbsdThisIsStackMemory(void *addr, size_t size) {
// OpenBSD only permits RSP to occupy memory that's been explicitly
// defined as stack memory, i.e. `lo <= %rsp < hi` must be the case
relegated errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
relegated bool FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
// get interval
uintptr_t lo = (uintptr_t)attr->__stackaddr;
@ -503,15 +503,11 @@ relegated errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
hi = hi & -__pagesize;
// tell os it's stack memory
errno_t olderr = errno;
if (!TellOpenbsdThisIsStackMemory((void *)lo, hi - lo)) {
errno_t err = errno;
errno = olderr;
return err;
}
if (!TellOpenbsdThisIsStackMemory((void *)lo, hi - lo))
return false;
// update attributes with usable stack address
attr->__stackaddr = (void *)lo;
attr->__stacksize = hi - lo;
return 0;
return true;
}

View file

@ -8,7 +8,7 @@ void cosmo_stack_unlock(void);
void cosmo_stack_wipe(void);
bool TellOpenbsdThisIsStackMemory(void *, size_t);
errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *);
bool FixupCustomStackOnOpenbsd(pthread_attr_t *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_STACK_H_ */

View file

@ -31,17 +31,17 @@
// @returnstwice
.ftrace1
swapcontext:
beg
.ftrace2
#include "libc/intrin/getcontext.inc"
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
push %rsi
push %rsi
pro
cpush %rsi
cpush %rsi
call __swapcontextsig
pop %rdi
pop %rdi
pop %rbp
cpop %rdi
cpop %rdi
epi
test %eax,%eax
jnz 1f
#elif defined(__aarch64__)
@ -56,4 +56,5 @@ swapcontext:
#endif
jmp __tailcontext
1: ret
end
.endfn swapcontext,globl

View file

@ -24,9 +24,9 @@
//
// @return 0 on success, or -1 w/ errno
sys_sched_yield:
beg
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
pro
xor %eax,%eax
mov __hostos(%rip),%dl
@ -84,13 +84,16 @@ sys_sched_yield:
// fails a positive or negative errno might get returned.
#endif
9: leave
9: epi
ret
#elif defined(__aarch64__)
stp x29,x30,[sp,-32]!
mov x29,sp
.cfi_adjust_cfa_offset 32
.cfi_rel_offset x29,16
.cfi_rel_offset x30,24
mov x3,0
mov x2,0
add x4,sp,16
@ -101,10 +104,14 @@ sys_sched_yield:
mov x16,#0x5d // select(0,0,0,0,&blah) for xnu
svc 0
ldp x29,x30,[sp],32
.cfi_adjust_cfa_offset -32
.cfi_restore x30
.cfi_restore x29
ret
#else
#error "arch unsupported"
#endif
end
.endfn sys_sched_yield,globl
.previous

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Copyright 2024 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
@ -16,22 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/syscall-nt.internal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/nt/process.h"
#include "libc/nt/process.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processbasicinformation.h"
textwindows int sys_getppid_nt(void) {
struct NtProcessBasicInformation ProcessInformation;
uint32_t gotsize = 0;
if (!NtError(
NtQueryInformationProcess(GetCurrentProcess(), 0, &ProcessInformation,
sizeof(ProcessInformation), &gotsize)) &&
gotsize >= sizeof(ProcessInformation) &&
ProcessInformation.InheritedFromUniqueProcessId) {
return ProcessInformation.InheritedFromUniqueProcessId;
}
return GetCurrentProcessId();
/**
* Allocates memory on The New Technology.
*/
textwindows void *VirtualAlloc(void *lpAddress, uint64_t dwSize,
uint32_t flAllocationType, uint32_t flProtect) {
return VirtualAllocEx(GetCurrentProcess(), lpAddress, dwSize,
flAllocationType, flProtect);
}

View file

@ -19,32 +19,23 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/macros.h"
#include "libc/mem/alloca.h"
#include "libc/nt/enum/memflags.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
__msabi extern typeof(VirtualAllocEx) *const __imp_VirtualAllocEx;
static const char *DescribeAllocationType(char buf[48], uint32_t x) {
const struct DescribeFlags kAllocationTypeFlags[] = {
{kNtMemCommit, "Commit"}, //
{kNtMemReserve, "Reserve"}, //
{kNtMemReset, "Reset"}, //
};
return _DescribeFlags(buf, 48, kAllocationTypeFlags,
ARRAYLEN(kAllocationTypeFlags), "kNtMem", x);
}
void *VirtualAllocEx(int64_t hProcess, void *lpAddress, uint64_t dwSize,
uint32_t flAllocationType, uint32_t flProtect) {
/**
* Allocates memory on The New Technology.
*/
textwindows void *VirtualAllocEx(int64_t hProcess, void *lpAddress,
uint64_t dwSize, uint32_t flAllocationType,
uint32_t flProtect) {
void *res = __imp_VirtualAllocEx(hProcess, lpAddress, dwSize,
flAllocationType, flProtect);
if (!res)
__winerr();
NTTRACE("VirtualAllocEx(%ld, %p, %'lu, %s, %s) → %p% m", hProcess, lpAddress,
dwSize, DescribeAllocationType(alloca(48), flAllocationType),
dwSize, DescribeNtAllocationType(flAllocationType),
DescribeNtPageFlags(flProtect), res);
return res;
}

View file

@ -19,4 +19,3 @@
#include "libc/runtime/runtime.h"
size_t __virtualmax = -1;
size_t __virtualsize = 0;

View file

@ -58,9 +58,8 @@ textstartup void *_AcpiOsMapUncachedMemory(uintptr_t phy, size_t n) {
}
textstartup static void *_AcpiOsAllocatePages(size_t n) {
struct DirectMap dm = sys_mmap_metal(NULL, n, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void *addr = dm.addr;
void *addr = sys_mmap_metal(NULL, n, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == (void *)-1)
addr = NULL;
return addr;

View file

@ -12,6 +12,7 @@
#include "libc/nt/files.h"
#include "libc/nt/ipc.h"
#include "libc/nt/memory.h"
#include "libc/nt/nls.h"
#include "libc/nt/paint.h"
#include "libc/nt/process.h"
#include "libc/nt/registry.h"
@ -1420,6 +1421,15 @@
#define HKEY_CURRENT_CONFIG kNtHkeyCurrentConfig
#define HKEY_DYN_DATA kNtHkeyDynData
#define HKEY_CURRENT_USER_LOCAL_SETTINGS kNtHkeyCurrentUserLocalSettings
#define KEY_QUERY_VALUE kNtKeyQueryValue
#define KEY_SET_VALUE kNtKeySetValue
#define KEY_CREATE_SUB_KEY kNtKeyCreateSubKey
#define KEY_ENUMERATE_SUB_KEYS kNtKeyEnumerateSubKeys
#define KEY_NOTIFY kNtKeyNotify
#define KEY_CREATE_LINK kNtKeyCreateLink
#define KEY_WOW64_32KEY kNtWow6432Key
#define KEY_WOW64_64KEY kNtWow6464Key
#define KEY_WOW64_RES kNtWow64Res
#define KEY_READ kNtKeyRead
#define KEY_WRITE kNtKeyWrite
#define KEY_EXECUTE kNtKeyExecute
@ -4291,6 +4301,13 @@
#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define CP_ACP 0
#define CP_OEMCP 1
#define CP_MACCP 2
#define CP_THREAD_ACP 3
#define CP_SYMBOL 42
#define CP_UTF7 65000
#define CP_UTF8 65001
#endif /* COSMOPOLITAN_LIBC_COMPAT_INCLUDE_WINDOWS_H_ */

View file

@ -3,7 +3,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/rusage.h"
#include "libc/dce.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/w.h"
COSMOPOLITAN_C_START_

View file

@ -158,6 +158,60 @@
.weak \canonical
.endm
.macro beg
.cfi_startproc
.endm
.macro pro
#if defined(__x86_64__)
push %rbp
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rbp,0
mov %rsp,%rbp
.cfi_def_cfa_register %rbp
#elif defined(__aarch64__)
stp x29,x30,[sp,-16]!
mov x29,sp
.cfi_adjust_cfa_offset 16
.cfi_rel_offset x29,0
.cfi_rel_offset x30,8
#else
#error "unsupported architecture"
#endif
.endm
.macro epi
#if defined(__x86_64__)
.cfi_def_cfa_register %rsp
leave
.cfi_adjust_cfa_offset -8
.cfi_restore %rbp
#elif defined(__aarch64__)
ldp x29,x30,[sp],#16
.cfi_adjust_cfa_offset -16
.cfi_restore x30
.cfi_restore x29
#else
#error "unsupported architecture"
#endif
.endm
.macro end
.cfi_endproc
.endm
.macro cpush reg:req
push \reg
.cfi_adjust_cfa_offset 8
.cfi_rel_offset \reg,0
.endm
.macro cpop reg:req
pop \reg
.cfi_adjust_cfa_offset -8
.cfi_restore \reg
.endm
#ifdef __aarch64__
.macro jmp dest:req
b \dest

View file

@ -7,8 +7,8 @@
// @note public domain
// @see en.wikipedia.org/wiki/Sorting_network
djbsort_avx2:
push %rbp
mov %rsp,%rbp
beg
pro
push %r15
push %r14
push %r13
@ -795,11 +795,13 @@ djbsort_avx2:
pop %r13
pop %r14
pop %r15
pop %rbp
epi
ret
end
.endfn djbsort_avx2,globl,hidden
minmax_vector:
beg
cmp $7,%rdx
jg .L13
.L2: test %rdx,%rdx
@ -838,9 +840,11 @@ minmax_vector:
sub $8,%rdx
jne .L7
ret
end
.endfn minmax_vector
int32_twostages_32:
beg
sub $-128,%rdi
.L17: lea -128(%rdi),%rax
test %rsi,%rsi
@ -866,13 +870,14 @@ int32_twostages_32:
add $512,%rdi
jmp .L17
.L21: ret
end
.endfn int32_twostages_32
int32_threestages:
push %rbp
beg
pro
imul $-24,%rdx,%r8
lea 0(,%rdx,8),%rax
mov %rsp,%rbp
push %r15
push %r14
push %r13
@ -961,11 +966,13 @@ int32_threestages:
pop %r13
pop %r14
pop %r15
pop %rbp
epi
ret
end
.endfn int32_threestages
merge16_finish:
beg
vpminsd %ymm1,%ymm0,%ymm3
vpmaxsd %ymm1,%ymm0,%ymm0
vperm2i128 $32,%ymm0,%ymm3,%ymm2
@ -994,9 +1001,11 @@ merge16_finish:
.L31: vmovdqu %ymm2,(%rdi)
vmovdqu %ymm0,32(%rdi)
ret
end
.endfn merge16_finish
int32_sort_2power:
beg
push %r13
lea 16(%rsp),%r13
andq $-32,%rsp
@ -2075,6 +2084,7 @@ int32_sort_2power:
lea -16(%r13),%rsp
pop %r13
ret
end
.endfn int32_sort_2power
.rodata.cst32

View file

@ -32,7 +32,8 @@
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value
// @see test/libc/runtime/gc_test.c
.ftrace1
__gc: .ftrace2
__gc: beg
.ftrace2
#ifdef __x86_64__
@ -47,8 +48,7 @@ __gc: .ftrace2
mov 8(%r8),%r9
mov 16(%r8),%rdi
push 24(%r8)
push %rbp
mov %rsp,%rbp
pro
sub $32,%rsp
mov %rax,-8(%rbp)
mov %rdx,-16(%rbp)
@ -57,7 +57,7 @@ __gc: .ftrace2
movdqa -32(%rbp),%xmm0
mov -16(%rbp),%rdx
mov -8(%rbp),%rax
leave
epi
ret
9: ud2
nop
@ -102,4 +102,5 @@ __gc: .ftrace2
#endif /* __x86_64__ */
end
.endfn __gc,globl,hidden

View file

@ -31,7 +31,9 @@
// @noreturn
.ftrace1
gclongjmp:
beg
.ftrace2
pro
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
@ -65,4 +67,5 @@ gclongjmp:
#else
#error "unsupported architecture"
#endif /* __x86_64__ */
end
.endfn gclongjmp,globl

View file

@ -26,7 +26,7 @@
// @see gclongjmp()
// @see siglongjmp()
.ftrace1
longjmp:
longjmp:beg
.ftrace2
_longjmp:
#ifdef __x86_64__
@ -61,6 +61,7 @@ _longjmp:
#else
#error "unsupported architecture"
#endif
end
.endfn longjmp,globl
.endfn _longjmp,globl
.alias longjmp,siglongjmp

View file

@ -30,8 +30,8 @@
// @note slower than __sysv2nt
// @see NT2SYSV() macro
__nt2sysv:
push %rbp
mov %rsp,%rbp
beg
pro
sub $256,%rsp
push %rbx
push %rdi
@ -48,6 +48,7 @@ __nt2sysv:
pop %rsi
pop %rdi
pop %rbx
leave
epi
ret
end
.endfn __nt2sysv,globl,hidden

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp advapi32,__imp_RegOpenKeyExA,RegOpenKeyExA
.text.windows
.ftrace1
RegOpenKeyExA:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_RegOpenKeyExA(%rip),%rax
jmp __sysv2nt6
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn RegOpenKeyExA,globl
.previous

View file

@ -1,6 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_
#define kNtKeyQueryValue 0x00000001
#define kNtKeySetValue 0x00000002
#define kNtKeyCreateSubKey 0x00000004
#define kNtKeyEnumerateSubKeys 0x00000008
#define kNtKeyNotify 0x00000010
#define kNtKeyCreateLink 0x00000020
#define kNtWow6432Key 0x00000200
#define kNtWow6464Key 0x00000100
#define kNtWow64Res 0x00000300
#define kNtKeyRead 0x00020019
#define kNtKeyWrite 0x00020006
#define kNtKeyExecute 0x00020019

View file

@ -49,6 +49,7 @@ COSMOPOLITAN_C_START_
intptr_t LoadResource(int64_t hModule, int64_t hResInfo);
uint32_t SetHandleCount(uint32_t uNumber);
uint32_t GetLogicalDrives(void);
uint32_t GetLogicalDriveStringsA(uint32_t nBufferLength, char *lpBuffer);
bool32 FlushFileBuffers(int64_t hFile);
int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess,
@ -205,6 +206,7 @@ uint32_t GetFinalPathNameByHandle(int64_t hFile, char16_t *out_path,
uint32_t GetFullPathName(const char16_t *lpFileName, uint32_t nBufferLength,
char16_t *lpBuffer, char16_t **lpFilePart);
uint32_t GetShortPathName(const char16_t *lpszLongPath, char16_t *out_lpszShortPath, uint32_t cchBuffer);
bool32 GetOverlappedResult(int64_t hFile, struct NtOverlapped *lpOverlapped,
uint32_t *lpNumberOfBytesTransferred, bool32 bWait);

19
libc/nt/kernel32/GetACP.S Normal file
View file

@ -0,0 +1,19 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetACP,GetACP
.text.windows
.ftrace1
GetACP:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
sub $32,%rsp
call *__imp_GetACP(%rip)
leave
#elif defined(__aarch64__)
mov x0,#0
#endif
ret
.endfn GetACP,globl
.previous

View file

@ -1,18 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_VirtualAlloc,VirtualAlloc
.imp kernel32,__imp_GetCPInfoExW,GetCPInfoExW
.text.windows
.ftrace1
VirtualAlloc:
GetCPInfoEx:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_VirtualAlloc(%rip),%rax
mov __imp_GetCPInfoExW(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn VirtualAlloc,globl
.endfn GetCPInfoEx,globl
.previous

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetLogicalDriveStringsA,GetLogicalDriveStringsA
.text.windows
.ftrace1
GetLogicalDriveStringsA:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_GetLogicalDriveStringsA(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn GetLogicalDriveStringsA,globl
.previous

View file

@ -0,0 +1,19 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetOEMCP,GetOEMCP
.text.windows
.ftrace1
GetOEMCP:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
sub $32,%rsp
call *__imp_GetOEMCP(%rip)
leave
#elif defined(__aarch64__)
mov x0,#0
#endif
ret
.endfn GetOEMCP,globl
.previous

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetShortPathNameW,GetShortPathNameW
.text.windows
.ftrace1
GetShortPathName:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_GetShortPathNameW(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn GetShortPathName,globl
.previous

View file

@ -9,7 +9,6 @@
# KERNEL32.DLL
#
# Name Actual DLL Arity
imp '' CreateDirectoryW kernel32 2
imp '' CreateFileA kernel32 7
imp '' CreateFileMappingNumaW kernel32 7
@ -130,10 +129,12 @@ imp 'GetFileTime' GetFileTime kernel32 4
imp 'GetFileType' GetFileType kernel32 1
imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 4
imp 'GetFullPathName' GetFullPathNameW kernel32 4
imp 'GetShortPathName' GetShortPathNameW kernel32 3
imp 'GetHandleInformation' GetHandleInformation kernel32 2
imp 'GetLargestConsoleWindowSize' GetLargestConsoleWindowSize kernel32 1
imp 'GetLastError' GetLastError kernel32 0
imp 'GetLogicalDrives' GetLogicalDrives kernel32 0
imp 'GetLogicalDriveStringsA' GetLogicalDriveStringsA kernel32 2
imp 'GetMaximumProcessorCount' GetMaximumProcessorCount kernel32 1 # Windows 7+
imp 'GetModuleFileName' GetModuleFileNameW kernel32 3
imp 'GetModuleHandle' GetModuleHandleA kernel32 1
@ -187,6 +188,9 @@ imp 'GetVolumeInformationByHandle' GetVolumeInformationByHandleW kernel32
imp 'GetVolumePathName' GetVolumePathNameW kernel32 3
imp 'GetWindowsDirectory' GetWindowsDirectoryW kernel32 2
imp 'GetWindowsDirectoryA' GetWindowsDirectoryA kernel32 2
imp 'GetOEMCP' GetOEMCP kernel32 0
imp 'GetACP' GetACP kernel32 0
imp 'GetCPInfoEx' GetCPInfoExW kernel32 3
imp 'GlobalAlloc' GlobalAlloc kernel32 2
imp 'GlobalFree' GlobalFree kernel32 1
imp 'GlobalLock' GlobalLock kernel32 1
@ -303,7 +307,6 @@ imp 'UnlockFile' UnlockFile kernel32 5
imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 2
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 3
imp 'UpdateProcThreadAttribute' UpdateProcThreadAttribute kernel32 7
imp 'VirtualAlloc' VirtualAlloc kernel32 4
imp 'VirtualFree' VirtualFree kernel32 3
imp 'VirtualLock' VirtualLock kernel32 2
imp 'VirtualQuery' VirtualQuery kernel32 3
@ -358,6 +361,7 @@ imp 'RegLoadKey' RegLoadKeyW advapi32 3
imp 'RegNotifyChangeKeyValue' RegNotifyChangeKeyValue advapi32 5
imp 'RegOpenCurrentUser' RegOpenCurrentUser advapi32 2
imp 'RegOpenKeyEx' RegOpenKeyExW advapi32 5
imp 'RegOpenKeyExA' RegOpenKeyExA advapi32 5
imp 'RegOpenUserClassesRoot' RegOpenUserClassesRoot advapi32 4
imp 'RegOverridePredefKey' RegOverridePredefKey advapi32 2
imp 'RegQueryInfoKey' RegQueryInfoKeyW advapi32 12

35
libc/nt/nls.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef COSMOPOLITAN_LIBC_NT_NLS_H_
#define COSMOPOLITAN_LIBC_NT_NLS_H_
#include "libc/nt/struct/cpinfoex.h"
/* ░░░░
cosmopolitan § new technology » internationalization
*/
COSMOPOLITAN_C_START_
uint32_t GetOEMCP();
uint32_t GetACP();
bool32 GetCPInfoEx(uint32_t CodePage, uint32_t dwFlags, struct NtCpInfoEx *out_lpCPInfoEx) paramsnonnull((3));
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_NT_NLS_H_ */

View file

@ -51,6 +51,8 @@ int RegOpenKey(int64_t hKey, const char16_t *opt_lpSubKey,
int RegOpenKeyEx(int64_t hKey, const char16_t *opt_lpSubKey,
uint32_t opt_ulOptions, int samDesired, int64_t *out_phkResult)
paramsnonnull((5));
int RegOpenKeyExA(int64_t hKey, const char *opt_lpSubKey, uint32_t opt_ulOptions,
int samDesired, int64_t *out_phkResult) paramsnonnull((5));
int RegCloseKey(int64_t hKey);
int RegGetValue(int64_t hkey, const char16_t *opt_lpSubKey,

13
libc/nt/struct/cpinfoex.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_
#define COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_
struct NtCpInfoEx {
uint32_t MaxCharSize;
uint8_t DefaultChar[2];
uint8_t LeadByte[12];
char16_t UnicodeDefaultChar;
uint32_t CodePage;
char16_t CodePageName[260];
};
#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_ */

View file

@ -30,6 +30,7 @@ LIBC_PROC_A_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_NT_PSAPI \
LIBC_RUNTIME \
LIBC_STR \

View file

@ -22,7 +22,6 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/fds.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/strace.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
@ -24,16 +25,23 @@
#include "libc/calls/syscall-nt.internal.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/fds.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/mem/mem.h"
#include "libc/nt/accounting.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/proc/describefds.internal.h"
#include "libc/proc/ntspawn.h"
@ -41,18 +49,19 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#ifdef __x86_64__
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
extern pthread_mutex_t __sig_worker_lock;
extern atomic_int __sig_worker_state;
static void sys_execve_nt_abort(sigset_t sigmask) {
_pthread_unlock();
_pthread_mutex_unlock(&__sig_worker_lock);
__sig_worker_state &= ~2;
__sig_unblock(sigmask);
}
@ -61,17 +70,17 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
// execve() needs to be @asyncsignalsafe
sigset_t sigmask = __sig_block();
_pthread_mutex_lock(&__sig_worker_lock); // order matters
_pthread_lock(); // order matters
__sig_worker_state |= 2;
for (;;)
if (__sig_worker_state & 1)
break;
// new process should be a child of our parent
int64_t hParentProcess;
int ppid = sys_getppid_nt();
if (!(hParentProcess = OpenProcess(
kNtProcessDupHandle | kNtProcessCreateProcess, false, ppid))) {
sys_execve_nt_abort(sigmask);
return -1;
}
int64_t hParentProcess =
sys_getppid_nt_win32
? OpenProcess(kNtProcessDupHandle | kNtProcessCreateProcess, false,
sys_getppid_nt_win32)
: 0;
// inherit pid
char pidvar[11 + 21];
@ -81,6 +90,16 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
char maskvar[6 + 21];
FormatUint64(stpcpy(maskvar, "_MASK="), sigmask);
// inherit parent process id
char ppidvar[12 + 21 + 1 + 21 + 1], *p = ppidvar;
p = stpcpy(p, "_COSMO_PPID=");
if (hParentProcess) {
p = FormatUint64(p, sys_getppid_nt_win32);
*p++ = ':';
p = FormatUint64(p, __pid);
setenv("_COSMO_PPID", ppidvar, true);
}
// define stdio handles for the spawned subprocess
struct NtStartupInfo si = {
.cb = sizeof(struct NtStartupInfo),
@ -94,13 +113,22 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
}
}
// which process is responsible for spawning the child?
int64_t hCreatorProcess;
if (hParentProcess) {
hCreatorProcess = hParentProcess;
} else {
hCreatorProcess = GetCurrentProcess();
}
// pass serialized file descriptor table in environment
char *fdspec;
int64_t *lpExplicitHandles;
uint32_t dwExplicitHandleCount;
if (!(fdspec = __describe_fds(g_fds.p, g_fds.n, &si, hParentProcess,
if (!(fdspec = __describe_fds(g_fds.p, g_fds.n, &si, hCreatorProcess,
&lpExplicitHandles, &dwExplicitHandleCount))) {
CloseHandle(hParentProcess);
if (hParentProcess)
__imp_CloseHandle(hParentProcess);
sys_execve_nt_abort(sigmask);
return -1;
}
@ -114,12 +142,14 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
// launch the process
struct NtProcessInformation pi;
int rc = ntspawn(&(struct NtSpawnArgs){
AT_FDCWD, program, argv, envp, (char *[]){fdspec, maskvar, pidvar, 0}, 0,
0, hParentProcess, lpExplicitHandles, dwExplicitHandleCount, &si, &pi});
__undescribe_fds(hParentProcess, lpExplicitHandles, dwExplicitHandleCount);
AT_FDCWD, program, argv, envp,
(char *[]){fdspec, maskvar, pidvar, ppidvar, 0}, 0, 0, hCreatorProcess,
lpExplicitHandles, dwExplicitHandleCount, &si, &pi});
__undescribe_fds(hCreatorProcess, lpExplicitHandles, dwExplicitHandleCount);
if (rc == -1) {
free(fdspec);
CloseHandle(hParentProcess);
if (hParentProcess)
__imp_CloseHandle(hParentProcess);
sys_execve_nt_abort(sigmask);
if (GetLastError() == kNtErrorSharingViolation) {
return etxtbsy();
@ -128,18 +158,56 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
}
}
// give child to libc/proc/proc.c worker thread in parent
int64_t handle;
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, &handle,
0, false, kNtDuplicateSameAccess)) {
unassert(!(handle & 0xFFFFFFFFFF000000));
__imp_TerminateProcess(-1, 0x23000000u | handle);
} else {
// TODO(jart): Why does `make loc` print this?
// kprintf("DuplicateHandle failed w/ %d\n", GetLastError());
__imp_TerminateProcess(-1, ECHILD);
// check if parent spoofing worked
if (hParentProcess) {
// give child to libc/proc/proc.c worker thread in parent
int64_t handle;
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
&handle, 0, false, kNtDuplicateSameAccess)) {
unassert(!(handle & 0xFFFFFFFFFF000000));
__imp_TerminateProcess(-1, 0x23000000u | handle);
} else {
// TODO(jart): Why does `make loc` print this?
// kprintf("DuplicateHandle failed w/ %d\n", GetLastError());
__imp_TerminateProcess(-1, ECHILD);
}
__builtin_unreachable();
}
// we couldn't reparent the new process
STRACE("warning: execve() lingering due to non-cosmo parent process");
// terminate other threads
_pthread_lock();
struct Dll *e;
struct PosixThread *me = _pthread_self();
for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
if (pt == me)
continue;
TerminateThread(
atomic_load_explicit(&pt->tib->tib_syshand, memory_order_relaxed),
SIGKILL);
}
// wait for child to terminate and propagate exit code
for (;;) {
uint32_t status;
WaitForSingleObject(pi.hProcess, -1u);
GetExitCodeProcess(pi.hProcess, &status);
if (status != kNtStillActive) {
if ((status & 0xFF000000u) == 0x23000000u) {
// handle child execve()
__imp_CloseHandle(pi.hProcess);
pi.hProcess = status & 0x00FFFFFF;
} else {
// handle child _Exit()
if (status == 0xc9af3d51u)
status = kNtStillActive;
TerminateThisProcess(status);
}
}
}
__builtin_unreachable();
}
#endif /* __x86_64__ */

View file

@ -57,11 +57,6 @@
* compiled by MSVC or Cygwin is launched instead, then only the stdio
* file descriptors can be passed along.
*
* On Windows, the parent process must be a cosmo program. If you're
* calling execve() from a program that wasn't launched by cosmopolitan
* bash, or some similar program, then ask yourself if what you really
* want is to either (a) call fork() first, or (b) use posix_spawn().
*
* On Windows, `argv` and `envp` can't contain binary strings. They need
* to be valid UTF-8 in order to round-trip the WIN32 API, without being
* corrupted.

View file

@ -44,8 +44,9 @@
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
@ -89,6 +90,7 @@ textwindows static void sys_fork_nt_child(void) {
// setup runtime
__klog_handle = 0;
__tls_index = __imp_TlsAlloc();
__morph_tls();
__set_tls_win32(__winmain_tib);
__tls_enabled = true;
@ -211,8 +213,6 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
// let's go
bool ok = true;
uint32_t child_old_protect;
uint32_t parent_old_protect;
// copy memory manager maps
for (struct MapSlab *slab =
@ -225,11 +225,12 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
}
// copy private memory maps
int alloc_prot = -1;
for (struct Map *map = __maps_first(); map; map = __maps_next(map)) {
if ((map->flags & MAP_TYPE) == MAP_SHARED)
continue;
continue; // shared memory doesn't need to be copied to subprocess
if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) != MAP_FILE)
continue;
continue; // ignore things like signal worker stack memory
if (__maps_isalloc(map)) {
size_t allocsize = map->size;
for (struct Map *m2 = __maps_next(map); m2; m2 = __maps_next(m2)) {
@ -240,22 +241,44 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
}
}
if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) == MAP_FILE) {
ok = ok && !!VirtualProtectEx(procinfo.hProcess, map->addr, allocsize,
kNtPageReadwrite, &child_old_protect);
// portable executable segment
if (map->prot & PROT_EXEC)
// TODO(jart): write a __remorph_tls() function
continue;
if (!(map->prot & PROT_WRITE)) {
uint32_t child_old_protect;
ok = ok && !!VirtualProtectEx(procinfo.hProcess, map->addr, allocsize,
kNtPageReadwrite, &child_old_protect);
alloc_prot = PROT_READ | PROT_WRITE;
} else {
alloc_prot = map->prot;
}
} else {
// private mapping
uint32_t page_flags;
if (!(alloc_prot & PROT_WRITE)) {
page_flags = kNtPageReadwrite;
alloc_prot = PROT_READ | PROT_WRITE;
} else {
page_flags = __prot2nt(alloc_prot, false);
}
ok = ok && !!VirtualAllocEx(procinfo.hProcess, map->addr, allocsize,
kNtMemReserve | kNtMemCommit,
kNtPageExecuteReadwrite);
kNtMemReserve | kNtMemCommit, page_flags);
}
}
uint32_t parent_old_protect;
if (!(map->prot & PROT_READ))
ok = ok && !!VirtualProtect(map->addr, map->size, kNtPageReadwrite,
&parent_old_protect);
ok = ok && !!WriteProcessMemory(procinfo.hProcess, map->addr, map->addr,
map->size, 0);
ok = ok &&
!!VirtualProtectEx(procinfo.hProcess, map->addr, map->size,
__prot2nt(map->prot, false), &child_old_protect);
!!WriteProcessMemory(procinfo.hProcess, map->addr, map->addr,
(map->size + __pagesize - 1) & -__pagesize, 0);
if (map->prot != alloc_prot) {
uint32_t child_old_protect;
ok = ok &&
!!VirtualProtectEx(procinfo.hProcess, map->addr, map->size,
__prot2nt(map->prot, false), &child_old_protect);
}
if (!(map->prot & PROT_READ))
ok = ok && !!VirtualProtect(map->addr, map->size, parent_old_protect,
&parent_old_protect);

View file

@ -16,10 +16,12 @@
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/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/syscall-nt.internal.h"
@ -37,12 +39,13 @@
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/stdio/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ss.h"
#include "libc/thread/itimer.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
@ -52,9 +55,9 @@
__msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId;
extern atomic_int __sig_worker_state;
extern pthread_mutex_t __cxa_lock_obj;
extern pthread_mutex_t __pthread_lock_obj;
extern pthread_mutex_t __sig_worker_lock;
void __rand64_lock(void);
void __rand64_unlock(void);
@ -119,6 +122,8 @@ static void fork_prepare(void) {
_weaken(__localtime_lock)();
if (_weaken(__dlopen_lock))
_weaken(__dlopen_lock)();
if (IsWindows())
__proc_lock();
if (_weaken(cosmo_stack_lock))
_weaken(cosmo_stack_lock)();
__cxa_lock();
@ -151,6 +156,8 @@ static void fork_parent(void) {
__cxa_unlock();
if (_weaken(cosmo_stack_unlock))
_weaken(cosmo_stack_unlock)();
if (IsWindows())
__proc_unlock();
if (_weaken(__dlopen_unlock))
_weaken(__dlopen_unlock)();
if (_weaken(__localtime_unlock))
@ -161,7 +168,7 @@ static void fork_parent(void) {
_pthread_mutex_unlock(&supreme_lock);
}
static void fork_child(void) {
static void fork_child(int ppid_win32, int ppid_cosmo) {
if (_weaken(__rand64_wipe))
_weaken(__rand64_wipe)();
_pthread_mutex_wipe_np(&__fds_lock_obj);
@ -185,9 +192,11 @@ static void fork_child(void) {
sys_read_nt_wipe_keystrokes();
__proc_wipe_and_reset();
__itimer_wipe_and_reset();
_pthread_mutex_wipe_np(&__sig_worker_lock);
atomic_init(&__sig_worker_state, 0);
if (_weaken(__sig_init))
_weaken(__sig_init)();
if (_weaken(sys_getppid_nt_wipe))
_weaken(sys_getppid_nt_wipe)(ppid_win32, ppid_cosmo);
}
if (_weaken(_pthread_onfork_child))
_weaken(_pthread_onfork_child)();
@ -196,8 +205,9 @@ static void fork_child(void) {
int _fork(uint32_t dwCreationFlags) {
struct Dll *e;
int ax, dx, tid, parent;
parent = __pid;
int ax, dx, tid, ppid_win32, ppid_cosmo;
ppid_win32 = IsWindows() ? GetCurrentProcessId() : 0;
ppid_cosmo = __pid;
BLOCK_SIGNALS;
fork_prepare();
if (!IsWindows()) {
@ -217,7 +227,7 @@ int _fork(uint32_t dwCreationFlags) {
// get new thread id
struct CosmoTib *tib = __get_tls();
struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread;
struct PosixThread *me = (struct PosixThread *)tib->tib_pthread;
tid = IsLinux() || IsXnuSilicon() ? dx : sys_gettid();
atomic_init(&tib->tib_ctid, tid);
atomic_init(&tib->tib_ptid, tid);
@ -237,10 +247,10 @@ int _fork(uint32_t dwCreationFlags) {
// turn other threads into zombies
// we can't free() them since we're monopolizing all locks
// we assume the operating system already reclaimed system handles
dll_remove(&_pthread_list, &pt->list);
dll_remove(&_pthread_list, &me->list);
struct Dll *old_threads = _pthread_list;
_pthread_list = 0;
dll_make_first(&_pthread_list, &pt->list);
dll_make_first(&_pthread_list, &me->list);
atomic_init(&_pthread_count, 1);
// get new system thread handle
@ -258,25 +268,43 @@ int _fork(uint32_t dwCreationFlags) {
atomic_init(&tib->tib_sigpending, 0);
// we can't be canceled if the canceler no longer exists
atomic_init(&pt->pt_canceled, false);
atomic_init(&me->pt_canceled, false);
// forget locks
bzero(tib->tib_locks, sizeof(tib->tib_locks));
// xnu fork() doesn't preserve sigaltstack()
if (IsXnu() && me->tib->tib_sigstack_addr) {
struct sigaltstack_bsd ss;
ss.ss_sp = me->tib->tib_sigstack_addr;
ss.ss_size = me->tib->tib_sigstack_size;
ss.ss_flags = me->tib->tib_sigstack_flags;
if (IsXnuSilicon()) {
__syslib->__sigaltstack(&ss, 0);
} else {
sys_sigaltstack(&ss, 0);
}
}
// run user fork callbacks
fork_child();
fork_child(ppid_win32, ppid_cosmo);
// free threads
if (_weaken(_pthread_free)) {
while ((e = dll_first(old_threads))) {
pt = POSIXTHREAD_CONTAINER(e);
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
atomic_init(&pt->tib->tib_syshand, 0);
dll_remove(&old_threads, e);
_weaken(_pthread_free)(pt);
}
}
STRACE("fork() → 0 (child of %d)", parent);
// reactivate ftrace
/* if (ftrace_stackdigs) */
/* if (_weaken(ftrace_install)) */
/* _weaken(ftrace_install)(); */
STRACE("fork() → 0 (child of %d)", ppid_cosmo);
} else {
// this is the parent process
fork_parent();

93
libc/proc/getppid-nt.c Normal file
View file

@ -0,0 +1,93 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 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/syscall-nt.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/nt/process.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processbasicinformation.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
int sys_getppid_nt_win32;
int sys_getppid_nt_cosmo;
textwindows static int sys_getppid_nt_ntdll(void) {
struct NtProcessBasicInformation ProcessInformation;
uint32_t gotsize = 0;
if (!NtError(
NtQueryInformationProcess(GetCurrentProcess(), 0, &ProcessInformation,
sizeof(ProcessInformation), &gotsize)) &&
gotsize >= sizeof(ProcessInformation) &&
ProcessInformation.InheritedFromUniqueProcessId) {
return ProcessInformation.InheritedFromUniqueProcessId;
}
return 0;
}
static void sys_getppid_nt_extract(const char *str) {
int c;
int win32 = 0;
int cosmo = 0;
if (str) {
for (;;) {
c = *str;
if (!('0' <= c && c <= '9'))
break;
win32 *= 10;
win32 += c - '0';
++str;
}
if (win32 && *str++ == ':') {
for (;;) {
c = *str;
if (!('0' <= c && c <= '9'))
break;
cosmo *= 10;
cosmo += c - '0';
++str;
}
if (win32 == sys_getppid_nt_ntdll()) {
sys_getppid_nt_win32 = win32;
sys_getppid_nt_cosmo = cosmo;
}
}
}
}
__attribute__((__constructor__(90))) static void init(void) {
if (!IsWindows())
return;
sys_getppid_nt_extract(getenv("_COSMO_PPID"));
}
textwindows int sys_getppid_nt(void) {
if (sys_getppid_nt_cosmo)
return sys_getppid_nt_cosmo;
return sys_getppid_nt_ntdll();
}
textwindows void sys_getppid_nt_wipe(int win32, int cosmo) {
sys_getppid_nt_win32 = win32;
sys_getppid_nt_cosmo = cosmo;
}

View file

@ -22,7 +22,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h"

View file

@ -29,7 +29,7 @@
#include "libc/nt/struct/iocounters.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/errfuns.h"

View file

@ -19,7 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
// retrieves handle of process
// supports only current process and processes we created

View file

@ -33,7 +33,7 @@
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__

View file

@ -51,6 +51,7 @@
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h"
@ -58,7 +59,8 @@
#include "libc/proc/ntspawn.h"
#include "libc/proc/posix_spawn.h"
#include "libc/proc/posix_spawn.internal.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
@ -396,6 +398,14 @@ static textwindows errno_t posix_spawn_nt_impl(
}
FormatUint64(stpcpy(maskvar, "_MASK="), childmask);
// inherit parent process id
char ppidvar[12 + 21 + 1 + 21 + 1], *p = ppidvar;
p = stpcpy(p, "_COSMO_PPID=");
p = FormatUint64(p, GetCurrentProcessId());
*p++ = ':';
p = FormatUint64(p, __pid);
setenv("_COSMO_PPID", ppidvar, true);
// launch process
int rc = -1;
struct NtProcessInformation procinfo;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/proc/proc.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
@ -47,7 +48,6 @@
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
@ -67,9 +67,8 @@
#define STACK_SIZE 65536
struct Procs __proc = {
.lock = PTHREAD_MUTEX_INITIALIZER,
};
struct Procs __proc;
static pthread_mutex_t __proc_lock_obj = PTHREAD_MUTEX_INITIALIZER;
textwindows static void __proc_stats(int64_t h, struct rusage *ru) {
bzero(ru, sizeof(*ru));
@ -258,14 +257,14 @@ textwindows static void __proc_setup(void) {
*/
textwindows void __proc_lock(void) {
cosmo_once(&__proc.once, __proc_setup);
_pthread_mutex_lock(&__proc.lock);
_pthread_mutex_lock(&__proc_lock_obj);
}
/**
* Unlocks process tracker.
*/
textwindows void __proc_unlock(void) {
_pthread_mutex_unlock(&__proc.lock);
_pthread_mutex_unlock(&__proc_lock_obj);
}
/**
@ -273,10 +272,8 @@ textwindows void __proc_unlock(void) {
*/
textwindows void __proc_wipe_and_reset(void) {
// TODO(jart): Should we preserve this state in forked children?
pthread_mutex_t lock = __proc.lock;
_pthread_mutex_wipe_np(&__proc_lock_obj);
bzero(&__proc, sizeof(__proc));
__proc.lock = lock;
_pthread_mutex_wipe_np(&__proc.lock);
}
/**

View file

@ -27,7 +27,6 @@ struct Proc {
struct Procs {
int waiters;
atomic_uint once;
pthread_mutex_t lock;
intptr_t thread;
intptr_t onbirth;
intptr_t haszombies;
@ -41,16 +40,16 @@ struct Procs {
extern struct Procs __proc;
void __proc_lock(void) dontthrow;
void __proc_unlock(void) dontthrow;
int64_t __proc_handle(int) libcesque;
int64_t __proc_search(int) libcesque;
struct Proc *__proc_new(void) libcesque;
void __proc_add(struct Proc *) libcesque;
void __proc_free(struct Proc *) libcesque;
void __proc_wipe_and_reset(void) libcesque;
int __proc_harvest(struct Proc *, bool) libcesque;
int sys_wait4_nt(int, int *, int, struct rusage *) libcesque;
void __proc_lock(void);
void __proc_unlock(void);
int64_t __proc_handle(int);
int64_t __proc_search(int);
struct Proc *__proc_new(void);
void __proc_add(struct Proc *);
void __proc_free(struct Proc *);
void __proc_wipe_and_reset(void);
int __proc_harvest(struct Proc *, bool);
int sys_wait4_nt(int, int *, int, struct rusage *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_PROC_H_ */

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h"
static dontinline textwindows int sys_sched_setaffinity_nt(

View file

@ -23,7 +23,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h"

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
@ -27,25 +28,22 @@
#include "libc/nt/events.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
static textwindows int __proc_reap(struct Proc *pr, int *wstatus,
textwindows static int __proc_reap(struct Proc *pr, int *wstatus,
struct rusage *opt_out_rusage) {
if (wstatus) {
if (wstatus)
*wstatus = pr->wstatus;
}
if (opt_out_rusage) {
if (opt_out_rusage)
*opt_out_rusage = pr->ru;
}
dll_remove(&__proc.zombies, &pr->elem);
if (dll_is_empty(__proc.zombies)) {
if (dll_is_empty(__proc.zombies))
ResetEvent(__proc.haszombies);
}
if (pr->waiters) {
pr->status = PROC_UNDEAD;
dll_make_first(&__proc.undead, &pr->elem);
@ -56,19 +54,18 @@ static textwindows int __proc_reap(struct Proc *pr, int *wstatus,
return pr->pid;
}
static textwindows int __proc_check(int pid, int *wstatus,
textwindows static int __proc_check(int pid, int *wstatus,
struct rusage *opt_out_rusage) {
struct Dll *e;
for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, e)) {
struct Proc *pr = PROC_CONTAINER(e);
if (pid == -1 || pid == pr->pid) {
if (pid == -1 || pid == pr->pid)
return __proc_reap(pr, wstatus, opt_out_rusage);
}
}
return 0;
}
static textwindows int __proc_wait(int pid, int *wstatus, int options,
textwindows static int __proc_wait(int pid, int *wstatus, int options,
struct rusage *rusage, sigset_t waitmask) {
for (;;) {
@ -134,14 +131,18 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// perform blocking operation
uint32_t wi;
uintptr_t event;
struct PosixThread *pt = _pthread_self();
pt->pt_blkmask = waitmask;
pt->pt_event = event = CreateEvent(0, 0, 0, 0);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, event}, 0, -1u);
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
CloseHandle(event);
if ((event = CreateEvent(0, 0, 0, 0))) {
struct PosixThread *pt = _pthread_self();
pt->pt_event = event;
pt->pt_blkmask = waitmask;
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, event}, 0, -1u);
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
CloseHandle(event);
} else {
wi = -1u;
}
// log warning if handle unexpectedly closed
if (wi & kNtWaitAbandoned) {
@ -159,9 +160,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// check if killed or win32 error
if (wi) {
if (pr) {
if (!--pr->waiters && pr->status == PROC_UNDEAD) {
if (!--pr->waiters && pr->status == PROC_UNDEAD)
__proc_free(pr);
}
} else {
--__proc.waiters;
}
@ -178,17 +178,15 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// handle process exit notification
--pr->waiters;
if (pr->status == PROC_ALIVE) {
if (pr->status == PROC_ALIVE)
__proc_harvest(pr, true);
}
switch (pr->status) {
case PROC_ALIVE:
// exit caused by execve() reparenting
__proc_unlock();
if (!pr->waiters) {
if (!pr->waiters)
// avoid deadlock that could theoretically happen
SetEvent(__proc.onbirth);
}
__proc_unlock();
break;
case PROC_ZOMBIE:
// exit happened and we're the first to know
@ -197,9 +195,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
return rc;
case PROC_UNDEAD:
// exit happened but another thread waited first
if (!pr->waiters) {
if (!pr->waiters)
__proc_free(pr);
}
__proc_unlock();
return echild();
default:

View file

@ -21,7 +21,7 @@
#include "libc/calls/struct/rusage.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h"
/**

View file

@ -30,18 +30,18 @@
// @param 8(rsp) x6 is arg
// @return tid of child on success, or -errno on error
sys_clone_linux:
beg
pro
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
push %rbx
cpush %rbx
mov %rcx,%r10
mov 16(%rbp),%rbx
mov $56,%eax // __NR_clone
syscall
test %rax,%rax
jz 2f
0: pop %rbx
pop %rbp
0: cpop %rbx
epi
ret
2: xor %ebp,%ebp // child thread
mov %rbx,%rdi // arg
@ -50,15 +50,13 @@ sys_clone_linux:
mov $60,%eax // __NR_exit(exitcode)
syscall
#elif defined(__aarch64__)
stp x29,x30,[sp,#-16]!
mov x29,sp
mov x8,x3 // swap x3 and x4
mov x3,x4 // swap x3 and x4
mov x4,x8 // swap x3 and x4
mov x8,#220 // __NR_clone
svc #0
cbz x0,2f
ldp x29,x30,[sp],#16
epi
ret
2: mov x29,#0 // wipe backtrace
mov x28,x3 // set cosmo tls
@ -69,4 +67,5 @@ sys_clone_linux:
#else
#error "unsupported architecture"
#endif
end
.endfn sys_clone_linux,globl,hidden

View file

@ -32,8 +32,8 @@
// @param rdx is environ
// @param rcx is auxv
// @noreturn
cosmo: push %rbp
mov %rsp,%rbp
cosmo: beg
pro
mov %edi,%r12d
mov %rsi,%r13
mov %rdx,%r14
@ -104,7 +104,10 @@ cosmo: push %rbp
je 2f
push %rax
push %rax
call .Largs
mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
call *(%rax)
pop %rax
pop %rax
@ -112,17 +115,15 @@ cosmo: push %rbp
jmp 1b
// call main()
2: call .Largs
2: mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
.weak main
call main
xchg %eax,%edi
call exit
.Largs: mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
ret
end
.endfn cosmo,weak
// Enables Thread Local Storage.

View file

@ -28,8 +28,12 @@ ftrace_hook:
cmpl $0,__ftrace(%rip)
jle 1f
.cfi_startproc
push %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
mov %rsp,%rbp
.cfi_def_cfa_register %rbp
and $-16,%rsp
sub $128,%rsp
movdqu %xmm0,-0x80(%rbp)
@ -41,13 +45,21 @@ ftrace_hook:
movdqu %xmm6,-0x20(%rbp)
movdqu %xmm7,-0x10(%rbp)
push %rax
.cfi_offset %rax, -24
push %rcx
.cfi_offset %rcx, -32
push %rdx
.cfi_offset %rdx, -40
push %rdi
.cfi_offset %rdi, -48
push %rsi
.cfi_offset %rsi, -56
push %r8
.cfi_offset %r8, -64
push %r9
.cfi_offset %r9, -72
push %r10
.cfi_offset %r10, -80
call ftracer
movdqu -0x80(%rbp),%xmm0
movdqu -0x70(%rbp),%xmm1
@ -66,12 +78,20 @@ ftrace_hook:
pop %rcx
pop %rax
leave
.cfi_restore %rbp
.cfi_def_cfa %rsp, 8
1: ret
.cfi_endproc
#elif defined(__aarch64__)
stp x29,x30,[sp,-384]!
.cfi_startproc
.cfi_def_cfa_offset 384
.cfi_offset 29, -384 // x29 (fp) is saved at [sp - 384]
.cfi_offset 30, -376 // x30 (lr) is saved at [sp - 376]
mov x29,sp
.cfi_def_cfa_register 29
stp x0,x1,[sp,16]
adrp x0,__ftrace
@ -80,18 +100,45 @@ ftrace_hook:
ble 1f
stp x2,x3,[sp,32]
.cfi_offset 2, -352
.cfi_offset 3, -344
stp x4,x5,[sp,48]
.cfi_offset 4, -336
.cfi_offset 5, -328
stp x6,x7,[sp,64]
.cfi_offset 6, -320
.cfi_offset 7, -312
stp x8,x9,[sp,80]
.cfi_offset 8, -304
.cfi_offset 9, -296
stp x10,x11,[sp,96]
.cfi_offset 10, -288
.cfi_offset 11, -280
stp x12,x13,[sp,112]
.cfi_offset 12, -272
.cfi_offset 13, -264
stp x14,x15,[sp,128]
.cfi_offset 14, -256
.cfi_offset 15, -248
stp x16,x19,[sp,160]
.cfi_offset 16, -224
.cfi_offset 19, -216
stp x20,x21,[sp,176]
.cfi_offset 20, -208
.cfi_offset 21, -200
stp x22,x23,[sp,192]
.cfi_offset 22, -192
.cfi_offset 23, -184
stp x24,x25,[sp,208]
.cfi_offset 24, -176
.cfi_offset 25, -168
stp x26,x27,[sp,224]
.cfi_offset 26, -160
.cfi_offset 27, -152
stp x17,x28,[sp,240]
.cfi_offset 17, -144
.cfi_offset 28, -136
// No CFI directives needed for FP registers
stp q0,q1,[sp,256]
stp q2,q3,[sp,288]
stp q4,q5,[sp,320]
@ -119,7 +166,12 @@ ftrace_hook:
1: ldp x0,x1,[sp,16]
ldp x29,x30,[sp],384
.cfi_restore 29
.cfi_restore 30
.cfi_def_cfa 7, 0 // On some ARM systems the stack pointer is represented by register 7
.cfi_def_cfa_offset 0
ret
.cfi_endproc
#endif /* __x86_64__ */
.endfn ftrace_hook,globl,hidden

View file

@ -24,12 +24,13 @@
#include "libc/intrin/kprintf.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
__msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__funline void __morph_mprotect(void *addr, size_t size, int prot, int ntprot) {
#ifdef __x86_64__
@ -54,7 +55,7 @@ __funline void __morph_mprotect(void *addr, size_t size, int prot, int ntprot) {
}
#endif
} else {
__imp_VirtualProtect(addr, size, ntprot, &op);
__imp_VirtualProtectEx(GetCurrentProcess(), addr, size, ntprot, &op);
}
#elif defined(__aarch64__)
register long r0 asm("x0") = (long)addr;

View file

@ -83,7 +83,6 @@ extern uint64_t kStartTsc;
extern const char kNtSystemDirectory[];
extern const char kNtWindowsDirectory[];
extern size_t __virtualmax;
extern size_t __virtualsize;
extern size_t __stackmax;
extern bool32 __isworker;
/* utilities */

View file

@ -79,7 +79,7 @@ __msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode;
__msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP;
__msabi extern typeof(SetEnvironmentVariable) *const __imp_SetEnvironmentVariableW;
__msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle;
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
__msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
// clang-format on
@ -206,11 +206,12 @@ abi wontreturn static void WinInit(const char16_t *cmdline) {
int stackprot = (intptr_t)ape_stack_prot;
if (~stackprot & PROT_EXEC) {
uint32_t old;
__imp_VirtualProtect(stackaddr, stacksize, kNtPageReadwrite, &old);
__imp_VirtualProtectEx(GetCurrentProcess(), stackaddr, stacksize,
kNtPageReadwrite, &old);
}
uint32_t oldattr;
__imp_VirtualProtect(stackaddr, GetGuardSize(),
kNtPageReadwrite | kNtPageGuard, &oldattr);
__imp_VirtualProtectEx(GetCurrentProcess(), stackaddr, GetGuardSize(),
kNtPageReadwrite | kNtPageGuard, &oldattr);
if (_weaken(__maps_stack)) {
struct NtSystemInfo si;
__imp_GetSystemInfo(&si);

View file

@ -18,13 +18,19 @@
*/
#include "libc/sock/ifaddrs.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h"
#include "libc/sock/struct/sockaddr6.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/iff.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h"
@ -36,6 +42,20 @@ struct IfAddr {
struct sockaddr_in bstaddr;
};
struct IfAddr6Info {
int addr_scope;
int addr_flags;
};
struct IfAddr6 {
struct ifaddrs ifaddrs;
char name[IFNAMSIZ];
struct sockaddr_in6 addr;
struct sockaddr_in6 netmask;
struct sockaddr_in6 bstaddr; // unused
struct IfAddr6Info info;
};
/**
* Frees network interface address list.
*/
@ -48,6 +68,73 @@ void freeifaddrs(struct ifaddrs *ifp) {
}
}
// hex repr to network order int
static uint128_t hex2no(const char *str) {
uint128_t res = 0;
const int max_quads = sizeof(uint128_t) * 2;
int i = 0;
while ((i < max_quads) && str[i]) {
uint8_t acc = (((str[i] & 0xF) + (str[i] >> 6)) | ((str[i] >> 3) & 0x8));
acc = acc << 4;
i += 1;
if (str[i]) {
acc = acc | (((str[i] & 0xF) + (str[i] >> 6)) | ((str[i] >> 3) & 0x8));
i += 1;
}
res = (res >> 8) | (((uint128_t)acc) << ((sizeof(uint128_t) - 1) * 8));
}
res = res >> ((max_quads - i) * 4);
return res;
}
/**
* Gets network interface IPv6 address list on linux.
*
* @return 0 on success, or -1 w/ errno
*/
static int getifaddrs_linux_ip6(struct ifconf *conf) {
int fd;
int n = 0;
struct ifreq *ifreq = conf->ifc_req;
const int bufsz = 44 + IFNAMSIZ + 1;
char buf[bufsz + 1]; // one line max size
if ((fd = sys_openat(0, "/proc/net/if_inet6", O_RDONLY, 0)) == -1) {
return -1;
}
while ((n = sys_read(fd, &buf[n], bufsz - n)) &&
((char *)ifreq < (conf->ifc_buf + conf->ifc_len))) {
// flags linux include/uapi/linux/if_addr.h:44
// scope linux include/net/ipv6.h:L99
// *addr, *index, *plen, *scope, *flags, *ifname
char *s[] = {&buf[0], &buf[33], &buf[36], &buf[39], &buf[42], &buf[45]};
int ifnamelen = 0;
while (*s[5] == ' ') {
++s[5];
}
while (s[5][ifnamelen] > '\n') {
++ifnamelen;
}
buf[32] = buf[35] = buf[38] = buf[41] = buf[44] = s[5][ifnamelen] = '\0';
bzero(ifreq, sizeof(*ifreq));
ifreq->ifr_addr.sa_family = AF_INET6;
memcpy(&ifreq->ifr_name, s[5], ifnamelen);
*((uint128_t *)&ifreq->ifr6_addr) = hex2no(s[0]);
ifreq->ifr6_ifindex = hex2no(s[1]);
ifreq->ifr6_prefixlen = hex2no(s[2]);
ifreq->ifr6_scope = hex2no(s[3]);
ifreq->ifr6_flags = hex2no(s[4]);
++ifreq;
int tlen = &s[5][ifnamelen] - &buf[0] + 1;
n = bufsz - tlen;
memcpy(&buf, &buf[tlen], n);
}
conf->ifc_len = (char *)ifreq - conf->ifc_buf;
return sys_close(fd);
}
/**
* Gets network interface address list.
*
@ -55,6 +142,7 @@ void freeifaddrs(struct ifaddrs *ifp) {
* @see tool/viz/getifaddrs.c for example code
*/
int getifaddrs(struct ifaddrs **out_ifpp) {
// printf("%d\n", sizeof(struct ifreq));
int rc = -1;
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) {
@ -65,42 +153,88 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
conf.ifc_buf = data;
conf.ifc_len = size;
if (!ioctl(fd, SIOCGIFCONF, &conf)) {
if (IsLinux()) {
struct ifconf confl6;
confl6.ifc_buf = data + conf.ifc_len;
confl6.ifc_len = size - conf.ifc_len;
if ((rc = getifaddrs_linux_ip6(&confl6)))
return rc;
conf.ifc_len += confl6.ifc_len;
}
struct ifaddrs *res = 0;
for (struct ifreq *ifr = (struct ifreq *)data;
(char *)ifr < data + conf.ifc_len; ++ifr) {
if (ifr->ifr_addr.sa_family != AF_INET) {
continue; // TODO(jart): IPv6 support
}
struct IfAddr *addr;
if ((addr = calloc(1, sizeof(struct IfAddr)))) {
memcpy(addr->name, ifr->ifr_name, IFNAMSIZ);
addr->ifaddrs.ifa_name = addr->name;
memcpy(&addr->addr, &ifr->ifr_addr, sizeof(struct sockaddr_in));
addr->ifaddrs.ifa_addr = (struct sockaddr *)&addr->addr;
addr->ifaddrs.ifa_netmask = (struct sockaddr *)&addr->netmask;
if (!ioctl(fd, SIOCGIFFLAGS, ifr)) {
addr->ifaddrs.ifa_flags = ifr->ifr_flags;
uint16_t family = ifr->ifr_addr.sa_family;
if (family == AF_INET) {
struct IfAddr *addr;
if ((addr = calloc(1, sizeof(struct IfAddr)))) {
memcpy(addr->name, ifr->ifr_name, IFNAMSIZ);
addr->ifaddrs.ifa_name = addr->name;
memcpy(&addr->addr, &ifr->ifr_addr, sizeof(struct sockaddr_in));
addr->ifaddrs.ifa_addr = (struct sockaddr *)&addr->addr;
addr->ifaddrs.ifa_netmask = (struct sockaddr *)&addr->netmask;
if (!ioctl(fd, SIOCGIFFLAGS, ifr)) {
addr->ifaddrs.ifa_flags = ifr->ifr_flags;
}
if (!ioctl(fd, SIOCGIFNETMASK, ifr)) {
memcpy(&addr->netmask, &ifr->ifr_addr,
sizeof(struct sockaddr_in));
}
unsigned long op;
if (addr->ifaddrs.ifa_flags & IFF_BROADCAST) {
op = SIOCGIFBRDADDR;
} else if (addr->ifaddrs.ifa_flags & IFF_POINTOPOINT) {
op = SIOCGIFDSTADDR;
} else {
op = 0;
}
if (op && !ioctl(fd, op, ifr)) {
memcpy(&addr->bstaddr, &ifr->ifr_addr,
sizeof(struct sockaddr_in));
addr->ifaddrs.ifa_broadaddr = // is union'd w/ ifu_dstaddr
(struct sockaddr *)&addr->bstaddr;
}
addr->ifaddrs.ifa_next = res;
res = (struct ifaddrs *)addr;
}
if (!ioctl(fd, SIOCGIFNETMASK, ifr)) {
memcpy(&addr->netmask, &ifr->ifr_addr,
sizeof(struct sockaddr_in));
} else if (family == AF_INET6) {
struct IfAddr6 *addr6;
if ((addr6 = calloc(1, sizeof(struct IfAddr6)))) {
addr6->ifaddrs.ifa_name = addr6->name;
addr6->ifaddrs.ifa_addr = (struct sockaddr *)&addr6->addr;
addr6->ifaddrs.ifa_netmask = (struct sockaddr *)&addr6->netmask;
addr6->ifaddrs.ifa_broadaddr = (struct sockaddr *)&addr6->bstaddr;
addr6->ifaddrs.ifa_data = (void *)&addr6->info;
memcpy(&addr6->name, &ifr->ifr_name, IFNAMSIZ);
addr6->info.addr_flags = ifr->ifr6_flags;
addr6->info.addr_scope = ifr->ifr6_scope;
addr6->addr.sin6_family = AF_INET6;
addr6->addr.sin6_port = 0;
addr6->addr.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->addr.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr));
addr6->netmask.sin6_family = AF_INET6;
addr6->netmask.sin6_port = 0;
addr6->netmask.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->netmask.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr));
*((uint128_t *)&(addr6->netmask.sin6_addr)) &=
(UINT128_MAX >> ifr->ifr6_prefixlen);
if (!ioctl(fd, SIOCGIFFLAGS, ifr)) {
addr6->ifaddrs.ifa_flags = ifr->ifr_flags;
}
bzero(&addr6->bstaddr, sizeof(struct sockaddr_in6));
addr6->ifaddrs.ifa_next = res;
res = (struct ifaddrs *)addr6;
}
unsigned long op;
if (addr->ifaddrs.ifa_flags & IFF_BROADCAST) {
op = SIOCGIFBRDADDR;
} else if (addr->ifaddrs.ifa_flags & IFF_POINTOPOINT) {
op = SIOCGIFDSTADDR;
} else {
op = 0;
}
if (op && !ioctl(fd, op, ifr)) {
memcpy(&addr->bstaddr, &ifr->ifr_addr,
sizeof(struct sockaddr_in));
addr->ifaddrs.ifa_broadaddr = // is union'd w/ ifu_dstaddr
(struct sockaddr *)&addr->bstaddr;
}
addr->ifaddrs.ifa_next = res;
res = (struct ifaddrs *)addr;
}
}
*out_ifpp = res;

View file

@ -92,9 +92,10 @@ textwindows dontinline static ssize_t sys_sendfile_nt(
}
struct NtOverlapped ov = {.hEvent = WSACreateEvent(), .Pointer = offset};
cosmo_once(&g_transmitfile.once, transmitfile_init);
if (g_transmitfile.lpTransmitFile(oh, ih, uptobytes, 0, &ov, 0, 0) ||
WSAGetLastError() == kNtErrorIoPending ||
WSAGetLastError() == WSAEINPROGRESS) {
if (ov.hEvent &&
(g_transmitfile.lpTransmitFile(oh, ih, uptobytes, 0, &ov, 0, 0) ||
WSAGetLastError() == kNtErrorIoPending ||
WSAGetLastError() == WSAEINPROGRESS)) {
if (WSAGetOverlappedResult(oh, &ov, &uptobytes, true, &flags)) {
rc = uptobytes;
if (opt_in_out_inoffset) {

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_
#include "libc/sock/struct/sockaddr.h"
#include "libc/sock/struct/sockaddr6.h"
COSMOPOLITAN_C_START_
#define IF_NAMESIZE 16
@ -11,6 +12,14 @@ struct ifreq {
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn;
union {
struct {
uint16_t sa_family;
uint16_t ifr6_ifindex; /* Interface index */
uint16_t ifr6_flags; /* Flags */
uint8_t ifr6_scope; /* Addr scope */
uint8_t ifr6_prefixlen; /* Prefix length */
struct in6_addr ifr6_addr;
} in6;
struct sockaddr ifru_addr; /* SIOCGIFADDR */
struct sockaddr ifru_dstaddr; /* SIOCGIFDSTADDR */
struct sockaddr ifru_netmask; /* SIOCGIFNETMASK */
@ -29,5 +38,11 @@ struct ifreq {
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_ifindex ifr_ifru.ifru_ivalue
#define ifr6_addr ifr_ifru.in6.ifr6_addr /* IP6 Addr */
#define ifr6_scope ifr_ifru.in6.ifr6_scope /* IP6 Addr scope */
#define ifr6_prefixlen ifr_ifru.in6.ifr6_prefixlen /* IP6 Prefix length */
#define ifr6_ifindex ifr_ifru.in6.ifr6_ifindex /* IP6 If index */
#define ifr6_flags ifr_ifru.in6.ifr6_flags /* IP6 If flags */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ */

View file

@ -21,6 +21,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/errfuns.h"
int sys_getentropy(void *, size_t) asm("sys_getrandom");
@ -39,6 +40,8 @@ int getentropy(void *p, size_t n) {
rc = eio();
} else if ((!p && n)) {
rc = efault();
} else if (IsXnuSilicon()) {
rc = __syslib->__getentropy(p, n);
} else if (IsXnu() || IsOpenbsd()) {
rc = sys_getentropy(p, n);
} else {

View file

@ -1981,4 +1981,4 @@ syscon misc UL_SETFSIZE 2 2 2 2 2 0 0 0
syscon misc XATTR_CREATE 1 1 2 2 0 0 0 0
syscon misc XATTR_REPLACE 2 2 4 4 0 0 0 0
# https://youtu.be/GUQUD3IMbb4?t=85
# https://youtu.be/3SNBXoWs4GM

View file

@ -102,8 +102,8 @@ __pid: .quad 0
.previous
systemfive_cp:
push %rbp
mov %rsp,%rbp // so backtraces work
beg
pro
systemfive_cancellable: // our pthread_cancel() miracle code
cmpb $0,__tls_enabled(%rip) // inspired by the musl libc design!
je 1f // we handle linux and bsd together!
@ -123,7 +123,7 @@ systemfive_cancellable: // our pthread_cancel() miracle code
clc // no cancellable system calls exist
syscall // that have 7+ args on the bsd OSes
systemfive_cancellable_end: // i/o calls park here for long time
pop %rbp
epi
jnc 2f
neg %rax // turns bsd errno to system v errno
2: cmp $-4095,%rax // but we still check again on eintr
@ -144,11 +144,13 @@ systemfive_cancellable_end: // i/o calls park here for long time
je systemfive_errno // we aren't actually cancelled
jmp 4f // now we are in fact cancelled
systemfive_cancel: // SIGTHR will jump here too
pop %rbp
epi
4: jmp _pthread_cancel_ack // tail call
.weak _pthread_cancel_ack // must be linked if we're cancelled
end
#if IsModeDbg()
not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
beg
nop
.weak report_cancellation_point
5: ezlea report_cancellation_point,cx
@ -157,6 +159,7 @@ not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
call *%rcx
6: ud2
nop
end
#endif
.globl systemfive_cancellable_end
.globl systemfive_cancellable
@ -166,19 +169,20 @@ not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
.Lanchorpoint:
#if SupportsLinux() || SupportsMetal()
systemfive_linux:
beg
and $0xfff,%eax // remove nonlinux bits from ordinal
cmp $0xfff,%eax // checks if unsupported by platform
je systemfive_enosys // never taken branches cost nothing
btr $11,%eax // 0x800 means a call is cancellable
jc systemfive_cp // it is handled by the holiest code
mov %rcx,%r10 // syscall instruction clobbers %rcx
push %rbp // linux never reads args from stack
mov %rsp,%rbp // having frame will help backtraces
pro // linux never reads args from stack
syscall // this is known as a context switch
pop %rbp // next we check to see if it failed
epi // next we check to see if it failed
cmp $-4095,%rax // system five nexgen32e abi § a.2.1
jae systemfive_error // encodes errno as neg return value
ret
end
.endfn systemfive_linux,globl,hidden
systemfive_error:
neg %eax
@ -186,27 +190,35 @@ systemfive_error:
.endfn systemfive_error,globl,hidden
#endif
systemfive_errno:
beg
xchg %eax,%ecx
call __errno_location
mov %ecx,(%rax) // normalize to c library convention
push $-1 // negative one is only error result
pop %rax // the push pop is to save code size
ret
end
.endfn systemfive_errno,globl,hidden
systemfive_enosys:
beg
mov ENOSYS(%rip),%eax
jmp systemfive_errno
end
.endfn systemfive_enosys,globl,hidden
#if SupportsNetbsd()
systemfive_netbsd:
beg
shr $4*13,%rax
jmp systemfive_bsdscrub
end
.endfn systemfive_netbsd,globl,hidden
#endif
#if SupportsOpenbsd()
systemfive_openbsd:
beg
shr $4*10,%rax
jmp systemfive_bsdscrub
end
.endfn systemfive_openbsd,globl,hidden
#endif
#if SupportsFreebsd()
@ -222,6 +234,7 @@ systemfive_bsdscrub:
// 𝑠𝑙𝑖𝑑𝑒
.endfn systemfive_bsdscrub,globl,hidden
systemfive_bsd:
beg
cmp $0xfff,%ax
je systemfive_enosys
btr $11,%eax // checks/reset the 800 cancellable bit
@ -230,6 +243,7 @@ systemfive_bsd:
syscall // bsd will need arg on stack sometimes
jc systemfive_errno // bsd sets carry flag if %rax is errno
ret
end
.endfn systemfive_bsd
#endif
#if SupportsXnu()

View file

@ -215,6 +215,7 @@ LIBC_TESTMAIN_DIRECTDEPS = \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_PROC \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_SYSV \
@ -222,7 +223,7 @@ LIBC_TESTMAIN_DIRECTDEPS = \
LIBC_TESTLIB \
LIBC_TESTLIB_RUNNER \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GETOPT
THIRD_PARTY_GETOPT \
LIBC_TESTMAIN_DEPS := \
$(call uniq,$(foreach x,$(LIBC_TESTMAIN_DIRECTDEPS),$($(x))))

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
@ -31,6 +32,7 @@
#include "libc/intrin/strace.h"
#include "libc/intrin/ubsan.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/leaks.h"
@ -52,6 +54,8 @@
#include "libc/thread/tls.h"
#include "third_party/getopt/getopt.internal.h"
#pragma weak main
#define USAGE \
" [FLAGS]\n\
\n\
@ -88,7 +92,41 @@ static void GetOpts(int argc, char *argv[]) {
}
}
#pragma weak main
static int rando(void) {
return _rand64() & INT_MAX;
}
static void limit_process_to_single_cpu(void) {
extern int disable_limit_process_to_single_cpu;
if (_weaken(disable_limit_process_to_single_cpu))
return;
if (!(IsLinux() || IsFreebsd() || IsNetbsd() || IsWindows()))
return;
if (IsFreebsd() && getuid())
return;
cpu_set_t legal;
if (sched_getaffinity(0, sizeof(cpu_set_t), &legal) == -1) {
perror("sched_setaffinity failed");
exit(1);
}
int count = CPU_COUNT(&legal);
cpu_set_t newset;
CPU_ZERO(&newset);
bool done = false;
while (!done) {
for (int i = 0; i < CPU_SETSIZE; ++i) {
if (CPU_ISSET(i, &legal) && !(rando() % count)) {
CPU_SET(rando() % count, &newset);
done = true;
break;
}
}
}
if (sched_setaffinity(0, sizeof(cpu_set_t), &newset) == -1) {
perror("sched_setaffinity failed");
exit(1);
}
}
/**
* Generic test program main function.
@ -108,8 +146,11 @@ int main(int argc, char *argv[]) {
return 1;
}
// // this sometimes helps tease out mt bugs
// limit_process_to_single_cpu();
// test huge pointers by enabling pml5t
if (_rand64() % 2) {
if (rando() % 2) {
errno_t e = errno;
mmap((char *)0x80000000000000, 1, PROT_NONE, //
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

View file

@ -23,17 +23,36 @@
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/thread.h"
/**
* Returns true if signal is most likely a stack overflow.
* Returns true if signal is caused by stack overflow.
*/
char __is_stack_overflow(siginfo_t *si, void *arg) {
// sanity check
ucontext_t *uc = arg;
if (!si || !uc)
return false;
if (si->si_signo != SIGSEGV && si->si_signo != SIGBUS)
if (si->si_signo != SIGSEGV && //
si->si_signo != SIGBUS)
return false;
intptr_t sp = uc->uc_mcontext.SP;
intptr_t fp = (intptr_t)si->si_addr;
return ABS(fp - sp) < __pagesize;
// get stack information
pthread_attr_t attr;
if (pthread_getattr_np(pthread_self(), &attr))
return false;
size_t guardsize;
if (pthread_attr_getguardsize(&attr, &guardsize))
return false;
void *stackaddr;
size_t stacksize;
if (pthread_attr_getstack(&attr, &stackaddr, &stacksize))
return false;
// determine if faulting address is inside guard region
char *x = (char *)si->si_addr;
char *lo = (char *)stackaddr - guardsize;
char *hi = (char *)stackaddr;
return lo <= x && x < hi;
}

Some files were not shown because too many files have changed in this diff Show more