Compare commits

..
78 Commits
Author SHA1 Message Date
Justine Tunney af2ef0d223 Fix the build 2022-10-14 11:18:40 -07:00
Justine Tunney 8111462789 Add posix semaphores support
There's still some bugs to work out on Windows and OpenBSD.
2022-10-14 09:21:02 -07:00
Justine Tunney f52f65b2e3 Make system() and popen() thread safe 2022-10-13 15:54:05 -07:00
Justine Tunney 997ce29ddc Elevate Windows production worthiness
- SQLite file locking now works on Windows
- SQLite will now use fdatasync() on non-Apple platforms
- Fix Ctrl-C handler on Windows to not crash with TLS
- Signals now work in multithreaded apps on Windows
- fcntl() will now accurately report EINVAL errors
- fcntl() now has excellent --strace logging
- Token bucket replenish now go 100x faster
- *NSYNC cancellations now work on Windows
- Support closefrom() on NetBSD
2022-10-13 13:44:41 -07:00
tkchia d38700687a [metal] Allow more fine-grained control over page permissions (#663)
- use PAGE_RSRV bit (originally only for blinkenlights),
  rather than PAGE_V bit, to indicate that a virtual address
  page has been reserved — this should allow a program to
  create & reserve inaccessible "guard pages"
- mark page table entries for non-code pages with PAGE_XD bit,
  which should be supported on (circa) post-2004 x86-64 CPUs
2022-10-12 11:07:11 -07:00
Justine Tunney 0f89140882 Further improve cocmd interpreter 2022-10-12 10:44:54 -07:00
Justine Tunney 0cee831da3 Revamp posix_spawn() implementation 2022-10-12 05:26:58 -07:00
Justine Tunney b41f91c658 Greatly expand system() shell code features
The cosmopolitan command interpreter now has 13 builtin commands,
variable support, support for ; / && / || syntax, asynchronous support,
and plenty of unit tests with bug fixes.

This change fixes a bug in posix_spawn() with null envp arg. strace
logging now uses atomic writes for scatter functions. Breaking change
renaming GetCpuCount() to _getcpucount(). TurfWar is now updated to use
the new token bucket algorithm. WIN32 affinity masks now inherit across
fork() and execve().
2022-10-11 21:30:31 -07:00
Justine Tunney e7329b7cba Implement atomic swar token bucket library 2022-10-11 21:22:04 -07:00
Justine Tunney c19ac8729d Reinvent the classic unix wall command 2022-10-11 21:22:03 -07:00
Connor 9d2f993364 Fix make sandboxing logic for .STRICT mode (#661)
Patch segfaults and handle the `.STRICT = 0` case.
2022-10-11 21:16:03 -07:00
tkchia 31dab8a75d [metal] Fix bug: do not initialize IDT & TSS if unneeded (#654)
libc/intrin/interrupts.S should not be linked in unless
an IDT (or TSS) is explicitly requested somewhere (i.e.
it should probably not be a mandatory module).
2022-10-10 20:54:46 -07:00
tkchiaandtkchia 7a06760e6f Rename LINUX to _HOSTLINUX etc. to reduce clashes (#655)
Co-authored-by: tkchia <[email protected]>
2022-10-10 20:31:25 -07:00
Connor 9209ea63a7 Integrate upstream dash changes into unbourne shell (#656) 2022-10-10 20:29:28 -07:00
Malcolm Seyd 84b9b8ed87 Fix ParseHttpMessage failing to store >2 repeatable headers (#657) 2022-10-10 20:17:17 -07:00
Justine Tunney e557058ac8 Improve cosmo's conformance to libc-test
This change addresses various open source compatibility issues, so that
we pass 313/411 of the tests in https://github.com/jart/libc-test where
earlier today we were passing about 30/411 of them, due to header toil.
Please note that Glibc only passes 341/411 so 313 today is pretty good!

- Make the conformance of libc/isystem/ headers nearly perfect
- Import more of the remaining math library routines from Musl
- Fix inconsistencies with type signatures of calls like umask
- Write tests for getpriority/setpriority which work great now
- conform to `struct sockaddr *` on remaining socket functions
- Import a bunch of uninteresting stdlib functions e.g. rand48
- Introduce readdir_r, scandir, pthread_kill, sigsetjmp, etc..

Follow the instructions in our `tool/scripts/cosmocc` toolchain to run
these tests yourself. You use `make CC=cosmocc` on the test repository
2022-10-10 17:52:41 -07:00
Justine Tunney 467a332e38 Introduce sigtimedwait() and sigwaitinfo()
This change also invents sigcountset() and strsignal_r() and improves
the quality of siginfo_t handling.
2022-10-10 07:39:44 -07:00
Justine Tunney 7ae556463a Rename rand64() to _rand64() 2022-10-10 04:12:06 -07:00
Justine Tunney c424352a0a Disable make sandobxing unless .STRICT=1
This change makes Landlock Make backwards compatible.
2022-10-10 03:49:58 -07:00
Justine Tunney d5910e2673 Fix bugs and make code tinier
- Fixed bug where stdio eof wasn't being sticky
- Fixed bug where fseeko() wasn't clearing eof state
- Removed assert() usage from libc favoring _unassert() / _npassert()
2022-10-09 23:21:34 -07:00
Justine Tunney 9b7c8db846 Perform some code maintenance
- Change IDT code so kprintf() isn't mandatory dependency
- Document current intentions around pthread_cancel()
- Make _npassert() an _unassert() in MODE=tiny
2022-10-09 13:00:46 -07:00
Justine Tunney 4a6fd3d910 Make more improvements to threading support
- fix rare thread exit race condition on openbsd
- pthread_getattr_np() now supplies detached status
- child threads may now pthread_join() the main thread
- introduce sigandset(), sigorset(), and sigisemptyset()
- introduce pthread_cleanup_push() and pthread_cleanup_pop()
2022-10-09 00:08:47 -07:00
Justine Tunney 38df0a4186 Release Cosmpolitan 2.1.1 2022-10-08 09:17:13 -07:00
Justine Tunney 1c0adb556d Release redbean v2.1 2022-10-08 09:03:51 -07:00
Justine Tunney 8aca94f951 Add shared memory hit counter example to redbean 2022-10-08 08:39:13 -07:00
Justine Tunney 38e3ab57a6 Add the TurfWar schema 2022-10-08 03:23:21 -07:00
Justine Tunney 672ccda37c Clean up some sleep code 2022-10-08 03:00:48 -07:00
Justine Tunney 9849b4c7ba Add *NSYNC unit test suite
This change also fixes the clock_nanosleep() api and polyfills futexes
on Windows, Mac, and NetBSD using exponential backoff.
2022-10-07 21:34:15 -07:00
tkchia 3421b9a580 [metal] Push forward timing of VGA TTY initialization (#653) 2022-10-07 17:10:28 -07:00
Justine Tunney 29d695f4c9 Make unbing() not need initialization 2022-10-07 14:56:02 -07:00
Justine Tunney 7d6835c0dd Release pledge v1.8 2022-10-07 03:41:50 -07:00
Justine Tunney 05197afca2 Do some work on TurfWar 2022-10-07 03:11:07 -07:00
tkchia bc353f454b Fix sys_mmap_metal() for non-MAP_FIXED case (#651)
- correctly check that virtual region we want to use is
  unmapped, rather than accidentally clobbering existing pages
- avoid placing mmap'd memory at null virtual address
2022-10-06 16:27:52 -07:00
Danny Robinson 7bc24888fe Update redbean api definitions (#652) 2022-10-06 16:27:23 -07:00
Justine Tunney 59ac141e49 Improve the affinity system calls 2022-10-06 15:08:29 -07:00
Justine Tunney 60b68d7152 Fix naming for redbean shared memory atomics 2022-10-06 09:41:22 -07:00
Justine Tunney a5b483f2d4 Make some quick fixes 2022-10-06 06:36:46 -07:00
tkchia d3efa47f81 Show "screen of death" on VGA console upon program crash (#650)
* [metal] Refactoring: separate out sys_writev_vga() and _vga_init() modules

* [metal] Read VGA info from BDA before long mode entry, not after

If using a pre-existing VGA text console, the VGA initialization
code now retrieves the cursor position & character height from
the BIOS data area while still in real mode — rather than
reading from the BIOS data area only after entering long mode.

(This should help make the code more correct, if Cosmopolitan
were to support UEFI graphics output in the future.  If the
program were booted via UEFI, then the long mode IsMetal()
code would still be activated, but the BIOS data area might
not have been initialized in that case.)

This change also means that there are now a few more fields
in the `struct mman`.

* [metal] VGA console can now show "screen of death" upon a crash

There is now a new function _klog_vga(), which can be called
by kprintf() to output system messages — e.g. information about
CPU exceptions — on the VGA screen.

* [metal] CPU exception handler now dumps cr2 value
* [metal] Add demo of program crash reporting w/ bare metal VGA TTY
* [metal] Reduce size of "screen of death" code
2022-10-06 05:36:15 -07:00
Justine Tunney 7822917fc2 Add shared memory apis to redbean
You can now do things like implement mutexes using futexes in your
redbean lua code. This provides the fastest possible inter-process
communication for your production systems when SQLite alone as ipc
or things like pipes aren't sufficient.
2022-10-06 04:55:26 -07:00
Justine Tunney 81ee11a16e Fix futimes() regression
Fixes #647
2022-10-05 19:25:07 -07:00
Hugues Morisset f155205eb0 Add imaxdiv, wcscoll, getdtablesize (#639) 2022-10-05 07:14:58 -07:00
Gavin Hayes e46ef487a8 Add utime to utime.h (#648) 2022-10-05 07:13:23 -07:00
Daniel Oltmanns afc07b9339 Proof of concept of sqlite serialization (#436)
* Proof of concept of sqlite serialization

This is a minimal proof of concept in order to show that it is easily possible to store the sqlite database within the zip file itself not requiring creating an external file first. Changes include compiling the sqlite library with the serialization flag, adding serialize/deserialize to the lua sqlite library and demonstrating the work via the redbean demo.

* Change demo for sqlite serialization

As explained in https://github.com/jart/cosmopolitan/pull/436#issuecomment-1164706893 the original use case is not possible with sqlite serialization, as an in-memory database cannot be shared across multiple processes. Thereby, this use case simply creates a backup of the in-memory database created in '.init.lua' and loads it to do a query.

* Fix sqlite3_deserialize parameters

The call to the sqlite3 library for the deserilization wasn't fully correct. This should fix the size parameters.
2022-10-05 07:09:53 -07:00
tkchia edb8fef06c Add basic character output for VGA graphics mode console (#649)
* Test output of colors for VGA graphics modes in examples/vga.c
* [metal] Character output in VGA graphics modes is mostly working
* [metal] Mention magic key to switch video mode, at bootup
2022-10-05 06:46:50 -07:00
Justine Tunney b75a4654cf Introduce clock_nanosleep() 2022-10-05 06:37:15 -07:00
Justine Tunney fe3216e961 Perform some code cleanup 2022-10-04 23:32:16 -07:00
Justine Tunney 174d288e66 Tune claim SQL query 2022-10-04 10:22:08 -07:00
Justine Tunney 9f9b240f3d Make HTTP message parsing a little faster
ParseHttpMessage() now does a better job avoiding malloc() calls and
headers commonly sent by CloudFlare can now be consulted in constant
time using our hard-coded perfect hash table.  This increases /claim
performance from 321k to 337k qps which is 5% faster.
2022-10-04 06:37:46 -07:00
Justine Tunney 726f04e8aa Further enhance IPv4 TurfWar server
- We now vary `/claim` responses based on the `Accept` header
- Remove xasprintf() call to boost `/claim` perf to 321k qps!
2022-10-04 05:27:36 -07:00
Justine Tunney 556697cbd8 Fix MODE=dbg build 2022-10-03 22:58:00 -07:00
Justine Tunney 3ee3736a01 Put finishing touches on turfwar http server
- Shutdown process now has optimal cancellation latency
- Fairer techniques for shedding connections under load
- We no longer need to call poll() which is now removed
2022-10-03 21:50:00 -07:00
Justine Tunney 01bd7d1008 Update a few remaining zlib source files 2022-10-03 19:24:02 -07:00
Justine Tunney 32321ab1e9 Further improve ipv4.games server 2022-10-03 16:00:04 -07:00
Justine Tunney 3b4fcd8575 Fix corner case in Linux stack mappings
We need to make sure no existing mappings exist between the
MAP_GROWSDOWN page and the guard page, since otherwise it's
not going to be able to grow down thus causing difficult to
troubleshoot failures.
2022-10-03 13:43:52 -07:00
Justine Tunney 6ba3b448f3 Fix file descriptor leak in turfwar.c 2022-10-03 08:34:04 -07:00
Justine Tunney 91e167caaf Rewrite IPv4 Turf War backend
It can now handle 240k SQLite write QPS at 3ms 99 percentile latency.
We're still working out the kinks since it's brand new. But we've got
this running in production already!
2022-10-03 08:23:54 -07:00
Justine Tunney ccbae7799e Improve docs of more system calls
This change also found a few POSIX compliance bugs with errnos. Another
bug was discovered where, on Windows, pread() and pwrite() could modify
the file position in cases where ReadFile() returned an error e.g. when
seeking past the end of file. We also have more tests!
2022-10-02 22:14:33 -07:00
Justine Tunney af24c19db3 Support whitespace after cocmd output redirection 2022-10-02 21:55:16 -07:00
Justine Tunney 950a1b310b Embed cocmd.com interpreter for system() / open()
This change lets you use system() in an easier and portable way. The
problem with the call in the past has always been that bourne and
cmd.com on Windows have less than nothing in common, so pretty much the
only command system() could be used for across platforms was maybe echo.
cmd.exe is also a security liability due to its escaping rules.

Since cocmd.com implements 85% of what we need from bourne, in a really
tiny way, it makes perfect sense to be embedded in these functionss. We
get a huge performance boost too.

Fixes #644
2022-10-02 15:29:57 -07:00
Justine Tunney daca5499b9 Add some tests for execve() 2022-10-02 14:58:14 -07:00
Danny Robinson 2526a9b8c7 Fix re.NOSUB memory error (#645) 2022-10-02 12:49:23 -07:00
Justine Tunney 7549a5755e Support futexes on FreeBSD 2022-10-02 11:57:13 -07:00
Justine Tunney 795d295590 Tune GitHub Actions to use APE loader 2022-10-02 10:20:08 -07:00
Justine Tunney 3f3cb0650b Have execve() escape double quotes in cmd.exe's preferred style
This makes it possible for us to use system() and popen() with paths
that redirect to filenames that contain spaces, e.g.

    system("echo.com hello >\"hello there.txt\"")

It's difficult to solve this problem, because WIN32 only allows passing
one single argument when launching programs and each program is allowed
to tokenize that however it wants. Most software follows the convention
of cmd.exe which is poorly documented and positively byzantine.

In the future we're going to solve this by not using cmd.exe at all and
instead embedding the cocmd.com interpreter into the system() function.
In the meantime, our documentation has been updated to help recalibrate
any expectation the user might hold regarding the security of using the
Windows command interpreter.

Fixes #644
2022-10-02 09:15:46 -07:00
Justine Tunney acd8900071 Add fexecve() and map O_EXEC to O_PATH on Linux 2022-10-02 09:15:46 -07:00
Justine Tunney 6c60793f3a Add better fix for Windows fork+strace TLS crashes 2022-10-02 09:15:46 -07:00
Justine Tunney ad97775370 Improve system call documentation
This change also introduces partial faccessat() support for zipos and
makes some slight breaking changes in errno results. close() is fixed
to use `EBADF` rather than `EINVAL` and we're now using `ENOTSUP` not
`EOPNOTSUPP` to indicate that zipos doesn't support a system call yet
2022-10-02 09:15:46 -07:00
Justine Tunney 0b5f84dd20 Introduce double quote support in cocmd.com shell 2022-10-02 09:15:46 -07:00
Justine Tunney 27b5deefb1 Introduce testlib_extract() helper 2022-10-02 09:15:46 -07:00
tkchia ecb2ef7c39 Start exploring graphical video modes for VGA console (#637) 2022-10-02 01:50:16 -07:00
Hugues Morisset 304cf8869c Fix wcsdup malloc size (#641)
Other wcs* function expect a full sizeof(wchar_t) NUL char at the end
of the string.
2022-10-02 00:47:05 -07:00
tkchia 3e0ddf70e9 Make shell script magic less prone to breakage (#643)
The metal boot sector code was wrapped in a single-quoted
string, like so:

    MZqFpD='
    ...MZ HEADER...
    ...E_LFANEW...
    ...BIOS BOOT SECTOR...'

This might break the shell code loader if the boot sector code
contains a 0x27 (single quote) byte.  This patch wraps the
boot sector code in a here-document instead:

    MZqFpD='
    ...MZ HEADER...' <<'@'
    ...E_LFANEW...
    ...BIOS BOOT SECTOR...
    @

This is harder to break — when interpreted as a shell script,
the code can only accidentally terminate the here-document
if there is a "\n@\n" sequence inside the BIOS boot portion.
2022-10-02 00:45:25 -07:00
Justine Tunney 5005f2e446 Rewrite brk() and sbrk()
This change reduces the .bss memory requirement for all executables by
O(64kb). The brk system calls are now fully tested and figured out and
might be useful for tiny programs that only target System Five.
2022-10-01 23:11:56 -07:00
tkchia bc8532688b Enable CPU exception handling w/ IDT & TSS (#640) 2022-09-29 14:43:08 -07:00
Justine Tunney 09811e739f Add Wasmer to Special Thanks 2022-09-27 19:00:11 -07:00
Justine Tunney 24988f2351 Add Rob Figueiredo to Special Thanks 2022-09-27 18:17:22 -07:00
Justine Tunney b46f763ee7 Permit multiple certs with same common name
This is needed to support Cloudflare interop.
2022-09-27 18:17:04 -07:00
Gavin Hayes 87708c5d6e Change accept type to struct sockaddr * (#630) 2022-09-20 07:49:16 -07:00
914 changed files with 29772 additions and 7284 deletions

No files matched your search

+5 -2
View File
@@ -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 }}
+14 -2
View File
@@ -121,6 +121,7 @@ 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 # │
@@ -160,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
@@ -167,7 +169,7 @@ 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
@@ -202,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
@@ -307,7 +310,7 @@ COSMOPOLITAN_OBJECTS = \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
LIBC_THREAD \
THIRD_PARTY_NSYNC_MALLOC \
THIRD_PARTY_NSYNC_MEM \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_RUNTIME \
@@ -400,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
+5 -3
View File
@@ -23,8 +23,8 @@ If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux:
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.zip
unzip cosmopolitan-amalgamation-2.1.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 -gdwarf-4 \
@@ -258,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.
+26 -16
View File
@@ -125,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
@@ -250,7 +251,6 @@ pc: cld
xor %cx,%cx # current cylinder
xor %dh,%dh # current head
mov $v_ape_realsectors,%di # total sectors
sub $v_ape_realslacksectors,%di
3: call pcread
dec %di
jnz 3b
@@ -549,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.
@@ -874,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
@@ -1137,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)
@@ -1172,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 │
@@ -1278,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
@@ -1408,7 +1415,7 @@ pinit: push %ds
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
mov $512,%cx # PD±2MB
mov $PAGE_V+PAGE_RW,%eax
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
xor %di,%di
0: stosl
add $0x1000,%eax
@@ -1431,9 +1438,9 @@ golong: cli
mov %eax,%cr4
movl $EFER,%ecx
rdmsr
or $EFER_LME|EFER_SCE,%eax
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
wrmsr
lgdt REAL(gdt)
lgdt REAL(_gdtrphy)
mov %cr0,%eax
or $CR0_PE|CR0_PG|CR0_MP,%eax
and $~CR0_EM,%eax
@@ -1451,6 +1458,8 @@ long: xor %eax,%eax
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
@@ -1464,6 +1473,8 @@ long: xor %eax,%eax
call __map_phdrs
push $0x037f
fldcw (%rsp)
lgdt _gdtr # reload GDTR for
# virtual memory space
movabs $kernel,%rax
jmp *%rax
.endfn long
@@ -1544,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
@@ -1586,7 +1597,6 @@ kernel: movabs $ape_stack_vaddr,%rsp
.ldsvar _end
.ldsvar _etext
.ldsvar v_ape_realsectors
.ldsvar v_ape_realslacksectors
.ldsvar v_ape_highsectors
.ldsvar ape_idata_ro
.ldsvar ape_pad_rodata
+3 -5
View File
@@ -427,7 +427,7 @@ SECTIONS {
KEEP(*(.bssepilogue))
/*END: NT FORK COPYING */
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
. = ALIGN(PAGESIZE);
HIDDEN(_end = .);
PROVIDE_HIDDEN(end = .);
} :Bss
@@ -565,13 +565,11 @@ SHSTUB2(ape_loader_dd_count,
#if SupportsMetal()
HIDDEN(v_ape_realsectors =
MIN(0x70000 - IMAGE_BASE_REAL,
ROUNDUP(RVA(_edata), 4096)) / 512);
HIDDEN(v_ape_realslacksectors =
v_ape_realsectors - MIN(0x70000 - IMAGE_BASE_REAL,
ROUNDUP(RVA(_edata), 512)) / 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 */
+2 -2
View File
@@ -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
View File
@@ -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
+31
View File
@@ -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__)
@@ -257,5 +271,22 @@
(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_ */
Binary file not shown.
+15 -23
View File
@@ -73,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
+1
View File
@@ -73,6 +73,7 @@ EXAMPLES_DIRECTDEPS = \
NET_HTTPS \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_LIBCXX \
+1 -8
View File
@@ -9,19 +9,12 @@
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/nt/nt/process.h"
#include "libc/mem/gc.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
dontinline void dostuff(const char *s) {
int i, us;
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
for (i = 0; i < 5; ++i) {
us = rand() % 500000;
usleep(us);
+2 -2
View File
@@ -8,8 +8,8 @@
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/intrin/kprintf.h"
#include "libc/runtime/sysconf.h"
#include "libc/runtime/runtime.h"
int main() {
kprintf("%d\n", GetCpuCount());
kprintf("%d\n", _getcpucount());
}
+2 -2
View File
@@ -102,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);
@@ -215,7 +215,7 @@ const struct Function {
{"moby", moby}, //
{"mt19937", _mt19937}, //
{"python", pythonx2}, //
{"rand64", rand64}, //
{"rand64", _rand64}, //
{"rdrand", rdrand}, //
{"rdrnd", rdrand}, //
{"rdseed", rdseed}, //
+3 -4
View File
@@ -28,7 +28,6 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/sysconf.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/sockaddr.h"
@@ -137,7 +136,7 @@ void *Worker(void *id) {
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
errno = 0;
if (bind(server, &addr, sizeof(addr)) == -1) {
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
kprintf("%s() failed %m\n", "socket");
goto CloseWorker;
}
@@ -167,7 +166,7 @@ void *Worker(void *id) {
// 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
@@ -299,7 +298,7 @@ int main(int argc, char *argv[]) {
PORT);
}
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
if (!(1 <= threads && threads <= 100000)) {
kprintf("error: invalid number of threads: %d\n", threads);
exit(1);
+436 -357
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -49,12 +49,12 @@ int main(int argc, char *argv[]) {
printf("res = %d?\n", res);
return -1;
}
printf("Hello World! %.19Lg\n", atan2l(x, y));
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 %`'.*s\r\n", res, buf);
printf("got \e[97m%`'.*s\e[0m\r\n", res, buf);
}
}
}
+33
View File
@@ -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 (;;);
}
+148
View File
@@ -0,0 +1,148 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/struct/tm.h"
#include "third_party/getopt/getopt.h"
#include "third_party/musl/passwd.h"
/**
* @fileoverview program for broadcasting message to all terminals, e.g.
*
* o//examples/wall.com hello friends
*
* Will place some bold text into the top left corners of all terminals:
*
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
* hello friends
*
* It's useful for having one terminal tab notify your other ones when
* something like a long running job completes. In the old days back
* when unix systems had multiple users, the wall command provided the
* ultimate lulz especially if it's a setuid binary with root privs.
*/
#define GETOPTS "v"
#define USAGE \
"\
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
-v increase verbosity\n\
Examples:\n\
wall.com 'hello my friends'\n\
echo hello my friends | wall.com\n\
"
int g_verbose;
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
switch (opt) {
case 'v':
g_verbose++;
break;
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
default:
write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
}
}
}
char *GetHost(void) {
static char host[254];
if (gethostname(host, sizeof(host))) {
strcpy(host, "localhost");
}
return host;
}
char *GetTime(void) {
int64_t t;
struct tm tm;
struct timespec ts;
clock_gettime(0, &ts);
localtime_r(&ts.tv_sec, &tm);
return _chomp(asctime(&tm));
}
int main(int argc, char *argv[]) {
GetOpts(argc, argv);
// create broadcast banner
// we use \e[1m so the text is strong & visually distinct
// we use \e[K so it doesn't get lost in a forest of text
// we map \n → \r\n because teletype might be in raw mode
char *msg = 0;
const char *s;
appends(&msg, "\e7"); // save cursor position
appends(&msg, "\e[H"); // goto top left corne
appends(&msg, "\e[K"); // clear line forward
appends(&msg, "\e[1m"); // bold text
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
GetHost());
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K");
// append broadcast message
if (optind < argc) {
// use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') {
appends(&msg, "\r\n\e[K");
} else {
appendw(&msg, *s & 255);
}
}
}
} else {
// otherwise use stdin as message
ssize_t i, rc;
char buf[512];
while ((rc = read(0, buf, sizeof(buf))) > 0) {
for (i = 0; i < rc; ++i) {
if (buf[i] == '\n') {
appends(&msg, "\r\n\e[K"); // clear line forward
} else {
appendw(&msg, buf[i] & 255);
}
}
}
}
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
// try to send message to all pseudoteletypewriters
for (int i = 0;; ++i) {
int fd;
char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) break;
if (g_verbose) perror(pts);
}
write(fd, msg, appendz(msg).i);
close(fd);
}
return 0;
}
+50 -9
View File
@@ -16,19 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
#define static_assert _Static_assert
#endif
#define _unassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
unreachable; \
} \
} while (0)
#ifdef __GNUC__
#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) \
do { \
({ \
if (__builtin_expect(!(x), 0)) { \
notpossible; \
} \
} while (0)
(void)0; \
})
#else
#define _npassert(x) _unassert(x)
#endif
#endif
#ifdef __GNUC__
/**
* Specifies expression being false is undefined behavior.
*
* This is a good way to tell the compiler about your invariants, which
* leads to smaller faster programs. The expression is never removed by
* the preprocessor so it's recommended that it be free of side-effects
* if you intend for it to be removed. At the same time, this guarantee
* makes this assertion useful for things like system calls, since they
* won't be removed by `NDEBUG` mode.
*
* If this assertion fails, the worst possible things can happen unless
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
* that's capable of debugging this macro.
*/
#define _unassert(x) \
({ \
if (__builtin_expect(!(x), 0)) { \
unreachable; \
} \
(void)0; \
})
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
@@ -16,5 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sig.internal.h"
bool __time_critical;
struct Signals __sig;
+37 -51
View File
@@ -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/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 2.
* @threadsafe
*/
#include "libc/thread/tls.h"
/**
* Allocates piece of memory for storing pending signal.
@@ -61,6 +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,7 +178,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
bool delivered;
switch (__sighandrvas[sig]) {
case (intptr_t)SIG_DFL:
if (__sig_isfatal(sig)) {
if (__sig_is_fatal(sig)) {
STRACE("terminating on %G", sig);
_Exitr(128 + sig);
}
@@ -194,20 +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();
}
}
@@ -216,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);
@@ -228,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;
@@ -276,7 +284,7 @@ textwindows bool __sig_check(bool restartable) {
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
struct Signal *cur, *prev, *next;
if (rva != (unsigned)(intptr_t)SIG_IGN &&
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
return;
}
if (__sig.queue) {
@@ -298,25 +306,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
__sig_unlock();
}
}
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *cur;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (cur = __sig.queue; cur; cur = cur->next) {
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
} else {
STRACE("%G is ignored", cur->sig);
}
}
__sig_unlock();
}
}
+20 -30
View File
@@ -17,49 +17,39 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.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
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
/**
* Changes signal mask for main thread.
* @return 0 on success, or -1 w/ errno
*/
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i;
uint64_t a, b;
uint64_t x, y, *mask;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
__sig_lock();
if (__tls_enabled) {
mask = &__get_tls()->tib_sigmask;
} else {
mask = &__sig.sigmask;
}
if (old) {
*old = __sig.mask;
old->__bits[0] = *mask;
old->__bits[1] = 0;
}
if (neu) {
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
if (how == SIG_BLOCK) {
__sig.mask.__bits[i] |= neu->__bits[i];
} else if (how == SIG_UNBLOCK) {
__sig.mask.__bits[i] &= ~neu->__bits[i];
} else {
__sig.mask.__bits[i] = neu->__bits[i];
}
x = *mask;
y = neu->__bits[0];
if (how == SIG_BLOCK) {
x |= y;
} else if (how == SIG_UNBLOCK) {
x &= ~y;
} else {
x = y;
}
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
x &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP) | GetSigBit(SIGABRT));
*mask = x;
}
__sig_unlock();
return 0;
} else {
return einval();
}
}
#undef GetSigBit
+43
View File
@@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.h"
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *s;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (s = __sig.queue; s; s = s->next) {
if (__sig_is_applicable(s) &&
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
sigaddset(pending, s->sig);
}
}
__sig_unlock();
}
}
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libc/calls/struct/timespec.h"
/**
* Compares two nanosecond timestamps.
* Compares nanosecond timestamps.
*/
int _timespec_cmp(struct timespec a, struct timespec b) {
int cmp;
+1
View File
@@ -26,6 +26,7 @@
* @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)) {
+7
View File
@@ -20,6 +20,13 @@
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.h"
/**
* Returns current monotonic time.
*
* This function uses a `CLOCK_MONOTONIC` clock and never fails.
*
* @see _timespec_real()
*/
struct timespec _timespec_mono(void) {
struct timespec ts;
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
+9
View File
@@ -20,6 +20,15 @@
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.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) {
struct timespec ts;
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
+38
View File
@@ -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;
}
}
+35
View File
@@ -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;
}
+26 -5
View File
@@ -20,14 +20,35 @@
#include "libc/limits.h"
/**
* Converts timespec interval to microseconds.
* Reduces `ts` from 1e-9 to 1e-6 granularity w/ ceil rounding.
*
* This function uses ceiling rounding. For example, if `ts` is one
* nanosecond, then one microsecond will be returned. Ceil rounding
* is needed by many interfaces, e.g. setitimer(), because the zero
* timestamp has a special meaning.
*
* This function also detects overflow in which case `INT64_MAX` or
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
*
* @return 64-bit scalar holding microseconds since epoch
* @see _timespec_totimeval()
*/
int64_t _timespec_tomicros(struct timespec x) {
int64_t _timespec_tomicros(struct timespec ts) {
int64_t us;
if (!__builtin_mul_overflow(x.tv_sec, 1000000ul, &us) &&
!__builtin_add_overflow(us, x.tv_nsec / 1000, &us)) {
// reduce precision from nanos to micros
if (ts.tv_nsec <= 999999000) {
ts.tv_nsec = (ts.tv_nsec + 999) / 1000;
} else {
ts.tv_nsec = 0;
if (ts.tv_sec < INT64_MAX) {
ts.tv_sec += 1;
}
}
// convert to scalar result
if (!__builtin_mul_overflow(ts.tv_sec, 1000000ul, &us) &&
!__builtin_add_overflow(us, ts.tv_nsec, &us)) {
return us;
} else if (x.tv_sec < 0) {
} else if (ts.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
+25 -5
View File
@@ -20,14 +20,34 @@
#include "libc/limits.h"
/**
* Converts timespec interval to milliseconds.
* Reduces `ts` from 1e-9 to 1e-3 granularity w/ ceil rounding.
*
* This function uses ceiling rounding. For example, if `ts` is one
* nanosecond, then one millisecond will be returned. Ceil rounding
* is needed by many interfaces, e.g. setitimer(), because the zero
* timestamp has a special meaning.
*
* This function also detects overflow in which case `INT64_MAX` or
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
*
* @return 64-bit scalar milliseconds since epoch
*/
int64_t _timespec_tomillis(struct timespec x) {
int64_t _timespec_tomillis(struct timespec ts) {
int64_t ms;
if (!__builtin_mul_overflow(x.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, x.tv_nsec / 1000000, &ms)) {
// reduce precision from nanos to millis
if (ts.tv_nsec <= 999000000) {
ts.tv_nsec = (ts.tv_nsec + 999999) / 1000000;
} else {
ts.tv_nsec = 0;
if (ts.tv_sec < INT64_MAX) {
ts.tv_sec += 1;
}
}
// convert to scalar result
if (!__builtin_mul_overflow(ts.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, ts.tv_nsec, &ms)) {
return ms;
} else if (x.tv_sec < 0) {
} else if (ts.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
+6 -1
View File
@@ -20,7 +20,12 @@
#include "libc/limits.h"
/**
* Converts timespec interval to nanoseconds.
* Converts timespec to scalar.
*
* This function will detect overflow in which case `INT64_MAX` or
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
*
* @return 64-bit integer holding nanoseconds since epoch
*/
int64_t _timespec_tonanos(struct timespec x) {
int64_t ns;
+16 -1
View File
@@ -18,6 +18,21 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timeval.h"
/**
* Reduces `ts` from 1e-9 to 1e-6 granularity w/ ceil rounding.
*
* This function uses ceiling rounding. For example, if `ts` is one
* nanosecond, then one microsecond will be returned. Ceil rounding
* is needed by many interfaces, e.g. setitimer(), because the zero
* timestamp has a special meaning.
*
* @return microseconds since epoch
* @see _timespec_tomicros()
*/
struct timeval _timespec_totimeval(struct timespec ts) {
return (struct timeval){ts.tv_sec, ts.tv_nsec / 1000};
if (ts.tv_nsec < 1000000000 - 999) {
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
} else {
return (struct timeval){ts.tv_sec + 1, 0};
}
}
+30
View File
@@ -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/timeval.h"
/**
* Compares microseconds timestamps.
*/
int _timeval_cmp(struct timeval a, struct timeval b) {
int cmp;
if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) {
cmp = (a.tv_usec > b.tv_usec) - (a.tv_usec < b.tv_usec);
}
return cmp;
}
+26
View File
@@ -0,0 +1,26 @@
/*-*- 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/timeval.h"
/**
* Checks if 𝑥 = 𝑦.
*/
bool _timeval_eq(struct timeval x, struct timeval y) {
return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}
+34
View File
@@ -0,0 +1,34 @@
/*-*- 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/timeval.h"
/**
* Returns true if timeval `x` is greater than `y`.
*/
bool _timeval_gt(struct timeval x, struct timeval y) {
if (x.tv_sec > y.tv_sec) {
return true;
}
if (x.tv_sec == y.tv_sec) {
if (x.tv_usec > y.tv_usec) {
return true;
}
}
return false;
}
+28
View File
@@ -0,0 +1,28 @@
/*-*- 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/timeval.h"
/**
* Checks if 𝑥 ≥ 𝑦.
*/
bool _timeval_gte(struct timeval x, struct timeval y) {
if (x.tv_sec > y.tv_sec) return true;
if (x.tv_sec < y.tv_sec) return false;
return x.tv_usec >= y.tv_usec;
}
+32
View File
@@ -0,0 +1,32 @@
/*-*- 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/timeval.h"
/**
* Subtracts two nanosecond timestamps.
*/
struct timeval _timeval_sub(struct timeval a, struct timeval b) {
a.tv_sec -= b.tv_sec;
if (a.tv_usec < b.tv_usec) {
a.tv_usec += 1000000;
a.tv_sec--;
}
a.tv_usec -= b.tv_usec;
return a;
}
+3
View File
@@ -18,6 +18,9 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timeval.h"
/**
* Coerces `tv` from 1e-6 to 1e-9 granularity.
*/
struct timespec _timeval_totimespec(struct timeval tv) {
return (struct timespec){tv.tv_sec, tv.tv_usec * 1000};
}
+6 -1
View File
@@ -22,9 +22,14 @@
/**
* Checks if effective user can access path in particular ways.
*
* This is equivalent to saying:
*
* faccessat(AT_FDCWD, path, mode, 0);
*
* @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK
* @return 0 if ok, or -1 and sets errno
* @return 0 if ok, or -1 w/ errno
* @see faccessat() for further documentation
* @asyncsignalsafe
*/
int access(const char *path, int mode) {
+1 -3
View File
@@ -32,12 +32,10 @@
* @asyncsignalsafe
*/
unsigned alarm(unsigned seconds) {
int rc;
struct itimerval it;
bzero(&it, sizeof(it));
it.it_value.tv_sec = seconds;
rc = setitimer(ITIMER_REAL, &it, &it);
assert(rc != -1);
_npassert(!setitimer(ITIMER_REAL, &it, &it));
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
return 0;
} else {
+6 -1
View File
@@ -1,7 +1,8 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
#include "libc/intrin/asmflag.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/intrin/asmflag.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@@ -14,6 +15,10 @@ forceinline bool __asan_is_valid_timespec(const struct timespec *ts) {
return zf;
}
forceinline bool __asan_is_valid_timeval(const struct timeval *tv) {
return __asan_is_valid_timespec((const struct timespec *)tv);
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */
+14 -12
View File
@@ -84,7 +84,8 @@ int execv(const char *, char *const[]);
int execve(const char *, char *const[], char *const[]);
int execvp(const char *, char *const[]);
int execvpe(const char *, char *const[], char *const[]);
int faccessat(int, const char *, int, uint32_t);
int fexecve(int, char *const[], char *const[]);
int faccessat(int, const char *, int, int);
int fadvise(int, uint64_t, uint64_t, int);
int fchdir(int);
int fchmod(int, uint32_t) dontthrow;
@@ -127,8 +128,9 @@ int linkat(int, const char *, int, const char *, int);
int madvise(void *, uint64_t, int);
int memfd_create(const char *, unsigned int);
int mincore(void *, size_t, unsigned char *);
int mkdir(const char *, uint32_t);
int mkdirat(int, const char *, uint32_t);
int mkdir(const char *, unsigned);
int mkdirat(int, const char *, unsigned);
int makedirs(const char *, unsigned);
int mkfifo(const char *, uint32_t);
int mkfifoat(int, const char *, uint32_t);
int mknod(const char *, uint32_t, uint64_t);
@@ -147,7 +149,7 @@ int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_fadvise(int, int64_t, int64_t, int);
int posix_madvise(void *, uint64_t, int);
int prctl(int, ...);
int raise(int);
@@ -161,10 +163,10 @@ int sched_yield(void);
int seccomp(unsigned, unsigned, void *);
int setegid(uint32_t);
int seteuid(uint32_t);
int setfsgid(int);
int setfsuid(int);
int setgid(int);
int setgroups(size_t size, const uint32_t list[]);
int setfsgid(unsigned);
int setfsuid(unsigned);
int setgid(unsigned);
int setgroups(size_t, const uint32_t[]);
int setpgid(int, int);
int setpgrp(void);
int setpriority(int, unsigned, int);
@@ -173,7 +175,7 @@ int setresgid(uint32_t, uint32_t, uint32_t);
int setresuid(uint32_t, uint32_t, uint32_t);
int setreuid(uint32_t, uint32_t);
int setsid(void);
int setuid(int);
int setuid(unsigned);
int sigignore(int);
int siginterrupt(int, int);
int symlink(const char *, const char *);
@@ -186,9 +188,9 @@ int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, uint32_t);
int truncate(const char *, uint64_t);
int truncate(const char *, int64_t);
int ttyname_r(int, char *, size_t);
int umask(int);
unsigned umask(unsigned);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
@@ -203,7 +205,7 @@ long ptrace(int, ...);
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t getfiledescriptorsize(int);
ssize_t lseek(int, int64_t, unsigned);
ssize_t lseek(int, int64_t, int);
ssize_t pread(int, void *, size_t, int64_t);
ssize_t pwrite(int, const void *, size_t, int64_t);
ssize_t read(int, void *, size_t);
+7
View File
@@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use asan because:
# siginfo_t memory is owned by kernels
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
OVERRIDE_COPTS += \
-ffreestanding \
-fno-sanitize=address
# we can't use asan because:
# ucontext_t memory is owned by xnu kernel
o/$(MODE)/libc/calls/sigenter-xnu.o: private \
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libc/calls/termios.h"
#include "libc/sysv/errfuns.h"
int cfsetispeed(struct termios *t, int speed) {
int cfsetispeed(struct termios *t, unsigned speed) {
if (speed) {
if (CBAUD) {
if (speed & ~CBAUD) return einval();
+1 -1
View File
@@ -20,7 +20,7 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int cfsetospeed(struct termios *t, int speed) {
int cfsetospeed(struct termios *t, unsigned speed) {
if (CBAUD) {
if (!(speed & ~CBAUD)) {
t->c_cflag &= ~CBAUD;
+3 -1
View File
@@ -16,11 +16,12 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/**
@@ -34,6 +35,7 @@
*/
int chdir(const char *path) {
int rc;
GetProgramExecutableName(); // XXX: ugly workaround
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
rc = efault();
} else if (!IsWindows()) {
+28 -2
View File
@@ -17,17 +17,43 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Changes root directory.
*
* Please consider using unveil() instead of chroot(). If you use this
* system call then consider using both chdir() and closefrom() before
* calling this function. Otherwise there's a small risk that fchdir()
* could be used to escape the chroot() environment. Cosmopolitan Libc
* focuses on static binaries which make chroot() infinitely easier to
* use since you don't need to construct an entire userspace each time
* however unveil() is still better to use on modern Linux and OpenBSD
* because it doesn't require root privileges.
*
* @param path shall become the new root directory
* @return 0 on success, or -1 w/ errno
* @raise EACCES if we don't have permission to search a component of `path`
* @raise ENOTDIR if a directory component in `path` exists as non-directory
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
* @raise EPERM if not root or pledge() is in play
* @raise EIO if a low-level i/o error occurred
* @raise EFAULT if `path` is bad memory
* @raise ENOENT if `path` doesn't exist
* @raise ENOSYS on Windows
*/
int chroot(const char *path) {
int rc;
rc = sys_chroot(path);
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
rc = efault();
} else {
rc = sys_chroot(path);
}
STRACE("chroot(%s) → %d% m", path, rc);
return rc;
}
+7 -1
View File
@@ -17,10 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
@@ -49,6 +49,12 @@ static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
/**
* Returns granularity of clock.
*
* @return 0 on success, or -1 w/ errno
* @error EPERM if pledge() is in play without stdio promise
* @error EINVAL if `clock` isn't supported on this system
* @error EFAULT if `ts` points to bad memory
* @threadsafe
*/
int clock_getres(int clock, struct timespec *ts) {
int rc;
+23 -4
View File
@@ -20,7 +20,6 @@
#include "libc/calls/asan.internal.h"
#include "libc/calls/clock_gettime.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/syscall_support-sysv.internal.h"
@@ -30,9 +29,11 @@
#include "libc/intrin/asmflag.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* Returns nanosecond time.
@@ -48,12 +49,30 @@
* __clock_gettime l: 35𝑐 11𝑛𝑠
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
*
* @param clock can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
* @param clock can be one of:
* - `CLOCK_REALTIME`: universally supported
* - `CLOCK_REALTIME_FAST`: ditto but faster on freebsd
* - `CLOCK_MONOTONIC`: universally supported
* - `CLOCK_MONOTONIC_FAST`: ditto but faster on freebsd
* - `CLOCK_MONOTONIC_RAW`: nearly universally supported
* - `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd
* - `CLOCK_THREAD_CPUTIME_ID`: linux and bsd
* - `CLOCK_REALTIME_COARSE`: : linux and openbsd
* - `CLOCK_MONOTONIC_COARSE`: linux
* - `CLOCK_PROF`: linux and netbsd
* - `CLOCK_BOOTTIME`: linux and openbsd
* - `CLOCK_REALTIME_ALARM`: linux-only
* - `CLOCK_BOOTTIME_ALARM`: linux-only
* - `CLOCK_TAI`: linux-only
* @param ts is where the result is stored
* @return 0 on success, or -1 w/ errno
* @error EINVAL if clock isn't supported on this system
* @error EPERM if pledge() is in play without stdio promise
* @error EINVAL if `clock` isn't supported on this system
* @error EFAULT if `ts` points to bad memory
* @see strftime(), gettimeofday()
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
int clock_gettime(int clock, struct timespec *ts) {
int rc;
@@ -65,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
rc = __clock_gettime(clock, ts);
}
#if SYSDEBUG
if (!__time_critical) {
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
DescribeTimespec(rc, ts), rc);
}
+57
View File
@@ -0,0 +1,57 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_clock_nanosleep_nt(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
struct timespec now, abs;
if (flags & TIMER_ABSTIME) {
abs = *req;
for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1;
if (_timespec_gte(now, abs)) return 0;
if (_check_interrupts(false, g_fds.p)) return eintr();
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
false);
}
} else {
if (sys_clock_gettime_nt(clock, &now)) return -1;
abs = _timespec_add(now, *req);
for (;;) {
sys_clock_gettime_nt(clock, &now);
if (_timespec_gte(now, abs)) return 0;
if (_check_interrupts(false, g_fds.p)) {
if (rem) *rem = _timespec_sub(abs, now);
return eintr();
}
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
false);
}
}
}
@@ -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 │
@@ -18,19 +18,28 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_utimes_nt(const char *path, const struct timeval tv[2]) {
struct timespec ts[2];
if (tv) {
ts[0].tv_sec = tv[0].tv_sec;
ts[0].tv_nsec = tv[0].tv_usec * 1000;
ts[1].tv_sec = tv[1].tv_sec;
ts[1].tv_nsec = tv[1].tv_usec * 1000;
return sys_utimensat_nt(AT_FDCWD, path, ts, 0);
int sys_clock_nanosleep_openbsd(int clock, int flags,
const struct timespec *req,
struct timespec *rem) {
int res;
struct timespec now, rel;
if (clock == CLOCK_REALTIME) {
if (!flags) {
res = sys_nanosleep(req, rem);
} else {
sys_clock_gettime(clock, &now);
if (_timespec_gt(*req, now)) {
rel = _timespec_sub(*req, now);
res = sys_nanosleep(&rel, 0);
} else {
res = 0;
}
}
} else {
return sys_utimensat_nt(AT_FDCWD, path, NULL, 0);
res = enotsup();
}
return res;
}
@@ -16,30 +16,34 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/fmt/conv.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
// we don't want instrumentation because:
// - nanosleep() depends on this and ftrace can take microsecs
/**
* Converts `struct timespec` to `struct timeval`.
*
* This divides ts.tv_nsec by 1000 with upward rounding and overflow
* handling. Your ts.tv_nsec must be on the interval `[0,1000000000)`
* otherwise `{-1, -1}` is returned.
*
* @return converted timeval whose tv_usec will be -1 on error
*/
noinstrument struct timeval _timespec2timeval(struct timespec ts) {
if (0 <= ts.tv_nsec && ts.tv_nsec < 1000000000) {
if (0 <= ts.tv_nsec && ts.tv_nsec < 1000000000 - 999) {
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int res;
struct timeval now, abs, rel;
if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) {
abs = _timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0);
if (_timeval_gt(abs, now)) {
rel = _timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel);
} else {
res = 0;
}
} else {
return (struct timeval){ts.tv_sec + 1, 0};
res = sys_nanosleep_xnu(req, rem);
}
} else {
return (struct timeval){-1, -1};
res = enotsup();
}
return res;
}
+124
View File
@@ -0,0 +1,124 @@
/*-*- 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/asan.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* Sleeps for particular amount of time.
*
* Here's how you could sleep for one second:
*
* clock_nanosleep(0, 0, &(struct timespec){1}, 0);
*
* Your sleep will be interrupted automatically if you do something like
* press ctrl-c during the wait. That's an `EINTR` error and it lets you
* immediately react to status changes. This is always the case, even if
* you're using `SA_RESTART` since this is a `@norestart` system call.
*
* void OnCtrlC(int sig) {} // EINTR only happens after delivery
* signal(SIGINT, OnCtrlC); // do delivery rather than kill proc
* printf("save me from sleeping forever by pressing ctrl-c\n");
* clock_nanosleep(0, 0, &(struct timespec){INT_MAX}, 0);
* printf("you're my hero\n");
*
* If you want to perform an uninterruptible sleep without having to use
* sigprocmask() to block all signals then this function provides a good
* solution to that problem. For example:
*
* struct timespec rel, now, abs;
* clock_gettime(CLOCK_REALTIME, &now);
* rel = _timespec_frommillis(100);
* abs = _timespec_add(now, rel);
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
*
* will accurately spin on `EINTR` errors. That way you're not impeding
* signal delivery and you're not losing precision on your wait timeout.
* This function has first-class support on Linux, FreeBSD, and NetBSD;
* on OpenBSD it's good; on XNU it's bad; and on Windows it's ugly.
*
* @param clock should be `CLOCK_REALTIME` and you may consult the docs
* of your preferred platforms to see what other clocks might work
* @param flags can be 0 for relative and `TIMER_ABSTIME` for absolute
* @param req can be a relative or absolute time, depending on `flags`
* @param rem shall be updated with the remainder of unslept time when
* (1) it's non-null; (2) `flags` is 0; and (3) -1 w/ `EINTR` is
* returned; if this function returns 0 then `rem` is undefined;
* if flags is `TIMER_ABSTIME` then `rem` is ignored
* @return 0 on success, or errno on error
* @raise EINTR when a signal got delivered while we were waiting
* @raise ENOTSUP if `clock` is known but we can't use it here
* @raise EFAULT if `req` or null or bad memory was passed
* @raise EINVAL if `clock` is unknown to current platform
* @raise EINVAL if `flags` has an unrecognized value
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
* @raise ENOSYS on bare metal
* @returnserrno
* @norestart
*/
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int rc, e = errno;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
rc = efault();
} else if (clock == 127 || //
(flags & ~TIMER_ABSTIME) || //
req->tv_sec < 0 || //
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = einval();
} else if (IsLinux() || IsFreebsd() || IsNetbsd()) {
rc = sys_clock_nanosleep(clock, flags, req, rem);
} else if (IsXnu()) {
rc = sys_clock_nanosleep_xnu(clock, flags, req, rem);
} else if (IsOpenbsd()) {
rc = sys_clock_nanosleep_openbsd(clock, flags, req, rem);
} else if (IsMetal()) {
rc = enosys();
} else {
rc = sys_clock_nanosleep_nt(clock, flags, req, rem);
}
if (rc == -1) {
rc = errno;
errno = e;
}
#if SYSDEBUG
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req),
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
}
#endif
return rc;
}
+17 -9
View File
@@ -32,17 +32,25 @@
/**
* Closes file descriptor.
*
* This function may be used for file descriptors returned by functions
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
* This function releases resources returned by functions such as:
*
* This function should never be called twice for the same file
* descriptor, regardless of whether or not an error happened. However
* that doesn't mean the error should be ignored.
* - openat()
* - socket()
* - accept()
* - epoll_create()
* - landlock_create_ruleset()
*
* This function should never be reattempted if an error is returned;
* however, that doesn't mean the error should be ignored. This goes
* against the conventional wisdom of looping on `EINTR`.
*
* @return 0 on success, or -1 w/ errno
* @error EINTR means a signal was received while closing in which case
* close() does not need to be called again, since the fd will close
* in the background
* @raise EINTR if signal was delivered; do *not* retry
* @raise EBADF if `fd` is negative or not open; however, an exception
* is made by Cosmopolitan Libc for `close(-1)` which returns zero
* and does nothing, in order to assist with code that may wish to
* close the same resource multiple times without dirtying `errno`
* @raise EIO if a low-level i/o error occurred
* @asyncsignalsafe
* @vforksafe
*/
@@ -51,7 +59,7 @@ int close(int fd) {
if (fd == -1) {
rc = 0;
} else if (fd < 0) {
rc = einval();
rc = ebadf();
} else {
// for performance reasons we want to avoid holding __fds_lock()
// while sys_close() is happening. this leaves the kernel / libc
+13 -11
View File
@@ -35,27 +35,29 @@
* }
*
* @return 0 on success, or -1 w/ errno
* @error EBADF if `first` is negative
* @error EBADF on OpenBSD if `first` is greater than highest fd
* @error EINVAL if flags are bad or first is greater than last
* @error EMFILE if a weird race condition happens on Linux
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
* @error EINTR possibly on OpenBSD
* @error ENOMEM on Linux maybe
* @raise EBADF if `first` is negative
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
* @raise EBADF on OpenBSD if `first` is greater than highest fd
* @raise EINVAL if flags are bad or first is greater than last
* @raise EMFILE if a weird race condition happens on Linux
* @raise EINTR possibly on OpenBSD
* @raise ENOMEM on Linux maybe
*/
int closefrom(int first) {
int rc, err;
if (IsNetbsd() || IsWindows() || IsMetal()) {
rc = enosys();
} else if (first < 0) {
if (first < 0) {
// consistent with openbsd
// freebsd allows this but it's dangerous
// necessary on linux due to type signature
rc = ebadf();
} else if (IsFreebsd() || IsOpenbsd()) {
rc = sys_closefrom(first);
} else if (IsLinux()) {
rc = sys_close_range(first, 0xffffffffu, 0);
} else if (IsNetbsd()) {
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
} else {
rc = sys_closefrom(first);
rc = enosys();
}
STRACE("closefrom(%d) → %d% m", first, rc);
return rc;
+4
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
@@ -79,6 +80,7 @@ static void copy_file_range_init(void) {
* @raise EXDEV if source and destination are on different filesystems
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise EPERM if `fdout` refers to an immutable file on Linux
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
* @raise EINVAL if ranges overlap or `flags` is non-zero
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
* @raise EFAULT if one of the pointers memory is bad
@@ -104,6 +106,8 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
(opt_in_out_outoffset &&
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
rc = efault();
} else if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip)) {
rc = enotsup();
} else {
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
opt_in_out_outoffset, uptobytes, flags);
+11 -10
View File
@@ -21,20 +21,21 @@
#include "libc/sysv/consts/o.h"
/**
* Creates new file, returning open()'d file descriptor.
* Creates file.
*
* This function is shorthand for:
* This is equivalent to saying:
*
* open(file, O_CREAT | O_WRONLY | O_TRUNC, mode)
* int fd = openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
*
* @param file is a UTF-8 string, which is truncated if it exists
* @param mode is an octal user/group/other permission, e.g. 0755
* @return a number registered with the system to track the open file,
* which must be stored using a 64-bit type in order to support both
* System V and Windows, and must be closed later on using close()
* @see open(), touch()
* @param file specifies filesystem path to create
* @param mode is octal bits, e.g. 0644 usually
* @return file descriptor, or -1 w/ errno
* @see openat() for further documentation
* @asyncsignalsafe
* @restartable
* @threadsafe
* @vforksafe
*/
dontdiscard int creat(const char *file, uint32_t mode) {
int creat(const char *file, uint32_t mode) {
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
+4 -3
View File
@@ -32,15 +32,16 @@
*
* @param fd remains open afterwards
* @return some arbitrary new number for fd
* @raise EOPNOTSUPP if zipos file
* @raise EBADF if fd isn't open
* @raise EPERM if pledge() is in play without stdio
* @raise ENOTSUP if `fd` is a zip file descriptor
* @raise EBADF if `fd` is negative or not open
* @asyncsignalsafe
* @vforksafe
*/
int dup(int fd) {
int rc;
if (__isfdkind(fd, kFdZip)) {
rc = eopnotsupp();
rc = enotsup();
} else if (!IsWindows()) {
rc = sys_dup(fd);
} else {
+7 -4
View File
@@ -18,10 +18,10 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
@@ -38,16 +38,19 @@
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @return new file descriptor, or -1 w/ errno
* @raise EBADF is oldfd isn't open
* @raise EBADF is newfd negative or too big
* @raise EPERM if pledge() is in play without stdio
* @raise EMFILE if `RLIMIT_NOFILE` has been reached
* @raise ENOTSUP if `oldfd` is on zip file system
* @raise EINTR if a signal handler was called
* @raise EBADF is `newfd` negative or too big
* @raise EBADF is `oldfd` isn't open
* @asyncsignalsafe
* @vforksafe
*/
int dup2(int oldfd, int newfd) {
int rc;
if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
rc = enotsup();
} else if (!IsWindows()) {
rc = sys_dup2(oldfd, newfd);
} else if (newfd < 0) {
+7 -5
View File
@@ -38,11 +38,13 @@
* @param flags may have O_CLOEXEC which is needed to preserve the
* close-on-execve() state after file descriptor duplication
* @return newfd on success, or -1 w/ errno
* @raise EINVAL if flags has unsupported bits
* @raise EINVAL if newfd equals oldfd
* @raise EBADF is oldfd isn't open
* @raise EBADF is newfd negative or too big
* @raise ENOTSUP if `oldfd` is a zip file descriptor
* @raise EPERM if pledge() is in play without stdio
* @raise EINVAL if `flags` has unsupported bits
* @raise EINTR if a signal handler was called
* @raise EBADF is `newfd` negative or too big
* @raise EINVAL if `newfd` equals oldfd
* @raise EBADF is `oldfd` isn't open
* @see dup(), dup2()
*/
int dup3(int oldfd, int newfd, int flags) {
@@ -52,7 +54,7 @@ int dup3(int oldfd, int newfd, int flags) {
} else if (oldfd < 0 || newfd < 0) {
rc = ebadf();
} else if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
rc = enotsup();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
} else {
+1 -1
View File
@@ -99,7 +99,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
startinfo.hStdError = __getfdhandleactual(2);
// spawn the process
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
if (rc == -1) {
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
__imp_ExitProcess(6543);
+4
View File
@@ -35,6 +35,10 @@
/**
* Replaces current process with program.
*
* On Windows, `argv` and `envp` can't contain binary strings. They need
* to be valid UTF-8 in order to round-trip the WIN32 API, without being
* corrupted.
*
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specify program arguments
+22 -12
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
@@ -35,33 +36,42 @@
* @param dirfd is normally AT_FDCWD but if it's an open directory and
* file is a relative path, then file is opened relative to dirfd
* @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
* @note on Linux flags is only supported on Linux 5.8+
* @param amode can be `R_OK`, `W_OK`, `X_OK`, or `F_OK`
* @param flags can have `AT_EACCESS` and/or `AT_SYMLINK_NOFOLLOW`
* @return 0 if ok, or -1 and sets errno
* @raise EINVAL if `mode` has bad value
* @raise EPERM if pledge() is in play without rpath promise
* @raise EACCES if access for requested `mode` would be denied
* @raise ENOTDIR if a directory component in `path` exists as non-directory
* @raise ENOENT if component of `path` doesn't exist or `path` is empty
* @raise ENOTSUP if `path` is a zip file and `dirfd` isn't `AT_FDCWD`
* @note on Linux `flags` is only supported on Linux 5.8+
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
int faccessat(int dirfd, const char *path, int amode, int flags) {
int e, rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
struct ZiposUri zipname;
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
_weaken(__zipos_notat)(dirfd, path) == -1) {
rc = -1; /* TODO(jart): implement me */
} else if (__isfdkind(dirfd, kFdZip)) {
rc = enotsup();
} else if (_weaken(__zipos_open) &&
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
rc = _weaken(__zipos_access)(&zipname, amode);
} else if (!IsWindows()) {
e = errno;
if (!flags) goto NoFlags;
if ((rc = sys_faccessat2(dirfd, path, mode, flags)) == -1) {
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
if (errno == ENOSYS) {
errno = e;
NoFlags:
rc = sys_faccessat(dirfd, path, mode, flags);
rc = sys_faccessat(dirfd, path, amode, flags);
}
}
} else {
rc = sys_faccessat_nt(dirfd, path, mode, flags);
rc = sys_faccessat_nt(dirfd, path, amode, flags);
}
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(dirfd), path,
mode, flags, rc);
amode, flags, rc);
return rc;
}
+2 -1
View File
@@ -37,6 +37,7 @@
* @param path must exist
* @param mode contains octal flags (base 8)
* @param flags can have `AT_SYMLINK_NOFOLLOW`
* @raise ENOTSUP if `dirfd` or `path` use zip file system
* @errors ENOENT, ENOTDIR, ENOSYS
* @asyncsignalsafe
* @see fchmod()
@@ -47,7 +48,7 @@ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {
rc = eopnotsupp();
rc = enotsup();
} else if (!IsWindows()) {
rc = sys_fchmodat(dirfd, path, mode, flags);
} else {
+2 -1
View File
@@ -34,6 +34,7 @@
* @param gid is group id, or -1 to not change
* @param flags can have AT_SYMLINK_NOFOLLOW, etc.
* @return 0 on success, or -1 w/ errno
* @raise ENOTSUP if `dirfd` or `path` use zip file system
* @see chown(), lchown() for shorthand notation
* @see /etc/passwd for user ids
* @see /etc/group for group ids
@@ -46,7 +47,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {
STRACE("zipos fchownat not supported yet");
rc = enotsup();
} else {
rc = sys_fchownat(dirfd, path, uid, gid, flags);
}
+1 -7
View File
@@ -37,8 +37,6 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
bool __force_sqlite_to_work_until_we_can_fix_it;
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
@@ -110,11 +108,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
ok = true;
}
}
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
return 0;
} else {
return -1;
}
return ok ? 0 : -1;
}
if (l->l_type == F_UNLCK) {
+90 -8
View File
@@ -18,11 +18,15 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/calls/struct/flock.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@@ -44,9 +48,49 @@
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.
*
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
* @param fd is the file descriptor
* @param cmd can be one of:
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
* - `F_GETFL` returns file descriptor status flags
* - `F_SETFL` sets file descriptor status flags
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
* - `F_SETLK` for record locking where `arg` is `struct flock`
* - `F_SETLKW` ditto but waits (i.e. blocks) for lock
* - `F_GETLK` to retrieve information about a record lock
* - `F_OFD_SETLK` for better locks on Linux and XNU
* - `F_OFD_SETLKW` for better locks on Linux and XNU
* - `F_OFD_GETLK` for better locks on Linux and XNU
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
* - `F_MAXFD` on NetBSD to get max open file descriptor
* - `F_NOCACHE` on MacOS to toggle data caching
* - `F_GETPIPE_SZ` on Linux to get pipe size
* - `F_SETPIPE_SZ` on Linux to set pipe size
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` on Linux
* - `DN_ACCESS` for file access
* - `DN_MODIFY` for file modifications
* - `DN_CREATE` for file creations
* - `DN_DELETE` for file deletions
* - `DN_RENAME` for file renames
* - `DN_ATTRIB` for file attribute changes
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
* @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno
* @raise EBADF if `fd` isn't a valid open file descriptor
* @raise EINVAL if `cmd` is unknown or unsupported by os
* @raise EINVAL if `cmd` is invalid or unsupported by os
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
* `RLIMIT_NOFILE` would be exceeded
* @asyncsignalsafe
* @restartable
*/
@@ -54,20 +98,58 @@ int fcntl(int fd, int cmd, ...) {
int rc;
va_list va;
uintptr_t arg;
va_start(va, cmd);
arg = va_arg(va, uintptr_t);
va_end(va);
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
if (cmd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
}
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
rc = einval();
}
} else {
rc = einval();
rc = ebadf();
}
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
#ifdef SYSDEBUG
if (cmd == F_GETFD || //
cmd == F_GETOWN || //
cmd == F_FULLFSYNC || //
cmd == F_BARRIERFSYNC || //
cmd == F_MAXFD) {
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
} else if (cmd == F_GETFL) {
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
DescribeOpenFlags(rc));
} else if (cmd == F_SETLK || //
cmd == F_SETLKW || //
cmd == F_GETLK || //
((SupportsLinux() || SupportsXnu()) && //
cmd != -1 && //
(cmd == F_OFD_SETLK || //
cmd == F_OFD_SETLKW || //
cmd == F_OFD_GETLK))) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeFlock(cmd, (struct flock *)arg), rc);
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
cmd == F_GETPATH) {
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
!rc ? (const char *)arg : "n/a", rc);
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeDnotifyFlags(arg), rc);
} else {
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
}
#endif
return rc;
}
+5 -3
View File
@@ -17,10 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
@@ -33,6 +34,7 @@
*/
int fdatasync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fdatasync(fd);
@@ -41,8 +43,8 @@ int fdatasync(int fd) {
}
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fdatasync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
}
return rc;
}
+78
View File
@@ -0,0 +1,78 @@
/*-*- 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/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int sys_fexecve(int, char *const[], char *const[]);
/**
* Executes binary executable at file descriptor.
*
* This is only supported on Linux and FreeBSD. APE binaries currently
* aren't supported.
*
* @param fd is opened executable and current file position is ignored
* @return doesn't return on success, otherwise -1 w/ errno
* @raise ENOEXEC if file at `fd` isn't an assimilated ELF executable
* @raise ENOSYS on Windows, XNU, OpenBSD, NetBSD, and Metal
*/
int fexecve(int fd, char *const argv[], char *const envp[]) {
int rc;
size_t i;
if (!argv || !envp ||
(IsAsan() &&
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
rc = efault();
} else {
#ifdef SYSDEBUG
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "fexecve(%d, {", fd);
for (i = 0; argv[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", argv[i]);
}
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", envp[i]);
}
kprintf("})\n");
}
#endif
if (IsLinux()) {
char path[14 + 12];
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);
rc = __sys_execve(path, argv, envp);
} else if (IsFreebsd()) {
rc = sys_fexecve(fd, argv, envp);
} else {
rc = enosys();
}
}
STRACE("fexecve(%d) failed %d% m", fd, rc);
return rc;
}
+5 -3
View File
@@ -17,10 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
@@ -33,6 +34,7 @@
*/
int fsync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fsync(fd);
@@ -41,8 +43,8 @@ int fsync(int fd) {
}
STRACE("fysnc(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fsync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fsync_fake(%d) → %d% m", fd, rc);
}
return rc;
}
+11 -2
View File
@@ -16,9 +16,12 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/enum/filemovemethod.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_ftruncate_nt(int64_t handle, uint64_t length) {
@@ -28,7 +31,13 @@ textwindows int sys_ftruncate_nt(int64_t handle, uint64_t length) {
if ((ok = SetFilePointerEx(handle, 0, &tell, kNtFileCurrent))) {
ok = SetFilePointerEx(handle, length, NULL, kNtFileBegin) &&
SetEndOfFile(handle);
SetFilePointerEx(handle, tell, NULL, kNtFileBegin);
_npassert(SetFilePointerEx(handle, tell, NULL, kNtFileBegin));
}
if (ok) {
return 0;
} else if (GetLastError() == kNtErrorAccessDenied) {
return einval(); // ftruncate() doesn't raise EACCES
} else {
return __winerr();
}
return ok ? 0 : __winerr();
}
+42 -8
View File
@@ -18,31 +18,65 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Changes size of file.
* Changes size of open file.
*
* If the file size is increased, the extended area shall appear as if
* it were zero-filled. If your file size is decreased, the extra data
* shall be lost.
*
* This function never changes the file position. This is true even if
* ftruncate() causes the position to become beyond the end of file in
* which case, the rules described in the lseek() documentation apply.
*
* Some operating systems implement an optimization, where `length` is
* treated as a logical size and the requested physical space won't be
* allocated until non-zero values get written into it. Our tests show
* this happens on Linux (usually with 4096 byte granularity), FreeBSD
* (which favors 512-byte granularity), and MacOS (prefers 4096 bytes)
* however Windows, OpenBSD, and NetBSD always reserve physical space.
* This may be inspected using fstat() and consulting stat::st_blocks.
*
* @param fd must be open for writing
* @param length may be greater than current current file size, in which
* case System V guarantees it'll be zero'd but Windows NT doesn't;
* since the prior extends logically and the latter physically
* @param length may be greater than current current file size
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `length` is negative
* @raise EINTR if signal was delivered instead
* @raise EIO if a low-level i/o error happened
* @raise EFBIG or EINVAL if `length` is too huge
* @raise ENOTSUP if `fd` is a zip file descriptor
* @raise EBADF if `fd` isn't an open file descriptor
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
* @raise EINVAL if `fd` wasn't opened in a writeable mode
* @raise ENOSYS on bare metal
* @see truncate()
* @asyncsignalsafe
* @threadsafe
*/
int ftruncate(int fd, int64_t length) {
int rc;
if (fd < 0) {
rc = einval();
rc = ebadf();
} else if (__isfdkind(fd, kFdZip)) {
rc = enotsup();
} else if (IsMetal()) {
rc = enosys();
} else if (!IsWindows()) {
rc = sys_ftruncate(fd, length, length);
} else {
if (fd >= g_fds.n) rc = ebadf();
if (IsNetbsd() && rc == -1 && errno == ENOSPC) {
errno = EFBIG; // POSIX doesn't specify ENOSPC for ftruncate()
}
} else if (__isfdopen(fd)) {
rc = sys_ftruncate_nt(g_fds.p[fd].handle, length);
} else {
rc = ebadf();
}
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
return rc;
+25 -5
View File
@@ -16,16 +16,36 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Sets atime/mtime on file descriptor.
* Changes access/modified time on open file, the modern way.
*
* This function is the same as `utimensat(fd, 0, ts, 0)`.
* XNU only has microsecond (1e-6) accuracy. Windows only has
* hectonanosecond (1e-7) accuracy. RHEL5 (Linux c. 2007) doesn't
* support this system call.
*
* @param ts is atime/mtime, or null for current time
* @raise ENOSYS on RHEL5
* @param fd is file descriptor of file whose timestamps will change
* @param ts is {access, modified} timestamps, or null for current time
* @return 0 on success, or -1 w/ errno
* @raise ENOTSUP if `fd` is on the zip filesystem
* @raise EINVAL if `flags` had an unrecognized value
* @raise EPERM if pledge() is in play without `fattr` promise
* @raise EINVAL if `ts` specifies a nanosecond value that's out of range
* @raise EBADF if `fd` isn't an open file descriptor
* @raise EFAULT if `ts` memory was invalid
* @raise ENOSYS on RHEL5 or bare metal
* @asyncsignalsafe
* @threadsafe
*/
int futimens(int fd, const struct timespec ts[2]) {
return utimensat(fd, 0, ts, 0);
int rc;
rc = __utimens(fd, 0, ts, 0);
STRACE("futimens(%d, {%s, %s}) → %d% m", fd, DescribeTimespec(0, ts),
DescribeTimespec(0, ts ? ts + 1 : 0), rc);
return rc;
}
+25 -5
View File
@@ -16,25 +16,45 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Sets atime/mtime on file descriptor.
*
* @param ts is atime/mtime, or null for current time
* @note better than microsecond precision on most platforms
* @see fstat() for reading timestamps
* @return 0 on success, or -1 w/ errno
* @raise ENOTSUP if `fd` is on zip filesystem
* @raise EBADF if `fd` isn't an open file descriptor
* @raise EPERM if pledge() is in play without `fattr` promise
* @raise EINVAL if `tv` specifies a microsecond value that's out of range
* @raise ENOSYS on RHEL5 or bare metal
* @see futimens() for modern version
* @asyncsignalsafe
* @threadsafe
*/
int futimes(int fd, const struct timeval tv[hasatleast 2]) {
int futimes(int fd, const struct timeval tv[2]) {
int rc;
struct timespec ts[2];
if (tv) {
ts[0].tv_sec = tv[0].tv_sec;
ts[0].tv_nsec = tv[0].tv_usec * 1000;
ts[1].tv_sec = tv[1].tv_sec;
ts[1].tv_nsec = tv[1].tv_usec * 1000;
return utimensat(fd, NULL, ts, 0);
rc = __utimens(fd, 0, ts, 0);
} else {
return utimensat(fd, NULL, NULL, 0);
rc = __utimens(fd, 0, 0, 0);
}
STRACE("futimes(%d, {%s, %s}) → %d% m", fd, DescribeTimeval(0, tv),
DescribeTimeval(0, tv ? tv + 1 : 0), rc);
return rc;
}
-2
View File
@@ -19,7 +19,5 @@
#include "libc/calls/state.internal.h"
#include "libc/thread/thread.h"
// TODO(jart): These should be _Thread_local but doing that currently
// causes a regression with runitd.com on Windows.
unsigned __sighandrvas[NSIG];
unsigned __sighandflags[NSIG];
+14 -8
View File
@@ -34,7 +34,7 @@
#define HW_NCPUONLINE_NETBSD 16
#define ALL_PROCESSOR_GROUPS 0xffff
static unsigned GetCpuCountLinux(void) {
static unsigned _getcpucount_linux(void) {
cpu_set_t s = {0};
if (sys_sched_getaffinity(0, sizeof(s), &s) != -1) {
return CPU_COUNT(&s);
@@ -43,7 +43,7 @@ static unsigned GetCpuCountLinux(void) {
}
}
static unsigned GetCpuCountBsd(void) {
static unsigned _getcpucount_bsd(void) {
size_t n;
int c, cmd[2];
n = sizeof(c);
@@ -62,12 +62,12 @@ static unsigned GetCpuCountBsd(void) {
}
}
static unsigned GetCpuCountImpl(void) {
static unsigned _getcpucount_impl(void) {
if (!IsWindows()) {
if (!IsBsd()) {
return GetCpuCountLinux();
return _getcpucount_linux();
} else {
return GetCpuCountBsd();
return _getcpucount_bsd();
}
} else {
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
@@ -77,18 +77,24 @@ static unsigned GetCpuCountImpl(void) {
static int g_cpucount;
// precompute because process affinity on linux may change later
__attribute__((__constructor__)) static void init(void) {
g_cpucount = GetCpuCountImpl();
__attribute__((__constructor__)) static void _getcpucount_init(void) {
g_cpucount = _getcpucount_impl();
}
/**
* Returns number of CPUs in system.
*
* This is the same as the standard interface:
*
* sysconf(_SC_NPROCESSORS_ONLN);
*
* Except this function isn't a bloated diamond dependency.
*
* On Intel systems with HyperThreading this will return the number of
* cores multiplied by two.
*
* @return cpu count or 0 if it couldn't be determined
*/
unsigned GetCpuCount(void) {
unsigned _getcpucount(void) {
return g_cpucount;
}
+1 -1
View File
@@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) {
return 0;
}
} else if (_weaken(malloc)) {
assert(!__vforked);
_unassert(!__vforked);
if (!size) size = PATH_MAX;
if (!(p = _weaken(malloc)(size))) {
STRACE("getcwd(%p, %'zu) %m", buf, size);
+29
View File
@@ -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/calls.h"
#include "libc/calls/internal.h"
/**
* Gets file descriptor table size.
*
* @return current limit on the number of open files per process
*/
int getdtablesize(void) {
return g_fds.n;
}
+3 -3
View File
@@ -20,10 +20,10 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/thread/thread.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/sysconf.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32)
@@ -60,7 +60,7 @@ static textstartup void sys_getloadavg_nt_init(void) {
double a[3];
if (IsWindows()) {
load = 1;
cpus = GetCpuCount() / 2;
cpus = _getcpucount() / 2;
cpus = MAX(1, cpus);
GetSystemTimes(&idle1, &kern1, &user1);
}
+12 -3
View File
@@ -16,18 +16,26 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/strace.internal.h"
#include "libc/assert.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
/**
* Returns parent process id.
*
* @return parent process id (always successful)
* @note slow on Windows; needs to iterate process tree
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
int getppid(void) {
int rc;
if (!IsWindows()) {
if (IsMetal()) {
rc = 1;
} else if (!IsWindows()) {
if (!IsNetbsd()) {
rc = sys_getppid();
} else {
@@ -36,6 +44,7 @@ int getppid(void) {
} else {
rc = sys_getppid_nt();
}
STRACE("getppid() → %d% m", rc);
_npassert(rc >= 0);
STRACE("%s() → %d", "getppid", rc);
return rc;
}
+58 -19
View File
@@ -16,28 +16,67 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/kntprioritycombos.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nexgen32e/ffs.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_getpriority_nt(int ignored) {
size_t i;
uint32_t tier, lg2tier, wut;
if ((tier = GetPriorityClass(GetCurrentProcess())) != 0 &&
(wut = GetThreadPriority(GetCurrentThread())) != -1u) {
lg2tier = ffs(tier);
for (i = 0; i < kNtPriorityCombosLen; ++i) {
if (kNtPriorityCombos[i].lg2tier == lg2tier &&
kNtPriorityCombos[i].wut == wut) {
return kNtPriorityCombos[i].nice;
}
}
abort();
} else {
return __winerr();
textwindows int sys_getpriority_nt(int which, unsigned pid) {
int rc;
uint32_t tier;
int64_t h, closeme = -1;
if (which != PRIO_PROCESS) {
return einval();
}
if (!pid || pid == getpid()) {
h = GetCurrentProcess();
} else if (__isfdkind(pid, kFdProcess)) {
h = g_fds.p[pid].handle;
} else {
h = OpenProcess(kNtProcessQueryInformation, false, pid);
if (!h) return __winerr();
closeme = h;
}
if ((tier = GetPriorityClass(h))) {
switch (tier) {
case kNtRealtimePriorityClass:
rc = -16;
break;
case kNtHighPriorityClass:
rc = -10;
break;
case kNtAboveNormalPriorityClass:
rc = -5;
break;
case kNtNormalPriorityClass:
rc = 0;
break;
case kNtBelowNormalPriorityClass:
rc = 5;
break;
case kNtIdlePriorityClass:
rc = 15;
break;
default:
notpossible;
}
} else {
rc = __winerr();
}
if (closeme != -1) {
CloseHandle(closeme);
}
return rc;
}
+40 -10
View File
@@ -17,10 +17,13 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asmflag.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
/**
* Returns nice value of thing.
@@ -29,20 +32,47 @@
* to clear `errno` beforehand and see if it changed, in order to truly
* determine if an error happened.
*
* @param which can be PRIO_PROCESS, PRIO_PGRP, PRIO_USER
* On Windows, there's only six priority classes. We define them as -16
* (realtime), -10 (high), -5 (above), 0 (normal), 5 (below), 15 (idle)
* which are the only values that'll roundtrip getpriority/setpriority.
*
* @param which can be one of:
* - `PRIO_PROCESS` is supported universally
* - `PRIO_PGRP` is supported on unix
* - `PRIO_USER` is supported on unix
* @param who is the pid, pgid, or uid (0 means current)
* @return value ∈ [-NZERO,NZERO) or -1 w/ errno
* @see setpriority(), nice()
* @raise EINVAL if `which` was invalid or unsupported
* @raise EPERM if access to process was denied
* @raise ESRCH if no such process existed
* @see setpriority()
*/
int getpriority(int which, unsigned who) {
privileged int getpriority(int which, unsigned who) {
int rc;
if (!IsWindows()) {
if ((rc = sys_getpriority(which, who)) != -1) {
rc = 20 - rc;
char cf;
if (IsLinux()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(140), "D"(which), "S"(who)
: "rcx", "r11", "memory");
if (rc >= 0) {
rc = NZERO - rc;
} else {
errno = -rc;
rc = -1;
}
} else if (IsBsd()) {
asm volatile(CFLAG_ASM("syscall")
: CFLAG_CONSTRAINT(cf), "=a"(rc)
: "1"((IsXnu() ? 0x2000000 : 0) | 100), "D"(which), "S"(who)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
if (cf) {
errno = rc;
rc = -1;
}
} else {
rc = sys_getsetpriority_nt(which, who, 0, sys_getpriority_nt);
rc = sys_getpriority_nt(which, who);
}
STRACE("getpriority(%d, %u) → %d% m", which, who, rc);
STRACE("getpriority(%s, %u) → %d% m", DescribeWhichPrio(which), who, rc);
return rc;
}
+1 -4
View File
@@ -33,7 +33,7 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
int64_t me, nsignals;
int64_t me;
struct NtIoCounters iocount;
struct NtProcessMemoryCountersEx memcount;
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
@@ -48,9 +48,6 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
!GetProcessIoCounters(me, &iocount)) {
return __winerr();
}
__sig_lock();
nsignals = __sig_count;
__sig_unlock();
*usage = (struct rusage){
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),
+3 -2
View File
@@ -18,7 +18,6 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
@@ -26,7 +25,9 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
#include "libc/time/struct/timezone.h"
typedef axdx_t gettimeofday_f(struct timeval *, struct timezone *, void *);
@@ -62,7 +63,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
rc = __gettimeofday(tv, tz, 0).ax;
}
#if SYSDEBUG
if (!__time_critical) {
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
}
#endif
+19 -8
View File
@@ -16,10 +16,12 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/runtime.h"
@@ -38,7 +40,7 @@ static textwindows dontinline uint32_t GetUserNameHash(void) {
char16_t buf[257];
uint32_t size = ARRAYLEN(buf);
GetUserName(&buf, &size);
return KnuthMultiplicativeHash32(buf, size >> 1);
return KnuthMultiplicativeHash32(buf, size >> 1) & INT_MAX;
}
/**
@@ -47,18 +49,22 @@ static textwindows dontinline uint32_t GetUserNameHash(void) {
* This never fails. On Windows, which doesn't really have this concept,
* we return a deterministic value that's likely to work.
*
* @return user id (always successful)
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
uint32_t getuid(void) {
uint32_t rc;
if (!IsWindows()) {
int rc;
if (IsMetal()) {
rc = 0;
} else if (!IsWindows()) {
rc = sys_getuid();
} else {
rc = GetUserNameHash();
}
STRACE("%s() → %u% m", "getuid", rc);
_npassert(rc >= 0);
STRACE("%s() → %d", "getuid", rc);
return rc;
}
@@ -68,16 +74,21 @@ uint32_t getuid(void) {
* This never fails. On Windows, which doesn't really have this concept,
* we return a deterministic value that's likely to work.
*
* @return group id (always successful)
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
uint32_t getgid(void) {
uint32_t rc;
if (!IsWindows()) {
int rc;
if (IsMetal()) {
rc = 0;
} else if (!IsWindows()) {
rc = sys_getgid();
} else {
rc = GetUserNameHash();
}
STRACE("%s() → %u% m", "getgid", rc);
_npassert(rc >= 0);
STRACE("%s() → %d", "getgid", rc);
return rc;
}
+4 -4
View File
@@ -31,11 +31,11 @@
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res;
if (__time_critical) return false;
if (__threaded && __threaded != gettid()) return false;
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
}
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
return res;
}
+1 -1
View File
@@ -253,7 +253,7 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
int count, i;
/* __hostInfo must be empty */
assert(__hostInfo == NULL);
_unassert(__hostInfo == NULL);
for (aa = firstAdapter; aa; aa = aa->Next) {
/* Skip all the interfaces with no address and the ones that are not AF_INET
-56
View File
@@ -1,56 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/bits.h"
#include "libc/calls/kntprioritycombos.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/ffs.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/threadpriority.h"
hidden const struct NtPriorityCombo kNtPriorityCombos[] = {
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
};
hidden const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);
-18
View File
@@ -1,18 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
#define COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct NtPriorityCombo {
int8_t nice; /* sorted by this */
int8_t lg2tier;
int8_t wut;
int8_t prio;
};
hidden extern const unsigned kNtPriorityCombosLen;
hidden extern const struct NtPriorityCombo kNtPriorityCombos[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_ */
+43 -5
View File
@@ -28,15 +28,53 @@
#include "libc/zipos/zipos.internal.h"
/**
* Changes current position of file descriptor/handle.
* Changes current position of file descriptor, e.g.
*
* int fd = open("hello.bin", O_RDONLY);
* lseek(fd, 100, SEEK_SET); // set position to 100th byte
* read(fd, buf, 8); // read bytes 100 through 107
*
* This function may be used to inspect the current position:
*
* int64_t pos = lseek(fd, 0, SEEK_CUR);
*
* You may seek past the end of file. If a write happens afterwards
* then the gap leading up to it will be filled with zeroes. Please
* note that lseek() by itself will not extend the physical medium.
*
* If dup() is used then the current position will be shared across
* multiple file descriptors. If you seek in one it will implicitly
* seek the other too.
*
* The current position of a file descriptor is shared between both
* processes and threads. For example, if an fd is inherited across
* fork(), and both the child and parent want to read from it, then
* changes made by one are observable to the other.
*
* The pread() and pwrite() functions obfuscate the need for having
* global shared file position state. Consider using them, since it
* helps avoid the gotchas of this interface described above.
*
* This function is supported by all OSes within our support vector
* and our unit tests demonstrate the behaviors described above are
* consistent across platforms.
*
* @param fd is a number returned by open()
* @param offset is the relative byte count
* @param whence can be SEEK_SET, SEEK_CUR, or SEEK_END
* @return new position relative to beginning, or -1 on error
* @param offset is 0-indexed byte count w.r.t. `whence`
* @param whence can be one of:
* - `SEEK_SET`: Sets the file position to `offset` [default]
* - `SEEK_CUR`: Sets the file position to `position + offset`
* - `SEEK_END`: Sets the file position to `filesize + offset`
* @return new position relative to beginning, or -1 w/ errno
* @raise ESPIPE if `fd` is a pipe, socket, or fifo
* @raise EBADF if `fd` isn't an open file descriptor
* @raise EINVAL if resulting offset would be negative
* @raise EINVAL if `whence` isn't valid
* @asyncsignalsafe
* @threadsafe
* @vforksafe
*/
int64_t lseek(int fd, int64_t offset, unsigned whence) {
int64_t lseek(int fd, int64_t offset, int whence) {
int64_t rc;
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_lseek)(
+91
View File
@@ -0,0 +1,91 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/str/path.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
/**
* Creates directory and parent components.
*
* This function is similar to mkdir() except it iteratively creates
* parent directories and it won't fail if the directory already exists.
*
* @param path is a UTF-8 string, preferably relative w/ forward slashes
* @param mode can be, for example, 0755
* @return 0 on success or -1 w/ errno
* @raise EEXIST if named file already exists as non-directory
* @raise ENOTDIR if directory component in `path` existed as non-directory
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
* @raise EROFS if parent directory is on read-only filesystem
* @raise ENOSPC if file system or parent directory is full
* @raise EACCES if write permission was denied on parent directory
* @raise EACCES if search permission was denied on component in `path`
* @raise ENOENT if `path` is an empty string
* @raise ELOOP if loop was detected resolving components of `path`
* @asyncsignalsafe
* @threadsafe
*/
int makedirs(const char *path, unsigned mode) {
int c, e, i, n;
struct stat st;
char buf[PATH_MAX];
e = errno;
n = strlen(path);
if (n >= PATH_MAX) return enametoolong();
memcpy(buf, path, n + 1);
i = n;
// descend
while (i) {
if (!mkdir(buf, mode)) break;
if (errno == EEXIST) {
if (i == n) goto CheckTop;
break;
}
if (errno != ENOENT) return -1;
while (i && _isdirsep(buf[i - 1])) buf[--i] = 0;
while (i && !_isdirsep(buf[i - 1])) buf[--i] = 0;
}
// ascend
for (;;) {
if (mkdir(buf, mode)) {
if (errno != EEXIST) return -1;
if (i == n) goto CheckTop;
}
if (i == n) break;
while (i < n && !_isdirsep((c = path[i]))) buf[i++] = c;
while (i < n && _isdirsep((c = path[i]))) buf[i++] = c;
}
Finish:
errno = e;
return 0;
CheckTop:
if (stat(path, &st)) return -1;
if (S_ISDIR(st.st_mode)) goto Finish;
return eexist();
}
+14 -7
View File
@@ -17,12 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Creates directory a.k.a. folder.
@@ -36,9 +31,21 @@
* @param path is a UTF-8 string, preferably relative w/ forward slashes
* @param mode can be, for example, 0755
* @return 0 on success or -1 w/ errno
* @error ENAMETOOLONG if >246 characters on NT
* @raise EEXIST if named file already exists
* @raise ENOTDIR if directory component in `path` existed as non-directory
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
* @raise EROFS if parent directory is on read-only filesystem
* @raise ENOSPC if file system or parent directory is full
* @raise EACCES if write permission was denied on parent directory
* @raise EACCES if search permission was denied on component in `path`
* @raise ENOENT if a component within `path` didn't exist
* @raise ENOENT if `path` is an empty string
* @raise ELOOP if loop was detected resolving components of `path`
* @see makedirs() which is higher-level
* @see mkdirat() for modern call
* @asyncsignalsafe
* @see makedirs()
* @threadsafe
*/
int mkdir(const char *path, unsigned mode) {
return mkdirat(AT_FDCWD, path, mode);
+15 -4
View File
@@ -31,12 +31,23 @@
/**
* Creates directory a.k.a. folder.
*
* @param dirfd is normally AT_FDCWD but if it's an open directory and
* @param dirfd is normally `AT_FDCWD` but if it's an open directory and
* path is relative, then path becomes relative to dirfd
* @param path is a UTF-8 string, preferably relative w/ forward slashes
* @param mode can be, for example, 0755
* @return 0 on success or -1 w/ errno
* @error EEXIST, ENOTDIR, ENAMETOOLONG, EACCES, ENOENT
* @param mode is permissions bits, which is usually 0755
* @return 0 on success, or -1 w/ errno
* @raise EEXIST if named file already exists
* @raise EBADF if `path` is relative and `dirfd` isn't `AT_FDCWD` or valid
* @raise ENOTDIR if directory component in `path` existed as non-directory
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
* @raise EROFS if parent directory is on read-only filesystem
* @raise ENOSPC if file system or parent directory is full
* @raise EACCES if write permission was denied on parent directory
* @raise EACCES if search permission was denied on component in `path`
* @raise ENOENT if a component within `path` didn't exist
* @raise ENOENT if `path` is an empty string
* @raise ELOOP if loop was detected resolving components of `path`
* @asyncsignalsafe
* @see makedirs()
*/
+28 -22
View File
@@ -34,8 +34,15 @@
static bool NeedsQuotes(const char *s) {
if (!*s) return true;
do {
if (*s == ' ' || *s == '\t') {
return true;
switch (*s) {
case '"':
case ' ':
case '\t':
case '\v':
case '\n':
return true;
default:
break;
}
} while (*s++);
return false;
@@ -45,19 +52,21 @@ static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
/**
* Converts System V argv to Windows-style command line.
*
* Escaping is performed and it's designed to round-trip with
* GetDosArgv() or GetDosArgv(). This function does NOT escape
* command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
*
* @param cmdline is output buffer
* @param prog is used as argv[0]
* @param argv is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpCommandLine or NULL w/ errno
* @see libc/runtime/dosargv.c
*/
// Converts System V argv to Windows-style command line.
//
// Escaping is performed and it's designed to round-trip with
// GetDosArgv() or GetDosArgv(). This function does NOT escape
// command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
//
// TODO(jart): this needs fuzzing and security review
//
// @param cmdline is output buffer
// @param prog is frontloaded as argv[0]
// @param argv is an a NULL-terminated array of UTF-8 strings
// @return 0 on success, or -1 w/ errno
// @raise E2BIG if everything is too huge
// @see "Everyone quotes command line arguments the wrong way" MSDN
// @see libc/runtime/getdosargv.c
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
char *const argv[]) {
char *arg;
@@ -102,8 +111,8 @@ textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
} else {
// turn stuff like `less /c/...`
// into `less c:/...`
// turn stuff like `more <\\\"/c/...\\\"`
// into `more <\\\"c:/...\\\"`
// turn stuff like `more <"/c/..."`
// into `more <"c:/..."`
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
@@ -115,11 +124,8 @@ textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
if (x == '\\') {
++slashes;
} else if (x == '"') {
for (s = 0; s < slashes * 2; ++s) {
APPEND(u'\\');
}
slashes = 0;
APPEND(u'\\');
APPEND(u'"');
APPEND(u'"');
APPEND(u'"');
} else {
for (s = 0; s < slashes; ++s) {
+21 -2
View File
@@ -17,8 +17,8 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/ntmagicpaths.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/systeminfo.h"
#include "libc/str/oldutf16.internal.h"
@@ -173,5 +173,24 @@ textwindows int __mkntpath2(const char *path,
p[j] = 0;
n = j;
return x + m + n;
// our path is now stored at `path16` with length `n`
n = x + m + n;
// To avoid toil like this:
//
// CMD.EXE was started with the above path as the current directory.
// UNC paths are not supported. Defaulting to Windows directory.
// Access is denied.
//
// Remove \\?\ prefix if we're within 260 character limit.
if (n > 4 && n < 260 && //
path16[0] == '\\' && //
path16[1] == '\\' && //
path16[2] == '?' && //
path16[3] == '\\') {
memmove(path16, path16 + 4, (n - 4 + 1) * sizeof(char16_t));
n -= 4;
}
return n;
}
-101
View File
@@ -1,101 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/errors.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/clockstonanos.internal.h"
textwindows int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
bool alertable;
uint32_t slice;
uint64_t begin;
int64_t ms, toto, nanos;
struct timespec elapsed;
// check req is legal timespec
if (!(0 <= req->tv_nsec && req->tv_nsec < 1000000000)) {
return einval();
}
// save beginning timestamp
if (!__time_critical && rem) {
begin = rdtsc();
} else {
begin = 0; // to prevent uninitialized warning
}
// convert timespec to milliseconds
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
__builtin_add_overflow(ms, (req->tv_nsec + 999999) / 1000000, &ms)) {
ms = INT64_MAX;
}
for (toto = ms;;) {
// check if signal was delivered
if (!__time_critical && _check_interrupts(false, g_fds.p)) {
if (rem) {
nanos = ClocksToNanos(rdtsc(), begin);
elapsed.tv_sec = nanos / 1000000000;
elapsed.tv_nsec = nanos % 1000000000;
*rem = _timespec_sub(*req, elapsed);
if (rem->tv_sec < 0) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
}
return eintr();
}
// configure the sleep
slice = MIN(__SIG_POLLING_INTERVAL_MS, ms);
if (__time_critical) {
alertable = false;
} else {
alertable = true;
POLLTRACE("... sleeping %'ldms of %'ld", toto - ms, toto);
}
// perform the sleep
if (SleepEx(slice, alertable) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR"); // in case we ever figure it out
continue;
}
// check if full duration has elapsed
if ((ms -= slice) <= 0) {
if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return 0;
}
}
}
+14 -20
View File
@@ -19,40 +19,34 @@
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
// nanosleep() on xnu: a bloodbath of a polyfill
// consider using clock_nanosleep(TIMER_ABSTIME)
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
int rc;
axdx_t axdx;
struct timeval tv;
struct timespec begin, end, elapsed;
if (rem) {
if (sys_clock_gettime_xnu(CLOCK_MONOTONIC, &begin) == -1) {
return -1;
}
}
tv = _timespec2timeval(*req);
rc = sys_select(0, 0, 0, 0, &tv);
struct timeval wt, t1, t2, td;
if (rem) sys_gettimeofday_xnu(&t1, 0, 0);
wt = _timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &wt);
if (rem) {
if (!rc) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else if (rc == -1 && errno == EINTR) {
sys_clock_gettime_xnu(CLOCK_MONOTONIC, &end);
elapsed = _timespec_sub(end, begin);
*rem = _timespec_sub(*req, elapsed);
if (rem->tv_sec < 0) {
// xnu select() doesn't modify timeout
// so we need, yet another system call
sys_gettimeofday_xnu(&t2, 0, 0);
td = _timeval_sub(t2, t1);
if (_timeval_gte(td, wt)) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else {
*rem = _timeval_totimespec(_timeval_sub(wt, td));
}
}
}
return rc;
}
+12 -49
View File
@@ -16,67 +16,30 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#include "libc/sysv/consts/clock.h"
/**
* Sleeps for a particular amount of time.
* Sleeps for relative amount of time.
*
* @param req is the duration of time we should sleep
* @param rem if non-NULL will receive the amount of time that wasn't
* slept because a signal was delivered. If no signal's delivered
* then this value will be set to `{0, 0}`. It's also fine to set
* this value to the same pointer as `req`.
* @param rem if non-null will be updated with the remainder of unslept
* time when -1 w/ `EINTR` is returned otherwise `rem` is undefined
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
* @raise EINTR if a signal was delivered, and `rem` is updated
* @raise EINTR if a signal was delivered and `rem` is updated
* @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
* @raise ENOSYS on bare metal
* @note POSIX.1 specifies nanosleep() measures against `CLOCK_REALTIME`
* however Linux measures uses `CLOCK_MONOTONIC`. This shouldn't
* matter, since POSIX.1 further specifies that discontinuous
* changes in `CLOCK_REALTIME` shouldn't impact nanosleep()
* @see clock_nanosleep()
* @norestart
*/
int nanosleep(const struct timespec *req, struct timespec *rem) {
int rc;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
rc = efault();
} else if (req->tv_sec < 0 ||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
rc = einval();
} else if (!IsWindows() && !IsMetal() && !IsXnu()) {
rc = sys_nanosleep(req, rem);
} else if (IsXnu()) {
rc = sys_nanosleep_xnu(req, rem);
} else if (IsMetal()) {
rc = enosys(); /* TODO: Sleep on Metal */
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, req, rem))) {
return 0;
} else {
rc = sys_nanosleep_nt(req, rem);
errno = rc;
return -1;
}
// Linux Kernel doesn't change the remainder value on success, but
// some kernels like OpenBSD will. POSIX doesn't specify the Linux
// behavior. So we polyfill it here.
if (!rc && rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
#ifdef SYSDEBUG
if (!__time_critical) {
STRACE("nanosleep(%s, [%s]) → %d% m", DescribeTimespec(rc, req),
DescribeTimespec(rc, rem), rc);
}
#endif
return rc;
}
Loaded 100 of 914 files, more files were not shown because too many files have changed in this diff. Show more