mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52f1db7220 | ||
|
|
c995838e5c | ||
|
|
539bddce8c | ||
|
|
002df0f16c | ||
|
|
be16bcdcd3 | ||
|
|
cb9a0466f1 | ||
|
|
543c93f623 | ||
|
|
3f0bcdc3ef | ||
|
|
0d7c265392 | ||
|
|
022536cab6 | ||
|
|
2278327eba | ||
|
|
37d40e087f | ||
|
|
179e048bba | ||
|
|
c2590cf7a0 | ||
|
|
89d1e5b8f2 | ||
|
|
5e60e5ad10 | ||
|
|
6b06a8176d | ||
|
|
14d036b68d | ||
|
|
fae0c0286f | ||
|
|
d6ff4c754e | ||
|
|
f44d88707e | ||
|
|
fc96af058b | ||
|
|
bd6069deb5 | ||
|
|
e9735a7738 | ||
|
|
0ea10c8631 | ||
|
|
e522aa3a07 | ||
|
|
d7b88734cd | ||
|
|
da8f5009fd | ||
|
|
ef9776755e | ||
|
|
da336b3ea8 | ||
|
|
69bee64a59 | ||
|
|
f7ff77d865 | ||
|
|
648bf6555c | ||
|
|
60cb435cb4 | ||
|
|
64c284003d | ||
|
|
3d2d04b25e | ||
|
|
5af19b7eed | ||
|
|
8111462789 | ||
|
|
f52f65b2e3 | ||
|
|
997ce29ddc | ||
|
|
d38700687a | ||
|
|
0f89140882 | ||
|
|
0cee831da3 | ||
|
|
b41f91c658 | ||
|
|
e7329b7cba | ||
|
|
c19ac8729d | ||
|
|
9d2f993364 | ||
|
|
31dab8a75d | ||
|
|
7a06760e6f | ||
|
|
9209ea63a7 | ||
|
|
84b9b8ed87 | ||
|
|
e557058ac8 | ||
|
|
467a332e38 | ||
|
|
7ae556463a | ||
|
|
c424352a0a | ||
|
|
d5910e2673 | ||
|
|
9b7c8db846 | ||
|
|
4a6fd3d910 |
No files matched your search
@@ -60,8 +60,8 @@
|
||||
# build/config.mk
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10 win10:31336
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
@@ -92,6 +92,7 @@ o/$(MODE): \
|
||||
.UNVEIL = \
|
||||
libc/integral \
|
||||
libc/disclaimer.inc \
|
||||
rwc:/dev/shm \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
/proc/stat \
|
||||
@@ -121,11 +122,13 @@ include third_party/compiler_rt/compiler_rt.mk # │
|
||||
include libc/str/str.mk # │
|
||||
include third_party/xed/xed.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include third_party/double-conversion/dc.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/vga/vga.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include third_party/nsync/nsync.mk # │
|
||||
@@ -149,7 +152,6 @@ include dsp/mpeg/mpeg.mk # │
|
||||
include dsp/dsp.mk # │
|
||||
include third_party/zlib/gz/gz.mk # │
|
||||
include third_party/musl/musl.mk # │
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/libc.mk #─┘
|
||||
include libc/sock/sock.mk #─┐
|
||||
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||
@@ -168,8 +170,9 @@ include test/tool/args/test.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
include net/finger/finger.mk
|
||||
include third_party/double-conversion/double-conversion.mk
|
||||
include third_party/double-conversion/test/test.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/tr/tr.mk
|
||||
include third_party/sed/sed.mk
|
||||
include third_party/awk/awk.mk
|
||||
include third_party/make/make.mk
|
||||
@@ -309,7 +312,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
THIRD_PARTY_NSYNC_MALLOC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
@@ -402,6 +405,15 @@ $(SRCS): \
|
||||
libc/integral/lp64arg.inc \
|
||||
libc/integral/lp64.inc
|
||||
|
||||
.PHONY: toolchain
|
||||
toolchain: o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/public/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a
|
||||
|
||||
# UNSPECIFIED PREREQUISITES TUTORIAL
|
||||
#
|
||||
# A build rule must exist for all files that make needs to consider in
|
||||
|
||||
@@ -23,8 +23,8 @@ If you're doing your development work on Linux or BSD then you need just
|
||||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.1.1.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.2.zip
|
||||
unzip cosmopolitan-amalgamation-2.2.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
||||
@@ -246,12 +246,16 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 | 2012 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
|
||||
for a community supported version of Cosmopolitan that works on Windows
|
||||
Vista and Windows 7.
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Funding for this project is crowdsourced using
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "ape/macros.internal.h"
|
||||
#include "ape/notice.inc"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
@@ -112,7 +113,15 @@ cstr: .endobj cstr,globl,hidden # ←for gdb readability
|
||||
//
|
||||
// @param dl is drive number
|
||||
// @noreturn
|
||||
ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
ape_mz:
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
#else
|
||||
// Avoid virus scanner reputation damage when targeting System Five.
|
||||
// WARNING: This prefix is experimental; it may be removed sometime.
|
||||
// TODO(jart): Find another prefix that will work with BIOS loading.
|
||||
.asciz "JTqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
#endif
|
||||
.short 0x1000 # MZ: lowers upper bound load / 16
|
||||
.short 0xf800 # MZ: roll greed on bss
|
||||
.short 0 # MZ: lower bound on stack segment
|
||||
@@ -874,7 +883,7 @@ ape_macho:
|
||||
.long (520f-510f)/4 # count
|
||||
510: .quad 0 # rax
|
||||
.quad IMAGE_BASE_VIRTUAL # rbx
|
||||
.quad XNU # rcx
|
||||
.quad _HOSTXNU # rcx
|
||||
.quad 0 # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
@@ -1285,8 +1294,8 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
jl 10f
|
||||
mov %edi,%eax
|
||||
cpuid
|
||||
mov $1<<29,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx
|
||||
mov $1<<29|1<<20,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx # & nx support
|
||||
cmp %edi,%edx
|
||||
jne 10f
|
||||
xor %ax,%ax
|
||||
@@ -1415,7 +1424,7 @@ pinit: push %ds
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||
mov $512,%cx # PD±2MB
|
||||
mov $PAGE_V+PAGE_RW,%eax
|
||||
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
|
||||
xor %di,%di
|
||||
0: stosl
|
||||
add $0x1000,%eax
|
||||
@@ -1438,7 +1447,7 @@ golong: cli
|
||||
mov %eax,%cr4
|
||||
movl $EFER,%ecx
|
||||
rdmsr
|
||||
or $EFER_LME|EFER_SCE,%eax
|
||||
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
|
||||
wrmsr
|
||||
lgdt REAL(_gdtrphy)
|
||||
mov %cr0,%eax
|
||||
@@ -1555,21 +1564,21 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||
#endif
|
||||
push $METAL # sets __hostos in crt.S
|
||||
push $_HOSTMETAL # sets __hostos in crt.S
|
||||
pop %rcx
|
||||
push $0
|
||||
pushq .Lenv0(%rip) # envp[0][0]
|
||||
mov %rsp,%rbp
|
||||
mov .Lenv0(%rip),%rax
|
||||
mov %rax,(%rbp) # envp[0][0]
|
||||
push $0 # argv[0][0]
|
||||
pushq .Largv0+8(%rip) # argv[0][8]
|
||||
pushq .Largv0(%rip) # argv[0][0]
|
||||
mov %rsp,%rax
|
||||
push $0 # auxv[1][1]
|
||||
push $0 # auxv[1][0]
|
||||
push %rbp # auxv[0][1]
|
||||
push %rax # auxv[0][1]
|
||||
push $31 # auxv[0][0] AT_EXECFN
|
||||
push $0 # envp[1]
|
||||
push $.Lenv0 # envp[0]
|
||||
push %rbp # envp[0]
|
||||
push $0 # argv[1]
|
||||
push %rbp # argv[0]
|
||||
push %rax # argv[0]
|
||||
push $1 # argc
|
||||
xor %ebp,%ebp
|
||||
xor %eax,%eax
|
||||
@@ -1585,6 +1594,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
|
||||
.rodata
|
||||
.Lenv0: .asciz "METAL=1"
|
||||
.Largv0:
|
||||
.asciz APE_COM_NAME
|
||||
.org .Largv0+16
|
||||
.previous
|
||||
|
||||
#endif /* SupportsMetal() */
|
||||
|
||||
+2
-4
@@ -565,12 +565,10 @@ SHSTUB2(ape_loader_dd_count,
|
||||
#if SupportsMetal()
|
||||
HIDDEN(v_ape_realsectors =
|
||||
MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 512)) / 512);
|
||||
ROUNDUP(RVA(_tdata_end), 512)) / 512);
|
||||
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||
HIDDEN(v_ape_highsectors =
|
||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||
PROVIDE_HIDDEN(_tss = 0);
|
||||
PROVIDE_HIDDEN(_tss_end = 0);
|
||||
(ROUNDUP(RVA(_tdata_end), 512) / 512) - v_ape_realsectors);
|
||||
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
@@ -133,6 +134,7 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $UID -eq 0 ]; then
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
@@ -97,6 +97,8 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-sysv:M::JTqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-sysv:M::JTqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
||||
@@ -11,6 +11,7 @@ fi
|
||||
echo "APE Uninstaller intends to run"
|
||||
echo
|
||||
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE'"
|
||||
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv'"
|
||||
echo " $SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
|
||||
echo
|
||||
echo "You may then use ape/apeinstall.sh to reinstall it"
|
||||
@@ -21,4 +22,7 @@ set -ex
|
||||
if [ -f /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE' || exit
|
||||
fi
|
||||
if [ -f /proc/sys/fs/binfmt_misc/APE-sysv ]; then
|
||||
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv' || exit
|
||||
fi
|
||||
$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit
|
||||
+2
-2
@@ -175,7 +175,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -221,7 +221,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -121,7 +121,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
@@ -182,6 +182,14 @@
|
||||
|
||||
// Task State Segment Descriptor Entries.
|
||||
.macro .tssdescstub name:req
|
||||
.ifndef \name
|
||||
.weak \name
|
||||
.set \name,0
|
||||
.endif
|
||||
.ifndef \name\()_end
|
||||
.weak \name\()_end
|
||||
.set \name\()_end,0
|
||||
.endif
|
||||
.stub \name\()_desc_ent0,quad
|
||||
.stub \name\()_desc_ent1,quad
|
||||
.endm
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern unsigned char _base[];
|
||||
extern unsigned char _ehead[];
|
||||
extern unsigned char _etext[];
|
||||
extern unsigned char _edata[];
|
||||
extern unsigned char _ezip[];
|
||||
extern unsigned char _end[];
|
||||
extern unsigned char _ereal[];
|
||||
extern unsigned char _tdata_start[];
|
||||
extern unsigned char _tdata_end[];
|
||||
extern unsigned char _tbss_start[];
|
||||
extern unsigned char _tbss_end[];
|
||||
extern unsigned char __privileged_start[];
|
||||
extern unsigned char __privileged_addr[];
|
||||
extern unsigned char __privileged_size[];
|
||||
extern unsigned char __privileged_end[];
|
||||
extern unsigned char __test_start[];
|
||||
extern unsigned char __ro[];
|
||||
extern unsigned char *__relo_start[];
|
||||
extern unsigned char *__relo_end[];
|
||||
extern uint8_t __zip_start[];
|
||||
extern uint8_t __zip_end[];
|
||||
extern uint8_t __data_start[];
|
||||
extern uint8_t __data_end[];
|
||||
extern uint8_t __bss_start[];
|
||||
extern uint8_t __bss_end[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */
|
||||
Binary file not shown.
Binary file not shown.
+27
-6
@@ -29,7 +29,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE),fastbuild)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
|
||||
CONFIG_OFLAGS += -g0
|
||||
CONFIG_LDFLAGS += -S
|
||||
TARGET_ARCH ?= -msse3
|
||||
@@ -125,6 +125,22 @@ TARGET_ARCH ?= -msse3
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
endif
|
||||
|
||||
# System Five Mode
|
||||
#
|
||||
# - `make MODE=sysv`
|
||||
# - Optimized
|
||||
# - Backtraces
|
||||
# - Debuggable
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - No Windows bloat!
|
||||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Tiny Mode
|
||||
#
|
||||
# - `make MODE=tiny`
|
||||
@@ -151,7 +167,8 @@ CONFIG_CCFLAGS += \
|
||||
-fschedule-insns2 \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
-foptimize-sibling-calls \
|
||||
-DDWARFLESS
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
@@ -181,7 +198,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=1
|
||||
-DSUPPORT_VECTOR=1 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -217,7 +235,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=113
|
||||
-DSUPPORT_VECTOR=113 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -252,7 +271,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=121
|
||||
-DSUPPORT_VECTOR=121 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_CCFLAGS += \
|
||||
@@ -287,7 +307,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=251
|
||||
-DSUPPORT_VECTOR=251 \
|
||||
-DDWARFLESS
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
@@ -59,9 +59,15 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
kprintf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
char *buffer;
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
buffer = malloc(13);
|
||||
|
||||
+7
-7
@@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
|
||||
volatile unsigned long x;
|
||||
struct timespec now, start, next, interval;
|
||||
printf("hammering the cpu...\n");
|
||||
next = start = _timespec_mono();
|
||||
interval = _timespec_frommillis(500);
|
||||
next = _timespec_add(next, interval);
|
||||
next = start = timespec_mono();
|
||||
interval = timespec_frommillis(500);
|
||||
next = timespec_add(next, interval);
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
x *= 7;
|
||||
if (!(i % 256)) {
|
||||
now = _timespec_mono();
|
||||
if (_timespec_gte(now, next)) {
|
||||
now = timespec_mono();
|
||||
if (timespec_cmp(now, next) >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
next = _timespec_add(next, interval);
|
||||
next = timespec_add(next, interval);
|
||||
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
|
||||
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000.,
|
||||
timespec_tonanos(timespec_sub(now, start)) / 1000000000.,
|
||||
(double)clock() / CLOCKS_PER_SEC);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void show(int clock) {
|
||||
}
|
||||
shown[n++] = clock;
|
||||
if (clock_getres(clock, &ts) != -1) {
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), timespec_tonanos(ts));
|
||||
} else {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
@@ -24,6 +25,12 @@
|
||||
*/
|
||||
|
||||
noubsan int main(int argc, char *argv[]) {
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
ShowCrashReports();
|
||||
return 1 / (x = 0);
|
||||
|
||||
+24
-1
@@ -49,12 +49,12 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
@@ -71,8 +71,10 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_AWK \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
@@ -83,7 +85,9 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_SED \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_TR \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
@@ -142,6 +146,25 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
# # force symtab.com to be a zip file, by pulling a zip asset into linkage
|
||||
# # we wouldn't need to do this if we depended on functions like localtime
|
||||
# o/$(MODE)/examples/symtab.com.dbg: \
|
||||
# $(EXAMPLES_DEPS) \
|
||||
# o/$(MODE)/examples/symtab.o \
|
||||
# o/$(MODE)/examples/symtab.c.zip.o \
|
||||
# o/$(MODE)/examples/examples.pkg \
|
||||
# $(EXAMPLES_BOOTLOADER)
|
||||
# @$(APELINK)
|
||||
|
||||
# modify .com so it can read the symbol table without needing the .com.dbg file
|
||||
o/$(MODE)/examples/symtab.com: \
|
||||
o/$(MODE)/examples/symtab.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
o/$(MODE)/tool/build/symtab.com
|
||||
@$(MAKE_OBJCOPY)
|
||||
@$(MAKE_SYMTAB_CREATE)
|
||||
@$(MAKE_SYMTAB_ZIP)
|
||||
|
||||
o/$(MODE)/examples/picol.o: private \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
+1
-8
@@ -9,19 +9,12 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
dontinline void dostuff(const char *s) {
|
||||
int i, us;
|
||||
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
us = rand() % 500000;
|
||||
usleep(us);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int main() {
|
||||
kprintf("%d\n", GetCpuCount());
|
||||
kprintf("%d\n", _getcpucount());
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
@@ -102,7 +103,7 @@ uint64_t rngset64(void) {
|
||||
static unsigned i;
|
||||
static uint64_t s;
|
||||
if (!i) {
|
||||
s = rand64();
|
||||
s = _rand64();
|
||||
i = (s + 1) & (511);
|
||||
}
|
||||
return MarsagliaXorshift64(&s);
|
||||
@@ -215,7 +216,7 @@ const struct Function {
|
||||
{"moby", moby}, //
|
||||
{"mt19937", _mt19937}, //
|
||||
{"python", pythonx2}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rand64", _rand64}, //
|
||||
{"rdrand", rdrand}, //
|
||||
{"rdrnd", rdrand}, //
|
||||
{"rdseed", rdseed}, //
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
@@ -137,7 +136,7 @@ void *Worker(void *id) {
|
||||
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
|
||||
errno = 0;
|
||||
|
||||
if (bind(server, &addr, sizeof(addr)) == -1) {
|
||||
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
kprintf("%s() failed %m\n", "socket");
|
||||
goto CloseWorker;
|
||||
}
|
||||
@@ -299,7 +298,7 @@ int main(int argc, char *argv[]) {
|
||||
PORT);
|
||||
}
|
||||
|
||||
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
|
||||
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
|
||||
if (!(1 <= threads && threads <= 100000)) {
|
||||
kprintf("error: invalid number of threads: %d\n", threads);
|
||||
exit(1);
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
#include "third_party/libcxx/vector"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("zipos");
|
||||
|
||||
#define USAGE \
|
||||
" [ROM] [FMV]\n\
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#if 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/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "net/http/ip.h"
|
||||
|
||||
/**
|
||||
* @fileoverview fast local network port scanner, e.g.
|
||||
*
|
||||
* make -j8 o//examples/portscan.com
|
||||
* o//examples/portscan.com 10.10.10.0/24 22
|
||||
*/
|
||||
|
||||
const char *FormatIp(char buf[16], uint32_t ip) {
|
||||
snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define FormatIp(x) FormatIp(alloca(16), x)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int port;
|
||||
struct Cidr in;
|
||||
uint32_t netmask;
|
||||
const char *status;
|
||||
struct timeval timeout;
|
||||
uint32_t network_address;
|
||||
uint32_t last_host_address;
|
||||
uint32_t first_host_address;
|
||||
|
||||
if (argc != 3) {
|
||||
PrintUsage:
|
||||
fprintf(stderr,
|
||||
"usage: %s IP/CIDR PORT\n"
|
||||
"example: %s 192.168.0.0/24 22\n",
|
||||
argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in = ParseCidr(argv[1], -1);
|
||||
if (in.addr == -1) {
|
||||
fprintf(stderr, "error: bad ip/cidr\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
port = atoi(argv[2]);
|
||||
if (!(1 <= port && port <= 65535)) {
|
||||
fprintf(stderr, "error: bad port\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr > 30) {
|
||||
fprintf(stderr, "error: maximum supported cidr is 30\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr < 22) {
|
||||
fprintf(stderr, "error: minimum cidr support right now is 22\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
netmask = -1u << (32 - in.cidr);
|
||||
network_address = in.addr & netmask;
|
||||
first_host_address = network_address + 1;
|
||||
last_host_address = (network_address | ~netmask) - 1;
|
||||
|
||||
assert(last_host_address > first_host_address);
|
||||
assert(last_host_address - first_host_address < 1024);
|
||||
|
||||
fprintf(stderr, "scanning %s through %s\n", FormatIp(first_host_address),
|
||||
FormatIp(last_host_address));
|
||||
|
||||
timeout = timeval_frommillis(100);
|
||||
for (int64_t ip = first_host_address; ip <= last_host_address; ++ip) {
|
||||
if (!fork()) {
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
setsockopt(3, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
if (!connect(3,
|
||||
(struct sockaddr *)&(struct sockaddr_in){
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(ip),
|
||||
.sin_port = htons(port),
|
||||
},
|
||||
sizeof(struct sockaddr_in))) {
|
||||
status = "open";
|
||||
} else if (errno == ECONNREFUSED) {
|
||||
status = "closed";
|
||||
} else if (errno != EINPROGRESS) {
|
||||
status = _strerrno(errno);
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
if (status) {
|
||||
printf("%-15s %s\n", FormatIp(ip), status);
|
||||
}
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (wait(0) == -1 && errno == ECHILD) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#if 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/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("reboot your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_AUTOBOOT)) {
|
||||
printf("system is rebooting...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#if 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/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("shutdown your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_POWER_OFF)) {
|
||||
printf("system is shutting down...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#if 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/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
/**
|
||||
* @fileoverview example of how to embed symbol table in .com file
|
||||
*
|
||||
* # build our binary
|
||||
* make -j16 o//examples/symtab.com
|
||||
*
|
||||
* # move binary somewhere else
|
||||
* # so it can't find the .com.dbg binary
|
||||
* cp o//examples/symtab.com /tmp
|
||||
*
|
||||
* # run program
|
||||
* # notice that it has a symbolic backtrace
|
||||
* /tmp/symtab.com
|
||||
*
|
||||
* @see examples/examples.mk
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// this links all the debugging and zip functionality
|
||||
ShowCrashReports();
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
return 1 / (x = 0);
|
||||
}
|
||||
+13
-6
@@ -7,13 +7,20 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Command Interpreter Demo
|
||||
* Yes this works on Windows.
|
||||
*/
|
||||
|
||||
STATIC_YOINK("_tr");
|
||||
STATIC_YOINK("_sed");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (IsWindows()) {
|
||||
system("notepad");
|
||||
} else {
|
||||
system("ls | tr a-z A-Z");
|
||||
}
|
||||
system("x=world\n"
|
||||
"echo hello $x |\n"
|
||||
" tr a-z A-Z |\n"
|
||||
" sed 's/\\(.\\)/\\1 /g'");
|
||||
}
|
||||
+436
-357
File diff suppressed because it is too large.
Load diff
+148
@@ -0,0 +1,148 @@
|
||||
#if 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/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/passwd.h"
|
||||
|
||||
/**
|
||||
* @fileoverview program for broadcasting message to all terminals, e.g.
|
||||
*
|
||||
* o//examples/wall.com hello friends
|
||||
*
|
||||
* Will place some bold text into the top left corners of all terminals:
|
||||
*
|
||||
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
|
||||
* hello friends
|
||||
*
|
||||
* It's useful for having one terminal tab notify your other ones when
|
||||
* something like a long running job completes. In the old days back
|
||||
* when unix systems had multiple users, the wall command provided the
|
||||
* ultimate lulz especially if it's a setuid binary with root privs.
|
||||
*/
|
||||
|
||||
#define GETOPTS "v"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
|
||||
-v increase verbosity\n\
|
||||
Examples:\n\
|
||||
wall.com 'hello my friends'\n\
|
||||
echo hello my friends | wall.com\n\
|
||||
"
|
||||
|
||||
int g_verbose;
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_verbose++;
|
||||
break;
|
||||
case '?':
|
||||
write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GetHost(void) {
|
||||
static char host[254];
|
||||
if (gethostname(host, sizeof(host))) {
|
||||
strcpy(host, "localhost");
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
char *GetTime(void) {
|
||||
int64_t t;
|
||||
struct tm tm;
|
||||
struct timespec ts;
|
||||
clock_gettime(0, &ts);
|
||||
localtime_r(&ts.tv_sec, &tm);
|
||||
return _chomp(asctime(&tm));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
|
||||
// create broadcast banner
|
||||
// we use \e[1m so the text is strong & visually distinct
|
||||
// we use \e[K so it doesn't get lost in a forest of text
|
||||
// we map \n → \r\n because teletype might be in raw mode
|
||||
char *msg = 0;
|
||||
const char *s;
|
||||
appends(&msg, "\e7"); // save cursor position
|
||||
appends(&msg, "\e[H"); // goto top left corne
|
||||
appends(&msg, "\e[K"); // clear line forward
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
// append broadcast message
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
} else {
|
||||
appendw(&msg, *s & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise use stdin as message
|
||||
ssize_t i, rc;
|
||||
char buf[512];
|
||||
while ((rc = read(0, buf, sizeof(buf))) > 0) {
|
||||
for (i = 0; i < rc; ++i) {
|
||||
if (buf[i] == '\n') {
|
||||
appends(&msg, "\r\n\e[K"); // clear line forward
|
||||
} else {
|
||||
appendw(&msg, buf[i] & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
|
||||
|
||||
// try to send message to all pseudoteletypewriters
|
||||
for (int i = 0;; ++i) {
|
||||
int fd;
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) break;
|
||||
if (g_verbose) perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+50
-9
@@ -16,19 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#define _unassert(x) \
|
||||
do { \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if !defined(TINY) && !defined(MODE_DBG)
|
||||
/**
|
||||
* Specifies expression can't possibly be false.
|
||||
*
|
||||
* This macro uses the `notpossible` keyword and is intended for things
|
||||
* like systems integration, where we know for a fact that something is
|
||||
* never going to happen, but there's no proof. So we don't want to add
|
||||
* extra bloat for filenames and line numbers, since `ShowCrashReports`
|
||||
* can print a backtrace if we just embed the UD2 instruction to crash.
|
||||
* That's useful for systems code, for the following reason. Invariants
|
||||
* make sense with _unassert() since they usually get placed at the top
|
||||
* of functions. But if you used _unassert() to test a system call does
|
||||
* not fail, then check happens at the end of your function usually and
|
||||
* is therefore likely to result in a failure condition where execution
|
||||
* falls through into a different function, which is shocking to debug.
|
||||
*
|
||||
* In `MODE=tiny` these assertions are redefined as undefined behavior.
|
||||
*/
|
||||
#define _npassert(x) \
|
||||
do { \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
notpossible; \
|
||||
} \
|
||||
} while (0)
|
||||
(void)0; \
|
||||
})
|
||||
#else
|
||||
#define _npassert(x) _unassert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
/**
|
||||
* Specifies expression being false is undefined behavior.
|
||||
*
|
||||
* This is a good way to tell the compiler about your invariants, which
|
||||
* leads to smaller faster programs. The expression is never removed by
|
||||
* the preprocessor so it's recommended that it be free of side-effects
|
||||
* if you intend for it to be removed. At the same time, this guarantee
|
||||
* makes this assertion useful for things like system calls, since they
|
||||
* won't be removed by `NDEBUG` mode.
|
||||
*
|
||||
* If this assertion fails, the worst possible things can happen unless
|
||||
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
|
||||
* that's capable of debugging this macro.
|
||||
*/
|
||||
#define _unassert(x) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,5 +16,6 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
||||
int __vforked;
|
||||
struct Signals __sig;
|
||||
@@ -16,26 +16,23 @@
|
||||
│ 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/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||
* @threadsafe
|
||||
*/
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
@@ -61,6 +58,18 @@ static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
static inline textwindows int __sig_is_masked(int sig) {
|
||||
if (__tls_enabled) {
|
||||
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
|
||||
} else {
|
||||
return __sig.sigmask & (1ull << (sig - 1));
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int __sig_is_applicable(struct Signal *s) {
|
||||
return s->tid <= 0 || s->tid == gettid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
@@ -70,7 +79,7 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (__sig_is_applicable(res) && !__sig_is_masked(res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
@@ -78,8 +87,6 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%G is masked", res->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
@@ -101,7 +108,6 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
STRACE("delivering %G", sig);
|
||||
|
||||
// enter the signal
|
||||
__sig_lock();
|
||||
rva = __sighandrvas[sig];
|
||||
flags = __sighandflags[sig];
|
||||
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
|
||||
@@ -112,12 +118,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// signal handler. in that case you must use SA_NODEFER.
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
__sig_unlock();
|
||||
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
__repstosb(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
@@ -134,7 +139,9 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// since sigaction() is @asyncsignalsafe we only restore it if the
|
||||
// user didn't change it during the signal handler. we also don't
|
||||
// need to do anything if this was a oneshot signal or nodefer.
|
||||
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
|
||||
__sighandrvas[sig] = rva;
|
||||
}
|
||||
}
|
||||
|
||||
if (!restartable) {
|
||||
@@ -150,7 +157,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
static textwindows bool __sig_is_fatal(int sig) {
|
||||
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -168,7 +175,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
if (__sig_is_fatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
_Exitr(128 + sig);
|
||||
}
|
||||
@@ -194,20 +201,18 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
__sig_lock();
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
__sig_unlock();
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
// TODO(jart): ucontext_t support
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
} else {
|
||||
STRACE("%G is masked", sig);
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
return __sig_add(gettid(), sig, si_code);
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,18 +221,19 @@ textwindows int __sig_raise(int sig, int si_code) {
|
||||
* @return 0 on success, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
textwindows int __sig_add(int tid, int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
__sig_lock();
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
|
||||
STRACE("ignoring %G", sig);
|
||||
rc = 0;
|
||||
} else {
|
||||
STRACE("enqueuing %G", sig);
|
||||
__sig_lock();
|
||||
++__sig_count;
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->tid = tid;
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
@@ -236,8 +242,8 @@ textwindows int __sig_add(int sig, int si_code) {
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
__sig_unlock();
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
@@ -276,7 +282,7 @@ textwindows bool __sig_check(bool restartable) {
|
||||
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
struct Signal *cur, *prev, *next;
|
||||
if (rva != (unsigned)(intptr_t)SIG_IGN &&
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
|
||||
return;
|
||||
}
|
||||
if (__sig.queue) {
|
||||
@@ -298,25 +304,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *cur;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (cur = __sig.queue; cur; cur = cur->next) {
|
||||
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
|
||||
} else {
|
||||
STRACE("%G is ignored", cur->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
@@ -16,50 +16,45 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||
* @threadsafe
|
||||
*/
|
||||
#define GetSigBit(x) (1ull << (((x)-1) & 63))
|
||||
|
||||
struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||
int i;
|
||||
uint64_t a, b;
|
||||
uint64_t x, y, *mask;
|
||||
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
|
||||
__sig_lock();
|
||||
if (__tls_enabled) {
|
||||
mask = &__get_tls()->tib_sigmask;
|
||||
} else {
|
||||
mask = &__sig.sigmask;
|
||||
}
|
||||
if (old) {
|
||||
*old = __sig.mask;
|
||||
old->__bits[0] = *mask;
|
||||
old->__bits[1] = 0;
|
||||
}
|
||||
if (neu) {
|
||||
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
|
||||
if (how == SIG_BLOCK) {
|
||||
__sig.mask.__bits[i] |= neu->__bits[i];
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
__sig.mask.__bits[i] &= ~neu->__bits[i];
|
||||
} else {
|
||||
__sig.mask.__bits[i] = neu->__bits[i];
|
||||
}
|
||||
x = *mask;
|
||||
y = neu->__bits[0];
|
||||
if (how == SIG_BLOCK) {
|
||||
x |= y;
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
x &= ~y;
|
||||
} else {
|
||||
x = y;
|
||||
}
|
||||
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
|
||||
x &= ~(0
|
||||
#define M(x) | GetSigBit(x)
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
);
|
||||
*mask = x;
|
||||
}
|
||||
__sig_unlock();
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
#undef GetSigBit
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *s;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (s = __sig.queue; s; s = s->next) {
|
||||
if (__sig_is_applicable(s) &&
|
||||
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
sigaddset(pending, s->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -32,12 +32,10 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
unsigned alarm(unsigned seconds) {
|
||||
int rc;
|
||||
struct itimerval it;
|
||||
bzero(&it, sizeof(it));
|
||||
it.it_value.tv_sec = seconds;
|
||||
rc = setitimer(ITIMER_REAL, &it, &it);
|
||||
assert(rc != -1);
|
||||
_npassert(!setitimer(ITIMER_REAL, &it, &it));
|
||||
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#include "libc/thread/thread.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_CANCELLATIONS \
|
||||
do { \
|
||||
int _CancelState; \
|
||||
_CancelState = _pthread_block_cancellations()
|
||||
|
||||
#define ALLOW_CANCELLATIONS \
|
||||
_pthread_allow_cancellations(_CancelState); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int _pthread_block_cancellations(void);
|
||||
void _pthread_allow_cancellations(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_SIGNALS \
|
||||
do { \
|
||||
sigset_t _SigMask; \
|
||||
_SigMask = _sigblockall()
|
||||
|
||||
#define ALLOW_SIGNALS \
|
||||
_sigsetmask(_SigMask); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_ */
|
||||
+52
-51
@@ -65,13 +65,13 @@ char *ttyname(int);
|
||||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chmod(const char *, unsigned);
|
||||
int chown(const char *, unsigned, unsigned);
|
||||
int chroot(const char *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int creat(const char *, unsigned);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
int dup3(int, int, int);
|
||||
@@ -84,25 +84,22 @@ int execv(const char *, char *const[]);
|
||||
int execve(const char *, char *const[], char *const[]);
|
||||
int execvp(const char *, char *const[]);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int faccessat(int, const char *, int, uint32_t);
|
||||
int faccessat(int, const char *, int, int);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, uint32_t) dontthrow;
|
||||
int fchmodat(int, const char *, uint32_t, int);
|
||||
int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
int fchmod(int, unsigned) dontthrow;
|
||||
int fchmodat(int, const char *, unsigned, int);
|
||||
int fchown(int, unsigned, unsigned);
|
||||
int fchownat(int, const char *, unsigned, unsigned, int);
|
||||
int fcntl(int, int, ...);
|
||||
int fdatasync(int);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
int getdomainname(char *, size_t);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
int getgroups(int size, uint32_t list[]);
|
||||
int getgroups(int, unsigned[]);
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int) libcesque;
|
||||
@@ -110,35 +107,29 @@ int getpgrp(void) nosideeffect;
|
||||
int getpid(void) nosideeffect libcesque;
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
uint32_t getuid(void) libcesque;
|
||||
int sys_iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int lchmod(const char *, uint32_t);
|
||||
int lchown(const char *, uint32_t, uint32_t);
|
||||
int lchmod(const char *, unsigned);
|
||||
int lchown(const char *, unsigned, unsigned);
|
||||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int mincore(void *, size_t, unsigned char *);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
int mkfifo(const char *, uint32_t);
|
||||
int mkfifoat(int, const char *, uint32_t);
|
||||
int mknod(const char *, uint32_t, uint64_t);
|
||||
int mknodat(int, const char *, int32_t, uint64_t);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int mkdir(const char *, unsigned);
|
||||
int mkdirat(int, const char *, unsigned);
|
||||
int mkfifo(const char *, unsigned);
|
||||
int mkfifoat(int, const char *, unsigned);
|
||||
int mknod(const char *, unsigned, uint64_t);
|
||||
int mknodat(int, const char *, int, uint64_t);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
@@ -148,7 +139,7 @@ int pipe(int[hasatleast 2]);
|
||||
int pipe2(int[hasatleast 2], int);
|
||||
int pivot_root(const char *, const char *);
|
||||
int pledge(const char *, const char *);
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_fadvise(int, int64_t, int64_t, int);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
int prctl(int, ...);
|
||||
int raise(int);
|
||||
@@ -160,36 +151,42 @@ int renameat2(long, const char *, long, const char *, int);
|
||||
int rmdir(const char *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int setegid(uint32_t);
|
||||
int seteuid(uint32_t);
|
||||
int setfsgid(int);
|
||||
int setfsuid(int);
|
||||
int setgid(int);
|
||||
int setgroups(size_t size, const uint32_t list[]);
|
||||
int setegid(unsigned);
|
||||
int seteuid(unsigned);
|
||||
int setfsgid(unsigned);
|
||||
int setfsuid(unsigned);
|
||||
int setgid(unsigned);
|
||||
int setgroups(size_t, const unsigned[]);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
int setregid(uint32_t, uint32_t);
|
||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||
int setreuid(uint32_t, uint32_t);
|
||||
int setregid(unsigned, unsigned);
|
||||
int setresgid(unsigned, unsigned, unsigned);
|
||||
int setresuid(unsigned, unsigned, unsigned);
|
||||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(int);
|
||||
int setuid(unsigned);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sys_iopl(int);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int tcgetpgrp(int);
|
||||
int tcsetpgrp(int, int);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int touch(const char *, unsigned);
|
||||
int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int umask(int);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
int unlinkat(int, const char *, int);
|
||||
@@ -198,21 +195,25 @@ int usleep(unsigned);
|
||||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
int32_t tcgetpgrp(int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, unsigned);
|
||||
ssize_t lseek(int, int64_t, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
ssize_t pwrite(int, const void *, size_t, int64_t);
|
||||
ssize_t read(int, void *, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t readlink(const char *, char *, size_t);
|
||||
ssize_t readlinkat(int, const char *, char *, size_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
unsigned getegid(void) nosideeffect;
|
||||
unsigned geteuid(void) nosideeffect;
|
||||
unsigned getgid(void) nosideeffect;
|
||||
unsigned getuid(void) libcesque;
|
||||
unsigned umask(unsigned);
|
||||
void sync(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
+16
-6
@@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
|
||||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
# we can't use asan because:
|
||||
# siginfo_t memory is owned by kernels
|
||||
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we can't use asan because:
|
||||
# ucontext_t memory is owned by xnu kernel
|
||||
o/$(MODE)/libc/calls/sigenter-xnu.o: private \
|
||||
@@ -172,12 +179,15 @@ o//libc/calls/statfs2cosmo.o: private \
|
||||
# we always want -O2 because:
|
||||
# division is expensive if not optimized
|
||||
o/$(MODE)/libc/calls/clock.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/_timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/_timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
||||
o/$(MODE)/libc/calls/timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommicros.o \
|
||||
o/$(MODE)/libc/calls/timeval_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommicros.o: private \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
|
||||
@@ -18,7 +18,24 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns input baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns output baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
@@ -26,3 +43,46 @@ uint32_t cfgetospeed(const struct termios *t) {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetispeed(struct termios *t, unsigned speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ospeed = speed;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
int chdir(const char *path) {
|
||||
int rc;
|
||||
GetProgramExecutableName(); // XXX: ugly workaround
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_chdir(path);
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@
|
||||
*/
|
||||
int chroot(const char *path) {
|
||||
int rc;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
rc = sys_chroot(path);
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ int64_t clock(void) {
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
|
||||
errno = e;
|
||||
if (getrusage(RUSAGE_SELF, &ru) != -1) {
|
||||
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
ts = timeval_totimespec(timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct {
|
||||
pthread_once_t once;
|
||||
@@ -30,7 +30,7 @@ static struct {
|
||||
} g_mono;
|
||||
|
||||
static void sys_clock_gettime_mono_init(void) {
|
||||
g_mono.base_wall = _timespec_real();
|
||||
g_mono.base_wall = timespec_real();
|
||||
g_mono.base_tick = rdtsc();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
||||
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
nanos = cycles / 3;
|
||||
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos));
|
||||
*time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
||||
@@ -84,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
|
||||
rc = __clock_gettime(clock, ts);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||
DescribeTimespec(rc, ts), rc);
|
||||
}
|
||||
|
||||
@@ -33,24 +33,24 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
||||
abs = *req;
|
||||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
abs = _timespec_add(now, *req);
|
||||
abs = timespec_add(now, *req);
|
||||
for (;;) {
|
||||
sys_clock_gettime_nt(clock, &now);
|
||||
if (_timespec_gte(now, abs)) return 0;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
if (rem) *rem = _timespec_sub(abs, now);
|
||||
return eintr();
|
||||
if (rem) *rem = timespec_sub(abs, now);
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ int sys_clock_nanosleep_openbsd(int clock, int flags,
|
||||
res = sys_nanosleep(req, rem);
|
||||
} else {
|
||||
sys_clock_gettime(clock, &now);
|
||||
if (_timespec_gt(*req, now)) {
|
||||
rel = _timespec_sub(*req, now);
|
||||
if (timespec_cmp(*req, now) > 0) {
|
||||
rel = timespec_sub(*req, now);
|
||||
res = sys_nanosleep(&rel, 0);
|
||||
} else {
|
||||
res = 0;
|
||||
|
||||
@@ -31,10 +31,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
||||
struct timeval now, abs, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = _timespec_totimeval(*req);
|
||||
abs = timespec_totimeval(*req);
|
||||
sys_gettimeofday_xnu(&now, 0, 0);
|
||||
if (_timeval_gt(abs, now)) {
|
||||
rel = _timeval_sub(abs, now);
|
||||
if (timeval_cmp(abs, now) > 0) {
|
||||
rel = timeval_sub(abs, now);
|
||||
res = sys_select(0, 0, 0, 0, &rel);
|
||||
} else {
|
||||
res = 0;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
@@ -55,8 +56,8 @@
|
||||
*
|
||||
* struct timespec rel, now, abs;
|
||||
* clock_gettime(CLOCK_REALTIME, &now);
|
||||
* rel = _timespec_frommillis(100);
|
||||
* abs = _timespec_add(now, rel);
|
||||
* rel = timespec_frommillis(100);
|
||||
* abs = timespec_add(now, rel);
|
||||
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
|
||||
*
|
||||
* will accurately spin on `EINTR` errors. That way you're not impeding
|
||||
@@ -74,18 +75,21 @@
|
||||
* if flags is `TIMER_ABSTIME` then `rem` is ignored
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINTR when a signal got delivered while we were waiting
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise ENOTSUP if `clock` is known but we can't use it here
|
||||
* @raise EFAULT if `req` or null or bad memory was passed
|
||||
* @raise EINVAL if `clock` is unknown to current platform
|
||||
* @raise EINVAL if `flags` has an unrecognized value
|
||||
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
|
||||
* @raise EFAULT if bad memory was passed
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @returnserrno
|
||||
* @norestart
|
||||
*/
|
||||
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int rc, e = errno;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
||||
(rem && !__asan_is_valid_timespec(rem))))) {
|
||||
@@ -112,8 +116,10 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
errno = e;
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
||||
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
|
||||
|
||||
@@ -18,15 +18,22 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd) {
|
||||
void sys_fcntl_nt_lock_cleanup(int) hidden;
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd, int fildes) {
|
||||
int e;
|
||||
bool ok = true;
|
||||
|
||||
if (_weaken(sys_fcntl_nt_lock_cleanup)) {
|
||||
_weaken(sys_fcntl_nt_lock_cleanup)(fildes);
|
||||
}
|
||||
|
||||
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
|
||||
+2
-2
@@ -16,10 +16,10 @@
|
||||
│ 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/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -81,7 +81,7 @@ int close(int fd) {
|
||||
} else if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdProcess)) { //
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
rc = sys_close_nt(g_fds.p + fd, fd);
|
||||
} else {
|
||||
rc = eio();
|
||||
}
|
||||
|
||||
+16
-16
@@ -27,35 +27,35 @@
|
||||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* if (closefrom(3))
|
||||
* for (int i = 3; i < 256; ++i)
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EBADF if `first` is negative
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @raise EBADF if `first` is negative
|
||||
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
|
||||
* @raise EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @raise EINVAL if flags are bad or first is greater than last
|
||||
* @raise EMFILE if a weird race condition happens on Linux
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR possibly on OpenBSD
|
||||
* @raise ENOMEM on Linux maybe
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (IsNetbsd() || IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (first < 0) {
|
||||
if (first < 0) {
|
||||
// consistent with openbsd
|
||||
// freebsd allows this but it's dangerous
|
||||
// necessary on linux due to type signature
|
||||
rc = ebadf();
|
||||
} else if (IsFreebsd() || IsOpenbsd()) {
|
||||
rc = sys_closefrom(first);
|
||||
} else if (IsLinux()) {
|
||||
rc = sys_close_range(first, 0xffffffffu, 0);
|
||||
} else if (IsNetbsd()) {
|
||||
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
|
||||
} else {
|
||||
rc = sys_closefrom(first);
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
@@ -39,6 +41,7 @@ static bool HasCopyFileRange(void) {
|
||||
bool ok;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
BLOCK_CANCELLATIONS;
|
||||
if (IsLinux()) {
|
||||
// We modernize our detection by a few years for simplicity.
|
||||
// This system call is chosen since it's listed by pledge().
|
||||
@@ -49,6 +52,7 @@ static bool HasCopyFileRange(void) {
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
errno = e;
|
||||
return ok;
|
||||
}
|
||||
@@ -81,6 +85,7 @@ static void copy_file_range_init(void) {
|
||||
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
|
||||
* @raise EPERM if `fdout` refers to an immutable file on Linux
|
||||
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINVAL if ranges overlap or `flags` is non-zero
|
||||
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
|
||||
* @raise EFAULT if one of the pointers memory is bad
|
||||
@@ -93,12 +98,15 @@ static void copy_file_range_init(void) {
|
||||
* @raise EIO if a low-level i/o error happens
|
||||
* @see sendfile() for seekable → socket
|
||||
* @see splice() for fd ↔ pipe
|
||||
* @cancellationpoint
|
||||
*/
|
||||
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
int64_t *opt_in_out_outoffset, size_t uptobytes,
|
||||
uint32_t flags) {
|
||||
ssize_t rc;
|
||||
pthread_once(&g_copy_file_range.once, copy_file_range_init);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!g_copy_file_range.ok) {
|
||||
rc = enosys();
|
||||
} else if (IsAsan() && ((opt_in_out_inoffset &&
|
||||
@@ -112,6 +120,8 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
|
||||
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
|
||||
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#ifdef MODE_DBG
|
||||
|
||||
int begin_cancellation_point(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_INCANCEL;
|
||||
pt->flags |= PT_INCANCEL;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void end_cancellation_point(int state) {
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
pt->flags &= ~PT_INCANCEL;
|
||||
pt->flags |= state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void report_cancellation_point(void) {
|
||||
BLOCK_CANCELLATIONS;
|
||||
_bt("error: need BEGIN/END_CANCELLATION_POINT\n");
|
||||
ALLOW_CANCELLATIONS;
|
||||
}
|
||||
|
||||
#endif /* MODE_DBG */
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int begin_cancellation_point(void);
|
||||
void end_cancellation_point(int);
|
||||
|
||||
#ifndef MODE_DBG
|
||||
#define BEGIN_CANCELLATION_POINT (void)0
|
||||
#define END_CANCELLATION_POINT (void)0
|
||||
#else
|
||||
#define BEGIN_CANCELLATION_POINT \
|
||||
do { \
|
||||
int _Cp; \
|
||||
_Cp = begin_cancellation_point()
|
||||
#define END_CANCELLATION_POINT \
|
||||
end_cancellation_point(_Cp); \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_ */
|
||||
@@ -31,6 +31,7 @@
|
||||
* @param mode is octal bits, e.g. 0644 usually
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
||||
+14
-25
@@ -31,13 +31,11 @@
|
||||
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
int64_t rc, proc, handle;
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= -1);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
__fds_lock();
|
||||
|
||||
if (oldfd >= g_fds.n ||
|
||||
if (!__isfdopen(oldfd) || newfd < -1 ||
|
||||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||
__fds_unlock();
|
||||
@@ -45,27 +43,18 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
|
||||
// allocate a new file descriptor
|
||||
for (;;) {
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
__fds_unlock();
|
||||
close(newfd);
|
||||
__fds_lock();
|
||||
}
|
||||
if (!g_fds.p[newfd].kind) {
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
break;
|
||||
}
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
sys_close_nt(g_fds.p + newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +75,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd_unlocked(newfd);
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||
startinfo.hStdError = __getfdhandleactual(2);
|
||||
|
||||
// spawn the process
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
|
||||
if (rc == -1) {
|
||||
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
|
||||
__imp_ExitProcess(6543);
|
||||
|
||||
+37
-24
@@ -16,6 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -39,12 +41,17 @@ static bool IsApeBinary(const char *path) {
|
||||
int fd;
|
||||
char buf[8];
|
||||
bool res = false;
|
||||
// TODO(jart): Should we block signals too?
|
||||
BLOCK_CANCELLATIONS;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
|
||||
if (sys_read(fd, buf, 8) == 8 && //
|
||||
(READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='"))) {
|
||||
res = true;
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -61,35 +68,41 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
|
||||
}
|
||||
|
||||
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int e;
|
||||
size_t i;
|
||||
int e, rc;
|
||||
char *buf;
|
||||
char **shargs;
|
||||
const char *ape;
|
||||
e = errno;
|
||||
__sys_execve(prog, argv, envp);
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
if (errno == ENOEXEC) {
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
return enoexec();
|
||||
rc = -1;
|
||||
}
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
return rc;
|
||||
}
|
||||
+6
-18
@@ -23,6 +23,7 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
@@ -53,26 +54,13 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int rc;
|
||||
size_t i;
|
||||
if (!prog || !argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid(prog, 1) || !__asan_is_valid_strlist(argv) ||
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
(IsAsan() && (!__asan_is_valid_str(prog) || //
|
||||
!__asan_is_valid_strlist(argv) || //
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "execve(%#s, {", prog);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
int execvpe(const char *prog, char *const argv[], char *const *envp) {
|
||||
char *exe;
|
||||
char pathbuf[PATH_MAX];
|
||||
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
|
||||
if (IsAsan() && !__asan_is_valid_str(prog)) return efault();
|
||||
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1;
|
||||
return execve(exe, argv, envp);
|
||||
}
|
||||
@@ -48,10 +48,10 @@
|
||||
* @note on Linux `flags` is only supported on Linux 5.8+
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int amode, uint32_t flags) {
|
||||
int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
int e, rc;
|
||||
struct ZiposUri zipname;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
*/
|
||||
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
|
||||
int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
|
||||
+223
-47
@@ -16,6 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
@@ -24,65 +25,131 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
bool __force_sqlite_to_work_until_we_can_fix_it;
|
||||
struct FileLock {
|
||||
struct FileLock *next;
|
||||
int64_t off;
|
||||
int64_t len;
|
||||
int fd;
|
||||
bool exc;
|
||||
};
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
struct FileLocks {
|
||||
pthread_mutex_t mu;
|
||||
struct FileLock *list;
|
||||
struct FileLock *free;
|
||||
};
|
||||
|
||||
static struct FileLocks g_locks;
|
||||
|
||||
static textwindows struct FileLock *NewFileLock(void) {
|
||||
struct FileLock *fl;
|
||||
if (g_locks.free) {
|
||||
fl = g_locks.free;
|
||||
g_locks.free = fl->next;
|
||||
} else {
|
||||
fl = kmalloc(sizeof(*fl));
|
||||
}
|
||||
bzero(fl, sizeof(*fl));
|
||||
fl->next = g_locks.list;
|
||||
g_locks.list = fl;
|
||||
return fl;
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
static textwindows void FreeFileLock(struct FileLock *fl) {
|
||||
fl->next = g_locks.free;
|
||||
g_locks.free = fl;
|
||||
}
|
||||
|
||||
static textwindows bool OverlapsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
uint64_t BegA, EndA, BegB, EndB;
|
||||
BegA = off;
|
||||
EndA = off + (len - 1);
|
||||
BegB = fl->off;
|
||||
EndB = fl->off + (fl->len - 1);
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
}
|
||||
|
||||
static textwindows bool EncompassesFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return off <= fl->off && fl->off + fl->len <= off + len;
|
||||
}
|
||||
|
||||
static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return fl->off == off && off + len == fl->off + fl->len;
|
||||
}
|
||||
|
||||
hidden textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
uintptr_t arg) {
|
||||
int e;
|
||||
struct flock *l;
|
||||
uint32_t flags, err;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
return __winerr();
|
||||
}
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
int64_t pos, off, len, end, size;
|
||||
|
||||
l = (struct flock *)arg;
|
||||
len = l->l_len;
|
||||
off = l->l_start;
|
||||
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
|
||||
|
||||
switch (l->l_whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
off = pos + off;
|
||||
pos = 0;
|
||||
if (SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
off = pos + off;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
off = size - off;
|
||||
off = INT64_MAX - off;
|
||||
break;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
len = size - off;
|
||||
len = INT64_MAX - off;
|
||||
}
|
||||
|
||||
if (off < 0 || len < 0) {
|
||||
if (off < 0 || len < 0 || __builtin_add_overflow(off, len, &end)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
@@ -91,8 +158,57 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
.Pointer = (void *)(uintptr_t)off};
|
||||
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||
// make it possible to transition read locks to write locks
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
if (EqualsFileLock(fl, off, len)) {
|
||||
if (fl->exc == l->l_type == F_WRLCK) {
|
||||
// we already have this lock
|
||||
return 0;
|
||||
} else {
|
||||
// unlock our read lock and acquire write lock below
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (OverlapsFileLock(fl, off, len)) {
|
||||
return enotsup();
|
||||
}
|
||||
}
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// return better information on conflicting locks if possible
|
||||
if (cmd == F_GETLK) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len) &&
|
||||
(l->l_type == F_WRLCK || !fl->exc)) {
|
||||
l->l_whence = SEEK_SET;
|
||||
l->l_start = fl->off;
|
||||
l->l_len = fl->len;
|
||||
l->l_type == fl->exc ? F_WRLCK : F_RDLCK;
|
||||
l->l_pid = getpid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (cmd != F_SETLKW) {
|
||||
// TODO(jart): we should use expo backoff in wrapper function
|
||||
// should not matter since sqlite doesn't need it
|
||||
flags |= kNtLockfileFailImmediately;
|
||||
}
|
||||
if (l->l_type == F_WRLCK) {
|
||||
@@ -103,72 +219,132 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
if (ok) {
|
||||
l->l_type = F_UNLCK;
|
||||
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
notpossible;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
l->l_pid = -1;
|
||||
ok = true;
|
||||
}
|
||||
} else if (ok) {
|
||||
fl = NewFileLock();
|
||||
fl->off = off;
|
||||
fl->len = len;
|
||||
fl->exc = l->l_type == F_WRLCK;
|
||||
fl->fd = fd;
|
||||
}
|
||||
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
e = errno;
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else if (errno == ENOLCK) {
|
||||
errno = e;
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd && EncompassesFileLock(fl, off, len)) {
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// win32 won't let us carve up existing locks
|
||||
int overlap_count = 0;
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len)) {
|
||||
++overlap_count;
|
||||
}
|
||||
}
|
||||
|
||||
// try to handle the carving cases needed by sqlite
|
||||
if (overlap_count == 1) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
off <= fl->off && //
|
||||
off + len >= fl->off && //
|
||||
off + len < fl->off + fl->len) {
|
||||
// cleave left side of lock
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (!UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
fl->len = (fl->off + fl->len) - (off + len);
|
||||
fl->off = off + len;
|
||||
ov.Pointer = (void *)(uintptr_t)fl->off;
|
||||
if (!LockFileEx(f->handle, kNtLockfileExclusiveLock, 0, fl->len,
|
||||
fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap_count) {
|
||||
return enotsup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return einval();
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
uint32_t flags;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||
rc = g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
|
||||
O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||
// O_NONBLOCK might require we start doing all i/o in threads
|
||||
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
|
||||
// not worth it.
|
||||
return einval();
|
||||
rc = enosys();
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
rc = 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
rc = 0;
|
||||
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
rc = sys_fcntl_nt_lock(g_fds.p + fd, fd, cmd, arg);
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
rc = sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
rc = ebadf();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
@@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
rc = impl(fd, cmd, arg);
|
||||
if (islock) {
|
||||
flock2cosmo(arg);
|
||||
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
|
||||
errno = e;
|
||||
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+107
-14
@@ -17,17 +17,22 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/flock.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Does things with file descriptor, via re-imagined hourglass api, e.g.
|
||||
* Does things with file descriptor, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
*
|
||||
@@ -37,16 +42,60 @@
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
|
||||
*
|
||||
* This function implements POSIX Advisory Locks, which let independent
|
||||
* processes (and on Windows, threads too!) read/write lock byte ranges
|
||||
* of files. See `test/libc/calls/lock_test.c` for an example.
|
||||
* This function implements file record locking, which lets independent
|
||||
* processes (and on Linux 3.15+, threads too!) lock arbitrary ranges
|
||||
* associated with a file. See `test/libc/calls/lock_test.c` and other
|
||||
* locking related tests in that folder.
|
||||
*
|
||||
* Please be warned that locks currently do nothing on Windows since
|
||||
* figuring out how to polyfill them correctly is a work in progress.
|
||||
* On Windows, the Cosmopolitan Libc polyfill for POSIX advisory locks
|
||||
* only implements enough of its nuances to support SQLite's needs. Some
|
||||
* possibilities, e.g. punching holes in lock, will raise `ENOTSUP`.
|
||||
*
|
||||
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
|
||||
* @param fd is the file descriptor
|
||||
* @param cmd can be one of:
|
||||
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
|
||||
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
|
||||
* - `F_GETFL` returns file descriptor status flags
|
||||
* - `F_SETFL` sets file descriptor status flags
|
||||
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
|
||||
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
|
||||
* - `F_SETLK` for record locking where `arg` is `struct flock *`
|
||||
* - `F_SETLKW` ditto but waits for lock (SQLite avoids this)
|
||||
* - `F_GETLK` to retrieve information about a record lock
|
||||
* - `F_OFD_SETLK` for better non-blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_SETLKW` for better blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_GETLK` for better lock querying (Linux 3.15+ only)
|
||||
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
|
||||
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
|
||||
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
|
||||
* - `F_MAXFD` on NetBSD to get max open file descriptor
|
||||
* - `F_NOCACHE` on MacOS to toggle data caching
|
||||
* - `F_GETPIPE_SZ` on Linux to get pipe size
|
||||
* - `F_SETPIPE_SZ` on Linux to set pipe size
|
||||
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` (Linux only)
|
||||
* - `DN_ACCESS` for file access
|
||||
* - `DN_MODIFY` for file modifications
|
||||
* - `DN_CREATE` for file creations
|
||||
* - `DN_DELETE` for file deletions
|
||||
* - `DN_RENAME` for file renames
|
||||
* - `DN_ATTRIB` for file attribute changes
|
||||
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
|
||||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EBADF if `fd` isn't a valid open file descriptor
|
||||
* @raise EINVAL if `cmd` is unknown or unsupported by os
|
||||
* @raise EINVAL if `cmd` is invalid or unsupported by os
|
||||
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
|
||||
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
|
||||
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
|
||||
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
|
||||
* @raise ENOTSUP on Windows if locking operation isn't supported yet
|
||||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
@@ -54,20 +103,64 @@ int fcntl(int fd, int cmd, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
uintptr_t arg;
|
||||
|
||||
va_start(va, cmd);
|
||||
arg = va_arg(va, uintptr_t);
|
||||
va_end(va);
|
||||
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
if (cmd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
END_CANCELLATION_POINT;
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
|
||||
|
||||
#ifdef SYSDEBUG
|
||||
if (cmd == F_GETFD || //
|
||||
cmd == F_GETOWN || //
|
||||
cmd == F_FULLFSYNC || //
|
||||
cmd == F_BARRIERFSYNC || //
|
||||
cmd == F_MAXFD) {
|
||||
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
|
||||
} else if (cmd == F_GETFL) {
|
||||
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeOpenFlags(rc));
|
||||
} else if (cmd == F_SETLK || //
|
||||
cmd == F_SETLKW || //
|
||||
cmd == F_GETLK || //
|
||||
((SupportsLinux() || SupportsXnu()) && //
|
||||
cmd != -1 && //
|
||||
(cmd == F_OFD_SETLK || //
|
||||
cmd == F_OFD_SETLKW || //
|
||||
cmd == F_OFD_GETLK))) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeFlock(cmd, (struct flock *)arg), rc);
|
||||
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
|
||||
cmd == F_GETPATH) {
|
||||
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
!rc ? (const char *)arg : "n/a", rc);
|
||||
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeDnotifyFlags(arg), rc);
|
||||
} else {
|
||||
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -23,5 +23,6 @@
|
||||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (_check_interrupts(false, 0)) return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
+11
-3
@@ -17,10 +17,12 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
@@ -29,20 +31,26 @@
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fdatasync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = 0;
|
||||
STRACE("fdatasync(%d) → disabled% m", fd);
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+3
-17
@@ -21,8 +21,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -48,21 +47,8 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "fexecve(%d, {", fd);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (IsLinux()) {
|
||||
char path[14 + 12];
|
||||
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);
|
||||
|
||||
@@ -51,7 +51,7 @@ bool fileexists(const char *path) {
|
||||
struct ZiposUri zipname;
|
||||
uint16_t path16[PATH_MAX];
|
||||
e = errno;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
||||
+7
-1
@@ -17,10 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
||||
/**
|
||||
* Acquires lock on file.
|
||||
@@ -30,15 +31,20 @@
|
||||
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
|
||||
* non-blocking, and unlocking
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
int flock(int fd, int op) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!IsWindows()) {
|
||||
rc = sys_flock(fd, op);
|
||||
} else {
|
||||
rc = sys_flock_nt(fd, op);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("flock(%d, %d) → %d% m", fd, op, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
||||
int rc;
|
||||
void *p;
|
||||
union metastat ms;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
|
||||
if (IsLinux()) {
|
||||
_Static_assert(sizeof(*st) == sizeof(ms.linux), "assumption broken");
|
||||
if (IsAsan() && (st && !__asan_is_valid(st, sizeof(*st)))) return efault();
|
||||
|
||||
@@ -17,22 +17,26 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int fstatfs(int fd, struct statfs *sf) {
|
||||
int rc;
|
||||
union statfs_meta m;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
CheckLargeStackAllocation(&m, sizeof(m));
|
||||
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_fstatfs(fd, &m)) != -1) {
|
||||
statfs2cosmo(sf, &m);
|
||||
@@ -42,6 +46,8 @@ int fstatfs(int fd, struct statfs *sf) {
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
|
||||
return rc;
|
||||
}
|
||||
+11
-3
@@ -17,32 +17,40 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fsync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fsync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fysnc(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = 0;
|
||||
STRACE("fsync(%d) → disabled% m", fd);
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fsync_fake(%d) → %d% m", fd, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
@@ -49,6 +50,7 @@
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `length` is negative
|
||||
* @raise EINTR if signal was delivered instead
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EIO if a low-level i/o error happened
|
||||
* @raise EFBIG or EINVAL if `length` is too huge
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
@@ -56,12 +58,14 @@
|
||||
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
|
||||
* @raise EINVAL if `fd` wasn't opened in a writeable mode
|
||||
* @raise ENOSYS on bare metal
|
||||
* @see truncate()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int ftruncate(int fd, int64_t length) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
@@ -78,6 +82,8 @@ int ftruncate(int fd, int64_t length) {
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
#define HW_NCPUONLINE_NETBSD 16
|
||||
#define ALL_PROCESSOR_GROUPS 0xffff
|
||||
|
||||
static unsigned GetCpuCountLinux(void) {
|
||||
static unsigned _getcpucount_linux(void) {
|
||||
cpu_set_t s = {0};
|
||||
if (sys_sched_getaffinity(0, sizeof(s), &s) != -1) {
|
||||
return CPU_COUNT(&s);
|
||||
@@ -43,7 +43,7 @@ static unsigned GetCpuCountLinux(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetCpuCountBsd(void) {
|
||||
static unsigned _getcpucount_bsd(void) {
|
||||
size_t n;
|
||||
int c, cmd[2];
|
||||
n = sizeof(c);
|
||||
@@ -62,12 +62,12 @@ static unsigned GetCpuCountBsd(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetCpuCountImpl(void) {
|
||||
static unsigned _getcpucount_impl(void) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsBsd()) {
|
||||
return GetCpuCountLinux();
|
||||
return _getcpucount_linux();
|
||||
} else {
|
||||
return GetCpuCountBsd();
|
||||
return _getcpucount_bsd();
|
||||
}
|
||||
} else {
|
||||
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
|
||||
@@ -77,18 +77,24 @@ static unsigned GetCpuCountImpl(void) {
|
||||
static int g_cpucount;
|
||||
|
||||
// precompute because process affinity on linux may change later
|
||||
__attribute__((__constructor__)) static void init(void) {
|
||||
g_cpucount = GetCpuCountImpl();
|
||||
__attribute__((__constructor__)) static void _getcpucount_init(void) {
|
||||
g_cpucount = _getcpucount_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of CPUs in system.
|
||||
*
|
||||
* This is the same as the standard interface:
|
||||
*
|
||||
* sysconf(_SC_NPROCESSORS_ONLN);
|
||||
*
|
||||
* Except this function isn't a bloated diamond dependency.
|
||||
*
|
||||
* On Intel systems with HyperThreading this will return the number of
|
||||
* cores multiplied by two.
|
||||
*
|
||||
* @return cpu count or 0 if it couldn't be determined
|
||||
*/
|
||||
unsigned GetCpuCount(void) {
|
||||
unsigned _getcpucount(void) {
|
||||
return g_cpucount;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
|
||||
int fd;
|
||||
union metastat st[2];
|
||||
char buf[XNU_MAXPATHLEN], *ret = NULL;
|
||||
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if ((fd = __sys_openat_nc(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if (__sys_fstat(fd, &st[0]) != -1) {
|
||||
if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
|
||||
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
|
||||
|
||||
@@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
} else if (_weaken(malloc)) {
|
||||
assert(!__vforked);
|
||||
_unassert(!__vforked);
|
||||
if (!size) size = PATH_MAX;
|
||||
if (!(p = _weaken(malloc)(size))) {
|
||||
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
@@ -60,7 +61,14 @@ ssize_t getfiledescriptorsize(int fd) {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsMetal()) {
|
||||
rc = -1;
|
||||
if (fd < 0 || fd >= g_fds.n) {
|
||||
rc = ebadf();
|
||||
} else if (g_fds.p[fd].kind != kFdFile) {
|
||||
rc = eacces();
|
||||
} else {
|
||||
struct MetalFile *state = (struct MetalFile *)g_fds.p[fd].handle;
|
||||
rc = state->size;
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
if (!__sys_fstat(fd, &st)) {
|
||||
rc = METASTAT(st, st_size);
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32)
|
||||
|
||||
@@ -60,7 +60,7 @@ static textstartup void sys_getloadavg_nt_init(void) {
|
||||
double a[3];
|
||||
if (IsWindows()) {
|
||||
load = 1;
|
||||
cpus = GetCpuCount() / 2;
|
||||
cpus = _getcpucount() / 2;
|
||||
cpus = MAX(1, cpus);
|
||||
GetSystemTimes(&idle1, &kern1, &user1);
|
||||
}
|
||||
|
||||
+58
-19
@@ -16,28 +16,67 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/kntprioritycombos.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nexgen32e/ffs.h"
|
||||
#include "libc/nt/enum/processaccess.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/prio.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_getpriority_nt(int ignored) {
|
||||
size_t i;
|
||||
uint32_t tier, lg2tier, wut;
|
||||
if ((tier = GetPriorityClass(GetCurrentProcess())) != 0 &&
|
||||
(wut = GetThreadPriority(GetCurrentThread())) != -1u) {
|
||||
lg2tier = ffs(tier);
|
||||
for (i = 0; i < kNtPriorityCombosLen; ++i) {
|
||||
if (kNtPriorityCombos[i].lg2tier == lg2tier &&
|
||||
kNtPriorityCombos[i].wut == wut) {
|
||||
return kNtPriorityCombos[i].nice;
|
||||
}
|
||||
}
|
||||
abort();
|
||||
} else {
|
||||
return __winerr();
|
||||
textwindows int sys_getpriority_nt(int which, unsigned pid) {
|
||||
int rc;
|
||||
uint32_t tier;
|
||||
int64_t h, closeme = -1;
|
||||
|
||||
if (which != PRIO_PROCESS) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!pid || pid == getpid()) {
|
||||
h = GetCurrentProcess();
|
||||
} else if (__isfdkind(pid, kFdProcess)) {
|
||||
h = g_fds.p[pid].handle;
|
||||
} else {
|
||||
h = OpenProcess(kNtProcessQueryInformation, false, pid);
|
||||
if (!h) return __winerr();
|
||||
closeme = h;
|
||||
}
|
||||
|
||||
if ((tier = GetPriorityClass(h))) {
|
||||
switch (tier) {
|
||||
case kNtRealtimePriorityClass:
|
||||
rc = -16;
|
||||
break;
|
||||
case kNtHighPriorityClass:
|
||||
rc = -10;
|
||||
break;
|
||||
case kNtAboveNormalPriorityClass:
|
||||
rc = -5;
|
||||
break;
|
||||
case kNtNormalPriorityClass:
|
||||
rc = 0;
|
||||
break;
|
||||
case kNtBelowNormalPriorityClass:
|
||||
rc = 5;
|
||||
break;
|
||||
case kNtIdlePriorityClass:
|
||||
rc = 15;
|
||||
break;
|
||||
default:
|
||||
notpossible;
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
if (closeme != -1) {
|
||||
CloseHandle(closeme);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
+40
-10
@@ -17,10 +17,13 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Returns nice value of thing.
|
||||
@@ -29,20 +32,47 @@
|
||||
* to clear `errno` beforehand and see if it changed, in order to truly
|
||||
* determine if an error happened.
|
||||
*
|
||||
* @param which can be PRIO_PROCESS, PRIO_PGRP, PRIO_USER
|
||||
* On Windows, there's only six priority classes. We define them as -16
|
||||
* (realtime), -10 (high), -5 (above), 0 (normal), 5 (below), 15 (idle)
|
||||
* which are the only values that'll roundtrip getpriority/setpriority.
|
||||
*
|
||||
* @param which can be one of:
|
||||
* - `PRIO_PROCESS` is supported universally
|
||||
* - `PRIO_PGRP` is supported on unix
|
||||
* - `PRIO_USER` is supported on unix
|
||||
* @param who is the pid, pgid, or uid (0 means current)
|
||||
* @return value ∈ [-NZERO,NZERO) or -1 w/ errno
|
||||
* @see setpriority(), nice()
|
||||
* @raise EINVAL if `which` was invalid or unsupported
|
||||
* @raise EPERM if access to process was denied
|
||||
* @raise ESRCH if no such process existed
|
||||
* @see setpriority()
|
||||
*/
|
||||
int getpriority(int which, unsigned who) {
|
||||
privileged int getpriority(int which, unsigned who) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_getpriority(which, who)) != -1) {
|
||||
rc = 20 - rc;
|
||||
char cf;
|
||||
if (IsLinux()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(140), "D"(which), "S"(who)
|
||||
: "rcx", "r11", "memory");
|
||||
if (rc >= 0) {
|
||||
rc = NZERO - rc;
|
||||
} else {
|
||||
errno = -rc;
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsBsd()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(rc)
|
||||
: "1"((IsXnu() ? 0x2000000 : 0) | 100), "D"(which), "S"(who)
|
||||
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
|
||||
if (cf) {
|
||||
errno = rc;
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
rc = sys_getsetpriority_nt(which, who, 0, sys_getpriority_nt);
|
||||
rc = sys_getpriority_nt(which, who);
|
||||
}
|
||||
STRACE("getpriority(%d, %u) → %d% m", which, who, rc);
|
||||
STRACE("getpriority(%s, %u) → %d% m", DescribeWhichPrio(which), who, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
@@ -76,6 +77,11 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsMetal()) {
|
||||
if (!memccpy(p, APE_COM_NAME, 0, e - p - 1)) e[-1] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if argv[0] exists then turn it into an absolute path. we also try
|
||||
// adding a .com suffix since the ape auto-appends it when resolving
|
||||
if (__argc && (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) ||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
|
||||
int64_t me, nsignals;
|
||||
int64_t me;
|
||||
struct NtIoCounters iocount;
|
||||
struct NtProcessMemoryCountersEx memcount;
|
||||
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
|
||||
@@ -48,9 +48,6 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
|
||||
!GetProcessIoCounters(me, &iocount)) {
|
||||
return __winerr();
|
||||
}
|
||||
__sig_lock();
|
||||
nsignals = __sig_count;
|
||||
__sig_unlock();
|
||||
*usage = (struct rusage){
|
||||
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
|
||||
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),
|
||||
|
||||
@@ -63,7 +63,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||
rc = __gettimeofday(tv, tz, 0).ax;
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,6 @@ hidden extern const struct Fd kEmptyFd;
|
||||
int __reservefd(int) hidden;
|
||||
int __reservefd_unlocked(int) hidden;
|
||||
void __releasefd(int) hidden;
|
||||
void __releasefd_unlocked(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
int __ensurefds_unlocked(int) hidden;
|
||||
void __printfds(void) hidden;
|
||||
@@ -43,8 +42,8 @@ forceinline size_t _clampio(size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
int sys_close_nt(struct Fd *) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_close_nt(struct Fd *, int) hidden;
|
||||
int _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
@@ -18,25 +18,33 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/lockcmpxchgp.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
bool res;
|
||||
if (__threaded && __threaded != gettid()) return false;
|
||||
textwindows int _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
||||
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
||||
}
|
||||
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
|
||||
return res;
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) return eintr();
|
||||
return 0;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
|
||||
int count, i;
|
||||
|
||||
/* __hostInfo must be empty */
|
||||
assert(__hostInfo == NULL);
|
||||
_unassert(__hostInfo == NULL);
|
||||
|
||||
for (aa = firstAdapter; aa; aa = aa->Next) {
|
||||
/* Skip all the interfaces with no address and the ones that are not AF_INET
|
||||
|
||||
@@ -51,7 +51,7 @@ bool isdirectory(const char *path) {
|
||||
union metastat st;
|
||||
struct ZiposUri zipname;
|
||||
e = errno;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
||||
@@ -48,7 +48,7 @@ bool isregularfile(const char *path) {
|
||||
union metastat st;
|
||||
struct ZiposUri zipname;
|
||||
e = errno;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
||||
@@ -51,7 +51,7 @@ bool issymlink(const char *path) {
|
||||
union metastat st;
|
||||
struct ZiposUri zipname;
|
||||
e = errno;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
||||
+5
-1
@@ -17,10 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
@@ -38,6 +38,10 @@
|
||||
* >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc.
|
||||
* =0 checks both if pid exists and we can signal it
|
||||
* @return 0 if something was accomplished, or -1 w/ errno
|
||||
* @raise ESRCH if `pid` couldn't be found
|
||||
* @raise EPERM if lacked permission to signal process
|
||||
* @raise EPERM if pledge() is in play without `proc` promised
|
||||
* @raise EINVAL if the provided `sig` is invalid or unsupported
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int kill(int pid, int sig) {
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/kntprioritycombos.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/ffs.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/enum/threadpriority.h"
|
||||
|
||||
hidden const struct NtPriorityCombo kNtPriorityCombos[] = {
|
||||
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
|
||||
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
|
||||
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
|
||||
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
|
||||
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
|
||||
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
|
||||
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
|
||||
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
|
||||
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
|
||||
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
|
||||
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
|
||||
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
|
||||
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
|
||||
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
|
||||
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
|
||||
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
|
||||
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
|
||||
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
|
||||
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
|
||||
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
|
||||
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
|
||||
};
|
||||
|
||||
hidden const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);
|
||||
Regular → Executable
-18
@@ -1,18 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct NtPriorityCombo {
|
||||
int8_t nice; /* sorted by this */
|
||||
int8_t lg2tier;
|
||||
int8_t wut;
|
||||
int8_t prio;
|
||||
};
|
||||
|
||||
hidden extern const unsigned kNtPriorityCombosLen;
|
||||
hidden extern const struct NtPriorityCombo kNtPriorityCombos[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_ */
|
||||
+1
-1
@@ -41,7 +41,7 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
|
||||
int flags) {
|
||||
int rc;
|
||||
if (IsAsan() &&
|
||||
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
|
||||
(!__asan_is_valid_str(oldpath) || !__asan_is_valid_str(newpath))) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
((rc = __zipos_notat(olddirfd, oldpath)) == -1 ||
|
||||
|
||||
@@ -34,6 +34,8 @@ textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
|
||||
} else {
|
||||
return espipe();
|
||||
}
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
return espipe();
|
||||
} else {
|
||||
return ebadf();
|
||||
}
|
||||
|
||||
Loaded 100 of 1379 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user