mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af2ef0d223 | ||
|
|
8111462789 | ||
|
|
f52f65b2e3 | ||
|
|
997ce29ddc | ||
|
|
d38700687a | ||
|
|
0f89140882 | ||
|
|
0cee831da3 | ||
|
|
b41f91c658 | ||
|
|
e7329b7cba | ||
|
|
c19ac8729d | ||
|
|
9d2f993364 | ||
|
|
31dab8a75d | ||
|
|
7a06760e6f | ||
|
|
9209ea63a7 | ||
|
|
84b9b8ed87 | ||
|
|
e557058ac8 | ||
|
|
467a332e38 | ||
|
|
7ae556463a | ||
|
|
c424352a0a | ||
|
|
d5910e2673 | ||
|
|
9b7c8db846 | ||
|
|
4a6fd3d910 | ||
|
|
38df0a4186 | ||
|
|
1c0adb556d | ||
|
|
8aca94f951 | ||
|
|
38e3ab57a6 | ||
|
|
672ccda37c | ||
|
|
9849b4c7ba | ||
|
|
3421b9a580 | ||
|
|
29d695f4c9 | ||
|
|
7d6835c0dd | ||
|
|
05197afca2 | ||
|
|
bc353f454b | ||
|
|
7bc24888fe | ||
|
|
59ac141e49 | ||
|
|
60b68d7152 | ||
|
|
a5b483f2d4 | ||
|
|
d3efa47f81 | ||
|
|
7822917fc2 | ||
|
|
81ee11a16e | ||
|
|
f155205eb0 | ||
|
|
e46ef487a8 | ||
|
|
afc07b9339 | ||
|
|
edb8fef06c | ||
|
|
b75a4654cf | ||
|
|
fe3216e961 | ||
|
|
174d288e66 | ||
|
|
9f9b240f3d | ||
|
|
726f04e8aa | ||
|
|
556697cbd8 | ||
|
|
3ee3736a01 | ||
|
|
01bd7d1008 | ||
|
|
32321ab1e9 | ||
|
|
3b4fcd8575 | ||
|
|
6ba3b448f3 | ||
|
|
91e167caaf | ||
|
|
ccbae7799e | ||
|
|
af24c19db3 | ||
|
|
950a1b310b | ||
|
|
daca5499b9 | ||
|
|
2526a9b8c7 | ||
|
|
7549a5755e | ||
|
|
795d295590 | ||
|
|
3f3cb0650b | ||
|
|
acd8900071 | ||
|
|
6c60793f3a | ||
|
|
ad97775370 | ||
|
|
0b5f84dd20 | ||
|
|
27b5deefb1 | ||
|
|
ecb2ef7c39 | ||
|
|
304cf8869c | ||
|
|
3e0ddf70e9 | ||
|
|
5005f2e446 | ||
|
|
bc8532688b | ||
|
|
09811e739f | ||
|
|
24988f2351 | ||
|
|
b46f763ee7 | ||
|
|
87708c5d6e | ||
|
|
8c2bf341e9 | ||
|
|
6cc9e08f1b | ||
|
|
bfb85fe6d0 | ||
|
|
2cc1d5ac4c | ||
|
|
6e582d245b | ||
|
|
2395a9eced | ||
|
|
0060940d84 | ||
|
|
1ea01fc905 | ||
|
|
c7a8cd21e9 | ||
|
|
224c12f54d | ||
|
|
be29b709b7 | ||
|
|
e14ae1642e | ||
|
|
40991ec992 | ||
|
|
97bb5a3a80 | ||
|
|
bc3d84341d | ||
|
|
c937fbb222 | ||
|
|
cdf9e8c8a3 | ||
|
|
4c40c500b8 | ||
|
|
3665232d66 | ||
|
|
775944a2d0 | ||
|
|
994e1f4386 | ||
|
|
3733b43a8f | ||
|
|
134ffee519 | ||
|
|
6c90f830d9 | ||
|
|
14731d61fa | ||
|
|
418bcb39af | ||
|
|
3f49889841 | ||
|
|
1ad2f530f9 | ||
|
|
654ceaba7d | ||
|
|
6a3330d7c9 | ||
|
|
945699694e | ||
|
|
aab4ee4072 | ||
|
|
8f5678882d | ||
|
|
9fa6725067 | ||
|
|
06f9a5b627 | ||
|
|
446a1f7c5a | ||
|
|
df08b541af | ||
|
|
e0fabd1d49 | ||
|
|
9cf2bdc9a8 | ||
|
|
ed5b763a0c | ||
|
|
22b63d0b98 | ||
|
|
6f7d0cb1c3 | ||
|
|
b69f3d2488 | ||
|
|
0305194d98 | ||
|
|
55ddf73484 | ||
|
|
569c031934 | ||
|
|
9b89a7c51d | ||
|
|
b5cb71ab84 | ||
|
|
3de35e196c | ||
|
|
5dff63a31c | ||
|
|
cdb2284f0d | ||
|
|
333768440c | ||
|
|
cfcf5918bc | ||
|
|
bae7367774 | ||
|
|
155b378a39 | ||
|
|
e9272f03fb | ||
|
|
3265324e00 | ||
|
|
c3208eb9d5 | ||
|
|
1729a8259c | ||
|
|
094ccbb4bd | ||
|
|
e97f1a99cf | ||
|
|
1db76c288e | ||
|
|
f68151c010 | ||
|
|
2d17ab016c | ||
|
|
c32e2d4486 | ||
|
|
5140897c27 | ||
|
|
9f963dc597 | ||
|
|
0547eabcd6 | ||
|
|
b73e35c6fa | ||
|
|
0e2b1bfeed | ||
|
|
571c2c3c69 | ||
|
|
b7c07d548c | ||
|
|
6c323383e5 | ||
|
|
de511bc71a | ||
|
|
114176c304 | ||
|
|
a849a63771 | ||
|
|
4339d9f15e | ||
|
|
d5c9308a43 | ||
|
|
8bd9ad8342 | ||
|
|
3fdb1c14f1 | ||
|
|
598640864a | ||
|
|
d861d2787b | ||
|
|
dbf12c30b0 | ||
|
|
11ec60d5fc | ||
|
|
55c6297e13 | ||
|
|
12d9e1e128 | ||
|
|
7ff0ea8c13 | ||
|
|
7de2f229a7 | ||
|
|
4b4ea046c4 | ||
|
|
44c315d789 | ||
|
|
8cd4248f7f | ||
|
|
d721ff8938 | ||
|
|
9be364d40a | ||
|
|
af24f21556 | ||
|
|
b0287ef34c | ||
|
|
6a04bc3318 | ||
|
|
8dd4ec68d0 | ||
|
|
b9dc74b672 | ||
|
|
e1590e1e38 | ||
|
|
8569704c1d | ||
|
|
9c017c98d3 | ||
|
|
74879bf067 | ||
|
|
8a3d8497e3 | ||
|
|
3c00d8c29c | ||
|
|
1ef955c33b | ||
|
|
494d74271b | ||
|
|
12212894eb | ||
|
|
a4522fba8d | ||
|
|
0c70e8963d | ||
|
|
b66bd064d8 | ||
|
|
c5c4dfcd21 | ||
|
|
c5659b93f8 | ||
|
|
263711965f | ||
|
|
33b5b5b312 | ||
|
|
d213a48190 | ||
|
|
3f0414e1cb | ||
|
|
adaaeb7dd0 | ||
|
|
164e2ab27b | ||
|
|
d2cec808dc | ||
|
|
91a3252434 | ||
|
|
8cab92a069 | ||
|
|
5a632cf72d | ||
|
|
7b74f6e20e | ||
|
|
253cc1754b | ||
|
|
8722006c46 | ||
|
|
58d22c7c3d | ||
|
|
2227cefa5d | ||
|
|
f0bf9f3389 | ||
|
|
04cd62c319 | ||
|
|
e204fc0820 | ||
|
|
b76540105d | ||
|
|
14e3025749 | ||
|
|
51fa5535ac | ||
|
|
bea0b55576 | ||
|
|
57b39d8793 | ||
|
|
d52170ca34 | ||
|
|
bf757c4646 | ||
|
|
99a92048b4 | ||
|
|
2f1679e5cf | ||
|
|
ee49b71be2 | ||
|
|
73845be1f0 | ||
|
|
35203c0551 | ||
|
|
83d41e4588 | ||
|
|
a51edaa0db | ||
|
|
d76dfadc7a | ||
|
|
8835b82a7c | ||
|
|
2827df688a |
No files matched your search
@@ -21,8 +21,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: support ape bins
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
|
||||
- name: support ape bins 1
|
||||
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
|
||||
|
||||
- name: support ape bins 2
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
||||
|
||||
- name: make matrix
|
||||
run: V=0 make -j2 MODE=${{ matrix.mode }}
|
||||
@@ -11,3 +11,5 @@ __pycache__
|
||||
/TAGS
|
||||
/bx_enh_dbg.ini
|
||||
/tool/emacs/*.elc
|
||||
/perf.data
|
||||
/perf.data.old
|
||||
Vendored
+2
-2
@@ -43,10 +43,10 @@
|
||||
"forcealignargpointer=",
|
||||
"noasan=",
|
||||
"noubsan=",
|
||||
"testonly=",
|
||||
"donothing=",
|
||||
"nosideeffect=",
|
||||
"unreachable=",
|
||||
"unreachable=",,
|
||||
"notpossible=",
|
||||
"thatispacked=",
|
||||
"dontthrow=",
|
||||
"nocallback=",
|
||||
|
||||
@@ -61,13 +61,19 @@
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
.FEATURES: output-sync
|
||||
.PHONY: all o bins check test depend tags
|
||||
|
||||
ifneq ($(m),)
|
||||
ifeq ($(MODE),)
|
||||
MODE := $(m)
|
||||
endif
|
||||
endif
|
||||
|
||||
all: o
|
||||
o: o/$(MODE)
|
||||
|
||||
@@ -88,11 +94,13 @@ o/$(MODE): \
|
||||
libc/disclaimer.inc \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
/proc/self/status \
|
||||
/proc/stat \
|
||||
rw:/dev/null \
|
||||
w:o/stack.log \
|
||||
/etc/hosts \
|
||||
~/.runit.psk
|
||||
~/.runit.psk \
|
||||
/proc/self/status \
|
||||
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
|
||||
PKGS =
|
||||
|
||||
@@ -113,17 +121,21 @@ include third_party/compiler_rt/compiler_rt.mk # │
|
||||
include libc/str/str.mk # │
|
||||
include third_party/xed/xed.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include third_party/double-conversion/dc.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk #─┘
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/vga/vga.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include third_party/nsync/nsync.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||
include libc/mem/mem.mk #─┐
|
||||
include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
|
||||
include libc/time/time.mk # │ You can finally call malloc()
|
||||
include third_party/nsync/mem/mem.mk # │
|
||||
include libc/thread/thread.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include third_party/libcxx/libcxx.mk # │
|
||||
@@ -149,6 +161,7 @@ include net/https/https.mk # │
|
||||
include third_party/regex/regex.mk #─┘
|
||||
include third_party/tidy/tidy.mk
|
||||
include third_party/third_party.mk
|
||||
include third_party/nsync/testing/testing.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include tool/args/args.mk
|
||||
@@ -156,8 +169,10 @@ include test/tool/args/test.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
include net/finger/finger.mk
|
||||
include third_party/double-conversion/double-conversion.mk
|
||||
include third_party/double-conversion/test/test.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/sed/sed.mk
|
||||
include third_party/awk/awk.mk
|
||||
include third_party/make/make.mk
|
||||
include third_party/finger/finger.mk
|
||||
include third_party/argon2/argon2.mk
|
||||
@@ -189,6 +204,7 @@ include tool/hash/hash.mk
|
||||
include tool/net/net.mk
|
||||
include tool/viz/viz.mk
|
||||
include tool/tool.mk
|
||||
include net/turfwar/turfwar.mk
|
||||
include test/libc/tinymath/test.mk
|
||||
include test/libc/intrin/test.mk
|
||||
include test/libc/mem/test.mk
|
||||
@@ -206,6 +222,7 @@ include test/libc/fmt/test.mk
|
||||
include test/libc/dns/test.mk
|
||||
include test/libc/time/test.mk
|
||||
include test/libc/stdio/test.mk
|
||||
include test/libc/zipos/test.mk
|
||||
include test/libc/release/test.mk
|
||||
include test/libc/test.mk
|
||||
include test/net/http/test.mk
|
||||
@@ -258,94 +275,102 @@ o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS
|
||||
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: .UNSANDBOXED = 1
|
||||
TAGS: private .UNSANDBOXED = 1
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||
@$(RM) $@
|
||||
@$(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: .UNSANDBOXED = 1
|
||||
HTAGS: private .UNSANDBOXED = 1
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||
@$(RM) $@
|
||||
@build/htags -L $< -o $@
|
||||
|
||||
loc: .UNSANDBOXED = 1
|
||||
loc: private .UNSANDBOXED = 1
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
find -name \*.h -or -name \*.c -or -name \*.S | \
|
||||
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
|
||||
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
NET_HTTP \
|
||||
LIBC_DNS \
|
||||
LIBC_SOCK \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_MSWSOCK \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_MUSL \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_ELF \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_URL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NT_KERNEL32 \
|
||||
# PLEASE: MAINTAIN TOPOLOGICAL ORDER
|
||||
# FROM HIGHEST LEVEL TO LOWEST LEVEL
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
NET_HTTP \
|
||||
LIBC_DNS \
|
||||
LIBC_SOCK \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_MSWSOCK \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_MUSL \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_NSYNC \
|
||||
LIBC_ELF \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_VGA \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_URL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_SYNCHRONIZATION \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E
|
||||
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
APE \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
APE \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
LIBC_VGA \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
@@ -359,6 +384,7 @@ o/cosmopolitan.h: \
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
|
||||
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
|
||||
@@ -377,6 +403,15 @@ $(SRCS): \
|
||||
libc/integral/lp64arg.inc \
|
||||
libc/integral/lp64.inc
|
||||
|
||||
.PHONY: toolchain
|
||||
toolchain: o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/public/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a
|
||||
|
||||
# UNSPECIFIED PREREQUISITES TUTORIAL
|
||||
#
|
||||
# A build rule must exist for all files that make needs to consider in
|
||||
|
||||
@@ -23,11 +23,11 @@ If you're doing your development work on Linux or BSD then you need just
|
||||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.0.zip
|
||||
unzip cosmopolitan-amalgamation-2.0.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.1.1.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 \
|
||||
-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 \
|
||||
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
|
||||
objcopy -S -O binary hello.com.dbg hello.com
|
||||
@@ -40,6 +40,21 @@ You now have a portable program.
|
||||
bash -c './hello.com' # zsh/fish workaround (we patched them in 2021)
|
||||
```
|
||||
|
||||
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):
|
||||
|
||||
```sh
|
||||
sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
|
||||
```
|
||||
|
||||
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 to `${TMPDIR:-${HOME:-.}}`
|
||||
@@ -85,7 +100,7 @@ heavyweight features like tracing to your binaries by default. In that
|
||||
case, you may want to consider using our build system:
|
||||
|
||||
```sh
|
||||
make -j8 MODE=tiny
|
||||
make m=tiny
|
||||
```
|
||||
|
||||
Which will cause programs such as `hello.com` and `life.com` to shrink
|
||||
@@ -140,7 +155,7 @@ cd cosmopolitan
|
||||
This will build the entire repository and run all the tests:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16
|
||||
build/bootstrap/make.com
|
||||
o//examples/hello.com
|
||||
find o -name \*.com | xargs ls -rShal | less
|
||||
```
|
||||
@@ -159,7 +174,7 @@ having minimal deterministic builds. For example, if you wanted to build
|
||||
only hello.com then you could do that as follows:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//examples/hello.com
|
||||
build/bootstrap/make.com o//examples/hello.com
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
@@ -168,7 +183,7 @@ directory name. For example, if you wanted to build only the targets and
|
||||
subtargets of the chibicc package including its tests, you would say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//third_party/chibicc
|
||||
build/bootstrap/make.com o//third_party/chibicc
|
||||
o//third_party/chibicc/chibicc.com --help
|
||||
```
|
||||
|
||||
@@ -176,18 +191,19 @@ 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 -j16 MODE=tiny
|
||||
build/bootstrap/make.com m=tiny
|
||||
```
|
||||
|
||||
Here's some other build modes you can try:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug
|
||||
build/bootstrap/make.com -j16 MODE=asan # production memory safety
|
||||
build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations
|
||||
build/bootstrap/make.com -j16 MODE=rel # traditional release binaries
|
||||
build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance
|
||||
build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries
|
||||
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
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
@@ -196,7 +212,7 @@ For further details, see [//build/config.mk](build/config.mk).
|
||||
|
||||
Here's the recommended `~/.gdbinit` config:
|
||||
|
||||
```
|
||||
```gdb
|
||||
set host-charset UTF-8
|
||||
set target-charset UTF-8
|
||||
set target-wide-charset UTF-8
|
||||
@@ -229,11 +245,11 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
| :--- | ---: | ---: |
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Windows | Vista | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
## Special Thanks
|
||||
@@ -242,8 +258,10 @@ Funding for this project is crowdsourced using
|
||||
[GitHub Sponsors](https://github.com/sponsors/jart) and
|
||||
[Patreon](https://www.patreon.com/jart). Your support is what makes this
|
||||
project possible. Thank you! We'd also like to give special thanks to
|
||||
the following individuals:
|
||||
the following groups and individuals:
|
||||
|
||||
- [Joe Drumgoole](https://github.com/jdrumgoole)
|
||||
- [Rob Figueiredo](https://github.com/robfig)
|
||||
- [Wasmer](https://wasmer.io/)
|
||||
|
||||
For publicly sponsoring our work at the highest tier.
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nexgen32e/vidya.internal.h"
|
||||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
@@ -126,6 +125,7 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
.org 0x24 # MZ: bytes reserved for you
|
||||
.ascii "JT" # MZ: OEM identifier
|
||||
.short 0 # MZ: OEM information
|
||||
.ascii "' <<'@'\n"
|
||||
.org 0x40-4 # MZ: bytes reserved for you
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.long RVA(ape_pe) # PE: the new technology
|
||||
@@ -236,8 +236,9 @@ pc: cld
|
||||
#endif
|
||||
ljmp $0,$REAL(1f)
|
||||
1: mov %cx,%ds
|
||||
mov $IMAGE_BASE_REAL-0x0500,%cx # clears bss
|
||||
mov $0x0500>>4,%ax # struct mman
|
||||
.set mm,0x0500 # struct mman
|
||||
mov $IMAGE_BASE_REAL-mm,%cx # clears bss
|
||||
mov $mm>>4,%ax
|
||||
mov %ax,%es
|
||||
xor %ax,%ax
|
||||
xor %di,%di
|
||||
@@ -328,7 +329,7 @@ dsknfo: push %bx
|
||||
movpp %es,%ds
|
||||
xor %si,%si
|
||||
mov %si,%es
|
||||
mov $0x1510,%si # mman::pc_drive_base_table
|
||||
mov $mm+"struct mman::pc_drive_base_table",%si
|
||||
xchg %si,%di
|
||||
movsw #→ headunloadtime, headloadtime
|
||||
movsw #→ shutofftime, bytespersector
|
||||
@@ -381,11 +382,11 @@ pcread: push %ax
|
||||
add $512>>4,%si
|
||||
mov %si,%es
|
||||
inc %al # ++sector
|
||||
cmp 0x151c,%al # mman::pc_drive_last_sector
|
||||
cmp mm+"struct mman::pc_drive_last_sector",%al
|
||||
jbe 2f
|
||||
mov $1,%al
|
||||
inc %dh # ++head
|
||||
cmp 0x1520,%dh # mman::pc_drive_last_head
|
||||
cmp mm+"struct mman::pc_drive_last_head",%dh
|
||||
jbe 2f
|
||||
xor %dh,%dh
|
||||
inc %cx # ++cylinder
|
||||
@@ -484,19 +485,19 @@ ape.mbrpad:
|
||||
ape_disk:
|
||||
.stub ape.diskid,quad
|
||||
.org 0x1be,0x00
|
||||
.macro .partn x
|
||||
.stub ape.part\x\().status,byte # 0=absent / 0x80=present
|
||||
.stub ape.part\x\().first.head,byte # in low 6 bits
|
||||
.stub ape.part\x\().first.cylinder,byte
|
||||
.stub ape.part\x\().first.sector,byte
|
||||
.stub ape.part\x\().filesystem,byte
|
||||
.stub ape.part\x\().last.head,byte
|
||||
.stub ape.part\x\().last.cylinder,byte
|
||||
.stub ape.part\x\().last.sector,byte
|
||||
.stub ape.part\x\().lba,long # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||||
.stub ape.part\x\().sector.count,long # sectors are 512 bytes
|
||||
.macro .partn x:req sta h0 s0 c0 fs h9 s9 c9 lba0 nsec
|
||||
.stub ape.part\x\().status,byte,\sta # 0=non-boot / 0x80=active
|
||||
.stub ape.part\x\().first.head,byte,\h0
|
||||
.stub ape.part\x\().first.sector,byte,\s0 # in low 6 bits
|
||||
.stub ape.part\x\().first.cylinder,byte,\c0
|
||||
.stub ape.part\x\().filesystem,byte,\fs
|
||||
.stub ape.part\x\().last.head,byte,\h9
|
||||
.stub ape.part\x\().last.sector,byte,\s9
|
||||
.stub ape.part\x\().last.cylinder,byte,\c9
|
||||
.stub ape.part\x\().lba,long,\lba0 # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||||
.stub ape.part\x\().sector.count,long,\nsec # sectors are 512 bytes
|
||||
.endm
|
||||
.partn 1
|
||||
.partn 1,0x80,0,1,0,0x7f,0xff,0xff,0xff,0,0xffffffff
|
||||
.partn 2
|
||||
.partn 3
|
||||
.partn 4
|
||||
@@ -548,7 +549,7 @@ ape_disk:
|
||||
the bourne executable & linkable format */
|
||||
|
||||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
apesh: .ascii "\n@\n#'\"\n" # sixth edition shebang
|
||||
// Until all operating systems can be updated to support APE,
|
||||
// we have a beautiful, yet imperfect workaround, which is to
|
||||
// modify the binary to follow the local system's convention.
|
||||
@@ -568,11 +569,11 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
.ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape\"\n"
|
||||
.ascii "[ -x \"$t\" ] || {\n"
|
||||
.ascii "mkdir -p \"${t%/*}\" &&\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
|
||||
.shstub ape_loader_dd_skip,2
|
||||
.ascii "\" count=\""
|
||||
.ascii " count="
|
||||
.shstub ape_loader_dd_count,2
|
||||
.ascii "\" bs=64 2>/dev/null\n"
|
||||
.ascii " bs=64 2>/dev/null\n"
|
||||
#if SupportsXnu()
|
||||
.ascii "[ -d /Applications ] && "
|
||||
.ascii "dd if=\"$t.$$\""
|
||||
@@ -636,11 +637,11 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
.ascii "dd if=\"$o\""
|
||||
.ascii " of=\"$o\""
|
||||
.ascii " bs=8"
|
||||
.ascii " skip=\""
|
||||
.ascii " skip="
|
||||
.shstub ape_macho_dd_skip,2
|
||||
.ascii "\" count=\""
|
||||
.ascii " count="
|
||||
.shstub ape_macho_dd_count,2
|
||||
.ascii "\" conv=notrunc 2>/dev/null\n"
|
||||
.ascii " conv=notrunc 2>/dev/null\n"
|
||||
#endif /* XNU */
|
||||
.ascii "[ x\"$1\" = x--assimilate ] && exit 0\n"
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
@@ -873,7 +874,7 @@ ape_macho:
|
||||
.long (520f-510f)/4 # count
|
||||
510: .quad 0 # rax
|
||||
.quad IMAGE_BASE_VIRTUAL # rbx
|
||||
.quad XNU # rcx
|
||||
.quad _HOSTXNU # rcx
|
||||
.quad 0 # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
@@ -1136,12 +1137,17 @@ sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
|
||||
.endobj sconf,global,hidden
|
||||
|
||||
// Global Descriptor Table
|
||||
//
|
||||
// @note address portion only concern legacy modes
|
||||
.align 8
|
||||
gdt: .short 2f-1f # table byte length
|
||||
.long REAL(1f),0 # table address
|
||||
.zero 2
|
||||
_gdtrphy:
|
||||
.short 2f-1f-1 # table byte length
|
||||
.long REAL(1f) # table address (physical space)
|
||||
.endobj _gdtrphy,global,hidden
|
||||
_gdtr:
|
||||
.short 2f-1f-1 # table byte length
|
||||
.quad 1f # table address (final virtual space)
|
||||
.endobj _gdtr,global,hidden
|
||||
.align 8
|
||||
_gdt:
|
||||
1:
|
||||
// ┌G:granularity (1 → limit *= 0x1000)
|
||||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||||
@@ -1171,7 +1177,9 @@ gdt: .short 2f-1f # table byte length
|
||||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||||
2: .endobj gdt,global,hidden
|
||||
.tssdescstub _tss #56,64
|
||||
2:
|
||||
.endobj _gdt,global,hidden
|
||||
|
||||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||||
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
||||
@@ -1277,8 +1285,8 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
jl 10f
|
||||
mov %edi,%eax
|
||||
cpuid
|
||||
mov $1<<29,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx
|
||||
mov $1<<29|1<<20,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx # & nx support
|
||||
cmp %edi,%edx
|
||||
jne 10f
|
||||
xor %ax,%ax
|
||||
@@ -1288,29 +1296,39 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
.endfn lcheck
|
||||
|
||||
// Gets memory map from BIOS.
|
||||
e820: mov $0x0510>>4,%di # mman::e820
|
||||
mov %di,%es
|
||||
xor %edi,%edi # es:di is destination buffer
|
||||
xor %ebx,%ebx # ebx is an api state tracker
|
||||
e820: xor %ebx,%ebx # %ebx is an api state tracker
|
||||
mov %bx,%es
|
||||
mov $mm+"struct mman::e820",%di # es:di is destination buffer
|
||||
1: mov $0xE820,%eax # magic
|
||||
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
|
||||
mov $0x534d4150,%edx # magic number
|
||||
movl $1,8+8+4/*SmapEntry::acpi3*/(%di) # prefill ACPI attributes;
|
||||
# apparently some buggy BIOSes say
|
||||
# that they return this field, yet
|
||||
# do not fill it correctly
|
||||
int $0x15 # ax,bx,cx,dx,di → ax,bx,cx
|
||||
jc 9f # cf = unsupported or abuse
|
||||
cmp %edx,%eax # more magic means success
|
||||
jne 9f
|
||||
test %cx,%cx # discard empty results
|
||||
jz 5f
|
||||
mov 8/*LODWORD(SmapEntry::size)*/(%di),%eax
|
||||
or 8+4/*HIDWORD(SmapEntry::size)*/(%di),%eax
|
||||
jz 5f
|
||||
cmp $8+8+4+1,%cx # discard if ignore flag
|
||||
jb 4f
|
||||
testb $1/*ignore*/,8+8+4/*SmapEntry::__acpi3*/(%di)
|
||||
jnz 5f
|
||||
testb $1/*don't ignore*/,8+8+4/*SmapEntry::acpi3*/(%di)
|
||||
jz 5f
|
||||
4: add $8+8+4+4,%di # keep entry
|
||||
5: test %ebx,%ebx # last entry?
|
||||
jz 8f
|
||||
cmp $0x1000,%di
|
||||
cmp $mm+"struct mman::e820_end"-(8+8+4+4),%di
|
||||
jb 1b
|
||||
8: ret
|
||||
8: xor %ax,%ax # add a blank sentinel entry
|
||||
mov $(8+8)/2,%cx
|
||||
cld
|
||||
rep stosw
|
||||
ret
|
||||
9: mov $REAL(str.e820),%di
|
||||
call rldie
|
||||
.endfn e820
|
||||
@@ -1380,9 +1398,16 @@ a20: cli
|
||||
|
||||
// Initializes long mode paging.
|
||||
pinit: push %ds
|
||||
push %es
|
||||
#define SEG 0x79000
|
||||
mov $SEG>>4,%ax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
xor %di,%di
|
||||
xor %ax,%ax
|
||||
mov $(0x7f000-SEG)/2,%cx
|
||||
cld
|
||||
rep stosw
|
||||
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPT←PML4T (+)
|
||||
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPT←PML4T (-)
|
||||
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDT←PDPT (+)
|
||||
@@ -1390,14 +1415,15 @@ pinit: push %ds
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||
mov $512,%cx # PD±2MB
|
||||
mov $PAGE_V+PAGE_RW,%eax
|
||||
xor %si,%si
|
||||
0: mov %eax,(%si)
|
||||
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
|
||||
xor %di,%di
|
||||
0: stosl
|
||||
add $0x1000,%eax
|
||||
add $8,%si
|
||||
scasl # di += 4
|
||||
loop 0b
|
||||
mov $0x7e000,%eax # PML4T←CR3
|
||||
mov %eax,%cr3
|
||||
pop %es
|
||||
pop %ds
|
||||
ret
|
||||
.endfn pinit
|
||||
@@ -1406,15 +1432,15 @@ pinit: push %ds
|
||||
//
|
||||
// @see Intel Manual V3A §4.1.2
|
||||
golong: cli
|
||||
lidt 0x1522 # mman::bad_idt
|
||||
lidt mm+"struct mman::bad_idt"
|
||||
mov %cr4,%eax
|
||||
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
||||
mov %eax,%cr4
|
||||
movl $EFER,%ecx
|
||||
rdmsr
|
||||
or $EFER_LME|EFER_SCE,%eax
|
||||
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
|
||||
wrmsr
|
||||
lgdt REAL(gdt)
|
||||
lgdt REAL(_gdtrphy)
|
||||
mov %cr0,%eax
|
||||
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
||||
and $~CR0_EM,%eax
|
||||
@@ -1424,14 +1450,16 @@ golong: cli
|
||||
|
||||
// Long mode is long.
|
||||
.code64
|
||||
long: push $GDT_LONG_DATA
|
||||
pop %rax
|
||||
long: xor %eax,%eax
|
||||
mov $GDT_LONG_DATA,%al
|
||||
mov %eax,%ds
|
||||
mov %eax,%ss
|
||||
mov %eax,%es
|
||||
mov %eax,%fs
|
||||
mov %eax,%gs
|
||||
mov $0x80000,%esp
|
||||
mov $GDT_LONG_TSS,%al
|
||||
ltr %ax
|
||||
xor %r12d,%r12d
|
||||
xor %r13d,%r13d
|
||||
xor %r14d,%r14d
|
||||
@@ -1439,12 +1467,14 @@ long: push $GDT_LONG_DATA
|
||||
xor %ebx,%ebx
|
||||
xor %ebp,%ebp
|
||||
push %rbp
|
||||
mov $0x0500,%rdi # mman
|
||||
mov $mm,%rdi
|
||||
mov %cr3,%rsi
|
||||
mov $IMAGE_BASE_REAL,%edx
|
||||
call __map_phdrs
|
||||
push $0x037f
|
||||
fldcw (%rsp)
|
||||
lgdt _gdtr # reload GDTR for
|
||||
# virtual memory space
|
||||
movabs $kernel,%rax
|
||||
jmp *%rax
|
||||
.endfn long
|
||||
@@ -1525,7 +1555,7 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||
#endif
|
||||
push $METAL # sets __hostos in crt.S
|
||||
push $_HOSTMETAL # sets __hostos in crt.S
|
||||
pop %rcx
|
||||
push $0
|
||||
mov %rsp,%rbp
|
||||
|
||||
+18
-9
@@ -180,6 +180,7 @@
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/pf2prot.internal.h"
|
||||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.h"
|
||||
|
||||
ENTRY(_start)
|
||||
@@ -279,6 +280,7 @@ SECTIONS {
|
||||
KEEP(*(.keep.text))
|
||||
*(.text .stub .text.*)
|
||||
KEEP(*(SORT_BY_NAME(.sort.text.*)))
|
||||
*(.subrs)
|
||||
|
||||
KEEP(*(.ape.pad.test));
|
||||
*(.test.unlikely)
|
||||
@@ -380,17 +382,16 @@ SECTIONS {
|
||||
PROVIDE_HIDDEN(edata = .);
|
||||
KEEP(*(SORT_BY_NAME(.zip.*)))
|
||||
HIDDEN(_ezip = .);
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Ram
|
||||
|
||||
.tdata . : {
|
||||
_tdata_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tdata))
|
||||
*(SORT_BY_ALIGNMENT(.tdata.*))
|
||||
. = ALIGN(16);
|
||||
_tdata_end = .;
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Tls
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Tls :Ram
|
||||
|
||||
/*END: file content that's loaded by o/s */
|
||||
/*BEGIN: bss memory void */
|
||||
@@ -399,7 +400,7 @@ SECTIONS {
|
||||
_tbss_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tbss))
|
||||
*(SORT_BY_ALIGNMENT(.tbss.*))
|
||||
. = ALIGN(16);
|
||||
. = ALIGN(TLS_ALIGNMENT);
|
||||
/* the %fs register is based on this location */
|
||||
_tbss_end = .;
|
||||
} :Tls
|
||||
@@ -426,7 +427,7 @@ SECTIONS {
|
||||
|
||||
KEEP(*(.bssepilogue))
|
||||
/*END: NT FORK COPYING */
|
||||
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
|
||||
. = ALIGN(PAGESIZE);
|
||||
HIDDEN(_end = .);
|
||||
PROVIDE_HIDDEN(end = .);
|
||||
} :Bss
|
||||
@@ -457,6 +458,7 @@ SECTIONS {
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_line_str 0 : { *(.debug_line_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
@@ -465,6 +467,7 @@ SECTIONS {
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
@@ -485,8 +488,10 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56);
|
||||
PFSTUB4(ape_elf_shnum, 0);
|
||||
PFSTUB4(ape_elf_shstrndx, 0);
|
||||
|
||||
HIDDEN(_tdata_size = _tdata_end - _tdata_start);
|
||||
HIDDEN(_tls_size = _tbss_end - _tdata_start);
|
||||
HIDDEN(_tdata_size = _tdata_end - _tdata_start);
|
||||
HIDDEN(_tbss_size = _tbss_end - _tbss_start);
|
||||
HIDDEN(_tbss_offset = _tbss_start - _tdata_start);
|
||||
HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start));
|
||||
|
||||
HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE));
|
||||
@@ -560,10 +565,11 @@ SHSTUB2(ape_loader_dd_count,
|
||||
#if SupportsMetal()
|
||||
HIDDEN(v_ape_realsectors =
|
||||
MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 4096)) / 512);
|
||||
ROUNDUP(RVA(_edata), 512)) / 512);
|
||||
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||
HIDDEN(v_ape_highsectors =
|
||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
|
||||
#endif
|
||||
|
||||
/* ZIP End of Central Directory header */
|
||||
@@ -708,8 +714,11 @@ ASSERT(!DEFINED(_start16) || REAL(_end) < 65536,
|
||||
ASSERT(IS2POW(ape_stack_memsz),
|
||||
"ape_stack_memsz must be a two power");
|
||||
|
||||
ASSERT(!(ape_stack_vaddr & (ape_stack_memsz - 1)),
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000000000 - ape_stack_memsz);");
|
||||
ASSERT(ape_stack_vaddr % ape_stack_memsz == 0,
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000040000 - ape_stack_memsz);");
|
||||
|
||||
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
|
||||
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
|
||||
|
||||
/* Let's not be like Knight Capital. */
|
||||
/* NOCROSSREFS_TO(.test .text) */
|
||||
|
||||
+21
@@ -63,7 +63,27 @@ o/$(MODE)/ape/ape.lds: \
|
||||
ape/macros.internal.h \
|
||||
ape/relocations.h \
|
||||
libc/intrin/bits.h \
|
||||
libc/thread/tls.h \
|
||||
libc/calls/struct/timespec.h \
|
||||
libc/thread/thread.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/elf/pf2prot.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/str/str.h \
|
||||
libc/zip.h
|
||||
|
||||
o/$(MODE)/ape/public/ape.lds: OVERRIDE_CPPFLAGS += -UCOSMO
|
||||
o/$(MODE)/ape/public/ape.lds: \
|
||||
ape/public/ape.lds \
|
||||
ape/ape.lds \
|
||||
ape/macros.internal.h \
|
||||
ape/relocations.h \
|
||||
libc/intrin/bits.h \
|
||||
libc/thread/tls.h \
|
||||
libc/calls/struct/timespec.h \
|
||||
libc/thread/thread.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/elf/pf2prot.internal.h \
|
||||
@@ -159,6 +179,7 @@ o/$(MODE)/ape/ape.macho.dbg: \
|
||||
o/$(MODE)/ape: $(APE_CHECKS) \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/public/ape.lds \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
o/$(MODE)/ape/ape.macho \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
|
||||
+33
-33
@@ -32,23 +32,23 @@
|
||||
// @see ape/ape.lds
|
||||
// @see winimp
|
||||
.macro .imp dll:req fn:req actual:req hint
|
||||
.dll \dll
|
||||
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
|
||||
.dll "\dll"
|
||||
.section ".piro.data.sort.iat.2.\dll\().2.\actual","aw",@progbits
|
||||
.type \fn,@object
|
||||
.align __SIZEOF_POINTER__
|
||||
\fn: .quad RVA((\dll\().\actual))
|
||||
\fn: .quad RVA(("\dll\().\actual"))
|
||||
.size \fn,.-\fn
|
||||
.globl \fn
|
||||
.hidden \fn
|
||||
.previous
|
||||
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
|
||||
.Lidata.ilt.\dll\().\actual:
|
||||
.quad RVA((\dll\().\actual))
|
||||
.type .Lidata.ilt.\dll\().\actual,@object
|
||||
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
|
||||
.section ".idata.ro.ilt.\dll\().2.\actual","a",@progbits
|
||||
".Lidata.ilt.\dll\().\actual":
|
||||
.quad RVA("\dll\().\actual")
|
||||
.type ".Lidata.ilt.\dll\().\actual",@object
|
||||
.size ".Lidata.ilt.\dll\().\actual",.-".Lidata.ilt.\dll\().\actual"
|
||||
.previous
|
||||
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
|
||||
\dll\().\actual:
|
||||
.section ".idata.ro.hnt.\dll\().2.\actual","a",@progbits
|
||||
"\dll\().\actual":
|
||||
.ifnb \hint # hint i.e. guess function ordinal
|
||||
.short \hint
|
||||
.else
|
||||
@@ -56,55 +56,55 @@
|
||||
.endif
|
||||
.asciz "\actual"
|
||||
.align 2 # documented requirement
|
||||
.globl \dll\().\actual
|
||||
.hidden \dll\().\actual
|
||||
.type \dll\().\actual,@object
|
||||
.size \dll\().\actual,.-\dll\().\actual
|
||||
.globl "\dll\().\actual"
|
||||
.hidden "\dll\().\actual"
|
||||
.type "\dll\().\actual",@object
|
||||
.size "\dll\().\actual",.-"\dll\().\actual"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
// Defines DLL import.
|
||||
// @note this is an implementation detail of .imp
|
||||
.macro .dll name:req
|
||||
.section .idata.ro.idt.2.\name,"aG",@progbits,\name,comdat
|
||||
.equ .Lidata.idt.\name,.
|
||||
.long RVA(idata.ilt.\name) # ImportLookupTable
|
||||
.section ".idata.ro.idt.2.\name","aG",@progbits,"\name",comdat
|
||||
.equ ".Lidata.idt.\name",.
|
||||
.long RVA("idata.ilt.\name") # ImportLookupTable
|
||||
.long 0 # TimeDateStamp
|
||||
.long 0 # ForwarderChain
|
||||
.long RVA(.Lidata.str.\name) # DllNameRva
|
||||
.long RVA(idata.iat.\name) # ImportAddressTable
|
||||
.type .Lidata.idt.\name,@object
|
||||
.size .Lidata.idt.\name,.-.Lidata.idt.\name
|
||||
.long RVA(".Lidata.str.\name") # DllNameRva
|
||||
.long RVA("idata.iat.\name") # ImportAddressTable
|
||||
.type ".Lidata.idt.\name",@object
|
||||
.size ".Lidata.idt.\name",.-".Lidata.idt.\name"
|
||||
.previous
|
||||
.section .idata.ro.ilt.\name\().1,"aG",@progbits,\name,comdat
|
||||
.section ".idata.ro.ilt.\name\().1","aG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.ilt.\name,@object
|
||||
idata.ilt.\name:
|
||||
.type "idata.ilt.\name",@object
|
||||
"idata.ilt.\name":
|
||||
.previous/*
|
||||
...
|
||||
decentralized content
|
||||
...
|
||||
*/.section .idata.ro.ilt.\name\().3,"aG",@progbits,\name,comdat
|
||||
*/.section ".idata.ro.ilt.\name\().3","aG",@progbits,"\name",comdat
|
||||
.quad 0
|
||||
.previous
|
||||
.section .idata.ro.hnt.\name\().1,"aG",@progbits,\name,comdat
|
||||
.section ".idata.ro.hnt.\name\().1","aG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.hnt.\name,@object
|
||||
.equ idata.hnt.\name,.
|
||||
.type "idata.hnt.\name",@object
|
||||
.equ "idata.hnt.\name",.
|
||||
.previous
|
||||
.section .piro.data.sort.iat.2.\name\().1,"awG",@progbits,\name,comdat
|
||||
.section ".piro.data.sort.iat.2.\name\().1","awG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.iat.\name,@object
|
||||
idata.iat.\name:
|
||||
.type "idata.iat.\name",@object
|
||||
"idata.iat.\name":
|
||||
.previous/*
|
||||
...
|
||||
decentralized content
|
||||
...
|
||||
*/.section .piro.data.sort.iat.2.\name\().3,"awG",@progbits,\name,comdat
|
||||
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
|
||||
.quad 0
|
||||
.previous
|
||||
.section .rodata.str1.1,"aSM",@progbits,1
|
||||
.Lidata.str.\name:
|
||||
".Lidata.str.\name":
|
||||
.asciz "\name\().dll"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
+2
-2
@@ -175,7 +175,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -221,7 +221,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -121,7 +121,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
+17
-17
@@ -179,7 +179,7 @@ struct ElfPhdr {
|
||||
|
||||
extern char ehdr[];
|
||||
extern char _end[];
|
||||
static void *syscall;
|
||||
static void *syscall_;
|
||||
static char relocated;
|
||||
static struct PathSearcher ps;
|
||||
extern char __syscall_loader[];
|
||||
@@ -275,7 +275,7 @@ __attribute__((__noreturn__)) static void Exit(int rc, int os) {
|
||||
asm volatile("call\t*%2"
|
||||
: /* no outputs */
|
||||
: "a"((IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)), "D"(rc),
|
||||
"rm"(syscall)
|
||||
"rm"(syscall_)
|
||||
: "memory");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -285,7 +285,7 @@ static void Close(int fd, int os) {
|
||||
asm volatile("call\t*%4"
|
||||
: "=a"(ax), "=D"(di)
|
||||
: "0"((IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"rm"(syscall)
|
||||
"rm"(syscall_)
|
||||
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ static int Read(int fd, void *data, int size, int os) {
|
||||
asm volatile("call\t*%8"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||
: "0"((IsLinux() ? 0 : 3) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"2"(data), "3"(size), "rm"(syscall)
|
||||
"2"(data), "3"(size), "rm"(syscall_)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
return ax;
|
||||
}
|
||||
@@ -306,7 +306,7 @@ static void Write(int fd, const void *data, int size, int os) {
|
||||
asm volatile("call\t*%8"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||
: "0"((IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"2"(data), "3"(size), "rm"(syscall)
|
||||
"2"(data), "3"(size), "rm"(syscall_)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ static void Execve(const char *prog, char **argv, char **envp, int os) {
|
||||
asm volatile("call\t*%8"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||
: "0"(59 | (IsXnu() ? 0x2000000 : 0)), "1"(prog), "2"(argv),
|
||||
"3"(envp), "rm"(syscall)
|
||||
"3"(envp), "rm"(syscall_)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ static int Access(const char *path, int mode, int os) {
|
||||
asm volatile("call\t*%7"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||
: "0"((IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(mode), "rm"(syscall)
|
||||
"1"(path), "2"(mode), "rm"(syscall_)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ static int Msyscall(long p, long n, int os) {
|
||||
} else {
|
||||
asm volatile("call\t*%6"
|
||||
: "=a"(ax), "=D"(di), "=S"(si)
|
||||
: "0"(37), "1"(p), "2"(n), "rm"(syscall)
|
||||
: "0"(37), "1"(p), "2"(n), "rm"(syscall_)
|
||||
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
@@ -350,7 +350,7 @@ static int Open(const char *path, int flags, int mode, int os) {
|
||||
asm volatile("call\t*%8"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||
: "0"((IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(flags), "3"(mode), "rm"(syscall)
|
||||
"1"(path), "2"(flags), "3"(mode), "rm"(syscall_)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
@@ -369,7 +369,7 @@ __attribute__((__noinline__)) static long Mmap(long addr, long size, int prot,
|
||||
"pop\t%%r9"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx), "+r"(flags_),
|
||||
"+r"(fd_), "+r"(off_)
|
||||
: "rm"(syscall),
|
||||
: "rm"(syscall_),
|
||||
"0"((IsLinux() ? 9
|
||||
: IsFreebsd() ? 477
|
||||
: 197) |
|
||||
@@ -379,7 +379,7 @@ __attribute__((__noinline__)) static long Mmap(long addr, long size, int prot,
|
||||
return ax;
|
||||
}
|
||||
|
||||
static int MunmapLinux(const void *addr, unsigned long size) {
|
||||
int MunmapLinux(const void *addr, unsigned long size) {
|
||||
int ax;
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
@@ -388,7 +388,7 @@ static int MunmapLinux(const void *addr, unsigned long size) {
|
||||
return ax;
|
||||
}
|
||||
|
||||
static int PrctlLinux(int op, long a, long b, long c, long d) {
|
||||
int PrctlLinux(int op, long a, long b, long c, long d) {
|
||||
int rc;
|
||||
asm volatile("mov\t%5,%%r10\n\t"
|
||||
"mov\t%6,%%r8\n\t"
|
||||
@@ -589,7 +589,7 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
||||
// since it probably means a userspace program executed this loader
|
||||
// and passed us a custom syscall function earlier.
|
||||
if (Msyscall(code, codesize, os) != -1) {
|
||||
syscall = 0;
|
||||
syscall_ = 0;
|
||||
}
|
||||
|
||||
#if TROUBLESHOOT
|
||||
@@ -600,7 +600,7 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
||||
// to extend the behavior of this loader in the future. we don't need
|
||||
// to clear the xmm registers since the ape loader should be compiled
|
||||
// with the -mgeneral-regs-only flag.
|
||||
register void *r8 asm("r8") = syscall;
|
||||
register void *r8 asm("r8") = syscall_;
|
||||
asm volatile("xor\t%%eax,%%eax\n\t"
|
||||
"xor\t%%r9d,%%r9d\n\t"
|
||||
"xor\t%%r10d,%%r10d\n\t"
|
||||
@@ -659,10 +659,10 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
||||
}
|
||||
|
||||
// get syscall function pointer
|
||||
if (handoff && handoff->syscall) {
|
||||
syscall = handoff->syscall;
|
||||
if (handoff && handoff->systemcall) {
|
||||
syscall_ = handoff->systemcall;
|
||||
} else {
|
||||
syscall = __syscall_loader;
|
||||
syscall_ = __syscall_loader;
|
||||
}
|
||||
|
||||
if (handoff) {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ struct ApeLoader {
|
||||
int os;
|
||||
char *prog;
|
||||
char *page;
|
||||
void *syscall;
|
||||
void *systemcall;
|
||||
};
|
||||
|
||||
#endif /* COSMOPOLITAN_APE_LOADER_H_ */
|
||||
+65
-37
@@ -180,6 +180,20 @@
|
||||
.stub \name\()_bcs\n,long
|
||||
.endm
|
||||
|
||||
// Task State Segment Descriptor Entries.
|
||||
.macro .tssdescstub name:req
|
||||
.ifndef \name
|
||||
.weak \name
|
||||
.set \name,0
|
||||
.endif
|
||||
.ifndef \name\()_end
|
||||
.weak \name\()_end
|
||||
.set \name\()_end,0
|
||||
.endif
|
||||
.stub \name\()_desc_ent0,quad
|
||||
.stub \name\()_desc_ent1,quad
|
||||
.endm
|
||||
|
||||
/* clang-format on */
|
||||
#elif defined(__LINKER__)
|
||||
|
||||
@@ -221,44 +235,58 @@
|
||||
/**
|
||||
* Binary coded decimal support.
|
||||
*
|
||||
* <p>This allows linker scripts to generate dd commands. Leading spaces
|
||||
* need to be inserted so Mac doesn't consider them octal; therefore,
|
||||
* parameters must be quoted; and eight digits should be good enough.
|
||||
* <p>This allows linker scripts to generate dd commands, e.g. ape.lds.
|
||||
* There are a few ways to pad each number to the necessary 8 bytes.
|
||||
* Spaces cannot be prepended because busybox refuses to parse them.
|
||||
* Zeros cannot be prepended because Mac will take numbers as octal.
|
||||
* That leaves appending spaces. The user's shell ought to treat any
|
||||
* unquoted run of spaces as if there was only one, so this is safe.
|
||||
*/
|
||||
#define SHSTUB2(SYM, X) \
|
||||
HIDDEN(SYM##_bcs0 = BCD10K(X)); \
|
||||
HIDDEN(SYM##_bcs1 = BCD(X))
|
||||
#define BCD(X) \
|
||||
((X) == 0 \
|
||||
? 0x20202030 \
|
||||
: (X) < 10 ? 0x30202020 + (((X) % 10) << 24) \
|
||||
: (X) < 100 ? 0x30302020 + (((X) % 10) << 24) + \
|
||||
(((X) / 10 % 10) << 16) \
|
||||
: (X) < 1000 ? 0x30303020 + (((X) % 10) << 24) + \
|
||||
(((X) / 10 % 10) << 16) + \
|
||||
(((X) / 100 % 10) << 8) \
|
||||
: 0x30303030 + (((X) % 10) << 24) + \
|
||||
(((X) / 10 % 10) << 16) + \
|
||||
(((X) / 100 % 10) << 8) + \
|
||||
(((X) / 1000 % 10) << 0))
|
||||
#define BCD10K(X) \
|
||||
((X) < 10000 \
|
||||
? 0x20202020 \
|
||||
: (X) < 100000 \
|
||||
? 0x30202020 + (((X) / 10000 % 10) << 24) \
|
||||
: (X) < 1000000 \
|
||||
? 0x30302020 + (((X) / 10000 % 10) << 24) + \
|
||||
(((X) / 100000 % 10) << 16) \
|
||||
: (X) < 10000000 \
|
||||
? 0x30303020 + (((X) / 10000 % 10) << 24) + \
|
||||
(((X) / 100000 % 10) << 16) + \
|
||||
(((X) / 1000000 % 10) << 8) \
|
||||
: (X) < 100000000 \
|
||||
? 0x30303030 + (((X) / 10000 % 10) << 24) + \
|
||||
(((X) / 100000 % 10) << 16) + \
|
||||
(((X) / 1000000 % 10) << 8) + \
|
||||
(((X) / 10000000 % 10) << 0) \
|
||||
: 0xffffffffffffffff)
|
||||
#define SHSTUB2(SYM, X) \
|
||||
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
|
||||
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
|
||||
#define BCD_SMEAR(X) ((X) + (X) * 10000)
|
||||
#define BCD_LEFT(X) \
|
||||
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
|
||||
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
|
||||
: (X) < 1000000 ? BCD_RIGHT(BCD_SMEAR((X) / 100)) \
|
||||
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
|
||||
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + \
|
||||
(X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + \
|
||||
((X) / 10) % 10 + \
|
||||
(X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + \
|
||||
((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + \
|
||||
(X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 ? 0x30303030 + \
|
||||
((X) / 1000) % 10 + \
|
||||
((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + \
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
*/
|
||||
#define TSSDESCSTUB2(SYM, BASE, LIM) \
|
||||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
@@ -0,0 +1 @@
|
||||
#include "ape/ape.lds"
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
*/
|
||||
#define REAL(x) ((x) - (IMAGE_BASE_VIRTUAL - IMAGE_BASE_REAL))
|
||||
|
||||
#if IMAGE_BASE_VIRTUAL % 0x200000 != 0
|
||||
#error "IMAGE_BASE_VIRTUAL must be 2mb aligned"
|
||||
#if IMAGE_BASE_VIRTUAL % 0x1000 != 0
|
||||
#error "IMAGE_BASE_VIRTUAL must be 4kb aligned"
|
||||
#endif
|
||||
#if IMAGE_BASE_PHYSICAL % 0x1000 != 0
|
||||
#error "IMAGE_BASE_PHYSICAL must be 4kb aligned"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+95
-63
@@ -4,20 +4,35 @@
|
||||
# Default Mode
|
||||
#
|
||||
# - `make`
|
||||
# - Optimized
|
||||
# - Backtraces
|
||||
# - Debuggable
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - Reasonably small
|
||||
# - Reasonably optimized
|
||||
# - Reasonably debuggable
|
||||
#
|
||||
ifeq ($(MODE),)
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-DSYSDEBUG \
|
||||
-O2
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Fast Build Mode
|
||||
#
|
||||
# - `make MODE=fastbuild`
|
||||
# - No debugging
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - Some optimizations
|
||||
# - Limited Backtraces
|
||||
# - Compiles 28% faster
|
||||
#
|
||||
ifeq ($(MODE),fastbuild)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
CONFIG_OFLAGS += -g0
|
||||
CONFIG_LDFLAGS += -S
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Optimized Mode
|
||||
@@ -31,19 +46,11 @@ endif
|
||||
# - No memory corruption detection
|
||||
# - assert() / CHECK_xx() may leak code into binary for debuggability
|
||||
# - GCC 8+ hoists check fails into .text.cold, thus minimizing impact
|
||||
#
|
||||
ifeq ($(MODE), opt)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DNDEBUG \
|
||||
-msse2avx \
|
||||
-Wa,-msse2avx
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-DSYSDEBUG \
|
||||
-O3 \
|
||||
-fmerge-all-constants
|
||||
TARGET_ARCH ?= \
|
||||
-march=native
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -msse2avx -Wa,-msse2avx
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O3 -fmerge-all-constants
|
||||
TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
|
||||
# Optimized Linux Mode
|
||||
@@ -54,18 +61,12 @@ endif
|
||||
# - Turns off function tracing
|
||||
# - Turns off support for older cpu models
|
||||
# - Turns off support for other operating systems
|
||||
#
|
||||
ifeq ($(MODE), optlinux)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DNDEBUG \
|
||||
-msse2avx \
|
||||
-Wa,-msse2avx \
|
||||
-DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += \
|
||||
-O3 -fmerge-all-constants
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
TARGET_ARCH ?= \
|
||||
-march=native
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -msse2avx -Wa,-msse2avx -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
DEFAULT_COPTS += -mred-zone
|
||||
TARGET_ARCH ?= -march=native
|
||||
endif
|
||||
|
||||
# Release Mode
|
||||
@@ -81,16 +82,12 @@ endif
|
||||
# - DCHECK_xx() statements removed
|
||||
# - No memory corruption detection
|
||||
# - CHECK_xx() won't leak strings into binary
|
||||
#
|
||||
ifeq ($(MODE), rel)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DNDEBUG
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
-O2
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
-O1
|
||||
CONFIG_CPPFLAGS += -DNDEBUG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
TARGET_ARCH ?= -msse3
|
||||
PYFLAGS += -O1
|
||||
endif
|
||||
|
||||
# Asan Mode
|
||||
@@ -103,14 +100,11 @@ endif
|
||||
# - Backtraces
|
||||
# - Debuggability
|
||||
# - Larger binaries
|
||||
#
|
||||
ifeq ($(MODE), asan)
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
-O2
|
||||
CONFIG_COPTS += \
|
||||
-fsanitize=address
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Debug Mode
|
||||
@@ -122,22 +116,13 @@ endif
|
||||
# - Stack canaries
|
||||
# - No optimization (TODO)
|
||||
# - Enormous binaries
|
||||
#
|
||||
ifeq ($(MODE), dbg)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DMODE_DBG
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-DSYSDEBUG \
|
||||
-O2 \
|
||||
-fno-inline
|
||||
CONFIG_COPTS += \
|
||||
-fsanitize=address \
|
||||
-fsanitize=undefined
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
OVERRIDE_CCFLAGS += \
|
||||
-fno-pie
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O -fno-inline
|
||||
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
|
||||
TARGET_ARCH ?= -msse3
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
endif
|
||||
|
||||
# Tiny Mode
|
||||
@@ -151,6 +136,7 @@ endif
|
||||
# - No backtraces
|
||||
# - No algorithmics
|
||||
# - YOLO
|
||||
#
|
||||
ifeq ($(MODE), tiny)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
@@ -166,6 +152,10 @@ CONFIG_CCFLAGS += \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
@@ -185,6 +175,7 @@ endif
|
||||
# - No portability
|
||||
# - No algorithmics
|
||||
# - YOLO
|
||||
#
|
||||
ifeq ($(MODE), tinylinux)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
@@ -193,6 +184,10 @@ CONFIG_CPPFLAGS += \
|
||||
-DSUPPORT_VECTOR=1
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
@@ -216,6 +211,7 @@ endif
|
||||
# - No backtraces
|
||||
# - No algorithmics
|
||||
# - YOLO
|
||||
#
|
||||
ifeq ($(MODE), tinylinuxbsd)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
@@ -224,6 +220,10 @@ CONFIG_CPPFLAGS += \
|
||||
-DSUPPORT_VECTOR=113
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
@@ -246,6 +246,7 @@ endif
|
||||
# - No backtraces
|
||||
# - No algorithmics
|
||||
# - YOLO
|
||||
#
|
||||
ifeq ($(MODE), tinysysv)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
@@ -260,6 +261,10 @@ CONFIG_CCFLAGS += \
|
||||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
@@ -276,6 +281,7 @@ endif
|
||||
# - No backtraces
|
||||
# - No algorithmics
|
||||
# - YOLO
|
||||
#
|
||||
ifeq ($(MODE), tinynowin)
|
||||
CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
@@ -288,10 +294,36 @@ CONFIG_CCFLAGS += \
|
||||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# GCC11 Mode
|
||||
# https://justine.lol/compilers/x86_64-linux-musl__x86_64-linux-musl__g++-11.2.0.tar.xz
|
||||
ifeq ($(MODE), gcc11)
|
||||
.UNVEIL += rx:/opt/gcc11
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
|
||||
AS = /opt/gcc11/bin/x86_64-linux-musl-as
|
||||
CC = /opt/gcc11/bin/x86_64-linux-musl-gcc
|
||||
CXX = /opt/gcc11/bin/x86_64-linux-musl-g++
|
||||
CXXFILT = /opt/gcc11/bin/x86_64-linux-musl-c++filt
|
||||
LD = /opt/gcc11/bin/x86_64-linux-musl-ld.bfd
|
||||
NM = /opt/gcc11/bin/x86_64-linux-musl-nm
|
||||
GCC = /opt/gcc11/bin/x86_64-linux-musl-gcc
|
||||
STRIP = /opt/gcc11/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = /opt/gcc11/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = /opt/gcc11/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = /opt/gcc11/bin/x86_64-linux-musl-addr2line
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2 -Wno-stringop-overread
|
||||
CONFIG_CFLAGS += -Wno-old-style-definition
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# LLVM Mode
|
||||
ifeq ($(MODE), llvm)
|
||||
TARGET_ARCH ?= -msse3
|
||||
|
||||
+22
-24
@@ -65,7 +65,6 @@ ZIPOBJ = build/bootstrap/zipobj.com
|
||||
FIXUPOBJ = build/bootstrap/fixupobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
|
||||
SYMTAB = $(TMPDIR)/$(subst /,_,$@).symtab
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell build/bootstrap/pwd.com)
|
||||
@@ -74,33 +73,25 @@ IMAGE_BASE_VIRTUAL ?= 0x400000
|
||||
IGNORE := $(shell $(ECHO) -2 ♥cosmo)
|
||||
IGNORE := $(shell $(MKDIR) o/tmp)
|
||||
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","")
|
||||
AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe
|
||||
CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe
|
||||
LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe
|
||||
NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe
|
||||
GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
|
||||
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
|
||||
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
|
||||
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
|
||||
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
|
||||
endif
|
||||
|
||||
AS = $(PREFIX)as
|
||||
CC = $(PREFIX)gcc
|
||||
CXX = $(PREFIX)g++
|
||||
CXXFILT = $(PREFIX)c++filt
|
||||
LD = $(PREFIX)ld.bfd
|
||||
NM = $(PREFIX)nm
|
||||
GCC = $(PREFIX)gcc
|
||||
STRIP = $(PREFIX)strip
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
@@ -108,6 +99,12 @@ export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
ifeq ($(LANDLOCKMAKE_VERSION),)
|
||||
TMPSAFE = $(TMPDIR)/$(subst /,_,$@).tmp
|
||||
else
|
||||
TMPSAFE = $(TMPDIR)/
|
||||
endif
|
||||
|
||||
FTRACE = \
|
||||
-pg
|
||||
|
||||
@@ -143,6 +140,7 @@ DEFAULT_CCFLAGS = \
|
||||
|
||||
DEFAULT_OFLAGS = \
|
||||
-g \
|
||||
-gdwarf-4 \
|
||||
-gdescribe-dies
|
||||
|
||||
DEFAULT_COPTS = \
|
||||
|
||||
+5
-1
@@ -12,5 +12,9 @@
|
||||
|
||||
tail = $(wordlist 2,$(words $1),$1)
|
||||
reverse = $(if $1,$(call reverse,$(call tail,$1)) $(firstword $1))
|
||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||
uniqr = $(if $1,$(call uniqr,$(filter-out $(firstword $1),$1)) $(firstword $1))
|
||||
|
||||
# polyfill uniq native (landlock make 1.4)
|
||||
ifneq ($(call uniq,c b c a),c b a)
|
||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||
endif
|
||||
+119
-19
@@ -25,7 +25,6 @@ o/%.o: o/%.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(
|
||||
o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
||||
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
|
||||
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||
o/%.zip.o: o/% ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||
@@ -44,14 +43,6 @@ o/$(MODE)/%.initabi.o: %.initabi.c ; @$(COMPILE) -AOBJECTIFY.init $(OBJECTIFY.in
|
||||
o/$(MODE)/%.ncabi.o: %.ncabi.c ; @$(COMPILE) -AOBJECTIFY.nc $(OBJECTIFY.ncabi.c) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -wtT$@ $< $(TESTARGS)
|
||||
o/$(MODE)/%.zip.o: % ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
|
||||
o/%.o: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
||||
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
|
||||
@@ -77,12 +68,12 @@ o/%.a:
|
||||
@$(COMPILE) -AARCHIVE -wT$@ $(AR) $(ARFLAGS) $@ @$(TMPDIR)/$(subst /,_,$@)
|
||||
|
||||
o/%.pkg:
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@).args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPDIR)/$(subst /,_,$@)
|
||||
$(file >$(TMPSAFE).args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
|
||||
|
||||
o/$(MODE)/%.pkg:
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPDIR)/$(subst /,_,$@)
|
||||
$(file >$(TMPSAFE).args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
|
||||
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||
@@ -101,18 +92,86 @@ o/$(MODE)/%: o/$(MODE)/%.com o/$(MODE)/tool/build/cp.com o/$(MODE)/tool/build/as
|
||||
@$(COMPILE) -wAASSIMILATE -T$@ o/$(MODE)/tool/build/assimilate.com $@
|
||||
|
||||
################################################################################
|
||||
# strict header checking
|
||||
# these rules are unsandboxed since they're kind of a sandboxing test themselves
|
||||
# LOCAL UNIT TESTS
|
||||
#
|
||||
# We always run unit tests as part of the normal `make` invocation. you
|
||||
# may override the $(TESTARGS) variable to do things such as enable the
|
||||
# benchmarking feature. For example:
|
||||
#
|
||||
# TESTARGS = -b
|
||||
#
|
||||
# May be specified in your ~/.cosmo.mk file. You can also use this to
|
||||
# enable things like function tracing. For example:
|
||||
#
|
||||
# TESTARGS = ----ftrace
|
||||
# .PLEDGE += prot_exec
|
||||
#
|
||||
# You could then run a command like:
|
||||
#
|
||||
# make -j8 o//test/libc/calls/openbsd_test.com.runs
|
||||
#
|
||||
# You need PROT_EXEC permission since ftrace morphs the binary. It's
|
||||
# also worth mentioning that the pledge.com command can simulate what
|
||||
# Landlock Make does:
|
||||
#
|
||||
# o//tool/build/pledge.com \
|
||||
# -v. -p 'stdio rpath wpath cpath tty prot_exec' \
|
||||
# o//test/libc/calls/openbsd_test.com \
|
||||
# ----ftrace
|
||||
#
|
||||
# This is useful in the event a test binary should run by itself, but
|
||||
# fails to run beneath Landlock Make. It's also useful sometimes to
|
||||
# override the verbosity when running tests:
|
||||
#
|
||||
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.com.runs
|
||||
#
|
||||
# This way, if for some reason a test should fail but calls exit(0),
|
||||
# then the stdout/stderr output, which would normally be suppressed,
|
||||
# will actually be displayed.
|
||||
|
||||
o/%.h.ok: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.runs: o/$(MODE)/%
|
||||
@$(COMPILE) -ACHECK -wtT$@ $< $(TESTARGS)
|
||||
|
||||
################################################################################
|
||||
# ELF ZIP FILES
|
||||
#
|
||||
# zipobj.com lets us do fast incremental linking of compressed data.
|
||||
# it's nice because if we link a hundred binaries that use the time zone
|
||||
# database, then that database only needs to be DEFLATE'd once.
|
||||
|
||||
o/%.zip.o: o/%
|
||||
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.zip.o: %
|
||||
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.zip.o: %
|
||||
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
# an issue with sandboxing arises when creating directory entries in the
|
||||
# zip file. we need the trailing slash (e.g. o//foo/.zip.o) but Landlock
|
||||
# Make avoids sandboxing directory names that have a trailing slash (so
|
||||
# they can be used to watch for deleted files, without creating overly
|
||||
# broad unveiling). such rules need to be written more explicitly.
|
||||
o/$(MODE)%/.zip.o: %
|
||||
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
################################################################################
|
||||
# STRICT HEADER CHECKING
|
||||
#
|
||||
# these rules are unsandboxed since they're already a sandboxing test,
|
||||
# and it would be too costly in terms of make latency to have every
|
||||
# header file depend on $(HDRS) and $(INCS).
|
||||
|
||||
o/%.h.ok: private .UNSANDBOXED = 1
|
||||
o/%.h.ok: %.h
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.h.ok: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.h.ok: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.h.ok: %.h
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.hh.ok: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.hh.ok: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.hh.ok: %.hh
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
@@ -120,6 +179,47 @@ o/%.okk: .UNSANDBOXED = 1
|
||||
o/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.okk: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.okk: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
################################################################################
|
||||
# EXECUTABLE HELPERS
|
||||
|
||||
MAKE_OBJCOPY = \
|
||||
$(COMPILE) -AOBJCOPY -T$@ \
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
MAKE_SYMTAB_CREATE = \
|
||||
$(COMPILE) -wASYMTAB \
|
||||
o/$(MODE)/tool/build/symtab.com \
|
||||
-o $(TMPSAFE)/.symtab \
|
||||
$<
|
||||
|
||||
MAKE_SYMTAB_ZIP = \
|
||||
$(COMPILE) -AZIP -T$@ \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
-b$(TMPDIR) \
|
||||
-9qj \
|
||||
$@ \
|
||||
$(TMPSAFE)/.symtab
|
||||
|
||||
################################################################################
|
||||
# EMACS ASSEMBLY GENERATION
|
||||
|
||||
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: %.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: %.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
+2
-2
@@ -67,7 +67,7 @@ plm_buffer_t *plm_buffer_create_with_file(FILE *fh, int close_when_done) {
|
||||
|
||||
plm_buffer_t *plm_buffer_create_with_memory(unsigned char *bytes, size_t length, int free_when_done) {
|
||||
plm_buffer_t *b;
|
||||
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
b = memalign(_Alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
memset(b, 0, sizeof(plm_buffer_t));
|
||||
b->capacity = length;
|
||||
b->length = length;
|
||||
@@ -79,7 +79,7 @@ plm_buffer_t *plm_buffer_create_with_memory(unsigned char *bytes, size_t length,
|
||||
|
||||
plm_buffer_t * plm_buffer_create_with_capacity(size_t capacity) {
|
||||
plm_buffer_t *b;
|
||||
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
b = memalign(_Alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
memset(b, 0, sizeof(plm_buffer_t));
|
||||
b->capacity = capacity;
|
||||
b->free_when_done = true;
|
||||
|
||||
+1
-1
@@ -277,7 +277,7 @@ void plm_audio_read_samples(plm_audio_t *self, int ch, int sb, int part);
|
||||
void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp);
|
||||
|
||||
plm_audio_t *plm_audio_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) {
|
||||
plm_audio_t *self = (plm_audio_t *)memalign(alignof(plm_audio_t), sizeof(plm_audio_t));
|
||||
plm_audio_t *self = (plm_audio_t *)memalign(_Alignof(plm_audio_t), sizeof(plm_audio_t));
|
||||
memset(self, 0, sizeof(plm_audio_t));
|
||||
|
||||
self->samples.count = PLM_AUDIO_SAMPLES_PER_FRAME;
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
#include "dsp/core/ituround.h"
|
||||
#include "dsp/core/q.h"
|
||||
#include "dsp/core/twixt8.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
@@ -203,8 +203,8 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
|
||||
CHECK_LE(sxn, sxw);
|
||||
CHECK_LE(dyn, dyw);
|
||||
CHECK_LE(dxn, dxw);
|
||||
CHECK_LT(bsrl(syn) + bsrl(sxn), 32);
|
||||
CHECK_LT(bsrl(dyn) + bsrl(dxn), 32);
|
||||
CHECK_LT(_bsrl(syn) + _bsrl(sxn), 32);
|
||||
CHECK_LT(_bsrl(dyn) + _bsrl(dxn), 32);
|
||||
CHECK_LE(dyw, 0x7fff);
|
||||
CHECK_LE(dxw, 0x7fff);
|
||||
CHECK_LE(syw, 0x7fff);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
|
||||
const struct termios *opt_out_oldconf) {
|
||||
struct termios *opt_out_oldconf) {
|
||||
struct termios conf[2];
|
||||
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
|
||||
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
|
||||
|
||||
+4
-3
@@ -83,10 +83,11 @@ int ttyident(struct TtyIdent *ti, int ttyinfd, int ttyoutfd) {
|
||||
if (ttyident_probe(ti, ttyinfd, ttyoutfd, "\e[>c") != -1) {
|
||||
rc = 0;
|
||||
memset(&outer, 0, sizeof(outer));
|
||||
if (ti->id == 83 /* GNU Screen */ && (ti->next || weaken(malloc)) &&
|
||||
if (ti->id == 83 /* GNU Screen */ && (ti->next || _weaken(malloc)) &&
|
||||
ttyident_probe(&outer, ttyinfd, ttyoutfd, "\eP\e[>c\e\\") != -1 &&
|
||||
(ti->next = (ti->next ? ti->next
|
||||
: weaken(malloc)(sizeof(struct TtyIdent))))) {
|
||||
(ti->next =
|
||||
(ti->next ? ti->next
|
||||
: _weaken(malloc)(sizeof(struct TtyIdent))))) {
|
||||
memcpy(ti->next, &outer, sizeof(outer));
|
||||
} else {
|
||||
free_s(&ti->next);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ int ttysendtitle(int, const char *, const struct TtyIdent *);
|
||||
int ttyident(struct TtyIdent *, int, int);
|
||||
void ttyidentclear(struct TtyIdent *);
|
||||
char *ttydescribe(char *, size_t, const struct TtyIdent *);
|
||||
int ttyconfig(int, ttyconf_f, int64_t, const struct termios *);
|
||||
int ttyconfig(int, ttyconf_f, int64_t, struct termios *);
|
||||
int ttyrestore(int, const struct termios *);
|
||||
int ttysetrawdeadline(struct termios *, int64_t);
|
||||
int ttysetrawmode(struct termios *, int64_t);
|
||||
|
||||
+5
-4
@@ -25,7 +25,7 @@
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
@@ -97,8 +98,8 @@ static relegated void ttyraw_onsig(int sig, struct siginfo *info,
|
||||
}
|
||||
for (i = 0; i < ARRAYLEN(g_ttyraw.sigs); ++i) {
|
||||
if (g_ttyraw.sigs[i] == sig) {
|
||||
if (g_ttyraw.next[i] != SIG_IGN) {
|
||||
if (g_ttyraw.next[i] != SIG_DFL) {
|
||||
if (g_ttyraw.next[i] != (void *)SIG_IGN) {
|
||||
if (g_ttyraw.next[i] != (void *)SIG_DFL) {
|
||||
if (g_ttyraw.next[i]) {
|
||||
g_ttyraw.next[i](sig, info, ctx);
|
||||
}
|
||||
@@ -117,7 +118,7 @@ static textstartup void ttyraw_initsig(int sig, unsigned flags, unsigned mask) {
|
||||
struct sigaction old;
|
||||
g_ttyraw.next[i] = xsigaction(sig, ttyraw_onsig, flags, mask, &old) != -1
|
||||
? old.sa_sigaction
|
||||
: SIG_DFL;
|
||||
: (void *)SIG_DFL;
|
||||
g_ttyraw.sigs[i++] = sig;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* @fileoverview clock() function demo
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned long i;
|
||||
volatile unsigned long x;
|
||||
struct timespec now, start, next, interval;
|
||||
printf("hammering the cpu...\n");
|
||||
next = start = _timespec_mono();
|
||||
interval = _timespec_frommillis(500);
|
||||
next = _timespec_add(next, interval);
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
x *= 7;
|
||||
if (!(i % 256)) {
|
||||
now = _timespec_mono();
|
||||
if (_timespec_gte(now, next)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
next = _timespec_add(next, interval);
|
||||
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
|
||||
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000.,
|
||||
(double)clock() / CLOCKS_PER_SEC);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
int n;
|
||||
int shown[64];
|
||||
|
||||
void show(int clock) {
|
||||
int i;
|
||||
struct timespec ts;
|
||||
if (clock == 127) return;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (shown[i] == clock) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
shown[n++] = clock;
|
||||
if (clock_getres(clock, &ts) != -1) {
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
|
||||
} else {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
show(CLOCK_REALTIME);
|
||||
show(CLOCK_REALTIME_FAST);
|
||||
show(CLOCK_REALTIME_PRECISE);
|
||||
show(CLOCK_MONOTONIC);
|
||||
show(CLOCK_MONOTONIC_RAW);
|
||||
show(CLOCK_MONOTONIC_FAST);
|
||||
show(CLOCK_MONOTONIC_PRECISE);
|
||||
show(CLOCK_PROCESS_CPUTIME_ID);
|
||||
show(CLOCK_THREAD_CPUTIME_ID);
|
||||
show(CLOCK_PROF);
|
||||
show(CLOCK_BOOTTIME);
|
||||
show(CLOCK_REALTIME_ALARM);
|
||||
show(CLOCK_BOOTTIME_ALARM);
|
||||
show(CLOCK_TAI);
|
||||
show(CLOCK_UPTIME);
|
||||
show(CLOCK_UPTIME_PRECISE);
|
||||
show(CLOCK_UPTIME_FAST);
|
||||
show(CLOCK_SECOND);
|
||||
}
|
||||
+2
-1
@@ -8,11 +8,12 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
+5
-3
@@ -9,19 +9,21 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/appendresourcereport.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
@@ -152,7 +154,7 @@ int main(int argc, char *argv[]) {
|
||||
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
|
||||
n = 0;
|
||||
start = line;
|
||||
if (startswith(start, "time ")) {
|
||||
if (_startswith(start, "time ")) {
|
||||
timeit = true;
|
||||
start += 5;
|
||||
} else {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
|
||||
+6
-5
@@ -7,7 +7,6 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -15,15 +14,16 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/goodsocket.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/slice.h"
|
||||
#include "libc/str/str.h"
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "libc/sysv/consts/tcp.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "net/http/http.h"
|
||||
#include "net/http/url.h"
|
||||
#include "net/https/https.h"
|
||||
@@ -182,7 +183,7 @@ int main(int argc, char *argv[]) {
|
||||
struct Url url;
|
||||
char *host, *port;
|
||||
bool usessl = false;
|
||||
_gc(ParseUrl(urlarg, -1, &url));
|
||||
_gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
|
||||
_gc(url.params.p);
|
||||
if (url.scheme.n) {
|
||||
if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) {
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
+2
-2
@@ -7,9 +7,9 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
/**
|
||||
* @fileoverview ISO-8601 international high-precision timestamp printer.
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,12 +66,14 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_VGA \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
@@ -79,6 +81,8 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
|
||||
+1
-9
@@ -8,21 +8,13 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
dontinline void dostuff(const char *s) {
|
||||
int i, us;
|
||||
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
us = rand() % 500000;
|
||||
usleep(us);
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
return 0;
|
||||
char *p = _gc(malloc(64));
|
||||
strcpy(p, "this memory is free'd when main() returns");
|
||||
}
|
||||
+4
-14
@@ -7,19 +7,9 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int c, n;
|
||||
char a[22], *p;
|
||||
if ((c = GetCpuCount())) {
|
||||
p = FormatInt64(a, c);
|
||||
*p++ = '\n';
|
||||
return write(1, a, p - a) == p - a ? 0 : 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
int main() {
|
||||
kprintf("%d\n", _getcpucount());
|
||||
}
|
||||
@@ -7,20 +7,21 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/xorshift.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/xorshift.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
@@ -101,7 +102,7 @@ uint64_t rngset64(void) {
|
||||
static unsigned i;
|
||||
static uint64_t s;
|
||||
if (!i) {
|
||||
s = rand64();
|
||||
s = _rand64();
|
||||
i = (s + 1) & (511);
|
||||
}
|
||||
return MarsagliaXorshift64(&s);
|
||||
@@ -214,7 +215,7 @@ const struct Function {
|
||||
{"moby", moby}, //
|
||||
{"mt19937", _mt19937}, //
|
||||
{"python", pythonx2}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rand64", _rand64}, //
|
||||
{"rdrand", rdrand}, //
|
||||
{"rdrnd", rdrand}, //
|
||||
{"rdseed", rdseed}, //
|
||||
|
||||
+22
-20
@@ -8,27 +8,26 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.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/atomic.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
@@ -47,6 +46,9 @@
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/consts/tcp.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/wait0.internal.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "net/http/http.h"
|
||||
@@ -103,14 +105,14 @@
|
||||
"Cache-Control: private; max-age=0\r\n"
|
||||
|
||||
int threads;
|
||||
_Atomic(int) workers;
|
||||
_Atomic(int) messages;
|
||||
_Atomic(int) listening;
|
||||
_Atomic(int) connections;
|
||||
_Atomic(int) closingtime;
|
||||
atomic_int workers;
|
||||
atomic_int messages;
|
||||
atomic_int listening;
|
||||
atomic_int connections;
|
||||
atomic_int closingtime;
|
||||
const char *volatile status;
|
||||
|
||||
int Worker(void *id, int tid) {
|
||||
void *Worker(void *id) {
|
||||
int server, yes = 1;
|
||||
|
||||
// load balance incoming connections for port 8080 across all threads
|
||||
@@ -134,7 +136,7 @@ int Worker(void *id, int tid) {
|
||||
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
|
||||
errno = 0;
|
||||
|
||||
if (bind(server, &addr, sizeof(addr)) == -1) {
|
||||
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
kprintf("%s() failed %m\n", "socket");
|
||||
goto CloseWorker;
|
||||
}
|
||||
@@ -164,7 +166,7 @@ int Worker(void *id, int tid) {
|
||||
|
||||
// wait for client connection
|
||||
clientaddrsize = sizeof(clientaddr);
|
||||
client = accept(server, &clientaddr, &clientaddrsize);
|
||||
client = accept(server, (struct sockaddr *)&clientaddr, &clientaddrsize);
|
||||
|
||||
// accept() can raise a very diverse number of errors but none of
|
||||
// them are really true showstoppers that would necessitate us to
|
||||
@@ -276,8 +278,8 @@ void PrintStatus(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
struct spawn *th;
|
||||
int i, rc;
|
||||
pthread_t *th;
|
||||
uint32_t *hostips;
|
||||
// ShowCrashReports();
|
||||
|
||||
@@ -296,9 +298,9 @@ int main(int argc, char *argv[]) {
|
||||
PORT);
|
||||
}
|
||||
|
||||
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
|
||||
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
|
||||
if (!(1 <= threads && threads <= 100000)) {
|
||||
kprintf("error: invalid number of threads\n");
|
||||
kprintf("error: invalid number of threads: %d\n", threads);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -309,12 +311,12 @@ int main(int argc, char *argv[]) {
|
||||
pledge("stdio inet", 0);
|
||||
|
||||
// spawn over 9,000 worker threads
|
||||
th = calloc(threads, sizeof(*th));
|
||||
th = calloc(threads, sizeof(pthread_t));
|
||||
for (i = 0; i < threads; ++i) {
|
||||
++workers;
|
||||
if (_spawn(Worker, (void *)(intptr_t)i, th + i) == -1) {
|
||||
if ((rc = pthread_create(th + i, 0, Worker, (void *)(intptr_t)i))) {
|
||||
--workers;
|
||||
kprintf("error: _spawn(%d) failed %m\n", i);
|
||||
kprintf("error: pthread_create(%d) failed %s\n", i, strerror(rc));
|
||||
}
|
||||
if (!(i % 500)) {
|
||||
PrintStatus();
|
||||
@@ -332,7 +334,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// join the workers
|
||||
for (i = 0; i < threads; ++i) {
|
||||
_join(th + i);
|
||||
pthread_join(th[i], 0);
|
||||
}
|
||||
|
||||
// clean up memory
|
||||
|
||||
+1
-2
@@ -14,8 +14,7 @@
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
const struct itimerval kHertz = {
|
||||
{1, 0},
|
||||
|
||||
+6
-4
@@ -8,12 +8,14 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char hostname[254];
|
||||
CHECK_NE(-1, gethostname(hostname, sizeof(hostname)));
|
||||
puts(hostname);
|
||||
char name[254];
|
||||
gethostname(name, sizeof(name));
|
||||
kprintf("gethostname() → %#s\n", name);
|
||||
getdomainname(name, sizeof(name));
|
||||
kprintf("getdomainname() → %#s\n", name);
|
||||
return 0;
|
||||
}
|
||||
+6
-4
@@ -9,9 +9,11 @@
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/http.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
@@ -43,15 +45,15 @@ void PrintImg(const char *path) {
|
||||
size_t n;
|
||||
int opt, i, yn, xn, cn, w, h;
|
||||
void *img, *pix, *src, *mime;
|
||||
if (!(img = gc(xslurp(path, &n)))) exit(2);
|
||||
if (!(pix = gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
|
||||
if (!(img = _gc(xslurp(path, &n)))) exit(2);
|
||||
if (!(pix = _gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
|
||||
if (linktag) {
|
||||
printf("<a href=\"%s\"\n >", path);
|
||||
}
|
||||
src = path;
|
||||
if (datauri) {
|
||||
src = xasprintf("data:%s;base64,%s", FindContentType(path, -1),
|
||||
gc(EncodeBase64(img, n, &n)));
|
||||
_gc(EncodeBase64(img, n, &n)));
|
||||
}
|
||||
w = (xn + (1 << scale) / 2) >> scale;
|
||||
h = (yn + (1 << scale) / 2) >> scale;
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/critbit0.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpdecode.internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
|
||||
/**
|
||||
* @fileoverview Simple Interactive Spell Checker.
|
||||
*
|
||||
* This is an attempt to get spell checking to work in Emacs across
|
||||
* platforms. While the computer science behind spell checking is very
|
||||
* simple, unfortunately Emacs probes all these System Five spell progs
|
||||
* similar to how websites have been known to probe User-Agent strings.
|
||||
*
|
||||
* Here's how we believe the repl works:
|
||||
*
|
||||
* $ make -j8 o//examples/ispell.com
|
||||
* $ o//examples/ispell.com
|
||||
* @(#) Cosmopolitan Ispell Version 3.4.00 8 Feb 2015
|
||||
* word: hello
|
||||
* ok
|
||||
* word: héllo
|
||||
* how about: hills, hello, hilly, jello
|
||||
* word: lova
|
||||
* how about: diva, dona, dora, dove, elva, fora, hove, iota
|
||||
* word: hecruhecrue
|
||||
* not found
|
||||
*
|
||||
* The dictionary for this program is embedded as a text file within the
|
||||
* zip structure of the binary. It can be edited after distribution.
|
||||
*
|
||||
* It's possible to go even fancier than what this code is doing, by
|
||||
* using cmudict phonemes, bloom filters, unicode tables e.g. e vs. é,
|
||||
* and even doing ML similar to Google's online spell checker.
|
||||
*
|
||||
* TODO: Figure out why Emacs rejects this interface.
|
||||
*/
|
||||
|
||||
#define MISSING_LETTER_DISTANCE 5
|
||||
#define MAX_NEARBY_WORD_DISTANCE 6
|
||||
#define MAX_NEARBY_RESULTS 8
|
||||
|
||||
FILE *f;
|
||||
char *line;
|
||||
size_t linesize;
|
||||
const char *query;
|
||||
struct critbit0 words; /* does O(log 𝑛) fast path lookup */
|
||||
|
||||
struct NearbyWords {
|
||||
size_t i, n;
|
||||
struct WordMatch {
|
||||
long dist;
|
||||
char *word;
|
||||
} * p;
|
||||
} nearby;
|
||||
|
||||
long WordDistance(const char *a, const char *b) {
|
||||
long dist;
|
||||
int gota, gotb;
|
||||
unsigned long h, p;
|
||||
wint_t chara, charb;
|
||||
dist = p = 0;
|
||||
for (;;) {
|
||||
gota = abs(tpdecode(a, &chara)); /* parses utf-8 multibyte characters */
|
||||
gotb = abs(tpdecode(b, &charb)); /* abs() handles -1, always yields � */
|
||||
if (!chara && !charb) break;
|
||||
if (!chara || !charb) {
|
||||
dist += MISSING_LETTER_DISTANCE;
|
||||
} else if ((h = hamming(chara, charb))) {
|
||||
dist += h + p++; /* penalize multiple mismatched letters */
|
||||
}
|
||||
if (chara) a += gota;
|
||||
if (charb) b += gotb;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
intptr_t ConsiderWord(const char *word, void *arg) {
|
||||
long dist;
|
||||
if ((dist = WordDistance(word, query)) < MAX_NEARBY_WORD_DISTANCE) {
|
||||
append(&nearby, &((struct WordMatch){dist, word}));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CompareWords(const struct WordMatch *a, const struct WordMatch *b) {
|
||||
return a->dist < b->dist;
|
||||
}
|
||||
|
||||
void FindNearbyWords(void) {
|
||||
nearby.i = 0;
|
||||
critbit0_allprefixed(&words, "", ConsiderWord, NULL);
|
||||
qsort(nearby.p, nearby.i, sizeof(struct WordMatch), (void *)CompareWords);
|
||||
}
|
||||
|
||||
void SpellChecker(void) {
|
||||
int i;
|
||||
printf("@(#) Cosmopolitan Ispell Version 3.4.00 8 Feb 2015\r\n");
|
||||
while (!feof(stdin)) {
|
||||
printf("word: ");
|
||||
fflush(stdout);
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
query = strtolower(_chomp(line));
|
||||
if (critbit0_contains(&words, query)) {
|
||||
printf("ok\r\n");
|
||||
} else {
|
||||
FindNearbyWords();
|
||||
if (nearby.i) {
|
||||
printf("how about: ");
|
||||
for (i = 0; i < MIN(MAX_NEARBY_RESULTS, nearby.i); ++i) {
|
||||
if (i) printf(", ");
|
||||
fputs(nearby.p[i].word, stdout);
|
||||
}
|
||||
printf("\r\n");
|
||||
} else {
|
||||
printf("not found\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
CHECK_NE(-1, fclose(stdin));
|
||||
CHECK_NE(-1, fclose(stdout));
|
||||
}
|
||||
|
||||
void LoadWords(void) {
|
||||
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
|
||||
while (getline(&line, &linesize, f) > 0) {
|
||||
critbit0_insert(&words, strtolower(_chomp(line)));
|
||||
}
|
||||
CHECK_NE(-1, fclose(f));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
LoadWords();
|
||||
SpellChecker();
|
||||
return 0;
|
||||
}
|
||||
+3
-3
@@ -58,14 +58,14 @@ Contact: [email protected]\"\n\
|
||||
#endif
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#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"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
@@ -355,7 +355,7 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
* Returns 0 on success, -1 on error. */
|
||||
int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
struct winsize ws;
|
||||
if (getttysize(STDOUT_FILENO, &ws) == -1 || ws.ws_col == 0) {
|
||||
if (_getttysize(1, &ws) == -1 || ws.ws_col == 0) {
|
||||
/* ioctl() failed. Try to query the terminal itself. */
|
||||
int orig_row, orig_col, retval;
|
||||
|
||||
|
||||
+3
-3
@@ -11,12 +11,12 @@
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
|
||||
struct stat st;
|
||||
|
||||
@@ -49,7 +49,7 @@ void List(const char *path) {
|
||||
const char *vpath;
|
||||
if (strcmp(path, ".") == 0) {
|
||||
vpath = "";
|
||||
} else if (!endswith(path, "/")) {
|
||||
} else if (!_endswith(path, "/")) {
|
||||
vpath = _gc(xasprintf("%s/", path));
|
||||
} else {
|
||||
vpath = path;
|
||||
|
||||
+5
-4
@@ -7,19 +7,20 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
struct stat st;
|
||||
struct Files {
|
||||
|
||||
+6
-5
@@ -10,21 +10,21 @@
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/winsize.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"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
@@ -39,7 +39,8 @@
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
@@ -286,7 +287,7 @@ void GetTermSize(void) {
|
||||
struct winsize wsize_;
|
||||
wsize_.ws_row = 25;
|
||||
wsize_.ws_col = 80;
|
||||
getttysize(STDIN_FILENO, &wsize_);
|
||||
_getttysize(0, &wsize_);
|
||||
FreeSamplingSolution(ssy_);
|
||||
FreeSamplingSolution(ssx_);
|
||||
tyn_ = wsize_.ws_row * 2;
|
||||
|
||||
+3
-2
@@ -17,14 +17,15 @@
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
||||
/**
|
||||
@@ -76,7 +77,7 @@ void GetTtySize(void) {
|
||||
struct winsize wsize;
|
||||
wsize.ws_row = tyn;
|
||||
wsize.ws_col = txn;
|
||||
getttysize(1, &wsize);
|
||||
_getttysize(1, &wsize);
|
||||
tyn = wsize.ws_row;
|
||||
txn = wsize.ws_col;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
||||
+1
-2
@@ -8,11 +8,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (c) 2010, 2012 David E. O'Brien │
|
||||
│ Copyright (c) 1980, 1992, 1993 │
|
||||
│ The Regents of the University of California. All rights reserved. │
|
||||
│ │
|
||||
│ Redistribution and use in source and binary forms, with or without │
|
||||
│ modification, are permitted provided that the following conditions │
|
||||
│ are met: │
|
||||
│ 1. Redistributions of source code must retain the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer. │
|
||||
│ 2. Redistributions in binary form must reproduce the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer in the │
|
||||
│ documentation and/or other materials provided with the distribution. │
|
||||
│ 3. Neither the name of the University nor the names of its contributors │
|
||||
│ may be used to endorse or promote products derived from this software │
|
||||
│ without specific prior written permission. │
|
||||
│ │
|
||||
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
|
||||
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
|
||||
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
|
||||
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
|
||||
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
|
||||
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
|
||||
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
|
||||
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
|
||||
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
|
||||
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
|
||||
│ SUCH DAMAGE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/bswap.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
// clang-format off
|
||||
|
||||
/**
|
||||
* @fileoverview Terminal Screencast Recorder / Player, e.g.
|
||||
*
|
||||
* make o//examples/script.com
|
||||
* o//examples/script.com -r
|
||||
* # type stuff..
|
||||
* # CTRL-D
|
||||
* o//examples/script.com -p typescript
|
||||
*
|
||||
* @note works on Linux, OpenBSD, NetBSD, FreeBSD, MacOS
|
||||
* @see https://asciinema.org/
|
||||
*/
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
FreeBSD Script (BSD-3 License)\\n\
|
||||
Copyright (c) 2010, 2012 David E. O'Brien\\n\
|
||||
Copyright (c) 1980, 1992, 1993\\n\
|
||||
\tThe Regents of the University of California.\\n\
|
||||
\tAll rights reserved.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define DEF_BUF 65536
|
||||
|
||||
struct stamp {
|
||||
uint64_t scr_len; /* amount of data */
|
||||
uint64_t scr_sec; /* time it arrived in seconds... */
|
||||
uint32_t scr_usec; /* ...and microseconds */
|
||||
uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
|
||||
};
|
||||
|
||||
static FILE *fscript;
|
||||
static int master, slave;
|
||||
static int child;
|
||||
static const char *fname;
|
||||
static char *fmfname;
|
||||
static int qflg, ttyflg;
|
||||
static int usesleep, rawout, showexit;
|
||||
|
||||
static struct termios tt;
|
||||
|
||||
static void done(int) wontreturn;
|
||||
static void doshell(char **);
|
||||
static void finish(void);
|
||||
static void record(FILE *, char *, size_t, int);
|
||||
static void consume(FILE *, off_t, char *, int);
|
||||
static void playback(FILE *) wontreturn;
|
||||
static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int cc;
|
||||
struct termios rtt, stt;
|
||||
struct winsize win;
|
||||
struct timeval tv, *tvp;
|
||||
time_t tvec, start;
|
||||
static char obuf[BUFSIZ];
|
||||
static char ibuf[BUFSIZ];
|
||||
fd_set rfd;
|
||||
int aflg, Fflg, kflg, pflg, ch, k, n;
|
||||
int flushtime, readstdin;
|
||||
int fm_fd, fm_log;
|
||||
|
||||
aflg = Fflg = kflg = pflg = 0;
|
||||
usesleep = 1;
|
||||
rawout = 0;
|
||||
flushtime = 30;
|
||||
fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
|
||||
warning. (not needed w/clang) */
|
||||
showexit = 0;
|
||||
|
||||
while ((ch = getopt(argc, argv, "adeFfkpqrt:")) != -1)
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
aflg = 1;
|
||||
break;
|
||||
case 'd':
|
||||
usesleep = 0;
|
||||
break;
|
||||
case 'e': /* Default behavior, accepted for linux compat */
|
||||
break;
|
||||
case 'F':
|
||||
Fflg = 1;
|
||||
break;
|
||||
case 'k':
|
||||
kflg = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pflg = 1;
|
||||
break;
|
||||
case 'q':
|
||||
qflg = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rawout = 1;
|
||||
break;
|
||||
case 't':
|
||||
flushtime = atoi(optarg);
|
||||
if (flushtime < 0)
|
||||
err(1, "invalid flush time %d", flushtime);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
fname = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
} else
|
||||
fname = "typescript";
|
||||
|
||||
if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
|
||||
err(1, "%s", fname);
|
||||
|
||||
if (pflg)
|
||||
playback(fscript);
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &tt) == -1 ||
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1) {
|
||||
if (errno != ENOTTY) /* For debugger. */
|
||||
err(1, "tcgetattr/ioctl");
|
||||
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
|
||||
err(1, "openpty");
|
||||
} else {
|
||||
if (openpty(&master, &slave, NULL, &tt, &win) == -1)
|
||||
err(1, "openpty");
|
||||
ttyflg = 1;
|
||||
}
|
||||
|
||||
if (rawout)
|
||||
record(fscript, NULL, 0, 's');
|
||||
|
||||
if (!qflg) {
|
||||
tvec = time(NULL);
|
||||
printf("Script started, output file is %s\n", fname);
|
||||
if (!rawout) {
|
||||
fprintf(fscript, "Script started on %s",
|
||||
ctime(&tvec));
|
||||
if (argv[0]) {
|
||||
showexit = 1;
|
||||
fprintf(fscript, "Command: ");
|
||||
for (k = 0 ; argv[k] ; ++k)
|
||||
fprintf(fscript, "%s%s", k ? " " : "",
|
||||
argv[k]);
|
||||
fprintf(fscript, "\n");
|
||||
}
|
||||
}
|
||||
fflush(fscript);
|
||||
}
|
||||
if (ttyflg) {
|
||||
rtt = tt;
|
||||
cfmakeraw(&rtt);
|
||||
rtt.c_lflag &= ~ECHO;
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
warn("fork");
|
||||
done(1);
|
||||
}
|
||||
if (child == 0) {
|
||||
doshell(argv);
|
||||
}
|
||||
close(slave);
|
||||
|
||||
start = tvec = time(0);
|
||||
readstdin = 1;
|
||||
for (;;) {
|
||||
FD_ZERO(&rfd);
|
||||
FD_SET(master, &rfd);
|
||||
if (readstdin)
|
||||
FD_SET(STDIN_FILENO, &rfd);
|
||||
if (!readstdin && ttyflg) {
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
readstdin = 1;
|
||||
} else if (flushtime > 0) {
|
||||
tv.tv_sec = flushtime - (tvec - start);
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
} else {
|
||||
tvp = NULL;
|
||||
}
|
||||
n = select(master + 1, &rfd, 0, 0, tvp);
|
||||
if (n < 0 && errno != EINTR)
|
||||
break;
|
||||
if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
|
||||
cc = read(STDIN_FILENO, ibuf, BUFSIZ);
|
||||
if (cc < 0)
|
||||
break;
|
||||
if (cc == 0) {
|
||||
if (tcgetattr(master, &stt) == 0 &&
|
||||
(stt.c_lflag & ICANON) != 0) {
|
||||
write(master, &stt.c_cc[VEOF], 1);
|
||||
}
|
||||
readstdin = 0;
|
||||
}
|
||||
if (cc > 0) {
|
||||
if (rawout)
|
||||
record(fscript, ibuf, cc, 'i');
|
||||
write(master, ibuf, cc);
|
||||
if (kflg && tcgetattr(master, &stt) >= 0 &&
|
||||
((stt.c_lflag & ECHO) == 0)) {
|
||||
fwrite(ibuf, 1, cc, fscript);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n > 0 && FD_ISSET(master, &rfd)) {
|
||||
cc = read(master, obuf, sizeof (obuf));
|
||||
if (cc <= 0)
|
||||
break;
|
||||
write(STDOUT_FILENO, obuf, cc);
|
||||
if (rawout)
|
||||
record(fscript, obuf, cc, 'o');
|
||||
else
|
||||
fwrite(obuf, 1, cc, fscript);
|
||||
}
|
||||
tvec = time(0);
|
||||
if (tvec - start >= flushtime) {
|
||||
fflush(fscript);
|
||||
start = tvec;
|
||||
}
|
||||
if (Fflg)
|
||||
fflush(fscript);
|
||||
}
|
||||
finish();
|
||||
done(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
finish(void)
|
||||
{
|
||||
int e, status;
|
||||
|
||||
if (waitpid(child, &status, 0) == child) {
|
||||
if (WIFEXITED(status))
|
||||
e = WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status))
|
||||
e = WTERMSIG(status);
|
||||
else /* can't happen */
|
||||
e = 1;
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
doshell(char **av)
|
||||
{
|
||||
const char *shell;
|
||||
|
||||
shell = getenv("SHELL");
|
||||
if (shell == NULL)
|
||||
shell = _PATH_BSHELL;
|
||||
|
||||
close(master);
|
||||
fclose(fscript);
|
||||
free(fmfname);
|
||||
login_tty(slave);
|
||||
setenv("SCRIPT", fname, 1);
|
||||
if (av[0]) {
|
||||
execvp(av[0], av);
|
||||
warn("%s", av[0]);
|
||||
} else {
|
||||
execl(shell, shell, "-i", 0);
|
||||
warn("%s", shell);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
done(int eno)
|
||||
{
|
||||
time_t tvec;
|
||||
|
||||
if (ttyflg)
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
|
||||
tvec = time(NULL);
|
||||
if (rawout)
|
||||
record(fscript, NULL, 0, 'e');
|
||||
if (!qflg) {
|
||||
if (!rawout) {
|
||||
if (showexit)
|
||||
fprintf(fscript, "\nCommand exit status:"
|
||||
" %d", eno);
|
||||
fprintf(fscript,"\nScript done on %s",
|
||||
ctime(&tvec));
|
||||
}
|
||||
printf("\nScript done, output file is %s\n", fname);
|
||||
}
|
||||
fclose(fscript);
|
||||
close(master);
|
||||
exit(eno);
|
||||
}
|
||||
|
||||
static void
|
||||
record(FILE *fp, char *buf, size_t cc, int direction)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct stamp stamp;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
stamp.scr_len = cc;
|
||||
stamp.scr_sec = tv.tv_sec;
|
||||
stamp.scr_usec = tv.tv_usec;
|
||||
stamp.scr_direction = direction;
|
||||
iov[0].iov_len = sizeof(stamp);
|
||||
iov[0].iov_base = &stamp;
|
||||
iov[1].iov_len = cc;
|
||||
iov[1].iov_base = buf;
|
||||
if (writev(fileno(fp), &iov[0], 2) == -1)
|
||||
err(1, "writev");
|
||||
}
|
||||
|
||||
static void
|
||||
consume(FILE *fp, off_t len, char *buf, int reg)
|
||||
{
|
||||
size_t l;
|
||||
|
||||
if (reg) {
|
||||
if (fseeko(fp, len, SEEK_CUR) == -1)
|
||||
err(1, NULL);
|
||||
}
|
||||
else {
|
||||
while (len > 0) {
|
||||
l = MIN(DEF_BUF, len);
|
||||
if (fread(buf, sizeof(char), l, fp) != l)
|
||||
err(1, "cannot read buffer");
|
||||
len -= l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define swapstamp(stamp) do { \
|
||||
if (stamp.scr_direction > 0xff) { \
|
||||
stamp.scr_len = bswap_64(stamp.scr_len); \
|
||||
stamp.scr_sec = bswap_64(stamp.scr_sec); \
|
||||
stamp.scr_usec = bswap_32(stamp.scr_usec); \
|
||||
stamp.scr_direction = bswap_32(stamp.scr_direction); \
|
||||
} \
|
||||
} while (0/*CONSTCOND*/)
|
||||
|
||||
static void
|
||||
termset(void)
|
||||
{
|
||||
struct termios traw;
|
||||
|
||||
if (tcgetattr(STDOUT_FILENO, &tt) == -1) {
|
||||
if (errno != ENOTTY) /* For debugger. */
|
||||
err(1, "tcgetattr");
|
||||
return;
|
||||
}
|
||||
ttyflg = 1;
|
||||
traw = tt;
|
||||
cfmakeraw(&traw);
|
||||
traw.c_lflag |= ISIG;
|
||||
tcsetattr(STDOUT_FILENO, TCSANOW, &traw);
|
||||
}
|
||||
|
||||
static void
|
||||
termreset(void)
|
||||
{
|
||||
if (ttyflg) {
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tt);
|
||||
ttyflg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
playback(FILE *fp)
|
||||
{
|
||||
struct timespec tsi, tso;
|
||||
struct stamp stamp;
|
||||
struct stat pst;
|
||||
static char buf[DEF_BUF];
|
||||
off_t nread, save_len;
|
||||
size_t l;
|
||||
time_t tclock;
|
||||
int reg;
|
||||
|
||||
if (fstat(fileno(fp), &pst) == -1)
|
||||
err(1, "fstat failed");
|
||||
|
||||
reg = S_ISREG(pst.st_mode);
|
||||
|
||||
for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
|
||||
if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
|
||||
if (reg)
|
||||
err(1, "reading playback header");
|
||||
else
|
||||
break;
|
||||
}
|
||||
swapstamp(stamp);
|
||||
save_len = sizeof(stamp);
|
||||
|
||||
if (reg && stamp.scr_len >
|
||||
(uint64_t)(pst.st_size - save_len) - nread)
|
||||
errx(1, "invalid stamp");
|
||||
|
||||
save_len += stamp.scr_len;
|
||||
tclock = stamp.scr_sec;
|
||||
tso.tv_sec = stamp.scr_sec;
|
||||
tso.tv_nsec = stamp.scr_usec * 1000;
|
||||
|
||||
switch (stamp.scr_direction) {
|
||||
case 's':
|
||||
if (!qflg)
|
||||
printf("Script started on %s",
|
||||
ctime(&tclock));
|
||||
tsi = tso;
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
termset();
|
||||
atexit(termreset);
|
||||
break;
|
||||
case 'e':
|
||||
termreset();
|
||||
if (!qflg)
|
||||
printf("\nScript done on %s",
|
||||
ctime(&tclock));
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
break;
|
||||
case 'i':
|
||||
/* throw input away */
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
break;
|
||||
case 'o':
|
||||
tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
|
||||
tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
|
||||
if (tsi.tv_nsec < 0) {
|
||||
tsi.tv_sec -= 1;
|
||||
tsi.tv_nsec += 1000000000;
|
||||
}
|
||||
if (usesleep)
|
||||
nanosleep(&tsi, NULL);
|
||||
tsi = tso;
|
||||
while (stamp.scr_len > 0) {
|
||||
l = MIN(DEF_BUF, stamp.scr_len);
|
||||
if (fread(buf, sizeof(char), l, fp) != l)
|
||||
err(1, "cannot read buffer");
|
||||
|
||||
write(STDOUT_FILENO, buf, l);
|
||||
stamp.scr_len -= l;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errx(1, "invalid direction");
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
SCRIPT(1) Cosmopolitan General Commands Manual SCRIPT(1)
|
||||
|
||||
𝐍𝐀𝐌𝐄
|
||||
𝘀𝗰𝗿𝗶𝗽𝘁 — make typescript of terminal session
|
||||
|
||||
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
|
||||
𝘀𝗰𝗿𝗶𝗽𝘁 [-𝗮𝗱𝗲𝗳𝗸𝗽𝗾𝗿] [-𝐅 p̲i̲p̲e̲] [-𝘁 t̲i̲m̲e̲] [f̲i̲l̲e̲ [c̲o̲m̲m̲a̲n̲d̲ .̲.̲.̲]]
|
||||
|
||||
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility makes a typescript of everything printed on your termi‐
|
||||
nal. It is useful for students who need a hardcopy record of an interac‐
|
||||
tive session as proof of an assignment, as the typescript file can be
|
||||
printed out later with lpr(1).
|
||||
|
||||
If the argument f̲i̲l̲e̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 saves all dialogue in f̲i̲l̲e̲. If no
|
||||
file name is given, the typescript is saved in the file t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲.
|
||||
|
||||
If the argument c̲o̲m̲m̲a̲n̲d̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 will run the specified command
|
||||
with an optional argument vector instead of an interactive shell.
|
||||
|
||||
The following options are available:
|
||||
|
||||
-𝗮 Append the output to f̲i̲l̲e̲ or t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲, retaining the prior con‐
|
||||
tents.
|
||||
|
||||
-𝗱 When playing back a session with the -𝗽 flag, do not sleep between
|
||||
records when playing back a timestamped session.
|
||||
|
||||
-𝗲 Accepted for compatibility with u̲t̲i̲l̲-̲l̲i̲n̲u̲x̲ 𝘀𝗰𝗿𝗶𝗽𝘁. The child com‐
|
||||
mand exit status is always the exit status of 𝘀𝗰𝗿𝗶𝗽𝘁.
|
||||
|
||||
-𝐅 p̲i̲p̲e̲
|
||||
Immediately flush output after each write. This will allow a user
|
||||
to create a named pipe using mkfifo(1) and another user may watch
|
||||
the live session using a utility like cat(1).
|
||||
|
||||
-𝗸 Log keys sent to the program as well as output.
|
||||
|
||||
-𝗽 Play back a session recorded with the -𝗿 flag in real time.
|
||||
|
||||
-𝗾 Run in quiet mode, omit the start, stop and command status mes‐
|
||||
sages.
|
||||
|
||||
-𝗿 Record a session with input, output, and timestamping.
|
||||
|
||||
-𝘁 t̲i̲m̲e̲
|
||||
Specify the interval at which the script output file will be
|
||||
flushed to disk, in seconds. A value of 0 causes 𝘀𝗰𝗿𝗶𝗽𝘁 to flush
|
||||
after every character I/O event. The default interval is 30 sec‐
|
||||
onds.
|
||||
|
||||
The script ends when the forked shell (or command) exits (a c̲o̲n̲t̲r̲o̲l̲-̲D̲ to
|
||||
exit the Bourne shell (sh(1)), and e̲x̲i̲t̲, l̲o̲g̲o̲u̲t̲ or c̲o̲n̲t̲r̲o̲l̲-̲D̲ (if i̲g̲n̲o̲r̲e̲e̲o̲f̲
|
||||
is not set) for the C-shell, csh(1)).
|
||||
|
||||
Certain interactive commands, such as vi(1), create garbage in the type‐
|
||||
script file. The 𝘀𝗰𝗿𝗶𝗽𝘁 utility works best with commands that do not ma‐
|
||||
nipulate the screen. The results are meant to emulate a hardcopy terminal,
|
||||
not an addressable one.
|
||||
|
||||
𝐄𝐍𝐕𝐈𝐑𝐎𝐍𝐌𝐄𝐍𝐓
|
||||
The following environment variables are utilized by 𝘀𝗰𝗿𝗶𝗽𝘁:
|
||||
|
||||
SCRIPT
|
||||
The SCRIPT environment variable is added to the sub-shell. If
|
||||
SCRIPT already existed in the users environment, its value is over‐
|
||||
written within the sub-shell. The value of SCRIPT is the name of
|
||||
the t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲ file.
|
||||
|
||||
SHELL If the variable SHELL exists, the shell forked by 𝘀𝗰𝗿𝗶𝗽𝘁 will be
|
||||
that shell. If SHELL is not set, the Bourne shell is assumed.
|
||||
(Most shells set this variable automatically).
|
||||
|
||||
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
|
||||
csh(1) (for the h̲i̲s̲t̲o̲r̲y̲ mechanism)
|
||||
|
||||
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 command appeared in 3.0BSD.
|
||||
|
||||
The -𝗱, -𝗽 and -𝗿 options first appeared in NetBSD 2.0 and were ported to
|
||||
FreeBSD 9.2.
|
||||
|
||||
𝐁𝐔𝐆𝐒
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility places 𝗲𝘃𝗲𝗿𝘆𝘁𝗵𝗶𝗻𝗴 in the log file, including linefeeds
|
||||
and backspaces. This is not what the naive user expects.
|
||||
|
||||
It is not possible to specify a command without also naming the script file
|
||||
because of argument parsing compatibility issues.
|
||||
|
||||
When running in -𝗸 mode, echo cancelling is far from ideal. The slave ter‐
|
||||
minal mode is checked for ECHO mode to check when to avoid manual echo log‐
|
||||
ging. This does not work when the terminal is in a raw mode where the pro‐
|
||||
gram being run is doing manual echo.
|
||||
|
||||
If 𝘀𝗰𝗿𝗶𝗽𝘁 reads zero bytes from the terminal, it switches to a mode when it
|
||||
only attempts to read once a second until there is data to read. This pre‐
|
||||
vents 𝘀𝗰𝗿𝗶𝗽𝘁 from spinning on zero-byte reads, but might cause a 1-second
|
||||
delay in processing of user input.
|
||||
|
||||
BSD September 1, 2020 BSD
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
volatile bool gotalrm;
|
||||
|
||||
void OnSigAlrm(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
void OnSigAlrm(int sig, siginfo_t *si, void *ctx) {
|
||||
gotalrm = true;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -14,11 +14,11 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
/**
|
||||
* @fileoverview File metadata viewer.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Basic POSIX Threads Example.
|
||||
*
|
||||
* $ make -j8 o//examples/thread.com
|
||||
* $ o//examples/thread.com
|
||||
* hi there
|
||||
*
|
||||
*/
|
||||
|
||||
void *worker(void *arg) {
|
||||
fputs(arg, stdout);
|
||||
return "there\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
void *result;
|
||||
pthread_t id;
|
||||
pthread_create(&id, 0, worker, "hi ");
|
||||
pthread_join(id, &result);
|
||||
fputs(result, stdout);
|
||||
}
|
||||
+2
-1
@@ -12,10 +12,11 @@
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xspawn.h"
|
||||
|
||||
/**
|
||||
* @fileoverview command for showing how long a command takes
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
|
||||
+5
-5
@@ -24,7 +24,7 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
#define CTRL(C) ((C) ^ 0b01000000)
|
||||
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
||||
@@ -80,7 +80,7 @@ int rawmode(void) {
|
||||
}
|
||||
|
||||
void getsize(void) {
|
||||
if (getttysize(1, &wsize) != -1) {
|
||||
if (_getttysize(1, &wsize) != -1) {
|
||||
printf("termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
|
||||
wsize.ws_row);
|
||||
} else {
|
||||
@@ -148,12 +148,12 @@ int main(int argc, char *argv[]) {
|
||||
if (iscntrl(code[0]) && !code[1]) {
|
||||
printf("is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
||||
} else if (_startswith(code, "\e[") && _endswith(code, "R")) {
|
||||
yn = 1, xn = 1;
|
||||
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
||||
printf("inband signalling says terminal size is %d×%d\r\n", xn, yn);
|
||||
} else if (startswith(code, "\e[<") &&
|
||||
(endswith(code, "m") || endswith(code, "M"))) {
|
||||
} else if (_startswith(code, "\e[<") &&
|
||||
(_endswith(code, "m") || _endswith(code, "M"))) {
|
||||
e = 0, y = 1, x = 1;
|
||||
sscanf(code, "\e[<%d;%d;%d%c", &e, &y, &x, &c);
|
||||
printf("mouse %s at %d×%d\r\n", describemouseevent(e | (c == 'm') << 2),
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
* and this example should work on all supported platforms even Windows
|
||||
*/
|
||||
|
||||
void handler(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
void handler(int sig, siginfo_t *si, void *vctx) {
|
||||
struct XedDecodedInst xedd;
|
||||
struct ucontext *ctx = vctx;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
|
||||
ctx->uc_mcontext.rip += xedd.length;
|
||||
|
||||
+6
-6
@@ -14,11 +14,11 @@
|
||||
int main(int argc, char *argv[]) {
|
||||
struct utsname names;
|
||||
if (uname(&names)) return 1;
|
||||
printf("%-10s %s\n", "sysname", names.sysname);
|
||||
printf("%-10s %s\n", "nodename", names.nodename);
|
||||
printf("%-10s %s\n", "release", names.release);
|
||||
printf("%-10s %s\n", "version", names.version);
|
||||
printf("%-10s %s\n", "machine", names.machine);
|
||||
printf("%-10s %s\n", "domainname", names.domainname);
|
||||
printf("%-10s %`'s\n", "sysname", names.sysname);
|
||||
printf("%-10s %`'s\n", "release", names.release);
|
||||
printf("%-10s %`'s\n", "version", names.version);
|
||||
printf("%-10s %`'s\n", "machine", names.machine);
|
||||
printf("%-10s %`'s\n", "nodename", names.nodename);
|
||||
printf("%-10s %`'s\n", "domainname", names.domainname);
|
||||
return 0;
|
||||
}
|
||||
+439
-359
File diff suppressed because it is too large.
Load diff
@@ -1,143 +0,0 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/consts/w.h"
|
||||
|
||||
#define STR(s) s, strlen(s)
|
||||
|
||||
struct termios tio;
|
||||
struct winsize wsz;
|
||||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
char databuf[512];
|
||||
char pathbuf[PATH_MAX];
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ssize_t rc;
|
||||
const char *prog;
|
||||
size_t i, got, wrote;
|
||||
int ws, mfd, sfd, pid;
|
||||
|
||||
if (argc < 2) {
|
||||
write(2, STR("usage: "));
|
||||
if (argc > 0) write(2, argv[0], strlen(argv[0]));
|
||||
write(2, STR(" prog [argv₁...]\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(prog = commandv(argv[1], pathbuf, sizeof(pathbuf)))) {
|
||||
write(2, STR("error: "));
|
||||
write(2, argv[1], strlen(argv[1]));
|
||||
write(2, STR(" not found\n"));
|
||||
return 2;
|
||||
}
|
||||
|
||||
bzero(&wsz, sizeof(wsz));
|
||||
wsz.ws_col = 80;
|
||||
wsz.ws_row = 45;
|
||||
|
||||
bzero(&tio, sizeof(tio));
|
||||
tio.c_iflag = ICRNL | IXON | IUTF8;
|
||||
tio.c_oflag = OPOST | ONLCR;
|
||||
tio.c_cflag = CREAD | CS8;
|
||||
tio.c_lflag =
|
||||
ISIG | ICANON | ECHO | ECHOE | ECHOK | IEXTEN | ECHOCTL | ECHOKE;
|
||||
tio.c_cc[VMIN] = 1;
|
||||
tio.c_cc[VINTR] = CTRL('C');
|
||||
tio.c_cc[VQUIT] = CTRL('\\');
|
||||
tio.c_cc[VERASE] = CTRL('?');
|
||||
tio.c_cc[VKILL] = CTRL('U');
|
||||
tio.c_cc[VEOF] = CTRL('D');
|
||||
tio.c_cc[VSTART] = CTRL('Q');
|
||||
tio.c_cc[VSTOP] = CTRL('S');
|
||||
tio.c_cc[VSUSP] = CTRL('Z');
|
||||
tio.c_cc[VREPRINT] = CTRL('R');
|
||||
tio.c_cc[VDISCARD] = CTRL('O');
|
||||
tio.c_cc[VWERASE] = CTRL('W');
|
||||
tio.c_cc[VLNEXT] = CTRL('V');
|
||||
|
||||
if (openpty(&mfd, &sfd, 0, &tio, &wsz)) {
|
||||
write(2, STR("error: openpty() failed\n"));
|
||||
return 3;
|
||||
}
|
||||
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
sigemptyset(&ignore.sa_mask);
|
||||
sigaction(SIGINT, &ignore, &saveint);
|
||||
sigaction(SIGQUIT, &ignore, &savequit);
|
||||
sigemptyset(&chldmask);
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
|
||||
if ((pid = vfork()) == -1) {
|
||||
write(2, STR("error: vfork() failed\n"));
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
close(0);
|
||||
dup(sfd);
|
||||
close(1);
|
||||
dup(sfd);
|
||||
close(2);
|
||||
dup(sfd);
|
||||
close(mfd);
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execv(prog, argv + 1);
|
||||
return 127;
|
||||
}
|
||||
close(sfd);
|
||||
|
||||
for (;;) {
|
||||
if (waitpid(pid, &ws, WNOHANG) == pid) {
|
||||
break;
|
||||
}
|
||||
rc = read(mfd, databuf, sizeof(databuf));
|
||||
if (rc == -1) {
|
||||
perror("read");
|
||||
return 5;
|
||||
}
|
||||
if (!(got = rc)) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < got; i += wrote) {
|
||||
rc = write(1, databuf + i, got - i);
|
||||
if (rc != -1) {
|
||||
wrote = rc;
|
||||
} else {
|
||||
write(2, STR("error: read() failed\n"));
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
|
||||
if (WIFEXITED(ws)) {
|
||||
return WEXITSTATUS(ws);
|
||||
} else {
|
||||
return 128 + WTERMSIG(ws);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/isystem/unistd.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Bare Metal VGA TTY demo.
|
||||
*
|
||||
* This program can boot as an operating system. Try it out:
|
||||
*
|
||||
* make -j8 o//examples/vga.com
|
||||
* qemu-system-x86_64 -hda o//examples/vga.com -serial stdio
|
||||
*
|
||||
* Please note that, by default, APE binaries only use the serial port
|
||||
* for stdio. To get the VGA console as an added bonus:
|
||||
*
|
||||
* STATIC_YOINK("vga_console");
|
||||
*
|
||||
* Should be added to the top of your main() program source file.
|
||||
*/
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
struct termios tio;
|
||||
char buf[16];
|
||||
ssize_t res;
|
||||
if (tcgetattr(0, &tio) != -1) {
|
||||
tio.c_lflag &= ~(ECHO | ICANON);
|
||||
tcsetattr(0, TCSANOW, &tio);
|
||||
}
|
||||
write(1, "\e[5n", 4);
|
||||
res = read(0, buf, 4);
|
||||
if (res != 4 || memcmp(buf, "\e[0n", 4) != 0) {
|
||||
printf("res = %d?\n", res);
|
||||
return -1;
|
||||
}
|
||||
printf("\e[92;44mHello World!\e[0m %.19Lg\n", atan2l(x, y));
|
||||
|
||||
// read/print loop so machine doesn't reset on metal
|
||||
for (;;) {
|
||||
if ((res = readansi(0, buf, 16)) > 0) {
|
||||
printf("got \e[97m%`'.*s\e[0m\r\n", res, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/isystem/unistd.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Demo of program crash reporting with Bare Metal VGA TTY.
|
||||
*
|
||||
* make -j8 o//examples/vga2.com
|
||||
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
|
||||
*/
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
STATIC_YOINK("_idt");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile int x = 1;
|
||||
volatile int y = 2;
|
||||
printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3));
|
||||
for (;;);
|
||||
}
|
||||
@@ -7,16 +7,12 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
|
||||
/**
|
||||
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/passwd.h"
|
||||
|
||||
/**
|
||||
* @fileoverview program for broadcasting message to all terminals, e.g.
|
||||
*
|
||||
* o//examples/wall.com hello friends
|
||||
*
|
||||
* Will place some bold text into the top left corners of all terminals:
|
||||
*
|
||||
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
|
||||
* hello friends
|
||||
*
|
||||
* It's useful for having one terminal tab notify your other ones when
|
||||
* something like a long running job completes. In the old days back
|
||||
* when unix systems had multiple users, the wall command provided the
|
||||
* ultimate lulz especially if it's a setuid binary with root privs.
|
||||
*/
|
||||
|
||||
#define GETOPTS "v"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
|
||||
-v increase verbosity\n\
|
||||
Examples:\n\
|
||||
wall.com 'hello my friends'\n\
|
||||
echo hello my friends | wall.com\n\
|
||||
"
|
||||
|
||||
int g_verbose;
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_verbose++;
|
||||
break;
|
||||
case '?':
|
||||
write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GetHost(void) {
|
||||
static char host[254];
|
||||
if (gethostname(host, sizeof(host))) {
|
||||
strcpy(host, "localhost");
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
char *GetTime(void) {
|
||||
int64_t t;
|
||||
struct tm tm;
|
||||
struct timespec ts;
|
||||
clock_gettime(0, &ts);
|
||||
localtime_r(&ts.tv_sec, &tm);
|
||||
return _chomp(asctime(&tm));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
|
||||
// create broadcast banner
|
||||
// we use \e[1m so the text is strong & visually distinct
|
||||
// we use \e[K so it doesn't get lost in a forest of text
|
||||
// we map \n → \r\n because teletype might be in raw mode
|
||||
char *msg = 0;
|
||||
const char *s;
|
||||
appends(&msg, "\e7"); // save cursor position
|
||||
appends(&msg, "\e[H"); // goto top left corne
|
||||
appends(&msg, "\e[K"); // clear line forward
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
// append broadcast message
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
} else {
|
||||
appendw(&msg, *s & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise use stdin as message
|
||||
ssize_t i, rc;
|
||||
char buf[512];
|
||||
while ((rc = read(0, buf, sizeof(buf))) > 0) {
|
||||
for (i = 0; i < rc; ++i) {
|
||||
if (buf[i] == '\n') {
|
||||
appends(&msg, "\r\n\e[K"); // clear line forward
|
||||
} else {
|
||||
appendw(&msg, buf[i] & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
|
||||
|
||||
// try to send message to all pseudoteletypewriters
|
||||
for (int i = 0;; ++i) {
|
||||
int fd;
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) break;
|
||||
if (g_verbose) perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (c) 1980, 1993 │
|
||||
│ The Regents of the University of California. All rights reserved. │
|
||||
│ │
|
||||
│ Redistribution and use in source and binary forms, with or without │
|
||||
│ modification, are permitted provided that the following conditions │
|
||||
│ are met: │
|
||||
│ 1. Redistributions of source code must retain the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer. │
|
||||
│ 2. Redistributions in binary form must reproduce the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer in the │
|
||||
│ documentation and/or other materials provided with the distribution. │
|
||||
│ 3. Neither the name of the University nor the names of its contributors │
|
||||
│ may be used to endorse or promote products derived from this software │
|
||||
│ without specific prior written permission. │
|
||||
│ │
|
||||
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
|
||||
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
|
||||
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
|
||||
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
|
||||
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
|
||||
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
|
||||
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
|
||||
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
|
||||
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
|
||||
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
|
||||
│ SUCH DAMAGE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/mem/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
// clang-format off
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
FreeBSD Whois (BSD-3 License)\\n\
|
||||
Copyright (c) 1980, 1993\\n\
|
||||
\tThe Regents of the University of California.\\n\
|
||||
\tAll rights reserved.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define ABUSEHOST "whois.abuse.net"
|
||||
#define ANICHOST "whois.arin.net"
|
||||
#define DENICHOST "whois.denic.de"
|
||||
#define DKNICHOST "whois.dk-hostmaster.dk"
|
||||
#define FNICHOST "whois.afrinic.net"
|
||||
#define GNICHOST "whois.nic.gov"
|
||||
#define IANAHOST "whois.iana.org"
|
||||
#define INICHOST "whois.internic.net"
|
||||
#define KNICHOST "whois.krnic.net"
|
||||
#define LNICHOST "whois.lacnic.net"
|
||||
#define MNICHOST "whois.ra.net"
|
||||
#define PDBHOST "whois.peeringdb.com"
|
||||
#define PNICHOST "whois.apnic.net"
|
||||
#define QNICHOST_TAIL ".whois-servers.net"
|
||||
#define RNICHOST "whois.ripe.net"
|
||||
#define VNICHOST "whois.verisign-grs.com"
|
||||
|
||||
#define DEFAULT_PORT "whois"
|
||||
|
||||
#define WHOIS_RECURSE 0x01
|
||||
#define WHOIS_QUICK 0x02
|
||||
#define WHOIS_SPAM_ME 0x04
|
||||
|
||||
#define CHOPSPAM ">>> Last update of WHOIS database:"
|
||||
|
||||
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
|
||||
|
||||
#define SCAN(p, end, check) \
|
||||
while ((p) < (end)) \
|
||||
if (check) ++(p); \
|
||||
else break
|
||||
|
||||
static struct {
|
||||
const char *suffix, *server;
|
||||
} whoiswhere[] = {
|
||||
/* Various handles */
|
||||
{ "-ARIN", ANICHOST },
|
||||
{ "-NICAT", "at" QNICHOST_TAIL },
|
||||
{ "-NORID", "no" QNICHOST_TAIL },
|
||||
{ "-RIPE", RNICHOST },
|
||||
/* Nominet's whois server doesn't return referrals to JANET */
|
||||
{ ".ac.uk", "ac.uk" QNICHOST_TAIL },
|
||||
{ ".gov.uk", "ac.uk" QNICHOST_TAIL },
|
||||
{ "", IANAHOST }, /* default */
|
||||
{ NULL, NULL } /* safety belt */
|
||||
};
|
||||
|
||||
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
|
||||
static struct {
|
||||
const char *prefix;
|
||||
size_t len;
|
||||
} whois_referral[] = {
|
||||
WHOIS_REFERRAL("whois:"), /* IANA */
|
||||
WHOIS_REFERRAL("Whois Server:"),
|
||||
WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
|
||||
WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
|
||||
WHOIS_REFERRAL("ReferralServer: rwhois://"), /* ARIN */
|
||||
WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* We have a list of patterns for RIRs that assert ignorance rather than
|
||||
* providing referrals. If that happens, we guess that ARIN will be more
|
||||
* helpful. But, before following a referral to an RIR, we check if we have
|
||||
* asked that RIR already, and if so we make another guess.
|
||||
*/
|
||||
static const char *actually_arin[] = {
|
||||
"netname: ERX-NETBLOCK\n", /* APNIC */
|
||||
"netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct {
|
||||
int loop;
|
||||
const char *host;
|
||||
} try_rir[] = {
|
||||
{ 0, ANICHOST },
|
||||
{ 0, RNICHOST },
|
||||
{ 0, PNICHOST },
|
||||
{ 0, FNICHOST },
|
||||
{ 0, LNICHOST },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
reset_rir(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; try_rir[i].host != NULL; i++)
|
||||
try_rir[i].loop = 0;
|
||||
}
|
||||
|
||||
static const char *port = DEFAULT_PORT;
|
||||
|
||||
static const char *choose_server(char *);
|
||||
static struct addrinfo *gethostinfo(const char *, const char *, int);
|
||||
static void s_asprintf(char **ret, const char *format, ...);
|
||||
static void usage(void);
|
||||
static void whois(const char *, const char *, const char *, int);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *country, *host;
|
||||
int ch, flags;
|
||||
|
||||
#ifdef SOCKS
|
||||
SOCKSinit(argv[0]);
|
||||
#endif
|
||||
|
||||
country = host = NULL;
|
||||
flags = 0;
|
||||
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
host = ANICHOST;
|
||||
break;
|
||||
case 'A':
|
||||
host = PNICHOST;
|
||||
break;
|
||||
case 'b':
|
||||
host = ABUSEHOST;
|
||||
break;
|
||||
case 'c':
|
||||
country = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
host = FNICHOST;
|
||||
break;
|
||||
case 'g':
|
||||
host = GNICHOST;
|
||||
break;
|
||||
case 'h':
|
||||
host = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
host = INICHOST;
|
||||
break;
|
||||
case 'I':
|
||||
host = IANAHOST;
|
||||
break;
|
||||
case 'k':
|
||||
host = KNICHOST;
|
||||
break;
|
||||
case 'l':
|
||||
host = LNICHOST;
|
||||
break;
|
||||
case 'm':
|
||||
host = MNICHOST;
|
||||
break;
|
||||
case 'p':
|
||||
port = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
host = PDBHOST;
|
||||
break;
|
||||
case 'Q':
|
||||
flags |= WHOIS_QUICK;
|
||||
break;
|
||||
case 'r':
|
||||
host = RNICHOST;
|
||||
break;
|
||||
case 'R':
|
||||
flags |= WHOIS_RECURSE;
|
||||
break;
|
||||
case 'S':
|
||||
flags |= WHOIS_SPAM_ME;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!argc || (country != NULL && host != NULL))
|
||||
usage();
|
||||
|
||||
/*
|
||||
* If no host or country is specified, rely on referrals from IANA.
|
||||
*/
|
||||
if (host == NULL && country == NULL) {
|
||||
if ((host = getenv("WHOIS_SERVER")) == NULL &&
|
||||
(host = getenv("RA_SERVER")) == NULL) {
|
||||
if (!(flags & WHOIS_QUICK))
|
||||
flags |= WHOIS_RECURSE;
|
||||
}
|
||||
}
|
||||
while (argc-- > 0) {
|
||||
if (country != NULL) {
|
||||
char *qnichost;
|
||||
s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
|
||||
whois(*argv, qnichost, port, flags);
|
||||
free(qnichost);
|
||||
} else
|
||||
whois(*argv, host != NULL ? host :
|
||||
choose_server(*argv), port, flags);
|
||||
reset_rir();
|
||||
argv++;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
choose_server(char *domain)
|
||||
{
|
||||
size_t len = strlen(domain);
|
||||
int i;
|
||||
|
||||
for (i = 0; whoiswhere[i].suffix != NULL; i++) {
|
||||
size_t suffix_len = strlen(whoiswhere[i].suffix);
|
||||
if (len > suffix_len &&
|
||||
strcasecmp(domain + len - suffix_len,
|
||||
whoiswhere[i].suffix) == 0)
|
||||
return (whoiswhere[i].server);
|
||||
}
|
||||
errx(EX_SOFTWARE, "no default whois server");
|
||||
}
|
||||
|
||||
static struct addrinfo *
|
||||
gethostinfo(const char *host, const char *hport, int exit_on_noname)
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
res = NULL;
|
||||
error = getaddrinfo(host, hport, &hints, &res);
|
||||
if (error && (exit_on_noname || error != EAI_NONAME))
|
||||
err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for asprintf(3) that exits on error.
|
||||
*/
|
||||
static void
|
||||
s_asprintf(char **ret, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
if (vasprintf(ret, format, ap) == -1) {
|
||||
va_end(ap);
|
||||
err(EX_OSERR, "vasprintf()");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int
|
||||
connect_to_any_host(struct addrinfo *hostres)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
nfds_t i, j;
|
||||
size_t count;
|
||||
struct pollfd *fds;
|
||||
int timeout = 180, s = -1;
|
||||
|
||||
for (res = hostres, count = 0; res; res = res->ai_next)
|
||||
count++;
|
||||
fds = calloc(count, sizeof(*fds));
|
||||
if (fds == NULL)
|
||||
err(EX_OSERR, "calloc()");
|
||||
|
||||
/*
|
||||
* Traverse the result list elements and make non-block
|
||||
* connection attempts.
|
||||
*/
|
||||
count = i = 0;
|
||||
for (res = hostres; res != NULL; res = res->ai_next) {
|
||||
s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
|
||||
res->ai_protocol);
|
||||
if (s < 0)
|
||||
continue;
|
||||
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
/* Add the socket to poll list */
|
||||
fds[i].fd = s;
|
||||
fds[i].events = POLLERR | POLLHUP |
|
||||
POLLIN | POLLOUT;
|
||||
/*
|
||||
* From here until a socket connects, the
|
||||
* socket fd is owned by the fds[] poll array.
|
||||
*/
|
||||
s = -1;
|
||||
count++;
|
||||
i++;
|
||||
} else {
|
||||
close(s);
|
||||
s = -1;
|
||||
|
||||
/*
|
||||
* Poll only if we have something to poll,
|
||||
* otherwise just go ahead and try next
|
||||
* address
|
||||
*/
|
||||
if (count == 0)
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* If we are at the last address, poll until a connection is
|
||||
* established or we failed all connection attempts.
|
||||
*/
|
||||
if (res->ai_next == NULL)
|
||||
timeout = INFTIM;
|
||||
|
||||
/*
|
||||
* Poll the watched descriptors for successful connections:
|
||||
* if we still have more untried resolved addresses, poll only
|
||||
* once; otherwise, poll until all descriptors have errors,
|
||||
* which will be considered as ETIMEDOUT later.
|
||||
*/
|
||||
do {
|
||||
int n;
|
||||
|
||||
n = poll(fds, i, timeout);
|
||||
if (n == 0) {
|
||||
/*
|
||||
* No event reported in time. Try with a
|
||||
* smaller timeout (but cap at 2-3ms)
|
||||
* after a new host have been added.
|
||||
*/
|
||||
if (timeout >= 3)
|
||||
timeout >>= 1;
|
||||
|
||||
break;
|
||||
} else if (n < 0) {
|
||||
/*
|
||||
* errno here can only be EINTR which we would
|
||||
* want to clean up and bail out.
|
||||
*/
|
||||
s = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the event(s) we have seen.
|
||||
*/
|
||||
for (j = 0; j < i; j++) {
|
||||
if (fds[j].fd == -1 || fds[j].events == 0 ||
|
||||
fds[j].revents == 0)
|
||||
continue;
|
||||
if (fds[j].revents & ~(POLLIN | POLLOUT)) {
|
||||
close(fds[j].fd);
|
||||
fds[j].fd = -1;
|
||||
fds[j].events = 0;
|
||||
count--;
|
||||
continue;
|
||||
} else if (fds[j].revents & (POLLIN | POLLOUT)) {
|
||||
/* Connect succeeded. */
|
||||
s = fds[j].fd;
|
||||
fds[j].fd = -1;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
} while (timeout == INFTIM && count != 0);
|
||||
}
|
||||
|
||||
/* All attempts were failed */
|
||||
s = -1;
|
||||
if (count == 0)
|
||||
errno = ETIMEDOUT;
|
||||
|
||||
done:
|
||||
/* Close all watched fds except the succeeded one */
|
||||
for (j = 0; j < i; j++)
|
||||
if (fds[j].fd != -1)
|
||||
close(fds[j].fd);
|
||||
free(fds);
|
||||
return (s);
|
||||
}
|
||||
|
||||
static void
|
||||
whois(const char *query, const char *hostname, const char *hostport, int flags)
|
||||
{
|
||||
FILE *fp;
|
||||
struct addrinfo *hostres;
|
||||
char *buf, *host, *nhost, *nport, *p;
|
||||
int comment, s, f;
|
||||
size_t len, i;
|
||||
|
||||
hostres = gethostinfo(hostname, hostport, 1);
|
||||
s = connect_to_any_host(hostres);
|
||||
if (s == -1)
|
||||
err(EX_OSERR, "connect()");
|
||||
|
||||
/* Restore default blocking behavior. */
|
||||
if ((f = fcntl(s, F_GETFL)) == -1)
|
||||
err(EX_OSERR, "fcntl()");
|
||||
f &= ~O_NONBLOCK;
|
||||
if (fcntl(s, F_SETFL, f) == -1)
|
||||
err(EX_OSERR, "fcntl()");
|
||||
|
||||
fp = fdopen(s, "r+");
|
||||
if (fp == NULL)
|
||||
err(EX_OSERR, "fdopen()");
|
||||
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, DENICHOST) == 0 ||
|
||||
strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
|
||||
const char *q;
|
||||
int idn = 0;
|
||||
for (q = query; *q != '\0'; q++)
|
||||
if (!isascii(*q))
|
||||
idn = 1;
|
||||
fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
|
||||
} else if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, DKNICHOST) == 0 ||
|
||||
strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
|
||||
fprintf(fp, "--show-handles %s\r\n", query);
|
||||
else if ((flags & WHOIS_SPAM_ME) ||
|
||||
strchr(query, ' ') != NULL)
|
||||
fprintf(fp, "%s\r\n", query);
|
||||
else if (strcasecmp(hostname, ANICHOST) == 0) {
|
||||
if (strncasecmp(query, "AS", 2) == 0 &&
|
||||
strspn(query+2, "0123456789") == strlen(query+2))
|
||||
fprintf(fp, "+ a %s\r\n", query+2);
|
||||
else
|
||||
fprintf(fp, "+ %s\r\n", query);
|
||||
} else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
|
||||
fprintf(fp, "domain %s\r\n", query);
|
||||
else
|
||||
fprintf(fp, "%s\r\n", query);
|
||||
fflush(fp);
|
||||
|
||||
comment = 0;
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, ANICHOST) == 0 ||
|
||||
strcasecmp(hostname, RNICHOST) == 0)) {
|
||||
comment = 2;
|
||||
}
|
||||
|
||||
nhost = NULL;
|
||||
while ((buf = fgetln(fp, &len)) != NULL) {
|
||||
/* Nominet */
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
|
||||
break;
|
||||
/* RIRs */
|
||||
if (comment == 1 && buf[0] == '#')
|
||||
break;
|
||||
else if (comment == 2) {
|
||||
if (strchr("#%\r\n", buf[0]) != NULL)
|
||||
continue;
|
||||
else
|
||||
comment = 1;
|
||||
}
|
||||
|
||||
printf("%.*s", (int)len, buf);
|
||||
|
||||
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
|
||||
for (i = 0; whois_referral[i].prefix != NULL; i++) {
|
||||
p = buf;
|
||||
SCAN(p, buf+len, *p == ' ');
|
||||
if (strncasecmp(p, whois_referral[i].prefix,
|
||||
whois_referral[i].len) != 0)
|
||||
continue;
|
||||
p += whois_referral[i].len;
|
||||
SCAN(p, buf+len, *p == ' ');
|
||||
host = p;
|
||||
SCAN(p, buf+len, ishost(*p));
|
||||
if (p > host) {
|
||||
char *pstr;
|
||||
|
||||
s_asprintf(&nhost, "%.*s",
|
||||
(int)(p - host), host);
|
||||
|
||||
if (*p != ':') {
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
|
||||
pstr = ++p;
|
||||
SCAN(p, buf+len, isdigit(*p));
|
||||
if (p > pstr && (p - pstr) < 6) {
|
||||
s_asprintf(&nport, "%.*s",
|
||||
(int)(p - pstr), pstr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Invalid port; don't recurse */
|
||||
free(nhost);
|
||||
nhost = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; actually_arin[i] != NULL; i++) {
|
||||
if (strncmp(buf, actually_arin[i], len) == 0) {
|
||||
s_asprintf(&nhost, "%s", ANICHOST);
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Verisign etc. */
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
len >= sizeof(CHOPSPAM)-1 &&
|
||||
(strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
|
||||
strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
freeaddrinfo(hostres);
|
||||
|
||||
f = 0;
|
||||
for (i = 0; try_rir[i].host != NULL; i++) {
|
||||
/* Remember visits to RIRs */
|
||||
if (try_rir[i].loop == 0 &&
|
||||
strcasecmp(try_rir[i].host, hostname) == 0)
|
||||
try_rir[i].loop = 1;
|
||||
/* Do we need to find an alternative RIR? */
|
||||
if (try_rir[i].loop != 0 && nhost != NULL &&
|
||||
strcasecmp(try_rir[i].host, nhost) == 0) {
|
||||
free(nhost);
|
||||
nhost = NULL;
|
||||
free(nport);
|
||||
nport = NULL;
|
||||
f = 1;
|
||||
}
|
||||
}
|
||||
if (f) {
|
||||
/* Find a replacement RIR */
|
||||
for (i = 0; try_rir[i].host != NULL; i++) {
|
||||
if (try_rir[i].loop == 0) {
|
||||
s_asprintf(&nhost, "%s", try_rir[i].host);
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nhost != NULL) {
|
||||
/* Ignore self-referrals */
|
||||
if (strcasecmp(hostname, nhost) != 0) {
|
||||
printf("# %s\n\n", nhost);
|
||||
whois(query, nhost, nport, flags);
|
||||
}
|
||||
free(nhost);
|
||||
free(nport);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
|
||||
"[-p port] name ...\n");
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
+57
-3
@@ -7,16 +7,70 @@ extern bool __assert_disable;
|
||||
void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(EXPR) ((void)0)
|
||||
#define assert(x) ((void)0)
|
||||
#else
|
||||
#define assert(EXPR) \
|
||||
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
|
||||
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__), 0)))
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifndef TINY
|
||||
/**
|
||||
* Specifies expression can't possibly be false.
|
||||
*
|
||||
* This macro uses the `notpossible` keyword and is intended for things
|
||||
* like systems integration, where we know for a fact that something is
|
||||
* never going to happen, but there's no proof. So we don't want to add
|
||||
* extra bloat for filenames and line numbers, since `ShowCrashReports`
|
||||
* can print a backtrace if we just embed the UD2 instruction to crash.
|
||||
* That's useful for systems code, for the following reason. Invariants
|
||||
* make sense with _unassert() since they usually get placed at the top
|
||||
* of functions. But if you used _unassert() to test a system call does
|
||||
* not fail, then check happens at the end of your function usually and
|
||||
* is therefore likely to result in a failure condition where execution
|
||||
* falls through into a different function, which is shocking to debug.
|
||||
*
|
||||
* In `MODE=tiny` these assertions are redefined as undefined behavior.
|
||||
*/
|
||||
#define _npassert(x) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
notpossible; \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#else
|
||||
#define _npassert(x) _unassert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
/**
|
||||
* Specifies expression being false is undefined behavior.
|
||||
*
|
||||
* This is a good way to tell the compiler about your invariants, which
|
||||
* leads to smaller faster programs. The expression is never removed by
|
||||
* the preprocessor so it's recommended that it be free of side-effects
|
||||
* if you intend for it to be removed. At the same time, this guarantee
|
||||
* makes this assertion useful for things like system calls, since they
|
||||
* won't be removed by `NDEBUG` mode.
|
||||
*
|
||||
* If this assertion fails, the worst possible things can happen unless
|
||||
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
|
||||
* that's capable of debugging this macro.
|
||||
*/
|
||||
#define _unassert(x) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ASSERT_H_ */
|
||||
+24
-39
@@ -1,21 +1,8 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview C11 Atomic Types
|
||||
*
|
||||
* We supoprt C++ and old C compilers. It's recommended you use macros
|
||||
* like `_Atomic(int)` rather than `_Atomic int` or `atomic_int` since
|
||||
* we only define a portability macro for the syntax `_Atomic(T)`.
|
||||
*
|
||||
* @see libc/integral/c.inc
|
||||
* @see libc/intrin/atomic.h
|
||||
*/
|
||||
|
||||
#define atomic_bool _Atomic(_Bool)
|
||||
#define atomic_bool32 atomic_int32
|
||||
#define atomic_bool32 _Atomic(__INT32_TYPE__)
|
||||
#define atomic_char _Atomic(char)
|
||||
#define atomic_schar _Atomic(signed char)
|
||||
#define atomic_uchar _Atomic(unsigned char)
|
||||
@@ -27,29 +14,29 @@ COSMOPOLITAN_C_START_
|
||||
#define atomic_ulong _Atomic(unsigned long)
|
||||
#define atomic_llong _Atomic(long long)
|
||||
#define atomic_ullong _Atomic(unsigned long long)
|
||||
#define atomic_char16_t _Atomic(char16_t)
|
||||
#define atomic_char32_t _Atomic(char32_t)
|
||||
#define atomic_wchar_t _Atomic(wchar_t)
|
||||
#define atomic_intptr_t _Atomic(intptr_t)
|
||||
#define atomic_uintptr_t _Atomic(uintptr_t)
|
||||
#define atomic_size_t _Atomic(size_t)
|
||||
#define atomic_ptrdiff_t _Atomic(ptrdiff_t)
|
||||
#define atomic_int_fast8_t _Atomic(int_fast8_t)
|
||||
#define atomic_uint_fast8_t _Atomic(uint_fast8_t)
|
||||
#define atomic_int_fast16_t _Atomic(int_fast16_t)
|
||||
#define atomic_uint_fast16_t _Atomic(uint_fast16_t)
|
||||
#define atomic_int_fast32_t _Atomic(int_fast32_t)
|
||||
#define atomic_uint_fast32_t _Atomic(uint_fast32_t)
|
||||
#define atomic_int_fast64_t _Atomic(int_fast64_t)
|
||||
#define atomic_uint_fast64_t _Atomic(uint_fast64_t)
|
||||
#define atomic_int_least8_t _Atomic(int_least8_t)
|
||||
#define atomic_uint_least8_t _Atomic(uint_least8_t)
|
||||
#define atomic_int_least16_t _Atomic(int_least16_t)
|
||||
#define atomic_uint_least16_t _Atomic(uint_least16_t)
|
||||
#define atomic_int_least32_t _Atomic(int_least32_t)
|
||||
#define atomic_uint_least32_t _Atomic(uint_least32_t)
|
||||
#define atomic_int_least64_t _Atomic(int_least64_t)
|
||||
#define atomic_uint_least64_t _Atomic(uint_least64_t)
|
||||
#define atomic_char16_t _Atomic(__CHAR16_TYPE__)
|
||||
#define atomic_char32_t _Atomic(__CHAR32_TYPE__)
|
||||
#define atomic_wchar_t _Atomic(__WCHAR_TYPE__)
|
||||
#define atomic_intptr_t _Atomic(__INTPTR_TYPE__)
|
||||
#define atomic_uintptr_t _Atomic(__UINTPTR_TYPE__)
|
||||
#define atomic_size_t _Atomic(__SIZE_TYPE__)
|
||||
#define atomic_ptrdiff_t _Atomic(__PTRDIFF_TYPE__)
|
||||
#define atomic_int_fast8_t _Atomic(__INT_FAST8_TYPE__)
|
||||
#define atomic_uint_fast8_t _Atomic(__UINT_FAST8_TYPE__)
|
||||
#define atomic_int_fast16_t _Atomic(__INT_FAST16_TYPE__)
|
||||
#define atomic_uint_fast16_t _Atomic(__UINT_FAST16_TYPE__)
|
||||
#define atomic_int_fast32_t _Atomic(__INT_FAST32_TYPE__)
|
||||
#define atomic_uint_fast32_t _Atomic(__UINT_FAST32_TYPE__)
|
||||
#define atomic_int_fast64_t _Atomic(__INT_FAST64_TYPE__)
|
||||
#define atomic_uint_fast64_t _Atomic(__UINT_FAST64_TYPE__)
|
||||
#define atomic_int_least8_t _Atomic(__INT_LEAST8_TYPE__)
|
||||
#define atomic_uint_least8_t _Atomic(__UINT_LEAST8_TYPE__)
|
||||
#define atomic_int_least16_t _Atomic(__INT_LEAST16_TYPE__)
|
||||
#define atomic_uint_least16_t _Atomic(__UINT_LEAST16_TYPE__)
|
||||
#define atomic_int_least32_t _Atomic(__INT_LEAST32_TYPE__)
|
||||
#define atomic_uint_least32_t _Atomic(__UINT_LEAST32_TYPE__)
|
||||
#define atomic_int_least64_t _Atomic(__INT_LEAST64_TYPE__)
|
||||
#define atomic_uint_least64_t _Atomic(__UINT_LEAST64_TYPE__)
|
||||
|
||||
#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
@@ -75,6 +62,4 @@ COSMOPOLITAN_C_START_
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ATOMIC_H_ */
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
void CPU_AND(cpu_set_t *d, cpu_set_t *x, cpu_set_t *y) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(d->__bits); ++i) {
|
||||
d->__bits[i] = x->__bits[i] & y->__bits[i];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
int CPU_COUNT(cpu_set_t *set) {
|
||||
int i, c;
|
||||
for (c = i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
c += popcnt(set->__bits[i]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int CPU_EQUAL(cpu_set_t *x, cpu_set_t *y) {
|
||||
return !memcmp(x, y, sizeof(*x));
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
void CPU_OR(cpu_set_t *d, cpu_set_t *x, cpu_set_t *y) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(d->__bits); ++i) {
|
||||
d->__bits[i] = x->__bits[i] | y->__bits[i];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
void CPU_XOR(cpu_set_t *d, cpu_set_t *x, cpu_set_t *y) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(d->__bits); ++i) {
|
||||
d->__bits[i] = x->__bits[i] ^ y->__bits[i];
|
||||
}
|
||||
}
|
||||
@@ -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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,11 +16,9 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
void(warn)(const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
(vwarn)(fmt, va);
|
||||
va_end(va);
|
||||
void CPU_ZERO(cpu_set_t *set) {
|
||||
bzero(set, sizeof(*set));
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,6 +16,6 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
||||
char __fatalbuf[FRAMESIZE];
|
||||
struct Signals __sig;
|
||||
@@ -16,26 +16,22 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||
* @threadsafe
|
||||
*/
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
@@ -61,6 +57,18 @@ static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
static inline textwindows int __sig_is_masked(int sig) {
|
||||
if (__tls_enabled) {
|
||||
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
|
||||
} else {
|
||||
return __sig.sigmask & (1ull << (sig - 1));
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int __sig_is_applicable(struct Signal *s) {
|
||||
return s->tid <= 0 || s->tid == gettid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
@@ -70,7 +78,7 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (__sig_is_applicable(res) && !__sig_is_masked(res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
@@ -78,8 +86,6 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%G is masked", res->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
@@ -117,7 +123,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
__repstosb(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
@@ -134,7 +140,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// since sigaction() is @asyncsignalsafe we only restore it if the
|
||||
// user didn't change it during the signal handler. we also don't
|
||||
// need to do anything if this was a oneshot signal or nodefer.
|
||||
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
__sig_lock();
|
||||
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
|
||||
__sighandrvas[sig] = rva;
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
|
||||
if (!restartable) {
|
||||
@@ -150,7 +160,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
static textwindows bool __sig_is_fatal(int sig) {
|
||||
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -168,10 +178,9 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
if (__sig_is_fatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
__restorewintty();
|
||||
_Exit(128 + sig);
|
||||
_Exitr(128 + sig);
|
||||
}
|
||||
// fallthrough
|
||||
case (intptr_t)SIG_IGN:
|
||||
@@ -195,20 +204,17 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
__sig_lock();
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
__sig_unlock();
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
} else {
|
||||
STRACE("%G is masked", sig);
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
return __sig_add(gettid(), sig, si_code);
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,10 +223,10 @@ textwindows int __sig_raise(int sig, int si_code) {
|
||||
* @return 0 on success, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
textwindows int __sig_add(int tid, int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (1 <= sig && sig <= 64) {
|
||||
__sig_lock();
|
||||
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
|
||||
STRACE("ignoring %G", sig);
|
||||
@@ -229,6 +235,7 @@ textwindows int __sig_add(int sig, int si_code) {
|
||||
STRACE("enqueuing %G", sig);
|
||||
++__sig_count;
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->tid = tid;
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
@@ -246,7 +253,7 @@ textwindows int __sig_add(int sig, int si_code) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
* Checks for unblocked signals and delivers them on New Technology.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
@@ -264,3 +271,38 @@ textwindows bool __sig_check(bool restartable) {
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a signal should be ignored and if so discards existing
|
||||
* instances of said signal on New Technology.
|
||||
*
|
||||
* Even blocked signals are discarded.
|
||||
*
|
||||
* @param sig the signal number to remove
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
struct Signal *cur, *prev, *next;
|
||||
if (rva != (unsigned)(intptr_t)SIG_IGN &&
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
|
||||
return;
|
||||
}
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (prev = 0, cur = __sig.queue; cur; cur = next) {
|
||||
next = cur->next;
|
||||
if (sig == cur->sig) {
|
||||
if (cur == __sig.queue) {
|
||||
__sig.queue = cur->next;
|
||||
} else if (prev) {
|
||||
prev->next = cur->next;
|
||||
}
|
||||
__sig_handle(false, cur->sig, cur->si_code, 0);
|
||||
__sig_free(cur);
|
||||
} else {
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
@@ -17,44 +17,37 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||
* @threadsafe
|
||||
*/
|
||||
#define GetSigBit(x) (1ull << (((x)-1) & 63))
|
||||
|
||||
struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||
int i;
|
||||
uint64_t a, b;
|
||||
uint64_t x, y, *mask;
|
||||
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
|
||||
__sig_lock();
|
||||
if (__tls_enabled) {
|
||||
mask = &__get_tls()->tib_sigmask;
|
||||
} else {
|
||||
mask = &__sig.sigmask;
|
||||
}
|
||||
if (old) {
|
||||
*old = __sig.mask;
|
||||
old->__bits[0] = *mask;
|
||||
old->__bits[1] = 0;
|
||||
}
|
||||
if (neu) {
|
||||
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
|
||||
if (how == SIG_BLOCK) {
|
||||
__sig.mask.__bits[i] |= neu->__bits[i];
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
__sig.mask.__bits[i] &= ~neu->__bits[i];
|
||||
} else {
|
||||
__sig.mask.__bits[i] = neu->__bits[i];
|
||||
}
|
||||
x = *mask;
|
||||
y = neu->__bits[0];
|
||||
if (how == SIG_BLOCK) {
|
||||
x |= y;
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
x &= ~y;
|
||||
} else {
|
||||
x = y;
|
||||
}
|
||||
__sig.mask.__bits[0] &= ~(SIGKILL | SIGSTOP);
|
||||
x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
|
||||
*mask = x;
|
||||
}
|
||||
__sig_unlock();
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *s;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (s = __sig.queue; s; s = s->next) {
|
||||
if (__sig_is_applicable(s) &&
|
||||
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
sigaddset(pending, s->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
extern const unsigned FIODGNAME;
|
||||
extern const unsigned TIOCPTSNAME;
|
||||
extern const unsigned TIOCPTYGNAME;
|
||||
|
||||
struct fiodgname_arg {
|
||||
int len;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
struct ptmget {
|
||||
int cfd;
|
||||
int sfd;
|
||||
char cn[1024];
|
||||
char sn[1024];
|
||||
};
|
||||
|
||||
int _ptsname(int fd, char *buf, size_t size) {
|
||||
int pty;
|
||||
size_t n;
|
||||
struct ptmget t;
|
||||
|
||||
if (_isptmaster(fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
t.sn[0] = '/';
|
||||
t.sn[1] = 'd';
|
||||
t.sn[2] = 'e';
|
||||
t.sn[3] = 'v';
|
||||
t.sn[4] = '/';
|
||||
t.sn[5] = 0;
|
||||
|
||||
if (IsLinux()) {
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
|
||||
t.sn[5] = 'p';
|
||||
t.sn[6] = 't';
|
||||
t.sn[7] = 's';
|
||||
t.sn[8] = '/';
|
||||
FormatInt32(t.sn + 9, pty);
|
||||
} else if (IsXnu()) {
|
||||
if (sys_ioctl(fd, TIOCPTYGNAME, t.sn)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (IsFreebsd()) {
|
||||
struct fiodgname_arg fgn = {sizeof(t.sn) - 5, t.sn + 5};
|
||||
if (sys_ioctl(fd, FIODGNAME, &fgn) == -1) {
|
||||
if (errno == EINVAL) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else if (IsNetbsd()) {
|
||||
if (sys_ioctl(fd, TIOCPTSNAME, &t)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
|
||||
if ((n = strlen(t.sn)) < size) {
|
||||
memcpy(buf, t.sn, n + 1);
|
||||
return 0;
|
||||
} else {
|
||||
return erange();
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,30 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
|
||||
/**
|
||||
* Compares nanosecond timestamps.
|
||||
*/
|
||||
int _timespec_cmp(struct timespec a, struct timespec b) {
|
||||
int cmp;
|
||||
if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) {
|
||||
cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
|
||||
/**
|
||||
* Converts timespec interval from nanoseconds.
|
||||
*/
|
||||
struct timespec _timespec_fromnanos(int64_t x) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = x / 1000000000;
|
||||
ts.tv_nsec = x % 1000000000;
|
||||
return ts;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Returns high-precision timestamp, the C11 way.
|
||||
*
|
||||
* @param ts receives `CLOCK_REALTIME` timestamp
|
||||
* @param base must be `TIME_UTC`
|
||||
* @return `base` on success, or `0` on failure
|
||||
* @see _timespec_real()
|
||||
*/
|
||||
int timespec_get(struct timespec *ts, int base) {
|
||||
if (base == TIME_UTC && !clock_gettime(CLOCK_REALTIME, ts)) {
|
||||
return base;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Returns high-precision timestamp granularity, the C23 way.
|
||||
*
|
||||
* @param ts receives granularity as a relative timestamp
|
||||
* @param base must be `TIME_UTC`
|
||||
* @return `base` on success, or `0` on failure
|
||||
*/
|
||||
int timespec_getres(struct timespec *ts, int base) {
|
||||
if (base == TIME_UTC && !clock_getres(CLOCK_REALTIME, ts)) {
|
||||
return base;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -19,13 +19,16 @@
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Returns current monotonic time.
|
||||
*
|
||||
* This function uses a `CLOCK_MONOTONIC` clock and never fails.
|
||||
*
|
||||
* @see _timespec_real()
|
||||
*/
|
||||
struct timespec _timespec_mono(void) {
|
||||
int ax, dx;
|
||||
struct timespec ts;
|
||||
ax = clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
|
||||
assert(!ax);
|
||||
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
|
||||
return ts;
|
||||
}
|
||||
@@ -19,13 +19,18 @@
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Returns current time.
|
||||
*
|
||||
* This function uses a `CLOCK_REALTIME` clock and never fails. Unlike
|
||||
* clock_gettime() or timespec_real() this interface avoids the use of
|
||||
* pointers which lets time handling code become more elegant.
|
||||
*
|
||||
* @see _timespec_mono()
|
||||
*/
|
||||
struct timespec _timespec_real(void) {
|
||||
int ax, dx;
|
||||
struct timespec ts;
|
||||
ax = clock_gettime(CLOCK_REALTIME_FAST, &ts);
|
||||
assert(!ax);
|
||||
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
|
||||
return ts;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
/**
|
||||
* Sleeps for specified delay.
|
||||
*
|
||||
* @return unslept time which may be non-zero if the call was interrupted
|
||||
*/
|
||||
struct timespec _timespec_sleep(struct timespec delay) {
|
||||
int rc;
|
||||
struct timespec remain;
|
||||
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
|
||||
return (struct timespec){0};
|
||||
} else {
|
||||
_npassert(rc == EINTR);
|
||||
return remain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
|
||||
/**
|
||||
* Sleeps until the specified time.
|
||||
*
|
||||
* @return 0 on success, or EINTR if interrupted
|
||||
*/
|
||||
int _timespec_sleep_until(struct timespec abs_deadline) {
|
||||
int rc;
|
||||
rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0);
|
||||
_npassert(!rc || rc == EINTR);
|
||||
return rc;
|
||||
}
|
||||
@@ -21,12 +21,12 @@
|
||||
/**
|
||||
* Subtracts two nanosecond timestamps.
|
||||
*/
|
||||
struct timespec _timespec_sub(struct timespec x, struct timespec y) {
|
||||
x.tv_sec -= y.tv_sec;
|
||||
x.tv_nsec -= y.tv_nsec;
|
||||
if (x.tv_nsec < 0) {
|
||||
x.tv_nsec += 1000000000;
|
||||
x.tv_sec -= 1;
|
||||
struct timespec _timespec_sub(struct timespec a, struct timespec b) {
|
||||
a.tv_sec -= b.tv_sec;
|
||||
if (a.tv_nsec < b.tv_nsec) {
|
||||
a.tv_nsec += 1000000000;
|
||||
a.tv_sec--;
|
||||
}
|
||||
return x;
|
||||
a.tv_nsec -= b.tv_nsec;
|
||||
return a;
|
||||
}
|
||||
Loaded 100 of 3332 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user