Compare commits

..

No commits in common. "master" and "3.9.7" have entirely different histories.

471 changed files with 6481 additions and 10374 deletions

View file

@ -1,8 +1,5 @@
name: build
env:
COSMOCC_VERSION: 3.9.2
on:
push:
branches:
@ -22,48 +19,13 @@ jobs:
matrix:
mode: ["", tiny, rel, tinylinux, optlinux]
steps:
- 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
- uses: actions/checkout@v3
- name: support ape bins 1
run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
run: sudo cp 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 }}

1
.gitignore vendored
View file

@ -15,4 +15,3 @@ __pycache__
/tool/emacs/*.elc
/perf.data
/perf.data.old
/qemu*core

View file

@ -77,8 +77,7 @@ COMMA := ,
PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran .cosmocc/current/bin/make, in which case make's working directory
# is in wsl
# - user ran build/bootstrap/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)
@ -90,7 +89,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 https://cosmo.zip/pub/cosmos/bin/make)
$(error please use build/bootstrap/make)
endif
LC_ALL = C
@ -136,7 +135,7 @@ ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10 luna
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
endif
ZIPOBJ_FLAGS += -a$(ARCH)

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/C++
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes 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,22 +87,15 @@ ape/apeinstall.sh
```
You can now build the mono repo with any modern version of GNU Make. To
bootstrap your build, you can install Cosmopolitan Make from this site:
https://cosmo.zip/pub/cosmos/bin/make
E.g.:
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.
```sh
curl -LO https://cosmo.zip/pub/cosmos/bin/make
./make -j8
build/bootstrap/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
@ -110,7 +103,7 @@ depends on core LIBC packages.
```sh
rm -rf o//libc o//test
.cosmocc/current/bin/make o//test/posix/signal_test
build/bootstrap/make o//test/posix/signal_test
o//test/posix/signal_test
```
@ -119,21 +112,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
.cosmocc/current/bin/make o//test/posix
build/bootstrap/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
.cosmocc/current/bin/make m=tiny
build/bootstrap/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
.cosmocc/current/bin/make m=tinylinux
build/bootstrap/make m=tinylinux
```
For further details, see [//build/config.mk](build/config.mk).

View file

@ -259,9 +259,6 @@ 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,13 +386,6 @@ 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()
@ -433,6 +426,11 @@ 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.*)))
@ -441,6 +439,7 @@ SECTIONS {
KEEP(*(.piro.pad.data))
*(.igot.plt)
KEEP(*(.dataepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */
_edata = .;
@ -520,9 +519,6 @@ 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) }
@ -586,11 +582,11 @@ ape_rom_memsz = ape_rom_filesz;
ape_rom_align = CONSTANT(COMMONPAGESIZE);
ape_rom_rva = RVA(ape_rom_vaddr);
ape_ram_vaddr = ADDR(.eh_frame);
ape_ram_vaddr = ADDR(.data);
ape_ram_offset = ape_ram_vaddr - __executable_start;
ape_ram_paddr = LOADADDR(.eh_frame);
ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
ape_ram_memsz = _end - ADDR(.eh_frame);
ape_ram_paddr = LOADADDR(.data);
ape_ram_filesz = ADDR(.bss) - ADDR(.data);
ape_ram_memsz = _end - ADDR(.data);
ape_ram_align = CONSTANT(COMMONPAGESIZE);
ape_ram_rva = RVA(ape_ram_vaddr);
@ -600,7 +596,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 : 4 * 1024 * 1024;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 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 .cosmocc/current/bin/make ]; then
MAKE=.cosmocc/current/bin/make
if [ -x build/bootstrap/make ]; then
MAKE=build/bootstrap/make
else
MAKE=make
fi

View file

@ -99,8 +99,3 @@ 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 __atomic_load_n(&shared, __ATOMIC_RELAXED) + 1;
return shared + 1;
}
size_t weak_count() const noexcept
{
return __atomic_load_n(&weak, __ATOMIC_RELAXED);
return weak;
}
private:
@ -349,7 +349,7 @@ class shared_ptr
template<typename U>
bool owner_before(const weak_ptr<U>& r) const noexcept
{
return rc < r.rc;
return !r.owner_before(*this);
}
private:
@ -382,34 +382,6 @@ 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)
@ -438,19 +410,6 @@ 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

@ -337,7 +337,7 @@ int main(int argc, char *argv[]) {
sigaddset(&block, SIGQUIT);
pthread_attr_t attr;
unassert(!pthread_attr_init(&attr));
unassert(!pthread_attr_setstacksize(&attr, 65536 - getpagesize()));
unassert(!pthread_attr_setstacksize(&attr, 65536));
unassert(!pthread_attr_setguardsize(&attr, getpagesize()));
unassert(!pthread_attr_setsigmask_np(&attr, &block));
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));

View file

@ -1,322 +0,0 @@
#/*────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#include <ctype.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
/**
* @fileoverview cosmopolitan flash cards viewer
*/
struct Card {
char* qa[2];
};
atomic_int g_done;
void onsig(int sig) {
g_done = 1;
}
void* xmalloc(int n) {
void* p;
if ((p = malloc(n)))
return p;
perror("malloc");
exit(1);
}
void* xrealloc(void* p, int n) {
if ((p = realloc(p, n)))
return p;
perror("realloc");
exit(1);
}
char* xstrcat(const char* a, const char* b) {
char* p;
size_t n, m;
n = strlen(a);
m = strlen(b);
p = xmalloc(n + m + 1);
memcpy(p, a, n);
memcpy(p + n, b, m + 1);
return p;
}
void shuffle(struct Card* a, int n) {
while (n > 1) {
int i = rand() % n--;
struct Card t = a[i];
a[i] = a[n];
a[n] = t;
}
}
char* trim(char* s) {
int i;
if (s) {
while (isspace(*s))
++s;
for (i = strlen(s); i--;) {
if (isspace(s[i])) {
s[i] = 0;
} else {
break;
}
}
}
return s;
}
char* readline(FILE* f) {
for (;;) {
char* line = trim(fgetln(f, 0));
if (!line)
return 0;
if (*line != '#')
if (*line)
return line;
}
}
char* fill(const char* text, int max_line_width, int* out_line_count) {
int text_len = strlen(text);
char* result = xmalloc(text_len * 2 + 1);
int result_pos = 0;
int line_start = 0;
int line_count = 1;
int i = 0;
while (i < text_len && isspace(text[i]))
i++;
while (i < text_len) {
int word_end = i;
while (word_end < text_len && !isspace(text[word_end]))
word_end++;
int word_length = word_end - i;
if ((result_pos - line_start) + (result_pos > line_start ? 1 : 0) +
word_length >
max_line_width) {
if (result_pos > line_start) {
++line_count;
result[result_pos++] = '\n';
line_start = result_pos;
}
} else if (result_pos > line_start) {
result[result_pos++] = ' ';
}
memcpy(result + result_pos, text + i, word_length);
result_pos += word_length;
i = word_end;
while (i < text_len && isspace(text[i]))
i++;
}
result[result_pos] = '\0';
result = xrealloc(result, result_pos + 1);
if (out_line_count)
*out_line_count = line_count;
return result;
}
void show(const char* text, int i, int n) {
// get pseudoteletypewriter dimensions
struct winsize ws = {80, 25};
tcgetwinsize(1, &ws);
int width = ws.ws_col;
if (width > (int)(ws.ws_col * .9))
width = ws.ws_col * .9;
if (width > 80)
width = 80;
width &= -2;
// clear display
printf("\033[H\033[J");
// display flash card text in middle of display
char buf[32];
int line_count;
char* lines = fill(text, width, &line_count);
sprintf(buf, "%d/%d\r\n\r\n", i + 1, n);
line_count += 2;
char* extra = xstrcat(buf, lines);
free(lines);
char* tokens = extra;
for (int j = 0;; ++j) {
char* line = strtok(tokens, "\n");
tokens = 0;
if (!line)
break;
printf("\033[%d;%dH%s", ws.ws_row / 2 - line_count / 2 + j + 1,
ws.ws_col / 2 - strlen(line) / 2 + 1, line);
}
free(extra);
fflush(stdout);
}
void usage(FILE* f, const char* prog) {
fprintf(f,
"usage: %s FILE\n"
"\n"
"here's an example of what your file should look like:\n"
"\n"
" # cosmopolitan flash cards\n"
" # california dmv drivers test\n"
" \n"
" which of the following point totals could result in "
"your license being suspended by the dmv?\n"
" 4 points in 12 months (middle)\n"
" \n"
" at 55 mph under good conditions a passenger vehicle can stop "
"within\n"
" 300 feet (not 200, not 400, middle)\n"
" \n"
" two sets of solid double yellow lines spaced two or more feet "
"apart indicate\n"
" a BARRIER (do not cross unless there's an opening)\n"
"\n"
"more specifically, empty lines are ignored, lines starting with\n"
"a hash are ignored, then an even number of lines must remain,\n"
"where each two lines is a card, holding question and answer.\n",
prog);
}
int main(int argc, char* argv[]) {
// show help
if (argc != 2) {
usage(stderr, argv[0]);
return 1;
}
if (!strcmp(argv[1], "-?") || //
!strcmp(argv[1], "-h") || //
!strcmp(argv[1], "--help")) {
usage(stdout, argv[0]);
return 0;
}
// teletypewriter is required
if (!isatty(0) || !isatty(1)) {
perror("isatty");
return 2;
}
// load cards
FILE* f = fopen(argv[1], "r");
if (!f) {
perror(argv[1]);
return 3;
}
int count = 0;
struct Card* cards = 0;
for (;;) {
struct Card card;
if (!(card.qa[0] = readline(f)))
break;
card.qa[0] = strdup(card.qa[0]);
if (!(card.qa[1] = readline(f))) {
fprintf(stderr, "%s: flash card file has odd number of lines\n", argv[1]);
exit(1);
}
card.qa[1] = strdup(card.qa[1]);
cards = xrealloc(cards, (count + 1) * sizeof(struct Card));
cards[count++] = card;
}
fclose(f);
// randomize
srand(time(0));
shuffle(cards, count);
// catch ctrl-c
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = onsig;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
// enter raw mode
struct termios ot;
tcgetattr(1, &ot);
struct termios nt = ot;
cfmakeraw(&nt);
nt.c_lflag |= ISIG;
tcsetattr(1, TCSANOW, &nt);
printf("\033[?25l");
// show flash cards
int i = 0;
while (!g_done) {
show(cards[i / 2].qa[i % 2], i / 2, count);
// press any key
char b[8] = {0};
read(0, b, sizeof(b));
// q quits
if (b[0] == 'q')
break;
// b or ctrl-b goes backward
if (b[0] == 'b' || //
b[0] == ('B' ^ 0100)) {
if (--i < 0)
i = count * 2 - 1;
i &= -2;
continue;
}
// p or ctrl-p goes backward
if (b[0] == 'p' || //
b[0] == ('P' ^ 0100)) {
if (--i < 0)
i = count * 2 - 1;
i &= -2;
continue;
}
// up arrow goes backward
if (b[0] == 033 && //
b[1] == '[' && //
b[2] == 'A') {
if (--i < 0)
i = count * 2 - 1;
i &= -2;
continue;
}
// left arrow goes backward
if (b[0] == 033 && //
b[1] == '[' && //
b[2] == 'D') {
if (--i < 0)
i = count * 2 - 1;
i &= -2;
continue;
}
// only advance
if (++i == count * 2)
i = 0;
}
// free memory
for (int i = 0; i < count; ++i)
for (int j = 0; j < 2; ++j)
free(cards[i].qa[j]);
free(cards);
// cleanup terminal and show cursor
tcsetattr(1, TCSANOW, &ot);
printf("\033[?25h");
printf("\n");
}

View file

@ -7,13 +7,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/dce.h"
#include "libc/intrin/maps.h"
#include "libc/mem/alg.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/winargs.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/x/xasprintf.h"
@ -71,18 +67,8 @@ int main(int argc, char *argv[]) {
Append((uintptr_t)&__auxv[i + 1],
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
}
if (!IsWindows()) {
struct AddrSize stak = __get_main_stack();
Append((intptr_t)stak.addr + stak.size, "top of stack");
Append((intptr_t)stak.addr, "bottom of stack");
} else {
#ifdef __x86_64__
Append(GetStaticStackAddr(0) + GetStaticStackSize(), "top of stack");
Append(GetStaticStackAddr(0) + GetGuardSize(), "bottom of stack");
Append(GetStaticStackAddr(0), "bottom of guard region");
#endif
}
qsort(things.p, things.n, sizeof(*things.p), Compare);
for (int i = 0; i < things.n; ++i)
for (int i = 0; i < things.n; ++i) {
printf("%012lx %s\n", things.p[i].i, things.p[i].s);
}
}

View file

