mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make fixes and improvements
- Invent iso8601us() for faster timestamps - Improve --strace descriptions of sigset_t - Rebuild the Landlock Make bootstrap binary - Introduce MODE=sysv for non-Windows builds - Permit OFD fcntl() locks under pledge(flock) - redbean can now protect your kernel from ddos - Have vfork() fallback to sys_fork() not fork() - Change kmalloc() to not die when out of memory - Improve documentation for some termios functions - Rewrite putenv() and friends to conform to POSIX - Fix linenoise + strace verbosity issue on Windows - Fix regressions in our ability to show backtraces - Change redbean SetHeader() to no-op if value is nil - Improve fcntl() so SQLite locks work in non-WAL mode - Remove some unnecessary work during fork() on Windows - Create redbean-based SSL reverse proxy for IPv4 TurfWar - Fix ape/apeinstall.sh warning when using non-bash shells - Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean - Support $PWD, $UID, $GID, and $EUID in command interpreter - Introduce experimental JTqFpD APE prefix for non-Windows builds - Invent blackhole daemon for firewalling IP addresses via UNIX named socket - Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
This commit is contained in:
parent
648bf6555c
commit
f7ff77d865
209 changed files with 3818 additions and 998 deletions
10
ape/ape.S
10
ape/ape.S
|
@ -112,7 +112,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
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
|
@ -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,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);
|
||||
|
|
|
@ -146,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
|
||||
|
|
|
@ -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\
|
||||
|
|
42
examples/symtab.c
Normal file
42
examples/symtab.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -16,7 +16,9 @@
|
|||
│ 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/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
|
19
libc/calls/blocksigs.internal.h
Normal file
19
libc/calls/blocksigs.internal.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_INTERNAL_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_INTERNAL_H_ */
|
|
@ -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, 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,36 +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 *, unsigned);
|
||||
int mkdirat(int, const char *, unsigned);
|
||||
int makedirs(const char *, unsigned);
|
||||
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 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, ...);
|
||||
|
@ -161,19 +151,19 @@ 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 setegid(unsigned);
|
||||
int seteuid(unsigned);
|
||||
int setfsgid(unsigned);
|
||||
int setfsuid(unsigned);
|
||||
int setgid(unsigned);
|
||||
int setgroups(size_t, const uint32_t[]);
|
||||
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(unsigned);
|
||||
int sigignore(int);
|
||||
|
@ -181,16 +171,22 @@ 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 touch(const char *, unsigned);
|
||||
int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
unsigned umask(unsigned);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
int unlinkat(int, const char *, int);
|
||||
|
@ -199,11 +195,10 @@ 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, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
|
@ -212,8 +207,13 @@ 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_
|
||||
|
|
88
libc/calls/cfspeed.c
Normal file
88
libc/calls/cfspeed.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/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;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -27,12 +27,9 @@
|
|||
/**
|
||||
* 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
|
||||
* @raise EBADF if `first` is negative
|
||||
|
|
|
@ -45,27 +45,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;
|
||||
}
|
||||
sys_close_nt(g_fds.p + newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +77,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
|||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd_unlocked(newfd);
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -40,7 +41,9 @@ static bool IsApeBinary(const char *path) {
|
|||
char buf[8];
|
||||
bool res = false;
|
||||
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);
|
||||
|
@ -61,14 +64,14 @@ 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;
|
||||
if (errno == ENOEXEC) {
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
|
@ -83,13 +86,19 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
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 *));
|
||||
} else {
|
||||
return enoexec();
|
||||
}
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -54,8 +54,8 @@ 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) ||
|
||||
(IsAsan() && (!__asan_is_valid(prog, 1) || //
|
||||
!__asan_is_valid_strlist(argv) || //
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
|
|
|
@ -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,63 +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"
|
||||
|
||||
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 FileLock {
|
||||
struct FileLock *next;
|
||||
int64_t off;
|
||||
int64_t len;
|
||||
int fd;
|
||||
bool exc;
|
||||
};
|
||||
|
||||
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:
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -89,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) {
|
||||
|
@ -101,68 +219,133 @@ 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;
|
||||
}
|
||||
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;
|
||||
|
||||
// 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 = einval();
|
||||
} 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;
|
||||
rc = 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;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#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));
|
||||
*
|
||||
|
@ -41,12 +41,14 @@
|
|||
* 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 fd is the file descriptor
|
||||
* @param cmd can be one of:
|
||||
|
@ -56,12 +58,12 @@
|
|||
* - `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 (i.e. blocks) for lock
|
||||
* - `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 locks on Linux and XNU
|
||||
* - `F_OFD_SETLKW` for better locks on Linux and XNU
|
||||
* - `F_OFD_GETLK` for better locks on Linux and XNU
|
||||
* - `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`
|
||||
|
@ -71,7 +73,7 @@
|
|||
* - `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` on Linux
|
||||
* - `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
|
||||
|
@ -88,6 +90,7 @@
|
|||
* @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
|
||||
|
|
|
@ -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,7 +42,7 @@ forceinline size_t _clampio(size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
int sys_close_nt(struct Fd *) hidden;
|
||||
int sys_close_nt(struct Fd *, int) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -88,7 +88,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
|||
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
if (rc == -1) {
|
||||
__releasefd_unlocked(fd);
|
||||
__releasefd(fd);
|
||||
}
|
||||
__fds_unlock();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
|
|||
return -1;
|
||||
}
|
||||
if ((writer = __reservefd_unlocked(-1)) == -1) {
|
||||
__releasefd_unlocked(reader);
|
||||
__releasefd(reader);
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
|
|||
CloseHandle(hin);
|
||||
}
|
||||
}
|
||||
__releasefd_unlocked(writer);
|
||||
__releasefd_unlocked(reader);
|
||||
__releasefd(writer);
|
||||
__releasefd(reader);
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1606,19 +1606,26 @@ static privileged void AllowFcntlStdio(struct Filter *f) {
|
|||
|
||||
// The second argument of fcntl() must be one of:
|
||||
//
|
||||
// - F_GETLK (5)
|
||||
// - F_SETLK (6)
|
||||
// - F_SETLKW (7)
|
||||
// - F_GETLK (0x05)
|
||||
// - F_SETLK (0x06)
|
||||
// - F_SETLKW (0x07)
|
||||
// - F_OFD_GETLK (0x24)
|
||||
// - F_OFD_SETLK (0x25)
|
||||
// - F_OFD_SETLKW (0x26)
|
||||
//
|
||||
static privileged void AllowFcntlLock(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/*L2*/ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 5, 0, 5 - 3),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 8, 5 - 4, 0),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 9),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x05, 5, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 4, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x07, 3, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x24, 2, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x25, 1, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x26, 0, 1),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/* next filter */
|
||||
};
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -31,16 +28,13 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
||||
int e, i;
|
||||
size_t got;
|
||||
bool masked;
|
||||
ssize_t rc, toto;
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
if (fd < 0) {
|
||||
return ebadf();
|
||||
|
@ -94,26 +88,17 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
if (rc == -1) {
|
||||
if (!toto) {
|
||||
toto = -1;
|
||||
} else if (errno != EINTR) {
|
||||
notpossible;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
got = rc;
|
||||
toto += got;
|
||||
off += got;
|
||||
if (got != iov[i].iov_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!masked) {
|
||||
sigfillset(&mask);
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
|
||||
masked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (masked) {
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
|
||||
}
|
||||
|
||||
return toto;
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -31,17 +28,14 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
||||
int64_t off) {
|
||||
int i, e;
|
||||
bool masked;
|
||||
size_t sent;
|
||||
ssize_t rc, toto;
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
if (fd < 0) {
|
||||
return ebadf();
|
||||
|
@ -95,26 +89,17 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
|||
if (rc == -1) {
|
||||
if (!toto) {
|
||||
toto = -1;
|
||||
} else if (errno != EINTR) {
|
||||
notpossible;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sent = rc;
|
||||
toto += sent;
|
||||
off += sent;
|
||||
if (sent != iov[i].iov_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!masked) {
|
||||
sigfillset(&mask);
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
|
||||
masked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (masked) {
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
|
||||
}
|
||||
|
||||
return toto;
|
||||
|
|
|
@ -17,11 +17,18 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
// really want to avoid locking here so close() needn't block signals
|
||||
void __releasefd(int fd) {
|
||||
__fds_lock();
|
||||
__releasefd_unlocked(fd);
|
||||
__fds_unlock();
|
||||
int f1, f2;
|
||||
if (!(0 <= fd && fd < g_fds.n)) return;
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
f1 = atomic_load_explicit(&g_fds.f, memory_order_relaxed);
|
||||
do {
|
||||
f2 = MIN(fd, f1);
|
||||
} while (!atomic_compare_exchange_weak_explicit(
|
||||
&g_fds.f, &f1, f2, memory_order_release, memory_order_relaxed));
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -36,6 +37,8 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// TODO(jart): make more of this code lockless
|
||||
|
||||
static volatile size_t mapsize;
|
||||
|
||||
/**
|
||||
|
@ -71,9 +74,10 @@ int __ensurefds(int fd) {
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int __reservefd_unlocked(int start) {
|
||||
int fd;
|
||||
int fd, f1, f2;
|
||||
for (;;) {
|
||||
for (fd = MAX(start, g_fds.f); fd < g_fds.n; ++fd) {
|
||||
f1 = atomic_load_explicit(&g_fds.f, memory_order_acquire);
|
||||
for (fd = MAX(start, f1); fd < g_fds.n; ++fd) {
|
||||
if (!g_fds.p[fd].kind) {
|
||||
break;
|
||||
}
|
||||
|
@ -81,7 +85,11 @@ int __reservefd_unlocked(int start) {
|
|||
fd = __ensurefds_unlocked(fd);
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||
_cmpxchg(&g_fds.f, fd, fd + 1);
|
||||
// g_fds.f isn't guarded by our mutex
|
||||
do {
|
||||
f2 = MAX(fd + 1, f1);
|
||||
} while (!atomic_compare_exchange_weak_explicit(
|
||||
&g_fds.f, &f1, f2, memory_order_release, memory_order_relaxed));
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigaction.internal.h"
|
||||
#include "libc/calls/struct/siginfo.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
|
@ -474,9 +476,11 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (sig == SIGKILL || sig == SIGSTOP) {
|
||||
rc = einval();
|
||||
} else {
|
||||
BLOCK_SIGNALS;
|
||||
__sig_lock();
|
||||
rc = __sigaction(sig, act, oldact);
|
||||
__sig_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(0, act),
|
||||
DescribeSigaction(rc, oldact), rc);
|
||||
|
|
|
@ -16,13 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
void __releasefd_unlocked(int fd) {
|
||||
if (0 <= fd && fd < g_fds.n) {
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
g_fds.f = MIN(fd, g_fds.f);
|
||||
}
|
||||
/**
|
||||
* Blocks all signals without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigblockall(void) {
|
||||
sigset_t ss;
|
||||
sigfillset(&ss);
|
||||
return _sigsetmask(ss);
|
||||
}
|
|
@ -49,8 +49,8 @@ privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
|
|||
__repstosb(&g.uc, 0, sizeof(g.uc));
|
||||
__siginfo2cosmo(&g.si, (void *)openbsdinfo);
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
__repmovsb(&g.uc.uc_sigmask, &ctx->sc_mask,
|
||||
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
|
||||
g.uc.uc_sigmask.__bits[0] = ctx->sc_mask;
|
||||
g.uc.uc_sigmask.__bits[1] = 0;
|
||||
g.uc.uc_mcontext.rdi = ctx->sc_rdi;
|
||||
g.uc.uc_mcontext.rsi = ctx->sc_rsi;
|
||||
g.uc.uc_mcontext.rdx = ctx->sc_rdx;
|
||||
|
|
|
@ -473,6 +473,7 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
|
|||
if (xnuctx) {
|
||||
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
|
||||
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
||||
g.uc.uc_sigmask.__bits[1] = 0;
|
||||
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
||||
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
||||
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -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,21 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
return 0;
|
||||
/**
|
||||
* Sets signal mask without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigsetmask(sigset_t neu) {
|
||||
sigset_t res;
|
||||
if (IsMetal() || IsWindows()) {
|
||||
__sig_mask(SIG_SETMASK, &neu, &res);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ospeed = speed;
|
||||
return 0;
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &neu, &res));
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -25,7 +25,7 @@ struct Fd {
|
|||
};
|
||||
|
||||
struct Fds {
|
||||
int f; /* lowest free slot */
|
||||
_Atomic(int) f; /* lowest free slot */
|
||||
size_t n;
|
||||
struct Fd *p, *e;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ struct flock { /* cosmopolitan abi */
|
|||
int64_t l_start; /* starting offset */
|
||||
int64_t l_len; /* no. bytes (0 means to end of file) */
|
||||
int32_t l_pid; /* lock owner */
|
||||
int32_t l_sysid; /* remote system id or zero for local */
|
||||
int32_t l_sysid; /* remote system id or zero for local (freebsd) */
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -21,6 +21,8 @@ int sigprocmask(int, const sigset_t *, sigset_t *);
|
|||
int sigsuspend(const sigset_t *);
|
||||
int sigpending(sigset_t *);
|
||||
int pthread_sigmask(int, const sigset_t *, sigset_t *);
|
||||
sigset_t _sigsetmask(sigset_t);
|
||||
sigset_t _sigblockall(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -10,8 +10,8 @@ COSMOPOLITAN_C_START_
|
|||
│ cosmopolitan § syscalls » system five » structless synthetic jump slots ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
axdx_t __sys_fork(void) hidden;
|
||||
axdx_t __sys_pipe(i32[hasatleast 2], i32) hidden;
|
||||
axdx_t sys_fork(void) hidden;
|
||||
axdx_t sys_getpid(void) hidden;
|
||||
char *sys_getcwd(char *, u64) hidden;
|
||||
char *sys_getcwd_xnu(char *, u64) hidden;
|
||||
|
@ -46,6 +46,7 @@ i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
|
|||
i32 sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 sys_fdatasync(i32) hidden;
|
||||
i32 sys_flock(i32, i32) hidden;
|
||||
i32 sys_fork(void) hidden;
|
||||
i32 sys_fsync(i32) hidden;
|
||||
i32 sys_ftruncate(i32, i64, i64) hidden;
|
||||
i32 sys_getcontext(void *) hidden;
|
||||
|
|
|
@ -16,8 +16,41 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int tcdrain(int fd) {
|
||||
return ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
static textwindows int sys_tcdrain_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until all written output is transmitted.
|
||||
*
|
||||
* @param fd is file descriptor of tty
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcdrain(int fd) {
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
} else {
|
||||
rc = sys_tcdrain_nt(fd);
|
||||
}
|
||||
STRACE("tcdrain(%d) → %d% m", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,31 +16,91 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define kNtPurgeTxabort 1
|
||||
#define kNtPurgeRxabort 2
|
||||
|
||||
static const char *DescribeFlow(char buf[12], int action) {
|
||||
if (action == TCOOFF) return "TCOOFF";
|
||||
if (action == TCOON) return "TCOON";
|
||||
if (action == TCIOFF) return "TCIOFF";
|
||||
if (action == TCION) return "TCION";
|
||||
FormatInt32(buf, action);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int sys_tcflow_bsd(int fd, int action) {
|
||||
int rc;
|
||||
uint8_t c;
|
||||
struct termios t;
|
||||
if (action == TCOOFF) return sys_ioctl(fd, TIOCSTOP, 0);
|
||||
if (action == TCOON) return sys_ioctl(fd, TIOCSTART, 0);
|
||||
if (action != TCIOFF && action != TCION) return einval();
|
||||
if (sys_ioctl(fd, TCGETS, &t) == -1) return -1;
|
||||
c = t.c_cc[action == TCIOFF ? VSTOP : VSTART];
|
||||
if (c == 255) return 0; // code is disabled
|
||||
if (sys_write(fd, &c, 1) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dontinline textwindows int sys_tcflow_nt(int fd, int action) {
|
||||
bool32 ok;
|
||||
int64_t h;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
h = g_fds.p[fd].handle;
|
||||
if (action == TCOOFF) {
|
||||
ok = PurgeComm(h, kNtPurgeTxabort);
|
||||
} else if (action == TCIOFF) {
|
||||
ok = PurgeComm(h, kNtPurgeRxabort);
|
||||
} else if (action == TCOON || action == TCION) {
|
||||
ok = ClearCommBreak(h);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes flow of teletypewriter data.
|
||||
*
|
||||
* - `TCOOFF` suspends output
|
||||
* - `TCOON` resumes output
|
||||
* - `TCIOFF` transmits a STOP character
|
||||
* - `TCION` transmits a START character
|
||||
* @param fd is file descriptor of tty
|
||||
* @param action may be one of:
|
||||
* - `TCOOFF` to suspend output
|
||||
* - `TCOON` to resume output
|
||||
* - `TCIOFF` to transmit a `STOP` character
|
||||
* - `TCION` to transmit a `START` character
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `action` is invalid
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcflow(int fd, int action) {
|
||||
uint8_t c;
|
||||
struct termios t;
|
||||
if (!IsBsd()) return sys_ioctl(fd, TCXONC, action);
|
||||
if (action == TCOOFF) return sys_ioctl(fd, TIOCSTOP, 0);
|
||||
if (action == TCOON) return sys_ioctl(fd, TIOCSTART, 0);
|
||||
if (action != TCIOFF && action != TCION) return einval();
|
||||
if (tcgetattr(fd, &t) == -1) return -1;
|
||||
if ((c = t.c_cc[action == TCIOFF ? VSTOP : VSTART]) != 255) {
|
||||
if (sys_write(fd, &c, 1) == -1) return -1;
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (IsBsd()) {
|
||||
rc = sys_ioctl(fd, TCXONC, action);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCXONC, action);
|
||||
} else {
|
||||
rc = sys_tcflow_nt(fd, action);
|
||||
}
|
||||
return 0;
|
||||
STRACE("tcflow(%d, %s) → %d% m", fd, DescribeFlow(alloca(12), action), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,70 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define kNtPurgeTxclear 4
|
||||
#define kNtPurgeRxclear 8
|
||||
|
||||
static const char *DescribeFlush(char buf[12], int action) {
|
||||
if (action == TCIFLUSH) return "TCIFLUSH";
|
||||
if (action == TCOFLUSH) return "TCOFLUSH";
|
||||
if (action == TCIOFLUSH) return "TCIOFLUSH";
|
||||
FormatInt32(buf, action);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
||||
bool32 ok;
|
||||
int64_t h;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
ok = true;
|
||||
h = g_fds.p[fd].handle;
|
||||
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeRxclear);
|
||||
}
|
||||
if (queue == TCOFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeTxclear);
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes teletypewriter data.
|
||||
* Discards queued data on teletypewriter.
|
||||
*
|
||||
* @param queue may be one of:
|
||||
* - `TCIFLUSH` flushes data received but not read
|
||||
* - `TCOFLUSH` flushes data written but not transmitted
|
||||
* - `TCIOFLUSH` does both `TCOFLUSH` and `TCIFLUSH`
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `action` is invalid
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcflush(int fd, int queue) {
|
||||
/* TODO(jart): Windows? */
|
||||
return sys_ioctl(fd, TCFLSH, queue);
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCFLSH, queue);
|
||||
} else {
|
||||
rc = sys_tcflush_nt(fd, queue);
|
||||
}
|
||||
STRACE("tcflush(%d, %s) → %d% m", fd, DescribeFlush(alloca(12), queue), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,16 +16,29 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns which process group controls terminal.
|
||||
*
|
||||
* @return process group id on success, or -1 w/ errno
|
||||
* @raise ENOTTY if `fd` is isn't controlling teletypewriter
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t tcgetpgrp(int fd) {
|
||||
int pgrp;
|
||||
if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) return -1;
|
||||
return pgrp;
|
||||
int tcgetpgrp(int fd) {
|
||||
int rc, pgrp;
|
||||
if (IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = sys_ioctl(fd, TIOCGPGRP, &pgrp);
|
||||
}
|
||||
STRACE("tcgetpgrp(%d) → %d% m", fd, rc == -1 ? rc : pgrp);
|
||||
return rc == -1 ? rc : pgrp;
|
||||
}
|
||||
|
|
|
@ -17,18 +17,53 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int tcsendbreak(int fd, int len) {
|
||||
if (!IsBsd()) {
|
||||
return sys_ioctl(fd, TCSBRK, 0);
|
||||
} else {
|
||||
static int sys_tcsendbreak_bsd(int fd) {
|
||||
if (sys_ioctl(fd, TIOCSBRK, 0) == -1) return -1;
|
||||
usleep(400000);
|
||||
if (sys_ioctl(fd, TIOCCBRK, 0) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static textwindows int sys_tcsendbreak_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!TransmitCommChar(g_fds.p[fd].handle, '\0')) return __winerr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends break.
|
||||
*
|
||||
* @param fd is file descriptor of tty
|
||||
* @param duration of 0 sends a break for 0.25-0.5 seconds, and other
|
||||
* durations are treated the same by this implementation
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcsendbreak(int fd, int duration) {
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (IsBsd()) {
|
||||
rc = sys_tcsendbreak_bsd(fd);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, 0);
|
||||
} else {
|
||||
rc = sys_tcsendbreak_nt(fd);
|
||||
}
|
||||
STRACE("tcsendbreak(%d, %u) → %d% m", fd, duration, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,14 +17,33 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Puts process group in control of terminal.
|
||||
* Sets foreground process group id.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `pgrp` is invalid
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EPERM if `pgrp` didn't match process in our group
|
||||
* @raise ENOTTY if `fd` is isn't controlling teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcsetpgrp(int fd, int32_t pgrp) {
|
||||
int pgrp_int = pgrp;
|
||||
return ioctl(fd, TIOCSPGRP, &pgrp_int);
|
||||
int tcsetpgrp(int fd, int pgrp) {
|
||||
int rc;
|
||||
if (IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = sys_ioctl(fd, TIOCSPGRP, &pgrp);
|
||||
}
|
||||
STRACE("tcsetpgrp(%d, %d) → %d% m", fd, pgrp, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -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,18 +16,26 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
|
||||
int cfsetispeed(struct termios *t, unsigned speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (speed & ~CBAUD) return einval();
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
struct Env _getenv(char **p, const char *k) {
|
||||
char *t;
|
||||
int i, j;
|
||||
for (i = 0; (t = p[i]); ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!k[j] || k[j] == '=') {
|
||||
if (!t[j]) return (struct Env){t + j, i};
|
||||
if (t[j] == '=') return (struct Env){t + j + 1, i};
|
||||
break;
|
||||
}
|
||||
if (ToUpper(k[j] & 255) != ToUpper(t[j] & 255)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return (struct Env){0, i};
|
||||
}
|
15
libc/intrin/_getenv.internal.h
Normal file
15
libc/intrin/_getenv.internal.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Env {
|
||||
char *s;
|
||||
int i;
|
||||
};
|
||||
|
||||
struct Env _getenv(char **, const char *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_ */
|
|
@ -17,10 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/intrin.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
static _Thread_local bool noreentry;
|
||||
|
||||
/**
|
||||
* Shows backtrace if crash reporting facilities are linked.
|
||||
|
@ -28,12 +30,20 @@
|
|||
void _bt(const char *fmt, ...) {
|
||||
int e;
|
||||
va_list va;
|
||||
|
||||
if (!noreentry) {
|
||||
noreentry = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt) {
|
||||
va_start(va, fmt);
|
||||
kvprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
if (_weaken(ShowBacktrace)) {
|
||||
|
||||
if (_weaken(ShowBacktrace) && _weaken(GetSymbolTable)) {
|
||||
e = errno;
|
||||
_weaken(ShowBacktrace)(2, __builtin_frame_address(0));
|
||||
errno = e;
|
||||
|
@ -41,5 +51,18 @@ void _bt(const char *fmt, ...) {
|
|||
kprintf("_bt() can't show backtrace because you need:\n"
|
||||
"\tSTATIC_YOINK(\"ShowBacktrace\");\n"
|
||||
"to be linked.\n");
|
||||
if (_weaken(PrintBacktraceUsingSymbols) && _weaken(GetSymbolTable)) {
|
||||
e = errno;
|
||||
_weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
|
||||
_weaken(GetSymbolTable)());
|
||||
errno = e;
|
||||
} else {
|
||||
kprintf("_bt() can't show backtrace because you need:\n"
|
||||
"\tSTATIC_YOINK(\"PrintBacktraceUsingSymbols\");\n"
|
||||
"\tSTATIC_YOINK(\"GetSymbolTable\");\n"
|
||||
"to be linked.\n");
|
||||
}
|
||||
}
|
||||
|
||||
noreentry = false;
|
||||
}
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
|
||||
/**
|
||||
* Removes all environment variables.
|
||||
*
|
||||
* @return 0 on success, or nonzero on error
|
||||
*/
|
||||
int clearenv(void) {
|
||||
environ = 0;
|
||||
STRACE("clearenv() → 0");
|
||||
environ = NULL;
|
||||
return 0;
|
||||
}
|
|
@ -56,7 +56,7 @@ const char *(DescribeFlock)(char buf[N], int cmd, const struct flock *l) {
|
|||
append(", .l_pid=%d", l->l_pid);
|
||||
}
|
||||
|
||||
if (l->l_sysid) {
|
||||
if (IsFreebsd() && l->l_sysid) {
|
||||
append(", .l_sysid=%d", l->l_sysid);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,23 +16,68 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.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/mem/alloca.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
||||
const char *(DescribeSigaction)(char buf[256], int rc,
|
||||
static const char *DescribeSigHandler(char buf[64], void f(int)) {
|
||||
if (f == SIG_ERR) return "SIG_ERR";
|
||||
if (f == SIG_DFL) return "SIG_DFL";
|
||||
if (f == SIG_IGN) return "SIG_IGN";
|
||||
ksnprintf(buf, 64, "%t", f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *DescribeSigFlags(char buf[64], int x) {
|
||||
const struct DescribeFlags kSigFlags[] = {
|
||||
{SA_NOCLDSTOP, "NOCLDSTOP"}, //
|
||||
{SA_NOCLDWAIT, "NOCLDWAIT"}, //
|
||||
{SA_SIGINFO, "SIGINFO"}, //
|
||||
{SA_ONSTACK, "ONSTACK"}, //
|
||||
{SA_RESTART, "RESTART"}, //
|
||||
{SA_NODEFER, "NODEFER"}, //
|
||||
{SA_RESETHAND, "RESETHAND"}, //
|
||||
{SA_NOMASK, "NOMASK"}, //
|
||||
{SA_ONESHOT, "ONESHOT"}, //
|
||||
};
|
||||
return DescribeFlags(buf, 64, kSigFlags, ARRAYLEN(kSigFlags), "SA_", x);
|
||||
}
|
||||
|
||||
#define N 256
|
||||
|
||||
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
|
||||
|
||||
const char *(DescribeSigaction)(char buf[N], int rc,
|
||||
const struct sigaction *sa) {
|
||||
int o = 0;
|
||||
char b64[64];
|
||||
|
||||
if (rc == -1) return "n/a";
|
||||
if (!sa) return "NULL";
|
||||
if ((!IsAsan() && kisdangerous(sa)) ||
|
||||
(IsAsan() && !__asan_is_valid(sa, sizeof(*sa)))) {
|
||||
ksnprintf(buf, 256, "%p", sa);
|
||||
} else {
|
||||
ksnprintf(buf, 256, "{.sa_handler=%t, .sa_flags=%#lx, .sa_mask=%s}",
|
||||
sa->sa_handler, sa->sa_flags, DescribeSigset(rc, &sa->sa_mask));
|
||||
}
|
||||
ksnprintf(buf, N, "%p", sa);
|
||||
return buf;
|
||||
}
|
||||
|
||||
append("{.sa_handler=%s", DescribeSigHandler(b64, sa->sa_handler));
|
||||
|
||||
if (sa->sa_flags) {
|
||||
append(", .sa_flags=%s", DescribeSigFlags(b64, sa->sa_flags));
|
||||
}
|
||||
|
||||
if (!sigisemptyset(&sa->sa_mask)) {
|
||||
append(", .sa_mask=%s", DescribeSigset(rc, &sa->sa_mask));
|
||||
}
|
||||
|
||||
append("}");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
#define N 128
|
||||
|
@ -31,6 +32,7 @@
|
|||
|
||||
const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
||||
bool gotsome;
|
||||
const char *s;
|
||||
int sig, o = 0;
|
||||
sigset_t sigset;
|
||||
|
||||
|
@ -45,9 +47,9 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
if (sigcountset(ss) > 16) {
|
||||
append("~");
|
||||
sigemptyset(&sigset);
|
||||
for (sig = 1; sig <= NSIG; ++sig) {
|
||||
for (sig = 1; sig <= _NSIG; ++sig) {
|
||||
if (!sigismember(ss, sig)) {
|
||||
sigaddset(&sigset, sig);
|
||||
sigset.__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -56,14 +58,18 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
|
||||
append("{");
|
||||
gotsome = false;
|
||||
for (sig = 1; sig <= NSIG; ++sig) {
|
||||
for (sig = 1; sig <= _NSIG; ++sig) {
|
||||
if (sigismember(&sigset, sig) > 0) {
|
||||
if (gotsome) {
|
||||
append(",");
|
||||
} else {
|
||||
gotsome = true;
|
||||
}
|
||||
append("%s", strsignal(sig) + 3);
|
||||
s = strsignal(sig);
|
||||
if (s[0] == 'S' && s[1] == 'I' && s[2] == 'G') {
|
||||
s += 3;
|
||||
}
|
||||
append("%s", s);
|
||||
}
|
||||
}
|
||||
append("}");
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -29,17 +30,26 @@
|
|||
|
||||
#define G FRAMESIZE
|
||||
|
||||
static void _mapframe(void *p, int f) {
|
||||
int prot, flags;
|
||||
static void *_mapframe(void *p, int f) {
|
||||
int rc, prot, flags;
|
||||
struct DirectMap dm;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
flags = f | MAP_ANONYMOUS | MAP_FIXED;
|
||||
_npassert((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p);
|
||||
if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p) {
|
||||
__mmi_lock();
|
||||
_npassert(!TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
|
||||
dm.maphandle, prot, flags, false, false, 0,
|
||||
G));
|
||||
rc = TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
|
||||
dm.maphandle, prot, flags, false, false, 0, G);
|
||||
__mmi_unlock();
|
||||
if (!rc) {
|
||||
return p;
|
||||
} else {
|
||||
_unassert(errno == ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
_unassert(errno == ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +68,8 @@ static void _mapframe(void *p, int f) {
|
|||
* @param e points to end of memory that's allocated
|
||||
* @param h is highest address to which `e` may grow
|
||||
* @param f should be `MAP_PRIVATE` or `MAP_SHARED`
|
||||
* @return new value for `e`
|
||||
* @return new value for `e` or null w/ errno
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
*/
|
||||
noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
||||
char *q;
|
||||
|
@ -67,10 +78,10 @@ noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
|||
for (q = e; q < ((char *)p + n); q += 8) {
|
||||
if (!((uintptr_t)q & (G - 1))) {
|
||||
_unassert(q + G <= (char *)h);
|
||||
_mapframe(q, f);
|
||||
if (!_mapframe(q, f)) return 0;
|
||||
if (IsAsan()) {
|
||||
if (!((uintptr_t)SHADOW(q) & (G - 1))) {
|
||||
_mapframe(SHADOW(q), f);
|
||||
if (!_mapframe(SHADOW(q), f)) return 0;
|
||||
__asan_poison(q, G << kAsanScale, kAsanProtected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 2022 Gavin Arthur Hayes │
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,18 +16,28 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(putenv, test) {
|
||||
EXPECT_EQ(0, clearenv());
|
||||
EXPECT_EQ(0, putenv("hi=there"));
|
||||
EXPECT_STREQ("there", getenv("hi"));
|
||||
EXPECT_EQ(0, clearenv());
|
||||
EXPECT_EQ(0, putenv("hi=theretwo"));
|
||||
EXPECT_STREQ("theretwo", getenv("hi"));
|
||||
EXPECT_EQ(0, clearenv());
|
||||
EXPECT_EQ(0, setenv("hi", "therethree", 0));
|
||||
EXPECT_STREQ("therethree", getenv("hi"));
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
*
|
||||
* Environment variables can store empty string on Unix but not Windows.
|
||||
*
|
||||
* @return pointer to value of `environ` entry, or null if not found
|
||||
*/
|
||||
char *getenv(const char *s) {
|
||||
char **p;
|
||||
struct Env e;
|
||||
if (!s) return 0;
|
||||
if (!(p = environ)) return 0;
|
||||
e = _getenv(p, s);
|
||||
#if SYSDEBUG
|
||||
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
|
||||
// TODO(jart): memoize TZ or something
|
||||
STRACE("getenv(%#s) → %#s", s, e.s);
|
||||
}
|
||||
#endif
|
||||
return e.s;
|
||||
}
|
|
@ -7,6 +7,7 @@ LIBC_INTRIN_ARTIFACTS += LIBC_INTRIN_A
|
|||
LIBC_INTRIN = $(LIBC_INTRIN_A_DEPS) $(LIBC_INTRIN_A)
|
||||
LIBC_INTRIN_A = o/$(MODE)/libc/intrin/intrin.a
|
||||
LIBC_INTRIN_A_HDRS = $(filter %.h,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_INCS = $(filter %.inc,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS_S = $(filter %.S,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS_C = $(filter %.c,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS = $(LIBC_INTRIN_A_SRCS_S) $(LIBC_INTRIN_A_SRCS_C)
|
||||
|
@ -121,7 +122,6 @@ o/$(MODE)/libc/intrin/describeprotflags.o: private \
|
|||
-fno-sanitize=address
|
||||
|
||||
o/$(MODE)/libc/intrin/exit1.greg.o \
|
||||
o/$(MODE)/libc/intrin/getenv.greg.o \
|
||||
o/$(MODE)/libc/intrin/wsarecv.o \
|
||||
o/$(MODE)/libc/intrin/wsarecvfrom.o \
|
||||
o/$(MODE)/libc/intrin/createfile.o \
|
||||
|
@ -182,6 +182,7 @@ o/$(MODE)/libc/intrin/memmove.o: private \
|
|||
|
||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_INTRIN_INCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_INCS))
|
||||
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_INTRIN_CHECKS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_INTRIN_OBJS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_OBJS))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#define KMALLOC_ALIGN __BIGGEST_ALIGNMENT__
|
||||
#define KMALLOC_ALIGN sizeof(intptr_t)
|
||||
|
||||
static struct {
|
||||
char *endptr;
|
||||
|
@ -55,21 +55,37 @@ __attribute__((__constructor__)) static void kmalloc_init(void) {
|
|||
* The code malloc() depends upon uses this function to allocate memory.
|
||||
* The returned memory can't be freed, and leak detection is impossible.
|
||||
* This function panics when memory isn't available.
|
||||
*
|
||||
* Memory returned by this function is aligned on the word size, and as
|
||||
* such, kmalloc() shouldn't be used for vector operations.
|
||||
*
|
||||
* @return zero-initialized memory on success, or null w/ errno
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
*/
|
||||
void *kmalloc(size_t size) {
|
||||
char *start;
|
||||
size_t i, n;
|
||||
char *p, *e;
|
||||
size_t i, n, t;
|
||||
n = ROUNDUP(size + (IsAsan() * 8), KMALLOC_ALIGN);
|
||||
kmalloc_lock();
|
||||
i = g_kmalloc.total;
|
||||
g_kmalloc.total += n;
|
||||
start = (char *)kMemtrackKmallocStart;
|
||||
if (!g_kmalloc.endptr) g_kmalloc.endptr = start;
|
||||
g_kmalloc.endptr =
|
||||
_extend(start, g_kmalloc.total, g_kmalloc.endptr, MAP_PRIVATE,
|
||||
kMemtrackKmallocStart + kMemtrackKmallocSize);
|
||||
kmalloc_unlock();
|
||||
_unassert(!((intptr_t)(start + i) & (KMALLOC_ALIGN - 1)));
|
||||
if (IsAsan()) __asan_poison(start + i + size, n - size, kAsanHeapOverrun);
|
||||
return start + i;
|
||||
t = g_kmalloc.total;
|
||||
e = g_kmalloc.endptr;
|
||||
i = t;
|
||||
t += n;
|
||||
p = (char *)kMemtrackKmallocStart;
|
||||
if (!e) e = p;
|
||||
if ((e = _extend(p, t, e, MAP_PRIVATE,
|
||||
kMemtrackKmallocStart + kMemtrackKmallocSize))) {
|
||||
g_kmalloc.endptr = e;
|
||||
g_kmalloc.total = t;
|
||||
} else {
|
||||
p = 0;
|
||||
}
|
||||
kmalloc_unlock();
|
||||
if (p) {
|
||||
_unassert(!((intptr_t)(p + i) & (KMALLOC_ALIGN - 1)));
|
||||
if (IsAsan()) __asan_poison(p + i + size, n - size, kAsanHeapOverrun);
|
||||
return p + i;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void *kmalloc(size_t) attributeallocsize((1)) mallocesque returnsnonnull;
|
||||
void *kmalloc(size_t) mallocesque attributeallocsize((1)) returnsaligned((8));
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -16,19 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
static bool once;
|
||||
static char **expected;
|
||||
static size_t capacity;
|
||||
|
||||
static size_t GetEnvironLen(char **env) {
|
||||
|
@ -37,98 +34,69 @@ static size_t GetEnvironLen(char **env) {
|
|||
return p - env;
|
||||
}
|
||||
|
||||
static void RestoreOriginalEnvironment(char **envp) {
|
||||
environ = envp;
|
||||
}
|
||||
|
||||
static void PutEnvImplAtExit(void *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void FreeEnviron(char **env) {
|
||||
char **a;
|
||||
for (a = env; *a; ++a) {
|
||||
free(*a);
|
||||
}
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void GrowEnviron(void) {
|
||||
static char **GrowEnviron(char **a) {
|
||||
size_t n, c;
|
||||
char **a, **b, **p;
|
||||
a = environ;
|
||||
char **b, **p;
|
||||
if (!a) a = environ;
|
||||
n = a ? GetEnvironLen(a) : 0;
|
||||
c = MAX(16ul, n) << 1;
|
||||
b = calloc(c, sizeof(char *));
|
||||
if ((b = kmalloc(c * sizeof(char *)))) {
|
||||
if (a) {
|
||||
for (p = b; *a;) {
|
||||
*p++ = strdup(*a++);
|
||||
*p++ = *a++;
|
||||
}
|
||||
}
|
||||
__cxa_atexit(FreeEnviron, b, 0);
|
||||
environ = b;
|
||||
expected = b;
|
||||
capacity = c;
|
||||
return b;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int PutEnvImpl(char *s, bool overwrite) {
|
||||
char *p;
|
||||
unsigned i, namelen;
|
||||
if (!once) {
|
||||
__cxa_atexit(RestoreOriginalEnvironment, environ, 0);
|
||||
GrowEnviron();
|
||||
once = true;
|
||||
} else if (!environ) {
|
||||
GrowEnviron();
|
||||
}
|
||||
for (p = s; *p && *p != '='; ++p) {
|
||||
if (IsWindows()) {
|
||||
*p = ToUpper(*p);
|
||||
char **p;
|
||||
struct Env e;
|
||||
if (!(p = environ)) {
|
||||
if (!(p = GrowEnviron(0))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (*p != '=') goto Fail;
|
||||
namelen = p + 1 - s;
|
||||
for (i = 0; environ[i]; ++i) {
|
||||
if (!strncmp(environ[i], s, namelen)) {
|
||||
if (!overwrite) {
|
||||
free(s);
|
||||
e = _getenv(p, s);
|
||||
if (e.s && !overwrite) {
|
||||
return 0;
|
||||
}
|
||||
goto Replace;
|
||||
}
|
||||
}
|
||||
if (i + 1 >= capacity) {
|
||||
GrowEnviron();
|
||||
}
|
||||
environ[i + 1] = 0;
|
||||
Replace:
|
||||
__cxa_atexit(PutEnvImplAtExit, environ[i], 0);
|
||||
environ[i] = s;
|
||||
if (e.s) {
|
||||
p[e.i] = s;
|
||||
return 0;
|
||||
Fail:
|
||||
free(s);
|
||||
return einval();
|
||||
}
|
||||
|
||||
static void UnsetenvFree(void *p) {
|
||||
free(p);
|
||||
if (p != expected) {
|
||||
capacity = e.i;
|
||||
}
|
||||
|
||||
/* weakly called by unsetenv() when removing a pointer */
|
||||
void __freeenv(void *p) {
|
||||
if (once) {
|
||||
__cxa_atexit(UnsetenvFree, p, 0);
|
||||
if (e.i + 1 >= capacity) {
|
||||
if (!(p = GrowEnviron(p))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p[e.i + 1] = 0;
|
||||
p[e.i] = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emplaces environment key=value.
|
||||
*
|
||||
* @return 0 on success or non-zero on error
|
||||
* @param s should be a string that looks like `"name=value"` and it'll
|
||||
* become part of the environment; changes to its memory will change
|
||||
* the environment too
|
||||
* @return 0 on success, or non-zero w/ errno on error
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @see setenv(), getenv()
|
||||
*/
|
||||
int putenv(char *s) {
|
||||
int rc;
|
||||
rc = PutEnvImpl(strdup(s), true);
|
||||
STRACE("putenv(%#s) → %d", s, rc);
|
||||
rc = PutEnvImpl(s, true);
|
||||
STRACE("putenv(%#s) → %d% m", s, rc);
|
||||
return rc;
|
||||
}
|
|
@ -16,10 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -27,7 +26,7 @@
|
|||
/**
|
||||
* Copies variable to environment.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||
* @raise EINVAL if `name` is empty or contains `'='`
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @see putenv(), getenv()
|
||||
|
@ -35,12 +34,16 @@
|
|||
int setenv(const char *name, const char *value, int overwrite) {
|
||||
int rc;
|
||||
char *s;
|
||||
size_t namelen, valuelen;
|
||||
if (isempty(name) || strchr(name, '=')) return einval();
|
||||
namelen = strlen(name);
|
||||
valuelen = strlen(value);
|
||||
if (!(s = malloc(namelen + valuelen + 2))) return -1;
|
||||
memcpy(mempcpy(mempcpy(s, name, namelen), "=", 1), value, valuelen + 1);
|
||||
size_t n, m;
|
||||
const char *t;
|
||||
if (!name || !*name || !value) return einval();
|
||||
for (t = name; *t; ++t) {
|
||||
if (*t == '=') return einval();
|
||||
}
|
||||
n = strlen(name);
|
||||
m = strlen(value);
|
||||
if (!(s = kmalloc(n + 1 + m + 1))) return -1;
|
||||
memcpy(mempcpy(mempcpy(s, name, n), "=", 1), value, m + 1);
|
||||
rc = PutEnvImpl(s, overwrite);
|
||||
STRACE("setenv(%#s, %#s, %d) → %d% m", name, value, overwrite, rc);
|
||||
return rc;
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -28,11 +29,17 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigaddset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (!sigisprecious(sig)) {
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
if (
|
||||
#define M(x) sig != x &&
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
1) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
|
||||
/**
|
||||
* Returns population count of signal set.
|
||||
|
@ -27,9 +28,22 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigcountset(const sigset_t *set) {
|
||||
int r, i;
|
||||
for (r = i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
r += popcnt(set->__bits[i]);
|
||||
int r, i, x, y;
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
x = (uint32_t)set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 64:
|
||||
x = set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 128:
|
||||
x = set->__bits[0];
|
||||
y = set->__bits[1];
|
||||
break;
|
||||
default:
|
||||
notpossible;
|
||||
}
|
||||
return r;
|
||||
return popcnt(x) + popcnt(y);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigdelset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] &= ~(1ull << ((sig - 1) & 63));
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
|
@ -29,7 +30,17 @@
|
|||
*/
|
||||
int sigfillset(sigset_t *set) {
|
||||
memset(set->__bits, -1, sizeof(set->__bits));
|
||||
sigdelset(set, SIGKILL);
|
||||
sigdelset(set, SIGSTOP);
|
||||
#define M(x) set->__bits[(x - 1) >> 6] &= ~(1ull << ((x - 1) & 63));
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
set->__bits[0] &= 0xffffffff;
|
||||
break;
|
||||
case 64:
|
||||
set->__bits[1] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -30,7 +31,11 @@
|
|||
int sigismember(const sigset_t *set, int sig) {
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
* Returns true if you're not authorized to block this signal.
|
||||
*/
|
||||
int sigisprecious(int sig) {
|
||||
return sig == SIGKILL || //
|
||||
sig == SIGSTOP;
|
||||
return 0
|
||||
#define M(x) || sig == x
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
;
|
||||
}
|
||||
|
|
3
libc/intrin/sigisprecious.inc
Normal file
3
libc/intrin/sigisprecious.inc
Normal file
|
@ -0,0 +1,3 @@
|
|||
M(SIGKILL)
|
||||
M(SIGABRT)
|
||||
M(SIGSTOP)
|
|
@ -33,6 +33,7 @@
|
|||
* @param buf may be used to store output having at least 15 bytes
|
||||
* @return pointer to .rodata string, or to `buf` after mutating
|
||||
* @see sigaction()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
char *strsignal_r(int sig, char buf[hasatleast 15]) {
|
||||
|
|
|
@ -17,39 +17,29 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Removes environment variable.
|
||||
*
|
||||
* @param s is non-empty environment key which can't contain `'='`
|
||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||
* @raise EINVAL if `s` is an empty string or has a `'='` character
|
||||
*/
|
||||
int unsetenv(const char *s) {
|
||||
char **p;
|
||||
size_t i, j, k;
|
||||
if (s && (p = environ)) {
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!s[j]) {
|
||||
if (p[i][j] == '=') {
|
||||
if (_weaken(__freeenv)) {
|
||||
_weaken(__freeenv)(p[i]);
|
||||
}
|
||||
k = i + 1;
|
||||
do {
|
||||
p[k - 1] = p[k];
|
||||
} while (p[k++]);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
|
||||
break;
|
||||
}
|
||||
char **p, *t;
|
||||
struct Env e;
|
||||
if (!s || !*s) return einval();
|
||||
for (t = s; *t; ++t) {
|
||||
if (*t == '=') return einval();
|
||||
}
|
||||
if ((p = environ)) {
|
||||
e = _getenv(p, s);
|
||||
while (p[e.i]) {
|
||||
p[e.i] = p[e.i + 1];
|
||||
++e.i;
|
||||
}
|
||||
}
|
||||
return 0;
|
|
@ -125,7 +125,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
if (sys_pipe2(pipefds, O_CLOEXEC) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if ((pid = fork()) == -1) {
|
||||
if ((pid = __sys_fork().ax) == -1) {
|
||||
sys_close(pipefds[0]);
|
||||
sys_close(pipefds[1]);
|
||||
return -1;
|
||||
|
@ -149,19 +149,12 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
}
|
||||
p1 = buf;
|
||||
p3 = p1 + got;
|
||||
/*
|
||||
* remove racist output from gnu tooling, that can't be disabled
|
||||
* otherwise, since it breaks other tools like emacs that aren't
|
||||
* equipped to ignore it, and what's most problematic is that
|
||||
* addr2line somehow manages to put the racism onto the one line
|
||||
* in the backtrace we actually care about.
|
||||
*/
|
||||
for (got = p3 - buf, p1 = buf; got;) {
|
||||
if ((p2 = memmem(p1, got, " (discriminator ",
|
||||
strlen(" (discriminator ") - 1)) &&
|
||||
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
|
||||
if (p3 > p2 && p3[-1] == '\r') --p3;
|
||||
write(2, p1, p2 - p1);
|
||||
sys_write(2, p1, p2 - p1);
|
||||
got -= p3 - p1;
|
||||
p1 += p3 - p1;
|
||||
} else {
|
||||
|
@ -183,11 +176,13 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
}
|
||||
|
||||
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||
#if !defined(DWARFLESS)
|
||||
if (!IsTiny() && !__isworker) {
|
||||
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
|||
} else {
|
||||
addend = 0;
|
||||
}
|
||||
kprintf("%012lx %012lx %s%+d\n", frame, addr, __get_symbol_name(st, symbol),
|
||||
kprintf("%012lx %lx %s%+d\n", frame, addr, __get_symbol_name(st, symbol),
|
||||
addend);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -42,6 +42,7 @@ LIBC_LOG_A_DIRECTDEPS = \
|
|||
LIBC_SYSV_CALLS \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/ss.h"
|
||||
|
||||
STATIC_YOINK("zipos"); // for symtab
|
||||
STATIC_YOINK("__die"); // for backtracing
|
||||
STATIC_YOINK("ShowBacktrace"); // for backtracing
|
||||
STATIC_YOINK("GetSymbolTable"); // for backtracing
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -27,6 +26,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
|
@ -131,7 +131,9 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
__start_fatal(file, line);
|
||||
strcpy(buf32, "unknown");
|
||||
gethostname(buf32, sizeof(buf32));
|
||||
(dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid());
|
||||
(dprintf)(STDERR_FILENO,
|
||||
"exiting due to aforementioned error (host %s pid %d tid %d)\n",
|
||||
buf32, getpid(), gettid());
|
||||
__die();
|
||||
unreachable;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ struct CritbitNode {
|
|||
};
|
||||
|
||||
int PutEnvImpl(char *, bool) hidden;
|
||||
void __freeenv(void *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
93
libc/mem/sortedints.c
Normal file
93
libc/mem/sortedints.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/midpoint.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/sortedints.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
bool ContainsInt(const struct SortedInts *t, int k) {
|
||||
int l, m, r;
|
||||
l = 0;
|
||||
r = t->n - 1;
|
||||
while (l <= r) {
|
||||
m = _midpoint(l, r);
|
||||
if (t->p[m] < k) {
|
||||
l = m + 1;
|
||||
} else if (t->p[m] > k) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int LeftmostInt(const struct SortedInts *t, int k) {
|
||||
int l, m, r;
|
||||
l = 0;
|
||||
r = t->n;
|
||||
while (l < r) {
|
||||
m = _midpoint(l, r);
|
||||
if (t->p[m] < k) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m;
|
||||
}
|
||||
}
|
||||
_unassert(l == 0 || k >= t->p[l - 1]);
|
||||
_unassert(l == t->n || k <= t->p[l]);
|
||||
return l;
|
||||
}
|
||||
|
||||
int CountInt(const struct SortedInts *t, int k) {
|
||||
int i, c;
|
||||
for (c = 0, i = LeftmostInt(t, k); i < t->n; ++i) {
|
||||
if (t->p[i] == k) {
|
||||
++c;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
bool InsertInt(struct SortedInts *t, int k, bool u) {
|
||||
int l;
|
||||
_unassert(t->n >= 0);
|
||||
_unassert(t->n <= t->c);
|
||||
if (t->n == t->c) {
|
||||
++t->c;
|
||||
if (!IsModeDbg()) {
|
||||
t->c += t->c >> 1;
|
||||
}
|
||||
t->p = realloc(t->p, t->c * sizeof(*t->p));
|
||||
}
|
||||
l = LeftmostInt(t, k);
|
||||
if (l < t->n) {
|
||||
if (u && t->p[l] == k) {
|
||||
return false;
|
||||
}
|
||||
memmove(t->p + l + 1, t->p + l, (t->n - l) * sizeof(*t->p));
|
||||
}
|
||||
t->p[l] = k;
|
||||
t->n++;
|
||||
return true;
|
||||
}
|
19
libc/mem/sortedints.internal.h
Normal file
19
libc/mem/sortedints.internal.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_MEM_SORTEDINTS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_MEM_SORTEDINTS_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct SortedInts {
|
||||
int n;
|
||||
int c;
|
||||
int *p;
|
||||
};
|
||||
|
||||
bool ContainsInt(const struct SortedInts *, int);
|
||||
bool InsertInt(struct SortedInts *, int, bool);
|
||||
int CountInt(const struct SortedInts *, int);
|
||||
int LeftmostInt(const struct SortedInts *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_MEM_SORTEDINTS_INTERNAL_H_ */
|
|
@ -23,9 +23,8 @@
|
|||
// @param rdi points to the jmp_buf
|
||||
// @param esi is returned by setjmp() invocation (coerced nonzero)
|
||||
// @noreturn
|
||||
// @assume system five nexgen32e abi conformant
|
||||
// @note code built w/ microsoft abi compiler can't call this
|
||||
// @see _gclongjmp() unwinds _gc() destructors
|
||||
// @see _gclongjmp()
|
||||
// @see siglongjmp()
|
||||
longjmp:
|
||||
mov %esi,%eax
|
||||
test %eax,%eax
|
||||
|
@ -41,4 +40,3 @@ longjmp:
|
|||
jmp *56(%rdi)
|
||||
.endfn longjmp,globl
|
||||
.alias longjmp,_longjmp
|
||||
.alias longjmp,siglongjmp
|
||||
|
|
|
@ -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│
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 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,13 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
// Loads previously saved processor state.
|
||||
//
|
||||
// @param rdi points to the jmp_buf
|
||||
// @param esi is returned by setjmp() invocation (coerced nonzero)
|
||||
// @noreturn
|
||||
// @asyncsignalsafe
|
||||
siglongjmp:
|
||||
jmp longjmp
|
||||
.endfn siglongjmp,globl
|
36
libc/nt/comms.h
Normal file
36
libc/nt/comms.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NT_COMMS_H_
|
||||
#define COSMOPOLITAN_LIBC_NT_COMMS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
/* ░░░░
|
||||
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓░
|
||||
▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▒ ▒▒▒▓▓█
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||||
░▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓ █▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓░ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓ ▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒
|
||||
▒▒▒▒▓▓ ▓▒▒▓▓▓▓ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||||
▒▓ ▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓
|
||||
░░░░░░░░░░░▒▒▒▒ ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
|
||||
▒▒░░░░░░░░░░▒▒▒▒▒▓▓▓ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
|
||||
░▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓░ ░▓███▓
|
||||
▒▒░░░░░░░░░░▒▒▒▒▒▓▓░ ▒▓▓▓▒▒▒ ░▒▒▒▓ ████████████
|
||||
▒▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▒▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒░ ░███
|
||||
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ███
|
||||
▒▒░░░░░░░░░░▒▒▒▒▒▒▓▓ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ▓██
|
||||
▒░░░░░░░░░░░▒▒▒▒▒▓▓ ▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒▓ ▓██
|
||||
▒▒░░░▒▒▒░░░▒▒░▒▒▒▓▓▒ ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒ ███
|
||||
░▒▓ ░▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓ ▓██
|
||||
╔────────────────────────────────────────────────────────────────▀▀▀─────────│─╗
|
||||
│ cosmopolitan § new technology » communications ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
bool32 PurgeComm(int64_t hFile, uint32_t dwFlags);
|
||||
bool32 TransmitCommChar(int64_t hFile, char cChar);
|
||||
bool32 ClearCommBreak(int64_t hFile);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NT_COMMS_H_ */
|
|
@ -1,2 +1,15 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_ClearCommBreak,ClearCommBreak,0
|
||||
|
||||
.text.windows
|
||||
ClearCommBreak:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov %rdi,%rcx
|
||||
sub $32,%rsp
|
||||
call *__imp_ClearCommBreak(%rip)
|
||||
leave
|
||||
ret
|
||||
.endfn ClearCommBreak,globl
|
||||
.previous
|
||||
|
|
|
@ -1,2 +1,12 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_PurgeComm,PurgeComm,0
|
||||
|
||||
.text.windows
|
||||
PurgeComm:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov __imp_PurgeComm(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
.endfn PurgeComm,globl
|
||||
.previous
|
||||
|
|
|
@ -1,2 +1,12 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_TransmitCommChar,TransmitCommChar,0
|
||||
|
||||
.text.windows
|
||||
TransmitCommChar:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov __imp_TransmitCommChar(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
.endfn TransmitCommChar,globl
|
||||
.previous
|
||||
|
|
|
@ -112,7 +112,7 @@ imp 'CheckNameLegalDOS8Dot3' CheckNameLegalDOS8Dot3W kernel32 128
|
|||
imp 'CheckRemoteDebuggerPresent' CheckRemoteDebuggerPresent kernel32 0 2
|
||||
imp 'CheckTokenCapability' CheckTokenCapability kernel32 0
|
||||
imp 'CheckTokenMembershipEx' CheckTokenMembershipEx kernel32 0
|
||||
imp 'ClearCommBreak' ClearCommBreak kernel32 0
|
||||
imp 'ClearCommBreak' ClearCommBreak kernel32 0 1
|
||||
imp 'ClearCommError' ClearCommError kernel32 0
|
||||
imp 'CloseConsoleHandle' CloseConsoleHandle kernel32 134
|
||||
imp 'ClosePackageInfo' ClosePackageInfo kernel32 0
|
||||
|
@ -764,7 +764,7 @@ imp 'PssWalkMarkerSetPosition' PssWalkMarkerSetPosition kernel32 0
|
|||
imp 'PssWalkMarkerTell' PssWalkMarkerTell kernel32 1080
|
||||
imp 'PssWalkSnapshot' PssWalkSnapshot kernel32 0
|
||||
imp 'PulseEvent' PulseEvent kernel32 0 1
|
||||
imp 'PurgeComm' PurgeComm kernel32 0
|
||||
imp 'PurgeComm' PurgeComm kernel32 0 2
|
||||
imp 'QueryActCtx' QueryActCtxW kernel32 0
|
||||
imp 'QueryActCtxSettings' QueryActCtxSettingsW kernel32 0
|
||||
imp 'QueryActCtxSettingsWWorker' QueryActCtxSettingsWWorker kernel32 1085
|
||||
|
@ -1011,7 +1011,7 @@ imp 'TlsGetValue' TlsGetValue kernel32 0 1
|
|||
imp 'TlsSetValue' TlsSetValue kernel32 0 2
|
||||
imp 'Toolhelp32ReadProcessMemory' Toolhelp32ReadProcessMemory kernel32 1449
|
||||
imp 'TransactNamedPipe' TransactNamedPipe kernel32 0 7
|
||||
imp 'TransmitCommChar' TransmitCommChar kernel32 0
|
||||
imp 'TransmitCommChar' TransmitCommChar kernel32 0 2
|
||||
imp 'TryAcquireSRWLockExclusive' TryAcquireSRWLockExclusive kernel32 0 1
|
||||
imp 'TryAcquireSRWLockShared' TryAcquireSRWLockShared kernel32 0 1
|
||||
imp 'TryEnterCriticalSection' TryEnterCriticalSection kernel32 0 1
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -55,11 +56,6 @@
|
|||
#define TOMBSTONE ((char *)-1)
|
||||
#define READ24(s) READ32LE(s "\0")
|
||||
|
||||
struct Env {
|
||||
char *s;
|
||||
int i;
|
||||
};
|
||||
|
||||
static char *p;
|
||||
static char *q;
|
||||
static char *r;
|
||||
|
@ -71,7 +67,7 @@ static char *assign;
|
|||
static char var[32];
|
||||
static int lastchild;
|
||||
static int exitstatus;
|
||||
static char *envs[3000];
|
||||
static char *envs[500];
|
||||
static char *args[3000];
|
||||
static const char *prog;
|
||||
static char errbuf[512];
|
||||
|
@ -148,27 +144,9 @@ static int GetSignalByName(const char *s) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct Env GetEnv(char **p, const char *k) {
|
||||
int i, j;
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!k[j] || k[j] == '=') {
|
||||
if (p[i][j] == '=') {
|
||||
return (struct Env){p[i] + j + 1, i};
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (toupper(k[j] & 255) != toupper(p[i][j] & 255)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (struct Env){0, i};
|
||||
}
|
||||
|
||||
static void PutEnv(char **p, const char *kv) {
|
||||
struct Env e;
|
||||
e = GetEnv(p, kv);
|
||||
e = _getenv(p, kv);
|
||||
p[e.i] = kv;
|
||||
if (!e.s) p[e.i + 1] = 0;
|
||||
}
|
||||
|
@ -271,7 +249,7 @@ static int Read(void) {
|
|||
|
||||
static int Cd(void) {
|
||||
const char *s;
|
||||
if ((s = n > 1 ? args[1] : GetEnv(envs, "HOME").s)) {
|
||||
if ((s = n > 1 ? args[1] : _getenv(envs, "HOME").s)) {
|
||||
if (!chdir(s)) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -489,14 +467,27 @@ static const char *IntToStr(int x) {
|
|||
}
|
||||
|
||||
static const char *GetVar(const char *key) {
|
||||
static char vbuf[PATH_MAX];
|
||||
if (key[0] == '$' && !key[1]) {
|
||||
return IntToStr(getpid());
|
||||
} else if (key[0] == '!' && !key[1]) {
|
||||
return IntToStr(lastchild);
|
||||
} else if (key[0] == '?' && !key[1]) {
|
||||
return IntToStr(exitstatus);
|
||||
} else if (!strcmp(key, "PWD")) {
|
||||
_npassert(getcwd(vbuf, sizeof(vbuf)));
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "UID")) {
|
||||
FormatInt32(vbuf, getuid());
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "GID")) {
|
||||
FormatInt32(vbuf, getgid());
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "EUID")) {
|
||||
FormatInt32(vbuf, geteuid());
|
||||
return vbuf;
|
||||
} else {
|
||||
return GetEnv(envs, key).s;
|
||||
return _getenv(envs, key).s;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
|
@ -30,7 +32,8 @@ extern int __threadcalls_start[];
|
|||
#pragma weak __threadcalls_end
|
||||
|
||||
static privileged dontinline void FixupLockNops(void) {
|
||||
__morph_begin();
|
||||
sigset_t mask;
|
||||
__morph_begin(&mask);
|
||||
/*
|
||||
* _NOPL("__threadcalls", func)
|
||||
*
|
||||
|
@ -54,7 +57,7 @@ static privileged dontinline void FixupLockNops(void) {
|
|||
_base[*p + 1] = 0x67;
|
||||
_base[*p + 2] = 0xe8;
|
||||
}
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
}
|
||||
|
||||
void __enable_threads(void) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "libc/nexgen32e/msr.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdalign.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -196,9 +198,10 @@ privileged void __enable_tls(void) {
|
|||
if ((intptr_t)_tls_content && (IsWindows() || IsXnu())) {
|
||||
int n;
|
||||
uint64_t w;
|
||||
sigset_t mask;
|
||||
unsigned m, dis;
|
||||
unsigned char *p;
|
||||
__morph_begin();
|
||||
__morph_begin(&mask);
|
||||
|
||||
if (IsXnu()) {
|
||||
// Apple is quite straightforward to patch. We basically
|
||||
|
@ -262,7 +265,7 @@ privileged void __enable_tls(void) {
|
|||
}
|
||||
}
|
||||
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
}
|
||||
|
||||
// we are now allowed to use tls
|
||||
|
|
|
@ -224,9 +224,6 @@ textwindows void WinMainForked(void) {
|
|||
AbortFork("CloseHandle");
|
||||
}
|
||||
|
||||
// turn tls back on
|
||||
__enable_tls();
|
||||
|
||||
// rewrap the stdin named pipe hack
|
||||
// since the handles closed on fork
|
||||
struct Fds *fds = VEIL("r", &g_fds);
|
||||
|
@ -267,11 +264,14 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
uint32_t oldprot;
|
||||
char **args, **args2;
|
||||
char16_t pipename[64];
|
||||
bool needtls, threaded;
|
||||
int64_t reader, writer;
|
||||
struct NtStartupInfo startinfo;
|
||||
int i, n, pid, untrackpid, rc = -1;
|
||||
char *p, forkvar[6 + 21 + 1 + 21 + 1];
|
||||
struct NtProcessInformation procinfo;
|
||||
threaded = __threaded;
|
||||
needtls = __tls_enabled;
|
||||
if (!setjmp(jb)) {
|
||||
pid = untrackpid = __reservefd_unlocked(-1);
|
||||
reader = CreateNamedPipe(CreatePipeName(pipename),
|
||||
|
@ -345,9 +345,15 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
if (needtls) {
|
||||
__enable_tls();
|
||||
}
|
||||
if (threaded && !__threaded && _weaken(__enable_threads)) {
|
||||
_weaken(__enable_threads)();
|
||||
}
|
||||
}
|
||||
if (untrackpid != -1) {
|
||||
__releasefd_unlocked(untrackpid);
|
||||
__releasefd(untrackpid);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -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,13 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
int sys_fork(void) {
|
||||
axdx_t ad;
|
||||
int ax, dx;
|
||||
ad = __sys_fork();
|
||||
ax = ad.ax;
|
||||
dx = ad.dx;
|
||||
if (IsXnu() && ax != -1) {
|
||||
// eax always returned with childs pid
|
||||
// edx is 0 for parent and 1 for child
|
||||
ax &= dx - 1;
|
||||
}
|
||||
return ax;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
|
@ -33,30 +34,15 @@
|
|||
#include "libc/thread/tls.h"
|
||||
|
||||
int _fork(uint32_t dwCreationFlags) {
|
||||
axdx_t ad;
|
||||
bool threaded;
|
||||
sigset_t old, all;
|
||||
int ax, dx, parent;
|
||||
sigfillset(&all);
|
||||
_unassert(!sigprocmask(SIG_BLOCK, &all, &old));
|
||||
BLOCK_SIGNALS;
|
||||
if (__threaded && _weaken(_pthread_onfork_prepare)) {
|
||||
_weaken(_pthread_onfork_prepare)();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
ad = sys_fork();
|
||||
ax = ad.ax;
|
||||
dx = ad.dx;
|
||||
if (IsXnu() && ax != -1) {
|
||||
// eax always returned with childs pid
|
||||
// edx is 0 for parent and 1 for child
|
||||
ax &= dx - 1;
|
||||
}
|
||||
ax = sys_fork();
|
||||
} else {
|
||||
threaded = __threaded;
|
||||
ax = sys_fork_nt(dwCreationFlags);
|
||||
if (threaded && !__threaded && _weaken(__enable_threads)) {
|
||||
_weaken(__enable_threads)();
|
||||
}
|
||||
}
|
||||
if (!ax) {
|
||||
if (!IsWindows()) {
|
||||
|
@ -81,7 +67,7 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
}
|
||||
STRACE("fork() → %d% m", ax);
|
||||
}
|
||||
_unassert(!sigprocmask(SIG_SETMASK, &old, 0));
|
||||
ALLOW_SIGNALS;
|
||||
return ax;
|
||||
}
|
||||
|
||||
|
@ -92,6 +78,7 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
* @raise EAGAIN if `RLIMIT_NPROC` was exceeded or system lacked resources
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int fork(void) {
|
||||
return _fork(0);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
|
@ -45,13 +46,13 @@ privileged noinstrument noasan int __hook(void *ifunc,
|
|||
size_t i;
|
||||
char *p, *pe;
|
||||
intptr_t addr;
|
||||
sigset_t mask;
|
||||
uint64_t code, mcode;
|
||||
sigset_t mask, oldmask;
|
||||
intptr_t kMcount = (intptr_t)&mcount;
|
||||
intptr_t kProgramCodeStart = (intptr_t)_ereal;
|
||||
intptr_t kPrivilegedStart = (intptr_t)__privileged_addr;
|
||||
if (!symbols) return -1;
|
||||
__morph_begin();
|
||||
__morph_begin(&mask);
|
||||
for (i = 0; i < symbols->count; ++i) {
|
||||
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
|
||||
continue;
|
||||
|
@ -112,6 +113,6 @@ privileged noinstrument noasan int __hook(void *ifunc,
|
|||
}
|
||||
}
|
||||
}
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -135,39 +135,39 @@ forceinline pureconst bool IsFixedFrame(int x) {
|
|||
}
|
||||
|
||||
forceinline pureconst bool OverlapsImageSpace(const void *p, size_t n) {
|
||||
const unsigned char *start, *ender;
|
||||
const unsigned char *BegA, *EndA, *BegB, *EndB;
|
||||
if (n) {
|
||||
start = p;
|
||||
ender = start + (n - 1);
|
||||
return ((_base <= start && start < _end) ||
|
||||
(_base <= ender && ender < _end) ||
|
||||
(start < _base && _end <= ender));
|
||||
BegA = p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = _base;
|
||||
EndB = _end - 1;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline pureconst bool OverlapsArenaSpace(const void *p, size_t n) {
|
||||
intptr_t x, y;
|
||||
intptr_t BegA, EndA, BegB, EndB;
|
||||
if (n) {
|
||||
x = (intptr_t)p;
|
||||
y = x + (n - 1);
|
||||
return ((0x50000000 <= x && x <= 0x7ffdffff) ||
|
||||
(0x50000000 <= y && y <= 0x7ffdffff) ||
|
||||
(x < 0x50000000 && 0x7ffdffff < y));
|
||||
BegA = (intptr_t)p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = 0x50000000;
|
||||
EndB = 0x7ffdffff;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline pureconst bool OverlapsShadowSpace(const void *p, size_t n) {
|
||||
intptr_t x, y;
|
||||
intptr_t BegA, EndA, BegB, EndB;
|
||||
if (n) {
|
||||
x = (intptr_t)p;
|
||||
y = x + (n - 1);
|
||||
return ((0x7fff0000 <= x && x <= 0x10007fffffff) ||
|
||||
(0x7fff0000 <= y && y <= 0x10007fffffff) ||
|
||||
(x < 0x7fff0000 && 0x10007fffffff < y));
|
||||
BegA = (intptr_t)p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = 0x7fff0000;
|
||||
EndB = 0x10007fffffff;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -37,9 +38,6 @@
|
|||
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
|
||||
static int64_t vector;
|
||||
static sigset_t oldss;
|
||||
|
||||
static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
||||
int ntprot) {
|
||||
bool cf;
|
||||
|
@ -58,7 +56,7 @@ static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
|||
_Exit(26);
|
||||
}
|
||||
#endif
|
||||
if (ax) notpossible;
|
||||
_npassert(!ax);
|
||||
} else {
|
||||
__imp_VirtualProtect(addr, size, ntprot, &op);
|
||||
}
|
||||
|
@ -69,29 +67,26 @@ static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
|||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
privileged void __morph_begin(void) {
|
||||
privileged void __morph_begin(sigset_t *save) {
|
||||
int ax;
|
||||
bool cf;
|
||||
intptr_t dx;
|
||||
sigset_t ss = {{-1, -1}};
|
||||
STRACE("__morph_begin()");
|
||||
if (!IsWindows()) {
|
||||
if (!IsOpenbsd()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(&ss),
|
||||
"1"(&oldss)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
if (ax) notpossible;
|
||||
} else {
|
||||
if (IsOpenbsd()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(-1u)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
oldss.__bits[0] = ax & 0xffffffff;
|
||||
if (cf) notpossible;
|
||||
}
|
||||
save->__bits[0] = ax & 0xffffffff;
|
||||
_npassert(!cf);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(&ss), "1"(save)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
_npassert(!ax);
|
||||
}
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_WRITE,
|
||||
kNtPageWritecopy);
|
||||
|
@ -100,29 +95,25 @@ privileged void __morph_begin(void) {
|
|||
/**
|
||||
* Begins code morphing executable.
|
||||
*/
|
||||
privileged void __morph_end(void) {
|
||||
privileged void __morph_end(sigset_t *save) {
|
||||
int ax;
|
||||
long dx;
|
||||
bool cf;
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_EXEC,
|
||||
kNtPageExecuteRead);
|
||||
if (!IsWindows()) {
|
||||
if (!IsOpenbsd()) {
|
||||
if (IsOpenbsd()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(save->__bits[0])
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
_npassert(!cf);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(&oldss),
|
||||
"1"(0)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(save), "1"(0)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
if (ax) notpossible;
|
||||
} else {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_SETMASK),
|
||||
"S"(oldss.__bits[0])
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
if (cf) notpossible;
|
||||
}
|
||||
_npassert(!ax);
|
||||
}
|
||||
STRACE("__morph_end()");
|
||||
}
|
||||
|
|
12
libc/runtime/morph.h
Normal file
12
libc/runtime/morph.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __morph_begin(sigset_t *);
|
||||
void __morph_end(sigset_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_ */
|
|
@ -57,7 +57,7 @@ int atfork(void *, void *) libcesque;
|
|||
int atexit(void (*)(void)) libcesque;
|
||||
char *getenv(const char *) nosideeffect libcesque;
|
||||
int putenv(char *) paramsnonnull();
|
||||
int setenv(const char *, const char *, int) paramsnonnull();
|
||||
int setenv(const char *, const char *, int);
|
||||
int unsetenv(const char *);
|
||||
int clearenv(void);
|
||||
void fpreset(void);
|
||||
|
@ -100,8 +100,6 @@ char *GetInterpreterExecutableName(char *, size_t);
|
|||
void __printargs(const char *);
|
||||
void __paginate(int, const char *);
|
||||
int __arg_max(void);
|
||||
void __morph_begin(void);
|
||||
void __morph_end(void);
|
||||
void __print_maps(void);
|
||||
void __warn_if_powersave(void);
|
||||
const char *__describe_os(void);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -29,7 +31,7 @@ textstartup int __strace_init(int argc, char **argv, char **envp, long *auxv) {
|
|||
/* asan isn't initialized yet at runlevel 300 */
|
||||
if (__intercept_flag(&argc, argv, "--strace") ||
|
||||
__atoul(nulltoempty(__getenv(envp, "STRACE")))) {
|
||||
++__strace;
|
||||
atomic_store_explicit(&__strace, 1, memory_order_relaxed);
|
||||
}
|
||||
return (__argc = argc);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/macros.internal.h"
|
||||
.privileged
|
||||
|
||||
// Forks process without copying page tables.
|
||||
//
|
||||
|
@ -32,37 +31,55 @@
|
|||
// do anything in a vfork()'d child process. TLS memory must not
|
||||
// be disabled (it's enabled by default) since vfork() needs it.
|
||||
//
|
||||
// What makes vfork() dangerous is that any changes to memory in
|
||||
// the child process can happen in the parent too. The exception
|
||||
// to this rule is `errno` which is saved/restored in a register
|
||||
// by this implementation. However, despite its dangers, vfork's
|
||||
// performance is irresistible and wonderous to behold. If safer
|
||||
// code is desired, consider posix_spawn() which uses vfork().
|
||||
//
|
||||
// Do not make the assumption that the parent is suspended until
|
||||
// the child terminates since this impl calls fork() on Windows,
|
||||
// OpenBSD, and MacOS.
|
||||
// the child terminates since this uses the raw fork system call
|
||||
// on Windows, OpenBSD, and MacOS. In that case the process will
|
||||
// proceed without blocking the parent; however, the `__vforked`
|
||||
// variable is still set to true in the child, so lock functions
|
||||
// won't do anything, and other functions shall change behavior.
|
||||
// This ensures that, even if the operating system does not give
|
||||
// us the performance of vfork(), we'll still be able to cut out
|
||||
// the libc overhead, e.g. pthread_atfork().
|
||||
//
|
||||
// @return pid of child process or 0 if forked process
|
||||
// @returnstwice
|
||||
// @threadsafe
|
||||
// @vforksafe
|
||||
vfork: call __require_tls
|
||||
xor %edi,%edi # dwCreationFlags
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
jmp fork # TODO: asan and vfork don't mix?
|
||||
.endfn vfork,globl
|
||||
#else
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jnz sys_fork_nt # and we're lucky to have that
|
||||
#endif
|
||||
#if SupportsXnu()
|
||||
testb IsXnu()
|
||||
jnz fork
|
||||
#endif
|
||||
#if SupportsOpenbsd()
|
||||
testb IsOpenbsd()
|
||||
jnz fork # fake vfork plus msyscall issues
|
||||
#endif
|
||||
vfork:
|
||||
#if !IsTiny()
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
call __require_tls
|
||||
#ifdef SYSDEBUG
|
||||
ezlea .Llog,di
|
||||
call __stracef
|
||||
#endif /* SYSDEBUG */
|
||||
#endif
|
||||
pop %rbp
|
||||
#endif
|
||||
mov %fs:0,%r9 # get thread information block
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jnz 6f # and we're lucky to have that
|
||||
#endif
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
jmp 5f # TODO: asan and vfork don't mix?
|
||||
#endif
|
||||
#if SupportsXnu()
|
||||
testb IsXnu()
|
||||
jnz 5f
|
||||
#endif
|
||||
#if SupportsOpenbsd()
|
||||
testb IsOpenbsd()
|
||||
jnz 5f # fake vfork plus msyscall issues
|
||||
#endif
|
||||
mov 0x3c(%r9),%r8d # avoid question of @vforksafe errno
|
||||
pop %rsi # saves return address in a register
|
||||
mov __NR_vfork(%rip),%eax
|
||||
|
@ -79,12 +96,35 @@ vfork: call __require_tls
|
|||
cmp $-4095,%eax
|
||||
jae systemfive_error
|
||||
mov %r8d,0x3c(%r9) # restore errno
|
||||
test %eax,%eax
|
||||
jnz .Lprnt
|
||||
.Lchld: orb $TIB_FLAG_VFORKED,0x40(%r9)
|
||||
1: test %eax,%eax
|
||||
jnz .Lpar
|
||||
.Lchi: orb $TIB_FLAG_VFORKED,0x40(%r9)
|
||||
ret
|
||||
.Lprnt: andb $~TIB_FLAG_VFORKED,0x40(%r9)
|
||||
.Lpar: andb $~TIB_FLAG_VFORKED,0x40(%r9)
|
||||
ret
|
||||
#if SupportsXnu() || SupportsOpenbsd() || defined(__SANITIZE_ADDRESS__)
|
||||
5: push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %r9
|
||||
push %r9
|
||||
call sys_fork
|
||||
pop %r9
|
||||
pop %r9
|
||||
pop %rbp
|
||||
jmp 1b
|
||||
#endif
|
||||
#if SupportsWindows()
|
||||
6: push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %r9
|
||||
push %r9
|
||||
xor %edi,%edi # dwCreationFlags
|
||||
call sys_fork_nt
|
||||
pop %r9
|
||||
pop %r9
|
||||
pop %rbp
|
||||
jmp 1b
|
||||
#endif
|
||||
.endfn vfork,globl
|
||||
|
||||
#ifdef SYSDEBUG
|
||||
|
@ -93,5 +133,3 @@ vfork: call __require_tls
|
|||
.asciz "vfork()\n"
|
||||
.previous
|
||||
#endif /* DEBUGSYS */
|
||||
|
||||
#endif /* __SANITIZE_ADDRESS__ */
|
||||
|
|
|
@ -95,8 +95,8 @@ textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) {
|
|||
rc = 0;
|
||||
} else {
|
||||
CloseHandle(hpipe);
|
||||
__releasefd_unlocked(writer);
|
||||
__releasefd_unlocked(reader);
|
||||
__releasefd(writer);
|
||||
__releasefd(reader);
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue