Compare commits

..
67 Commits
Author SHA1 Message Date
Justine Tunney 69faf1b403 Release Cosmpolitan v3.1 2023-11-18 20:40:35 -08:00
Justine Tunney e4dea37b8e Make clock_nanosleep() cancel faster 2023-11-18 18:12:09 -08:00
Justine Tunney 0c89516ac5 Fix unzip warning with apelink generated symtabs 2023-11-18 17:15:22 -08:00
Justine Tunney 3e6d536822 Correct misunderstanding with zip64 extra records 2023-11-18 14:35:57 -08:00
Justine Tunney dbd8176ea8 Add CPU_COUNT_S() 2023-11-18 12:38:30 -08:00
Justine Tunney 545a8f4cb0 Add more sched.h content 2023-11-18 08:08:15 -08:00
Justine Tunney f7cfe03888 Fix dlopen() for FreeBSD and NetBSD 2023-11-18 04:35:48 -08:00
Justine Tunney 2c1efd3d78 Fix Python build break 2023-11-18 02:32:01 -08:00
Matheus Moreira 3ac473df3b Floating point parsing support for scanf family (#924) 2023-11-18 02:25:36 -08:00
Justine Tunney 8caf1b48a9 Improve time/sleep accuracy on Windows
It's now almost as good as Linux thanks to a Windows 8+ API.
2023-11-18 01:57:44 -08:00
Justine Tunney 72ac5f18d9 Fix dash compatible syntax issue 2023-11-17 16:47:47 -08:00
Justine Tunney 2c9d2943d6 Introduce AddDllDirectory() 2023-11-17 10:35:34 -08:00
Justine Tunney 32b97f2d25 Improve execve() path argument munging
Munging of paths passed inside the system() interpreter command is no
longer supported. You have to pass your paths to posix_spawn() or the
execve() family of functions if you want them to be munged. The first
three characters must match `^/[a-z]/` in which case, it'll be turned
into a DOS-style drive path with backslashes.
2023-11-17 09:59:03 -08:00
Justine Tunney 529cb4817c Improve dlopen() on Apple Silicon
- Introduce MAP_JIT which is zero on other platforms
- Invent __jit_begin() and __jit_end() which wrap Apple's APIs
- Runtime dispatch to sys_icache_invalidate() in __clear_cache()
2023-11-17 02:33:14 -08:00
Justine Tunney 7a9e176ecf Improve debug binary location detection 2023-11-17 00:07:39 -08:00
Justine Tunney 68c7c9c1e0 Clean up some code
- Use good ELF technique in cosmo_dlopen()
- Make strerror() conform more to other libc impls
- Introduce __clear_cache() and use it in cosmo_dlopen()
- Remove libc/fmt/fmt.h header (trying to kill off LIBC_FMT)
2023-11-16 17:31:07 -08:00
tkchia 7010a8081e Fix regression when building deathstar.com for aarch64 (#957)
It turns out my earlier commit ddc08dc974 caused a build with
MODE=aarch64 to fail.  The commit changed deathstar.c to link
in code to support a VGA console, but this is not implemented
yet for AArch64.  Thanks to @ahgamut for spotting this issue.
2023-11-16 12:13:17 -08:00
tkchia 665747a319 Make test/libc/calls/pledge_test.c work with "nonstandard" umask (#956)
The test was failing if the process's umask happened to be
0077, for example.  The file `foo` was then created with a
file mode of 0100600, rather than the expected 0100644.
2023-11-16 00:47:21 -08:00
Justine Tunney e05933c641 Mention zsh and fish in readme 2023-11-15 23:25:47 -08:00
Justine Tunney 8f5e516b39 Remove sync_file_range()
After hearing horror stories from a trusted colleague, I don't think
this is the kind of API we want to be supporting. Also SQLite wisdom
regarding fdatasync() has been added to the documentation.
2023-11-15 23:21:22 -08:00
Justine Tunney 8318d67503 Fix regression in cosmocc toolchain 2023-11-15 21:41:53 -08:00
Justine Tunney 1351d3cede Remove bool from public headers 2023-11-15 20:58:46 -08:00
Justine Tunney dffee606cf Run host compiler to create dlopen helper 2023-11-15 20:58:46 -08:00
tkchia ddc08dc974 [metal] Make deathstar.com draw onto both VGA and serial consoles (#955)
In addition, deathstar.com can now be booted up via UEFI.
2023-11-15 19:40:54 -08:00
Justine Tunney e4584ace81 Get cosmo_dlopen() working better on System Five
Imported functions are now aspected with a trampoline that blocks
signals and changes the thread-local storage register. This means
bigger more complicated libraries can now be imported even though
the whole technique remains fundamentally unsafe.
2023-11-15 10:56:30 -08:00
Justine Tunney 3a470ed356 Remove some exploratory some tests
These were reported as failing on some Apple Arm64 systems.
2023-11-14 21:21:22 -08:00
Justine Tunney 9f9aec013a Do better job documenting platform issues 2023-11-14 18:15:58 -08:00
tkchia eea601f346 [metal] Some minor fixes and tweaks (#933)
* [metal] Ensure DF is clear when calling C from exception handler
* [metal] Mark some internal routines and declarations as `@internal`
* [metal] Fix crash under UEFI when command line string is NULL
* [metal] Fix argc & argv[] setting, & VM page freeing, for UEFI

Part of the memory occupied by the argv[] contents was
erroneously used for page tables & then later erroneously
freed.  The symptom was that argv[0] would show up as an
empty string ("").
2023-11-14 15:26:59 -08:00
Justine Tunney 1c2e7c1333 Introduce SIP_DISABLED compile option for ape-m1.c
Systems that don't use SIP can now build APE Loader with this flag to
get a performance speedup.
2023-11-13 22:04:05 -08:00
Justine Tunney 0283f2772c Fix build in MODE=dbg 2023-11-13 15:13:45 -08:00
Justine Tunney 751d20d98d Fix nsync_mu_unlock_slow_() on Apple Silicon
We torture test dlmalloc() in test/libc/stdio/memory_test.c. That test
was crashing on occasion on Apple M1 microprocessors when dlmalloc was
using *NSYNC locks. It was relatively easy to spot the cause, which is
this one particular compare and swap operation, which needed to change
to use sequentially-consistent ordering rather than an acquire barrier
2023-11-13 11:07:13 -08:00
Justine Tunney 3b15d31247 Fix #include <shared_mutex> 2023-11-13 08:30:17 -08:00
Justine Tunney f047172bd3 Fix uname assignment in Makefile 2023-11-13 05:53:10 -08:00
mattx 5d5b282d12 Inform user when wsl2 interop causes build issues (#952) 2023-11-13 05:29:25 -08:00
Justine Tunney 25a892d6ae Add some platform notes to the README file 2023-11-13 02:26:34 -08:00
Justine Tunney d1e764b3cf Modernize README.md 2023-11-12 22:04:07 -08:00
Paul Kulchenko 5c1fdc9819 Fix session changeset procesing (reverting some of 0d748ad5 changes) (#949)
This removes strdup from Lua SQLite wrapper, as it's applied to binary changeset
strings, thus cutting them short (because of strlen).
2023-11-12 14:25:50 -08:00
Justine Tunney f25beb341c Add architecture flag to zipobj 2023-11-12 09:35:59 -08:00
Justine Tunney bed77186c3 Use simple locks in dlmalloc 2023-11-12 09:00:49 -08:00
Justine Tunney bcf268adf8 Don't modify argument block on MacOS Arm64
Some dynamic library had access to this information somehow and was
crashing when it didn't have the expected structure.
2023-11-12 05:59:03 -08:00
Justine Tunney 0863427b3a Make development more pleasant on MacOS Arm64 2023-11-12 05:42:17 -08:00
Justine Tunney f7cad70da1 Introduce posix tests package 2023-11-12 05:41:48 -08:00
Justine Tunney 48bd3d85df Fix sigaction() return handler address on XNU/BSD 2023-11-12 05:40:06 -08:00
Justine Tunney bd56a9cf51 Rename dlopen() to cosmo_dlopen() 2023-11-12 01:19:04 -08:00
Justine Tunney c6d3802d3a Add more fixes for new cosmocc toolchain
We now have an `#include <cxxabi.h>` header which defines all the APIs
Cosmopolitan's implemented so far. The `cosmocc` README.md file is now
greatly expanded with documentation.
2023-11-11 23:28:19 -08:00
Gautham 95124cacbe Fixes for building superconfigure (#948) 2023-11-11 22:11:11 -08:00
Justine Tunney b320321319 Add build/bootstrap/rollup.com 2023-11-11 19:58:45 -08:00
Justine Tunney 291103ad8d Redesign cosmocc toolchain
The `cosmocc` compiler is now being distributed as a self-contained
toolchain that's path-agnostic and it no longer requires you clone the
Cosmop repo to use it. The bin/ folder has been deleted from the mono
repo. The `fatcosmocc` command has been renamed to `cosmocc`. MacOS
support now works very well.
2023-11-11 14:18:08 -08:00
Justine Tunney 3802428026 Fix missing .ok file make warning 2023-11-11 02:32:22 -08:00
Justine Tunney d0ad2694ed Iterate more on recent changes 2023-11-11 00:28:22 -08:00
Paul Kulchenko 7138399f96 Close Lua state before exiting redbean worker to allow GC to collect (#941) 2023-11-10 18:37:00 -08:00
Justine Tunney cdbd10c9d0 Introduce X86_CHECK() macro 2023-11-10 15:41:55 -08:00
Justine Tunney afbef6c361 Freshen build/bootstrap/mkdeps.com 2023-11-10 12:39:52 -08:00
Justine Tunney 3d3cdcf276 Fix APE uname direction
Fixes #942
2023-11-10 12:34:25 -08:00
Justine Tunney d2f49ca175 Improve mkdeps
Our makefile generator now accepts badly formatted include lines. It's
now more hermetic with better error checking in the cosmo repo, and it
can be configured to not be hermetic at all.
2023-11-10 04:14:27 -08:00
Justine Tunney 241f949540 Use dynamic memory for *NSYNC waiters 2023-11-10 01:42:06 -08:00
Justine Tunney 15af5c2d7e Fix ucontext_t alignment in strict ansi mode
Using `cosmocc -std=c11` was causing `ucontext_t` to become misaligned.
This change also adds the GNU constants on x86_64 for accessing general
registers, so you will not need `#ifdef`s to support both Cosmo and GNU
2023-11-09 12:48:29 -08:00
Justine Tunney b8d1377ae1 Give new wait4() another review pass 2023-11-09 11:23:30 -08:00
Justine Tunney ea28f93a26 Support <isystem> includes in monorepo 2023-11-08 19:14:56 -08:00
Justine Tunney 5330442d85 Avoid APE fork bomb
This change addresses a $PATH resolution issue where APE depends on
uname and uname is an APE program. So sorry to anyone this impacted
we'll get a release out soon.
2023-11-08 11:37:42 -08:00
mataha cc3e3de044 Make args replace ... only at the end of file (#909)
So that the string '...' can be used verbatim elsewhere in the file.
2023-11-08 10:00:52 -08:00
Justine Tunney ac125d3e1f Fix console copy/paste issue
Fixes #936
2023-11-08 09:29:45 -08:00
Justine Tunney 956e68be59 Revert "Use %gs as TLS register when dlopen() is linked"
This reverts commit d71da7fc72.
2023-11-08 01:33:01 -08:00
Justine Tunney d71da7fc72 Use %gs as TLS register when dlopen() is linked
Fixes #938
2023-11-08 01:11:17 -08:00
Justine Tunney e961385e55 Put more thought into i/o polyfills
wait4() is now solid enough to run `make -j100` on Windows. You can now
use MSG_DONTWAIT on Windows. There was a handle leak in accept() that's
been fixed. Our WIN32 overlapped i/o code has been simplified. Priority
class now inherits into subprocesses, so the verynice command will work
and the signal mask will now be inherited by execve() and posix_spawn()
2023-11-07 18:32:35 -08:00
Justine Tunney 736fdb757a Implement raise() with getcontext() / setcontext() 2023-11-05 18:04:36 -08:00
Justine Tunney dd83db9567 Improve makefile for uname 2023-11-05 16:21:09 -08:00
643 changed files with 7625 additions and 4520 deletions

No files matched your search

+45 -15
View File
@@ -73,8 +73,16 @@ MODE := $(m)
endif
endif
UNAME_M = $(shell uname -m)
UNAME_S = $(shell uname -s)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran build/bootstrap/make.com, in which case make's working directory is in wsl
# - user ran make, in which case cocmd.com's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(shell pwd)),)
$(warning wsl2 interop is enabled)
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
endif
UNAME_M := $(shell uname -m)
UNAME_S := $(shell uname -s)
# apple still distributes a 17 year old version of gnu make
ifeq ($(MAKE_VERSION), 3.81)
@@ -85,7 +93,7 @@ endif
ifeq ($(TOOLCHAIN),) # if TOOLCHAIN isn't defined
ifeq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") # if our gcc isn't unbundled
ifneq ($(UNAME_M)-$(UNAME_S), x86_64-Linux) # if this is not amd64 linux
$(error you need to download https://justine.lol/cosmocc-0.0.18.zip and unzip it inside the cosmo directory)
$(error you need to download https://cosmo.zip/pub/cosmocc/cosmocc-0.0.18.zip and unzip it inside the cosmo directory)
endif
endif
endif
@@ -176,7 +184,6 @@ include libc/calls/calls.mk #─┐
include libc/irq/irq.mk # ├──SYSTEMS RUNTIME
include third_party/nsync/nsync.mk # │ You can issue system calls
include libc/runtime/runtime.mk # │
include libc/dlopen/dlopen.mk # │
include third_party/double-conversion/dc.mk # │
include libc/crt/crt.mk # │
include third_party/dlmalloc/dlmalloc.mk #─┘
@@ -184,8 +191,9 @@ include libc/mem/mem.mk #─┐
include third_party/gdtoa/gdtoa.mk # ├──DYNAMIC RUNTIME
include third_party/nsync/mem/mem.mk # │ You can now use stdio
include libc/proc/proc.mk # │ You can now use threads
include libc/thread/thread.mk # │ You can now use processes
include tool/hello/hello.mk # │ You can finally call malloc()
include libc/dlopen/dlopen.mk # │ You can now use processes
include libc/thread/thread.mk # │ You can finally call malloc()
include tool/hello/hello.mk # │
include third_party/zlib/zlib.mk # │
include libc/stdio/stdio.mk # │
include libc/time/time.mk # │
@@ -221,6 +229,7 @@ include third_party/nsync/testing/testing.mk
include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk
include tool/args/args.mk
include test/posix/test.mk
include test/tool/args/test.mk
include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
@@ -329,7 +338,7 @@ o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x)))) $(INCS) $(INCS)
$(file >$@,$(INCS))
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -s -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
@@ -403,13 +412,14 @@ COSMOPOLITAN_OBJECTS = \
LIBC_NT_KERNEL32 \
LIBC_NEXGEN32E
COSMOPOLITAN_HEADERS = \
COSMOPOLITAN_H_PKGS = \
APE \
LIBC \
LIBC_CALLS \
LIBC_DNS \
LIBC_ELF \
LIBC_FMT \
LIBC_DLOPEN \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
@@ -434,21 +444,41 @@ COSMOPOLITAN_HEADERS = \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_REGEX
COSMOCC_PKGS = \
$(COSMOPOLITAN_H_PKGS) \
THIRD_PARTY_AARCH64 \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_INTEL
o/$(MODE)/cosmopolitan.a: \
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
o/cosmopolitan.h: \
o/$(MODE)/tool/build/rollup.com \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_INCS))
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
COSMOCC_HDRS = \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOCC_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOCC_PKGS),$($(x)_INCS))
o/cosmocc.h.txt: Makefile
$(file >$@, $(call uniq,$(COSMOCC_HDRS)))
COSMOPOLITAN_H_ROOT_HDRS = \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
o/cosmopolitan.h.txt: Makefile
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
o/cosmopolitan.h: o/cosmopolitan.h.txt \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
@$(ECHO) '#ifndef __STRICT_ANSI__' >$@
@$(ECHO) '#define _COSMO_SOURCE' >>$@
@$(ECHO) '#endif' >>$@
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >>$@
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup.com @$< >>$@
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
+100 -433
View File
@@ -19,22 +19,17 @@ libc](https://justine.lol/cosmopolitan/index.html) website. We also have
## Getting Started
It's recommended that Cosmopolitan be installed to `/opt/cosmo` and
`/opt/cosmos` on your computer. The first has the monorepo. The second
contains your non-monorepo artifacts.
You can start by obtaining a release of our `cosmocc` compiler from
<https://cosmo.zip/pub/cosmocc/>.
```sh
sudo mkdir -p /opt
sudo chmod 1777 /opt
git clone https://github.com/jart/cosmopolitan /opt/cosmo
export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"
echo 'PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"' >>~/.profile
ape-install # optionally install a faster systemwide ape loader
cosmocc --update # pull cosmo and rebuild toolchain
mkdir -p cosmocc
cd cosmocc
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zip
```
You've now successfully installed your very own cosmos. Now let's build
an example program:
Here's an example program we can write:
```c
// hello.c
@@ -45,26 +40,11 @@ int main() {
}
```
To compile the program, you can run the `cosmocc` command. It's
important to give it an output path that ends with `.com` so the output
format will be Actually Portable Executable. When this happens, a
concomitant debug binary is created automatically too.
It can be compiled as follows:
```sh
cosmocc -o hello.com hello.c
./hello.com
./hello.com.dbg
```
You can use the `cosmocc` toolchain to build conventional open source
projects which use autotools. This strategy normally works:
```sh
export CC=cosmocc
export CXX=cosmoc++
./configure --prefix=/opt/cosmos
make -j
make install
cosmocc -o hello hello.c
./hello
```
The Cosmopolitan Libc runtime links some heavyweight troubleshooting
@@ -72,445 +52,119 @@ features by default, which are very useful for developers and admins.
Here's how you can log system calls:
```sh
./hello.com --strace
./hello --strace
```
Here's how you can get a much more verbose log of function calls:
```sh
./hello.com --ftrace
./hello --ftrace
```
If you don't want rich runtime features like the above included, and you
just want libc, and you want smaller simpler programs. In that case, you
can consider using `MODE=tiny`, which is preconfigured by the repo in
[build/config.mk](build/config.mk). Using this mode is much more
effective at reducing binary footprint than the `-Os` flag alone. You
can change your build mode by doing the following:
You can use the Cosmopolitan's toolchain to build conventional open
source projects which use autotools. This strategy normally works:
```sh
export MODE=tiny
cosmocc --update
```
We can also make our program slightly smaller by using the system call
interface directly, which is fine, since Cosmopolitan polyfills these
interfaces across platforms, including Windows. For example:
```c
// hello2.c
#include <unistd.h>
int main() {
write(1, "hello world\n", 12);
}
```
Once compiled, your APE binary should be ~36kb in size.
```sh
export MODE=tiny
cosmocc -Os -o hello2.com hello2.c
./hello2.com
```
But let's say you only care about your binaries running on Linux and you
don't want to use up all this additional space for platforms like WIN32.
In that case, you can try `MODE=tinylinux` for example which will create
executables more on the order of 8kb (similar to Musl Libc).
```sh
export MODE=tinylinux
cosmocc --update
cosmocc -Os -o hello2.com hello2.c
./hello2.com # <-- actually an ELF executable
```
## ARM
Cosmo supports cross-compiling binaries for machines with ARM
microprocessors. For example:
```sh
make -j8 m=aarch64 o/aarch64/third_party/ggml/llama.com
make -j8 m=aarch64-tiny o/aarch64-tiny/third_party/ggml/llama.com
```
That'll produce ELF executables that run natively on two operating
systems: Linux Arm64 (e.g. Raspberry Pi) and MacOS Arm64 (i.e. Apple
Silicon), thus giving you full performance. The catch is you have to
compile these executables on an x86_64-linux machine. The second catch
is that MacOS needs a little bit of help understanding the ELF format.
To solve that, we provide a tiny APE loader you can use on M1 machines.
```sh
scp ape/ape-m1.c macintosh:
scp o/aarch64/third_party/ggml/llama.com macintosh:
ssh macintosh
xcode-install
cc -o ape ape-m1.c
sudo cp ape /usr/local/bin/ape
```
You can run your ELF AARCH64 executable on Apple Silicon as follows:
```sh
ape ./llama.com
```
If you want to run the `MODE=aarch64` unit tests, you need to have
qemu-aarch64 installed as a binfmt_misc interpreter. It needs to be a
static binary if you want it to work with Landlock Make's security. You
can use the build included in our `third_party/qemu/` folder.
```
doas cp o/third_party/qemu/qemu-aarch64 /usr/bin/qemu-aarch64
doas sh -c "echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:CF' > /proc/sys/fs/binfmt_misc/register"
make -j8 m=aarch64
```
Please note that the qemu-aarch64 binfmt_misc interpreter installation
process is *essential* for being able to use the `aarch64-unknown-cosmo`
toolchain to build fat APE binaries on your x86-64 machine.
## AMD64 + ARM64 fat APE binaries
If you've setup the qemu binfmt_misc interpreter, then you can can use
cosmo's toolchains to build fat ape binaries. It works by compiling your
program twice, so you can have a native build for both architectures in
the same file. The two programs are merged together by apelink.com which
also embeds multiple copies of APE loader and multiple symbols tables.
The easiest way to build fat APE is using `fatcosmocc`. This compiler
works by creating a concomitant `.aarch64/foo.o` for every `foo.o` you
compile. The only exception is the C preprocessor mode, which actually
runs x86-64 GCC except with macros like `__x86_64__` undefined.
This toolchain works great for C projects that are written in a portable
way and don't produce architecture-specific artifacts. One example of a
large project that can be easily built is GNU coreutils.
```sh
cd coreutils
fatcosmocc --update ||exit
./configure CC=fatcosmocc \
AR=fatcosmoar \
INSTALL=$(command -v fatcosmoinstall) \
--prefix=/opt/cosmos \
--disable-nls \
--disable-dependency-tracking \
--disable-silent-rules
make -j8
```
You'll then have a bunch of files like `src/ls` which are fat ape
binaries. If you want to run them on Windows, then you simply need to
rename the file so that it has the `.com` suffix. Better yet, consider
making that a symlink (a.k.a. reparse point). The biggest gotcha with
`fatcosmocc` though is ensuring builds don't strip binaries. For
example, Linux's `install -s` command actually understands Windows'
Portable Executable format well enough to remove the MS-DOS stub, which
is where the APE shell script is stored. You need to ensure that
`fatcosmoinstall` is used instead. Especially if your project needs to
install the libraries built by `fatacosmoar` into `/opt/cosmos`.
## Advanced Fat APE Builds
Once you get seriously involved in creating fat APE builds of software
you're going to eventually outgrow `fatcosmocc`. One example is Emacs
which is trickier to build, because it produces architecture-specific
files, and it also depends on shared files, e.g. zoneinfo. Since we like
having everything in a neat little single-file executable container that
doesn't need an "installation wizard", this tutorial will explain how we
manage to accomplish that.
What you're going to do is, instead of using `fatcosmocc`, you're going
to use both the `x86_64-unknown-cosmo-cc` and `aarch64-unknown-cosmo-cc`
toolchains independently, and then run `apelink` and `zip` to manually
build the final files. But there's a few tricks to learn first.
The first trick is to create a symlink on your system called `/zip`.
Cosmopolitan Libc normally uses that as a synthetic folder that lets you
access the assets in your zip executable. But since that's a read-only
file system, your build system should use the normal one.
```sh
doas ln -sf /opt/cosmos /zip
```
Now create a file named `rebuild-fat.sh` which runs the build twice:
```sh
#!/bin/sh
set -ex
export MODE=aarch64
export COSMOS=/opt/cosmos/aarch64
rebuild-cosmos.sh aarch64
export MODE=
export COSMOS=/opt/cosmos/x86_64
rebuild-cosmos.sh x86_64
wall.com 'finished building'
```
Then create a second file `rebuild-cosmos.sh` which runs your build:
```sh
#!/bin/bash
set -ex
ARCH=${1:-x86_64}
export COSMO=${COSMO:-/opt/cosmo}
export COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
export AS=$(command -v $ARCH-unknown-cosmo-as) || exit
export CC=$(command -v $ARCH-unknown-cosmo-cc) || exit
export CXX=$(command -v $ARCH-unknown-cosmo-c++) || exit
export AR=$(command -v $ARCH-unknown-cosmo-ar) || exit
export STRIP=$(command -v $ARCH-unknown-cosmo-strip) || exit
export INSTALL=$(command -v $ARCH-unknown-cosmo-install) || exit
export OBJCOPY=$(command -v $ARCH-unknown-cosmo-objcopy) || exit
export OBJDUMP=$(command -v $ARCH-unknown-cosmo-objdump) || exit
export ADDR2LINE=$(command -v $ARCH-unknown-cosmo-addr2line) || exit
$CC --update
export COSMOPOLITAN_DISABLE_ZIPOS=1
cd ~/vendor/zlib
./configure --prefix=$COSMOS --static
make clean
make -j
make install
cd ~/vendor/ncurses-6.4
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH --disable-shared
make clean
make -j
make install
cd ~/vendor/readline-8.2
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH --disable-shared
make uninstall || true
make clean
make -j
make install
# NOTES:
# 1. You'll need to patch enum { FOO = x } that fails to build into a #define FOO
# 2. You'll need to patch configure.ac so it DOES NOT define USABLE_FIONREAD to 1
# 2. You'll need to patch configure.ac so it DOES NOT define INTERRUPT_INPUT to 1
cd ~/vendor/emacs-28.2
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH \
--without-x --with-threads --without-gnutls --disable-silent-rules --with-file-notification=no
make uninstall || true
make clean
export CC=x86_64-unknown-cosmo-cc
export CXX=x86_64-unknown-cosmo-c++
./configure --prefix=/opt/cosmos/x86_64
make -j
make install
```
Once you've completed this build process, you'll have the ELF files
`/opt/cosmos/x86_64/bin/emacs` and `/opt/cosmos/aarch64/bin/emacs`. Your
next move is to combine them into a single pristine `emacs.com` file.
## Cosmopolitan Source Builds
Cosmopolitan can be compiled from source on any of our supported
platforms. First, you need to download or clone the repository. If
you're not using x86-64 Linux then you'll need cosmocc too.
```sh
cd /zip
COSMO=${COSMO:-/opt/cosmo}
mkdir -p /opt/cosmos/bin
apelink \
-o /opt/cosmos/bin/emacs.com \
-l "$COSMO/o//ape/ape.elf" \
-l "$COSMO/o/aarch64/ape/ape.elf" \
-M "$COSMO/ape/ape-m1.c" \
/opt/cosmos/x86_64/bin/emacs \
/opt/cosmos/aarch64/bin/emacs
cd /zip
zip -r /opt/cosmos/bin/emacs.com \
aarch64/libexec \
x86_64/libexec \
share/terminfo \
$(find share/emacs -type f |
grep -v '\.el.gz$' |
grep -v refcards |
grep -v images)
git clone https://github.com/jart/cosmopolitan cosmo
cd cosmo
mkdir -p o/third_party/gcc
pushd o/third_party/gcc
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zip
popd
```
You can now scp your `emacs.com` build to seven operating systems for
two distinct kinds of microprocessors without any dependencies. All the
LISP, zoneinfo, and termcap files it needs are stored inside the ZIP
structure of the binary, which has performance that's equivalent to the
Linux filesystem (even though it decompresses artifacts on the fly!) For
this reason, you might actually find that fat APE Emacs goes faster if
you're using an operating system like Windows where files are go slow.
If you like to use Vim instead of Emacs, then you can build that too.
However Vim's build system makes it a bit harder, since it's configured
to always strip binaries. The `apelink` program needs the symbol tables
to still be there when it creates the fat version. Otherwise tools like
`--ftrace` won't work.
## Monolithic Source Builds
Cosmopolitan can be compiled from source on any Linux distro. First, you
need to download or clone the repository.
It's recommended that you install a systemwide APE Loader. This command
requires `sudo` access to copy the `ape` command to a system folder and
register with binfmt_misc on Linux, for even more performance.
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
tar xf cosmopolitan.tar.gz # see releases page
cd cosmopolitan
ape/apeinstall.sh
```
This will build the entire repository and run all the tests:
You can now build the mono repo with any modern version of GNU Make. To
make life easier, we've included one in the cosmocc toolchain, which is
guaranteed to be compatible and furthermore includes our extensions for
doing build system sandboxing.
```sh
build/bootstrap/make.com
o//third_party/gcc/bin/make -j8
o//examples/hello.com
find o -name \*.com | xargs ls -rShal | less
```
If you get an error running make.com then it's probably because you have
WINE installed to `binfmt_misc`. You can fix that by installing the the
APE loader as an interpreter. It'll improve build performance too!
```sh
bin/ape-install
```
Since the Cosmopolitan repository is very large, you might only want to
build a particular thing. Cosmopolitan's build config does a good job at
having minimal deterministic builds. For example, if you wanted to build
only hello.com then you could do that as follows:
build one particular thing. Here's an example of a target that can be
compiled relatively quickly, which is a simple POSIX test that only
depends on core LIBC packages.
```sh
build/bootstrap/make.com o//examples/hello.com
rm -rf o//libc o//test
o//third_party/gcc/bin/make o//test/posix/signal_test.com
o//test/posix/signal_test.com
```
Sometimes it's desirable to build a subset of targets, without having to
list out each individual one. You can do that by asking make to build a
directory name. For example, if you wanted to build only the targets and
subtargets of the chibicc package including its tests, you would say:
list out each individual one. For example if you wanted to build and run
all the unit tests in the `TEST_POSIX` package, you could say:
```sh
build/bootstrap/make.com o//third_party/chibicc
o//third_party/chibicc/chibicc.com --help
o//third_party/gcc/bin/make o//test/posix
```
Cosmopolitan provides a variety of build modes. For example, if you want
really tiny binaries (as small as 12kb in size) then you'd say:
```sh
build/bootstrap/make.com m=tiny
o//third_party/gcc/bin/make m=tiny
```
Here's some other build modes you can try:
You can furthermore cut out the bloat of other operating systems, and
have Cosmopolitan become much more similar to Musl Libc.
```sh
build/bootstrap/make.com m=dbg # asan + ubsan + debug
build/bootstrap/make.com m=asan # production memory safety
build/bootstrap/make.com m=opt # -march=native optimizations
build/bootstrap/make.com m=rel # traditional release binaries
build/bootstrap/make.com m=optlinux # optimal linux-only performance
build/bootstrap/make.com m=fastbuild # build 28% faster w/o debugging
build/bootstrap/make.com m=tinylinux # tiniest linux-only 4kb binaries
o//third_party/gcc/bin/make m=tinylinux
```
For further details, see [//build/config.mk](build/config.mk).
## Cosmopolitan Amalgamation
## Debugging
Another way to use Cosmopolitan is via our amalgamated release, where
we've combined everything into a single static archive and a single
header file. If you're doing your development work on Linux or BSD then
you need just five files to get started. Here's what you do on Linux:
To print a log of system calls to stderr:
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-3.0.2.zip
unzip cosmopolitan-amalgamation-3.0.2.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
-o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds -Wl,--gc-sections \
-Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 \
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
objcopy -S -O binary hello.com.dbg hello.com
cosmocc -o hello hello.c
./hello --strace
```
You now have a portable program.
To print a log of function calls to stderr:
```sh
./hello.com
bash -c './hello.com' # older zsh/fish workaround (patched in zsh 5.9 and fish 3.3.0)
cosmocc -o hello hello.c
./hello --ftrace
```
If `./hello.com` executed on Linux throws an error about not finding an
interpreter, it should be fixed by running the following command (although
note that it may not survive a system restart):
Both strace and ftrace use the unbreakable kprintf() facility, which is
able to be sent to a file by setting an environment variable.
```sh
sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
export KPRINTF_LOG=log
./hello --strace
```
If the same command produces puzzling errors on WSL or WINE when using
Redbean 2.x, they may be fixed by disabling binfmt_misc:
```sh
sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status'
```
Since we used the `ape-no-modify-self.o` bootloader (rather than
`ape.o`) your executable will not modify itself when it's run. What
it'll instead do, is extract a 4kb program (the [APE loader](https://justine.lol/apeloader/))
to `${TMPDIR:-${HOME:-.}}` that maps your program into memory without
needing to copy it. The APE loader must be in an executable location
(e.g. not stored on a `noexec` mount) for it to run. See below for
alternatives:
It's possible to install the APE loader systemwide as follows.
```sh
# System-Wide APE Install
# for Linux, Darwin, and BSDs
# 1. Copies APE Loader to /usr/bin/ape
# 2. Registers w/ binfmt_misc too if Linux
bin/ape-install
# System-Wide APE Uninstall
# for Linux, Darwin, and BSDs
bin/ape-uninstall
```
It's also possible to convert APE binaries into the system-local format
by using the `--assimilate` flag. Please note that if binfmt_misc is in
play, you'll need to unregister it temporarily before doing this, since
the assimilate feature is part of the shell script header.
```sh
$ file hello.com
hello.com: DOS/MBR boot sector
./hello.com --assimilate
$ file hello.com
hello.com: ELF 64-bit LSB executable
```
Now that you're up and running with Cosmopolitan Libc and APE, here's
some of the most important troubleshooting tools APE offers that you
should know, in case you encounter any issues:
```sh
./hello.com --strace # log system calls to stderr
./hello.com --ftrace # log function calls to stderr
```
Do you love tiny binaries? If so, you may not be happy with Cosmo adding
heavyweight features like tracing to your binaries by default. In that
case, you may want to consider using our build system:
```sh
make m=tiny
```
Which will cause programs such as `hello.com` and `life.com` to shrink
from 60kb in size to about 16kb. There's also a prebuilt amalgamation
online <https://justine.lol/cosmopolitan/cosmopolitan-tiny.zip> hosted
on our download page <https://justine.lol/cosmopolitan/download.html>.
## GDB
Here's the recommended `~/.gdbinit` config:
@@ -542,39 +196,52 @@ You normally run the `.com.dbg` file under gdb. If you need to debug the
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
```
## Alternative Development Environments
## Platform Notes
### MacOS
### Shells
If you're developing on MacOS you can install the GNU compiler
collection for x86_64-elf via homebrew:
If you use zsh and have trouble running APE programs try `sh -c ./prog`
or simply upgrade to zsh 5.9+ (since we patched it two years ago). The
same is the case for Python `subprocess`, old versions of fish, etc.
### Linux
Some Linux systems are configured to launch MZ executables under WINE.
Other distros configure their stock installs so that APE programs will
print "run-detectors: unable to find an interpreter". For example:
```sh
brew install x86_64-elf-gcc
jart@ubuntu:~$ wget https://cosmo.zip/pub/cosmos/bin/dash
jart@ubuntu:~$ chmod +x dash
jart@ubuntu:~$ ./dash
run-detectors: unable to find an interpreter for ./dash
```
Then in the above scripts just replace `gcc` and `objcopy` with
`x86_64-elf-gcc` and `x86_64-elf-objcopy` to compile your APE binary.
### Windows
If you're developing on Windows then you need to download an
x86_64-pc-linux-gnu toolchain beforehand. See the [Compiling on
Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
tutorial. It's needed because the ELF object format is what makes
universal binaries possible.
Cosmopolitan officially only builds on Linux. However, one highly
experimental (and currently broken) thing you could try, is building the
entire cosmo repository from source using the cross9 toolchain.
You can fix that by registering APE with `binfmt_misc`:
```sh
mkdir -p o/third_party
rm -rf o/third_party/gcc
wget https://justine.lol/linux-compiler-on-windows/cross9.zip
unzip cross9.zip
mv cross9 o/third_party/gcc
build/bootstrap/make.com
sudo wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
```
You should be good now. APE will not only work, it'll launch executables
400µs faster now too. However if things still didn't work out, it's also
possible to disable `binfmt_misc` as follows:
```sh
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli' # remove Ubuntu's MZ interpreter
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status' # remove ALL binfmt_misc entries
```
### WSL
It's normally unsafe to use APE in a WSL environment, because it tries
to run MZ executables as WIN32 binaries within the WSL environment. In
order to make it safe to use Cosmopolitan software on WSL, run this:
```sh
sudo sh -c "echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop"
```
## Discord Chatroom
+46 -31
View File
@@ -36,7 +36,7 @@
#define pagesz 16384
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
#define SYSLIB_VERSION 7
#define SYSLIB_VERSION 8
struct Syslib {
int magic;
@@ -62,7 +62,7 @@ struct Syslib {
/* v2 (2023-09-10) */
pthread_t (*pthread_self)(void);
void (*dispatch_release)(dispatch_semaphore_t);
int (*raise)(int);
long (*raise)(int);
int (*pthread_join)(pthread_t, void **);
void (*pthread_yield_np)(void);
int pthread_stack_min;
@@ -441,6 +441,10 @@ static long sys_close(int fd) {
return sysret(close(fd));
}
static long sys_raise(int sig) {
return sysret(raise(sig));
}
static long sys_pipe(int pfds[2]) {
return sysret(pipe(pfds));
}
@@ -625,7 +629,6 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
/* load from file */
if (p[i].p_filesz) {
long map1, map2;
int prot1, prot2;
unsigned long wipe;
prot1 = prot;
@@ -649,22 +652,33 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
if (prot1 & PROT_EXEC) {
#ifdef SIP_DISABLED
// if sip is disabled then we can load the executable segments
// of the binary into memory without needing to copy anything!
// off the binary into memory without needing to copy anything
// which provides considerably better performance for building
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
if (rc < 0) {
if (rc != -EPERM) Pexit(exe, rc, "mmap(exec)");
// apple arm64 won't allow PROT_EXEC mapping any unsigned file
// however we are allowed to copy it into an anonymous mapping
map1 = sys_mmap(0, size, PROT_READ, MAP_PRIVATE, fd,
p[i].p_offset & -pagesz);
if (map1 < 0) Pexit(exe, map1, "mmap(exec) workaround input");
map2 = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (map2 < 0) Pexit(exe, map2, "mmap(exec) workaround output");
memcpy((void *)map2, (void *)map1, size);
munmap((void *)map1, size);
if (rc == -EPERM) {
Pexit(exe, rc,
"map(exec) failed because SIP (System Integrity Protection) "
"is enabled, but APE Loader was compiled with SIP_DISABLED");
} else {
Pexit(exe, rc, "map(exec) failed");
}
}
#else
// the issue is that if sip is enabled then, attempting to map
// it with exec permission will cause xnu to phone home a hash
// of the entire file to apple intelligence as a one time cost
// which is literally minutes for executables holding big data
// since there's no public apple api for detecting sip we read
// as the default strategy which is slow but it works for both
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
#endif
} else {
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
if (rc < 0) Pexit(exe, rc, "prog mmap");
@@ -877,6 +891,7 @@ int main(int argc, char **argv, char **envp) {
M->lib.pthread_jit_write_protect_supported_np =
pthread_jit_write_protect_supported_np;
M->lib.pthread_jit_write_protect_np = pthread_jit_write_protect_np_workaround;
M->lib.sys_icache_invalidate = sys_icache_invalidate;
M->lib.pthread_create = pthread_create;
M->lib.pthread_exit = pthread_exit;
M->lib.pthread_kill = pthread_kill;
@@ -888,7 +903,7 @@ int main(int argc, char **argv, char **envp) {
M->lib.dispatch_walltime = dispatch_walltime;
M->lib.pthread_self = pthread_self;
M->lib.dispatch_release = dispatch_release;
M->lib.raise = raise;
M->lib.raise = sys_raise;
M->lib.pthread_join = pthread_join;
M->lib.pthread_yield_np = pthread_yield_np;
M->lib.pthread_stack_min = PTHREAD_STACK_MIN;
@@ -933,6 +948,21 @@ int main(int argc, char **argv, char **envp) {
sp = (long *)(argv - 1);
auxv = (long *)(envp + i + 1);
/* create new bottom of stack for spawned program
system v abi aligns this on a 16-byte boundary
grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}
memmove(sp2, sp, (auxv - sp) * sizeof(long));
argv = (char **)(sp2 + 1);
envp = (char **)(sp2 + 1 + argc + 1);
auxv = sp2 + (auxv - sp);
sp = sp2;
/* interpret command line arguments */
if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
/* if the first argument is a hyphen then we give the user the
@@ -955,21 +985,6 @@ int main(int argc, char **argv, char **envp) {
argv = (char **)((sp += 1) + 1);
}
/* create new bottom of stack for spawned program
system v abi aligns this on a 16-byte boundary
grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}
memmove(sp2, sp, (auxv - sp) * sizeof(long));
argv = (char **)(sp2 + 1);
envp = (char **)(sp2 + 1 + argc + 1);
auxv = sp2 + (auxv - sp);
sp = sp2;
/* allocate ephemeral memory for reading file */
n = sizeof(union ElfEhdrBuf);
ebuf = (union ElfEhdrBuf *)__builtin_alloca(n);
+15 -11
View File
@@ -592,7 +592,9 @@ ape_disk:
#ifdef APE_IS_SHELL_SCRIPT
apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.ascii "m=\"$(uname -m)\"\n"
.ascii "m=$(/bin/uname -m 2>/dev/null) || "
.ascii "m=$(/usr/bin/uname -m 2>/dev/null) || "
.ascii "m=x86_64\n"
.ascii "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]; then\n"
// Until all operating systems can be updated to support APE,
@@ -615,15 +617,15 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.ascii APE_VERSION_STR
.ascii "\"\n"
.ascii "[ -x \"$t\" ] || {\n"
.ascii "mkdir -p \"${t%/*}\" &&\n"
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
.ascii "/bin/mkdir -p \"${t%/*}\" &&\n"
.ascii "/bin/dd if=\"$o\" of=\"$t.$$\" skip="
.shstub ape_loader_dd_skip,2
.ascii " count="
.shstub ape_loader_dd_count,2
.ascii " bs=64 2>/dev/null\n"
#if SupportsXnu()
.ascii "[ -d /Applications ] && "
.ascii "dd if=\"$t.$$\""
.ascii "/bin/dd if=\"$t.$$\""
.ascii " of=\"$t.$$\""
.ascii " skip=5"
.ascii " count=8"
@@ -631,8 +633,8 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.ascii " conv=notrunc"
.ascii " 2>/dev/null\n"
#endif /* SupportsXnu() */
.ascii "chmod 755 \"$t.$$\"\n"
.ascii "mv -f \"$t.$$\" \"$t\"\n"
.ascii "/bin/chmod 755 \"$t.$$\"\n"
.ascii "/bin/mv -f \"$t.$$\" \"$t\"\n"
.ascii "}\n"
.ascii "exec \"$t\" \"$o\" \"$@\"\n"
.ascii "}\n"
@@ -648,9 +650,9 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.ascii "t=\"${TMPDIR:-${HOME:-.}}/$0\"\n"
.ascii "[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n"
.ascii "[ x\"$1\" != x--assimilate ] && {\n"
.ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n"
.ascii "cp -f \"$o\" \"$t.$$\" &&\n"
.ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n"
.ascii "/bin/mkdir -p \"${t%/*}\" 2>/dev/null\n"
.ascii "/bin/cp -f \"$o\" \"$t.$$\" &&\n"
.ascii "/bin/mv -f \"$t.$$\" \"$t\" || exit 120\n"
.ascii "o=\"$t\"\n"
.ascii "}\n"
#endif /* APE_NO_MODIFY_SELF */
@@ -681,7 +683,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.ascii "exec 7<&-\n"
#if SupportsXnu()
.ascii "[ -d /Applications ] && "
.ascii "dd if=\"$o\""
.ascii "/bin/dd if=\"$o\""
.ascii " of=\"$o\""
.ascii " bs=8"
.ascii " skip="
@@ -710,7 +712,9 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
// because they need to be in the first 4096 bytes
.section .emushprologue,"a",@progbits
emush: .ascii "\n@\n#'\"\n"
.ascii "s=\"$(uname -s)\"\n"
.ascii "s=$(/bin/uname -s 2>/dev/null) || "
.ascii "s=$(/usr/bin/uname -s 2>/dev/null) || "
.ascii "s=Darwin\n"
// our script is running on a non-x86_64 architecture
// 1. `dd` out the appropriate blink vm blob
// 2. gunzip the blink virtual machine executable
-1
View File
@@ -1 +0,0 @@
../bin/ape-install
+148
View File
@@ -0,0 +1,148 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
TMPDIR=${TMPDIR:-/tmp}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ "$(id -u)" -eq 0 ]; then
SUDO=
else
SUDO=sudo
fi
echo "Actually Portable Executable (APE) Installer" >&2
echo "Author: Justine Tunney <[email protected]>" >&2
# special installation process for apple silicon
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
if [ ! -d /usr/local/bin ]; then
echo "$SUDO mkdir -p /usr/local/bin" >&2
$SUDO mkdir -p /usr/local/bin || exit
fi
echo "$SUDO mv -f $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
$SUDO mv -f "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
exit
fi
################################################################################
# INSTALL APE LOADER SYSTEMWIDE
if [ -f o/depend ] && make -j8 o//ape; then
echo "successfully recompiled ape loader" >&2
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
echo "using ape loader you compiled earlier" >&2
elif [ -d build/bootstrap ]; then
# if make isn't being used then it's unlikely the user changed the sources
# in that case the prebuilt binaries should be completely up-to-date
echo "using prebuilt ape loader from cosmo repo" >&2
mkdir -p o//ape || exit
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
else
echo "no cosmopolitan libc repository here" >&2
echo "fetching ape loader from justine.lol" >&2
mkdir -p o//ape || exit
if command -v wget >/dev/null 2>&1; then
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
else
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
fi
chmod +x o//ape/ape.elf || exit
chmod +x o//ape/ape.macho || exit
fi
if [ "$(uname -s)" = "Darwin" ]; then
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
echo >&2
echo "installing o//ape/ape.macho to /usr/bin/ape" >&2
echo "$SUDO cp -f o//ape/ape.macho /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
echo "done" >&2
fi
else
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
echo >&2
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
echo "done" >&2
fi
fi
################################################################################
# REGISTER APE LOADER WITH BINFMT_MISC TOO (LINUX-ONLY)
if [ x"$(uname -s)" = xLinux ]; then
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
echo >&2
echo it looks like APE is already registered with binfmt_misc >&2
echo To reinstall please run ape/apeuninstall.sh first >&2
echo please check that it is mapped to ape not /bin/sh >&2
echo cat /proc/sys/fs/binfmt_misc/APE >&2
cat /proc/sys/fs/binfmt_misc/APE >&2
exit
fi
if ! [ -e /proc/sys/fs/binfmt_misc ]; then
echo >&2
echo loading binfmt_misc into your kernel >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO modprobe binfmt_misc >&2
$SUDO modprobe binfmt_misc || exit
echo done >&2
fi
if ! [ -e /proc/sys/fs/binfmt_misc/register ]; then
echo >&2
echo mounting binfmt_misc into your kernel >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc >&2
$SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc || exit
echo done >&2
fi
echo >&2
echo registering APE with binfmt_misc >&2
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-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
echo >&2
echo enabling binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' >&2
$SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' || exit
echo done >&2
fi
fi
################################################################################
{
echo
echo "------------------------------------------------------------------"
echo
echo "APE INSTALL COMPLETE"
echo
echo "If you decide to uninstall APE later on"
echo "you may do so using ape/apeuninstall.sh"
echo
echo "Enjoy your APE loader (>'.')>"
echo
} >&2
-1
View File
@@ -1 +0,0 @@
../bin/ape-uninstall
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ "$UID" = "0" ]; then
SUDO=
else
SUDO=sudo
fi
{
echo
echo "APE Uninstaller intends to run (in pseudo-shell)"
echo
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc."
echo
echo "You may then use ape/apeinstall.sh to reinstall it"
echo
} >&2
set -ex
for f in /proc/sys/fs/binfmt_misc/APE*; do
if [ -f $f ]; then
$SUDO sh -c "echo -1 >$f" || exit
fi
done
# system installation
if [ -f /usr/bin/ape ]; then
$SUDO rm -f /usr/bin/ape
fi
if [ -f /usr/local/bin/ape ]; then
$SUDO rm -f /usr/local/bin/ape
fi
# legacy installations
rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape"
# ad-hoc installations
for x in .ape \
.ape-1.1 \
.ape-1.3 \
.ape-1.4 \
.ape-1.5 \
.ape-1.6 \
.ape-1.7 \
.ape-1.8 \
.ape-1.9 \
.ape-blink-0.9.2 \
.ape-blink-1.0.0; do
rm -f \
~/$x \
/tmp/$x \
o/tmp/$x \
"${TMPDIR:-/tmp}/$x"
done
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-addr2line"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-1
View File
@@ -1 +0,0 @@
apecopy
-21
View File
@@ -1,21 +0,0 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
fatal_error() {
echo "$PROG: $1" >&2
exit 1
}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
if [ ! -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" ]; then
fatal_error "you need to run: aarch64-unknown-cosmo-cc --update"
fi
exec "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-as"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-nm"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objcopy"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objdump"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-${m:-aarch64}}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-strip"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-148
View File
@@ -1,148 +0,0 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
TMPDIR=${TMPDIR:-/tmp}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ "$(id -u)" -eq 0 ]; then
SUDO=
else
SUDO=sudo
fi
echo "Actually Portable Executable (APE) Installer" >&2
echo "Author: Justine Tunney <[email protected]>" >&2
# special installation process for apple silicon
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
if [ ! -d /usr/local/bin ]; then
echo "$SUDO mkdir -p /usr/local/bin" >&2
$SUDO mkdir -p /usr/local/bin || exit
fi
echo "$SUDO mv -f $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
$SUDO mv -f "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
exit
fi
################################################################################
# INSTALL APE LOADER SYSTEMWIDE
if [ -f o/depend ] && make -j8 o//ape; then
echo "successfully recompiled ape loader" >&2
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
echo "using ape loader you compiled earlier" >&2
elif [ -d build/bootstrap ]; then
# if make isn't being used then it's unlikely the user changed the sources
# in that case the prebuilt binaries should be completely up-to-date
echo "using prebuilt ape loader from cosmo repo" >&2
mkdir -p o//ape || exit
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
else
echo "no cosmopolitan libc repository here" >&2
echo "fetching ape loader from justine.lol" >&2
mkdir -p o//ape || exit
if command -v wget >/dev/null 2>&1; then
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
else
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
fi
chmod +x o//ape/ape.elf || exit
chmod +x o//ape/ape.macho || exit
fi
if [ "$(uname -s)" = "Darwin" ]; then
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
echo >&2
echo "installing o//ape/ape.macho to /usr/bin/ape" >&2
echo "$SUDO cp -f o//ape/ape.macho /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
echo "done" >&2
fi
else
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
echo >&2
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
echo "done" >&2
fi
fi
################################################################################
# REGISTER APE LOADER WITH BINFMT_MISC TOO (LINUX-ONLY)
if [ x"$(uname -s)" = xLinux ]; then
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
echo >&2
echo it looks like APE is already registered with binfmt_misc >&2
echo To reinstall please run ape/apeuninstall.sh first >&2
echo please check that it is mapped to ape not /bin/sh >&2
echo cat /proc/sys/fs/binfmt_misc/APE >&2
cat /proc/sys/fs/binfmt_misc/APE >&2
exit
fi
if ! [ -e /proc/sys/fs/binfmt_misc ]; then
echo >&2
echo loading binfmt_misc into your kernel >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO modprobe binfmt_misc >&2
$SUDO modprobe binfmt_misc || exit
echo done >&2
fi
if ! [ -e /proc/sys/fs/binfmt_misc/register ]; then
echo >&2
echo mounting binfmt_misc into your kernel >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc >&2
$SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc || exit
echo done >&2
fi
echo >&2
echo registering APE with binfmt_misc >&2
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-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
echo >&2
echo enabling binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo $SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' >&2
$SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' || exit
echo done >&2
fi
fi
################################################################################
{
echo
echo "------------------------------------------------------------------"
echo
echo "APE INSTALL COMPLETE"
echo
echo "If you decide to uninstall APE later on"
echo "you may do so using ape/apeuninstall.sh"
echo
echo "Enjoy your APE loader (>'.')>"
echo
} >&2
-64
View File
@@ -1,64 +0,0 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ "$UID" = "0" ]; then
SUDO=
else
SUDO=sudo
fi
{
echo
echo "APE Uninstaller intends to run (in pseudo-shell)"
echo
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc."
echo
echo "You may then use ape/apeinstall.sh to reinstall it"
echo
} >&2
set -ex
for f in /proc/sys/fs/binfmt_misc/APE*; do
if [ -f $f ]; then
$SUDO sh -c "echo -1 >$f" || exit
fi
done
# system installation
if [ -f /usr/bin/ape ]; then
$SUDO rm -f /usr/bin/ape
fi
if [ -f /usr/local/bin/ape ]; then
$SUDO rm -f /usr/local/bin/ape
fi
# legacy installations
rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape"
# ad-hoc installations
for x in .ape \
.ape-1.1 \
.ape-1.3 \
.ape-1.4 \
.ape-1.5 \
.ape-1.6 \
.ape-1.7 \
.ape-1.8 \
.ape-1.9 \
.ape-blink-0.9.2 \
.ape-blink-1.0.0; do
rm -f \
~/$x \
/tmp/$x \
o/tmp/$x \
"${TMPDIR:-/tmp}/$x"
done
-102
View File
@@ -1,102 +0,0 @@
#!/bin/sh
PROG=${0##*/}
COSMO=${COSMO:-/opt/cosmo}
if [ x"$1" = x"--version" ]; then
cat <<EOF
$PROG 0.1
Copyright (c) 2023 Justine Alexandra Roberts Tunney
Cosmopolitan Libc and LLVM libcxx/compiler-rt are subject to non-GPL
notice licenses, e.g. ISC, MIT, etc. Your compiled programs must embed
our copyright notices. This toolchain is configured to do so default.
Cosmopolitan comes with absolutely NO WARRANTY of any kind.
For more information, see the Cosmopolitan LICENSE files.
Copyright (C) 2019 Free Software Foundation, Inc.
This launches GNU GCC/Binutils subprocesses, which is free software; see
Cosmopolitan's third_party/gcc/ for source code and copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
EOF
exit
fi
if [ x"$1" = x"--help" ]; then
cat <<EOF
Usage: $PROG INPUT OUTPUT
Converts an executable linked by cosmocc to the Actually Portable
Executable file format. See $PROG --version for other details.
EOF
exit
fi
fatal_error() {
echo "$PROG: fatal error: $1" >&2
echo "operation terminated." >&2
exit 1
}
CROSS=1
ARCH=${PROG%%-*} # split(prog, '-')[0]
if [ x"$ARCH" = x"$PROG" ]; then
ARCH=x86_64
CROSS=0
fi
if [ x"$ARCH" = x"x86_64" ]; then
MODE=${MODE:-$m}
else
MODE=${MODE:-${m:-$ARCH}}
fi
if [ $CROSS -eq 0 ]; then
COSMOS=${COSMOS:-/opt/cosmos}
else
COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
fi
if [ x"$ARCH" = x"x86_64" ]; then
OBJCOPYFLAGS="-S -O binary"
elif [ x"$ARCH" = x"aarch64" ]; then
OBJCOPYFLAGS="-S"
else
fatal_error "$ARCH: unsupported architecture"
fi
if [ ! -d "$COSMO" ]; then
fatal_error "you need to clone cosmopolitan to your $COSMO directory"
fi
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
if [ ! -f "$COSMO/o//tool/build/zipcopy.com" ] ||
[ ! -f "$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" ]; then
if [ $CROSS -eq 0 ]; then
fatal_error "you need to run: cosmocc --update"
else
fatal_error "you need to run: $ARCH-unknown-cosmo-cosmocc --update"
fi
fi
INPUT=$1
OUTPUT=$2
if [ ! -f "$INPUT" ]; then
fatal_error "$INPUT: missing input and output arguments"
elif [ ! -f "$INPUT" ]; then
fatal_error "$INPUT: no such file"
elif [ ! -f "$INPUT" ]; then
fatal_error "$INPUT: missing output argument"
elif [ x"$INPUT" = x"$OUTPUT" ]; then
fatal_error "$INPUT: input and output file can't be the same"
fi
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" \
$OBJCOPYFLAGS \
"$INPUT" \
"$OUTPUT" || exit
"$COSMO/o//tool/build/zipcopy.com" \
"$INPUT" \
"$OUTPUT" || exit
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
COSMO=${COSMO:-/opt/cosmo}
exec "$COSMO/o//tool/build/apelink.com" "$@"
-31
View File
@@ -1,31 +0,0 @@
#!/bin/sh
COSMO=${COSMO:-/opt/cosmo}
set -- -apifCe "$@"
if [ -n "$ADDR2LINE" ]; then
exec "$ADDR2LINE" "$@"
fi
find_addr2line() {
if [ -x o/third_party/gcc/bin/$1-linux-cosmo-addr2line ]; then
ADDR2LINE=o/third_party/gcc/bin/$1-linux-cosmo-addr2line
elif [ -x o/third_party/gcc/bin/$1-linux-musl-addr2line ]; then
ADDR2LINE=o/third_party/gcc/bin/$1-linux-musl-addr2line
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line" ]; then
ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line"
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line" ]; then
ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line"
else
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
exit 1
fi
}
for ARCH in x86_64 aarch64; do
find_addr2line $ARCH
"$ADDR2LINE" "$@" 2>/dev/null && exit
done
echo "error: addr2line failed" >&2
exit 1
-1
View File
@@ -1 +0,0 @@
fatcosmocc
-1
View File
@@ -1 +0,0 @@
fatcosmoar
-1
View File
@@ -1 +0,0 @@
fatcosmocc
-1
View File
@@ -1 +0,0 @@
fatcosmocc
-1
View File
@@ -1 +0,0 @@
fatcosmoinstall
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-addr2line"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-1
View File
@@ -1 +0,0 @@
apecopy
-22
View File
@@ -1,22 +0,0 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
fatal_error() {
echo "$PROG: $1" >&2
exit 1
}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" ]; then
fatal_error "you need to run: x86_64-unknown-cosmo-cc --update"
fi
exec "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-as"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-1
View File
@@ -1 +0,0 @@
cosmocc
-1
View File
@@ -1 +0,0 @@
cosmocc
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-nm"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objcopy"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objdump"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
BRAND=musl
else
BRAND=cosmo
fi
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-strip"
if [ ! -x "$TOOL" ]; then
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
exit 1
fi
exec "$TOOL" "$@"
Binary file not shown.
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -222,7 +222,8 @@ DEFAULT_CPPFLAGS += \
-D_COSMO_SOURCE \
-DMODE='"$(MODE)"' \
-nostdinc \
-iquote .
-iquote. \
-isystem libc/isystem
DEFAULT_CFLAGS = \
-std=gnu2x
-1
View File
@@ -17,7 +17,6 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/tty/tty.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
+1
View File
@@ -19,6 +19,7 @@
#include "dsp/tty/tty.h"
#include "libc/mem/arraylist2.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/x/x.h"
/* TODO(jart): DELETE */
+8 -7
View File
@@ -10,20 +10,21 @@
#include "libc/calls/calls.h"
#include "libc/dlopen/dlfcn.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/runtime.h"
/**
* @fileoverview cosmopolitan dynamic runtime linking demo
*
* Our dlopen() interface currently supports:
* Our cosmo_dlopen() interface currently supports:
*
* - x86-64 Linux w/ Glibc
* - x86-64 Linux w/ Musl Libc
* - x86-64 FreeBSD
* - x86-64 Windows
* - x86-64 NetBSD
* - aarch64 Linux w/ Glibc
* - aarch64 Linux w/ Musl Libc
* - aarch64 MacOS
*
*/
@@ -31,16 +32,16 @@
int main(int argc, char **argv, char **envp) {
// open the host system's zlib library
void *libc = dlopen("libz.so", RTLD_LAZY);
void *libc = cosmo_dlopen("libz.so", RTLD_LAZY);
if (!libc) {
tinyprint(2, dlerror(), "\n", NULL);
tinyprint(2, cosmo_dlerror(), "\n", NULL);
exit(1);
}
// load crc() function address
unsigned (*crc32)(unsigned, void *, int) = dlsym(libc, "crc32");
unsigned (*crc32)(unsigned, void *, int) = cosmo_dlsym(libc, "crc32");
if (!crc32) {
tinyprint(2, dlerror(), "\n", NULL);
tinyprint(2, cosmo_dlerror(), "\n", NULL);
exit(1);
}
@@ -50,6 +51,6 @@ int main(int argc, char **argv, char **envp) {
tinyprint(1, "crc(hi) = ", ibuf, "\n", NULL);
// mop up
dlclose(libc);
cosmo_dlclose(libc);
exit(0);
}
-2
View File
@@ -100,8 +100,6 @@ EXAMPLES_DIRECTDEPS = \
EXAMPLES_DEPS := \
$(call uniq,$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x))))
$(EXAMPLES_OBJS): override CFLAGS += -isystem libc/isystem
o/$(MODE)/examples/examples.pkg: \
$(EXAMPLES_OBJS) \
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
+2 -37
View File
@@ -7,8 +7,9 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#ifdef __COSMOCC__
#ifndef _COSMO_SOURCE
#define _COSMO_SOURCE
#endif
#include <assert.h>
#include <cosmo.h>
#include <errno.h>
@@ -22,42 +23,6 @@
#include <sys/auxv.h>
#include <sys/socket.h>
#include <time.h>
#else
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/pledge.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/consts/timer.h"
#include "libc/thread/thread.h"
#include "libc/thread/thread2.h"
#include "net/http/http.h"
#endif
/**
* @fileoverview greenbean lightweight threaded web server
-1
View File
@@ -9,7 +9,6 @@
#endif
#include "libc/runtime/runtime.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "third_party/hiredis/hiredis.h"
-1
View File
@@ -62,7 +62,6 @@ Contact: [email protected]\"\n\
#include "libc/calls/termios.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/mem/alg.h"
#include "libc/mem/arraylist2.internal.h"
-1
View File
@@ -19,7 +19,6 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/inttypes.h"
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
do { \
type val; int ret; \
ret = sscanf(str, scan_fmt, &val); \
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
} while (0)
int main()
{
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
PARSE_AND_PRINT(float, "%f", "%f", "3715");
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
PARSE_AND_PRINT(float, "%f", "%f", "inF");
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
PARSE_AND_PRINT(float, "%f", "%f", "junk");
return 0;
}
-1
View File
@@ -33,7 +33,6 @@
*/
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
-1
View File
@@ -12,7 +12,6 @@
#include "libc/calls/struct/timeval.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
-1
View File
@@ -11,7 +11,6 @@
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
-1
View File
@@ -8,7 +8,6 @@
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/stdio/append.h"
-1
View File
@@ -15,7 +15,6 @@
#include "libc/calls/struct/sigset.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
-1
View File
@@ -122,7 +122,6 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/log/log.h"
-1
View File
@@ -11,7 +11,6 @@
#include "libc/calls/struct/timespec.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
#include "libc/stdio/stdio.h"
+10 -7
View File
@@ -14,7 +14,8 @@
#define _ASSERT_H
COSMOPOLITAN_C_START_
void __assert_fail(const char *, const char *, int) wontreturn relegated;
void __assert_fail(const char *, const char *, int);
void unassert(const char *, const char *, int);
#ifdef NDEBUG
#define assert(x) ((void)0)
@@ -31,12 +32,14 @@ void __assert_fail(const char *, const char *, int) wontreturn relegated;
#ifndef NDEBUG
#define unassert(x) __assert_macro(x, #x)
#define npassert(x) __assert_macro(x, #x)
#define __assert_macro(x, s) \
({ \
if (__builtin_expect(!(x), 0)) { \
__assert_fail(s, __FILE__, __LINE__); \
} \
(void)0; \
#define __assert_macro(x, s) \
({ \
if (__builtin_expect(!(x), 0)) { \
(unassert)(s, __FILE__, __LINE__); \
__asm__("nop"); \
__builtin_unreachable(); \
} \
(void)0; \
})
#else
#define npassert(x) \
@@ -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 2020 Justine Alexandra Roberts Tunney │
│ Copyright 2023 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,24 +16,13 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/limits.h"
#include "libc/mem/reverse.internal.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/intrin/popcnt.h"
/**
* Converts unsigned 64-bit integer to octal string.
* @param a needs at least 24 bytes
* @return bytes written w/o nul
*/
dontinline size_t uint64toarray_radix8(uint64_t i, char a[hasatleast 24]) {
size_t j;
j = 0;
do {
a[j++] = i % 8 + '0';
i /= 8;
} while (i > 0);
a[j] = '\0';
reverse(a, j);
return j;
int CPU_COUNT_S(size_t size, const cpu_set_t *set) {
int i, c = 0;
for (i = 0; i < size / sizeof(*set->__bits); i++) {
c += popcnt(set->__bits[i]);
}
return c;
}
+3 -2
View File
@@ -23,6 +23,7 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/**
* Handles assert() failure.
@@ -31,8 +32,8 @@ void __assert_fail(const char *expr, const char *file, int line) {
char ibuf[12];
sigset_t m = __sig_block();
FormatInt32(ibuf, line);
tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed (",
program_invocation_short_name, " ",
tinyprint(2, file, ":", ibuf, ": \e[31;1massert(", expr,
") failed\e[0m (cosmoaddr2line ", FindDebugBinary(), " ",
DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL);
__sig_unblock(m);
abort();
-1
View File
@@ -201,7 +201,6 @@ int setresuid(unsigned, unsigned, unsigned);
int getresgid(unsigned *, unsigned *, unsigned *);
int getresuid(unsigned *, unsigned *, unsigned *);
char *get_current_dir_name(void) __wur;
int sync_file_range(int, int64_t, int64_t, unsigned);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
int memfd_create(const char *, unsigned int);
int execvpe(const char *, char *const[], char *const[]);
+2
View File
@@ -146,6 +146,8 @@ o/$(MODE)/libc/calls/stackjump.o: libc/calls/stackjump.S
o/$(MODE)/libc/calls/sched_yield.o: libc/calls/sched_yield.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/calls/uname.o: libc/integral/normalize.inc
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
+1 -4
View File
@@ -20,9 +20,8 @@
#include "libc/intrin/atomic.h"
#include "libc/intrin/weaken.h"
#include "libc/thread/posixthread.internal.h"
#ifdef __x86_64__
textwindows int _check_cancel(void) {
int _check_cancel(void) {
if (_weaken(_pthread_cancel_ack) && //
_pthread_self() && !(_pthread_self()->pt_flags & PT_NOCANCEL) &&
atomic_load_explicit(&_pthread_self()->pt_canceled,
@@ -31,5 +30,3 @@ textwindows int _check_cancel(void) {
}
return 0;
}
#endif /* __x86_64__ */
+5 -1
View File
@@ -40,7 +40,11 @@ static dontinline int __clk_tck_init(void) {
size_t len;
struct clockinfo_netbsd clock;
if (IsWindows()) {
x = 1000;
// MSVC defines CLK_TCK as 1000 but 1ms is obviously not the
// scheduling quantum Windows actually uses. If we define it
// as 30 rather than 1000, then clock_nanosleep is much more
// accurately able to predict the duration of its busy waits
x = 30;
} else if (IsXnu() || IsOpenbsd()) {
x = 100;
} else if (IsFreebsd()) {
+12 -6
View File
@@ -25,14 +25,20 @@
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real,
int64_t real_coarse, int64_t boot) {
ts->tv_sec = 0;
if (clock == CLOCK_REALTIME) {
ts->tv_sec = 0;
ts->tv_nsec = real;
return 0;
} else if (clock == CLOCK_REALTIME_COARSE) {
ts->tv_nsec = real_coarse;
return 0;
} else if (clock == CLOCK_MONOTONIC) {
ts->tv_sec = 0;
ts->tv_nsec = 1;
ts->tv_nsec = 10;
return 0;
} else if (clock == CLOCK_BOOTTIME) {
ts->tv_nsec = boot;
return 0;
} else {
return einval();
@@ -40,11 +46,11 @@ static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
}
static int sys_clock_getres_nt(int clock, struct timespec *ts) {
return sys_clock_getres_poly(clock, ts, 100);
return sys_clock_getres_poly(clock, ts, 100, 1000000, 1000000);
}
static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
return sys_clock_getres_poly(clock, ts, 1000);
return sys_clock_getres_poly(clock, ts, 1000, 1000, 1000);
}
/**
+50 -15
View File
@@ -18,26 +18,61 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/wintime.internal.h"
#include "libc/nt/struct/filetime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/clock.h"
#define _CLOCK_REALTIME 0
#define _CLOCK_MONOTONIC 1
#define _CLOCK_REALTIME_COARSE 2
#define _CLOCK_BOOTTIME 3
static struct {
uint64_t base;
uint64_t freq;
} g_winclock;
textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
uint64_t t;
struct NtFileTime ft;
if (clock == CLOCK_REALTIME) {
if (!ts) return 0;
GetSystemTimeAsFileTime(&ft);
*ts = FileTimeToTimeSpec(ft);
return 0;
} else if (clock == CLOCK_MONOTONIC) {
if (!ts) return 0;
return sys_clock_gettime_mono(ts);
} else if (clock == CLOCK_BOOTTIME) {
if (ts) *ts = timespec_frommillis(GetTickCount64());
return 0;
} else {
return -EINVAL;
switch (clock) {
case _CLOCK_REALTIME:
if (ts) {
GetSystemTimePreciseAsFileTime(&ft);
*ts = FileTimeToTimeSpec(ft);
}
return 0;
case _CLOCK_REALTIME_COARSE:
if (ts) {
GetSystemTimeAsFileTime(&ft);
*ts = FileTimeToTimeSpec(ft);
}
return 0;
case _CLOCK_MONOTONIC:
if (ts) {
QueryPerformanceCounter(&t);
t = ((t - g_winclock.base) * 1000000000) / g_winclock.freq;
*ts = timespec_fromnanos(t);
}
return 0;
case _CLOCK_BOOTTIME:
if (ts) {
*ts = timespec_frommillis(GetTickCount64());
}
return 0;
default:
return -EINVAL;
}
}
static textstartup void winclock_init() {
if (IsWindows()) {
QueryPerformanceCounter(&g_winclock.base);
QueryPerformanceFrequency(&g_winclock.freq);
}
}
const void *const winclock_ctor[] initarray = {
winclock_init,
};
+13 -3
View File
@@ -18,6 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
@@ -27,6 +28,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/clktck.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
@@ -108,9 +110,17 @@ static int cosmo_clock_nanosleep(int clock, int flags,
}
// spin through final scheduling quantum
do unassert(!clock_gettime(time_clock, &now));
while (timespec_cmp(now, deadline) < 0);
return 0;
int rc = 0;
ftrace_enabled(-1);
do {
if (_check_cancel()) {
rc = -1;
break;
}
unassert(!clock_gettime(time_clock, &now));
} while (timespec_cmp(now, deadline) < 0);
ftrace_enabled(+1);
return rc;
}
/**
+2
View File
@@ -18,6 +18,8 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
uint32_t flags) {
+2
View File
@@ -17,8 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/limits.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/files.h"
#include "libc/str/str.h"
textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
int flags) {
+6 -1
View File
@@ -29,6 +29,11 @@
/**
* Blocks until kernel flushes non-metadata buffers for fd to disk.
*
* NOTE: For `IsXnu()` it's recommended that `fcntl(F_FULLFSYNC)` be
* favored instead of this function, and if that fails, the fallback
* path should call `fsync()` see the SQLite codebase. In the future
* Cosmopolitan might do this automatically.
*
* @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
@@ -37,8 +42,8 @@
* @raise EBADF if `fd` isn't an open file
* @raise EINTR if signal was delivered
* @raise EIO if an i/o error happened
* @see sync(), fsync(), sync_file_range()
* @see __nosync to secretly disable
* @see sync(), fsync()
* @cancelationpoint
* @asyncsignalsafe
*/
@@ -20,13 +20,17 @@
#include "libc/atomic.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/tinyelf.internal.h"
#include "libc/errno.h"
#include "libc/intrin/bits.h"
#include "libc/macros.internal.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
@@ -38,24 +42,57 @@ static struct {
char buf[PATH_MAX];
} g_comdbg;
static const char *kDbgExts[] = {
".dbg",
".com.dbg",
#ifdef __aarch64__
".aarch64.elf",
#elif defined(__powerpc64__)
".ppc64.elf",
#endif
};
static int GetElfMachine(void) {
#ifdef __x86_64__
return EM_NEXGEN32E;
#elif defined(__aarch64__)
return EM_AARCH64;
#elif defined(__powerpc64__)
return EM_PPC64;
#elif defined(__riscv)
return EM_RISCV;
#elif defined(__s390x__)
return EM_S390;
#else
#error "unsupported architecture"
#endif
}
static bool IsMyDebugBinary(const char *path) {
void *map;
int64_t size;
uintptr_t value;
bool res = false;
int fd, e = errno;
struct DirectMap dm;
BLOCK_CANCELATION;
if ((fd = open(path, O_RDONLY | O_CLOEXEC, 0)) != -1) {
// sanity test that this .com.dbg file (1) is an elf image, and (2)
// contains the same number of bytes of code as our .com executable
// which is currently running in memory.
if ((size = lseek(fd, 0, SEEK_END)) != -1 &&
(map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
if (READ32LE((char *)map) == READ32LE("\177ELF") &&
GetElfSymbolValue(map, "_etext", &value)) {
(dm = sys_mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)).addr !=
MAP_FAILED) {
if (READ32LE((char *)dm.addr) == READ32LE("\177ELF") &&
((Elf64_Ehdr *)dm.addr)->e_machine == GetElfMachine() &&
GetElfSymbolValue(dm.addr, "_etext", &value)) {
res = !_etext || value == (uintptr_t)_etext;
}
munmap(map, size);
if (!IsWindows()) {
sys_munmap(dm.addr, size);
} else {
CloseHandle(dm.maphandle);
UnmapViewOfFile(dm.addr);
}
}
close(fd);
}
@@ -65,20 +102,21 @@ static bool IsMyDebugBinary(const char *path) {
}
static void FindDebugBinaryInit(void) {
char *p = GetProgramExecutableName();
size_t n = strlen(p);
if ((n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) ||
IsMyDebugBinary(p)) {
g_comdbg.res = p;
} else if (n + 4 < ARRAYLEN(g_comdbg.buf)) {
mempcpy(mempcpy(g_comdbg.buf, p, n), ".dbg", 5);
const char *comdbg;
if ((comdbg = getenv("COMDBG")) && IsMyDebugBinary(comdbg)) {
g_comdbg.res = comdbg;
return;
}
char *prog = GetProgramExecutableName();
for (int i = 0; i < ARRAYLEN(kDbgExts); ++i) {
strlcpy(g_comdbg.buf, prog, sizeof(g_comdbg.buf));
strlcat(g_comdbg.buf, kDbgExts[i], sizeof(g_comdbg.buf));
if (IsMyDebugBinary(g_comdbg.buf)) {
g_comdbg.res = g_comdbg.buf;
return;
}
}
if (!g_comdbg.res) {
g_comdbg.res = getenv("COMDBG");
}
g_comdbg.res = prog;
}
/**
+1 -1
View File
@@ -37,8 +37,8 @@
* @raise EBADF if `fd` isn't an open file
* @raise EINTR if signal was delivered
* @raise EIO if an i/o error happened
* @see fdatasync(), sync_file_range()
* @see __nosync to secretly disable
* @see fdatasync()
* @cancelationpoint
* @asyncsignalsafe
*/
-6
View File
@@ -20,12 +20,6 @@
// Gets machine state.
//
// This function goes 14x slower if sigaction() has ever been used to
// install a signal handling function. If you don't care about signal
// safety and just want fast fibers, then you may override the global
// variable `__interruptible` to disable the sigprocmask() calls, for
// pure userspace context switching.
//
// @return 0 on success, or -1 w/ errno
// @see makecontext()
// @see swapcontext()
+1 -1
View File
@@ -164,6 +164,6 @@ int __getcwd(char *buf, size_t size) {
} else {
rc = sys_getcwd_metal(buf, size);
}
STRACE("__getcwd([%#hhs], %'zu) → %d% m", rc != -1 ? buf : "n/a", size, rc);
STRACE("getcwd([%#hhs], %'zu) → %d% m", rc != -1 ? buf : "n/a", size, rc);
return rc;
}
+1
View File
@@ -23,6 +23,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/rlimit.h"
+7 -4
View File
@@ -5,6 +5,7 @@
#include "libc/calls/struct/sigval.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/stdbool.h"
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
@@ -31,10 +32,6 @@ int64_t GetConsoleOutputHandle(void);
int IsWindowsExecutable(int64_t, const char16_t *);
void InterceptTerminalCommands(const char *, size_t);
forceinline int64_t __getfdhandleactual(int fd) {
return g_fds.p[fd].handle;
}
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
}
@@ -50,6 +47,12 @@ int _park_norestart(uint32_t, uint64_t);
int _park_restartable(uint32_t, uint64_t);
int sys_openat_metal(int, const char *, int, unsigned);
#ifdef __x86_64__
bool __iswsl1(void);
#else
#define __iswsl1() false
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ */
+1 -1
View File
@@ -75,7 +75,7 @@ static int ioctl_default(int fd, unsigned long request, void *arg) {
return sys_ioctl(fd, request, arg);
} else if (__isfdopen(fd)) {
if (g_fds.p[fd].kind == kFdSocket) {
handle = __getfdhandleactual(fd);
handle = g_fds.p[fd].handle;
if ((rc = _weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) {
return rc;
} else {
+1 -1
View File
@@ -56,6 +56,6 @@ bool32 ischardev(int fd) {
} else {
return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
}
}
+2
View File
@@ -18,9 +18,11 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/limits.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd,
const char *newpath) {
+1
View File
@@ -19,6 +19,7 @@
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/files.h"
#include "libc/str/str.h"
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
char16_t path16[PATH_MAX];
+26 -25
View File
@@ -16,11 +16,17 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
#include "libc/proc/ntspawn.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#define APPEND(c) \
@@ -54,6 +60,12 @@ static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
static bool LooksLikeCosmoDrivePath(const char *s) {
return s[0] == '/' && //
IsAlpha(s[1]) && //
s[2] == '/';
}
// Converts System V argv to Windows-style command line.
//
// Escaping is performed and it's designed to round-trip with
@@ -68,20 +80,31 @@ static inline int IsAlpha(int c) {
// @see libc/runtime/getdosargv.c
// @asyncsignalsafe
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
char *arg;
int slashes, n;
bool needsquote;
size_t i, j, k, s;
char argbuf[PATH_MAX];
for (k = i = 0; argv[i]; ++i) {
if (i) APPEND(u' ');
if ((needsquote = NeedsQuotes(argv[i]))) APPEND(u'"');
if (LooksLikeCosmoDrivePath(argv[i]) &&
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
mungentpath(argbuf);
arg = argbuf;
} else {
arg = argv[i];
}
if ((needsquote = NeedsQuotes(arg))) {
APPEND(u'"');
}
for (slashes = j = 0;;) {
wint_t x = argv[i][j++] & 255;
wint_t x = arg[j++] & 255;
if (x >= 0300) {
n = ThomPikeLen(x);
x = ThomPikeByte(x);
while (--n) {
wint_t y;
if ((y = argv[i][j++] & 255)) {
if ((y = arg[j++] & 255)) {
x = ThomPikeMerge(x, y);
} else {
x = 0;
@@ -90,28 +113,6 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
}
}
if (!x) break;
if (x == '/' || x == '\\') {
if (!i) {
// turn / into \ for first argv[i]
x = '\\';
// turn \c\... into c:\ for first argv[i]
if (k == 2 && IsAlpha(cmdline[1]) && cmdline[0] == '\\') {
cmdline[0] = cmdline[1];
cmdline[1] = ':';
}
} else {
// turn stuff like `less /c/...`
// into `less c:/...`
// turn stuff like `more <"/c/..."`
// into `more <"c:/..."`
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
cmdline[k - 2] = cmdline[k - 1];
cmdline[k - 1] = ':';
}
}
}
if (x == '\\') {
++slashes;
} else if (x == '"') {
+2 -33
View File
@@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/intrin/getenv.internal.h"
#include "libc/mem/alloca.h"
#include "libc/proc/ntspawn.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
@@ -51,38 +52,6 @@ static textwindows int Compare(const char *l, const char *r) {
return a - b;
}
static textwindows void FixPath(char *path) {
char *p;
// turn colon into semicolon
// unless it already looks like a dos path
for (p = path; *p; ++p) {
if (p[0] == ':' && p[1] != '\\') {
p[0] = ';';
}
}
// turn /c/... into c:\...
p = path;
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
p[0] = p[1];
p[1] = ':';
}
for (; *p; ++p) {
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
p[1] = p[2];
p[2] = ':';
}
}
// turn slash into backslash
for (p = path; *p; ++p) {
if (*p == '/') {
*p = '\\';
}
}
}
static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
int c, i, cmp;
char *var, *path = 0;
@@ -101,7 +70,7 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
} while (c);
// fixup key=/c/... → key=c:\...
if (path) FixPath(path);
if (path) mungentpath(path);
// append key=val to sorted list using insertion sort technique
for (i = env->vari;; --i) {
+55
View File
@@ -0,0 +1,55 @@
/*-*- 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 2023 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/proc/ntspawn.h"
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
textwindows void mungentpath(char *path) {
char *p;
// turn colon into semicolon
// unless it already looks like a dos path
for (p = path; *p; ++p) {
if (p[0] == ':' && p[1] != '\\') {
p[0] = ';';
}
}
// turn /c/... into c:\...
p = path;
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
p[0] = p[1];
p[1] = ':';
}
for (; *p; ++p) {
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
p[1] = p[2];
p[2] = ':';
}
}
// turn slash into backslash
for (p = path; *p; ++p) {
if (*p == '/') {
*p = '\\';
}
}
}
+6 -3
View File
@@ -21,6 +21,7 @@
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/syslib.internal.h"
/**
* Unmaps memory directly with system.
@@ -32,10 +33,12 @@
*/
int sys_munmap(void *p, size_t n) {
int rc;
if (!IsMetal()) {
rc = __sys_munmap(p, n);
} else {
if (IsXnuSilicon()) {
rc = _sysret(__syslib->__munmap(p, n));
} else if (IsMetal()) {
rc = sys_munmap_metal(p, n);
} else {
rc = __sys_munmap(p, n);
}
KERNTRACE("sys_munmap(%p /* %s */, %'zu) → %d", p,
DescribeFrame((intptr_t)p >> 16), n, rc);
-1
View File
@@ -24,7 +24,6 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
+2 -1
View File
@@ -126,7 +126,8 @@ textwindows int ntspawn(
if (CreateProcess(sb->path, sb->cmdline, 0, 0, true,
dwCreationFlags | kNtCreateUnicodeEnvironment |
kNtExtendedStartupinfoPresent |
kNtInheritParentAffinity,
kNtInheritParentAffinity |
GetPriorityClass(GetCurrentProcess()),
sb->envblock, opt_lpCurrentDirectory,
&info.StartupInfo, opt_out_lpProcessInformation)) {
rc = 0;
+5 -6
View File
@@ -32,11 +32,7 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) {
int sig;
if (_check_cancel() == -1) return -1;
if ((sig = __sig_get(waitmask))) {
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
if (!restartable || handler_was_called == 1) return eintr();
}
if ((sig = __sig_get(waitmask))) goto HandleSignal;
int expect = 0;
atomic_int futex = 0;
struct PosixThread *pt = _pthread_self();
@@ -45,9 +41,12 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool32 ok = WaitOnAddress(&futex, &expect, sizeof(int), msdelay);
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
if (ok && (sig = __sig_get(waitmask))) {
HandleSignal:
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
if (!restartable || handler_was_called == 1) return eintr();
if (!restartable || (handler_was_called & SIG_HANDLED_NO_RESTART)) {
return eintr();
}
}
return 0;
}
+3 -1
View File
@@ -55,6 +55,8 @@
#include "libc/thread/tls.h"
#ifdef __x86_64__
#define POLL_INTERVAL_MS 10
// Polls on the New Technology.
//
// This function is used to implement poll() and select(). You may poll
@@ -184,7 +186,7 @@ static textwindows int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
remain = timespec_sub(deadline, now);
millis = timespec_tomillis(remain);
waitfor = MIN(millis, 0xffffffffu);
waitfor = MIN(waitfor, __SIG_POLL_INTERVAL_MS);
waitfor = MIN(waitfor, POLL_INTERVAL_MS);
if (waitfor) {
POLLTRACE("poll() sleeping for %'d out of %'lu ms", waitfor,
timespec_tomillis(remain));
+1 -2
View File
@@ -18,7 +18,6 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/nexgen32e/yield.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/thread/thread.h"
@@ -32,7 +31,7 @@ int pthread_yield(void) {
if (IsXnuSilicon()) {
__syslib->__pthread_yield_np();
} else if (IsOpenbsd()) {
spin_yield(); // sched_yield() is punishingly slow on OpenBSD
pthread_pause_np(); // sched_yield() is punishingly slow on OpenBSD
} else {
sched_yield();
}
+14 -4
View File
@@ -23,6 +23,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
/**
* Sends signal to self.
@@ -33,17 +34,26 @@
*
* Note `SIG_DFL` still results in process death for most signals.
*
* POSIX defines raise() errors as returning non-zero and makes setting
* `errno` optional. Every platform we've tested in our support vector
* returns -1 with `errno` on error (like a normal system call).
*
* @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc.
* @return 0 on success, or nonzero on failure
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `sig` is invalid
* @asyncsignalsafe
*/
int raise(int sig) {
int rc;
if (IsXnuSilicon()) {
rc = __syslib->__raise(sig);
rc = _sysret(__syslib->__raise(sig));
} else if (IsWindows()) {
__sig_raise(sig, SI_TKILL);
rc = 0;
if (0 <= sig && sig <= 64) {
__sig_raise(sig, SI_TKILL);
rc = 0;
} else {
rc = einval();
}
} else {
rc = sys_tkill(gettid(), sig, 0);
}
+64 -84
View File
@@ -16,8 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
@@ -29,14 +27,11 @@
#include "libc/cosmo.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/console.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
@@ -51,6 +46,7 @@
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
@@ -134,7 +130,7 @@ struct Keystrokes {
bool end_of_file;
bool ohno_decckm;
uint16_t utf16hs;
atomic_int_fast16_t used;
int16_t freekeys;
int64_t cin, cot;
struct Dll *list;
struct Dll *line;
@@ -146,16 +142,46 @@ struct Keystrokes {
static struct Keystrokes __keystroke;
textwindows void __keystroke_wipe(void) {
textwindows void WipeKeystrokes(void) {
bzero(&__keystroke, sizeof(__keystroke));
}
static textwindows void FreeKeystrokeImpl(struct Dll *key) {
dll_make_first(&__keystroke.free, key);
++__keystroke.freekeys;
}
static textwindows struct Keystroke *NewKeystroke(void) {
struct Dll *e = dll_first(__keystroke.free);
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.free, &k->elem);
--__keystroke.freekeys;
k->buflen = 0;
return k;
}
static textwindows void FreeKeystroke(struct Dll **list, struct Dll *key) {
dll_remove(list, key);
FreeKeystrokeImpl(key);
}
static textwindows void FreeKeystrokes(struct Dll **list) {
struct Dll *key;
while ((key = dll_first(*list))) {
FreeKeystroke(list, key);
}
}
static textwindows void OpenConsole(void) {
__keystroke.vkt = kVirtualKey;
__keystroke.cin = CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite,
kNtFileShareRead, 0, kNtOpenExisting, 0, 0);
__keystroke.cot = CreateFile(u"CONOUT$", kNtGenericRead | kNtGenericWrite,
kNtFileShareWrite, 0, kNtOpenExisting, 0, 0);
for (int i = 0; i < ARRAYLEN(__keystroke.pool); ++i) {
dll_init(&__keystroke.pool[i].elem);
FreeKeystrokeImpl(&__keystroke.pool[i].elem);
}
}
static textwindows int AddSignal(int sig) {
@@ -413,34 +439,6 @@ static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r,
}
}
static textwindows struct Keystroke *NewKeystroke(void) {
struct Dll *e;
struct Keystroke *k = 0;
int i, n = ARRAYLEN(__keystroke.pool);
if (atomic_load_explicit(&__keystroke.used, memory_order_acquire) < n &&
(i = atomic_fetch_add(&__keystroke.used, 1)) < n) {
k = __keystroke.pool + i;
} else {
if ((e = dll_first(__keystroke.free))) {
k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.free, &k->elem);
}
if (!k) {
if (_weaken(malloc)) {
k = _weaken(malloc)(sizeof(struct Keystroke));
} else {
enomem();
return 0;
}
}
}
if (k) {
bzero(k, sizeof(*k));
dll_init(&k->elem);
}
return k;
}
static textwindows void WriteTty(const char *p, size_t n) {
WriteFile(__keystroke.cot, p, n, 0, 0);
}
@@ -479,8 +477,7 @@ static textwindows bool EraseKeystroke(void) {
struct Dll *e;
if ((e = dll_last(__keystroke.line))) {
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.line, e);
dll_make_first(&__keystroke.free, e);
FreeKeystroke(&__keystroke.line, e);
for (int i = k->buflen; i--;) {
if ((k->buf[i] & 0300) == 0200) continue; // utf-8 cont
EraseCharacter();
@@ -521,11 +518,7 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
}
// allocate object to hold keystroke
struct Keystroke *k;
if (!(k = NewKeystroke())) {
STRACE("out of keystroke memory");
return;
}
struct Keystroke *k = NewKeystroke();
memcpy(k->buf, buf, sizeof(k->buf));
k->buflen = len;
@@ -541,11 +534,11 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
} else {
dll_make_last(&__keystroke.line, &k->elem);
// handle enter in canonical mode
if (len == 1 && buf[0] &&
((buf[0] & 255) == '\n' || //
(buf[0] & 255) == __ttyconf.veol || //
(buf[0] & 255) == __ttyconf.veol2)) {
// flush canonical mode line if oom or enter
if (!__keystroke.freekeys || (len == 1 && buf[0] &&
((buf[0] & 255) == '\n' || //
(buf[0] & 255) == __ttyconf.veol || //
(buf[0] & 255) == __ttyconf.veol2))) {
dll_make_last(&__keystroke.list, __keystroke.line);
__keystroke.line = 0;
}
@@ -556,12 +549,13 @@ static textwindows void IngestConsoleInput(void) {
uint32_t i, n;
struct NtInputRecord records[16];
for (;;) {
if (!__keystroke.freekeys) return;
if (__keystroke.end_of_file) return;
if (!GetNumberOfConsoleInputEvents(__keystroke.cin, &n)) {
goto UnexpectedEof;
}
if (!n) return;
n = MIN(ARRAYLEN(records), n);
n = MIN(__keystroke.freekeys, MIN(ARRAYLEN(records), n));
if (!ReadConsoleInput(__keystroke.cin, records, n, &n)) {
goto UnexpectedEof;
}
@@ -576,19 +570,15 @@ UnexpectedEof:
// Discards all unread stdin bytes.
textwindows int FlushConsoleInputBytes(void) {
int rc;
BLOCK_SIGNALS;
InitConsole();
LockKeystrokes();
FlushConsoleInputBuffer(__keystroke.cin);
dll_make_first(&__keystroke.free, __keystroke.list);
__keystroke.list = 0;
dll_make_first(&__keystroke.free, __keystroke.line);
__keystroke.line = 0;
rc = 0;
FreeKeystrokes(&__keystroke.list);
FreeKeystrokes(&__keystroke.line);
UnlockKeystrokes();
ALLOW_SIGNALS;
return rc;
return 0;
}
// Returns number of stdin bytes that may be read without blocking.
@@ -700,11 +690,10 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
}
if (remain) {
memmove(k->buf, k->buf + got, remain);
k->buflen = remain;
} else {
dll_remove(&__keystroke.list, e);
dll_make_first(&__keystroke.free, e);
FreeKeystroke(&__keystroke.list, e);
}
k->buflen = remain;
if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) {
break;
}
@@ -723,8 +712,6 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
int sig;
int64_t sem;
uint32_t wi, ms = -1;
int handler_was_called;
struct PosixThread *pt;
if (!__ttyconf.vmin) {
if (!__ttyconf.vtime) {
return 0; // non-blocking w/o raising eagain
@@ -732,31 +719,24 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
ms = __ttyconf.vtime * 100;
}
}
if (f->flags & _O_NONBLOCK) {
return eagain(); // standard unix non-blocking
}
if (_check_cancel() == -1) return -1;
if ((sig = __sig_get(waitmask))) {
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
if (handler_was_called != 1) return -2;
return eintr();
}
pt = _pthread_self();
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
if (f->flags & _O_NONBLOCK) return eagain();
if ((sig = __sig_get(waitmask))) goto DeliverSignal;
struct PosixThread *pt = _pthread_self();
pt->pt_blkmask = waitmask;
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
wi = WaitForMultipleObjects(2, (int64_t[2]){__keystroke.cin, sem}, 0, ms);
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
pthread_cleanup_pop(true);
CloseHandle(sem);
if (wi == kNtWaitTimeout) return 0; // vtime elapsed
if (wi == 0) return -2; // console data
if (wi != 1) return __winerr(); // wait failed
if (!(sig = __sig_get(waitmask))) return eintr();
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
DeliverSignal:
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
if (handler_was_called != 1) return -2;
if (!(handler_was_called & SIG_HANDLED_NO_RESTART)) return -2;
return eintr();
}
@@ -774,8 +754,8 @@ static textwindows ssize_t ReadFromConsole(struct Fd *f, void *data,
return rc;
}
textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
int64_t offset, sigset_t waitmask) {
textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
sigset_t waitmask) {
// switch to terminal polyfill if reading from win32 console
struct Fd *f = g_fds.p + fd;
@@ -806,9 +786,9 @@ textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
}
}
static textwindows ssize_t sys_read_nt2(int fd, const struct iovec *iov,
size_t iovlen, int64_t opt_offset,
sigset_t waitmask) {
static textwindows ssize_t ReadIovecs(int fd, const struct iovec *iov,
size_t iovlen, int64_t opt_offset,
sigset_t waitmask) {
ssize_t rc;
size_t i, total;
if (opt_offset < -1) return einval();
@@ -816,8 +796,8 @@ static textwindows ssize_t sys_read_nt2(int fd, const struct iovec *iov,
if (iovlen) {
for (total = i = 0; i < iovlen; ++i) {
if (!iov[i].iov_len) continue;
rc = sys_read_nt_impl(fd, iov[i].iov_base, iov[i].iov_len, opt_offset,
waitmask);
rc =
ReadBuffer(fd, iov[i].iov_base, iov[i].iov_len, opt_offset, waitmask);
if (rc == -1) {
if (total && errno != ECANCELED) {
return total;
@@ -831,7 +811,7 @@ static textwindows ssize_t sys_read_nt2(int fd, const struct iovec *iov,
}
return total;
} else {
return sys_read_nt_impl(fd, NULL, 0, opt_offset, waitmask);
return ReadBuffer(fd, NULL, 0, opt_offset, waitmask);
}
}
@@ -839,7 +819,7 @@ textwindows ssize_t sys_read_nt(int fd, const struct iovec *iov, size_t iovlen,
int64_t opt_offset) {
ssize_t rc;
sigset_t m = __sig_block();
rc = sys_read_nt2(fd, iov, iovlen, opt_offset, m);
rc = ReadIovecs(fd, iov, iovlen, opt_offset, m);
__sig_unblock(m);
return rc;
}
+19 -72
View File
@@ -16,15 +16,12 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/errors.h"
#include "libc/nt/events.h"
@@ -34,28 +31,10 @@
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/stdio/sysparam.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
struct ReadwriteResources {
int64_t handle;
struct NtOverlapped *overlap;
};
static void UnwindReadwrite(void *arg) {
uint32_t got;
struct ReadwriteResources *rwc = arg;
CancelIoEx(rwc->handle, rwc->overlap);
GetOverlappedResult(rwc->handle, rwc->overlap, &got, true);
CloseHandle(rwc->overlap->hEvent);
}
/**
* Runs code that's common to read/write/pread/pwrite/etc on Windows.
*
@@ -64,17 +43,11 @@ static void UnwindReadwrite(void *arg) {
*/
textwindows ssize_t
sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
int64_t handle, uint64_t waitmask,
int64_t handle, sigset_t waitmask,
bool32 ReadOrWriteFile(int64_t, void *, uint32_t, uint32_t *,
struct NtOverlapped *)) {
bool32 ok;
int sig = 0;
int sig;
uint32_t exchanged;
int olderror = errno;
bool eagained = false;
bool canceled = false;
int handler_was_called;
struct PosixThread *pt;
struct Fd *f = g_fds.p + fd;
// win32 i/o apis generally take 32-bit values thus we implicitly
@@ -106,33 +79,26 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
}
RestartOperation:
bool eagained = false;
// check for signals and cancelation
if (_check_cancel() == -1) return -1; // ECANCELED
if ((sig = __sig_get(waitmask))) goto HandleInterrupt;
// signals have already been fully blocked by caller
// perform i/o operation with atomic signal/cancel checking
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 1, 0, 0),
.Pointer = offset};
struct ReadwriteResources rwc = {handle, &overlap};
pthread_cleanup_push(UnwindReadwrite, &rwc);
ok = ReadOrWriteFile(handle, data, size, 0, &overlap);
bool32 ok = ReadOrWriteFile(handle, data, size, 0, &overlap);
if (!ok && GetLastError() == kNtErrorIoPending) {
// win32 says this i/o operation needs to block
if (f->flags & _O_NONBLOCK) {
// abort the i/o operation if file descriptor is in non-blocking mode
CancelIoEx(handle, &overlap);
eagained = true;
} else if (_check_cancel()) {
// _check_cancel() can go three ways:
// 1. it'll return 0 if we're fine and no thread cancelation happened
// 2. it'll pthread_exit() and cleanup, when cancelation was deferred
// 3. it'll return -1 and raise ECANCELED if a cancelation was masked
CancelIoEx(handle, &overlap);
canceled = true;
} else if ((sig = __sig_get(waitmask))) {
// we've dequeued a signal that was pending per caller's old sigmask
// we can't call the signal handler until we release win32 resources
CancelIoEx(handle, &overlap);
} else {
// wait until i/o either completes or is canceled by another thread
// we avoid a race condition by having a second mask for unblocking
struct PosixThread *pt;
pt = _pthread_self();
pt->pt_blkmask = waitmask;
pt->pt_iohandle = handle;
@@ -147,30 +113,13 @@ RestartOperation:
if (ok) {
ok = GetOverlappedResult(handle, &overlap, &exchanged, true);
}
pthread_cleanup_pop(false);
CloseHandle(overlap.hEvent);
// if we acknowledged a pending masked mode cancelation request then
// we must pass it to the caller immediately now that cleanup's done
if (canceled) {
return ecanceled();
}
// if we removed a pending signal then we must raise it
// it's now safe to call a signal handler that longjmps
if (sig) {
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
} else {
handler_was_called = 0;
}
// if i/o succeeded then return its result
if (ok) {
if (!pwriting && seekable) {
f->pointer = offset + exchanged;
}
errno = olderror;
return exchanged;
}
@@ -180,17 +129,15 @@ RestartOperation:
if (eagained) {
return eagain();
}
// at this point the i/o must have been canceled due to a signal.
// this could be because we found the signal earlier and canceled
// ourself. otherwise it's due to a kill from another thread that
// added something to our mask and canceled our i/o, so we check.
if (!handler_was_called && (sig = __sig_get(waitmask))) {
handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1;
}
// read() is @restartable unless non-SA_RESTART hands were called
if (handler_was_called != 1) {
goto RestartOperation;
// otherwise it must be due to a kill() via __sig_cancel()
if ((sig = __sig_get(waitmask))) {
HandleInterrupt:
int handler_was_called = __sig_relay(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1; // possible if we SIGTHR'd
// read() is @restartable unless non-SA_RESTART hands were called
if (!(handler_was_called & SIG_HANDLED_NO_RESTART)) {
goto RestartOperation;
}
}
return eintr();
}
+1
View File
@@ -25,6 +25,7 @@
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
+60 -59
View File
@@ -18,8 +18,6 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/sysv/consts/sig.h"
#include "ape/sections.internal.h"
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
@@ -30,33 +28,26 @@
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bsf.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/popcnt.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/context.h"
#include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/signal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/errors.h"
#include "libc/nt/runtime.h"
#include "libc/nt/signals.h"
#include "libc/nt/struct/context.h"
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/ss.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
/**
@@ -169,53 +160,61 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
}
static textwindows sigaction_f __sig_handler(unsigned rva) {
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
return (sigaction_f)(__executable_start + rva);
}
textwindows int __sig_raise(int sig, int sic) {
textwindows int __sig_raise(volatile int sig, int sic) {
// create machine context object
struct PosixThread *pt = _pthread_self();
ucontext_t ctx = {.uc_sigmask = pt->tib->tib_sigmask};
struct NtContext nc;
nc.ContextFlags = kNtContextFull;
GetThreadContext(GetCurrentThread(), &nc);
_ntcontext2linux(&ctx, &nc);
// bitset of kinds of handlers called
volatile int handler_was_called = 0;
// loop over pending signals
ucontext_t ctx;
getcontext(&ctx);
if (!sig) {
if ((sig = __sig_get(ctx.uc_sigmask))) {
sic = SI_KERNEL;
} else {
return handler_was_called;
}
}
// process signal(s)
int handler_was_called = 0;
do {
// start the signal
unsigned rva, flags;
if (__sig_start(pt, sig, &rva, &flags)) {
if (flags & SA_RESETHAND) {
STRACE("resetting %G handler", sig);
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
// update the signal mask in preparation for signal handller
sigset_t blocksigs = __sighandmask[sig];
if (!(flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1);
ctx.uc_sigmask = atomic_fetch_or_explicit(
&pt->tib->tib_sigmask, blocksigs, memory_order_acquire);
// call the user's signal handler
char ssbuf[2][128];
siginfo_t si = {.si_signo = sig, .si_code = sic};
STRACE("__sig_raise(%G, %t) mask %s → %s", sig, __sig_handler(rva),
(DescribeSigset)(ssbuf[0], 0, &ctx.uc_sigmask),
(DescribeSigset)(ssbuf[1], 0, (sigset_t *)&pt->tib->tib_sigmask));
__sig_handler(rva)(sig, &si, &ctx);
(void)ssbuf;
// restore the original signal mask
atomic_store_explicit(&pt->tib->tib_sigmask, ctx.uc_sigmask,
memory_order_release);
handler_was_called |= (flags & SA_RESTART) ? 2 : 1;
unsigned rva, flags;
struct PosixThread *pt = _pthread_self();
if (__sig_start(pt, sig, &rva, &flags)) {
if (flags & SA_RESETHAND) {
STRACE("resetting %G handler", sig);
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
sic = SI_KERNEL;
} while ((sig = __sig_get(ctx.uc_sigmask)));
return handler_was_called;
// update the signal mask in preparation for signal handller
sigset_t blocksigs = __sighandmask[sig];
if (!(flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1);
ctx.uc_sigmask = atomic_fetch_or_explicit(&pt->tib->tib_sigmask, blocksigs,
memory_order_acquire);
// call the user's signal handler
char ssbuf[128];
siginfo_t si = {.si_signo = sig, .si_code = sic};
STRACE("__sig_raise(%G, %t) mask %s", sig, __sig_handler(rva),
(DescribeSigset)(ssbuf, 0, (sigset_t *)&pt->tib->tib_sigmask));
__sig_handler(rva)(sig, &si, &ctx);
// record this handler
if (flags & SA_RESTART) {
handler_was_called |= SIG_HANDLED_SA_RESTART;
} else {
handler_was_called |= SIG_HANDLED_NO_RESTART;
}
}
// restore sigmask
// loop back to top
// jump where handler says
sig = 0;
return setcontext(&ctx);
}
textwindows int __sig_relay(int sig, int sic, sigset_t waitmask) {
@@ -258,7 +257,6 @@ static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
struct CosmoTib *tib = __get_tls();
struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread;
for (;;) {
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
// update the signal mask in preparation for signal handller
sigset_t blocksigs = __sighandmask[sig];
@@ -272,7 +270,6 @@ static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
(DescribeSigset)(ssbuf[0], 0, &sf->ctx.uc_sigmask),
(DescribeSigset)(ssbuf[1], 0, (sigset_t *)&tib->tib_sigmask));
__sig_handler(sf->rva)(sig, &sf->si, &sf->ctx);
(void)ssbuf;
// restore the signal mask that was used by the interrupted code
// this may have been modified by the signal handler in the callback
@@ -314,12 +311,18 @@ static int __sig_killer(struct PosixThread *pt, int sig, int sic) {
__sig_terminate(sig);
}
// ignore signals already pending
uintptr_t th = _pthread_syshand(pt);
if (atomic_load_explicit(&pt->tib->tib_sigpending, memory_order_acquire) &
(1ull << (sig - 1))) {
return 0;
}
// take control of thread
// suspending the thread happens asynchronously
// however getting the context blocks until it's frozen
static pthread_spinlock_t killer_lock;
pthread_spin_lock(&killer_lock);
uintptr_t th = _pthread_syshand(pt);
if (SuspendThread(th) == -1u) {
STRACE("SuspendThread failed w/ %d", GetLastError());
pthread_spin_unlock(&killer_lock);
@@ -408,6 +411,10 @@ textwindows void __sig_generate(int sig, int sic) {
STRACE("terminating on %G due to no handler", sig);
__sig_terminate(sig);
}
if (atomic_load_explicit(&__sig.pending, memory_order_acquire) &
(1ull << (sig - 1))) {
return;
}
BLOCK_SIGNALS;
_pthread_lock();
for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) {
@@ -422,7 +429,6 @@ textwindows void __sig_generate(int sig, int sic) {
// choose this thread if it isn't masking sig
if (!(atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire) &
(1ull << (sig - 1)))) {
STRACE("generating %G by killing %d", sig, _pthread_tid(pt));
_pthread_ref(pt);
mark = pt;
break;
@@ -433,7 +439,6 @@ textwindows void __sig_generate(int sig, int sic) {
if (atomic_load_explicit(&pt->pt_blocker, memory_order_acquire) &&
!(atomic_load_explicit(&pt->pt_blkmask, memory_order_relaxed) &
(1ull << (sig - 1)))) {
STRACE("generating %G by unblocking %d", sig, _pthread_tid(pt));
_pthread_ref(pt);
mark = pt;
break;
@@ -444,7 +449,6 @@ textwindows void __sig_generate(int sig, int sic) {
__sig_killer(mark, sig, sic);
_pthread_unref(mark);
} else {
STRACE("all threads block %G so adding to pending signals of process", sig);
atomic_fetch_or_explicit(&__sig.pending, 1ull << (sig - 1),
memory_order_relaxed);
}
@@ -513,9 +517,6 @@ static int __sig_crash_sig(struct NtExceptionPointers *ep, int *code) {
static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
struct CosmoTib *tib) {
// increment the signal count for getrusage()
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
// log vital crash information reliably for --strace before doing much
// we don't print this without the flag since raw numbers scare people
// this needs at least one page of stack memory in order to get logged
+2 -7
View File
@@ -3,13 +3,8 @@
#include "libc/calls/struct/sigset.h"
#include "libc/thread/posixthread.internal.h"
#define __SIG_LOCK_INTERVAL_MS 1000 /* semaphore synchronization: solid */
#define __SIG_SIG_INTERVAL_MS 1000 /* posix signal polyfill also solid */
#define __SIG_PROC_INTERVAL_MS 1000 /* process waiting also pretty good */
#define __SIG_IO_INTERVAL_MS 1000 /* read/write cancel/notify is good */
#define __SIG_POLL_INTERVAL_MS 20 /* poll on windows is dumpster fire */
#define __SIG_LOGGING_INTERVAL_MS 1700
#define __SIG_QUEUE_LENGTH 32
#define SIG_HANDLED_NO_RESTART 1
#define SIG_HANDLED_SA_RESTART 2
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
+9 -15
View File
@@ -251,16 +251,24 @@ static int __sigaction(int sig, const struct sigaction *act,
}
if (rc != -1) {
sigaction_native2cosmo((union metasigaction *)oldact);
if (oldact && //
oldact->sa_handler != SIG_DFL && //
oldact->sa_handler != SIG_IGN && //
(IsFreebsd() || IsOpenbsd() || IsNetbsd() || IsXnu())) {
oldact->sa_handler =
(sighandler_t)((uintptr_t)__executable_start + __sighandrvas[sig]);
}
}
} else {
if (oldact) {
bzero(oldact, sizeof(*oldact));
oldrva = __sighandrvas[sig];
oldact->sa_mask = __sighandmask[sig];
oldact->sa_flags = __sighandflags[sig];
oldact->sa_sigaction =
(sigaction_f)(oldrva < kSigactionMinRva
? oldrva
: (intptr_t)&__executable_start + oldrva);
: (uintptr_t)&__executable_start + oldrva);
}
rc = 0;
}
@@ -479,13 +487,6 @@ static int __sigaction(int sig, const struct sigaction *act,
* spawned your process, happened to call `setrlimit()`. Doing this is
* a wonderful idea.
*
* Using signals might make your C runtime slower. Upon successfully
* installing its first signal handling function, sigaction() will set
* the global variable `__interruptible` to true, to let everything else
* know that signals are in play. That way code which would otherwise be
* frequently calling sigprocmask() out of an abundance of caution, will
* no longer need to pay its outrageous cost.
*
* Signal handlers should avoid clobbering global variables like `errno`
* because most signals are asynchronous, i.e. the signal handler might
* be called at any assembly instruction. If something like a `SIGCHLD`
@@ -506,13 +507,6 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
rc = einval();
} else {
rc = __sigaction(sig, act, oldact);
if (!rc && act && (uintptr_t)act->sa_handler >= kSigactionMinRva) {
static bool once;
if (!once) {
__interruptible = true;
once = true;
}
}
}
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(0, act),
DescribeSigaction(rc, oldact), rc);
-1
View File
@@ -51,7 +51,6 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info,
struct timespec ts;
union siginfo_meta si = {0};
BEGIN_CANCELATION_POINT;
(void)strsig;
if (IsAsan() && (!__asan_is_valid(set, sizeof(*set)) ||
(info && !__asan_is_valid(info, sizeof(*info))) ||
+30
View File
@@ -17,12 +17,42 @@ int sched_setaffinity(int, size_t, const cpu_set_t *);
#define CPU_SET(i, s) ((s)->__bits[(i) / 64] |= 1ull << ((i) % 64))
#define CPU_CLR(i, s) ((s)->__bits[(i) / 64] &= ~(1ull << ((i) % 64)))
#define CPU_ISSET(i, s) (!!((s)->__bits[(i) / 64] & (1ull << ((i) % 64))))
void CPU_ZERO(cpu_set_t *);
#define CPU_ZERO(x) CPU_ZERO(x)
int CPU_COUNT(cpu_set_t *);
#define CPU_COUNT(x) CPU_COUNT(x)
int CPU_EQUAL(cpu_set_t *, cpu_set_t *);
#define CPU_EQUAL(x, y) CPU_EQUAL(x, y)
void CPU_AND(cpu_set_t *, cpu_set_t *, cpu_set_t *);
#define CPU_AND(x, y, z) CPU_AND(x, y, z)
void CPU_OR(cpu_set_t *, cpu_set_t *, cpu_set_t *);
#define CPU_OR(x, y, z) CPU_OR(x, y, z)
void CPU_XOR(cpu_set_t *, cpu_set_t *, cpu_set_t *);
#define CPU_XOR(x, y, z) CPU_XOR(x, y, z)
int CPU_COUNT_S(size_t, const cpu_set_t *);
#define CPU_COUNT_S(x, y) CPU_COUNT_S(x, y)
#define CPU_ALLOC_SIZE(n) \
((((n) + (8 * sizeof(long) - 1)) & -(8 * sizeof(long))) / sizeof(long))
#define CPU_ALLOC(n) ((cpu_set_t *)calloc(1, CPU_ALLOC_SIZE(n)))
#define CPU_FREE(set) free(set)
#define CPU_ZERO_S(size, set) memset(set, 0, size)
#define CPU_EQUAL_S(size, set1, set2) (!memcmp(set1, set2, size))
#define _CPU_S(i, size, set, op) \
((i) / 8U >= (size) ? 0 \
: (((unsigned long *)(set))[(i) / 8 / sizeof(long)] op( \
1UL << ((i) % (8 * sizeof(long))))))
#define CPU_SET_S(i, size, set) _CPU_S(i, size, set, |=)
#define CPU_CLR_S(i, size, set) _CPU_S(i, size, set, &= ~)
#define CPU_ISSET_S(i, size, set) _CPU_S(i, size, set, &)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+2 -2
View File
@@ -41,10 +41,10 @@ int sys_futex(int *, int, int, const struct timespec *, int *);
static inline struct timespec timespec_fromseconds(int64_t __x) {
return (struct timespec){__x};
}
static inline bool timespec_iszero(struct timespec __ts) {
static inline int timespec_iszero(struct timespec __ts) {
return !(__ts.tv_sec | __ts.tv_nsec);
}
static inline bool timespec_isvalid(struct timespec __ts) {
static inline int timespec_isvalid(struct timespec __ts) {
return __ts.tv_sec >= 0 && __ts.tv_nsec + 0ull < 1000000000ull;
}
#endif /* _COSMO_SOURCE */
+2 -2
View File
@@ -39,10 +39,10 @@ static inline struct timeval timeval_fromseconds(int64_t __x) {
static inline struct timespec timeval_totimespec(struct timeval __tv) {
return (struct timespec){__tv.tv_sec, __tv.tv_usec * 1000};
}
static inline bool timeval_iszero(struct timeval __tv) {
static inline int timeval_iszero(struct timeval __tv) {
return !(__tv.tv_sec | __tv.tv_usec);
}
static inline bool timeval_isvalid(struct timeval __tv) {
static inline int timeval_isvalid(struct timeval __tv) {
return __tv.tv_sec >= 0 && __tv.tv_usec + 0ull < 1000000ull;
}
#endif /* _COSMO_SOURCE */
-6
View File
@@ -27,12 +27,6 @@
//
// swapcontext(x, y);
//
// This function goes 14x slower if sigaction() has ever been used to
// install a signal handling function. If you don't care about signal
// safety and just want fast fibers, then you may override the global
// variable `__interruptible` to disable the sigprocmask() calls, for
// pure userspace context switching.
//
// @return 0 on success, or -1 w/ errno
// @returnstwice
.ftrace1
+1
View File
@@ -32,6 +32,7 @@
#include "libc/nt/struct/tokenprivileges.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static struct {
Loaded 100 of 643 files, more files were not shown because too many files have changed in this diff. Show more