@ -1,17 +0,0 @@
#include <pthread.h>
#include <stdio.h>
// how to spawn a thread
void *my_thread(void *arg) {
printf("my_thread(%p) is running\n", arg);
return (void *)0x456L;
}
int main(int argc, char *argv[]) {
void *res;
pthread_t th;
pthread_create(&th, 0, my_thread, (void *)0x123L);
pthread_join(th, &res);
printf("my_thread() returned %p\n", res);
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/atomic.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
@ -24,37 +23,26 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/ntdll.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
static atomic_int usingRes;
static atomic_bool changedRes;
static textwindows int sys_clock_nanosleep_nt_impl(int clock,
struct timespec abs,
sigset_t waitmask) {
struct timespec now, wall;
uint32_t minRes, maxRes, oldRes;
sys_clock_gettime_nt(0, &wall);
if (sys_clock_gettime_nt(clock, &now))
return -1;
bool wantRes = clock == CLOCK_REALTIME || //
clock == CLOCK_MONOTONIC || //
clock == CLOCK_BOOTTIME;
if (wantRes && !atomic_fetch_add(&usingRes, 1))
changedRes = NtSuccess(NtQueryTimerResolution(&minRes, &maxRes, &oldRes)) &&
NtSuccess(NtSetTimerResolution(maxRes, true, &oldRes));
if (timespec_cmp(abs, now) > 0)
wall = timespec_add(wall, timespec_sub(abs, now));
int rc = _park_norestart(wall, waitmask);
if (wantRes && atomic_fetch_sub(&usingRes, 1) == 1 && changedRes)
NtSetTimerResolution(0, false, &minRes);
return rc;
uint32_t msdelay;
struct timespec now;
for (;;) {
if (sys_clock_gettime_nt(clock, &now))
return -1;
if (timespec_cmp(now, abs) >= 0)
return 0;
msdelay = timespec_tomillis(timespec_sub(abs, now));
msdelay = MIN(msdelay, -1u);
if (_park_norestart(msdelay, waitmask) == -1)
return -1;
}
}
textwindows int sys_clock_nanosleep_nt(int clock, int flags,

View file

@ -23,9 +23,9 @@
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
relegated int sys_clock_nanosleep_openbsd(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
int sys_clock_nanosleep_openbsd(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
int res;
struct timespec start, relative, remainder;
if (!flags) {

View file

@ -57,7 +57,6 @@
*
* @param clock may be
* - `CLOCK_REALTIME`
* - `CLOCK_BOOTTIME`
* - `CLOCK_MONOTONIC`
* - `CLOCK_REALTIME_COARSE` but is likely to sleep negative time
* - `CLOCK_MONTONIC_COARSE` but is likely to sleep negative time

View file

@ -51,7 +51,6 @@
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
struct FileLock {
@ -68,9 +67,7 @@ struct FileLocks {
struct FileLock *free;
};
static struct FileLocks g_locks = {
.mu = PTHREAD_MUTEX_INITIALIZER,
};
static struct FileLocks g_locks;
static textwindows struct FileLock *NewFileLock(void) {
struct FileLock *fl;
@ -113,7 +110,7 @@ static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
struct FileLock *fl, *ft, **flp;
_pthread_mutex_lock(&g_locks.mu);
pthread_mutex_lock(&g_locks.mu);
for (flp = &g_locks.list, fl = *flp; fl;) {
if (fl->fd == fd) {
*flp = fl->next;
@ -125,7 +122,7 @@ textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
fl = *flp;
}
}
_pthread_mutex_unlock(&g_locks.mu);
pthread_mutex_unlock(&g_locks.mu);
}
static textwindows int64_t GetfileSize(int64_t handle) {
@ -356,9 +353,9 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
struct Fd *f = g_fds.p + fd;
if (f->cursor) {
_pthread_mutex_lock(&g_locks.mu);
pthread_mutex_lock(&g_locks.mu);
rc = sys_fcntl_nt_lock(f, fd, cmd, arg);
_pthread_mutex_unlock(&g_locks.mu);
pthread_mutex_unlock(&g_locks.mu);
} else {
rc = ebadf();
}

View file

@ -21,23 +21,24 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/cxaatexit.h"
#include "libc/macros.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
#define CTOR __attribute__((__constructor__(99)))
#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32)
static int cpus;
static double load;
static pthread_spinlock_t lock;
static struct NtFileTime idle1, kern1, user1;
textwindows int sys_getloadavg_nt(double *a, int n) {
int i, rc;
uint64_t elapsed, used;
struct NtFileTime idle, kern, user;
__cxa_lock();
BLOCK_SIGNALS;
pthread_spin_lock(&lock);
if (GetSystemTimes(&idle, &kern, &user)) {
elapsed = (FT(kern) - FT(kern1)) + (FT(user) - FT(user1));
if (elapsed) {
@ -53,11 +54,12 @@ textwindows int sys_getloadavg_nt(double *a, int n) {
} else {
rc = __winerr();
}
__cxa_unlock();
pthread_spin_unlock(&lock);
ALLOW_SIGNALS;
return rc;
}
CTOR static textstartup void sys_getloadavg_nt_init(void) {
__attribute__((__constructor__(40))) static textstartup void ntinitload(void) {
if (IsWindows()) {
load = 1;
cpus = __get_cpu_count() / 2;

View file

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

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 2024 Justine Alexandra Roberts Tunney
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
@ -16,14 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nt/memory.h"
#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/runtime.h"
#include "libc/nt/struct/processbasicinformation.h"
/**
* 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);
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();
}

View file

@ -96,8 +96,9 @@ static int OldApeLoader(char *s) {
static int CopyWithCwd(const char *q, char *p, char *e) {
char c;
if (*q != '/') {
if (q[0] == '.' && q[1] == '/')
if (q[0] == '.' && q[1] == '/') {
q += 2;
}
int got = __getcwd(p, e - p - 1 /* '/' */);
if (got != -1) {
p += got - 1;
@ -117,10 +118,9 @@ static int CopyWithCwd(const char *q, char *p, char *e) {
// if q exists then turn it into an absolute path.
static int TryPath(const char *q) {
if (!q)
return 0;
if (!CopyWithCwd(q, g_prog.u.buf, g_prog.u.buf + sizeof(g_prog.u.buf)))
if (!CopyWithCwd(q, g_prog.u.buf, g_prog.u.buf + sizeof(g_prog.u.buf))) {
return 0;
}
return !sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0);
}
@ -129,8 +129,9 @@ static int TryPath(const char *q) {
void __init_program_executable_name(void) {
if (__program_executable_name && *__program_executable_name != '/' &&
CopyWithCwd(__program_executable_name, g_prog.u.buf,
g_prog.u.buf + sizeof(g_prog.u.buf)))
g_prog.u.buf + sizeof(g_prog.u.buf))) {
__program_executable_name = g_prog.u.buf;
}
}
static inline void InitProgramExecutableNameImpl(void) {
@ -211,12 +212,14 @@ static inline void InitProgramExecutableNameImpl(void) {
}
// don't trust argv or envp if set-id.
if (issetugid())
if (issetugid()) {
goto UseEmpty;
}
// try argv[0], then then $_.
if (TryPath(__argv[0]) || TryPath(__getenv(__envp, "_").s))
if (TryPath(__argv[0]) || TryPath(__getenv(__envp, "_").s)) {
goto UseBuf;
}
// give up and just copy argv[0] into it
if ((q = __argv[0])) {

View file

@ -114,8 +114,7 @@ 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()) {
ProcessPrng(p, n); // never fails
rc = n;
rc = ProcessPrng(p, n) ? n : __winerr();
} else if (have_getrandom) {
if (IsXnu() || IsOpenbsd()) {
rc = GetRandomBsd(p, n, GetRandomEntropy);
@ -185,7 +184,9 @@ 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

@ -21,7 +21,6 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/rlimit.h"
#include "libc/intrin/strace.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
@ -48,7 +47,8 @@ int getrlimit(int resource, struct rlimit *rlim) {
} else if (!IsWindows()) {
rc = sys_getrlimit(resource, rlim);
} else if (resource == RLIMIT_STACK) {
*rlim = __rlimit_stack_get();
rlim->rlim_cur = GetStaticStackSize();
rlim->rlim_max = GetStaticStackSize();
rc = 0;
} else if (resource == RLIMIT_AS) {
rlim->rlim_cur = __virtualmax;

View file

@ -3,7 +3,6 @@
#include "libc/atomic.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigval.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/intrin/fds.h"
#include "libc/macros.h"
@ -34,7 +33,6 @@ int64_t GetConsoleOutputHandle(void);
void EchoConsoleNt(const char *, size_t, bool);
int IsWindowsExecutable(int64_t, const char16_t *);
void InterceptTerminalCommands(const char *, size_t);
void sys_read_nt_wipe_keystrokes(void);
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
@ -48,8 +46,8 @@ int _check_signal(bool);
int _check_cancel(void);
bool _is_canceled(void);
int sys_close_nt(int, int);
int _park_norestart(struct timespec, uint64_t);
int _park_restartable(struct timespec, uint64_t);
int _park_norestart(uint32_t, uint64_t);
int _park_restartable(uint32_t, uint64_t);
int sys_openat_metal(int, const char *, int, unsigned);
#ifdef __x86_64__

View file

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

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/proc/ntspawn.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/strace.h"
@ -39,15 +38,12 @@
#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];
@ -67,12 +63,10 @@ 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 = overlap.hEvent &&
(ReadFile(fh, buf, len, 0, &overlap) ||
ok = (ReadFile(fh, buf, len, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(fh, &overlap, &got, true);
if (overlap.hEvent)
__imp_CloseHandle(overlap.hEvent);
CloseHandle(overlap.hEvent);
return ok ? got : -1;
}
@ -92,7 +86,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);
__imp_CloseHandle(fh);
CloseHandle(fh);
if (got < 3)
return enoexec();
pe = p + got;

View file

@ -49,9 +49,11 @@ 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)) {
state = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
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;
if (state == (void *)-1)
return -1;
} else {

View file

@ -19,96 +19,65 @@
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/fmt/wintime.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/events.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#ifdef __x86_64__
// returns 0 if deadline is reached
// returns 0 on timeout or spurious wakeup
// raises EINTR if a signal delivery interrupted wait operation
// raises ECANCELED if this POSIX thread was canceled in masked mode
textwindows static int _park_thread(struct timespec deadline, sigset_t waitmask,
textwindows static int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) {
for (;;) {
uint32_t handl = 0;
intptr_t hands[2];
struct PosixThread *pt = _pthread_self();
// create event object
intptr_t sigev;
if (!(sigev = CreateEvent(0, 0, 0, 0)))
return __winerr();
hands[handl++] = sigev;
// perform the wait operation
intptr_t sigev;
if (!(sigev = CreateEvent(0, 0, 0, 0)))
return __winerr();
pt->pt_event = sigev;
pt->pt_blkmask = waitmask;
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
int sig = 0;
uint32_t ws = 0;
if (!_is_canceled() &&
!(_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))))
ws = WaitForSingleObject(sigev, msdelay);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
CloseHandle(sigev);
// create high precision timer if needed
if (memcmp(&deadline, &timespec_max, sizeof(struct timespec))) {
intptr_t hTimer;
if ((hTimer = CreateWaitableTimer(NULL, true, NULL))) {
int64_t due = TimeSpecToWindowsTime(deadline);
if (SetWaitableTimer(hTimer, &due, 0, NULL, NULL, false)) {
hands[handl++] = hTimer;
} else {
CloseHandle(hTimer);
}
}
}
// perform wait operation
struct PosixThread *pt = _pthread_self();
pt->pt_event = sigev;
pt->pt_blkmask = waitmask;
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
int sig = 0;
uint32_t wi = 0;
if (!_is_canceled() &&
!(_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))))
wi = WaitForMultipleObjects(handl, hands, false, -1u);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
for (int i = 0; i < handl; ++i)
CloseHandle(hands[i]);
// recursion is now safe
if (wi == 1)
return 0;
if (wi == -1u)
return __winerr();
int handler_was_called = 0;
if (!sig) {
if (_check_cancel())
return -1;
if (_weaken(__sig_get))
sig = _weaken(__sig_get)(waitmask);
}
if (sig)
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel())
return -1;
if (handler_was_called & SIG_HANDLED_NO_RESTART)
// recursion is now safe
if (ws == -1u)
return __winerr();
int handler_was_called = 0;
if (sig)
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel())
return -1;
if (handler_was_called & SIG_HANDLED_NO_RESTART)
return eintr();
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (!restartable)
return eintr();
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (!restartable)
return eintr();
}
return 0;
}
textwindows int _park_norestart(struct timespec deadline, sigset_t waitmask) {
return _park_thread(deadline, waitmask, false);
textwindows int _park_norestart(uint32_t msdelay, sigset_t waitmask) {
return _park_thread(msdelay, waitmask, false);
}
textwindows int _park_restartable(struct timespec deadline, sigset_t waitmask) {
return _park_thread(deadline, waitmask, true);
textwindows int _park_restartable(uint32_t msdelay, sigset_t waitmask) {
return _park_thread(msdelay, waitmask, true);
}
#endif /* __x86_64__ */

View file

@ -18,20 +18,21 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/syscall_support-nt.internal.h"
#ifdef __x86_64__
textwindows int sys_pause_nt(void) {
int rc;
// we don't strictly need to block signals, but it reduces signal
// delivery latency, by preventing other threads from delivering a
// signal asynchronously. it takes about ~5us to deliver a signal
// using SetEvent() whereas it takes ~30us to use SuspendThread(),
// GetThreadContext(), SetThreadContext(), and ResumeThread().
BLOCK_SIGNALS;
_park_norestart(timespec_max, 0);
while (!(rc = _park_norestart(-1u, 0)))
donothing;
ALLOW_SIGNALS;
return -1;
return rc;
}
#endif /* __x86_64__ */

View file

@ -694,7 +694,6 @@ 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

@ -318,8 +318,8 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds,
textwindows static int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
struct timespec deadline,
const sigset_t waitmask) {
uint32_t waitms;
int i, n, rc, got = 0;
struct timespec now, next, target;
// we normally don't check for signals until we decide to wait, since
// it's nice to have functions like write() be unlikely to EINTR, but
@ -344,16 +344,9 @@ textwindows static int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
}
if (got)
return got;
now = sys_clock_gettime_monotonic_nt();
if (timespec_cmp(now, deadline) >= 0)
if (!(waitms = sys_poll_nt_waitms(deadline)))
return 0;
next = timespec_add(now, timespec_frommillis(POLL_INTERVAL_MS));
if (timespec_cmp(next, deadline) >= 0) {
target = deadline;
} else {
target = next;
}
if (_park_norestart(target, waitmask) == -1)
if (_park_norestart(waitms, waitmask) == -1)
return -1;
}
}

View file

@ -48,7 +48,6 @@
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/nt/events.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/inputrecord.h"
#include "libc/nt/synchronization.h"
@ -128,46 +127,33 @@ struct Keystrokes {
bool ohno_decckm;
bool bypass_mode;
uint16_t utf16hs;
size_t free_keys;
int16_t freekeys;
int64_t cin, cot;
struct Dll *list;
struct Dll *line;
struct Dll *free;
pthread_mutex_t lock;
struct Keystroke pool[512];
};
static struct Keystrokes __keystroke;
static pthread_mutex_t __keystroke_lock = PTHREAD_MUTEX_INITIALIZER;
textwindows void sys_read_nt_wipe_keystrokes(void) {
textwindows void WipeKeystrokes(void) {
bzero(&__keystroke, sizeof(__keystroke));
_pthread_mutex_wipe_np(&__keystroke_lock);
}
textwindows static void FreeKeystrokeImpl(struct Dll *key) {
dll_make_first(&__keystroke.free, key);
++__keystroke.free_keys;
}
textwindows static struct Keystroke *AllocKeystroke(void) {
struct Keystroke *k;
if (!(k = HeapAlloc(GetProcessHeap(), 0, sizeof(struct Keystroke))))
return 0;
dll_init(&k->elem);
return k;
++__keystroke.freekeys;
}
textwindows static struct Keystroke *NewKeystroke(void) {
struct Dll *e;
struct Keystroke *k;
if ((e = dll_first(__keystroke.free))) {
dll_remove(&__keystroke.free, e);
k = KEYSTROKE_CONTAINER(e);
--__keystroke.free_keys;
} else {
// PopulateKeystrokes() should make this branch impossible
if (!(k = AllocKeystroke()))
return 0;
}
struct Dll *e = dll_first(__keystroke.free);
if (!e) // See MIN(freekeys) before ReadConsoleInput()
__builtin_trap();
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.free, &k->elem);
--__keystroke.freekeys;
k->buflen = 0;
return k;
}
@ -183,22 +169,15 @@ textwindows static void FreeKeystrokes(struct Dll **list) {
FreeKeystroke(list, key);
}
textwindows static void PopulateKeystrokes(size_t want) {
struct Keystroke *k;
while (__keystroke.free_keys < want) {
if ((k = AllocKeystroke())) {
FreeKeystrokeImpl(&k->elem);
} else {
break;
}
}
}
textwindows static void OpenConsole(void) {
__keystroke.cin = CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite,
kNtFileShareRead, 0, kNtOpenExisting, 0, 0);
__keystroke.cot = CreateFile(u"CONOUT$", kNtGenericRead | kNtGenericWrite,
kNtFileShareWrite, 0, kNtOpenExisting, 0, 0);
for (int i = 0; i < ARRAYLEN(__keystroke.pool); ++i) {
dll_init(&__keystroke.pool[i].elem);
FreeKeystrokeImpl(&__keystroke.pool[i].elem);
}
}
textwindows static int AddSignal(int sig) {
@ -212,11 +191,11 @@ textwindows static void InitConsole(void) {
}
textwindows static void LockKeystrokes(void) {
_pthread_mutex_lock(&__keystroke_lock);
pthread_mutex_lock(&__keystroke.lock);
}
textwindows static void UnlockKeystrokes(void) {
_pthread_mutex_unlock(&__keystroke_lock);
pthread_mutex_unlock(&__keystroke.lock);
}
textwindows int64_t GetConsoleInputHandle(void) {
@ -539,12 +518,14 @@ textwindows static void IngestConsoleInputRecord(struct NtInputRecord *r) {
!(__ttyconf.magic & kTtyNoIexten)) { // IEXTEN
if (__keystroke.bypass_mode) {
struct Keystroke *k = NewKeystroke();
if (!k)
return;
memcpy(k->buf, buf, sizeof(k->buf));
k->buflen = len;
dll_make_last(&__keystroke.line, &k->elem);
EchoConsoleNt(buf, len, true);
if (!__keystroke.freekeys) {
dll_make_last(&__keystroke.list, __keystroke.line);
__keystroke.line = 0;
}
__keystroke.bypass_mode = false;
return;
} else if (len == 1 && buf[0] && //
@ -634,8 +615,6 @@ textwindows static void IngestConsoleInputRecord(struct NtInputRecord *r) {
// allocate object to hold keystroke
struct Keystroke *k = NewKeystroke();
if (!k)
return;
memcpy(k->buf, buf, sizeof(k->buf));
k->buflen = len;
@ -649,12 +628,12 @@ textwindows static void IngestConsoleInputRecord(struct NtInputRecord *r) {
} else {
dll_make_last(&__keystroke.line, &k->elem);
// flush canonical mode line on enter
if (len == 1 && buf[0] &&
((buf[0] & 255) == '\n' || //
(buf[0] & 255) == __ttyconf.veol || //
((buf[0] & 255) == __ttyconf.veol2 &&
!(__ttyconf.magic & kTtyNoIexten)))) {
// flush canonical mode line if oom or enter
if (!__keystroke.freekeys || (len == 1 && buf[0] &&
((buf[0] & 255) == '\n' || //
(buf[0] & 255) == __ttyconf.veol || //
((buf[0] & 255) == __ttyconf.veol2 &&
!(__ttyconf.magic & kTtyNoIexten))))) {
dll_make_last(&__keystroke.list, __keystroke.line);
__keystroke.line = 0;
}
@ -665,17 +644,15 @@ textwindows static void IngestConsoleInput(void) {
uint32_t i, n;
struct NtInputRecord records[16];
for (;;) {
if (!__keystroke.freekeys)
return;
if (__keystroke.end_of_file)
return;
if (!GetNumberOfConsoleInputEvents(__keystroke.cin, &n))
goto UnexpectedEof;
if (n > ARRAYLEN(records))
n = ARRAYLEN(records);
PopulateKeystrokes(n + 1);
if (n > __keystroke.free_keys)
n = __keystroke.free_keys;
if (!n)
if (!n || !__keystroke.freekeys)
return;
n = MIN(__keystroke.freekeys, MIN(ARRAYLEN(records), n));
if (!ReadConsoleInput(__keystroke.cin, records, n, &n))
goto UnexpectedEof;
for (i = 0; i < n && !__keystroke.end_of_file; ++i)
@ -997,10 +974,8 @@ textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
if (f->kind == kFdDevNull)
return 0;
if (f->kind == kFdDevRandom) {
ProcessPrng(data, size);
return size;
}
if (f->kind == kFdDevRandom)
return ProcessPrng(data, size) ? size : __winerr();
if (f->kind == kFdConsole)
return ReadFromConsole(f, data, size, waitmask);

View file

@ -23,7 +23,6 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/rlimit.h"
#include "libc/intrin/strace.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
@ -89,12 +88,10 @@ int setrlimit(int resource, const struct rlimit *rlim) {
} else if (!IsWindows() && !(IsNetbsd() && resource == RLIMIT_AS)) {
rc = sys_setrlimit(resource, rlim);
} else if (resource == RLIMIT_STACK) {
rc = 0;
rc = enotsup();
} else {
rc = einval();
}
if (!rc && resource == RLIMIT_STACK)
__rlimit_stack_set(*rlim); // so __rlimit_stack_get() works on all OSes
if (resource == RLIMIT_AS) {
__virtualmax = rlim->rlim_cur;
errno = olde;

View file

@ -35,8 +35,9 @@ void shm_path_np(const char *name, char buf[hasatleast 78]) {
const char *a;
uint8_t digest[BLAKE2B256_DIGEST_LENGTH];
a = "/tmp/", n = 5;
if (IsLinux() && isdirectory("/dev/shm"))
if (IsLinux() && isdirectory("/dev/shm")) {
a = "/dev/shm/", n = 9;
}
BLAKE2B256(name, strlen(name), digest);
p = mempcpy(buf, a, n);
p = hexpcpy(p, digest, BLAKE2B256_DIGEST_LENGTH);

View file

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

View file

@ -113,7 +113,7 @@ static int sigaltstack_bsd(const struct sigaltstack *neu,
* struct sigaction sa;
* struct sigaltstack ss;
* ss.ss_flags = 0;
* ss.ss_size = sysconf(_SC_SIGSTKSZ);
* ss.ss_size = sysconf(_SC_MINSIGSTKSZ) + 8192;
* ss.ss_sp = malloc(ss.ss_size);
* sigaltstack(&ss, 0);
* sigemptyset(&sa.ss_mask);
@ -121,16 +121,11 @@ static int sigaltstack_bsd(const struct sigaltstack *neu,
* sa.sa_handler = OnStackOverflow;
* sigaction(SIGSEGV, &sa, 0);
*
* Your stack size should be `sysconf(_SC_SIGSTKSZ)` which should be
* somewhere in the ballpark of 32kb to 64kb. You should go no lower
* than `sysconf(_SC_MINSIGSTKSZ) + 2048` which could be 4kb - 34kb.
* Cosmo also defines `SIGSTKSZ` as 32kb, which should also be safe.
*
* @param neu if non-null will install new signal alt stack
* @param old if non-null will receive current signal alt stack
* @return 0 on success, or -1 w/ errno
* @raise EFAULT if bad memory was supplied
* @raise ENOMEM if `neu->ss_size` is beneath `sysconf(_SC_MINSIGSTKSZ)`
* @raise ENOMEM if `neu->ss_size` is less than `MINSIGSTKSZ`
*/
int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
int rc;

View file

@ -33,7 +33,6 @@
#include "libc/runtime/syslib.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
/**
* @fileoverview XNU kernel callback normalization.
@ -514,7 +513,6 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
flags = __sighandflags[sig];
#ifdef __aarch64__
// xnu silicon claims to support sa_resethand but it does nothing
// this can be tested, since it clears the bit from flags as well
if (flags & SA_RESETHAND) {
@ -523,13 +521,6 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
__sighandflags[sig] = 0;
__sighandrvas[sig] = 0;
}
// unlike amd64, the instruction pointer on arm64 isn't advanced
// past the debugger breakpoint instruction automatically. we need
// this so execution can resume after __builtin_trap().
if (xnuctx && sig == SIGTRAP)
xnuctx->uc_mcontext->__ss.__pc += 4;
#endif
if (~flags & SA_SIGINFO) {

View file

@ -21,7 +21,6 @@
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
@ -60,7 +59,8 @@ int sigsuspend(const sigset_t *ignore) {
// using SetEvent() whereas it takes ~30us to use SuspendThread(),
// GetThreadContext(), SetThreadContext(), and ResumeThread().
BLOCK_SIGNALS;
rc = _park_norestart(timespec_max, waitmask);
while (!(rc = _park_norestart(-1u, waitmask)))
donothing;
ALLOW_SIGNALS;
} else {
rc = sys_sigsuspend((uint64_t[2]){waitmask}, 8);

View file

@ -13,6 +13,7 @@ extern unsigned __sighandflags[NSIG + 1];
extern uint64_t __sighandmask[NSIG + 1];
extern const struct NtSecurityAttributes kNtIsInheritable;
void __fds_wipe(void);
void __fds_lock(void);
void __fds_unlock(void);

View file

@ -4,21 +4,19 @@ COSMOPOLITAN_C_START_
typedef uint64_t sigset_t;
/* clang-format off */
int sigaddset(sigset_t *, int) libcesque paramsnonnull();
int sigdelset(sigset_t *, int) libcesque paramsnonnull();
int sigemptyset(sigset_t *) libcesque paramsnonnull();
int sigfillset(sigset_t *) libcesque paramsnonnull();
int sigandset(sigset_t *, const sigset_t *, const sigset_t *) libcesque paramsnonnull();
int sigorset(sigset_t *, const sigset_t *, const sigset_t *) libcesque paramsnonnull();
int sigisemptyset(const sigset_t *) libcesque paramsnonnull() nosideeffect;
int sigismember(const sigset_t *, int) libcesque paramsnonnull() nosideeffect;
int sigcountset(const sigset_t *) libcesque paramsnonnull() nosideeffect;
int sigprocmask(int, const sigset_t *, sigset_t *) dontthrow;
int sigsuspend(const sigset_t *) dontthrow;
int sigpending(sigset_t *) libcesque;
int pthread_sigmask(int, const sigset_t *, sigset_t *) dontthrow;
/* clang-format on */
int sigaddset(sigset_t *, int) paramsnonnull();
int sigdelset(sigset_t *, int) paramsnonnull();
int sigemptyset(sigset_t *) paramsnonnull();
int sigfillset(sigset_t *) paramsnonnull();
int sigandset(sigset_t *, const sigset_t *, const sigset_t *) paramsnonnull();
int sigorset(sigset_t *, const sigset_t *, const sigset_t *) paramsnonnull();
int sigisemptyset(const sigset_t *) paramsnonnull() nosideeffect;
int sigismember(const sigset_t *, int) paramsnonnull() nosideeffect;
int sigcountset(const sigset_t *) paramsnonnull() nosideeffect;
int sigprocmask(int, const sigset_t *, sigset_t *);
int sigsuspend(const sigset_t *);
int sigpending(sigset_t *);
int pthread_sigmask(int, const sigset_t *, sigset_t *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGSET_H_ */

View file

@ -5,15 +5,27 @@
#include "libc/sysv/consts/sig.h"
COSMOPOLITAN_C_START_
#ifndef MODE_DBG
/* block sigs because theoretical edge cases */
#define BLOCK_SIGNALS \
do { \
sigset_t _SigMask; \
_SigMask = __sig_block()
#define ALLOW_SIGNALS \
__sig_unblock(_SigMask); \
} \
while (0)
#else
/* doesn't block signals so we can get a crash
report, when a core runtime library crashes */
#define BLOCK_SIGNALS \
do { \
sigset_t _SigMask; \
sigprocmask(SIG_SETMASK, 0, &_SigMask)
#define ALLOW_SIGNALS \
} \
while (0)
#endif
sigset_t __sig_block(void);
void __sig_unblock(sigset_t);

View file

@ -1,14 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_
#include "libc/calls/ucontext.h"
#include "libc/nt/struct/context.h"
COSMOPOLITAN_C_START_
#ifdef __x86_64__
#define PC rip
#define SP rsp
#define BP rbp
#define RES0 rax
#define RES1 rdx
#define ARG0 rdi
#define ARG1 rsi
#define ARG2 rdx
@ -19,8 +18,6 @@ COSMOPOLITAN_C_START_
#define PC pc
#define SP sp
#define BP regs[29]
#define RES0 regs[0]
#define RES1 regs[1]
#define ARG0 regs[0]
#define ARG1 regs[1]
#define ARG2 regs[2]
@ -31,5 +28,8 @@ COSMOPOLITAN_C_START_
#error "unsupported architecture"
#endif
void _ntcontext2linux(struct ucontext *, const struct NtContext *);
void _ntlinux2context(struct NtContext *, const ucontext_t *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_INTERNAL_H_ */

View file

@ -2,9 +2,6 @@
#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);
@ -40,7 +37,6 @@ 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

@ -16,9 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.h"
#include "libc/time.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Returns time as seconds from UNIX epoch.
@ -28,11 +29,15 @@
* @asyncsignalsafe
*/
int64_t time(int64_t *opt_out_ret) {
int64_t secs = -1;
struct timespec ts;
if (!clock_gettime(CLOCK_REALTIME, &ts))
secs = ts.tv_sec;
if (opt_out_ret)
*opt_out_ret = secs;
int64_t secs;
struct timeval tv;
if (gettimeofday(&tv, 0) != -1) {
secs = tv.tv_sec;
if (opt_out_ret) {
*opt_out_ret = secs;
}
} else {
secs = -1;
}
return secs;
}

View file

@ -80,8 +80,7 @@ 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 = overlap.hEvent &&
(ReadFile(handle, buf, 2, 0, &overlap) ||
ok = (ReadFile(handle, buf, 2, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(handle, &overlap, &got, true);
CloseHandle(overlap.hEvent);

View file

@ -9,33 +9,18 @@ COSMOPOLITAN_C_START_
#define _COSMO_ATOMIC(x) x
#endif
errno_t cosmo_once(_COSMO_ATOMIC(unsigned) *, void (*)(void));
errno_t cosmo_once(_COSMO_ATOMIC(unsigned) *, void (*)(void)) libcesque;
int systemvpe(const char *, char *const[], char *const[]) libcesque;
char *GetProgramExecutableName(void) libcesque;
void unleaf(void) libcesque;
bool32 IsLinuxModern(void) libcesque;
int __demangle(char *, const char *, size_t) libcesque;
int __is_mangled(const char *) libcesque;
int cosmo_args(const char *, char ***) libcesque;
bool32 IsLinuxModern(void) libcesque;
int LoadZipArgs(int *, char ***) libcesque;
int cosmo_args(const char *, char ***) libcesque;
int cosmo_futex_wake(_COSMO_ATOMIC(int) *, int, char);
int cosmo_futex_wait(_COSMO_ATOMIC(int) *, int, char, int,
const struct timespec *);
errno_t cosmo_stack_alloc(size_t *, size_t *, void **) libcesque;
errno_t cosmo_stack_free(void *, size_t, size_t) libcesque;
void cosmo_stack_clear(void) libcesque;
void cosmo_stack_setmaxstacks(int) libcesque;
int cosmo_stack_getmaxstacks(void) libcesque;
int __deadlock_check(void *, int) libcesque;
int __deadlock_tracked(void *) libcesque;
void __deadlock_record(void *, int) libcesque;
void __deadlock_track(void *, int) libcesque;
void __deadlock_untrack(void *) libcesque;
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_COSMO_H_ */

View file

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

View file

@ -57,7 +57,6 @@
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#include "libc/temp.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
@ -132,8 +131,6 @@ struct {
long __sysv2nt14();
long foreign_tramp();
void __dlopen_lock(void);
void __dlopen_unlock(void);
static _Thread_local char dlerror_buf[128];
@ -254,7 +251,7 @@ static bool elf_slurp(struct Loaded *l, int fd, const char *file) {
return true;
}
dontinline static bool elf_load(struct Loaded *l, const char *file, long pagesz,
static dontinline bool elf_load(struct Loaded *l, const char *file, long pagesz,
char *interp_path, size_t interp_size) {
int fd;
if ((fd = open(file, O_RDONLY | O_CLOEXEC)) == -1)
@ -280,7 +277,7 @@ static long *push_strs(long *sp, char **list, int count) {
return sp;
}
wontreturn dontinstrument static void foreign_helper(void **p) {
static wontreturn dontinstrument void foreign_helper(void **p) {
__foreign.dlopen = p[0];
__foreign.dlsym = p[1];
__foreign.dlclose = p[2];
@ -288,7 +285,7 @@ wontreturn dontinstrument static void foreign_helper(void **p) {
_longjmp(__foreign.jb, 1);
}
dontinline static void elf_exec(const char *file, char **envp) {
static dontinline void elf_exec(const char *file, char **envp) {
// get microprocessor page size
long pagesz = __pagesize;
@ -412,7 +409,7 @@ static char *dlerror_set(const char *str) {
return dlerror_buf;
}
dontinline static char *foreign_alloc_block(void) {
static dontinline char *foreign_alloc_block(void) {
char *p = 0;
size_t sz = 65536;
if (!IsWindows()) {
@ -435,16 +432,17 @@ dontinline static char *foreign_alloc_block(void) {
return p;
}
dontinline static void *foreign_alloc(size_t n) {
static dontinline void *foreign_alloc(size_t n) {
void *res;
static char *block;
__dlopen_lock();
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
if (!block || READ32LE(block) + n > 65536)
if (!(block = foreign_alloc_block()))
return 0;
res = block + READ32LE(block);
WRITE32LE(block, READ32LE(block) + n);
__dlopen_unlock();
pthread_mutex_unlock(&lock);
return res;
}
@ -548,7 +546,7 @@ static void *foreign_thunk_nt(void *func) {
return code;
}
dontinline static bool foreign_compile(char exe[hasatleast PATH_MAX]) {
static dontinline bool foreign_compile(char exe[hasatleast PATH_MAX]) {
// construct path
strlcpy(exe, get_tmp_dir(), PATH_MAX);
@ -810,7 +808,7 @@ void *cosmo_dlopen(const char *path, int mode) {
}
ALLOW_CANCELATION;
ALLOW_SIGNALS;
STRACE("cosmo_dlopen(%#s, %d) → %p% m", path, mode, res);
STRACE("dlopen(%#s, %d) → %p% m", path, mode, res);
return res;
}
@ -855,7 +853,7 @@ void *cosmo_dlsym(void *handle, const char *name) {
} else {
func = 0;
}
STRACE("cosmo_dlsym(%p, %#s) → %p", handle, name, func);
STRACE("dlsym(%p, %#s) → %p", handle, name, func);
return func;
}
@ -890,7 +888,7 @@ int cosmo_dlclose(void *handle) {
} else {
res = -1;
}
STRACE("cosmo_dlclose(%p) → %d", handle, res);
STRACE("dlclose(%p) → %d", handle, res);
return res;
}
@ -909,6 +907,6 @@ char *cosmo_dlerror(void) {
} else {
res = dlerror_buf;
}
STRACE("cosmo_dlerror() → %#s", res);
STRACE("dlerror() → %#s", res);
return res;
}

View file

@ -17,10 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dlopen/dlfcn.h"
#include "libc/intrin/strace.h"
#define DLOPEN_ERROR \
"dlopen() isn't supported; consider using cosmo_dlopen() and read its docs"
/**
* Opens dynamic shared object using host platform libc.
@ -31,13 +27,12 @@
*
* @return null always
*/
void *dlopen(const char *path, int mode) {
STRACE("dlopen(%#s, %d) → 0 [%s]", path, mode, DLOPEN_ERROR);
void *dlopen(const char *, int) {
return 0;
}
char *dlerror(void) {
return DLOPEN_ERROR;
return "dlopen() isn't supported by cosmo; try using cosmo_dlopen()";
}
void *dlsym(void *, const char *) {

View file

@ -68,7 +68,6 @@
#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

@ -26,11 +26,11 @@ COSMOPOLITAN_C_START_
/* this header is included by 700+ files; therefore we */
/* hand-roll &__get_tls()->tib_errno to avoid #include */
/* cosmopolitan uses x28 as the tls register b/c apple */
#define errno \
(*__extension__({ \
errno_t *__ep; \
__asm__("sub\t%0,x28,#1024-0x3c" : "=r"(__ep)); \
__ep; \
#define errno \
(*__extension__({ \
errno_t *__ep; \
__asm__("sub\t%0,x28,#512-0x3c" : "=r"(__ep)); \
__ep; \
}))
#else
#define errno (*__errno_location())

View file

@ -49,6 +49,6 @@
int __vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
va_list);
int __fmt(void *, void *, const char *, va_list, int *);
char16_t *__itoa16(char16_t[21], uint64_t) __msabi;
__msabi char16_t *__itoa16(char16_t[21], uint64_t);
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */

View file

@ -135,7 +135,7 @@ typedef struct {
#define strftimeesque(n) __attribute__((__format__(__strftime__, n, 0)))
#ifndef privileged
#define privileged _Section(".privileged") dontinstrument dontubsan
#define privileged _Section(".privileged") dontinline dontinstrument dontubsan
#endif
#ifndef wontreturn

View file

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

View file

@ -20,7 +20,7 @@
#include "libc/intrin/getenv.h"
#include "libc/intrin/kprintf.h"
privileged optimizesize struct Env __getenv(char **p, const char *k) {
privileged struct Env __getenv(char **p, const char *k) {
char *t;
int i, j;
for (i = 0; (t = p[i]); ++i) {

View file

@ -16,18 +16,155 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
static void bzero128(char *p, size_t n) {
xmm_t v = {0};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
}
#if defined(__x86_64__) && !defined(__chibicc__)
_Microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
xmm_t v = {0};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else if (n >= 1024 && X86_HAVE(ERMS)) {
asm("rep stosb" : "+D"(p), "+c"(n), "=m"(*(char(*)[n])p) : "a"(0));
} else {
if (n < kHalfCache3 || !kHalfCache3) {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
} else {
while ((uintptr_t)(p + n) & 15) {
p[--n] = 0;
}
do {
n -= 32;
__builtin_ia32_movntdq((xmm_a *)(p + n), (xmm_a)v);
__builtin_ia32_movntdq((xmm_a *)(p + n + 16), (xmm_a)v);
} while (n > 32);
asm("sfence");
}
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
}
#endif
/**
* Sets memory to zero.
*
* bzero n=0 661 picoseconds
* bzero n=1 661 ps/byte 1,476 mb/s
* bzero n=2 330 ps/byte 2,952 mb/s
* bzero n=3 220 ps/byte 4,428 mb/s
* bzero n=4 165 ps/byte 5,904 mb/s
* bzero n=7 94 ps/byte 10,333 mb/s
* bzero n=8 41 ps/byte 23,618 mb/s
* bzero n=15 44 ps/byte 22,142 mb/s
* bzero n=16 20 ps/byte 47,236 mb/s
* bzero n=31 21 ps/byte 45,760 mb/s
* bzero n=32 20 ps/byte 47,236 mb/s
* bzero n=63 10 ps/byte 92,997 mb/s
* bzero n=64 15 ps/byte 62,982 mb/s
* bzero n=127 15 ps/byte 62,490 mb/s
* bzero n=128 10 ps/byte 94,473 mb/s
* bzero n=255 14 ps/byte 68,439 mb/s
* bzero n=256 9 ps/byte 105 gb/s
* bzero n=511 15 ps/byte 62,859 mb/s
* bzero n=512 11 ps/byte 83,976 mb/s
* bzero n=1023 15 ps/byte 61,636 mb/s
* bzero n=1024 10 ps/byte 88,916 mb/s
* bzero n=2047 9 ps/byte 105 gb/s
* bzero n=2048 8 ps/byte 109 gb/s
* bzero n=4095 8 ps/byte 115 gb/s
* bzero n=4096 8 ps/byte 118 gb/s
* bzero n=8191 7 ps/byte 129 gb/s
* bzero n=8192 7 ps/byte 130 gb/s
* bzero n=16383 6 ps/byte 136 gb/s
* bzero n=16384 6 ps/byte 137 gb/s
* bzero n=32767 6 ps/byte 140 gb/s
* bzero n=32768 6 ps/byte 141 gb/s
* bzero n=65535 15 ps/byte 64,257 mb/s
* bzero n=65536 15 ps/byte 64,279 mb/s
* bzero n=131071 15 ps/byte 63,166 mb/s
* bzero n=131072 15 ps/byte 63,115 mb/s
* bzero n=262143 15 ps/byte 62,052 mb/s
* bzero n=262144 15 ps/byte 62,097 mb/s
* bzero n=524287 15 ps/byte 61,699 mb/s
* bzero n=524288 15 ps/byte 61,674 mb/s
* bzero n=1048575 16 ps/byte 60,179 mb/s
* bzero n=1048576 15 ps/byte 61,330 mb/s
* bzero n=2097151 15 ps/byte 61,071 mb/s
* bzero n=2097152 15 ps/byte 61,065 mb/s
* bzero n=4194303 16 ps/byte 60,942 mb/s
* bzero n=4194304 16 ps/byte 60,947 mb/s
* bzero n=8388607 16 ps/byte 60,872 mb/s
* bzero n=8388608 16 ps/byte 60,879 mb/s
*
* @param p is memory address
* @param n is byte length
* @return p
* @asyncsignalsafe
*/
void bzero(void *p, size_t n) {
memset(p, 0, n);
char *b;
uint64_t x;
b = p;
#ifdef __x86_64__
asm("xorl\t%k0,%k0" : "=r"(x));
#else
if (1) {
memset(p, 0, n);
return;
}
x = 0;
#endif
if (n <= 16) {
if (n >= 8) {
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
} else if (n >= 4) {
__builtin_memcpy(b, &x, 4);
__builtin_memcpy(b + n - 4, &x, 4);
} else if (n) {
do {
asm volatile("" ::: "memory");
b[--n] = x;
} while (n);
}
#if defined(__x86_64__) && !defined(__chibicc__)
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0));
return;
} else if (X86_HAVE(AVX)) {
bzero_avx(b, n);
#endif
} else {
bzero128(b, n);
}
}
__weak_reference(bzero, explicit_bzero);

View file

@ -59,7 +59,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § Windows Time
//
QueryUnbiasedInterruptTimePrecise(&hectons);
*ts = WindowsDurationToTimeSpec(hectons);
*ts = timespec_fromnanos(hectons * 100);
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 = WindowsDurationToTimeSpec(hectons);
*ts = timespec_fromnanos(hectons * 100);
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 = WindowsDurationToTimeSpec(hectons);
*ts = timespec_fromnanos(hectons * 100);
return 0;
case _CLOCK_PROCESS_CPUTIME_ID:
GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel,

View file

@ -18,7 +18,6 @@
*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
@ -233,7 +232,6 @@ static int cosmo_futex_fix_timeout (struct timespec *memory, int clock,
* @raise EAGAIN if `*w` wasn't `expect`
* @raise EINTR if a signal handler was called while waiting
* @raise ECANCELED if calling thread was canceled while waiting
* @cancelationpoint
*/
int cosmo_futex_wait (atomic_int *w, int expect, char pshare,
int clock, const struct timespec *abstime) {
@ -242,7 +240,6 @@ int cosmo_futex_wait (atomic_int *w, int expect, char pshare,
struct PosixThread *pt;
struct timespec tsmem;
struct timespec *timeout = 0;
BEGIN_CANCELATION_POINT;
cosmo_once (&g_cosmo_futex.once, cosmo_futex_init);
@ -354,7 +351,6 @@ Finished:
DescribeTimespec (0, abstime),
DescribeErrno (rc));
END_CANCELATION_POINT;
return rc;
}

View file

@ -21,15 +21,16 @@
.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]
@ -45,7 +46,5 @@ cosmo_futex_thunk:
#else
#error "unsupported architecture"
#endif /* __x86_64__ */
1: epi
ret
end
1: ret
.endfn cosmo_futex_thunk,globl,hidden

View file

@ -1,26 +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 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/atomic.h"
#include "libc/stdalign.h"
#include "libc/thread/thread.h"
// this counter is important because pthread_exit() needs to know if
// it's an orphan thread, without needing to acquire _pthread_lock()
// which causes contention and a file descriptor explosion on netbsd
alignas(64) atomic_uint _pthread_count = 1;

View file

@ -20,13 +20,16 @@
#include "libc/intrin/atomic.h"
#include "libc/intrin/fds.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/posixthread.internal.h"
struct Cursor *__cursor_new(void) {
struct Cursor *c;
if ((c = _mapanon(sizeof(struct Cursor)))) {
if ((c->shared = _mapshared(sizeof(struct CursorShared)))) {
c->shared->lock = (pthread_mutex_t)PTHREAD_SHARED_MUTEX_INITIALIZER_NP;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&c->shared->lock, &attr);
pthread_mutexattr_destroy(&attr);
} else {
munmap(c, sizeof(struct Cursor));
c = 0;
@ -53,9 +56,9 @@ int __cursor_unref(struct Cursor *c) {
}
void __cursor_lock(struct Cursor *c) {
_pthread_mutex_lock(&c->shared->lock);
pthread_mutex_lock(&c->shared->lock);
}
void __cursor_unlock(struct Cursor *c) {
_pthread_mutex_unlock(&c->shared->lock);
pthread_mutex_unlock(&c->shared->lock);
}

View file

@ -18,9 +18,9 @@ struct CxaAtexitBlocks {
extern struct CxaAtexitBlocks __cxa_blocks;
void __cxa_lock(void) dontthrow;
void __cxa_unlock(void) dontthrow;
void __cxa_thread_finalize(void) dontthrow;
void __cxa_lock(void) libcesque;
void __cxa_unlock(void) libcesque;
void __cxa_thread_finalize(void) libcesque;
void __cxa_printexits(FILE *, void *) libcesque;
int __cxa_thread_atexit_impl(void *, void *, void *);

View file

@ -17,15 +17,22 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/cxaatexit.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
pthread_mutex_t __cxa_lock_obj = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t __cxa_lock_obj;
void __cxa_wipe(void) {
pthread_mutex_init(&__cxa_lock_obj, 0);
}
void __cxa_lock(void) {
_pthread_mutex_lock(&__cxa_lock_obj);
pthread_mutex_lock(&__cxa_lock_obj);
}
void __cxa_unlock(void) {
_pthread_mutex_unlock(&__cxa_lock_obj);
pthread_mutex_unlock(&__cxa_lock_obj);
}
__attribute__((__constructor__(60))) static textstartup void __cxa_init() {
pthread_atfork(__cxa_lock, __cxa_unlock, __cxa_wipe);
}

View file

@ -1,277 +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 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 "ape/sections.internal.h"
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "libc/thread/lock.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
/**
* @fileoverview deadlock detector for statically allocated locks
*
* This module helps you spot multi-threading bugs in your program.
* High-level abstractions like mutexes are much easier to use than
* atomics, but they still carry their own non-obvious dangers. For
* example, nesting locks need to be nested in a consistent way and
* normal mutexes can't be required recursively. Normally this will
* cause your program to deadlock, i.e. hang indefinitely, but this
* module can detect such conditions and return errors instead, and
* better yet print helpful information when using `cosmocc -mdbg`.
*/
#define ABI privileged optimizesize
// building our visitor function using this optimizesize keyword shrinks
// the stack memory requirement from 7168 to 2048 bytes. totally amazing
// although please note this maximum isn't a hard limit. for normal mode
// builds your posix mandated mutex error checking will be less accurate
// but still helpful and reliable, although your cosmocc -mdbg will trap
// and report that you've run into the limit, so you can talk to justine
#define MAX_LOCKS 64
// cosmo's tib reserves space for 64 nested locks before things degrade.
// the cosmopolitan c runtime defines 16 locks, which are all registered
// with pthread_atfork(). it means you get to have 48 mutexes right now,
// and if you register all of them, then calling fork() will cause there
// to be 2080 edges in your lock graph. talk to justine if you need more
// because we're obviously going to need to find a way to make this grow
#define LOCK_EDGES_MAX 2080
// supported lock objects must define `void *_edges`
#define LOCK_EDGES_OFFSET 0
static_assert(offsetof(struct MapLock, edges) == LOCK_EDGES_OFFSET);
static_assert(offsetof(pthread_mutex_t, _edges) == LOCK_EDGES_OFFSET);
struct LockEdge {
struct LockEdge *next;
void *dest;
};
struct VisitedLock {
struct VisitedLock *next;
void *lock;
};
typedef _Atomic(struct LockEdge *) LockEdges;
static struct DeadlockDetector {
atomic_size_t edges_allocated;
struct LockEdge edges_memory[LOCK_EDGES_MAX];
} __deadlock;
forceinline struct CosmoTib *__deadlock_tls(void) {
return __get_tls_privileged();
}
forceinline LockEdges *get_lock_edges(void *lock) {
return (LockEdges *)((char *)lock + LOCK_EDGES_OFFSET);
}
forceinline struct LockEdge *load_lock_edges(LockEdges *edges) {
return atomic_load_explicit(edges, memory_order_relaxed);
}
ABI static int is_static_memory(void *lock) {
return _etext <= (unsigned char *)lock && (unsigned char *)lock < _end;
}
ABI static struct LockEdge *__deadlock_alloc(void) {
size_t edges_allocated =
atomic_load_explicit(&__deadlock.edges_allocated, memory_order_relaxed);
for (;;) {
if (edges_allocated == LOCK_EDGES_MAX) {
if (IsModeDbg()) {
kprintf("error: cosmo LOCK_EDGES_MAX needs to be increased\n");
DebugBreak();
}
return 0;
}
if (atomic_compare_exchange_weak_explicit(
&__deadlock.edges_allocated, &edges_allocated, edges_allocated + 1,
memory_order_relaxed, memory_order_relaxed))
return &__deadlock.edges_memory[edges_allocated];
}
}
ABI static void __deadlock_add_edge(void *from, void *dest) {
LockEdges *edges = get_lock_edges(from);
for (struct LockEdge *e = load_lock_edges(edges); e; e = e->next)
if (e->dest == dest)
return;
struct LockEdge *edge;
if ((edge = __deadlock_alloc())) {
edge->next = load_lock_edges(edges);
edge->dest = dest;
// we tolerate duplicate elements in the interest of performance.
// once an element is inserted, it's never removed. that's why we
// don't need need to worry about the aba problem. the cas itself
// is very important since it ensures inserted edges aren't lost.
for (;;)
if (atomic_compare_exchange_weak_explicit(edges, &edge->next, edge,
memory_order_relaxed,
memory_order_relaxed))
break;
}
}
ABI static bool __deadlock_visit(void *lock, struct VisitedLock *visited,
int notrap, int depth) {
if (++depth == MAX_LOCKS) {
if (IsModeDbg()) {
kprintf("error: too much recursion in deadlock detector\n");
DebugBreak();
}
return false;
}
for (struct VisitedLock *v = visited; v; v = v->next) {
if (v->lock == lock) {
if (IsModeDbg() && !notrap) {
// lock hierarchy violated!
//
// when you lock mutexes in a nested way, your locks must be
// nested in the same order globally. otherwise deadlocks might
// occur. for example, if you say in your first thread
//
// pthread_mutex_lock(&x);
// pthread_mutex_lock(&y);
// pthread_mutex_unlock(&y);
// pthread_mutex_unlock(&x);
//
// then in your second thread you say
//
// pthread_mutex_lock(&y);
// pthread_mutex_lock(&x);
// pthread_mutex_unlock(&x);
// pthread_mutex_unlock(&y);
//
// then a deadlock might happen, because {x→y, y→x} is cyclic!
// they don't happen often, but this is the kind of thing that
// matters if you want to build carrier grade production stuff
kprintf("error: cycle detected in directed graph of nested locks\n");
for (struct VisitedLock *v = visited; v; v = v->next)
kprintf("\t- %t\n", v->lock); // strongly connected component
DebugBreak();
}
return true;
}
}
LockEdges *edges = get_lock_edges(lock);
struct VisitedLock visit = {visited, lock};
for (struct LockEdge *e = load_lock_edges(edges); e; e = e->next)
if (__deadlock_visit(e->dest, &visit, notrap, depth))
return true;
return false;
}
/**
* Returns true if lock is already locked by calling thread.
*
* This function may return false negatives if we run out of TLS memory.
* That suboptimal condition will be reported in debug mode.
*
* @return 1 if lock is certainly owned by calling thread, 0 if lock is
* certainly not owned by calling thread, and -1 if we're uncertain
*/
ABI int __deadlock_tracked(void *lock) {
int full = 1;
int owned = 0;
struct CosmoTib *tib = __deadlock_tls();
for (int i = 0; i < ARRAYLEN(tib->tib_locks); ++i) {
full &= tib->tib_locks[i] != NULL;
owned |= tib->tib_locks[i] == lock;
}
if (full)
return -1;
if (!owned && !is_static_memory(lock))
return -1;
return owned;
}
/**
* Records that lock is held by thread.
* @param notrap can prevent error printing and debug breaking
* @asyncsignalsafe
*/
ABI void __deadlock_track(void *lock, int notrap) {
if (!notrap && !is_static_memory(lock))
return;
struct CosmoTib *tib = __deadlock_tls();
for (int i = 0; i < ARRAYLEN(tib->tib_locks); ++i) {
if (!tib->tib_locks[i]) {
tib->tib_locks[i] = lock;
return;
}
}
if (IsModeDbg()) {
kprintf("error: cosmo tls max lock depth needs to be increased!\n");
DebugBreak();
}
}
/**
* Records relationship for all held locks to `lock`.
* @param notrap can prevent error printing and debug breaking
* @asyncsignalsafe
*/
ABI void __deadlock_record(void *lock, int notrap) {
if (!notrap && !is_static_memory(lock))
return;
struct CosmoTib *tib = __deadlock_tls();
for (int i = 0; i < ARRAYLEN(tib->tib_locks); ++i)
if (tib->tib_locks[i] && tib->tib_locks[i] != lock)
__deadlock_add_edge(tib->tib_locks[i], lock);
}
/**
* Returns EDEADLK if locking `lock` could cause a deadlock.
* @param notrap can prevent error printing and debug breaking
* @asyncsignalsafe
*/
ABI int __deadlock_check(void *lock, int notrap) {
struct CosmoTib *tib = __deadlock_tls();
for (int i = 0; i < ARRAYLEN(tib->tib_locks); ++i) {
if (tib->tib_locks[i] == lock)
return 0;
if (tib->tib_locks[i]) {
struct VisitedLock visit = {0, tib->tib_locks[i]};
if (__deadlock_visit(lock, &visit, notrap, 0))
return EDEADLK;
}
}
return 0;
}
/**
* Records that lock isn't held by thread.
* @asyncsignalsafe
*/
ABI void __deadlock_untrack(void *lock) {
struct CosmoTib *tib = __deadlock_tls();
for (int i = 0; i < ARRAYLEN(tib->tib_locks); ++i)
tib->tib_locks[i] = tib->tib_locks[i] != lock ? tib->tib_locks[i] : 0;
}

View file

@ -91,8 +91,6 @@ Copyright (c) 2024 Justine Tunney <jtunney@gmail.com>");
*
*/
#define ABI privileged optimizesize
#define DEMANGLE_NO_FLOATING_POINT
#define ASSERT(x) (void)0
@ -105,7 +103,6 @@ Copyright (c) 2024 Justine Tunney <jtunney@gmail.com>");
#define ELFTC_SUCCESS 1
#define VECTOR_DEF_CAPACITY 1
#define MAX_DEPTH 20
typedef unsigned short index_t;
@ -191,7 +188,6 @@ struct demangle_data {
enum type_qualifier ref_qualifier_type; /* ref qualifier type */
enum push_qualifier push_qualifier; /* which qualifiers to push */
int func_type;
int depth;
const char *cur; /* current mangled name ptr */
const char *last_sname; /* last source name */
intptr_t jmpbuf[5];
@ -224,18 +220,16 @@ static int demangle_read_sname(struct demangle_data *);
static int demangle_read_subst(struct demangle_data *);
static int demangle_read_type(struct demangle_data *, struct type_delimit *);
ABI static size_t
static privileged size_t
demangle_strlen(const char *s)
{
size_t n = 0;
while (*s++) {
asm volatile("" ::: "memory");
while (*s++)
++n;
}
return n;
}
ABI static char *
static privileged char *
demangle_stpcpy(char *d, const char *s)
{
size_t i = 0;
@ -246,7 +240,7 @@ demangle_stpcpy(char *d, const char *s)
}
}
ABI static void *
static privileged void *
demangle_mempcpy(void *a, const void *b, size_t n)
{
char *d = a;
@ -256,14 +250,14 @@ demangle_mempcpy(void *a, const void *b, size_t n)
return d;
}
ABI static void *
static privileged void *
demangle_memcpy(void *a, const void *b, size_t n)
{
demangle_mempcpy(a, b, n);
return a;
}
ABI static int
static privileged int
demangle_strncmp(const char *a, const char *b, size_t n)
{
size_t i = 0;
@ -274,7 +268,7 @@ demangle_strncmp(const char *a, const char *b, size_t n)
return (a[i] & 0xff) - (b[i] & 0xff);
}
ABI static int
static privileged int
demangle_memcmp(const void *a, const void *b, size_t n)
{
int c;
@ -289,7 +283,7 @@ demangle_memcmp(const void *a, const void *b, size_t n)
return 0;
}
ABI static void
static privileged void
demangle_strlcpy(char *dst, const char *src, size_t dsize)
{
size_t remain;
@ -301,7 +295,7 @@ demangle_strlcpy(char *dst, const char *src, size_t dsize)
*dst = 0;
}
ABI static long
static privileged long
demangle_strtol(const char *s, int base)
{
static const uint8_t demangle_base36[80] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,
@ -318,7 +312,7 @@ demangle_strtol(const char *s, int base)
return x;
}
ABI static char *
static privileged char *
demangle_strstr(const char *haystack, const char *needle)
{
size_t i;
@ -339,7 +333,7 @@ demangle_strstr(const char *haystack, const char *needle)
return 0;
}
ABI static char *
static privileged char *
demangle_utoa(char *p, unsigned long long x)
{
char t;
@ -360,7 +354,7 @@ demangle_utoa(char *p, unsigned long long x)
return p + i;
}
ABI static char *
static privileged char *
demangle_itoa(char *p, long long x)
{
if (x < 0)
@ -368,7 +362,7 @@ demangle_itoa(char *p, long long x)
return demangle_utoa(p, x);
}
ABI static void
static privileged void
demangle_free(struct demangle_data *h, void *ptr)
{
index_t base;
@ -385,17 +379,14 @@ demangle_free(struct demangle_data *h, void *ptr)
}
}
ABI static returnspointerwithnoaliases returnsnonnull void *
demangle_malloc(struct demangle_data *h, long a, long n)
static privileged returnspointerwithnoaliases returnsnonnull void *
demangle_malloc(struct demangle_data *h, int a, int n)
{
long rem;
int rem;
uintptr_t ptr;
index_t next, next2;
index_t *link, *link2;
long b = sizeof(index_t);
if (n < 0 || n >= 32768)
__builtin_longjmp(h->jmpbuf, 1);
int b = sizeof(index_t);
/* Roundup size. */
n += a - 1;
@ -442,7 +433,7 @@ demangle_malloc(struct demangle_data *h, long a, long n)
}
}
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
demangle_strdup(struct demangle_data *h, const char *s)
{
char *d = 0;
@ -454,7 +445,7 @@ demangle_strdup(struct demangle_data *h, const char *s)
return d;
}
ABI static void
static privileged void
demangle_vector_str_dest(struct demangle_data *h, struct vector_str *v)
{
int i;
@ -463,7 +454,7 @@ demangle_vector_str_dest(struct demangle_data *h, struct vector_str *v)
demangle_free(h, v->container);
}
ABI static void
static privileged void
demangle_vector_type_qualifier_dest(struct demangle_data *d,
struct vector_type_qualifier *v)
{
@ -471,7 +462,7 @@ demangle_vector_type_qualifier_dest(struct demangle_data *d,
demangle_vector_str_dest(d, &v->ext_name);
}
ABI static void
static privileged void
demangle_stack_str_init(struct stack_str *ss)
{
ss->str = ss->buf;
@ -480,7 +471,7 @@ demangle_stack_str_init(struct stack_str *ss)
ss->cap = sizeof(ss->buf);
}
ABI static void
static privileged void
demangle_stack_str_append(struct demangle_data *h, struct stack_str *ss,
const char *str, size_t len)
{
@ -503,7 +494,7 @@ demangle_stack_str_append(struct demangle_data *h, struct stack_str *ss,
#define demangle_stack_str_append_str(h, ss, s) \
demangle_stack_str_append(h, ss, s, demangle_strlen(s))
ABI static size_t
static privileged size_t
demangle_get_strlen_sum(struct demangle_data *h, const struct vector_str *v)
{
size_t i, len = 0;
@ -513,7 +504,7 @@ demangle_get_strlen_sum(struct demangle_data *h, const struct vector_str *v)
return len;
}
ABI static int
static privileged int
demangle_demangle_strncmp(const char *a, const char *b, size_t n)
{
size_t i = 0;
@ -531,7 +522,7 @@ demangle_demangle_strncmp(const char *a, const char *b, size_t n)
* @param l Length of the string.
* @return -1 at failed, 0 at not found, 1 at found.
*/
ABI static int
static privileged int
demangle_vector_str_find(struct demangle_data *h, const struct vector_str *v,
const char *o, size_t l)
{
@ -555,7 +546,7 @@ demangle_vector_str_find(struct demangle_data *h, const struct vector_str *v,
* @param l Length of the string.
* @return NULL at failed or NUL terminated new allocated string.
*/
ABI static char *
static privileged char *
demangle_vector_str_get_flat(struct demangle_data *ddata,
const struct vector_str *v, size_t *l)
{
@ -581,7 +572,7 @@ demangle_vector_str_get_flat(struct demangle_data *ddata,
return rtn;
}
ABI static void
static privileged void
demangle_vector_str_grow(struct demangle_data *ddata, struct vector_str *v)
{
size_t i, tmp_cap;
@ -609,7 +600,7 @@ demangle_vector_str_grow(struct demangle_data *ddata, struct vector_str *v)
* @brief Initialize vector_str.
* @return false at failed, true at success.
*/
ABI static void
static privileged void
demangle_vector_str_init(struct demangle_data *ddata, struct vector_str *v)
{
v->size = 0;
@ -625,7 +616,7 @@ demangle_vector_str_init(struct demangle_data *ddata, struct vector_str *v)
* @brief Remove last element in vector_str.
* @return false at failed, true at success.
*/
ABI static bool
static privileged bool
demangle_vector_str_pop(struct vector_str *v)
{
if (!v)
@ -645,7 +636,7 @@ demangle_vector_str_pop(struct vector_str *v)
* @brief Push back string to vector.
* @return false at failed, true at success.
*/
ABI static bool
static privileged bool
demangle_vector_str_push(struct demangle_data *ddata, struct vector_str *v,
const char *str, size_t len)
{
@ -669,7 +660,7 @@ demangle_vector_str_push(struct demangle_data *ddata, struct vector_str *v,
* @brief Push front org vector to det vector.
* @return false at failed, true at success.
*/
ABI static bool
static privileged bool
demangle_vector_str_push_vector_head(struct demangle_data *ddata,
struct vector_str *dst, struct vector_str *org)
{
@ -702,7 +693,7 @@ demangle_vector_str_push_vector_head(struct demangle_data *ddata,
* @brief Push org vector to the tail of det vector.
* @return false at failed, true at success.
*/
ABI static bool
static privileged bool
demangle_vector_str_push_vector(struct demangle_data *ddata,
struct vector_str *dst, struct vector_str *org)
{
@ -740,7 +731,7 @@ demangle_vector_str_push_vector(struct demangle_data *ddata,
* If r_len is not NULL, string length will be returned.
* @return NULL at failed or NUL terminated new allocated string.
*/
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
demangle_vector_str_substr(struct demangle_data *ddata,
const struct vector_str *v, size_t begin, size_t end, size_t *r_len)
{
@ -766,7 +757,7 @@ demangle_vector_str_substr(struct demangle_data *ddata,
return rtn;
}
ABI static int
static privileged int
demangle_vector_read_cmd_pop(struct vector_read_cmd *v)
{
if (!v->size)
@ -779,7 +770,7 @@ demangle_vector_read_cmd_pop(struct vector_read_cmd *v)
return 1;
}
ABI static void
static privileged void
demangle_vector_read_cmd_init(struct demangle_data *ddata,
struct vector_read_cmd *v)
{
@ -790,7 +781,7 @@ demangle_vector_read_cmd_init(struct demangle_data *ddata,
alignof(*v->r_container), sizeof(*v->r_container) * v->capacity);
}
ABI static void
static privileged void
demangle_data_init(struct demangle_data *d, const char *cur)
{
demangle_vector_str_init(d, &d->output);
@ -820,7 +811,7 @@ demangle_data_init(struct demangle_data *d, const char *cur)
d->last_sname = NULL;
}
ABI static int
static privileged int
demangle_push_str(struct demangle_data *ddata, const char *str, size_t len)
{
if (!str || !len)
@ -837,7 +828,7 @@ demangle_push_str(struct demangle_data *ddata, const char *str, size_t len)
}
#ifndef DEMANGLE_NO_FLOATING_POINT
ABI static int
static privileged int
demangle_push_fp(struct demangle_data *ddata,
char *decoder(struct demangle_data *, const char *, size_t))
{
@ -866,13 +857,13 @@ demangle_push_fp(struct demangle_data *ddata,
}
#endif // DEMANGLE_NO_FLOATING_POINT
ABI static int
static privileged int
demangle_pop_str(struct demangle_data *ddata)
{
return demangle_vector_str_pop(ddata->cur_output);
}
ABI static int
static privileged int
demangle_push_subst(struct demangle_data *ddata, const char *str, size_t len)
{
if (!str || !len)
@ -884,7 +875,7 @@ demangle_push_subst(struct demangle_data *ddata, const char *str, size_t len)
return 1;
}
ABI static int
static privileged int
demangle_push_subst_v(struct demangle_data *ddata, struct vector_str *v)
{
int rtn;
@ -904,7 +895,7 @@ demangle_push_subst_v(struct demangle_data *ddata, struct vector_str *v)
return rtn;
}
ABI static int
static privileged int
demangle_push_type_qualifier(struct demangle_data *ddata,
struct vector_type_qualifier *v, const char *type_str)
{
@ -1137,7 +1128,7 @@ demangle_push_type_qualifier(struct demangle_data *ddata,
return 1;
}
ABI static int
static privileged int
demangle_get_subst(struct demangle_data *ddata, size_t idx)
{
size_t len;
@ -1155,7 +1146,7 @@ demangle_get_subst(struct demangle_data *ddata, size_t idx)
return 1;
}
ABI static int
static privileged int
demangle_get_tmpl_param(struct demangle_data *ddata, size_t idx)
{
size_t len;
@ -1172,7 +1163,7 @@ demangle_get_tmpl_param(struct demangle_data *ddata, size_t idx)
return 1;
}
ABI static int
static privileged int
demangle_read_array(struct demangle_data *ddata)
{
size_t i, num_len, exp_len, p_idx, idx;
@ -1244,7 +1235,7 @@ demangle_read_array(struct demangle_data *ddata)
#ifndef DEMANGLE_NO_FLOATING_POINT
/* Simple hex to integer function used by decode_to_* function. */
ABI static int
static privileged int
hex_to_dec(char c)
{
switch (c) {
@ -1292,7 +1283,7 @@ hex_to_dec(char c)
* Todo
* Replace these functions to macro.
*/
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
decode_fp_to_double(struct demangle_data *ddata, const char *p, size_t len)
{
double f;
@ -1336,7 +1327,7 @@ again:
return rtn;
}
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
decode_fp_to_float(struct demangle_data *ddata, const char *p, size_t len)
{
size_t i, rtn_len, limit;
@ -1378,7 +1369,7 @@ again:
return rtn;
}
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
decode_fp_to_long_double(struct demangle_data *ddata, const char *p, size_t len)
{
long double f;
@ -1422,7 +1413,7 @@ again:
return rtn;
}
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
decode_fp_to_float128(struct demangle_data *ddata, const char *p, size_t len)
{
long double f;
@ -1479,7 +1470,7 @@ decode_fp_to_float128(struct demangle_data *ddata, const char *p, size_t len)
}
}
ABI static returnspointerwithnoaliases char *
static privileged returnspointerwithnoaliases char *
decode_fp_to_float80(struct demangle_data *ddata, const char *p, size_t len)
{
long double f;
@ -1542,7 +1533,7 @@ decode_fp_to_float80(struct demangle_data *ddata, const char *p, size_t len)
#endif // DEMANGLE_NO_FLOATING_POINT
ABI static int
static privileged int
demangle_read_expr_primary(struct demangle_data *ddata)
{
const char *num;
@ -1634,7 +1625,7 @@ demangle_read_expr_primary(struct demangle_data *ddata)
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
* http://gcc.gnu.org/viewcvs?view=rev&revision=124467
*/
ABI static int
static privileged int
demangle_local_source_name(struct demangle_data *ddata)
{
/* L */
@ -1660,7 +1651,7 @@ demangle_local_source_name(struct demangle_data *ddata)
* read unqualified-name, unqualified name are operator-name, ctor-dtor-name,
* source-name
*/
ABI static int
static privileged int
demangle_read_uqname(struct demangle_data *ddata)
{
size_t len;
@ -2089,7 +2080,7 @@ demangle_read_uqname(struct demangle_data *ddata)
* Read template parameter that forms in 'T[number]_'.
* This function much like to read_subst but only for types.
*/
ABI static int
static privileged int
demangle_read_tmpl_param(struct demangle_data *ddata)
{
long nth;
@ -2107,11 +2098,10 @@ demangle_read_tmpl_param(struct demangle_data *ddata)
/* T_ is first */
++nth;
while (*ddata->cur && *ddata->cur != '_')
while (*ddata->cur != '_')
++ddata->cur;
if (nth <= 0)
return 0;
ASSERT(nth > 0);
return demangle_get_tmpl_param(ddata, nth);
}
@ -2120,7 +2110,7 @@ demangle_read_tmpl_param(struct demangle_data *ddata)
return 0;
}
ABI static int
static privileged int
demangle_vector_read_cmd_push(struct demangle_data *ddata,
struct vector_read_cmd *v, enum read_cmd cmd, void *data)
{
@ -2149,7 +2139,7 @@ demangle_vector_read_cmd_push(struct demangle_data *ddata,
return 1;
}
ABI static int
static privileged int
demangle_read_tmpl_arg(struct demangle_data *ddata)
{
if (*ddata->cur == '\0')
@ -2168,7 +2158,7 @@ demangle_read_tmpl_arg(struct demangle_data *ddata)
return demangle_read_type(ddata, NULL);
}
ABI static int
static privileged int
demangle_read_tmpl_args(struct demangle_data *ddata)
{
struct vector_str *v;
@ -2221,7 +2211,7 @@ demangle_read_tmpl_args(struct demangle_data *ddata)
return demangle_vector_read_cmd_pop(&ddata->cmd);
}
ABI static int
static privileged int
demangle_read_expression_trinary(struct demangle_data *ddata, const char *name1,
size_t len1, const char *name2, size_t len2)
{
@ -2240,7 +2230,7 @@ demangle_read_expression_trinary(struct demangle_data *ddata, const char *name1,
return demangle_read_expression(ddata);
}
ABI static int
static privileged int
demangle_read_expression_unary(struct demangle_data *ddata, const char *name,
size_t len)
{
@ -2252,7 +2242,7 @@ demangle_read_expression_unary(struct demangle_data *ddata, const char *name,
return demangle_push_str(ddata, name, len);
}
ABI static int
static privileged int
demangle_read_expression_binary(struct demangle_data *ddata, const char *name,
size_t len)
{
@ -2266,8 +2256,8 @@ demangle_read_expression_binary(struct demangle_data *ddata, const char *name,
return demangle_read_expression(ddata);
}
ABI static int
demangle_read_expression_impl(struct demangle_data *ddata)
static privileged int
demangle_read_expression(struct demangle_data *ddata)
{
if (*ddata->cur == '\0')
return 0;
@ -2548,18 +2538,7 @@ demangle_read_expression_impl(struct demangle_data *ddata)
return 0;
}
ABI static int
demangle_read_expression(struct demangle_data *ddata)
{
if (ddata->depth == MAX_DEPTH)
__builtin_longjmp(ddata->jmpbuf, 1);
++ddata->depth;
int res = demangle_read_expression_impl(ddata);
--ddata->depth;
return res;
}
ABI static int
static privileged int
demangle_read_expression_flat(struct demangle_data *ddata, char **str)
{
struct vector_str *output;
@ -2588,7 +2567,7 @@ demangle_read_expression_flat(struct demangle_data *ddata, char **str)
}
/* size, capacity, ext_name */
ABI static void
static privileged void
demangle_vector_type_qualifier_init(struct demangle_data *ddata,
struct vector_type_qualifier *v)
{
@ -2604,7 +2583,7 @@ demangle_vector_type_qualifier_init(struct demangle_data *ddata,
demangle_vector_str_init(ddata, &v->ext_name);
}
ABI static struct read_cmd_item *
static privileged struct read_cmd_item *
demangle_vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
{
int i;
@ -2619,7 +2598,7 @@ demangle_vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
return 0;
}
ABI static int
static privileged int
demangle_read_function(struct demangle_data *ddata, int *ext_c,
struct vector_type_qualifier *v)
{
@ -2755,7 +2734,7 @@ demangle_read_function(struct demangle_data *ddata, int *ext_c,
return 1;
}
ABI static int
static privileged int
demangle_read_offset_number(struct demangle_data *ddata)
{
bool negative;
@ -2773,7 +2752,7 @@ demangle_read_offset_number(struct demangle_data *ddata)
start = ddata->cur;
}
while (*ddata->cur && *ddata->cur != '_')
while (*ddata->cur != '_')
++ddata->cur;
if (negative && !DEM_PUSH_STR(ddata, "-"))
@ -2791,7 +2770,7 @@ demangle_read_offset_number(struct demangle_data *ddata)
return 1;
}
ABI static int
static privileged int
demangle_read_nv_offset(struct demangle_data *ddata)
{
if (!DEM_PUSH_STR(ddata, "offset : "))
@ -2800,7 +2779,7 @@ demangle_read_nv_offset(struct demangle_data *ddata)
return demangle_read_offset_number(ddata);
}
ABI static int
static privileged int
demangle_read_v_offset(struct demangle_data *ddata)
{
if (!DEM_PUSH_STR(ddata, "offset : "))
@ -2816,7 +2795,7 @@ demangle_read_v_offset(struct demangle_data *ddata)
}
/* read offset, offset are nv-offset, v-offset */
ABI static int
static privileged int
demangle_read_offset(struct demangle_data *ddata)
{
if (*ddata->cur == 'h') {
@ -2830,7 +2809,7 @@ demangle_read_offset(struct demangle_data *ddata)
return 0;
}
ABI static int
static privileged int
demangle_read_type_flat(struct demangle_data *ddata, char **str)
{
struct vector_str *output;
@ -2862,7 +2841,7 @@ demangle_read_type_flat(struct demangle_data *ddata, char **str)
* read number
* number ::= [n] <decimal>
*/
ABI static int
static privileged int
demangle_read_number(struct demangle_data *ddata, long *rtn)
{
long len, negative_factor;
@ -2880,18 +2859,19 @@ demangle_read_number(struct demangle_data *ddata, long *rtn)
return 0;
len = demangle_strtol(ddata->cur, 10);
if (len < 0)
__builtin_longjmp(ddata->jmpbuf, 1);
while (ELFTC_ISDIGIT(*ddata->cur))
++ddata->cur;
ASSERT(len >= 0);
ASSERT(negative_factor == 1 || negative_factor == -1);
*rtn = len * negative_factor;
return 1;
}
ABI static int
static privileged int
demangle_read_number_as_string(struct demangle_data *ddata, char **str)
{
long n;
@ -2908,8 +2888,9 @@ demangle_read_number_as_string(struct demangle_data *ddata, char **str)
return 1;
}
ABI static int
demangle_read_encoding_impl(struct demangle_data *ddata)
/* read encoding, encoding are function name, data name, special-name */
static privileged int
demangle_read_encoding(struct demangle_data *ddata)
{
char *name, *type, *num_str;
long offset;
@ -3116,19 +3097,7 @@ demangle_read_encoding_impl(struct demangle_data *ddata)
return demangle_read_name(ddata);
}
/* read encoding, encoding are function name, data name, special-name */
ABI static int
demangle_read_encoding(struct demangle_data *ddata)
{
if (ddata->depth == MAX_DEPTH)
__builtin_longjmp(ddata->jmpbuf, 1);
++ddata->depth;
int res = demangle_read_encoding_impl(ddata);
--ddata->depth;
return res;
}
ABI static int
static privileged int
demangle_read_local_name(struct demangle_data *ddata)
{
struct vector_str local_name;
@ -3209,7 +3178,7 @@ demangle_read_local_name(struct demangle_data *ddata)
return 1;
}
ABI static int
static privileged int
demangle_read_nested_name(struct demangle_data *ddata)
{
struct stack_str v;
@ -3297,8 +3266,8 @@ next:
return 1;
}
ABI static int
demangle_read_name_impl(struct demangle_data *ddata)
static privileged int
demangle_read_name(struct demangle_data *ddata)
{
struct stack_str v;
struct vector_str *output;
@ -3359,18 +3328,7 @@ clean:
return rtn;
}
ABI static int
demangle_read_name(struct demangle_data *ddata)
{
if (ddata->depth == MAX_DEPTH)
__builtin_longjmp(ddata->jmpbuf, 1);
++ddata->depth;
int res = demangle_read_name_impl(ddata);
--ddata->depth;
return res;
}
ABI static int
static privileged int
demangle_read_name_flat(struct demangle_data *ddata, char **str)
{
struct vector_str *output;
@ -3398,7 +3356,7 @@ demangle_read_name_flat(struct demangle_data *ddata, char **str)
return 1;
}
ABI static int
static privileged int
demangle_read_pointer_to_member(struct demangle_data *ddata,
struct vector_type_qualifier *v)
{
@ -3458,10 +3416,9 @@ clean1:
}
/* read source-name, source-name is <len> <ID> */
ABI static int
static privileged int
demangle_read_sname(struct demangle_data *ddata)
{
size_t lim;
long len;
int err;
@ -3481,15 +3438,12 @@ demangle_read_sname(struct demangle_data *ddata)
ddata->last_sname = VEC_STR(ddata, ddata->cur_output,
ddata->cur_output->size - 1);
lim = demangle_strlen(ddata->cur);
if (len > lim)
len = lim;
ddata->cur += len;
return 1;
}
ABI static int
static privileged int
demangle_read_subst_stdtmpl(struct demangle_data *ddata, const char *str)
{
struct vector_str *output;
@ -3527,7 +3481,7 @@ demangle_read_subst_stdtmpl(struct demangle_data *ddata, const char *str)
return 1;
}
ABI static int
static privileged int
demangle_read_subst_std(struct demangle_data *ddata)
{
struct vector_str *output, v;
@ -3578,7 +3532,7 @@ demangle_read_subst_std(struct demangle_data *ddata)
return 1;
}
ABI static int
static privileged int
demangle_read_subst(struct demangle_data *ddata)
{
long nth;
@ -3693,11 +3647,10 @@ demangle_read_subst(struct demangle_data *ddata)
/* first was '_', so increase one */
++nth;
while (*ddata->cur && *ddata->cur != '_')
while (*ddata->cur != '_')
++ddata->cur;
if (nth <= 0)
return 0;
ASSERT(nth > 0);
return demangle_get_subst(ddata, nth);
}
@ -3706,7 +3659,7 @@ demangle_read_subst(struct demangle_data *ddata)
return 0;
}
ABI static int
static privileged int
demangle_vector_type_qualifier_push(struct demangle_data *ddata,
struct vector_type_qualifier *v, enum type_qualifier t)
{
@ -3735,8 +3688,8 @@ demangle_vector_type_qualifier_push(struct demangle_data *ddata,
return 1;
}
ABI static int
demangle_read_type_impl(struct demangle_data *ddata, struct type_delimit *td)
static privileged int
demangle_read_type(struct demangle_data *ddata, struct type_delimit *td)
{
struct vector_type_qualifier v;
struct vector_str *output, sv;
@ -3928,7 +3881,7 @@ again:
case 'E':
/* unexpected end (except some things) */
if (td && ddata->is_guard_variable)
if (ddata->is_guard_variable)
td->paren = false;
if (ddata->is_guard_variable ||
(ddata->ref_qualifier && ddata->is_functype)) {
@ -4149,8 +4102,6 @@ again:
if (!demangle_vector_str_push(ddata, &v.ext_name, ddata->cur,
len))
return 0;
if (len > demangle_strlen(ddata->cur))
len = demangle_strlen(ddata->cur);
ddata->cur += len;
if (!demangle_vector_type_qualifier_push(ddata, &v, TYPE_EXT))
return 0;
@ -4258,18 +4209,7 @@ clean:
return 0;
}
ABI static int
demangle_read_type(struct demangle_data *ddata, struct type_delimit *td)
{
if (ddata->depth == MAX_DEPTH)
__builtin_longjmp(ddata->jmpbuf, 1);
++ddata->depth;
int res = demangle_read_type_impl(ddata, td);
--ddata->depth;
return res;
}
ABI static int
static privileged int
demangle_copy_output(struct demangle_data *ddata, char *buf,
const struct vector_str *v, size_t buflen)
{
@ -4292,14 +4232,14 @@ demangle_copy_output(struct demangle_data *ddata, char *buf,
return -1;
}
ABI static int
static privileged int
demangle_failure(char *buf, const char *org, size_t buflen)
{
demangle_strlcpy(buf, org, buflen);
return -1;
}
ABI static int
static privileged int
demangle(struct demangle_data *ddata, char *buf, const char *org, size_t buflen)
{
struct vector_str ret_type;
@ -4451,7 +4391,7 @@ demangle(struct demangle_data *ddata, char *buf, const char *org, size_t buflen)
* @return bytes of output name or -1 upon error or truncation
* @asyncsignalsafe
*/
ABI int
privileged int
__demangle(char *buf, const char *org, size_t buflen)
{
struct demangle_data ddata[1];
@ -4465,7 +4405,7 @@ __demangle(char *buf, const char *org, size_t buflen)
*
* This means it starts with either "_Z" or "_GLOBAL__I_".
*/
ABI int
privileged int
__is_mangled(const char *org)
{
if (!org)

View file

@ -1,32 +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 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

@ -24,15 +24,13 @@
#define N 160
#define ABI privileged optimizesize
ABI static bool IsDangerous(const void *ptr) {
privileged static bool IsDangerous(const void *ptr) {
if (_weaken(kisdangerous))
return _weaken(kisdangerous)(ptr);
return false;
}
ABI static char *FormatHex(char *p, unsigned long x) {
privileged static char *FormatHex(char *p, unsigned long x) {
int k = x ? (__builtin_clzl(x) ^ 63) + 1 : 1;
k = (k + 3) & -4;
while (k > 0)
@ -41,7 +39,8 @@ ABI static char *FormatHex(char *p, unsigned long x) {
return p;
}
ABI const char *_DescribeBacktrace(char buf[N], const struct StackFrame *fr) {
privileged dontinstrument const char *_DescribeBacktrace(
char buf[N], const struct StackFrame *fr) {
char *p = buf;
char *pe = p + N;
bool gotsome = false;

View file

@ -29,7 +29,6 @@ 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;
@ -88,7 +87,6 @@ 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

@ -16,29 +16,25 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/macros.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#define MAP_GROWSDOWN_LINUX 0x00000100
const char *_DescribeMapFlags(char buf[64], int x) {
const struct DescribeFlags kMapFlags[] = {
{MAP_PRIVATE, "PRIVATE"}, //
{MAP_ANONYMOUS, "ANONYMOUS"}, //
{MAP_SHARED, "SHARED"}, //
{MAP_FIXED, "FIXED"}, //
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
{MAP_HUGETLB, "HUGETLB"}, //
{MAP_CONCEAL, "CONCEAL"}, //
{MAP_LOCKED, "LOCKED"}, //
{MAP_NORESERVE, "NORESERVE"}, //
{MAP_NONBLOCK, "NONBLOCK"}, //
{MAP_POPULATE, "POPULATE"}, //
{IsLinux() ? MAP_GROWSDOWN_LINUX : 0, "GROWSDOWN"}, //
{MAP_PRIVATE, "PRIVATE"}, //
{MAP_ANONYMOUS, "ANONYMOUS"}, //
{MAP_SHARED, "SHARED"}, //
{MAP_FIXED, "FIXED"}, //
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
{MAP_HUGETLB, "HUGETLB"}, //
{MAP_CONCEAL, "CONCEAL"}, //
{MAP_LOCKED, "LOCKED"}, //
{MAP_NORESERVE, "NORESERVE"}, //
{MAP_NONBLOCK, "NONBLOCK"}, //
{MAP_POPULATE, "POPULATE"}, //
};
return _DescribeFlags(buf, 64, kMapFlags, ARRAYLEN(kMapFlags), "MAP_", x);
}

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/describeflags.h"
#include "libc/intrin/maps.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
@ -25,13 +24,12 @@
static char DescribeMapType(int flags) {
switch (flags & MAP_TYPE) {
case MAP_FILE:
if (flags & MAP_NOFORK)
return 'i'; // executable image
return '-';
case MAP_PRIVATE:
if (flags & MAP_NOFORK)
return 'w'; // windows memory
return 'p';
return 'P';
else
return 'p';
case MAP_SHARED:
return 's';
default:

View file

@ -21,8 +21,6 @@
#include "libc/sysv/consts/prot.h"
const char *_DescribeProtFlags(char buf[48], int x) {
if (!x)
return "PROT_NONE";
const struct DescribeFlags kProtFlags[] = {
{PROT_READ, "READ"}, //
{PROT_WRITE, "WRITE"}, //

View file

@ -19,6 +19,7 @@
#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"
@ -31,11 +32,19 @@
static uint64_t sys_mmap_metal_break;
void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
int64_t off) {
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) {
/* 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();
@ -45,18 +54,18 @@ void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
struct Fd *sfd;
struct MetalFile *file;
if (off < 0 || fd < 0 || fd >= g_fds.n)
return MAP_FAILED;
return bad_mmap();
sfd = &g_fds.p[fd];
if (sfd->kind != kFdFile)
return MAP_FAILED;
return bad_mmap();
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 MAP_FAILED;
return bad_mmap();
faddr = (uint64_t)file->base + off;
if (faddr % 4096 != 0)
return MAP_FAILED;
return bad_mmap();
}
if (!(flags & MAP_FIXED_linux)) {
if (!addr) {
@ -79,7 +88,7 @@ void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
if ((flags & MAP_ANONYMOUS_linux)) {
page = __new_page(mm);
if (!page)
return MAP_FAILED;
return bad_mmap();
__clear_page(BANE + page);
e = page | PAGE_RSRV | PAGE_U;
if ((prot & PROT_WRITE))
@ -105,7 +114,9 @@ void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
break;
}
}
return (void *)addr;
res.addr = (void *)addr;
res.maphandle = -1;
return res;
}
#endif /* __x86_64__ */

122
libc/intrin/directmap-nt.c Normal file
View file

@ -0,0 +1,122 @@
/*-*- 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,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 2024 Justine Alexandra Roberts Tunney
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
@ -16,60 +16,51 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/directmap.h"
#include "libc/intrin/strace.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/errfuns.h"
// returns true if byte at memory address is readable
bool readable(void *addr) {
return testlib_pokememory(addr);
}
// returns true if page is reserved by linux memory manager
// it can be true for addresses that aren't listed in /proc/PID/maps
bool occupied(void *addr) {
int olde = errno;
char *want = (char *)((uintptr_t)addr & -__pagesize);
char *got =
__sys_mmap(want, __pagesize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0, 0);
if (got == MAP_FAILED) {
unassert(errno == IsFreebsd() ? EINVAL : EEXIST);
errno = olde;
return true;
/**
* 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);
}
sys_munmap(got, __pagesize);
return got != want;
}
TEST(stack, test) {
if (IsWindows())
return;
void *vstackaddr;
size_t stacksize = 65536;
size_t guardsize = 4096;
unassert(!cosmo_stack_alloc(&stacksize, &guardsize, &vstackaddr));
char *stackaddr = vstackaddr;
/* check memory reservation */
unassert(occupied(stackaddr + stacksize - 1)); // top stack
unassert(occupied(stackaddr)); // bot stack
unassert(occupied(stackaddr - 1)); // top guard
unassert(occupied(stackaddr - guardsize)); // bot guard
/* check memory accessibility */
unassert(readable(stackaddr + stacksize - 1)); // top stack
unassert(readable(stackaddr)); // bot stack
unassert(!readable(stackaddr - 1)); // top guard
unassert(!readable(stackaddr - guardsize)); // bot guard
unassert(!cosmo_stack_free(stackaddr, stacksize, guardsize));
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,7 +2,19 @@
#define COSMOPOLITAN_LIBC_INTRIN_DIRECTMAP_H_
COSMOPOLITAN_C_START_
void *sys_mmap_metal(void *, size_t, int, int, int, int64_t) libcesque;
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);
int sys_munmap_metal(void *, size_t) libcesque;
int __prot2nt(int, int) libcesque;

View file

@ -1,34 +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 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/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
static pthread_mutex_t __dlopen_lock_obj = PTHREAD_MUTEX_INITIALIZER;
void __dlopen_lock(void) {
_pthread_mutex_lock(&__dlopen_lock_obj);
}
void __dlopen_unlock(void) {
_pthread_mutex_unlock(&__dlopen_lock_obj);
}
void __dlopen_wipe(void) {
_pthread_mutex_wipe_np(&__dlopen_lock_obj);
}

View file

@ -44,13 +44,15 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#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;
@ -84,14 +86,19 @@ static textwindows void SetupWinStd(struct Fds *fds, int i, uint32_t x) {
}
textstartup void __init_fds(int argc, char **argv, char **envp) {
struct Fds *fds;
fds = &g_fds;
fds->n = 4;
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize);
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;
}
// inherit standard i/o file descriptors
if (IsMetal()) {
@ -145,7 +152,8 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
break;
if (!TokAtoi(&fdspec, &protocol))
break;
__ensurefds_unlocked(fd);
if (_weaken(__ensurefds_unlocked))
_weaken(__ensurefds_unlocked)(fd);
struct Fd *f = fds->p + fd;
if (f->handle && f->handle != -1 && f->handle != handle) {
CloseHandle(f->handle);
@ -180,9 +188,7 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
map->prot = PROT_READ | PROT_WRITE;
map->flags = MAP_SHARED | MAP_ANONYMOUS;
map->hand = shand;
__maps_lock();
__maps_insert(map);
__maps_unlock();
}
}
}

View file

@ -17,13 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/state.internal.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
void __fds_lock(void) {
_pthread_mutex_lock(&__fds_lock_obj);
pthread_mutex_lock(&__fds_lock_obj);
}
void __fds_unlock(void) {
_pthread_mutex_unlock(&__fds_lock_obj);
pthread_mutex_unlock(&__fds_lock_obj);
}

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 2024 Justine Alexandra Roberts Tunney
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
@ -16,8 +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/testlib/testlib.h"
#include "libc/stdio/fflush.internal.h"
int main(int argc, char *argv[]) {
}
pthread_mutex_t __fflush_lock_obj;
struct StdioFlush __fflush;

View file

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

View file

@ -17,13 +17,16 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/rlimit.internal.h"
#include "libc/dce.h"
#include "libc/intrin/getauxval.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/rlimit.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
// Hack for guessing boundaries of _start()'s stack
//
@ -88,9 +91,12 @@ static uintptr_t __get_main_top(int pagesz) {
}
static size_t __get_stack_size(int pagesz, uintptr_t start, uintptr_t top) {
size_t stacksz = __rlimit_stack_get().rlim_cur;
stacksz = MIN(stacksz, 1024ul * 1024 * 1024 * 1024);
return MAX(ROUNDDOWN(stacksz, pagesz), ROUNDUP(top - start, pagesz));
size_t size, max = 8 * 1024 * 1024;
struct rlimit rlim = {RLIM_INFINITY};
sys_getrlimit(RLIMIT_STACK, &rlim);
if ((size = rlim.rlim_cur) > max)
size = max;
return MAX(ROUNDUP(size, pagesz), ROUNDUP(top - start, pagesz));
}
/**

View file

@ -16,47 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/intrin/getauxval.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ss.h"
long __get_minsigstksz(void) {
struct AuxiliaryValue av;
av = __getauxval(AT_MINSIGSTKSZ);
if (av.isfound) {
long res = av.value;
if (!IsLinux())
res += sizeof(struct ucontext) + sizeof(struct siginfo) + 128;
if (res < _MINSIGSTKSZ)
res = _MINSIGSTKSZ;
return res;
struct AuxiliaryValue x;
x = __getauxval(AT_MINSIGSTKSZ);
if (x.isfound) {
return MAX(_MINSIGSTKSZ, x.value);
} else {
// _MINSIGSTKSZ takes these things into consideration:
//
// 1. The platform definition of MINSIGSTKSZ. This will probably be
// enforced by the kernel when calling sys_sigaltstack(). On ARM
// platforms this might be several kilobytes larger than x86. On
// Linux they really want you to use AT_MINSIGSTKSZ instead. The
// kernel should ideally set this to be the number of bytes that
// get subtracted from the stack pointer when delivering signals
// meaning that if you use this for a stack size your handler is
// called successfully but if it uses the stack then it'll crash
//
// 2. Cosmo sigenter overhead. On non-Linux OSes the kernel calls a
// trampoline in the libc runtime, which translates the platform
// specific signal frame to the Linux memory layout. It means we
// need to push ~1024 extra bytes on the stack to call a handler
//
// 3. Sanity testing. Assume we use sysconf(_SC_MINSIGSTKSZ) + 2048
// as our stack size (see stackoverflow1_test.c). Then we should
// have enough room to use kprintf() from our signal handler. If
// that isn't the case, then this should be increased a bit more
// noting that if 1024 is used then kprintf should print refusal
//
return _MINSIGSTKSZ;
}
}

View file

@ -17,11 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "ape/sections.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.internal.h"
/**
* Computes safer buffer size for alloca().
@ -31,19 +32,18 @@
* @return number of bytes to use for your buffer, or negative if the
* allocation would likely cause a stack overflow
*/
privileged optimizesize long __get_safe_size(long want, long extraspace) {
privileged long __get_safe_size(long want, long extraspace) {
if (!__tls_enabled)
return want;
struct PosixThread *pt;
struct CosmoTib *tib = __get_tls_privileged();
long bottom, sp = GetStackPointer();
if (sp >= (long)tib->tib_sigstack_addr &&
sp < (long)tib->tib_sigstack_addr + tib->tib_sigstack_size) {
if ((char *)sp >= tib->tib_sigstack_addr &&
(char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) {
bottom = (long)tib->tib_sigstack_addr;
} else if ((pt = (struct PosixThread *)tib->tib_pthread) &&
sp >= (long)pt->pt_attr.__stackaddr &&
sp < (long)pt->pt_attr.__stackaddr + pt->pt_attr.__stacksize) {
bottom = (long)pt->pt_attr.__stackaddr;
pt->pt_attr.__stacksize) {
bottom = (long)pt->pt_attr.__stackaddr + pt->pt_attr.__guardsize;
} else {
return want;
}

View file

@ -39,7 +39,7 @@
int gettid(void) {
int tid;
if (VERY_LIKELY(__tls_enabled && !__vforked)) {
tid = atomic_load_explicit(&__get_tls()->tib_ptid, memory_order_relaxed);
tid = atomic_load_explicit(&__get_tls()->tib_tid, memory_order_acquire);
if (VERY_LIKELY(tid > 0))
return tid;
}

View file

@ -1,43 +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 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/thread/itimer.h"
#include "libc/str/str.h"
#include "libc/thread/posixthread.internal.h"
struct IntervalTimer __itimer = {
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
};
textwindows void __itimer_lock(void) {
_pthread_mutex_lock(&__itimer.lock);
}
textwindows void __itimer_unlock(void) {
_pthread_mutex_unlock(&__itimer.lock);
}
textwindows void __itimer_wipe_and_reset(void) {
// timers aren't inherited by forked subprocesses
bzero(&__itimer.it, sizeof(__itimer.it));
_pthread_mutex_wipe_np(&__itimer.lock);
bzero(&__itimer.cond, sizeof(__itimer.cond));
__itimer.thread = 0;
__itimer.once = 0;
}

View file

@ -1,38 +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 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/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/runtime/runtime.h"
privileged optimizesize bool32 kisdangerous(const void *addr) {
bool32 res = true;
__maps_lock();
if (__maps.maps) {
struct Map *map;
if ((map = __maps_floor(addr)))
if ((const char *)addr >= map->addr &&
(const char *)addr <
map->addr + ((map->size + __pagesize - 1) & -__pagesize))
res = false;
} else {
res = false;
}
__maps_unlock();
return res;
}

View file

@ -65,11 +65,10 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.internal.h"
#include "libc/vga/vga.internal.h"
#include "libc/wctype.h"
#define ABI privileged optimizesize
#define STACK_ERROR "kprintf error: stack is about to overflow\n"
#define KGETINT(x, va, t, s) \
@ -160,7 +159,23 @@ __funline bool kischarmisaligned(const char *p, signed char t) {
return false;
}
ABI static void klogclose(long fd) {
privileged bool32 kisdangerous(const void *addr) {
bool32 res = true;
__maps_lock();
if (__maps.maps) {
struct Map *map;
if ((map = __maps_floor(addr)))
if ((const char *)addr >= map->addr &&
(const char *)addr < map->addr + map->size)
res = false;
} else {
res = false;
}
__maps_unlock();
return res;
}
privileged static void klogclose(long fd) {
#ifdef __x86_64__
long ax = __NR_close;
asm volatile("syscall"
@ -177,7 +192,7 @@ ABI static void klogclose(long fd) {
#endif
}
ABI static long klogfcntl(long fd, long cmd, long arg) {
privileged static long klogfcntl(long fd, long cmd, long arg) {
#ifdef __x86_64__
char cf;
long ax = __NR_fcntl;
@ -209,7 +224,7 @@ ABI static long klogfcntl(long fd, long cmd, long arg) {
#endif
}
ABI static long klogopen(const char *path) {
privileged static long klogopen(const char *path) {
long dirfd = AT_FDCWD;
long flags = O_WRONLY | O_CREAT | O_APPEND;
long mode = 0600;
@ -248,7 +263,7 @@ ABI static long klogopen(const char *path) {
}
// returns log handle or -1 if logging shouldn't happen
ABI long kloghandle(void) {
privileged long kloghandle(void) {
// kprintf() needs to own a file descriptor in case apps closes stderr
// our close() and dup() implementations will trigger this initializer
// to minimize a chance that the user accidentally closes their logger
@ -327,7 +342,7 @@ ABI long kloghandle(void) {
}
#ifdef __x86_64__
ABI void _klog_serial(const char *b, size_t n) {
privileged void _klog_serial(const char *b, size_t n) {
size_t i;
uint16_t dx;
unsigned char al;
@ -347,13 +362,14 @@ ABI void _klog_serial(const char *b, size_t n) {
}
#endif /* __x86_64__ */
ABI void klog(const char *b, size_t n) {
privileged void klog(const char *b, size_t n) {
#ifdef __x86_64__
long h;
uint32_t wrote;
long rax, rdi, rsi, rdx;
if ((h = kloghandle()) == -1)
if ((h = kloghandle()) == -1) {
return;
}
if (IsWindows()) {
bool32 ok;
intptr_t ev;
@ -404,14 +420,14 @@ ABI void klog(const char *b, size_t n) {
#endif
}
ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
privileged static size_t kformat(char *b, size_t n, const char *fmt,
va_list va) {
int si;
wint_t t, u;
char *cxxbuf;
const char *abet;
signed char type;
const char *s, *f;
int cxxbufsize = 0;
char cxxbuf[3000];
struct CosmoTib *tib;
unsigned long long x;
unsigned i, j, m, rem, sign, hash, cols, prec;
@ -561,7 +577,7 @@ ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
tib = __tls_enabled ? __get_tls_privileged() : 0;
if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) {
if (tib) {
x = atomic_load_explicit(&tib->tib_ptid, memory_order_relaxed);
x = atomic_load_explicit(&tib->tib_tid, memory_order_relaxed);
} else {
x = __pid;
}
@ -755,25 +771,13 @@ ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
x = va_arg(va, intptr_t);
if (_weaken(__symtab) && *_weaken(__symtab) &&
(idx = _weaken(__get_symbol)(0, x)) != -1) {
/* if (p + 1 <= e) */
/* *p++ = '&'; */
s = (*_weaken(__symtab))->name_base +
(*_weaken(__symtab))->names[idx];
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
// decipher c++ symbols if there's enough stack memory
// stack size requirement assumes max_depth's still 20
if (_weaken(__demangle) && //
_weaken(__is_mangled) && //
_weaken(__is_mangled)(s)) {
if (!cxxbufsize)
if ((cxxbufsize = __get_safe_size(8192, 8192)) >= 512) {
cxxbuf = alloca(cxxbufsize);
CheckLargeStackAllocation(cxxbuf, sizeof(cxxbufsize));
}
if (cxxbufsize >= 512)
if (_weaken(__demangle)(cxxbuf, s, cxxbufsize) != -1)
s = cxxbuf;
}
#pragma GCC pop_options
if (_weaken(__is_mangled) && _weaken(__is_mangled)(s) &&
_weaken(__demangle)(cxxbuf, s, sizeof(cxxbuf)) != -1)
s = cxxbuf;
goto FormatString;
}
base = 4;
@ -1029,7 +1033,7 @@ ABI static size_t kformat(char *b, size_t n, const char *fmt, va_list va) {
* @asyncsignalsafe
* @vforksafe
*/
ABI size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
privileged size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
size_t m;
va_list v;
va_start(v, fmt);
@ -1048,7 +1052,7 @@ ABI size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
* @asyncsignalsafe
* @vforksafe
*/
ABI size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
return kformat(b, n, fmt, v);
}
@ -1059,10 +1063,10 @@ ABI size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
* @asyncsignalsafe
* @vforksafe
*/
ABI void kvprintf(const char *fmt, va_list v) {
privileged void kvprintf(const char *fmt, va_list v) {
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
long size = __get_safe_size(8192, 2048);
long size = __get_safe_size(8000, 8000);
if (size < 80) {
klog(STACK_ERROR, sizeof(STACK_ERROR) - 1);
return;
@ -1145,7 +1149,7 @@ ABI void kvprintf(const char *fmt, va_list v) {
* @asyncsignalsafe
* @vforksafe
*/
ABI void kprintf(const char *fmt, ...) {
privileged void kprintf(const char *fmt, ...) {
// system call support runtime depends on this function
// function tracing runtime depends on this function
// asan runtime depends on this function

View file

@ -1,34 +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 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/thread/posixthread.internal.h"
#include "third_party/tz/lock.h"
static pthread_mutex_t __localtime_lock_obj = PTHREAD_MUTEX_INITIALIZER;
void __localtime_lock(void) {
_pthread_mutex_lock(&__localtime_lock_obj);
}
void __localtime_unlock(void) {
_pthread_mutex_unlock(&__localtime_lock_obj);
}
void __localtime_wipe(void) {
_pthread_mutex_wipe_np(&__localtime_lock_obj);
}

View file

@ -1,50 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_LOCKLESS_H_
#define COSMOPOLITAN_LIBC_INTRIN_LOCKLESS_H_
#include "libc/atomic.h"
#include "libc/intrin/atomic.h"
COSMOPOLITAN_C_START_
// lockless memory transactions
//
// - one writer
// - many readers
// - generation is monotonic
// - even numbers mean memory is ready
// - odd numbers mean memory is actively being changed
// - always use acquire semantics inside your read transaction
//
// let's say you want to be able to atomically read and write to 128-bit
// values, but you've only got a 64-bit system. if you expect that it'll
// frequently written, then you should use a mutex. but if you expect it
// to be frequently read and rarely written, then it's possible to do it
// without a mutex; in fact you don't even need the x86 lock instruction
// prefix; all that is required is a series of carefully ordered mov ops
// which are designed to exploit the strong ordering of the architecture
static inline unsigned lockless_write_begin(atomic_uint* genptr) {
unsigned gen = atomic_load_explicit(genptr, memory_order_acquire);
atomic_store_explicit(genptr, gen + 1, memory_order_release);
return gen;
}
static inline void lockless_write_end(atomic_uint* genptr, unsigned gen) {
atomic_store_explicit(genptr, gen + 2, memory_order_release);
}
static inline unsigned lockless_read_begin(atomic_uint* genptr) {
return atomic_load_explicit(genptr, memory_order_acquire);
}
static inline bool lockless_read_end(atomic_uint* genptr, unsigned* want) {
unsigned gen1 = *want;
unsigned gen2 = atomic_load_explicit(genptr, memory_order_acquire);
unsigned is_being_actively_changed = gen1 & 1;
unsigned we_lost_race_with_writers = gen1 ^ gen2;
if (!(is_being_actively_changed | we_lost_race_with_writers))
return true;
*want = gen2;
return false;
}
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_INTRIN_LOCKLESS_H_ */

View file

@ -19,27 +19,21 @@
#include "libc/intrin/maps.h"
#include "ape/sections.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/macros.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/lock.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
__static_yoink("_init_maps");
#endif
#define ABI privileged optimizespeed
struct Maps __maps;
void __maps_add(struct Map *map) {
@ -57,109 +51,74 @@ void __maps_stack(char *stackaddr, int pagesz, int guardsize, size_t stacksize,
__maps.stack.addr = stackaddr + guardsize;
__maps.stack.size = stacksize - guardsize;
__maps.stack.prot = stackprot;
__maps.stack.hand = MAPS_SUBREGION;
__maps.stack.flags = MAP_PRIVATE | MAP_ANONYMOUS;
__maps.stack.hand = -1;
__maps_adder(&__maps.stack, pagesz);
if (guardsize) {
__maps.guard.addr = stackaddr;
__maps.guard.size = guardsize;
__maps.guard.prot = PROT_NONE | PROT_GUARD;
__maps.guard.prot = PROT_NONE;
__maps.guard.hand = stackhand;
__maps.guard.flags = MAP_PRIVATE | MAP_ANONYMOUS;
__maps_adder(&__maps.guard, pagesz);
} else {
__maps.stack.hand = stackhand;
}
}
void __maps_init(void) {
int pagesz = __pagesize;
// initialize lemur64
__maps.rand = 2131259787901769494;
__maps.rand ^= kStartTsc;
// these static map objects avoid mandatory mmap() in __maps_alloc()
// they aren't actually needed for bootstrapping this memory manager
for (int i = 0; i < ARRAYLEN(__maps.spool); ++i)
__maps_free(&__maps.spool[i]);
// record _start() stack mapping
if (!IsWindows()) {
// linux v4.12+ reserves 1mb of guard space beneath rlimit_stack
// https://lwn.net/Articles/725832/. if we guess too small, then
// slackmap will create a bunch of zombie stacks in __print_maps
// to coverup the undisclosed memory but no cost if we guess big
size_t guardsize = 1024 * 1024;
guardsize += __pagesize - 1;
guardsize &= -__pagesize;
// track the main stack region that the os gave to start earlier
struct AddrSize stack = __get_main_stack();
__maps_stack(stack.addr - guardsize, pagesz, guardsize,
guardsize + stack.size, (uintptr_t)ape_stack_prot, 0);
struct AddrSize stack;
stack = __get_main_stack();
__maps_stack(stack.addr, pagesz, 0, stack.size, (uintptr_t)ape_stack_prot,
0);
}
// record .text and .data mappings
__maps_track((char *)__executable_start, _etext - __executable_start,
PROT_READ | PROT_EXEC, MAP_NOFORK);
static struct Map text, data;
text.addr = (char *)__executable_start;
text.size = _etext - __executable_start;
text.prot = PROT_READ | PROT_EXEC;
uintptr_t ds = ((uintptr_t)_etext + pagesz - 1) & -pagesz;
if (ds < (uintptr_t)_end)
__maps_track((char *)ds, (uintptr_t)_end - ds, PROT_READ | PROT_WRITE,
MAP_NOFORK);
if (ds < (uintptr_t)_end) {
data.addr = (char *)ds;
data.size = (uintptr_t)_end - ds;
data.prot = PROT_READ | PROT_WRITE;
__maps_adder(&data, pagesz);
}
__maps_adder(&text, pagesz);
}
bool __maps_held(void) {
return !__tls_enabled || (__get_tls()->tib_flags & TIB_FLAG_VFORKED) ||
MUTEX_OWNER(
atomic_load_explicit(&__maps.lock.word, memory_order_relaxed)) ==
atomic_load_explicit(&__get_tls()->tib_ptid, memory_order_relaxed);
}
bool __maps_reentrant(void) {
return __tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_VFORKED) &&
MUTEX_OWNER(
atomic_load_explicit(&__maps.lock.word, memory_order_relaxed)) ==
atomic_load_explicit(&__get_tls()->tib_ptid, memory_order_relaxed);
}
ABI void __maps_lock(void) {
privileged bool __maps_lock(void) {
int me;
uint64_t word, lock;
struct CosmoTib *tib;
if (!__tls_enabled)
return;
return false;
if (!(tib = __get_tls_privileged()))
return;
return false;
if (tib->tib_flags & TIB_FLAG_VFORKED)
return;
me = atomic_load_explicit(&tib->tib_ptid, memory_order_relaxed);
word = 0;
lock = MUTEX_LOCK(word);
lock = MUTEX_SET_OWNER(lock, me);
if (atomic_compare_exchange_strong_explicit(&__maps.lock.word, &word, lock,
memory_order_acquire,
memory_order_relaxed))
return;
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
return false;
me = atomic_load_explicit(&tib->tib_tid, memory_order_acquire);
if (me <= 0)
return false;
word = atomic_load_explicit(&__maps.lock, memory_order_relaxed);
for (;;) {
if (MUTEX_OWNER(word) == me) {
if (atomic_compare_exchange_weak_explicit(
&__maps.lock.word, &word, MUTEX_INC_DEPTH(word),
memory_order_relaxed, memory_order_relaxed))
return;
&__maps.lock, &word, MUTEX_INC_DEPTH(word), memory_order_relaxed,
memory_order_relaxed))
return true;
continue;
}
word = 0;
lock = MUTEX_LOCK(word);
lock = MUTEX_SET_OWNER(lock, me);
if (atomic_compare_exchange_weak_explicit(&__maps.lock.word, &word, lock,
if (atomic_compare_exchange_weak_explicit(&__maps.lock, &word, lock,
memory_order_acquire,
memory_order_relaxed))
return;
return false;
for (;;) {
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
word = atomic_load_explicit(&__maps.lock, memory_order_relaxed);
if (MUTEX_OWNER(word) == me)
break;
if (!word)
@ -168,7 +127,8 @@ ABI void __maps_lock(void) {
}
}
ABI void __maps_unlock(void) {
privileged void __maps_unlock(void) {
int me;
uint64_t word;
struct CosmoTib *tib;
if (!__tls_enabled)
@ -177,16 +137,19 @@ ABI void __maps_unlock(void) {
return;
if (tib->tib_flags & TIB_FLAG_VFORKED)
return;
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
me = atomic_load_explicit(&tib->tib_tid, memory_order_acquire);
if (me <= 0)
return;
word = atomic_load_explicit(&__maps.lock, memory_order_relaxed);
for (;;) {
if (MUTEX_DEPTH(word))
if (MUTEX_DEPTH(word)) {
if (atomic_compare_exchange_weak_explicit(
&__maps.lock.word, &word, MUTEX_DEC_DEPTH(word),
memory_order_relaxed, memory_order_relaxed))
&__maps.lock, &word, MUTEX_DEC_DEPTH(word), memory_order_relaxed,
memory_order_relaxed))
break;
if (atomic_compare_exchange_weak_explicit(&__maps.lock.word, &word, 0,
memory_order_release,
memory_order_relaxed))
}
if (atomic_compare_exchange_weak_explicit(
&__maps.lock, &word, 0, memory_order_release, memory_order_relaxed))
break;
}
}

View file

@ -3,29 +3,10 @@
#include "libc/intrin/atomic.h"
#include "libc/intrin/tree.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/tls2.internal.h"
COSMOPOLITAN_C_START_
/* size of dynamic memory that is used internally by your memory manager */
#define MAPS_SIZE 65536
/* when map->hand is MAPS_RESERVATION it means mmap() is transactionally
reserving address space it is in the process of requesting from win32 */
#define MAPS_RESERVATION -2
/* when map->hand is MAPS_SUBREGION it means that an allocation has been
broken into multiple fragments by mprotect(). the first fragment must
be set to MAPS_VIRTUAL or your CreateFileMapping() handle. your frags
must be perfectly contiguous in memory and should have the same flags */
#define MAPS_SUBREGION -3
/* indicates an allocation was created by VirtualAlloc() and so munmap()
must call VirtualFree() when destroying it. use it on the hand field. */
#define MAPS_VIRTUAL -4
/* if this is used on MAP_PRIVATE memory, then it's assumed to be memory
that win32 allocated, e.g. a CreateThread() stack. if this is used on
MAP_FILE memory, then it's assumed to be part of the executable image */
#define MAP_NOFORK 0x10000000
#define MAPS_RETRY ((void *)-1)
#define MAP_TREE_CONTAINER(e) TREE_CONTAINER(struct Map, tree, e)
@ -33,8 +14,8 @@ struct Map {
char *addr; /* granule aligned */
size_t size; /* must be nonzero */
int64_t off; /* ignore for anon */
int prot; /* memory protects */
int flags; /* memory map flag */
short prot; /* memory protects */
bool iscow; /* windows nt only */
bool readonlyfile; /* windows nt only */
unsigned visited; /* checks and fork */
@ -45,31 +26,15 @@ struct Map {
};
};
struct MapLock {
void *edges;
_Atomic(uint64_t) word;
};
struct MapSlab {
struct MapSlab *next;
struct Map maps[(MAPS_SIZE - sizeof(struct MapSlab *)) / sizeof(struct Map)];
};
struct Maps {
uint128_t rand;
struct Tree *maps;
struct MapLock lock;
_Atomic(uint64_t) lock;
_Atomic(uintptr_t) freed;
_Atomic(struct MapSlab *) slabs;
size_t count;
size_t pages;
char *pick;
struct Map stack;
struct Map guard;
#ifdef MODE_DBG
struct Map spool[1];
#else
struct Map spool[20];
#endif
};
struct AddrSize {
@ -79,18 +44,15 @@ struct AddrSize {
extern struct Maps __maps;
bool __maps_held(void);
void __maps_init(void);
void __maps_lock(void);
bool __maps_lock(void);
void __maps_check(void);
void __maps_unlock(void);
bool __maps_reentrant(void);
void *__maps_randaddr(void);
void __maps_add(struct Map *);
void __maps_free(struct Map *);
void __maps_insert(struct Map *);
int __maps_untrack(char *, size_t);
bool __maps_track(char *, size_t, int, int);
bool __maps_track(char *, size_t);
struct Map *__maps_alloc(void);
struct Map *__maps_floor(const char *);
void __maps_stack(char *, int, int, size_t, int, intptr_t);
@ -111,13 +73,6 @@ static inline struct Map *__maps_next(struct Map *map) {
return 0;
}
static inline struct Map *__maps_prev(struct Map *map) {
struct Tree *node;
if ((node = tree_prev(&map->tree)))
return MAP_TREE_CONTAINER(node);
return 0;
}
static inline struct Map *__maps_first(void) {
struct Tree *node;
if ((node = tree_first(__maps.maps)))
@ -125,16 +80,5 @@ static inline struct Map *__maps_first(void) {
return 0;
}
static inline struct Map *__maps_last(void) {
struct Tree *node;
if ((node = tree_last(__maps.maps)))
return MAP_TREE_CONTAINER(node);
return 0;
}
static inline bool __maps_isalloc(struct Map *map) {
return map->hand != MAPS_SUBREGION;
}
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_MAPS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@
#include "libc/intrin/describeflags.h"
#include "libc/intrin/directmap.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/tree.h"
@ -66,18 +67,17 @@ int __mprotect(char *addr, size_t size, int prot) {
// normalize size
size = (size + pagesz - 1) & -pagesz;
// test for signal handler reentry
if (__maps_reentrant())
return edeadlk();
// change mappings
int rc = 0;
bool found = false;
__maps_lock();
struct Map *map;
if (!(map = __maps_floor(addr)))
map = __maps_first();
for (; map && map->addr <= addr + size; map = __maps_next(map)) {
if (__maps_lock()) {
__maps_unlock();
return edeadlk();
}
struct Map *map, *floor;
StartOver:
floor = __maps_floor(addr);
for (map = floor; map && map->addr <= addr + size; map = __maps_next(map)) {
char *map_addr = map->addr;
size_t map_size = map->size;
char *beg = MAX(addr, map_addr);
@ -86,7 +86,7 @@ int __mprotect(char *addr, size_t size, int prot) {
continue;
found = true;
if (addr <= map_addr && addr + size >= map_addr + PGUP(map_size)) {
// change protection status of pages
// change protection of entire mapping
if (!__mprotect_chunk(map_addr, map_size, prot, map->iscow)) {
map->prot = prot;
} else {
@ -98,6 +98,8 @@ int __mprotect(char *addr, size_t size, int prot) {
size_t right = map_size - left;
struct Map *leftmap;
if ((leftmap = __maps_alloc())) {
if (leftmap == MAPS_RETRY)
goto StartOver;
if (!__mprotect_chunk(map_addr, left, prot, false)) {
leftmap->addr = map_addr;
leftmap->size = left;
@ -109,7 +111,7 @@ int __mprotect(char *addr, size_t size, int prot) {
leftmap->hand = map->hand;
map->addr += left;
map->size = right;
map->hand = MAPS_SUBREGION;
map->hand = -1;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left;
tree_insert(&__maps.maps, &leftmap->tree, __maps_compare);
@ -128,6 +130,8 @@ int __mprotect(char *addr, size_t size, int prot) {
size_t right = map_addr + map_size - addr;
struct Map *leftmap;
if ((leftmap = __maps_alloc())) {
if (leftmap == MAPS_RETRY)
goto StartOver;
if (!__mprotect_chunk(map_addr + left, right, prot, false)) {
leftmap->addr = map_addr;
leftmap->size = left;
@ -140,7 +144,7 @@ int __mprotect(char *addr, size_t size, int prot) {
map->addr += left;
map->size = right;
map->prot = prot;
map->hand = MAPS_SUBREGION;
map->hand = -1;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left;
tree_insert(&__maps.maps, &leftmap->tree, __maps_compare);
@ -160,8 +164,14 @@ int __mprotect(char *addr, size_t size, int prot) {
size_t right = map_size - middle - left;
struct Map *leftmap;
if ((leftmap = __maps_alloc())) {
if (leftmap == MAPS_RETRY)
goto StartOver;
struct Map *midlmap;
if ((midlmap = __maps_alloc())) {
if (midlmap == MAPS_RETRY) {
__maps_free(leftmap);
goto StartOver;
}
if (!__mprotect_chunk(map_addr + left, middle, prot, false)) {
leftmap->addr = map_addr;
leftmap->size = left;
@ -176,10 +186,10 @@ int __mprotect(char *addr, size_t size, int prot) {
midlmap->off = (map->flags & MAP_ANONYMOUS) ? 0 : map->off + left;
midlmap->prot = prot;
midlmap->flags = map->flags;
midlmap->hand = MAPS_SUBREGION;
midlmap->hand = -1;
map->addr += left + middle;
map->size = right;
map->hand = MAPS_SUBREGION;
map->hand = -1;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left + middle;
tree_insert(&__maps.maps, &leftmap->tree, __maps_compare);
@ -212,20 +222,11 @@ int __mprotect(char *addr, size_t size, int prot) {
/**
* Modifies restrictions on virtual memory address range.
*
* POSIX doesn't require mprotect() to be async signal safe. However you
* should be able to call this from a signal handler safely, if you know
* that your signal will never interrupt the cosmopolitan memory manager
* and the only way you can ensure that, is by blocking signals whenever
* you call mmap(), munmap(), mprotect(), etc.
*
* @param addr needs to be page size aligned
* @param size is rounded up to the page size
* @param prot can be PROT_NONE or a combination of PROT_READ,
* PROT_WRITE, and PROT_EXEC
* @param addr needs to be 4kb aligned
* @param prot can have PROT_{NONE,READ,WRITE,EXEC}
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `size` is zero
* @raise ENOMEM on tracking memory oom
* @raise EDEADLK if called from signal handler interrupting mmap()
* @see mmap()
*/
int mprotect(void *addr, size_t size, int prot) {
int rc;

View file

@ -19,34 +19,34 @@
#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/map.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
size = (size + __pagesize - 1) & -__pagesize;
if ((uintptr_t)addr & (__pagesize - 1))
int pagesz = __pagesize;
size = (size + pagesz - 1) & -pagesz;
if ((uintptr_t)addr & (pagesz - 1))
return einval();
if (__maps_reentrant())
return edeadlk();
int rc = 0;
__maps_lock();
struct Map *map;
if (!(map = __maps_floor(addr)))
map = __maps_first();
for (; map && map->addr <= addr + size; map = __maps_next(map)) {
if (map->flags & MAP_ANONYMOUS)
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
if (!FlushViewOfFile(beg, end - beg))
rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
if (__maps_lock()) {
rc = edeadlk();
} else {
struct Map *map, *floor;
floor = __maps_floor(addr);
for (map = floor; map && map->addr <= addr + size; map = __maps_next(map)) {
char *beg = MAX(addr, map->addr);
char *end = MIN(addr + size, map->addr + map->size);
if (beg < end)
if (!FlushViewOfFile(beg, end - beg))
rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
}
}
__maps_unlock();

View file

@ -38,7 +38,6 @@
* @param flags needs MS_ASYNC or MS_SYNC and can have MS_INVALIDATE
* @return 0 on success or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EDEADLK if called from signal handler interrupting mmap()
* @raise EINTR if we needed to block and a signal was delivered instead
* @raise EINVAL if `MS_SYNC` and `MS_ASYNC` were both specified
* @raise EINVAL if unknown `flags` were passed
@ -68,19 +67,23 @@ 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,6 +41,8 @@ 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

@ -0,0 +1,82 @@
/*-*- 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/calls/ucontext.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nt/struct/context.h"
#include "libc/str/str.h"
#ifdef __x86_64__
textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
if (!cr)
return;
ctx->uc_mcontext.eflags = cr->EFlags;
ctx->uc_mcontext.rax = cr->Rax;
ctx->uc_mcontext.rbx = cr->Rbx;
ctx->uc_mcontext.rcx = cr->Rcx;
ctx->uc_mcontext.rdx = cr->Rdx;
ctx->uc_mcontext.rdi = cr->Rdi;
ctx->uc_mcontext.rsi = cr->Rsi;
ctx->uc_mcontext.rbp = cr->Rbp;
ctx->uc_mcontext.rsp = cr->Rsp;
ctx->uc_mcontext.rip = cr->Rip;
ctx->uc_mcontext.r8 = cr->R8;
ctx->uc_mcontext.r9 = cr->R9;
ctx->uc_mcontext.r10 = cr->R10;
ctx->uc_mcontext.r11 = cr->R11;
ctx->uc_mcontext.r12 = cr->R12;
ctx->uc_mcontext.r13 = cr->R13;
ctx->uc_mcontext.r14 = cr->R14;
ctx->uc_mcontext.r15 = cr->R15;
ctx->uc_mcontext.cs = cr->SegCs;
ctx->uc_mcontext.gs = cr->SegGs;
ctx->uc_mcontext.fs = cr->SegFs;
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
__repmovsb(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
ctx->__fpustate.mxcsr = cr->MxCsr;
}
textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
if (!cr)
return;
cr->EFlags = ctx->uc_mcontext.eflags;
cr->Rax = ctx->uc_mcontext.rax;
cr->Rbx = ctx->uc_mcontext.rbx;
cr->Rcx = ctx->uc_mcontext.rcx;
cr->Rdx = ctx->uc_mcontext.rdx;
cr->Rdi = ctx->uc_mcontext.rdi;
cr->Rsi = ctx->uc_mcontext.rsi;
cr->Rbp = ctx->uc_mcontext.rbp;
cr->Rsp = ctx->uc_mcontext.rsp;
cr->Rip = ctx->uc_mcontext.rip;
cr->R8 = ctx->uc_mcontext.r8;
cr->R9 = ctx->uc_mcontext.r9;
cr->R10 = ctx->uc_mcontext.r10;
cr->R11 = ctx->uc_mcontext.r11;
cr->R12 = ctx->uc_mcontext.r12;
cr->R13 = ctx->uc_mcontext.r13;
cr->R14 = ctx->uc_mcontext.r14;
cr->R15 = ctx->uc_mcontext.r15;
cr->SegCs = ctx->uc_mcontext.cs;
cr->SegGs = ctx->uc_mcontext.gs;
cr->SegFs = ctx->uc_mcontext.fs;
cr->MxCsr = ctx->__fpustate.mxcsr;
__repmovsb(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate));
}
#endif /* __x86_64__ */

View file

@ -16,92 +16,39 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/bsr.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/macros.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
// this will usually return 12 since x86 pml4t uses a 47 bit address
// space in userspace, and decent arm machines uses a 48 bit address
// space. however it could go lower on embedded devices. it can also
// rise higher on expensive x86 machines with pml5t, if user uses it
static int get_address_digits(int pagesz) {
int max_bits = 0;
for (struct Tree *e = tree_first(__maps.maps); e; e = tree_next(e)) {
struct Map *map = MAP_TREE_CONTAINER(e);
char *end = map->addr + ((map->size + pagesz - 1) & -pagesz);
int bits = bsrll((uintptr_t)end) + 1;
if (bits > max_bits)
max_bits = bits;
}
return ((max_bits + 3) & -4) / 4;
}
/**
* Prints memory mappings known to cosmo.
* Prints memory mappings.
*/
void __print_maps(size_t limit) {
char mappingbuf[8], sb[16];
__maps_lock();
char sb[16];
char mappingbuf[8];
struct Map *last = 0;
int pagesz = __pagesize;
int gransz = __gransize;
int digs = get_address_digits(pagesz);
for (struct Tree *e = tree_first(__maps.maps); e; e = tree_next(e)) {
struct Map *map = MAP_TREE_CONTAINER(e);
// show gaps between maps
if (last) {
char *beg = last->addr + ((last->size + gransz - 1) & -gransz);
char *end = map->addr;
if (end > beg) {
size_t gap = end - beg;
sizefmt(sb, gap, 1024);
kprintf("%0*lx-%0*lx %sb\n", digs, beg, digs, end, sb);
}
}
last = map;
// show mapping
kprintf("%0*lx-%0*lx %!s", digs, map->addr, digs, map->addr + map->size,
kprintf("%012lx-%012lx %!s", map->addr, map->addr + map->size,
_DescribeMapping(mappingbuf, map->prot, map->flags));
sizefmt(sb, map->size, 1024);
kprintf(" %!sb", sb);
if (IsWindows()) {
switch (map->hand) {
case MAPS_RESERVATION:
kprintf(" reservation");
break;
case MAPS_SUBREGION:
break;
case MAPS_VIRTUAL:
kprintf(" virtual");
break;
default:
kprintf(" hand=%ld", map->hand);
break;
}
}
if (map->hand && map->hand != -1)
kprintf(" hand=%ld", map->hand);
if (map->iscow)
kprintf(" cow");
if (map->readonlyfile)
kprintf(" readonlyfile");
kprintf("\n");
// stay beneath our limit
if (!--limit)
break;
}
// print summary
kprintf("# %'zu bytes in %'zu mappings\n", __maps.pages * pagesz,
kprintf("# %'zu bytes in %'zu mappings\n", __maps.pages * __pagesize,
__maps.count);
__maps_unlock();
}

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