Compare commits

...
115 Commits
Author SHA1 Message Date
Justine Tunney 3093f0e467 Release Cosmopolitan v3.4.0 2024-06-05 03:07:03 -07:00
Justine Tunney 3609f65de3 Make malloc() go 200x faster
If pthread_create() is linked into the binary, then the cosmo runtime
will create an independent dlmalloc arena for each core. Whenever the
malloc() function is used it will index `g_heaps[sched_getcpu() / 2]`
to find the arena with the greatest hyperthread / numa locality. This
may be configured via an environment variable. For example if you say
`export COSMOPOLITAN_HEAP_COUNT=1` then you can restore the old ways.
Your process may be configured to have anywhere between 1 - 128 heaps

We need this revision because it makes multithreaded C++ applications
faster. For example, an HTTP server I'm working on that makes extreme
use of the STL went from 16k to 2000k requests per second, after this
change was made. To understand why, try out the malloc_test benchmark
which calls malloc() + realloc() in a loop across many threads, which
sees a a 250x improvement in process clock time and 200x on wall time

The tradeoff is this adds ~25ns of latency to individual malloc calls
compared to MODE=tiny, once the cosmo runtime has transitioned into a
fully multi-threaded state. If you don't need malloc() to be scalable
then cosmo provides many options for you. For starters the heap count
variable above can be set to put the process back in single heap mode
plus you can go even faster still, if you include tinymalloc.inc like
many of the programs in tool/build/.. are already doing since that'll
shave tens of kb off your binary footprint too. Theres also MODE=tiny
which is configured to use just 1 plain old dlmalloc arena by default

Another tradeoff is we need more memory now (except in MODE=tiny), to
track the provenance of memory allocation. This is so allocations can
be freely shared across threads, and because OSes can reschedule code
to different CPUs at any time.
2024-06-05 02:02:14 -07:00
Justine Tunney 9906f299bb Refactor and improve CTL and other code 2024-06-04 05:45:48 -07:00
Justine Tunney 1d8f37a2f0 Fix the MODE=tiny builds 2024-06-03 10:36:38 -07:00
Justine Tunney e677460d14 Delete .vscode folder
It hasn't been maintained in years. I'm tired of the root level of our
project having an advertisement for Microsoft Visual Studio Code. Your
preferred editor should be Emacs or Vim.
2024-06-03 09:40:45 -07:00
Justine Tunney 4937843f70 Introduce Cosmopolitan Templates Library (CTL) 2024-06-03 09:21:59 -07:00
Justine Tunney b003888696 Make __demangle() heap 10% more compact 2024-06-02 16:18:55 -07:00
Justine Tunney 2ca491dc56 Write more __demangle() tests 2024-06-02 07:37:15 -07:00
Justine Tunney 9aa353d88b Document __demangle() and fix a const func ptr bug 2024-06-02 04:15:48 -07:00
Justine Tunney c67faf61df Delete some unintentional code 2024-06-01 20:36:58 -07:00
Justine Tunney 165c6b37e2 Add C++ demangling to privileged runtime
Cosmo will now print C++ symbols correctly in --ftrace logs and
backtraces. Doing this required reducing the memory requirement
of the __demangle() function by 3x. This was accomplished using
16-bit indices and 16-bit malloc granularity. That puts a limit
on the longest symbol we can successfully decode, which I think
would be around 6553 characters long, given a 65536-byte buffer
2024-06-01 20:10:58 -07:00
Jōshin dcd626edf8 Add .git-blame-ignore-revs
If you follow the directions in that file then git blame will ignore the
listed commits. A commit should only go in that file if its only changes
were to formatting, particularly on a large part of the codebase (like a
change to .clang-format getting applied to the repo.)

Cribbed from here:

https://www.stefanjudis.com/today-i-learned/how-to-exclude-commits-from-git-blame/
2024-06-01 20:10:48 -07:00
Jōshin f032b5570b Run clang-format (#1197) 2024-06-01 16:30:43 -04:00
Justine Tunney ea081b262c Add some noexcept annotations 2024-06-01 03:19:53 -07:00
Justine Tunney fae1c32267 Encode ±INFINITY as ±1e5000
The V8 behavior of encoding infinity as null doesn't make sense to me.
Using ±1e5000 is better, because JSON.parse decodes it as INFINITY and
the information is preserved. This could be a breaking change for some
2024-06-01 03:19:50 -07:00
Justine Tunney 9b6718ac99 Improve backtraces
We're now able to rewind the instruction pointer in x86 backtraces. This
helps ensure addr2line cannot print information about unrelated adjacent
code. I've restored -fno-schedule-insns2 in most cases because it really
does cause unpredictable breakage for backtraces.
2024-05-30 15:23:11 -07:00
Justine Tunney cd672e251f Improve crash signal reporting on Windows
This change fixes a bug where exiting a crash signal handler on Windows
after adding the signal to uc_sigmask, but not correcting the CPU state
would cause the signal handler to loop infinitely, causing process hang

Another issue is that very tiny programs, that don't link posix signals
would not have their SIGILL / SIGSEGV / etc. status reported to Cosmo's
bash shell when terminating on crash. That's fixed by a tiny handler in
WinMain() that knows how to map WIN32 crash codes to the POSIX flavors.
2024-05-30 14:04:10 -07:00
Justine Tunney 500a47bc2f Fix undefined behavior in unit test
Fixes #1194
2024-05-29 20:31:46 -07:00
Justine Tunney e4d25d68e4 Drop support for Windows 8
Microsoft caused some very gentle breakages for Cosmopolitan. They
removed the version information from the PEB which caused uname to
report WINDOWS 0.0.0. We should have called GetVersionExW but that
doesn't really exist anymore either. Windows policy is now to give
whatever version we used in ape/ape.S. Windows8 has been EOL since
2023-01-10 so lets avoid our modern executables being relegated to
legacy infrastructure. Requiring Windows 10+ going forward lets us
remove runtime compatibility bloat from the codebase. Further note
Cosmopolitan maintains a Windows Vista branch on GitHub, so anyone
preferring the older versions, can still have a future with Cosmo.

Another neat thing this fixes is UTF-8 support in the console. The
changes Microsoft made broke the if statement that enabled UTF8 in
terminals. This explains why bug reports had broken arrows. In the
future this should be less of an issue, since the PEB code is gone
which means we more strictly conform to only Microsoft's WIN32 API
2024-05-29 19:37:47 -07:00
Justine Tunney f31a98d50a Fix bug with realpath() on Windows 2024-05-29 18:47:01 -07:00
Justine Tunney 2816df59b2 Increase tinymalloc granularity 2024-05-29 18:26:01 -07:00
Justine Tunney a05ce3ad9d Support avx512f + vpclmulqdq crc32() acceleration
Cosmo's _Cz_crc32() function now goes 73 GiB/s on Threadripper. This
will significantly improve the performance of the PKZIP file format.
This algorithm is also used by apelink, to create deterministic ids.
2024-05-29 10:13:37 -07:00
Justine Tunney 7c8df05042 Improve -march=native micro-architecture detection 2024-05-29 10:12:49 -07:00
Justine Tunney 4c77acdfcf Add LoadZipArgs() to <cosmo.h> 2024-05-29 10:12:20 -07:00
Justine Tunney b74b974cfd Introduce #include <tinygetopt.h>
The normal getopt() function is bloated because it links printf(). This
change exports the original authentic bsd getopt function, that cosmo's
always used internally so cosmocc users don't need to include internals
2024-05-29 10:11:17 -07:00
Justine Tunney 07cef612c3 Make dlmalloc 2.4x faster for multithreading
This change adds a TLS freelist for small dynamic memory allocations.
Cosmopolitan's TIB is now 512 bytes in size. Single-threaded malloc()
performance isn't impacted by this, until pthread_create() is called.
Single-threaded programs may also want to consider using:

    #include "libc/mem/tinymalloc.inc"

Which will shave 30k off the executable size and sometimes go faster.
2024-05-28 11:18:34 -07:00
Justine Tunney deaef81463 Favor siginfo_t over struct siginfo 2024-05-28 02:34:17 -07:00
Justine Tunney c638eabfe0 Fix compiler warning 2024-05-27 02:23:24 -07:00
Justine Tunney 8e68384e15 Upgrade to 2022-era LLVM LIBCXX 2024-05-27 02:12:27 -07:00
Justine Tunney 2f4ca71f26 Release Cosmopolitan v3.3.10 2024-05-26 22:13:45 -07:00
Justine Tunney 07004ebf04 Upgrade to superconfigure z0.0.42 2024-05-26 22:12:25 -07:00
Justine Tunney 086d7006da Improve crash handler on XNU
This avoids an issue where a crash signal could cause the MacOS process
to freeze and consume all CPU rather than dying as it rightfully should
2024-05-26 18:42:09 -07:00
Gavin Hayes 0a51241f7a ntspawn: fix initializing NtStartupInfoEx (#1190) 2024-05-26 20:54:09 -04:00
Justine Tunney c68f6599e5 Fix definition of getpeername on FreeBSD
We were using the COMPAT magic number, which was recently removed.
2024-05-26 17:03:22 -07:00
Justine Tunney af3f62a71a Ensure io requests are always capped at 0x7ffff000
This gives us the Linux behavior across platforms.

Fixes #1189
2024-05-26 16:53:13 -07:00
Justine Tunney 6cf9b9e0fc Release Cosmopolitan v3.3.9 2024-05-26 15:28:03 -07:00
Justine Tunney 1d4b452839 Refactor some code 2024-05-26 06:03:50 -07:00
Justine Tunney c2db3b703a Introduce --timelog=FILE flag to GNU Make 2024-05-25 14:50:20 -07:00
Justine Tunney edb03b89d8 Make stdin unbuffered when appropriate 2024-05-25 07:57:13 -07:00
Justine Tunney 7724664b13 Release Cosmopolitan v3.3.8 2024-05-25 05:59:20 -07:00
Justine Tunney 1df4296208 Fix stdio for character device regression
Caused by ed93fc3dd7
2024-05-25 05:58:09 -07:00
Justine Tunney ce9aeb2aed Release Cosmopolitan v3.3.7 2024-05-24 19:37:21 -07:00
Justine Tunney ed93fc3dd7 Fix fread() with 2gb+ sizes 2024-05-24 19:28:23 -07:00
Justine Tunney 5f61d273e4 Add hwap constants to sys/auxv.h 2024-05-24 11:44:44 -07:00
Justine Tunney bf3531de81 Make crash reports reliable in multithreaded case 2024-05-24 11:44:44 -07:00
Justine Tunney 3b0ea2db4d Remove -fno-schedule-insns2
This was originally added when we were using the mcount hooking
technique, to prevent the nop from floating above the frame pointer
creation. Now we use a better codegen technique for hooking so it's no
longer needed to sacrifice performance by using this flag.
2024-05-24 11:44:44 -07:00
Justine Tunney f029375d39 Introduce MAP_HUGETLB 2024-05-24 11:44:44 -07:00
Justine Tunney 9b87dd2b87 Refactor some code 2024-05-24 11:44:44 -07:00
Jōshin 787b04f752 Run all BLAKE2B256 test vectors (#1185) 2024-05-24 10:59:23 -07:00
Jōshin 0768807935 Rename python -> python3 (closes #1144) (#1187)
When we removed the com suffix from ape binaries, we broke the build for
ape's python for any case-insensitive file system, i.e. Windows and XNU,
because there is a third_party/python/Python that gets mirrored in the o
directory with the python object files and clashes with the binary name.
This patch hacks around this by renaming the binary to "python3" so that
it no longer clashes with that directory.
2024-05-24 10:56:33 -07:00
Justine Tunney 0b59f01b43 Put confstr() in unistd.h
Fixes #1184
2024-05-21 15:35:06 -07:00
Justine Tunney cf70a44756 Support shebang on Windows
Fixes #1010
2024-05-20 22:11:42 -07:00
Justine Tunney a52792c59f Add some missing build dependencies 2024-05-20 17:23:25 -07:00
Jōshin 65c9b28e99 Fix buffer overflow in os.tmpname (#1180)
At least on macOS, `strlen(getenv("TMPDIR"))` is 50. We now allow a /tmp
that takes up to 120 or so bytes to spell. Instead of overflowing, we do
a bounds check and the function fails successfully on even longer /tmps.

Fixes #1108 (os.tmpname crashes redbean)
2024-05-20 03:46:27 -04:00
Jōshin 4292348707 Import libbsd readpassphrase (#1182)
Included from:

https://gitlab.freedesktop.org/libbsd/libbsd

At commit 04a24db27ad1572f766bad772cdd9c146e6d9cf0.
2024-05-20 03:37:30 -04:00
Jōshin 2ec20b6c4c Fix #922 (Duplicated line) (#1178) 2024-05-20 00:33:50 -07:00
Jōshin 47183551d6 Fix sleb64 (#1179)
Fixes #920
2024-05-20 00:33:17 -07:00
Jōshin 42891e82bb Fix #959 (typo in cosmocc --version) 2024-05-18 15:20:27 -07:00
Gavin Hayes 624119ea38 Fix NT accept/connect not initializing with SO_UPDATE_*_CONTEXT (#1164) 2024-05-17 02:45:30 -07:00
Justine Tunney 2f3c6e7cc3 Revert "Remove zlib namespacing (#1142)"
This reverts commit 5488f0b2ca which was a
good experiment to try, that didn't work out due to #1176

Fixes #1176
2024-05-14 20:45:23 -07:00
Justine Tunney 13b9ecd537 Remove outdated restriction on -Werror on cosmocc
This was a good idea back when we were only using it to build various
open source projects. However it no longer makes sense that many more
people are depending on cosmocc, to develop new software. Our tooling
shouldn't be making these kinds of decisions for the user.
2024-05-09 14:03:51 -07:00
Justine Tunney 6659981457 Release Cosmopolitan v3.3.6 2024-05-08 04:20:22 -07:00
Justine Tunney ae2a7ac844 Fix thread-local storage bugs on aarch64
This change fixes an issue where .tbss memory might not be initialized.
2024-05-08 04:20:22 -07:00
Justine Tunney 793393a341 Polyfill SA_RESETHAND on MacOS ARM64
This change solves the XNU crash loop mystery. Apple's documentation
claims to support this feature, but they only define the constant in
their header files. The kernel acknowledges thi SA_RESETHAND bit, by
clearing it from the sa_flags state, returns zero, and does nothing.
2024-05-08 04:20:22 -07:00
Justine Tunney 952b9009e8 Avoid crash looping on AARCH64 2024-05-08 04:20:22 -07:00
Jōshin 8f18b3ad65 Reapply apeinstall.sh binfmt flags (#1171)
7d31fc3 made it safe to register ape with the binfmt P flag. Older files
will still get their paths passed via argv[0] and everything should just
work. This also restores the F flag that was rolled back alongside the P
flag; this seems like a good idea to me now. It makes it so /usr/bin/ape
is kind of part of the kernel; simply replacing the file will not change
the loader used. The binfmt will have to be reregistered as well.

ape/apeinstall.sh will already nag you if there's an existing binfmt for
ape. It might be nice to make it actually replace the registration.

This reverts commit df648fb174.
2024-05-08 01:48:48 -04:00
Jōshin 56e0fd9d1d Use latest cosmocc (#1175) 2024-05-08 00:08:26 -04:00
Justine Tunney df68a6362b Release Cosmopolitan v3.3.5 2024-05-07 18:18:10 -07:00
Justine Tunney 19c81863a3 Improve crash backtrace reliability
We're now able to pretty print a C++ backtrace upon crashing in pretty
much any runtime execution scenario. The default pledge sandbox policy
on Linux is now to return EPERM. If you call pledge and have debugging
functions linked (e.g. GetSymbolTable) then the symbol table shall get
loaded before any security policy is put in place. This change updates
build/bootstrap/fixupobj too and fixes some other sneaky build errors.
2024-05-07 18:10:28 -07:00
Jōshin 7d31fc311a Loaders rewrite argv[0] for old binaries (#1170)
For this to work, a loader has to be able to tell the difference between
an ‘old’ and a ‘new’ binary. This is achieved via a repurposing of ELF’s
e_flags field. We previously tried to use the padding in e_ident for it,
but binutils was resetting it to zero in e.g. strip.

This introduces one new ELF flag for cosmopolitan binaries. It is called
`EF_APE_MODERN`. We choose 0x101ca75, "lol cat 5".

It should now be safe to install the ape loader binfmt registration with
the `P` flag.
2024-05-07 20:42:18 -04:00
Justine Tunney 57c0b065c8 Make old C++ demangler asynchronous signal safe
It's now possible to safely print C++ backtraces from signal handlers.
This symbol demangler doesn't need malloc, tls, or even static memory.
Additionally, this change makes it 2x faster and adds test cases. It's
almost as performant and accurate as the libcxxabi implementation now.
2024-05-07 03:41:33 -07:00
Justine Tunney a6ecbb747d Introduce libc/mem/tinymalloc.inc
This allocator shaves ~20kb off single-threaded tool programs and is
slightly faster than proper malloc for simple non-demanding programs
2024-05-07 03:19:49 -07:00
Justine Tunney 3bf95ae7ec Invent tool for renaming ELF object symbols 2024-05-07 03:19:49 -07:00
Justine Tunney 5fd7b07fac Improve AVX512 feature detection 2024-05-07 03:19:49 -07:00
Jōshin 317c8bc312 Update MODE=tiny time zone list (#1167)
I took one canonical IANA zone ID from each of the different colored
regions in this article, except those that do not observe DST and do
not have a Google office. See the "Time in Europe" Wikipedia article.

As to which canonical ID to use, this was somewhat arbitrary. Brussels
was obvious, as the de facto capital of the EU. For the rest, I mostly
just went with lexicographic ordering of the most recognizable options.

I've sorted the American zones. This Keeps the U.S. ones together but
does everything alphabetically otherwise. I've added the remaining
Canadian zones These have DST (and Newfoundland is off by a half-
hour from a UTC interval) so they cannot use Etc/. The Pacific/ zones
are sort of sorted. The Chathan Islands have been added. This is the
last of the zones I believe with a non-integer hour offset from UTC.
2024-05-06 16:48:49 -07:00
Jōshin 2a1f352622 Tell vim not to mess with ape.S 2024-05-06 15:36:35 -07:00
Justine Tunney 06d916b449 Add VirtualAlloc2 WIN32 API 2024-05-04 23:26:40 -07:00
Justine Tunney 9ea64725b6 Fix build error 2024-05-04 23:23:56 -07:00
Justine Tunney f9fc7eb49f Fix MODE=dbg build errors 2024-05-04 23:20:12 -07:00
Justine Tunney b0df6c1fce Implement proper time zone support
Cosmopolitan now supports 104 time zones. They're embedded inside any
binary that links the localtime() function. Doing so adds about 100kb
to the binary size. This change also gets time zones working properly
on Windows for the first time. It's not needed to have /etc/localtime
exist on Windows, since we can get this information from WIN32. We're
also now updated to the latest version of Paul Eggert's TZ library.
2024-05-04 23:06:37 -07:00
Justine Tunney d5ebb1fa5b Add MapViewOfFile3 WIN32 API 2024-05-04 12:25:41 -07:00
Justine Tunney 130fd66f9e Release Cosmopolitan v3.3.4 2024-05-03 09:25:02 -07:00
Justine Tunney 8a44f913ae Delete flaky tests
Signals are extremely difficult to unit test reliably. This is why
functions like sigsuspend() exist. When testing something else and
portably it becomes impossible without access to kernel internals.

OpenMP flakes in QEMU on one of my workstations. I don't think the
support is production worthy, because there's been issues on MacOS
additionally. It works great for every experiment I've used it for
though. However a flaky test is worse than no test at all. So it's
removed until someone takes an interest in productionizing it.
2024-05-03 09:11:04 -07:00
Gautham 5488f0b2ca Remove zlib namespacing (#1142)
We have an optimized version of zlib from the Chromium project.
We need it for a lot of our libc services. It would be nice to export
this to user applications if we can, since projects like llamafile are
already depending on it under the private namespace, to avoid
needing to link zlib twice.
2024-05-03 08:07:25 -07:00
Gavin Hayes deff138e7e recvfrom: don't convert address if addrsize is 0 (#1153) 2024-05-03 08:03:57 -07:00
Gavin Hayes b6e40a3a58 Add /dev/(u)random on NT (#1163) 2024-05-03 07:59:51 -07:00
Cadence Ember 8f6bc9dabc Let signals interrupt fgets unless SA_RESTART set (#1152) 2024-05-03 07:49:41 -07:00
Justine Tunney 181cd4cbe8 Add sysctlbyname() for MacOS 2024-05-02 23:21:43 -07:00
Justine Tunney 5c6877b02b Introduce support for trapping math
The feenableexcept() and fedisableexcept() APIs are now provided which
let you detect when NaNs appear the moment it happens from anywhere in
your program. Tests have also been added for the mission critical math
functions expf() and erff(), whose perfect operation has been assured.
See examples/trapping.c to see how to use this powerful functionality.
2024-04-30 13:38:43 -07:00
Justine Tunney 403bc25412 Make MXCSR editable by signal handlers on Windows
It's now possible to recover from floating point exception traps.
2024-04-30 13:38:43 -07:00
Matt Colyer 3bcd40be12 Fix regression in apeinstall.sh (#1161)
This should have been a part of a6baba1.
2024-04-29 20:40:38 -07:00
Paul Kulchenko fcfdd26b72 Fix wrong parameter type in redbean documentation (#1162) 2024-04-29 20:09:25 -04:00
Justine Tunney 2b00ee8723 Fix errno.h documentation typos
Closes #1156
2024-04-28 22:57:21 -07:00
Justine Tunney ff2b6fc0b0 Add munlock() and mlock2() to pledge 2024-04-28 16:53:23 -07:00
Justine Tunney 0eef971494 Add much of C11 threads.h API 2024-04-28 07:04:08 -07:00
Gavin Hayes 2bfd6b37c1 Various paginate improvements (#1148)
* start on improving __paginate

* make __paginate more robust

* add __paginate_file

* cleanup __paginate unlinking
2024-04-26 23:12:25 -04:00
Gavin Hayes 69db501c68 Fix fork locking on win32 (#1141)
* Fix fork locking on win32

- __enable_threads / set __threaded in __proc_setup as threads are required for
  win32 subprocess management
- move mmi/fds locking out of pthread_atfork.c into fork.c so it's done anytime
  __threaded is set instead of being dependent of pthreads
- explicitly yoink _pthread_onfork_prepare, _pthread_onfork_parent, and
  _pthread_onfork_child in pthread_create.c so they are linked in in-case they
  are separated from _pthread_atfork

Big Thanks to @dfyz for help with locating the issue, testing, and devising a fix!

* fix child processes not being able to open files, initialize all necessary locks on fork
2024-04-25 23:01:27 -04:00
Jōshin 6e6fc38935 Apply clang-format update to repo (#1154)
Commit bc6c183 introduced a bunch of discrepancies between what files
look like in the repo and what clang-format says they should look like.
However, there were already a few discrepancies prior to that. Most of
these discrepancies seemed to be unintentional, but a few of them were
load-bearing (e.g., a #include that violated header ordering needing
something to have been #defined by a 'later' #include.)

I opted to take what I hope is a relatively smooth-brained approach: I
reverted the .clang-format change, ran clang-format on the whole repo,
reapplied the .clang-format change, reran clang-format again, and then
reverted the commit that contained the first run. Thus the full effect
of this PR should only be to apply the changed formatting rules to the
repo, and from skimming the results, this seems to be the case.

My work can be checked by applying the short, manual commits, and then
rerunning the command listed in the autogenerated commits (those whose
messages I have prefixed auto:) and seeing if your results agree.

It might be that the other diffs should be fixed at some point but I'm
leaving that aside for now.

fd '\.c(c|pp)?$' --print0| xargs -0 clang-format -i
2024-04-25 10:38:00 -07:00
Jōshin 342d0c81e5 vim spells the c++ filetype 'cpp' 2024-04-24 13:56:37 -07:00
Jōshin cec4c04aa1 Remove .com logic from GetProgramExecutableName (#1134)
The `com` parameter to `TryPath` was always 1, so there was no reason to
have it. This patch changes the logic to be as though `com` was 0, which
provides a possible answer to the TODO question -- the answer is no.

If we never care about appending `.com`, then `CopyWithCwd` doesn't need
to return anything beyond a boolean success value.
2024-04-23 22:07:19 -04:00
Alexey Izbyshev f8c0186221 Fix calling __dns_parse with potentially too large rlen
__res_send returns the full answer length even if it didn't fit the
buffer, but __dns_parse expects the length of the filled part of the
buffer.

Analogous to Musl commit 77327ed064bd57b0e1865cd0e0364057ff4a53b4 which
fixed the only other __dns_parse call site.
2024-04-23 09:36:07 -07:00
Quentin Rameau 6992d8c195 Remove arbitrary limit from DNS result parsing
The name resolution would abort when getting more than 63 records per
request, due to what seems to be a left-over from the original code.
This check was non-breaking but spurious prior to TCP fallback
support, since any 512-byte packet with more than 63 records was
necessarily malformed. But now, it wrongly rejects valid results.

Reported by Daniel Stefanik in Alpine Linux aports issue 15320.
2024-04-23 09:33:02 -07:00
Justine Tunney 1a6b4ab627 Import mntent bug fixes from Musl Libc
f314e133929b6379eccc632bef32eaebb66a7335
Author: Rich Felker <[email protected]>
Date:   Thu Nov 16 12:55:21 2023 -0500

    mntent: fields are delimited only by tabs or spaces, not general whitespace

    this matters because the kernel-provided mtab only escapes tabs,
    spaces, newlines, and backslashes. it leaves carriage returns, form
    feeds, and vertical tabs literal.

commit ee1d39bc1573c1ae49ee6b658938b56bbef95a6c
Author: q66 <[email protected]>
Date:   Thu Nov 9 20:48:44 2023 +0100

    mntent: unescape octal sequences

    As entries in mtab are delimited by spaces, whitespace characters
    are escaped as octal sequences. When reading them out, we have to
    unescape these sequences to get the proper string.
2024-04-23 09:29:56 -07:00
Justine Tunney 9e848abad9 Add missing Musl license headers 2024-04-23 09:29:46 -07:00
Justine Tunney 223eb358c4 Import compiler warning fix from Musl 2024-04-23 09:29:28 -07:00
Szabolcs Nagy ea3cc4ea0b math: fix fma(x,y,0) when x*y rounds to -0
if x!=0, y!=0, z==0 then

  fma(x,y,z) == x*y

in all rounding modes, while adding z can ruin the sign of 0 if x*y
rounds to -0.
2024-04-23 09:22:33 -07:00
Paul Kulchenko 01267ea0f5 Update GetRemoteAddr documentation to clarify that it may return nil. (#1149) 2024-04-22 01:55:08 -04:00
Justine Tunney bc6c18368f Update .clang-format 2024-04-19 17:11:08 -07:00
Jōshin 06839ab301 Change loop bound on uuidv4 test (#1143)
A half second (on my machine) is too long for a unit test. 1000
iterations is probably still overkill, but 0.01 seconds is fine.

Also made `y` local.
2024-04-12 12:22:34 -04:00
BONNAURE Olivier 39dde41516 [Redbean] Add UuidV4 method (#1140) 2024-04-12 11:10:27 -04:00
Jōshin 3e16e59f72 Move store after __asan_unpoison in __zipos_alloc (#1135)
Previously, the atomic store looked like it was happening while the
struct's memory was still poisoned. I was unable to observe any issues
with this, but this change seems to make the code more obviously correct
(at the cost of a redundant atomic store to zeroed space in case the map
needed to be extended.)
2024-04-10 23:04:03 -04:00
Justine Tunney cf9a1f7f33 Fix MODE=optlinux build 2024-04-06 21:02:19 -07:00
Justine Tunney 49a32136f8 Upgrade the One True Awk 2024-04-06 19:21:48 -07:00
Justine Tunney b9d6e6e348 Standardize on -fsigned-char
MaGuess on Discord pointed out the fact that cosmocc contradicts itself
on the signedness of `char`. It's up to each platform to choose one, so
the cosmo platform shall choose signed. The rationale is it makes the C
language syntax more internally similar. `char` should be `signed char`
for the same reason `int` means `signed int`. It's recommended that you
still assume `char` could go either way since that's portable thinking.
But if you want to assume we'll always have signed char, that's ok too.
2024-03-30 21:46:08 -07:00
Justine Tunney b431ca4449 Upgrade to cosmocc v3.3.3 2024-03-30 20:17:14 -07:00
3958 changed files with 242967 additions and 85292 deletions

No files matched your search

+2
View File
@@ -6,6 +6,8 @@ AlignConsecutiveMacros: true
AlignConsecutiveDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
AllowShortFunctionsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
KeepEmptyLinesAtTheStartOfBlocks: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
IncludeBlocks: Merge
+23
View File
@@ -0,0 +1,23 @@
# Run this command to always ignore formatting commits in git blame
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# Ran clang-format
f032b5570b4cd87c6bb4abb54c0b98e69c939955
# Applied clang-format update to repo
6e6fc38935054db0534d5af4fb99c6193305b946
# revert retabbing
2b315626f3af765cdfbc61114647412cdb798b3a
# more modeline errata
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
# fix more vi modelines
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
# flip et/noet in modelines
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
# fix vi modelines
394d998315f613a888cc6b6c051d4163bdf5cd6f
# clang-format
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
# ape-m1 formatting cleanup
da8baf2aa5ce93b958aca90a0ae69f537806324b
# Run clang-format on most sources
369f9740de4534c28d0e81ab2afc99decbb9a3e6
-108
View File
@@ -1,108 +0,0 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "c11",
"cppStandard": "c++11",
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
"defines": [
"libcesque=",
"pureconst=",
"paramsnonnull(x)=",
"alignas(x)",
"alignof(x)",
"artificial=",
"__wur=",
"mayalias=",
"forceinline=",
"forcealign(x)=",
"scanfesque(x)=",
"strftimeesque(x)=",
"wontreturn=",
"textreal=",
"mallocesque=",
"callocesque=",
"vallocesque=",
"reallocesque=",
"strlenesque=",
"memcpyesque=",
"hasatleast=",
"noinline=",
"textexit=",
"returnstwice=",
"textwindows=",
"privileged=",
"dontinstrument=",
"nodebuginfo=",
"interruptfn=",
"optimizespeed=",
"forcealignargpointer=",
"dontasan=",
"dontubsan=",
"donothing=",
"nosideeffect=",
"unreachable=",,
"notpossible=",
"thatispacked=",
"dontthrow=",
"dontcallback=",
"relegated=",
"hidden=",
"textstartup=",
"returnsnonnull=",
"returnspointerwithnoaliases=",
"printfesque(x)=",
"attributeallocsize(x)=",
"returnsaligned(x)=",
"attributeallocalign(x)=",
"nullterminated(x)="
]
},
{
"name": "Linux",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "gnu17",
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
"compilerArgs": [
"-Wall",
"-Werror",
"-fdebug-prefix-map=${workspaceFolder}=",
"-frecord-gcc-switches",
"-Wa,-W",
"-Wa,-I.",
"-Wa,--noexecstack",
"-Og",
"-g",
"-gdescribe-dies",
"-msse3",
"-mno-red-zone",
"-fno-math-errno",
"-fno-trapping-math",
"-fno-fp-int-builtin-inexact",
"-fno-ident",
"-fno-common",
"-fno-gnu-unique",
"-fstrict-aliasing",
"-fstrict-overflow",
"-fno-semantic-interposition",
"-mno-omit-leaf-frame-pointer",
"-fno-jump-tables",
"-nostdinc",
"-iquote."
],
"forcedInclude": [
"libc/integral/normalize.inc"
],
"defines": [
"COSMO",
"MODE="
]
}
],
"version": 4
}
-2
View File
@@ -1,2 +0,0 @@
#define __VSCODE_INTELLISENSE__ 1
#include "libc/integral/normalize.inc"
+10 -17
View File
@@ -133,7 +133,7 @@ endif
ifneq ($(findstring aarch64,$(MODE)),)
ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
HOSTS ?= pi studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
@@ -149,9 +149,9 @@ export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
COSMOCC = .cosmocc/3.3.2
COSMOCC = .cosmocc/3.3.5
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.2 a695012ffbeac5e26e3c4a740debc15273f47e9a8bdc55e8b76a623154d5914b)
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.5 db78fd8d3f8706e9dff4be72bf71d37a3f12062f212f407e1c33bc4af3780dd0)
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
@@ -174,6 +174,7 @@ all: o
o: o/$(MODE)
o/$(MODE): \
o/$(MODE)/ape \
o/$(MODE)/ctl \
o/$(MODE)/dsp \
o/$(MODE)/net \
o/$(MODE)/libc \
@@ -255,10 +256,11 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include ctl/BUILD.mk # │
include third_party/zlib/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
include libc/time/BUILD.mk # │
include third_party/tz/BUILD.mk # │
include net/BUILD.mk # │
include third_party/vqsort/BUILD.mk # │
include libc/log/BUILD.mk # │
@@ -299,6 +301,7 @@ include tool/viz/lib/BUILD.mk
include tool/args/BUILD.mk
include test/math/BUILD.mk
include test/posix/BUILD.mk
include test/ctl/BUILD.mk
include test/libcxx/BUILD.mk
include test/tool/args/BUILD.mk
include third_party/linenoise/BUILD.mk
@@ -362,7 +365,6 @@ include test/libc/fmt/BUILD.mk
include test/libc/time/BUILD.mk
include test/libc/proc/BUILD.mk
include test/libc/stdio/BUILD.mk
include test/libc/release/BUILD.mk
include test/libc/BUILD.mk
include test/net/http/BUILD.mk
include test/net/https/BUILD.mk
@@ -440,7 +442,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
LIBC_TIME \
THIRD_PARTY_TZ \
THIRD_PARTY_OPENMP \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB_GZ \
@@ -452,6 +454,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_THREAD \
LIBC_PROC \
THIRD_PARTY_NSYNC_MEM \
CTL \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_DLOPEN \
@@ -505,7 +508,6 @@ COSMOPOLITAN_H_PKGS = \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
LIBC_VGA \
@@ -521,6 +523,7 @@ COSMOPOLITAN_H_PKGS = \
COSMOCC_PKGS = \
$(COSMOPOLITAN_H_PKGS) \
CTL \
THIRD_PARTY_AARCH64 \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
@@ -543,15 +546,6 @@ COSMOPOLITAN_H_ROOT_HDRS = \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
o/cosmopolitan.h.txt: Makefile
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
o/cosmopolitan.h: o/cosmopolitan.h.txt \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup @$< >>$@
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.dbg \
@@ -573,7 +567,6 @@ $(SRCS): \
ifeq ($(ARCH), x86_64)
TOOLCHAIN_ARTIFACTS = \
o/cosmopolitan.h \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/ape/ape.elf \
+18 -1
View File
@@ -254,7 +254,24 @@ o/$(MODE)/ape: $(APE_CHECKS) \
endif
# these assembly files are safe to build on aarch64
o/$(MODE)/ape/ape.o: ape/ape.S
o/$(MODE)/ape/ape.o: \
ape/ape.S \
ape/ape.h \
libc/dce.h \
libc/elf/def.h \
ape/relocations.h \
libc/thread/tls.h \
ape/ape.internal.h \
ape/macros.internal.h \
libc/macho.internal.h \
libc/macros.internal.h \
libc/sysv/consts/prot.h \
libc/nt/pedef.internal.h \
libc/runtime/pc.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/ape/ape.lds: \
+3 -4
View File
@@ -293,7 +293,6 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
+82 -29
View File
@@ -31,6 +31,8 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
@@ -39,7 +41,7 @@
/* maximum path size that cosmo can take */
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
#define SYSLIB_VERSION 9 /* sync with libc/runtime/syslib.internal.h */
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
struct Syslib {
int magic;
@@ -106,6 +108,10 @@ struct Syslib {
OPTIONAL (cosmo lib should check __syslib->version) */
/* v9 (2024-01-31) */
int (*pthread_cpu_number_np)(size_t *);
/* v10 (2024-05-02) */
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
long (*sysctlnametomib)(const char *, int *, size_t *);
};
#define ELFCLASS32 1
@@ -140,6 +146,9 @@ struct Syslib {
#define AT_RANDOM 25
#define AT_EXECFN 31
#define EF_APE_MODERN 0x101ca75
#define EF_APE_MODERN_MASK 0x1ffffff
#define AUXV_WORDS 31
/* from the xnu codebase */
@@ -148,8 +157,8 @@ struct Syslib {
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
#define READ32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
@@ -221,13 +230,15 @@ struct ApeLoader {
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
while (*s++)
++n;
return n;
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255);
}
@@ -276,7 +287,8 @@ static char *Utoa(char p[21], unsigned long x) {
}
static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x;
if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x);
}
@@ -312,7 +324,8 @@ static int GetIndirectOffset(const char *arg0) {
static void Perror(const char *thing, long rc, const char *reason) {
char ibuf[21];
ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc);
if (rc)
Itoa(ibuf, -rc);
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
ibuf, "\n", 0l);
}
@@ -327,7 +340,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
return 0;
}
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
memmove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0;
return !access(ps->path, X_OK);
@@ -377,8 +391,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
ps->name = name;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
if (FindCommand(ps)) {
return ps->path;
} else {
@@ -545,6 +561,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
}
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen) {
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
}
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
void *newp, size_t newlen) {
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
}
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
return sysret(sysctlnametomib(name, mibp, sizep));
}
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
long *sp, struct ElfEhdr *e,
struct ElfPhdr *p,
@@ -585,10 +615,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr & -pagesz;
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue;
if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) {
if (Max(a, c) < Min(b, d)) {
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
}
}
@@ -614,7 +645,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
if (e->e_type == ET_DYN) {
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (rc < 0) Pexit(exe, rc, "pie mmap");
if (rc < 0)
Pexit(exe, rc, "pie mmap");
dynbase = rc;
if (dynbase & (pagesz - 1)) {
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@@ -630,14 +662,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) {
void *addr;
unsigned long size;
if (p[i].p_type != PT_LOAD) continue;
if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */
prot = 0;
flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ;
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
if (p[i].p_flags & PF_R)
prot |= PROT_READ;
if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
/* load from file */
if (p[i].p_filesz) {
@@ -657,7 +693,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
wipe = MIN(b - a, c - a);
wipe = Min(b - a, c - a);
if (wipe && (~prot1 & PROT_WRITE)) {
prot1 = PROT_READ | PROT_WRITE;
}
@@ -687,24 +723,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
as the default strategy which is slow but it works for both */
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
if (rc < 0)
Pexit(exe, rc, "prog mmap anon");
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
if (rc != p[i].p_filesz)
Pexit(exe, -errno, "prog pread");
#endif
} else {
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
if (rc < 0) Pexit(exe, rc, "prog mmap");
if (rc < 0)
Pexit(exe, rc, "prog mmap");
}
if (wipe) memset((void *)(dynbase + a), 0, wipe);
if (wipe)
memset((void *)(dynbase + a), 0, wipe);
if (prot2 != prot1) {
rc = sys_mprotect(addr, size, prot2);
if (rc < 0) Pexit(exe, rc, "prog mprotect");
if (rc < 0)
Pexit(exe, rc, "prog mprotect");
}
/* allocate extra bss */
if (c > b) {
flags |= MAP_ANONYMOUS;
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
if (rc < 0)
Pexit(exe, rc, "extra bss mmap");
}
} else {
/* allocate pure bss */
@@ -712,7 +754,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS;
rc = sys_mmap(addr, size, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "bss mmap");
if (rc < 0)
Pexit(exe, rc, "bss mmap");
}
}
@@ -759,7 +802,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
}
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
const char *exe, int fd, long *sp, long *auxv,
char *exe, int fd, long *sp, long *auxv,
char *execfn) {
long i, rc;
unsigned size;
@@ -780,6 +823,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
if (e->e_machine != EM_AARCH64) {
return "couldn't find ELF header with ARM64 machine type";
}
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
/* change argv[0] to resolved path for older binaries */
((char **)(sp + 1))[0] = exe;
}
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
Pexit(exe, 0, "e_phentsize is wrong");
}
@@ -790,8 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
if (rc < 0) return "failed to read ELF program headers";
if (rc != size) return "truncated read of ELF program headers";
if (rc < 0)
return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */
p = &M->phdr.phdr;
@@ -948,6 +997,9 @@ int main(int argc, char **argv, char **envp) {
M->lib.dlclose = dlclose;
M->lib.dlerror = dlerror;
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
M->lib.sysctl = sys_sysctl;
M->lib.sysctlbyname = sys_sysctlbyname;
M->lib.sysctlnametomib = sys_sysctlnametomib;
/* getenv("_") is close enough to at_execfn */
execfn = 0;
@@ -970,7 +1022,8 @@ int main(int argc, char **argv, char **envp) {
grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}
+4 -4
View File
@@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 nofixeol :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
@@ -196,7 +196,7 @@ ape_mz:
.quad ape_elf_entry // 18: e_entry
.quad ape_elf_phoff // 20: e_phoff
.quad ape_elf_shoff // 28: e_shoff
.long 0 // 30: e_flags
.long 0x101ca75 // 30: ape e_flags
.short 64 // 34: e_ehsize
.short 56 // 36: e_phentsize
.short ape_elf_phnum // 38: e_phnum
@@ -669,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.shstub ape_elf_entry,8 // 18: e_entry
.shstub ape_elf_phoff,8 // 20: e_phoff
.shstub ape_elf_shoff,8 // 28: e_shoff
.ascii "\\0\\0\\0\\0" // 30: e_flags
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
.ascii "\\100\\0" // 34: e_ehsize
.ascii "\\070\\0" // 36: e_phentsize
.shstub ape_elf_phnum,2 // 38: e_phnum
@@ -1036,7 +1036,7 @@ ape_pe: .ascin "PE",4
.quad ape_pe_base // ImageBase
.long ape_pe_sectionalignment // SectionAlignment
.long ape_pe_filealignment // FileAlignment
.short v_ntversion // MajorOperatingSystemVersion
.short 10 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion
.short 0 // MinorImageVersion
+3 -2
View File
@@ -553,7 +553,9 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = 1;
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
ape_cod_offset = 0;
ape_cod_vaddr = ADDR(.head);
@@ -713,7 +715,6 @@ ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
v_ntversion = LINK_WINDOWS ? 6 : 1;
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
v_ntsubsystem = (LINK_WINDOWS
+13 -6
View File
@@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x build/bootstrap/make.com ]; then
MAKE=build/bootstrap/make.com
if [ -x build/bootstrap/make ]; then
MAKE=build/bootstrap/make
else
MAKE=make
fi
@@ -137,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
echo done >&2
fi
uname_r="$(uname -r)"
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
FLAGS=FP
else
FLAGS=F
fi
echo >&2
echo registering APE with binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
+67 -30
View File
@@ -152,6 +152,9 @@
#define PR_SET_MM 35
#define PR_SET_MM_EXE_FILE 13
#define EF_APE_MODERN 0x101ca75
#define EF_APE_MODERN_MASK 0x1ffffff
#define READ32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
@@ -228,13 +231,15 @@ extern char _end[];
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
while (*s++)
++n;
return n;
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255);
}
@@ -353,7 +358,8 @@ static char *Utoa(char p[20], unsigned long x) {
}
static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x;
if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x);
}
@@ -362,7 +368,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
long arg5, long arg6,
long arg7, int numba,
char os) {
if (IsXnu()) numba |= 0x2000000;
if (IsXnu())
numba |= 0x2000000;
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
}
@@ -529,7 +536,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
switch ((c = *fmt++)) {
case 's':
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
if (k < 512) b[k++] = *s;
if (k < 512)
b[k++] = *s;
}
break;
case 'd':
@@ -542,16 +550,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
u -= 10;
c = 'a' + u;
}
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
}
break;
default:
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
break;
}
break;
default:
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
break;
}
}
@@ -560,7 +571,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
static void Perror(int os, const char *thing, long rc, const char *reason) {
char ibuf[21];
ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc);
if (rc)
Itoa(ibuf, -rc);
Print(os, 2, "ape error: ", thing, ": ", reason,
rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
}
@@ -572,8 +584,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
}
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
return 0;
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
MemMove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0;
return !Access(ps->path, X_OK, ps->os);
@@ -600,11 +614,14 @@ static char SearchPath(struct PathSearcher *ps) {
static char *Commandv(struct PathSearcher *ps, int os, char *name,
const char *syspath) {
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
if (!(ps->namelen = StrLen((ps->name = name))))
return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
return name;
ps->os = os;
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
ps->path[0] = 0;
if (SearchPath(ps)) {
return ps->path;
@@ -661,7 +678,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
Pexit(os, exe, 0, "ELF segments overlap your APE loader");
}
for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue;
if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) {
@@ -694,7 +712,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
if (e->e_type == ET_DYN) {
rc = Mmap(0, virtmax - virtmin, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "pie mmap");
if (rc < 0)
Pexit(os, exe, rc, "pie mmap");
dynbase = rc;
if (dynbase & (pagesz - 1)) {
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@@ -710,14 +729,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) {
void *addr;
unsigned long size;
if (p[i].p_type != PT_LOAD) continue;
if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */
prot = 0;
flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ;
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
if (p[i].p_flags & PF_R)
prot |= PROT_READ;
if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
if (p[i].p_filesz) {
/* load from file */
@@ -744,17 +767,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
if (wipe) Bzero((void *)(dynbase + a), wipe);
if (rc < 0)
Pexit(os, exe, rc, "prog mmap");
if (wipe)
Bzero((void *)(dynbase + a), wipe);
if (prot2 != prot1) {
rc = Mprotect(addr, size, prot2, os);
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
if (rc < 0)
Pexit(os, exe, rc, "prog mprotect");
}
/* allocate extra bss */
if (c > b) {
flags |= MAP_ANONYMOUS;
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
if (rc < 0)
Pexit(os, exe, rc, "extra bss mmap");
}
} else {
/* allocate pure bss */
@@ -762,7 +789,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS;
rc = Mmap(addr, size, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
if (rc < 0)
Pexit(os, exe, rc, "bss mmap");
}
}
@@ -783,7 +811,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
struct ElfPhdr *p;
/* validate page size */
if (!pagesz) pagesz = 4096;
if (!pagesz)
pagesz = 4096;
if (pagesz & (pagesz - 1)) {
Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
}
@@ -808,6 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
return "couldn't find ELF header with x86-64 machine type";
}
#endif
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
/* change argv[0] to resolved path for older binaries */
((char **)(sp + 1))[0] = exe;
}
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
Pexit(os, exe, 0, "e_phentsize is wrong");
}
@@ -818,8 +851,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
if (rc < 0) return "failed to read ELF program headers";
if (rc != size) return "truncated read of ELF program headers";
if (rc < 0)
return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */
p = &M->phdr.phdr;
@@ -949,7 +984,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
/* determine ape loader program name */
ape = argv[0];
if (!ape) ape = "ape";
if (!ape)
ape = "ape";
/* detect openbsd */
if (SupportsOpenbsd() && !os && !auxv[0]) {
@@ -1021,7 +1057,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
grows down the alloc by poking the guard pages */
n = (endp - sp + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}
+15 -26
View File
@@ -132,7 +132,7 @@
#define SHSTUB2(SYM, X) \
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
#define BCD_SMEAR(X) ((X) + (X) * 10000)
#define BCD_SMEAR(X) ((X) + (X)*10000)
#define BCD_LEFT(X) \
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
@@ -140,23 +140,16 @@
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
: 0xffffffffffffffff)
#define BCD_RIGHT(X) \
(((X)) < 10000 ? 0x20202020 \
: (X) < 100000 ? 0x20202030 + \
(X) % 10 \
: (X) < 1000000 ? 0x20203030 + \
((X) / 10) % 10 + \
(X) % 10 * 0x100 \
: (X) < 10000000 ? 0x20303030 + \
((X) / 100) % 10 + \
((X) / 10) % 10 * 0x100 + \
(X) % 10 * 0x10000 \
: (X) < 100000000 ? 0x30303030 + \
((X) / 1000) % 10 + \
((X) / 100) % 10 * 0x100 + \
((X) / 10) % 10 * 0x10000 + \
(X) % 10 * 0x1000000 \
: 0xffffffffffffffff)
#define BCD_RIGHT(X) \
(((X)) < 10000 ? 0x20202020 \
: (X) < 100000 ? 0x20202030 + (X) % 10 \
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
: (X) < 100000000 \
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
: 0xffffffffffffffff)
/**
* Laying out the GDT entries for a TSS for bare metal operation.
@@ -165,15 +158,11 @@
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 | \
#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)
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
#endif /* __ASSEMBLER__ */
#endif /* APE_MACROS_H_ */
+2
View File
@@ -16,6 +16,8 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
extern unsigned char _tbss_start[] __attribute__((__weak__));
extern unsigned char _tbss_end[] __attribute__((__weak__));
extern unsigned char _tls_align[] __attribute__((__weak__));
extern unsigned char _tdata_align[] __attribute__((__weak__));
extern unsigned char _tbss_align[] __attribute__((__weak__));
extern unsigned char __test_start[] __attribute__((__weak__));
extern unsigned char __ro[] __attribute__((__weak__));
extern unsigned char __data_start[] __attribute__((__weak__));
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11 -11
View File
@@ -11,20 +11,20 @@
#
ifeq ($(MODE),)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
TARGET_ARCH ?= -msse3
endif
ifeq ($(MODE), x86_64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
@@ -38,13 +38,13 @@ endif
#
ifeq ($(MODE), zero)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64-zero)
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0 -fdce
OVERRIDE_CXXFLAGS += -O0 -fdce
CONFIG_CPPFLAGS += -DSYSDEBUG
@@ -81,7 +81,7 @@ endif
#
ifeq ($(MODE), opt)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
TARGET_ARCH ?= -march=native
@@ -98,7 +98,7 @@ endif
# - Turns off support for other operating systems
#
ifeq ($(MODE), optlinux)
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
@@ -140,7 +140,7 @@ endif
#
ifeq ($(MODE), asan)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
CONFIG_COPTS += -fsanitize=address
@@ -160,7 +160,7 @@ endif
#
ifeq ($(MODE), dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
@@ -170,7 +170,7 @@ QUOTA ?= -C64 -L300
endif
ifeq ($(MODE), aarch64-dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
CONFIG_COPTS += -fsanitize=undefined
@@ -189,7 +189,7 @@ endif
#
ifeq ($(MODE), sysv)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
TARGET_ARCH ?= -msse3
+7 -7
View File
@@ -60,13 +60,10 @@ TMPSAFE = $(TMPDIR)/
endif
BACKTRACES = \
-fno-schedule-insns2 \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer
ifneq ($(ARCH), aarch64)
BACKTRACES += -fno-schedule-insns2
endif
SANITIZER = \
-fsanitize=address
@@ -127,6 +124,7 @@ ifeq ($(ARCH), aarch64)
DEFAULT_COPTS += \
-ffixed-x18 \
-ffixed-x28 \
-fsigned-char \
-mno-outline-atomics
endif
@@ -147,12 +145,14 @@ DEFAULT_CFLAGS = \
-std=gnu2x
DEFAULT_CXXFLAGS = \
-std=gnu++20 \
-fno-rtti \
-fno-exceptions \
-fuse-cxa-atexit \
-Wno-int-in-bool-context \
-Wno-narrowing \
-Wno-literal-suffix
-Wno-literal-suffix \
-isystem third_party/libcxx
DEFAULT_ASFLAGS = \
-W \
@@ -259,12 +259,12 @@ LD.libs = \
$(LIBS)
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
+8 -8
View File
@@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
fi
find_objdump() {
if [ -x .cosmocc/3.3.2/bin/$1-linux-cosmo-objdump ]; then
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump
elif [ -x .cosmocc/3.3.2/bin/$1-linux-musl-objdump ]; then
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-musl-objdump
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump"
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump"
if [ -x .cosmocc/3.3.5/bin/$1-linux-cosmo-objdump ]; then
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump
elif [ -x .cosmocc/3.3.5/bin/$1-linux-musl-objdump ]; then
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-musl-objdump
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump"
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump"
else
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
exit 1
+24 -12
View File
@@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
}
static char *FormatInt32(char *p, int32_t x) {
if (x < 0) *p++ = '-', x = -(uint32_t)x;
if (x < 0)
*p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x);
}
@@ -205,7 +206,8 @@ static size_t StrCat(char *dst, const char *src, size_t dsize) {
size_t m, n = dsize;
const char *p = dst;
const char *q = src;
while (n-- != 0 && *dst != '\0') dst++;
while (n-- != 0 && *dst != '\0')
dst++;
m = dst - p;
n = dsize - m;
if (n-- == 0) {
@@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
for (i = 0;; ++i) {
switch (path[i]) {
case 0:
if (i) return true;
if (i)
return true;
// fallthrough
case '\r':
case '\n':
@@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
char hexdigest[65];
char mode[2] = {g_mode};
unsigned char digest[32];
if (!IsSupportedPath(path)) return false;
if (!GetDigest(path, f, digest)) return false;
if (!IsSupportedPath(path))
return false;
if (!GetDigest(path, f, digest))
return false;
CopyHex(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL);
return true;
@@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
uint8_t wantdigest[32], gotdigest[32];
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
if (!*Chomp(buf)) continue;
if (!*Chomp(buf))
continue;
for (p = buf, i = 0; i < 32; ++i) {
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
if ((a = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
wantdigest[i] = a << 4 | b;
}
if (*p++ != ' ') goto InvalidLine;
if (!IsModeCharacter(*p++)) goto InvalidLine;
if (*p++ != ' ')
goto InvalidLine;
if (!IsModeCharacter(*p++))
goto InvalidLine;
path2 = p;
if (!*path2) goto InvalidLine;
if (!IsSupportedPath(path2)) continue;
if (!*path2)
goto InvalidLine;
if (!IsSupportedPath(path2))
continue;
if ((f2 = fopen(path2, "rb"))) {
if (GetDigest(path2, f2, gotdigest)) {
if (!memcmp(wantdigest, gotdigest, 32)) {
+13
View File
@@ -0,0 +1,13 @@
---
BasedOnStyle: Mozilla
IndentWidth: 4
ColumnLimit: 80
---
Language: Cpp
AllowShortFunctionsOnASingleLine: false
AlignTrailingComments: false
AlignEscapedNewlines: DontAlign
AlwaysBreakTemplateDeclarations: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
FixNamespaceComments: true
---
+48
View File
@@ -0,0 +1,48 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += CTL
CTL_ARTIFACTS += CTL_A
CTL = $(CTL_A_DEPS) $(CTL_A)
CTL_A = o/$(MODE)/ctl/ctl.a
CTL_A_FILES := $(wildcard ctl/*)
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
CTL_A_CHECKS = \
$(CTL_A).pkg \
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
CTL_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STR \
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
$(CTL_A): ctl/ \
$(CTL_A).pkg \
$(CTL_A_OBJS)
$(CTL_A).pkg: \
$(CTL_A_OBJS) \
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
$(CTL_A_OBJS): private \
OVERRIDE_CXXFLAGS += \
-Wframe-larger-than=4096 \
-Walloca-larger-than=4096 \
-ffunction-sections \
-fdata-sections \
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
.PHONY: o/$(MODE)/ctl
o/$(MODE)/ctl: $(CTL_CHECKS)
+5015
View File
File diff suppressed because it is too large. Load diff
+129
View File
@@ -0,0 +1,129 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
#define COSMOPOLITAN_CTL_OPTIONAL_H_
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
namespace ctl {
template<typename T>
class optional
{
public:
using value_type = T;
~optional() = default;
optional() noexcept : present_(false)
{
}
optional(const T& value) : present_(true), value_(value)
{
}
optional(T&& value) : present_(true), value_(std::move(value))
{
}
optional(const optional& other) : present_(other.present_)
{
if (present_)
new (&value_) T(other.value_);
}
optional(optional&& other) noexcept : present_(other.present_)
{
if (present_)
value_ = std::move(other.value_);
}
optional& operator=(const optional& other)
{
if (this != &other) {
present_ = other.present_;
if (present_)
value_ = other.value_;
}
return *this;
}
optional& operator=(optional&& other) noexcept
{
if (this != &other) {
present_ = other.present_;
if (present_)
value_ = std::move(other.value_);
}
return *this;
}
T& value() &
{
if (!present_)
__builtin_trap();
return value_;
}
const T& value() const&
{
if (!present_)
__builtin_trap();
return value_;
}
T&& value() &&
{
if (!present_)
__builtin_trap();
return std::move(value_);
}
explicit operator bool() const noexcept
{
return present_;
}
bool has_value() const noexcept
{
return present_;
}
void reset() noexcept
{
if (present_) {
value_.~T();
present_ = false;
}
}
template<typename... Args>
void emplace(Args&&... args)
{
present_ = true;
value_ = T(std::forward<Args>(args)...);
}
void swap(optional& other) noexcept
{
if (present_ && other.present_) {
std::swap(value_, other.value_);
} else if (present_) {
other.emplace(std::move(value_));
reset();
} else if (other.present_) {
emplace(std::move(other.value_));
other.reset();
}
}
private:
bool present_;
T value_;
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
+44
View File
@@ -0,0 +1,44 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 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 "string.h"
#include <stdckdint.h>
#include <string.h>
namespace ctl {
string
strcat(const string_view lhs, const string_view rhs) noexcept
{
string res;
size_t need;
if (ckd_add(&need, lhs.n, rhs.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
res.reserve(need);
if (lhs.n)
memcpy(res.p, lhs.p, lhs.n);
if (rhs.n)
memcpy(res.p + lhs.n, rhs.p, rhs.n);
res.p[res.n = lhs.n + rhs.n] = 0;
return res;
}
} // namespace ctl
+43
View File
@@ -0,0 +1,43 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 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 "string_view.h"
#include <string.h>
namespace ctl {
int
strcmp(const string_view lhs, const string_view rhs) noexcept
{
int r;
size_t m = lhs.n;
if ((m = rhs.n < m ? rhs.n : m)) {
if (!m)
return 0;
if ((r = memcmp(lhs.p, rhs.p, m)))
return r;
}
if (lhs.n == rhs.n)
return 0;
if (m < lhs.n)
return +1;
return -1;
}
} // namespace ctl
+323
View File
@@ -0,0 +1,323 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 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 "string.h"
#include <__atomic/fence.h>
#include <stdckdint.h>
namespace ctl {
string::~string() noexcept
{
if (n) {
if (n >= c)
__builtin_trap();
if (p[n])
__builtin_trap();
}
if (c && !p)
__builtin_trap();
free(p);
}
string::string(const char* s) noexcept
{
append(s, strlen(s));
}
string::string(const string& s) noexcept
{
append(s.p, s.n);
}
string::string(const string_view s) noexcept
{
append(s.p, s.n);
}
string::string(size_t size, char ch) noexcept
{
resize(size, ch);
}
string::string(const char* s, size_t size) noexcept
{
append(s, size);
}
const char*
string::c_str() const noexcept
{
if (!n)
return "";
if (n >= c)
__builtin_trap();
if (p[n])
__builtin_trap();
return p;
}
void
string::reserve(size_t c2) noexcept
{
char* p2;
if (c2 < n)
c2 = n;
if (ckd_add(&c2, c2, 15))
__builtin_trap();
c2 &= -16;
if (!(p2 = (char*)realloc(p, c2)))
__builtin_trap();
std::atomic_signal_fence(std::memory_order_seq_cst);
c = c2;
p = p2;
}
void
string::resize(size_t n2, char ch) noexcept
{
size_t c2;
if (ckd_add(&c2, n2, 1))
__builtin_trap();
reserve(c2);
if (n2 > n)
memset(p + n, ch, n2 - n);
p[n = n2] = 0;
}
void
string::append(char ch) noexcept
{
if (n + 2 > c) {
size_t c2 = c + 2;
c2 += c2 >> 1;
reserve(c2);
}
p[n++] = ch;
p[n] = 0;
}
void
string::grow(size_t size) noexcept
{
size_t need;
if (ckd_add(&need, n, size))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
if (need <= c)
return;
size_t c2 = c;
if (!c2) {
c2 = need;
} else {
while (c2 < need)
if (ckd_add(&c2, c2, c2 >> 1))
__builtin_trap();
}
reserve(c2);
}
void
string::append(char ch, size_t size) noexcept
{
grow(size);
if (size)
memset(p + n, ch, size);
p[n += size] = 0;
}
void
string::append(const void* data, size_t size) noexcept
{
grow(size);
if (size)
memcpy(p + n, data, size);
p[n += size] = 0;
}
void
string::pop_back() noexcept
{
if (!n)
__builtin_trap();
p[--n] = 0;
}
string&
string::operator=(string&& s) noexcept
{
if (p != s.p) {
if (p) {
clear();
append(s.p, s.n);
} else {
p = s.p;
n = s.n;
c = s.c;
s.p = nullptr;
s.n = 0;
s.c = 0;
}
}
return *this;
}
bool
string::operator==(const string_view s) const noexcept
{
if (n != s.n)
return false;
if (!n)
return true;
return !memcmp(p, s.p, n);
}
bool
string::operator!=(const string_view s) const noexcept
{
if (n != s.n)
return true;
if (!n)
return false;
return !!memcmp(p, s.p, n);
}
bool
string::contains(const string_view s) const noexcept
{
if (!s.n)
return true;
return !!memmem(p, n, s.p, s.n);
}
bool
string::ends_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p + n - s.n, s.p, s.n);
}
bool
string::starts_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p, s.p, s.n);
}
size_t
string::find(char ch, size_t pos) const noexcept
{
char* q;
if ((q = (char*)memchr(p, ch, n)))
return q - p;
return npos;
}
size_t
string::find(const string_view s, size_t pos) const noexcept
{
char* q;
if (pos > n)
__builtin_trap();
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
return q - p;
return npos;
}
string
string::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
if (ckd_add(&last, pos, count))
last = n;
if (last > n)
__builtin_trap();
return string(p + pos, count);
}
string&
string::replace(size_t pos, size_t count, const string_view& s) noexcept
{
size_t last;
if (ckd_add(&last, pos, count))
__builtin_trap();
if (last > n)
__builtin_trap();
size_t need;
if (ckd_add(&need, pos, s.n))
__builtin_trap();
size_t extra = n - last;
if (ckd_add(&need, need, extra))
__builtin_trap();
size_t c2;
if (ckd_add(&c2, need, 1))
__builtin_trap();
reserve(c2);
if (extra)
memmove(p + pos + s.n, p + last, extra);
memcpy(p + pos, s.p, s.n);
p[n = need] = 0;
return *this;
}
string&
string::insert(size_t i, const string_view s) noexcept
{
if (i > n)
__builtin_trap();
size_t extra = n - i;
size_t need;
if (ckd_add(&need, n, s.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
reserve(need);
if (extra)
memmove(p + i + s.n, p + i, extra);
memcpy(p + i, s.p, s.n);
p[n += s.n] = 0;
return *this;
}
string&
string::erase(size_t pos, size_t count) noexcept
{
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
size_t extra = n - (pos + count);
if (extra)
memmove(p + pos, p + pos + count, extra);
p[n = pos + extra] = 0;
return *this;
}
} // namespace ctl
+236
View File
@@ -0,0 +1,236 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRING_H_
#define COSMOPOLITAN_CTL_STRING_H_
#include "string_view.h"
namespace ctl {
struct string;
string
strcat(const string_view, const string_view) noexcept __wur;
struct string
{
char* p = nullptr;
size_t n = 0;
size_t c = 0;
using iterator = char*;
using const_iterator = const char*;
static constexpr size_t npos = -1;
~string() noexcept;
string() = default;
string(const string_view) noexcept;
string(const char*) noexcept;
string(const string&) noexcept;
string(const char*, size_t) noexcept;
explicit string(size_t, char = 0) noexcept;
string& operator=(string&&) noexcept;
const char* c_str() const noexcept;
void pop_back() noexcept;
void grow(size_t) noexcept;
void reserve(size_t) noexcept;
void resize(size_t, char = 0) noexcept;
void append(char) noexcept;
void append(char, size_t) noexcept;
void append(unsigned long) noexcept;
void append(const void*, size_t) noexcept;
string& insert(size_t, const string_view) noexcept;
string& erase(size_t = 0, size_t = npos) noexcept;
string substr(size_t = 0, size_t = npos) const noexcept;
string& replace(size_t, size_t, const string_view&) noexcept;
bool operator==(const string_view) const noexcept;
bool operator!=(const string_view) const noexcept;
bool contains(const string_view) const noexcept;
bool ends_with(const string_view) const noexcept;
bool starts_with(const string_view) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const string_view, size_t = 0) const noexcept;
string(string&& s) noexcept : p(s.p), n(s.n), c(s.c)
{
s.p = nullptr;
s.n = 0;
s.c = 0;
}
void clear() noexcept
{
n = 0;
}
bool empty() const noexcept
{
return !n;
}
char* data() const noexcept
{
return p;
}
size_t size() const noexcept
{
return n;
}
size_t length() const noexcept
{
return n;
}
size_t capacity() const noexcept
{
return c;
}
iterator begin() noexcept
{
return p;
}
iterator end() noexcept
{
return p + n;
}
const_iterator cbegin() const noexcept
{
return p;
}
const_iterator cend() const noexcept
{
return p + n;
}
char& front()
{
if (!n)
__builtin_trap();
return p[0];
}
const char& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
char& back()
{
if (!n)
__builtin_trap();
return p[n - 1];
}
const char& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
char& operator[](size_t i) noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
const char& operator[](size_t i) const noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
void push_back(char ch) noexcept
{
append(ch);
}
void append(const string_view s) noexcept
{
append(s.p, s.n);
}
inline constexpr operator string_view() const noexcept
{
return string_view(p, n);
}
string& operator=(const char* s) noexcept
{
clear();
append(s);
return *this;
}
string& operator=(const string_view s) noexcept
{
clear();
append(s);
return *this;
}
string& operator+=(char x) noexcept
{
append(x);
return *this;
}
string& operator+=(const string_view s) noexcept
{
append(s);
return *this;
}
string operator+(const string_view s) const noexcept
{
return strcat(*this, s);
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view s) const noexcept
{
return compare(s) >= 0;
}
};
} // namespace ctl
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wliteral-suffix"
inline ctl::string
operator"" s(const char* s, size_t n)
{
return ctl::string(s, n);
}
#pragma GCC diagnostic pop
#endif // COSMOPOLITAN_CTL_STRING_H_
+111
View File
@@ -0,0 +1,111 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 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 "string_view.h"
#include <stdckdint.h>
#include <string.h>
#include "string.h"
namespace ctl {
size_t
string_view::find(char ch, size_t pos) const noexcept
{
char* q;
if (n && (q = (char*)memchr(p, ch, n)))
return q - p;
return npos;
}
size_t
string_view::find(const string_view s, size_t pos) const noexcept
{
char* q;
if (pos > n)
__builtin_trap();
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
return q - p;
return npos;
}
string_view
string_view::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
if (ckd_add(&last, pos, count))
last = n;
if (last > n)
__builtin_trap();
return string_view(p + pos, count);
}
bool
string_view::operator==(const string_view s) const noexcept
{
if (n != s.n)
return false;
if (!n)
return true;
return !memcmp(p, s.p, n);
}
bool
string_view::operator!=(const string_view s) const noexcept
{
if (n != s.n)
return true;
if (!n)
return false;
return !!memcmp(p, s.p, n);
}
bool
string_view::contains(const string_view s) const noexcept
{
if (!s.n)
return true;
return !!memmem(p, n, s.p, s.n);
}
bool
string_view::ends_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p + n - s.n, s.p, s.n);
}
bool
string_view::starts_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p, s.p, s.n);
}
} // namespace ctl
+159
View File
@@ -0,0 +1,159 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRINGVIEW_H_
#define COSMOPOLITAN_CTL_STRINGVIEW_H_
namespace ctl {
struct string_view;
int
strcmp(const string_view, const string_view) noexcept;
struct string_view
{
const char* p;
size_t n;
using iterator = const char*;
using const_iterator = const char*;
static constexpr size_t npos = -1;
constexpr string_view() noexcept : p(nullptr), n(0)
{
}
constexpr string_view(const char* s) noexcept
: p(s), n(s ? __builtin_strlen(s) : 0)
{
}
constexpr string_view(const char* s, size_t n) noexcept : p(s), n(n)
{
}
inline constexpr ~string_view() noexcept
{
}
bool operator==(const string_view) const noexcept;
bool operator!=(const string_view) const noexcept;
bool contains(const string_view) const noexcept;
bool ends_with(const string_view) const noexcept;
bool starts_with(const string_view) const noexcept;
string_view substr(size_t = 0, size_t = npos) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const string_view, size_t = 0) const noexcept;
constexpr string_view& operator=(const string_view& s) noexcept
{
p = s.p;
n = s.n;
return *this;
}
constexpr bool empty() const noexcept
{
return !n;
}
constexpr const char* data() const noexcept
{
return p;
}
constexpr size_t size() const noexcept
{
return n;
}
constexpr size_t length() const noexcept
{
return n;
}
constexpr const char& operator[](size_t i) const noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
constexpr void remove_prefix(size_t count)
{
if (count > n)
__builtin_trap();
p += count;
n -= count;
}
constexpr void remove_suffix(size_t count)
{
if (count > n)
__builtin_trap();
n -= count;
}
constexpr const char& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
constexpr const char& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
constexpr const_iterator begin() noexcept
{
return p;
}
constexpr const_iterator end() noexcept
{
return p + n;
}
constexpr const_iterator cbegin() const noexcept
{
return p;
}
constexpr const_iterator cend() const noexcept
{
return p + n;
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view& s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view& s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view& s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view& s) const noexcept
{
return compare(s) >= 0;
}
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_
+246
View File
@@ -0,0 +1,246 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
#define COSMOPOLITAN_CTL_OPTIONAL_H_
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
namespace ctl {
template<typename T>
struct vector
{
size_t n = 0;
size_t c = 0;
T* p = nullptr;
using iterator = T*;
using const_iterator = const T*;
vector() = default;
~vector()
{
delete[] p;
}
vector(const vector& other)
{
n = other.n;
c = other.c;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(other.p[i]);
}
vector(vector&& other) noexcept
{
n = other.n;
c = other.c;
p = other.p;
other.n = 0;
other.c = 0;
other.p = nullptr;
}
explicit vector(size_t count, const T& value = T())
{
n = count;
c = count;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(value);
}
vector& operator=(const vector& other)
{
if (this != &other) {
T* newData = new T[other.c];
for (size_t i = 0; i < other.n; ++i) {
newData[i] = other.p[i];
}
delete[] p;
p = newData;
n = other.n;
c = other.c;
}
return *this;
}
vector& operator=(vector&& other) noexcept
{
if (this != &other) {
delete[] p;
p = other.p;
n = other.n;
c = other.c;
other.p = nullptr;
other.n = 0;
other.c = 0;
}
return *this;
}
bool empty() const
{
return !n;
}
size_t size() const
{
return n;
}
size_t capacity() const
{
return c;
}
T& operator[](size_t i)
{
if (i >= n)
__builtin_trap();
return p[i];
}
const T& operator[](size_t i) const
{
if (i >= n)
__builtin_trap();
return p[i];
}
iterator begin()
{
return p;
}
iterator end()
{
return p + n;
}
const_iterator cbegin() const
{
return p;
}
const_iterator cend() const
{
return p + n;
}
T& front()
{
if (!n)
__builtin_trap();
return p[0];
}
const T& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
T& back()
{
if (!n)
__builtin_trap();
return p[n - 1];
}
const T& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
void clear()
{
for (size_t i = 0; i < n; ++i)
p[i].~T();
n = 0;
}
void reserve(size_t c2)
{
if (c2 <= c)
return;
T* newP = new T[c2];
for (size_t i = 0; i < n; ++i)
newP[i] = std::move(p[i]);
delete[] p;
p = newP;
c = c2;
}
void push_back(const T& e)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(e);
++n;
}
void push_back(T&& e)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(std::forward<T>(e));
++n;
}
template<typename... Args>
void emplace_back(Args&&... args)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(std::forward<Args>(args)...);
++n;
}
void pop_back()
{
if (n > 0) {
--n;
p[n].~T();
}
}
void resize(size_t n2)
{
if (n2 > n) {
reserve(n2);
for (size_t i = n; i < n2; ++i)
new (&p[i]) T();
} else if (n2 < n) {
for (size_t i = n2; i < n; ++i)
p[i].~T();
}
n = n2;
}
void swap(vector& other) noexcept
{
std::swap(n, other.n);
std::swap(c, other.c);
std::swap(p, other.p);
}
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
+4 -2
View File
@@ -27,7 +27,8 @@
*/
int alaw(int x) {
int a, b, i;
if ((a = x) < 0) a = ~a;
if ((a = x) < 0)
a = ~a;
a >>= 4;
if (a > 15) {
if ((i = a >> 5)) {
@@ -40,6 +41,7 @@ int alaw(int x) {
a += 16;
}
}
if (x >= 0) a |= 128;
if (x >= 0)
a |= 128;
return a ^ 85;
}
+2 -2
View File
@@ -9,8 +9,8 @@ int mulaw(int);
int unmulaw(int);
void *double2byte(long, const void *, double, double) vallocesque;
void *byte2double(long, const void *, double, double) vallocesque;
void *dct(float[restrict hasatleast 8][8], unsigned,
float, float, float, float, float);
void *dct(float[restrict hasatleast 8][8], unsigned, float, float, float, float,
float);
void *dctjpeg(float[restrict hasatleast 8][8], unsigned);
double det3(const double[3][3]) nosideeffect;
void *inv3(double[restrict 3][3], const double[restrict 3][3], double);
+2 -2
View File
@@ -65,8 +65,8 @@
*
* @cost ~100ns
*/
void *dct(float M[restrict hasatleast 8][8], unsigned stride,
float c0, float c1, float c2, float c3, float c4) {
void *dct(float M[restrict hasatleast 8][8], unsigned stride, float c0,
float c1, float c2, float c3, float c4) {
unsigned y, x;
for (y = 0; y < stride * 8; y += stride) {
DCT(M[y][0], M[y][1], M[y][2], M[y][3], M[y][4], M[y][5], M[y][6], M[y][7],
+1 -1
View File
@@ -16,8 +16,8 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/core/core.h"
#include "dsp/core/gamma.h"
#include "dsp/core/core.h"
#include "libc/math.h"
double rgb2stdpc(double x, double g) {
+4 -2
View File
@@ -28,13 +28,15 @@
int mulaw(int x) {
int b, i, a, s, l, h;
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
if (a > 8191) a = 8191;
if (a > 8191)
a = 8191;
i = a >> 6;
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
h = 8 - s;
l = (a >> s) & 15;
l = 15 - l;
b = (h << 4) | l;
if (x >= 0) b |= 128;
if (x >= 0)
b |= 128;
return b;
}
+4 -2
View File
@@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
/* TODO(jart): This isn't acceptable. */
size_t i, j;
if (p > 0) {
if (p > 15) p = 15;
if (p > 15)
p = 15;
for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) {
pcm[i][j] =
@@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
}
} else if (p < 0) {
p = -p;
if (p > 15) p = 15;
if (p > 15)
p = 15;
for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] >> p;
+4 -2
View File
@@ -31,8 +31,10 @@ int unalaw(int x) {
i = (x ^ 85) & 127;
e = i >> 4;
m = i & 15;
if (e > 0) m += 16;
if (e > 0)
m += 16;
m = (m << 4) + 8;
if (e > 1) m = m << (e - 1);
if (e > 1)
m = m << (e - 1);
return x & 128 ? m : -m;
}
-1
View File
@@ -35,7 +35,6 @@ DSP_MPEG_A_DIRECTDEPS = \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_TIME \
LIBC_TINYMATH \
THIRD_PARTY_COMPILER_RT
+2 -1
View File
@@ -64,7 +64,8 @@ forceinline bool plm_buffer_has(plm_buffer_t *b, size_t bits) {
}
forceinline int plm_buffer_read(plm_buffer_t *self, int count) {
if (!plm_buffer_has(self, count)) return 0;
if (!plm_buffer_has(self, count))
return 0;
int value = 0;
while (count) {
int current_byte = self->bytes[self->bit_index >> 3];
+2 -2
View File
@@ -3,8 +3,8 @@
#include "dsp/mpeg/mpeg.h"
COSMOPOLITAN_C_START_
#define START_PACK 0xBA
#define START_END 0xB9
#define START_PACK 0xBA
#define START_END 0xB9
#define START_SYSTEM 0xBB
typedef struct plm_demux_t {
+2 -1
View File
@@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
di = (self->mb_row * dw + self->mb_col) * BW;
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
if (si > max_address || di > max_address) return;
if (si > max_address || di > max_address)
return;
d += di;
s += si;
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
+1 -1
View File
@@ -39,7 +39,7 @@
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "libc/x/x.h"
__static_yoink("pl_mpeg_notice");
-1
View File
@@ -31,7 +31,6 @@ DSP_SCALE_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X
+10 -5
View File
@@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
static bool IsNormalized(int n, double A[n]) {
int i;
double x;
for (x = i = 0; i < n; ++i) x += A[i];
for (x = i = 0; i < n; ++i)
x += A[i];
return fabs(x - 1) < 1e-4;
}
@@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
short *weights, *indices;
struct SamplingSolution *res;
long j, i, k, n, min, max, s, N[6];
if (!dar) dar = sn, dar /= dn;
if (!off) off = (dar - 1) / 2;
if (!dar)
dar = sn, dar /= dn;
if (!off)
off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4;
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
@@ -114,8 +117,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
for (k = 0, j = min; j <= max; ++j) {
fweights[k++] = ComputeWeight((j - x) / (f / par));
}
for (sum = k = 0; k < n; ++k) sum += fweights[k];
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum;
for (sum = k = 0; k < n; ++k)
sum += fweights[k];
for (j = 0; j < n; ++j)
fweights[j] *= 1 / sum;
DCHECK(IsNormalized(n, fweights));
for (j = 0; j < n; ++j) {
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));
-1
View File
@@ -38,7 +38,6 @@ DSP_TTY_A_DIRECTDEPS = \
LIBC_SOCK \
LIBC_SYSV \
LIBC_TINYMATH \
LIBC_TIME \
LIBC_X
DSP_TTY_A_DEPS := \
+6 -2
View File
@@ -24,9 +24,13 @@
* The alternate buffer trick lets one restore the console exactly as it
* was, once the program is done running.
*/
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
int ttyenablealtbuf(int ttyfd) {
return ttysend(ttyfd, "\e[?1049h");
}
/**
* Asks teletypewriter to restore blinking box thing.
*/
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }
int ttydisablealtbuf(int ttyfd) {
return ttysend(ttyfd, "\e[?1049l");
}
+4 -2
View File
@@ -30,8 +30,10 @@
static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l";
if (__nocolor) return 0;
if (visible) code[5] = 'h';
if (__nocolor)
return 0;
if (visible)
code[5] = 'h';
if (IsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
ntcursor.bVisible = visible;
+6 -2
View File
@@ -21,9 +21,13 @@
/**
* Asks teletypewriter to push current position.
*/
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
int ttysavecursor(int ttyfd) {
return ttysend(ttyfd, "\e[s");
}
/**
* Asks teletypewriter to pop previous position.
*/
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }
int ttyrestorecursor(int ttyfd) {
return ttysend(ttyfd, "\e[u");
}
+14 -6
View File
@@ -21,22 +21,30 @@
#include "libc/limits.h"
static char *ansitoa(char *p, unsigned xt, unsigned base) {
if (xt >= 8) xt -= 8, base += 60;
if (xt >= 8)
xt -= 8, base += 60;
return itoa8(p, xt + base);
}
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
*p++ = '\e';
*p++ = '[';
if (bg != -1u) p = ansitoa(p, bg, 40);
if (bg != -1u && fg != -1u) *p++ = ';';
if (fg != -1u) p = ansitoa(p, fg, 30);
if (bg != -1u)
p = ansitoa(p, bg, 40);
if (bg != -1u && fg != -1u)
*p++ = ';';
if (fg != -1u)
p = ansitoa(p, fg, 30);
*p++ = 'm';
return p;
}
char *setbg16_(char *p, struct TtyRgb bg) { return setansibgfg(p, bg.xt, -1u); }
char *setfg16_(char *p, struct TtyRgb fg) { return setansibgfg(p, -1u, fg.xt); }
char *setbg16_(char *p, struct TtyRgb bg) {
return setansibgfg(p, bg.xt, -1u);
}
char *setfg16_(char *p, struct TtyRgb fg) {
return setansibgfg(p, -1u, fg.xt);
}
char *setbgfg16_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
return setansibgfg(p, bg.xt, fg.xt);
}
+4 -2
View File
@@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Glyph *glyph) {
unsigned i;
CHECK_LT(pick.bg, 4);
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4);
if (pick.fg != 0xff)
CHECK_LT(pick.fg, 4);
i = 0;
if (pick.fg == 0xff) {
if (!ttyeq(*bg, chunk[pick.bg])) {
@@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
v = CopyGlyph(v, *glyph);
*x += 2;
*c += 2;
if (*x >= n) break;
if (*x >= n)
break;
CopyChunk(chunk, *c, n);
} while (ChunkEq(chunk, lastchunk));
*x -= 2;
+9 -5
View File
@@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
}
static textstartup void ttyraw_hidecursor(void) {
if (!g_ttyraw.setup) return;
if (g_ttyraw.flags & kTtyCursor) return;
if (!g_ttyraw.setup)
return;
if (g_ttyraw.flags & kTtyCursor)
return;
ttyhidecursor(FD);
}
static textexit int ttyraw_disable(void) {
if (!g_ttyraw.setup) return 0;
if (!g_ttyraw.setup)
return 0;
ttyshowcursor(FD);
return ttyrestore(FD, &g_ttyraw.old);
}
@@ -84,10 +87,11 @@ static textexit void ttyraw_onexit(void) {
ttyraw_disable();
}
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
static relegated void ttyraw_onsig(int sig, siginfo_t *info,
struct ucontext *ctx) {
size_t i;
if (g_ttyraw.noreentry) _Exit(128 + sig);
if (g_ttyraw.noreentry)
_Exit(128 + sig);
g_ttyraw.noreentry = true;
if (g_ttyraw.flags != -1) {
if (sig == SIGCONT) {
+4 -2
View File
@@ -65,7 +65,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_SYSV_CALLS \
LIBC_TESTLIB \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_VGA \
LIBC_X \
@@ -89,8 +88,10 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_SED \
THIRD_PARTY_STB \
THIRD_PARTY_TR \
THIRD_PARTY_TZ \
THIRD_PARTY_VQSORT \
THIRD_PARTY_XED \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_ZLIB \
TOOL_ARGS \
TOOL_BUILD_LIB \
@@ -154,7 +155,8 @@ o/$(MODE)/examples/picol.dbg: \
@$(APELINK)
o/$(MODE)/usr/share/dict/words.zip.o: private ZIPOBJ_FLAGS += -C2
o/$(MODE)/examples/wut.o: private COPTS += -fopenmp
o/$(MODE)/examples/blas.o: private COPTS += -O3 -fopenmp
$(EXAMPLES_OBJS): examples/BUILD.mk
+16
View File
@@ -0,0 +1,16 @@
#include <stdlib.h>
__static_yoink("__die");
__static_yoink("GetSymbolByAddr");
__static_yoink("malloc_inspect_all");
char *lol(int n) {
return malloc(n);
}
char *(*pLol)(int) = lol;
int main(int argc, char *argv[]) {
char *s = pLol(4);
s[4] = 1;
}
+221
View File
@@ -0,0 +1,221 @@
// Copyright 2024 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 <unistd.h>
#include <cinttypes>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include "libc/assert.h"
// high performance high accuracy matrix multiplication in ansi c
#define MATH __target_clones("avx512f,fma")
namespace {
namespace ansiBLAS {
static constexpr int KN = 8;
struct Vector {
double v[KN];
};
Vector load(const float *p) {
Vector x;
for (int i = 0; i < KN; ++i)
x.v[i] = p[i];
return x;
}
Vector madd(Vector x, Vector y, Vector s) {
for (int i = 0; i < KN; ++i)
s.v[i] = fma(x.v[i], y.v[i], s.v[i]);
return s;
}
float hsum(Vector x) {
double s = 0;
for (int i = 0; i < KN; ++i)
s += x.v[i];
return s;
}
struct ansiBLAS {
public:
ansiBLAS(int k, const float *A, int lda, const float *B, int ldb, float *C,
int ldc, int ith, int nth)
: k(k),
A(A),
lda(lda),
B(B),
ldb(ldb),
C(C),
ldc(ldc),
ith(ith),
nth(nth) {
}
void matmul(int m, int n) {
mnpack(0, m, 0, n);
}
private:
void mnpack(int m0, int m, int n0, int n) {
int mc, nc, mp, np;
if (m - m0 <= 0 || n - n0 <= 0)
return;
if (m - m0 >= 4 && n - n0 >= 3) {
mc = 4;
nc = 3;
gemm<4, 3>(m0, m, n0, n);
} else {
mc = 1;
nc = 1;
gemm<1, 1>(m0, m, n0, n);
}
mp = m0 + (m - m0) / mc * mc;
np = n0 + (n - n0) / nc * nc;
mnpack(mp, m, n0, np);
mnpack(m0, m, np, n);
}
template <int RM, int RN>
MATH void gemm(int m0, int m, int n0, int n) {
int ytiles = (m - m0) / RM;
int xtiles = (n - n0) / RN;
int tiles = xtiles * ytiles;
int duty = (tiles + nth - 1) / nth;
int start = duty * ith;
int end = start + duty;
if (end > tiles)
end = tiles;
for (int job = start; job < end; ++job) {
int ii = m0 + job / xtiles * RM;
int jj = n0 + job % xtiles * RN;
Vector Cv[RN][RM] = {};
for (int l = 0; l < k; l += KN)
for (int j = 0; j < RN; ++j)
for (int i = 0; i < RM; ++i)
Cv[j][i] = madd(load(A + lda * (ii + i) + l), //
load(B + ldb * (jj + j) + l), //
Cv[j][i]);
for (int j = 0; j < RN; ++j)
for (int i = 0; i < RM; ++i)
C[ldc * (jj + j) + (ii + i)] = hsum(Cv[j][i]);
}
}
const int k;
const float *const A;
const int lda;
const float *const B;
const int ldb;
float *const C;
const int ldc;
const int ith;
const int nth;
};
void sgemm(int m, int n, int k, //
const float *A, int lda, //
const float *B, int ldb, //
float *C, int ldc) {
int nth = sysconf(_SC_NPROCESSORS_ONLN);
#pragma omp parallel for
for (int ith = 0; ith < nth; ++ith) {
ansiBLAS tb{k, A, lda, B, ldb, C, ldc, ith, nth};
tb.matmul(m, n);
}
}
} // namespace ansiBLAS
long micros(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 1000000 + (ts.tv_nsec + 999) / 1000;
}
unsigned rand32(void) {
/* Knuth, D.E., "The Art of Computer Programming," Vol 2,
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
p. 106 (line 26) & p. 108 */
static unsigned long long lcg = 1;
lcg *= 6364136223846793005;
lcg += 1442695040888963407;
return lcg >> 32;
}
float float01(unsigned x) { // (0,1)
return 1.f / 8388608 * ((x >> 9) + .5f);
}
float numba(void) { // (-1,1)
return float01(rand32()) * 2 - 1;
}
void fill(int m, int n, float *A, int lda) {
for (int j = 0; j < n; ++j)
for (int i = 0; i < m; ++i)
A[lda * j + i] = numba();
}
float *new_matrix(int m, int n, int *lda) {
void *ptr = 0;
int b = 64 / sizeof(float);
*lda = (n + b - 1) & -b;
posix_memalign(&ptr, 4096, sizeof(float) * m * *lda);
return (float *)ptr;
}
} // namespace
void barrier(void) {
}
void (*pBarrier)(void) = barrier;
#define BENCH(x) \
do { \
x; \
int N = 10; \
long t1 = micros(); \
for (long i = 0; i < N; ++i) { \
pBarrier(); \
x; \
} \
long t2 = micros(); \
printf("%8" PRId64 " µs %s %g gigaflops\n", (t2 - t1 + N - 1) / N, #x, \
1e6 / ((t2 - t1 + N - 1) / N) * m * n * k * 2 * 1e-9); \
} while (0)
int main() {
int m = 1024;
int n = 1024;
int k = 1024;
int lda, ldb, ldc;
float *A = new_matrix(m, k, &lda);
float *B = new_matrix(n, k, &ldb);
float *C = new_matrix(n, m, &ldc);
fill(k, n, A, lda);
fill(k, m, B, ldb);
BENCH(ansiBLAS::sgemm(m, n, k, A, lda, B, ldb, C, ldc));
assert(C[0] == -0x1.20902ap+4);
assert(C[1] == -0x1.bf7726p+4);
free(C);
free(B);
free(A);
}
+11 -8
View File
@@ -7,6 +7,7 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
@@ -26,6 +27,13 @@
* o//examples/crashreport.com
*/
int Divide(int x, int y) {
volatile int z = 0; // force creation of stack frame
return x / y + z;
}
int (*pDivide)(int, int) = Divide;
dontubsan int main(int argc, char *argv[]) {
kprintf("----------------\n");
kprintf(" THIS IS A TEST \n");
@@ -34,12 +42,7 @@ dontubsan int main(int argc, char *argv[]) {
ShowCrashReports();
volatile double a = 0;
volatile double b = 23;
volatile double c = exp(b) / a;
(void)c;
volatile int x = 0;
volatile int y = 1 / x;
return y;
pDivide(1, 0);
pDivide(2, 0);
pDivide(3, 0);
}
+12
View File
@@ -7,6 +7,7 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
@@ -18,6 +19,17 @@ void crash(long x0, long x1, long x2, //
void (*pCrash)(long, long, long, double, double, double) = crash;
int main(int argc, char *argv[]) {
// // by default we launch an addr2line subprocess to print backtraces
// // with line numbers. you can force it to use the embedded solution
// setenv("ADDR2LINE", "", true);
// // using a seccomp sandbox is another way to force embedded backtraces
// pledge("stdio", NULL);
// enable the crash reporting feature
ShowCrashReports();
// time to die
pCrash(1, 2, 3, NAN, NAN, NAN);
}
+25 -4
View File
@@ -9,19 +9,30 @@
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/timezoneid.h"
#include "libc/nt/struct/timezoneinformation.h"
#include "libc/nt/time.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/struct/tm.h"
#include "libc/thread/threads.h"
#include "libc/time.h"
/**
* @fileoverview High performance ISO-8601 timestamp formatter.
*
* The strftime() function is very slow. This goes much faster.
* Consider using something like this instead for your loggers.
*/
char *GetTimestamp(void) {
int x;
struct timespec ts;
_Thread_local static long last;
_Thread_local static char s[27];
_Thread_local static struct tm tm;
thread_local static long last;
thread_local static char s[32];
thread_local static struct tm tm;
clock_gettime(0, &ts);
if (ts.tv_sec != last) {
localtime_r(&ts.tv_sec, &tm);
@@ -61,11 +72,21 @@ char *GetTimestamp(void) {
s[23] = '0' + x / 100000 % 10;
s[24] = '0' + x / 10000 % 10;
s[25] = '0' + x / 1000 % 10;
s[26] = tm.tm_gmtoff < 0 ? '-' : '+';
x = ABS(tm.tm_gmtoff) / 60 / 60;
s[27] = '0' + x / 10 % 10;
s[28] = '0' + x % 10;
x = ABS(tm.tm_gmtoff) / 60 % 60;
s[29] = '0' + x / 10 % 10;
s[30] = '0' + x % 10;
return s;
}
int main(int argc, char *argv[]) {
char buf[128], *p = buf;
// setenv("TZ", "UTC", true);
// setenv("TZ", "US/Eastern", true);
// setenv("TZ", "Asia/Kolkata", true);
p = stpcpy(p, GetTimestamp());
p = stpcpy(p, "\n");
write(1, buf, p - buf);
+2 -2
View File
@@ -1,9 +1,9 @@
#include "libc/stdio/stdio.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
int main(int argc, char* argv[]) {
fprintf(stderr, "%s (%s)\n", argv[0], GetProgramExecutableName());
for (char **p = environ; *p; ++p) {
for (char** p = environ; *p; ++p) {
printf("%s\n", *p);
}
return 0;
+15 -8
View File
@@ -104,8 +104,10 @@ void *Worker(void *id) {
if (client == -1) {
// accept() errors are generally ephemeral or recoverable
// it'd potentially be a good idea to exponential backoff here
if (errno == ECANCELED) continue; // pthread_cancel() was called
if (errno == EMFILE) ExplainPrlimit();
if (errno == ECANCELED)
continue; // pthread_cancel() was called
if (errno == EMFILE)
ExplainPrlimit();
LOG("accept() returned %m");
SomethingHappened();
continue;
@@ -149,7 +151,7 @@ void *Worker(void *id) {
// check that client message wasn't fragmented into more reads
InitHttpMessage(&msg, kHttpRequest);
if ((inmsglen = ParseHttpMessage(&msg, buf, got)) <= 0) {
if ((inmsglen = ParseHttpMessage(&msg, buf, got, sizeof(buf))) <= 0) {
if (!inmsglen) {
LOG("%6H client sent fragmented message");
} else {
@@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
--a_workers;
kprintf("pthread_create failed: %s\n", strerror(rc));
if (rc == EAGAIN) ExplainPrlimit();
if (!i) exit(1);
if (rc == EAGAIN)
ExplainPrlimit();
if (!i)
exit(1);
threads = i;
break;
}
@@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
PrintEphemeralStatusLine();
unassert(!pthread_cond_wait(&statuscond, &statuslock));
// limit status line updates to sixty frames per second
do tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
do
tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
while (timespec_cmp(tick, timespec_real()) < 0);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0);
}
@@ -378,7 +383,8 @@ int main(int argc, char *argv[]) {
}
// on windows this is the only way accept() can be canceled
if (IsWindows()) close(server);
if (IsWindows())
close(server);
// print status in terminal as the shutdown progresses
unassert(!pthread_mutex_lock(&statuslock));
@@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
}
// close the server socket
if (!IsWindows()) close(server);
if (!IsWindows())
close(server);
// clean up terminal line
LOG("thank you for choosing \e[32mgreenbean\e[0m");
+1 -1
View File
@@ -42,7 +42,7 @@
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "third_party/zlib/zlib.h"
// clang-format off
+2 -2
View File
@@ -7,11 +7,11 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/runtime/runtime.h"
#include "third_party/hiredis/hiredis.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "third_party/hiredis/hiredis.h"
/**
* @fileoverview Demo of using hiredis to connect to a Redis server
+93 -47
View File
@@ -71,7 +71,7 @@ Contact: [email protected]");
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "libc/time.h"
/* Syntax highlight types */
#define HL_NORMAL 0
@@ -212,10 +212,13 @@ void editorAtExit(void) {
int enableRawMode(int64_t fd) {
struct termios raw;
if (E.rawmode) return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO)) goto fatal;
if (E.rawmode)
return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO))
goto fatal;
atexit(editorAtExit);
if (tcgetattr(fd, &orig_termios) == -1) goto fatal;
if (tcgetattr(fd, &orig_termios) == -1)
goto fatal;
raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char,
@@ -233,7 +236,8 @@ int enableRawMode(int64_t fd) {
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal;
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
goto fatal;
E.rawmode = 1;
return 0;
@@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
char c, seq[3];
do {
nread = read(fd, &c, 1);
if (nread == -1) exit(1);
if (nread == -1)
exit(1);
} while (!nread);
while (1) {
@@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
return PAGE_DOWN;
case '\e': /* escape sequence */
/* If this is just an ESC, we'll timeout here. */
if (read(fd, seq, 1) == 0) return CTRL('[');
if (read(fd, seq, 1) == 0)
return CTRL('[');
if (seq[0] == '[') {
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */
if (read(fd, seq + 2, 1) == 0) return CTRL('[');
if (read(fd, seq + 2, 1) == 0)
return CTRL('[');
if (seq[2] == '~') {
switch (seq[1]) {
case '1':
@@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
} else if (seq[0] == 'v') {
return PAGE_UP;
} else if (seq[0] == 'O') {
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
/* ESC O sequences. */
switch (seq[1]) {
case 'H':
@@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
unsigned i = 0;
/* Report cursor location */
if (write(ofd, "\e[6n", 4) != 4) return -1;
if (write(ofd, "\e[6n", 4) != 4)
return -1;
/* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf) - 1) {
if (read(ifd, buf + i, 1) != 1) break;
if (buf[i] == 'R') break;
if (read(ifd, buf + i, 1) != 1)
break;
if (buf[i] == 'R')
break;
i++;
}
buf[i] = '\0';
/* Parse it. */
if (buf[0] != CTRL('[') || buf[1] != '[') return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1;
if (buf[0] != CTRL('[') || buf[1] != '[')
return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
return -1;
return 0;
}
@@ -359,12 +373,15 @@ int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
/* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
if (retval == -1) goto failed;
if (retval == -1)
goto failed;
/* Go to right/bottom margin and get position. */
if (write(ofd, "\e[999C\e[999B", 12) != 12) goto failed;
if (write(ofd, "\e[999C\e[999B", 12) != 12)
goto failed;
retval = getCursorPosition(ifd, ofd, rows, cols);
if (retval == -1) goto failed;
if (retval == -1)
goto failed;
/* Restore position. */
char seq[32];
@@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
row->hl = realloc(row->hl, row->rsize);
memset(row->hl, HL_NORMAL, row->rsize);
if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */
if (E.syntax == NULL)
return; /* No syntax, everything is HL_NORMAL. */
int i, prev_sep, in_string, in_comment;
char *p;
@@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
prev_sep = 0;
continue;
}
if (*p == in_string) in_string = 0;
if (*p == in_string)
in_string = 0;
p++;
i++;
continue;
@@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
for (j = 0; keywords[j]; j++) {
int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen - 1] == '|';
if (kw2) klen--;
if (kw2)
klen--;
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
/* Keyword */
@@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
* respecting tabs, substituting non printable characters with '?'. */
free(row->render);
for (j = 0; j < row->size; j++) {
if (row->chars[j] == '\t') tabs++;
if (row->chars[j] == '\t')
tabs++;
}
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
@@ -626,11 +647,13 @@ void editorUpdateRow(erow *row) {
/* Insert a row at the specified position, shifting the other rows on the bottom
* if required. */
void editorInsertRow(int at, char *s, size_t len) {
if (at > E.numrows) return;
if (at > E.numrows)
return;
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
if (at != E.numrows) {
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
for (int j = at + 1; j <= E.numrows; j++) E.row[j].idx++;
for (int j = at + 1; j <= E.numrows; j++)
E.row[j].idx++;
}
E.row[at].size = len;
E.row[at].chars = malloc(len + 1);
@@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
void editorDelRow(int at) {
erow *row;
if (at >= E.numrows) return;
if (at >= E.numrows)
return;
row = E.row + at;
editorFreeRow(row);
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
for (int j = at; j < E.numrows - 1; j++) E.row[j].idx++;
for (int j = at; j < E.numrows - 1; j++)
E.row[j].idx++;
E.numrows--;
E.dirty++;
}
@@ -729,7 +754,8 @@ void editorRowAppendString(erow *row, char *s, size_t len) {
/* Delete the character at offset 'at' from the specified row. */
void editorRowDelChar(erow *row, int at) {
if (row->size <= at) return;
if (row->size <= at)
return;
memmove(row->chars + at, row->chars + at + 1, row->size - at);
editorUpdateRow(row);
row->size--;
@@ -745,7 +771,8 @@ void editorInsertChar(int c) {
/* If the row where the cursor is currently located does not exist in our
* logical representation of the file, add enough empty rows as needed. */
if (!row) {
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0);
while (E.numrows <= filerow)
editorInsertRow(E.numrows, "", 0);
}
row = &E.row[filerow];
editorRowInsertChar(row, filecol, c);
@@ -773,7 +800,8 @@ void editorInsertNewline(void) {
}
/* If the cursor is over the current line size, we want to conceptually
* think it's just over the last character. */
if (filecol >= row->size) filecol = row->size;
if (filecol >= row->size)
filecol = row->size;
if (filecol == 0) {
editorInsertRow(filerow, "", 0);
} else {
@@ -800,7 +828,8 @@ void editorDelChar(void) {
int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row || (filecol == 0 && filerow == 0)) return;
if (!row || (filecol == 0 && filerow == 0))
return;
if (filecol == 0) {
/* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */
@@ -825,7 +854,8 @@ void editorDelChar(void) {
else
E.cx--;
}
if (row) editorUpdateRow(row);
if (row)
editorUpdateRow(row);
E.dirty++;
}
@@ -868,12 +898,15 @@ int editorSave(void) {
int len;
char *buf = editorRowsToString(&len);
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) goto writeerr;
if (fd == -1)
goto writeerr;
/* Use truncate + a single write(2) call in order to make saving
* a bit safer, under the limits of what we can do in a small editor. */
if (ftruncate(fd, len) == -1) goto writeerr;
if (write(fd, buf, len) != len) goto writeerr;
if (ftruncate(fd, len) == -1)
goto writeerr;
if (write(fd, buf, len) != len)
goto writeerr;
close(fd);
free(buf);
@@ -883,7 +916,8 @@ int editorSave(void) {
writeerr:
free(buf);
if (fd != -1) close(fd);
if (fd != -1)
close(fd);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return 1;
}
@@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
abAppend(&ab, "~", 1);
padding--;
}
while (padding--) abAppend(&ab, " ", 1);
while (padding--)
abAppend(&ab, " ", 1);
abAppend(&ab, welcome, welcomelen);
} else {
abAppend(&ab, "~\e[0K\r\n", 7);
@@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
int current_color = -1;
#endif
if (len > 0) {
if (len > E.screencols) len = E.screencols;
if (len > E.screencols)
len = E.screencols;
char *c = r->render + E.coloff;
#if SYNTAX
unsigned char *hl = r->hl + E.coloff;
@@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
E.numrows, E.dirty ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
E.numrows);
if (len > E.screencols) len = E.screencols;
if (len > E.screencols)
len = E.screencols;
abAppend(&ab, status, len);
while (len < E.screencols) {
if (E.screencols - len == rlen) {
@@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (row) {
for (j = E.coloff; j < (E.cx + E.coloff); j++) {
if (j < row->size && row->chars[j] == CTRL('I')) cx += 7 - ((cx) % 8);
if (j < row->size && row->chars[j] == CTRL('I'))
cx += 7 - ((cx) % 8);
cx++;
}
}
@@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
if (qlen != 0) query[--qlen] = '\0';
if (qlen != 0)
query[--qlen] = '\0';
last_match = -1;
} else if (c == CTRL('G')) {
break;
@@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
}
/* Search occurrence. */
if (last_match == -1) find_next = 1;
if (last_match == -1)
find_next = 1;
if (find_next) {
char *match = NULL;
int match_offset = 0;
@@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
break;
case ARROW_UP:
if (E.cy == 0) {
if (E.rowoff) E.rowoff--;
if (E.rowoff)
E.rowoff--;
} else {
E.cy -= 1;
}
@@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
case CTRL('L'):
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break;
case PAGE_UP:
@@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
E.cy = E.screenrows - 1;
}
times = E.screenrows;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break;
case HOME_KEY:
case CTRL('A'):
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT);
while (E.cx || E.coloff)
editorMoveCursor(ARROW_LEFT);
break;
case END_KEY:
case CTRL('E'):
+15
View File
@@ -0,0 +1,15 @@
#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/time.h"
int main(int argc, char *argv[]) {
int64_t t = 0;
localtime(&t);
}
+130 -66
View File
@@ -44,7 +44,7 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "libc/x/xasprintf.h"
#include "libc/x/xsigaction.h"
#include "libc/zip.internal.h"
@@ -492,7 +492,8 @@ void TransmitVideo(void) {
ssize_t rc;
struct Frame* f;
f = &vf_[frame_];
if (!HasVideo(f)) f = FlipFrameBuffer();
if (!HasVideo(f))
f = FlipFrameBuffer();
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
f->w += rc;
} else if (errno == EAGAIN) {
@@ -504,9 +505,12 @@ void TransmitVideo(void) {
void TransmitAudio(void) {
ssize_t rc;
if (!playpid_) return;
if (!audio_.i) return;
if (playfd_ == -1) return;
if (!playpid_)
return;
if (!audio_.i)
return;
if (playfd_ == -1)
return;
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
rc /= sizeof(short);
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
@@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
void PollAndSynchronize(void) {
do {
if (ReadKeyboard() == -1) {
if (errno != EINTR) Exit(1);
if (exited_) Exit(0);
if (resized_) GetTermSize();
if (errno != EINTR)
Exit(1);
if (exited_)
Exit(0);
if (resized_)
GetTermSize();
}
} while (!timeout_);
TransmitVideo();
@@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
}
}
}
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF];
if ((addr >> 13) == 3)
return PRAM[addr & 0x1FFF];
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
}
@@ -828,7 +836,8 @@ bool offset_toggle = false;
u8& NesMmap(int i) {
i &= 0x3FFF;
if (i >= 0x3F00) {
if (i % 4 == 0) i &= 0x0F;
if (i % 4 == 0)
i &= 0x0F;
return palette[i & 0x1F];
}
if (i < 0x2000) {
@@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
return open_bus_decay_timer = 77777, open_bus = v;
};
u8 res = open_bus;
if (write) RefreshOpenBus(v);
if (write)
RefreshOpenBus(v);
switch (index) { // Which port from $200x?
case 0:
if (write) {
@@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 2:
if (write) break;
if (write)
break;
res = reg.status | (open_bus & 0x1F);
reg.InVBlank = false; // Reading $2002 clears the vblank flag.
offset_toggle = false; // Also resets the toggle for address updates.
@@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 3:
if (write) reg.OAMaddr = v;
if (write)
reg.OAMaddr = v;
break; // Index into Object Attribute Memory
case 4:
if (write) {
@@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 5:
if (!write) break; // Set background scrolling offset
if (!write)
break; // Set background scrolling offset
if (offset_toggle) {
scroll.yfine = v & 7;
scroll.ycoarse = v >> 3;
@@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
offset_toggle = !offset_toggle;
break;
case 6:
if (!write) break; // Set video memory position for reads/writes
if (!write)
break; // Set video memory position for reads/writes
if (offset_toggle) {
scroll.vaddrlo = v;
vaddr.raw = (unsigned)scroll.raw;
@@ -926,17 +940,21 @@ void RenderingTick() {
case 2: // Point to attribute table
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
(vaddr.xcoarse / 4);
if (tile_decode_mode) break; // Or nametable, with sprites.
case 0: // Point to nametable
if (tile_decode_mode)
break; // Or nametable, with sprites.
case 0: // Point to nametable
ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
// Reset sprite data
if (x_ == 0) {
sprinpos = sproutpos = 0;
if (reg.ShowSP) reg.OAMaddr = 0;
if (reg.ShowSP)
reg.OAMaddr = 0;
}
if (!reg.ShowBG) break;
if (!reg.ShowBG)
break;
// Reset scrolling (vertical once, horizontal each scanline)
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw;
if (x_ == 304 && scanline == -1)
vaddr.raw = (unsigned)scroll.raw;
if (x_ == 256) {
vaddr.xcoarse = (unsigned)scroll.xcoarse;
vaddr.basenta_h = (unsigned)scroll.basenta_h;
@@ -949,7 +967,8 @@ void RenderingTick() {
}
// Name table access
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
if (!tile_decode_mode) break;
if (!tile_decode_mode)
break;
// Push the current tile into shift registers.
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
// 8 times.
@@ -976,7 +995,8 @@ void RenderingTick() {
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
memcpy(&o, &OAM2[sprrenpos], sizeof(o));
unsigned y = (scanline)-o.y;
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7);
if (o.attr & 0x80)
y ^= (reg.SPsize ? 15 : 7);
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
pat_addr += (y & 7) + (y & 8) * 2;
@@ -1011,8 +1031,10 @@ void RenderingTick() {
break;
}
++sprinpos; // next sprite
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex;
if (sproutpos < 8)
OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].sprindex = reg.OAMindex;
y1 = sprtmp;
y2 = sprtmp + (reg.SPsize ? 16 : 8);
if (!(scanline >= y1 && scanline < y2)) {
@@ -1020,19 +1042,23 @@ void RenderingTick() {
}
break;
case 1:
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].index = sprtmp;
break;
case 2:
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].attr = sprtmp;
break;
case 3:
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8) {
++sproutpos;
} else {
reg.SPoverflow = true;
}
if (sprinpos == 2) reg.OAMaddr = 8;
if (sprinpos == 2)
reg.OAMaddr = 8;
break;
}
}
@@ -1060,13 +1086,17 @@ void RenderPixel() {
auto& s = OAM3[sno];
// Check if this sprite is horizontally in range
unsigned xdiff = x_ - s.x_;
if (xdiff >= 8) continue; // Also matches negative values
if (xdiff >= 8)
continue; // Also matches negative values
// Determine which pixel to display; skip transparent pixels
if (!(s.attr & 0x40)) xdiff = 7 - xdiff;
if (!(s.attr & 0x40))
xdiff = 7 - xdiff;
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
if (!spritepixel) continue;
if (!spritepixel)
continue;
// Register sprite-0 hit if applicable
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true;
if (x_ < 255 && pixel && s.sprindex == 0)
reg.SP0hit = true;
// Render the pixel unless behind-background placement wanted
if (!(s.attr & 0x20) || !pixel) {
attr = (s.attr & 3) + 4;
@@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
}
if (ctrlmask & 0x80) {
joy_next_[0] = fgetc(fp);
if (feof(fp)) joy_next_[0] = 0;
if (feof(fp))
joy_next_[0] = 0;
}
if (ctrlmask & 0x40) {
joy_next_[1] = fgetc(fp);
if (feof(fp)) joy_next_[1] = 0;
if (feof(fp))
joy_next_[1] = 0;
}
}
}
@@ -1144,18 +1176,23 @@ void Tick() {
CPU::nmi = reg.InVBlank && reg.NMIenabled;
break;
}
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0;
if (VBlankState != 0)
VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer)
open_bus = 0;
// Graphics processing scanline?
if (scanline < DYN) {
/* Process graphics for this cycle */
if (reg.ShowBGSP) RenderingTick();
if (scanline >= 0 && x_ < 256) RenderPixel();
if (reg.ShowBGSP)
RenderingTick();
if (scanline >= 0 && x_ < 256)
RenderPixel();
}
// Done with the cycle. Check for end of scanline.
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting
if (++cycle_counter == 3)
cycle_counter = 0; // For NTSC pixel shifting
if (++x_ >= scanline_end) {
// Begin new scanline
FlushScanline(scanline);
@@ -1242,30 +1279,36 @@ struct channel {
template <unsigned c>
int Tick() {
channel& ch = *this;
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8;
if (!ChannelsEnabled[c])
return c == 4 ? 64 : 8;
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq];
if (c == 3)
wl = NoisePeriods[ch.reg.NoiseFreq];
int volume = ch.length_counter
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
: 0;
// Sample may change at wavelen intervals.
auto& S = ch.level;
if (!count(ch.wave_counter, wl)) return S;
if (!count(ch.wave_counter, wl))
return S;
switch (c) {
default: // Square wave. With four different 8-step binary waveforms (32
// bits of data total).
if (wl < 8) return S = 8;
if (wl < 8)
return S = 8;
return S = (0xF33C0C04u &
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
? volume
: 0;
case 2: // Triangle wave
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase;
if (ch.length_counter && ch.linear_counter && wl >= 3)
++ch.phase;
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
case 3: // Noise: Linear feedback shift register
if (!ch.hold) ch.hold = 1;
if (!ch.hold)
ch.hold = 1;
ch.hold =
(ch.hold >> 1) |
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
@@ -1302,7 +1345,8 @@ struct channel {
} else {
v -= 2;
}
if (v >= 0 && v <= 0x7F) ch.linear_counter = v;
if (v >= 0 && v <= 0x7F)
ch.linear_counter = v;
}
return S = ch.linear_counter;
}
@@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
ch.linear_counter = ch.reg.LinearCounterInit;
ch.env_delay = ch.reg.EnvDecayRate;
ch.envelope = 15;
if (index < 8) ch.phase = 0;
if (index < 8)
ch.phase = 0;
break;
case 0x10:
ch.reg.reg3 = value;
@@ -1384,9 +1429,11 @@ u8 Read() {
for (c = 0; c < 5; ++c) {
res |= channels[c].length_counter ? 1 << c : 0;
}
if (PeriodicIRQ) res |= 0x40;
if (PeriodicIRQ)
res |= 0x40;
PeriodicIRQ = false;
if (DMC_IRQ) res |= 0x80;
if (DMC_IRQ)
res |= 0x80;
DMC_IRQ = false;
CPU::intr = false;
return res;
@@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
if ((hz240counter.lo += 2) >= 14915) {
hz240counter.lo -= 14915;
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0;
if (++hz240counter.hi >= 4 + FiveCycleDivider)
hz240counter.hi = 0;
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
@@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
wl += d[ch.reg.SweepDecrease * 2 + c];
if (wl < 0x800) ch.reg.WaveLength = wl;
if (wl < 0x800)
ch.reg.WaveLength = wl;
}
// Linear tick (triangle wave only)
@@ -1464,20 +1513,24 @@ namespace CPU {
void Tick() {
// PPU clock: 3 times the CPU rate
for (unsigned n = 0; n < 3; ++n) PPU::Tick();
for (unsigned n = 0; n < 3; ++n)
PPU::Tick();
// APU clock: 1 times the CPU rate
for (unsigned n = 0; n < 1; ++n) APU::Tick();
for (unsigned n = 0; n < 1; ++n)
APU::Tick();
}
template <bool write>
u8 MemAccess(u16 addr, u8 v) {
// Memory writes are turned into reads while reset is being signalled
if (reset && write) return MemAccess<0>(addr);
if (reset && write)
return MemAccess<0>(addr);
Tick();
// Map the memory from CPU's viewpoint.
/**/ if (addr < 0x2000) {
u8& r = RAM[addr & 0x7FF];
if (!write) return r;
if (!write)
return r;
r = v;
} else if (addr < 0x4000) {
return PPU::PpuAccess(addr & 7, v, write);
@@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
WB(0x2004, RB((v & 7) * 0x0100 + b));
return 0;
case 0x15:
if (!write) return APU::Read();
if (!write)
return APU::Read();
APU::Write(0x15, v);
break;
case 0x16:
if (!write) return JoyRead(0);
if (!write)
return JoyRead(0);
JoyStrobe(v);
break;
case 0x17:
if (!write) return JoyRead(1); // write:passthru
if (!write)
return JoyRead(1); // write:passthru
default:
if (!write) break;
if (!write)
break;
APU::Write(addr & 0x1F, v);
}
} else {
@@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
}
void Misfire(u16 old, u16 addr) {
u16 q = wrap(old, addr);
if (q != addr) RB(q);
if (q != addr)
RB(q);
}
u8 Pop() {
return RB(0x100 | u8(++S));
@@ -1655,7 +1713,8 @@ void Op() {
} else if (intr && !P.I) {
op = 0x102;
}
if (!nmi_now) nmi_edge_detected = false;
if (!nmi_now)
nmi_edge_detected = false;
// Define function pointers for each opcode (00..FF) and each interrupt
// (100,101,102)
@@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
fgetc(fp);
fgetc(fp);
if (mappernum >= 0x40) mappernum &= 15;
if (mappernum >= 0x40)
mappernum &= 15;
GamePak::mappernum = mappernum;
// Read the ROM data
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000);
if (rom16count)
GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count)
GamePak::VRAM.resize(vrom8count * 0x2000);
fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
@@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
PPU::reg.value = 0;
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
for (unsigned a = 0; a < 0x800; ++a)
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
// Run the CPU until the program is killed.
for (;;) CPU::Op();
for (;;)
CPU::Op();
}
wontreturn void PrintUsage(int rc, FILE* f) {
+1
View File
@@ -42,6 +42,7 @@ EXAMPLES_PACKAGE_OBJS = \
EXAMPLES_PACKAGE_DIRECTDEPS = \
EXAMPLES_PACKAGE_LIB \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STDIO \
LIBC_TINYMATH
+1
View File
@@ -71,6 +71,7 @@ EXAMPLES_PACKAGE_LIB_A_CHECKS = \
EXAMPLES_PACKAGE_LIB_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_MEM \
LIBC_STDIO
# Evaluates variable as set of transitive package dependencies.
+26 -26
View File
@@ -1,31 +1,31 @@
#include <stdio.h>
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
do { \
type val; int ret; \
ret = sscanf(str, scan_fmt, &val); \
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
do { \
type val; \
int ret; \
ret = sscanf(str, scan_fmt, &val); \
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
} while (0)
int main()
{
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
PARSE_AND_PRINT(float, "%f", "%f", "3715");
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
PARSE_AND_PRINT(float, "%f", "%f", "inF");
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
PARSE_AND_PRINT(float, "%f", "%f", "junk");
return 0;
int main() {
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
PARSE_AND_PRINT(float, "%f", "%f", "3715");
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
PARSE_AND_PRINT(float, "%f", "%f", "inF");
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
PARSE_AND_PRINT(float, "%f", "%f", "junk");
return 0;
}
+62 -31
View File
@@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
} else if (*p->p == '[' && blevel == 0) {
level++;
} else if (*p->p == ']' && blevel == 0) {
if (!--level) break;
if (!--level)
break;
} else if (*p->p == '\\') {
p->p++;
p->len--;
} else if (*p->p == '{') {
blevel++;
} else if (*p->p == '}') {
if (blevel != 0) blevel--;
if (blevel != 0)
blevel--;
}
p->p++;
p->len--;
@@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
case ' ':
case '\t':
case '\r':
if (p->insidequote) return picolParseString(p);
if (p->insidequote)
return picolParseString(p);
return picolParseSep(p);
case '\n':
case ';':
if (p->insidequote) return picolParseString(p);
if (p->insidequote)
return picolParseString(p);
return picolParseEol(p);
case '[':
return picolParseCommand(p);
@@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
struct picolVar *v = i->callframe->vars;
while (v) {
if (strcmp(v->name, name) == 0) return v;
if (strcmp(v->name, name) == 0)
return v;
v = v->next;
}
return NULL;
@@ -334,7 +339,8 @@ int picolSetVar(struct picolInterp *i, char *name, char *val) {
struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) {
struct picolCmd *c = i->commands;
while (c) {
if (strcmp(c->name, name) == 0) return c;
if (strcmp(c->name, name) == 0)
return c;
c = c->next;
}
return NULL;
@@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
int tlen;
int prevtype = p.type;
picolGetToken(&p);
if (p.type == PT_EOF) break;
if (p.type == PT_EOF)
break;
tlen = p.end - p.start + 1;
if (tlen < 0) tlen = 0;
if (tlen < 0)
tlen = 0;
t = malloc(tlen + 1);
memcpy(t, p.start, tlen);
t[tlen] = '\0';
@@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
} else if (p.type == PT_CMD) {
retcode = picolEval(i, t);
free(t);
if (retcode != PICOL_OK) goto err;
if (retcode != PICOL_OK)
goto err;
t = strdup(i->result);
} else if (p.type == PT_ESC) {
/* XXX: escape handling missing! */
@@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
goto err;
}
retcode = c->func(i, argc, argv, c->privdata);
if (retcode != PICOL_OK) goto err;
if (retcode != PICOL_OK)
goto err;
}
/* Prepare for the next command */
for (j = 0; j < argc; j++) free(argv[j]);
for (j = 0; j < argc; j++)
free(argv[j]);
free(argv);
argv = NULL;
argc = 0;
@@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
prevtype = p.type;
}
err:
for (j = 0; j < argc; j++) free(argv[j]);
for (j = 0; j < argc; j++)
free(argv[j]);
free(argv);
return retcode;
}
@@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
char buf[64];
int a, b, c;
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
a = atoi(argv[1]);
b = atoi(argv[2]);
if (argv[0][0] == '+')
@@ -485,22 +498,26 @@ int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
}
int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
picolSetVar(i, argv[1], argv[2]);
picolSetResult(i, argv[2]);
return PICOL_OK;
}
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 2) return picolArityErr(i, argv[0]);
if (argc != 2)
return picolArityErr(i, argv[0]);
printf("%s\n", argv[1]);
return PICOL_OK;
}
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
int retcode;
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode;
if (argc != 3 && argc != 5)
return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
return retcode;
if (atoi(i->result))
return picolEval(i, argv[2]);
else if (argc == 5)
@@ -509,10 +526,12 @@ int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
}
int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
while (1) {
int retcode = picolEval(i, argv[1]);
if (retcode != PICOL_OK) return retcode;
if (retcode != PICOL_OK)
return retcode;
if (atoi(i->result)) {
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
continue;
@@ -530,7 +549,8 @@ int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
void *pd) {
if (argc != 1) return picolArityErr(i, argv[0]);
if (argc != 1)
return picolArityErr(i, argv[0]);
if (strcmp(argv[0], "break") == 0)
return PICOL_BREAK;
else if (strcmp(argv[0], "continue") == 0)
@@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
tofree = p;
while (1) {
char *start = p;
while (*p != ' ' && *p != '\0') p++;
while (*p != ' ' && *p != '\0')
p++;
if (*p != '\0' && p == start) {
p++;
continue;
}
if (p == start) break;
if (p == start)
break;
if (*p == '\0')
done = 1;
else
*p = '\0';
if (++arity > argc - 1) goto arityerr;
if (++arity > argc - 1)
goto arityerr;
picolSetVar(i, start, argv[arity]);
p++;
if (done) break;
if (done)
break;
}
free(tofree);
if (arity != argc - 1) goto arityerr;
if (arity != argc - 1)
goto arityerr;
errcode = picolEval(i, body);
if (errcode == PICOL_RETURN) errcode = PICOL_OK;
if (errcode == PICOL_RETURN)
errcode = PICOL_OK;
picolDropCallFrame(i); /* remove the called proc callframe */
return errcode;
arityerr:
@@ -594,14 +620,16 @@ arityerr:
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
char **procdata = malloc(sizeof(char *) * 2);
if (argc != 4) return picolArityErr(i, argv[0]);
if (argc != 4)
return picolArityErr(i, argv[0]);
procdata[0] = strdup(argv[2]); /* arguments list */
procdata[1] = strdup(argv[3]); /* procedure body */
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
}
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 1 && argc != 2) return picolArityErr(i, argv[0]);
if (argc != 1 && argc != 2)
return picolArityErr(i, argv[0]);
picolSetResult(i, (argc == 2) ? argv[1] : "");
return PICOL_RETURN;
}
@@ -631,9 +659,11 @@ int main(int argc, char **argv) {
int retcode;
printf("picol> ");
fflush(stdout);
if (fgets(clibuf, 1024, stdin) == NULL) return 0;
if (fgets(clibuf, 1024, stdin) == NULL)
return 0;
retcode = picolEval(&interp, clibuf);
if (interp.result[0] != '\0') printf("[%d] %s\n", retcode, interp.result);
if (interp.result[0] != '\0')
printf("[%d] %s\n", retcode, interp.result);
}
} else if (argc == 2) {
char buf[1024 * 16];
@@ -644,7 +674,8 @@ int main(int argc, char **argv) {
}
buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
fclose(fp);
if (picolEval(&interp, buf) != PICOL_OK) printf("%s\n", interp.result);
if (picolEval(&interp, buf) != PICOL_OK)
printf("%s\n", interp.result);
}
return 0;
}
+2 -1
View File
@@ -23,7 +23,8 @@
int main(int argc, char *argv[]) {
const char *prog = argv[0];
if (!prog) prog = "rusage";
if (!prog)
prog = "rusage";
if (argc < 2) {
tinyprint(2, prog, ": missing command\n", NULL);
+1 -1
View File
@@ -50,7 +50,7 @@
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "third_party/getopt/getopt.internal.h"
// clang-format off
+1 -1
View File
@@ -17,7 +17,7 @@
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time/time.h"
#include "libc/time.h"
volatile bool gotalrm;
+4 -2
View File
@@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
} while (x);
for (;;) {
*p++ = m[--i];
if (!i) break;
if (!(i % 3)) *p++ = ',';
if (!i)
break;
if (!(i % 3))
*p++ = ',';
}
*p = '\0';
return p;
+10 -5
View File
@@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
int Compare(const void *a, const void *b) {
struct Thing *x = (struct Thing *)a;
struct Thing *y = (struct Thing *)b;
if (x->i < y->i) return +1;
if (x->i > y->i) return -1;
if (x->i < y->i)
return +1;
if (x->i > y->i)
return -1;
return 0;
}
@@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
Append((uintptr_t)__oldstack, "__oldstack");
for (int i = 0;; ++i) {
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i]));
if (!argv[i]) break;
if (!argv[i])
break;
Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
}
for (int i = 0;; ++i) {
Append((uintptr_t)&environ[i],
xasprintf("&environ[%d] = %`'s", i, environ[i]));
if (!environ[i]) break;
if (!environ[i])
break;
Append((uintptr_t)environ[i],
xasprintf("environ[%d] = %`'s", i, environ[i]));
}
for (int i = 0;; i += 2) {
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i]));
if (!__auxv[i]) break;
if (!__auxv[i])
break;
Append((uintptr_t)&__auxv[i + 1],
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
}
+30 -11
View File
@@ -8,16 +8,18 @@
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/struct/stat.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/x/xiso8601.h"
#include "libc/time.h"
/**
* @fileoverview File metadata viewer.
@@ -27,6 +29,23 @@
bool numeric;
char *xiso8601(struct timespec ts) {
struct tm tm;
if (!localtime_r(&ts.tv_sec, &tm))
return 0;
int len = 128;
char *res = malloc(len);
char *ptr = res;
char *end = res + len;
if (!res)
return 0;
ptr += strftime(ptr, end - ptr, "%Y-%m-%d %H:%M:%S", &tm);
ptr += snprintf(ptr, end - ptr, ".%09ld", ts.tv_nsec);
ptr += strftime(ptr, end - ptr, "%z %Z", &tm);
unassert(ptr + 1 <= end);
return res;
}
const char *DescribeFileType(unsigned mode) {
switch (mode & S_IFMT) {
case S_IFIFO:
@@ -74,16 +93,16 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
"%-32s%s\n"
"%-32s%s\n"
"%-32s%s\n",
"bytes in file", st->st_size, "physical bytes", st->st_blocks * 512,
"device id w/ file", st->st_dev, "inode", st->st_ino,
"hard link count", st->st_nlink, "mode / permissions", st->st_mode,
DescribeFileType(st->st_mode), "owner id", st->st_uid, "group id",
st->st_gid, "flags", st->st_flags, "gen", st->st_gen,
"device id (if special)", st->st_rdev, "block size", st->st_blksize,
"access time", gc(xiso8601(&st->st_atim)), "modified time",
gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
gc(xiso8601(&st->st_ctim)), "birthtime",
gc(xiso8601(&st->st_birthtim)));
"bytes in file:", st->st_size, "physical bytes:", st->st_blocks * 512,
"device id w/ file:", st->st_dev, "inode:", st->st_ino,
"hard link count:", st->st_nlink, "mode / permissions:", st->st_mode,
DescribeFileType(st->st_mode), "owner id:", st->st_uid,
"group id:", st->st_gid, "flags:", st->st_flags, "gen:", st->st_gen,
"device id (if special):", st->st_rdev, "block size:", st->st_blksize,
"access time:", gc(xiso8601(st->st_atim)),
"modified time:", gc(xiso8601(st->st_mtim)),
"c[omplicated]time:", gc(xiso8601(st->st_ctim)),
"[birthtime]:", gc(xiso8601(st->st_birthtim)));
}
int main(int argc, char *argv[]) {
+142
View File
@@ -0,0 +1,142 @@
#include <fenv.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
#include "libc/calls/struct/aarch64.internal.h"
/*
Do you put lots of assert(!isnan(x)) in your code??
Your microprocessor has a feature to automate this.
Uncaught SIGFPE (FPE_FLTINV)
__math_invalidf at libc/tinymath/math_errf.c:88
logf at libc/tinymath/logf.c:100
main at examples/trapping.c:29
cosmo at libc/runtime/cosmo.S:105
_start at libc/crt/crt.S:116
This file shows how to use floating point exception
trapping with Cosmopolitan Libc.
*/
#define TRAPS (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
void spring_trap(int sig, siginfo_t *si, void *arg) {
// print signal safely
const char *msg;
int sic = si->si_code;
if (sic == FPE_INTDIV)
msg = "FPE_INTDIV: "; // integer divide by zero
else if (sic == FPE_INTOVF)
msg = "FPE_INTOVF: "; // integer overflow
else if (sic == FPE_FLTDIV)
msg = "FPE_FLTDIV: "; // floating point divide by zero
else if (sic == FPE_FLTOVF)
msg = "FPE_FLTOVF: "; // floating point overflow
else if (sic == FPE_FLTUND)
msg = "FPE_FLTUND: "; // floating point underflow
else if (sic == FPE_FLTRES)
msg = "FPE_FLTRES: "; // floating point inexact
else if (sic == FPE_FLTINV)
msg = "FPE_FLTINV: "; // invalid floating point operation
else if (sic == FPE_FLTSUB)
msg = "FPE_FLTSUB: "; // subscript out of range
else
msg = "SIGFPE: ";
write(1, msg, strlen(msg));
// recover from trap so that execution may resume
// without this the same signal will just keep getting raised
ucontext_t *ctx = arg;
#ifdef __x86_64__
if (ctx->uc_mcontext.fpregs) {
ctx->uc_mcontext.fpregs->mxcsr |= TRAPS << 7; // disable traps
ctx->uc_mcontext.fpregs->mxcsr &= ~TRAPS; // clear cages
return;
}
#elif defined(__aarch64__)
struct _aarch64_ctx *ac;
for (ac = (struct _aarch64_ctx *)ctx->uc_mcontext.__reserved; ac->magic;
ac = (struct _aarch64_ctx *)((char *)ac + ac->size)) {
if (ac->magic == FPSIMD_MAGIC) {
struct fpsimd_context *sm = (struct fpsimd_context *)ac;
sm->fpcr &= ~(TRAPS << 8); // disable traps
sm->fpsr &= ~TRAPS; // clear cages
return;
}
}
#endif
// exit if we can't recover execution
msg = "cannot recover from signal\n";
write(1, msg, strlen(msg));
_exit(1);
}
void setup_trap(void) {
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = spring_trap;
sigaction(SIGFPE, &sa, 0);
}
void activate_trap(void) {
feclearexcept(TRAPS);
if (feenableexcept(TRAPS)) {
static bool once;
if (!once) {
fprintf(stderr, "warning: trapping math isn't supported on this cpu\n");
once = true;
}
}
}
float ident(float x) {
return x;
}
float (*veil)(float) = ident;
int main(int argc, char *argv[]) {
float x;
setup_trap();
// test illegal math
activate_trap();
x = 0 / veil(0);
printf("0/0 = %g\n", x);
// test divide by zero
activate_trap();
x = 1 / veil(0);
printf("1/0 = %g\n", x);
// test divide by zero again
activate_trap();
x = -1 / veil(0);
printf("-1/0 = %g\n", x);
// test domain error
activate_trap();
x = logf(veil(-1));
printf("log(-1) = %g\n", x);
// test imaginary number
activate_trap();
x = sqrtf(veil(-1));
printf("sqrt(-1) = %g\n", x);
// test overflow
activate_trap();
x = expf(veil(88.8));
printf("expf(88.8) = %g\n", x);
// test underflow
activate_trap();
x = expf(veil(-104));
printf("expf(-104) = %g\n", x);
}
+2 -1
View File
@@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
if (iscntrl(code[0]) && !code[1]) {
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
if (code[0] == CTRL('C') || code[0] == CTRL('D'))
break;
} else if (startswith(code, "\e[") && endswith(code, "R")) {
yn = 1, xn = 1;
sscanf(code, "\e[%d;%dR", &yn, &xn);
+2 -1
View File
@@ -13,7 +13,8 @@
int main(int argc, char *argv[]) {
struct utsname names;
if (uname(&names)) return 1;
if (uname(&names))
return 1;
printf("%-10s %`'s\n", "sysname", names.sysname);
printf("%-10s %`'s\n", "release", names.release);
printf("%-10s %`'s\n", "version", names.version);
+989 -507
View File
File diff suppressed because it is too large. Load diff
+5 -3
View File
@@ -9,11 +9,11 @@
#endif
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/ftw.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/s.h"
#include "libc/stdio/ftw.h"
/**
* @fileoverview Directory walker example.
@@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
int main(int argc, char *argv[]) {
int flags = 0;
const char *dir;
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS;
if (argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL)
flags |= FTW_PHYS;
dir = argc < 2 ? "." : argv[1];
if (nftw(dir, display_info, 20, flags) == -1) {
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);
+9 -5
View File
@@ -16,7 +16,7 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/struct/tm.h"
#include "libc/time.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/musl/passwd.h"
@@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
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);
if (isatty(0) && (s = ttyname(0)))
appendf(&msg, " (%s)", s);
appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K");
@@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
if (optind < argc) {
// use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " ");
if (i)
appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') {
appends(&msg, "\r\n\e[K");
@@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) continue;
if (g_verbose) perror(pts);
if (errno == ENOENT)
continue;
if (g_verbose)
perror(pts);
}
write(fd, msg, appendz(msg).i);
close(fd);
+2 -91
View File
@@ -4,10 +4,8 @@
PKGS += LIBC
LIBC_ISYSTEM = \
libc/isystem/algorithm \
libc/isystem/alloca.h \
libc/isystem/ammintrin.h \
libc/isystem/any \
libc/isystem/ar.h \
libc/isystem/arm_acle.h \
libc/isystem/arm_bf16.h \
@@ -15,51 +13,16 @@ libc/isystem/arm_fp16.h \
libc/isystem/arm_neon.h \
libc/isystem/arpa/inet.h \
libc/isystem/arpa/nameser.h \
libc/isystem/array \
libc/isystem/assert.h \
libc/isystem/atomic \
libc/isystem/bit \
libc/isystem/bitset \
libc/isystem/byteswap.h \
libc/isystem/cassert \
libc/isystem/ccomplex \
libc/isystem/cctype \
libc/isystem/cerrno \
libc/isystem/cfenv \
libc/isystem/cfloat \
libc/isystem/charconv \
libc/isystem/chrono \
libc/isystem/cinttypes \
libc/isystem/ciso646 \
libc/isystem/climits \
libc/isystem/clocale \
libc/isystem/clzerointrin.h \
libc/isystem/cmath \
libc/isystem/codecvt \
libc/isystem/compare \
libc/isystem/complex \
libc/isystem/complex.h \
libc/isystem/condition_variable \
libc/isystem/cosmo.h \
libc/isystem/cpio.h \
libc/isystem/cpuid.h \
libc/isystem/crypt.h \
libc/isystem/csetjmp \
libc/isystem/csignal \
libc/isystem/cstdarg \
libc/isystem/cstdbool \
libc/isystem/cstddef \
libc/isystem/cstdint \
libc/isystem/cstdio \
libc/isystem/cstdlib \
libc/isystem/cstring \
libc/isystem/ctgmath \
libc/isystem/ctime \
libc/isystem/ctype.h \
libc/isystem/cwchar \
libc/isystem/cwctype \
libc/isystem/cxxabi.h \
libc/isystem/deque \
libc/isystem/dirent.h \
libc/isystem/dlfcn.h \
libc/isystem/elf.h \
@@ -67,57 +30,37 @@ libc/isystem/emmintrin.h \
libc/isystem/endian.h \
libc/isystem/err.h \
libc/isystem/errno.h \
libc/isystem/exception \
libc/isystem/execution \
libc/isystem/fcntl.h \
libc/isystem/features.h \
libc/isystem/fenv.h \
libc/isystem/filesystem \
libc/isystem/float.h \
libc/isystem/fnmatch.h \
libc/isystem/forward_list \
libc/isystem/fstream \
libc/isystem/ftw.h \
libc/isystem/functional \
libc/isystem/future \
libc/isystem/getopt.h \
libc/isystem/glob.h \
libc/isystem/grp.h \
libc/isystem/iconv.h \
libc/isystem/ifaddrs.h \
libc/isystem/immintrin.h \
libc/isystem/initializer_list \
libc/isystem/inttypes.h \
libc/isystem/iomanip \
libc/isystem/ios \
libc/isystem/iosfwd \
libc/isystem/iostream \
libc/isystem/iso646.h \
libc/isystem/istream \
libc/isystem/iterator \
libc/isystem/langinfo.h \
libc/isystem/libgen.h \
libc/isystem/limits \
libc/isystem/limits.h \
libc/isystem/link.h \
libc/isystem/linux/futex.h \
libc/isystem/linux/limits.h \
libc/isystem/linux/param.h \
libc/isystem/linux/types.h \
libc/isystem/list \
libc/isystem/locale \
libc/isystem/locale.h \
libc/isystem/malloc.h \
libc/isystem/map \
libc/isystem/math.h \
libc/isystem/memory \
libc/isystem/memory.h \
libc/isystem/mm3dnow.h \
libc/isystem/mm_malloc.h \
libc/isystem/mmintrin.h \
libc/isystem/mntent.h \
libc/isystem/monetary.h \
libc/isystem/mutex \
libc/isystem/mwaitxintrin.h \
libc/isystem/net/ethernet.h \
libc/isystem/net/if.h \
@@ -127,7 +70,6 @@ libc/isystem/netinet/in.h \
libc/isystem/netinet/ip.h \
libc/isystem/netinet/tcp.h \
libc/isystem/netinet/udp.h \
libc/isystem/new \
libc/isystem/nl_types.h \
libc/isystem/nmmintrin.h \
libc/isystem/nsync.h \
@@ -141,12 +83,9 @@ libc/isystem/nsync_note.h \
libc/isystem/nsync_once.h \
libc/isystem/nsync_time.h \
libc/isystem/nsync_waiter.h \
libc/isystem/numeric \
libc/isystem/omp-tools.h \
libc/isystem/omp.h \
libc/isystem/ompx.h \
libc/isystem/optional \
libc/isystem/ostream \
libc/isystem/paths.h \
libc/isystem/pmmintrin.h \
libc/isystem/poll.h \
@@ -154,27 +93,17 @@ libc/isystem/popcntintrin.h \
libc/isystem/pthread.h \
libc/isystem/pty.h \
libc/isystem/pwd.h \
libc/isystem/queue \
libc/isystem/random \
libc/isystem/ratio \
libc/isystem/regex \
libc/isystem/regex.h \
libc/isystem/resolv.h \
libc/isystem/sched.h \
libc/isystem/scoped_allocator \
libc/isystem/search.h \
libc/isystem/semaphore.h \
libc/isystem/set \
libc/isystem/setjmp.h \
libc/isystem/sgxintrin.h \
libc/isystem/shadow.h \
libc/isystem/shared_mutex \
libc/isystem/signal.h \
libc/isystem/smmintrin.h \
libc/isystem/span \
libc/isystem/spawn.h \
libc/isystem/sstream \
libc/isystem/stack \
libc/isystem/stdalign.h \
libc/isystem/stdarg.h \
libc/isystem/stdatomic.h \
@@ -182,18 +111,13 @@ libc/isystem/stdbool.h \
libc/isystem/stdc-predef.h \
libc/isystem/stdckdint.h \
libc/isystem/stddef.h \
libc/isystem/stdexcept \
libc/isystem/stdint.h \
libc/isystem/stdio.h \
libc/isystem/stdio_ext.h \
libc/isystem/stdlib.h \
libc/isystem/stdnoreturn.h \
libc/isystem/streambuf \
libc/isystem/string \
libc/isystem/string.h \
libc/isystem/string_view \
libc/isystem/strings.h \
libc/isystem/strstream \
libc/isystem/sys/auxv.h \
libc/isystem/sys/cdefs.h \
libc/isystem/sys/dir.h \
@@ -238,38 +162,26 @@ libc/isystem/sys/vfs.h \
libc/isystem/sys/wait.h \
libc/isystem/sysexits.h \
libc/isystem/syslog.h \
libc/isystem/system_error \
libc/isystem/termios.h \
libc/isystem/tgmath.h \
libc/isystem/thread \
libc/isystem/threads.h \
libc/isystem/time.h \
libc/isystem/tmmintrin.h \
libc/isystem/tuple \
libc/isystem/type_traits \
libc/isystem/typeindex \
libc/isystem/typeinfo \
libc/isystem/uchar.h \
libc/isystem/ucontext.h \
libc/isystem/uio.h \
libc/isystem/unistd.h \
libc/isystem/unordered_map \
libc/isystem/unordered_set \
libc/isystem/unwind.h \
libc/isystem/utility \
libc/isystem/utime.h \
libc/isystem/utmp.h \
libc/isystem/utmpx.h \
libc/isystem/valarray \
libc/isystem/variant \
libc/isystem/vector \
libc/isystem/version \
libc/isystem/wait.h \
libc/isystem/wchar.h \
libc/isystem/wctype.h \
libc/isystem/winternl.h \
libc/isystem/wmmintrin.h \
libc/isystem/x86intrin.h \
libc/isystem/xmmintrin.h
libc/isystem/xmmintrin.h \
LIBC_HDRS = $(filter %.h,$(LIBC_FILES)) $(LIBC_ISYSTEM)
LIBC_HDRS_H = $(filter %.h,$(LIBC_HDRS))
@@ -299,7 +211,6 @@ o/$(MODE)/libc: o/$(MODE)/libc/calls \
o/$(MODE)/libc/sysv \
o/$(MODE)/libc/testlib \
o/$(MODE)/libc/thread \
o/$(MODE)/libc/time \
o/$(MODE)/libc/tinymath \
o/$(MODE)/libc/vga \
o/$(MODE)/libc/x \
+7
View File
@@ -147,6 +147,13 @@ o/$(MODE)/libc/calls/pledge-linux.o: private \
-fPIC \
-ffreestanding
# we want -Os because:
# it makes a big difference
# it gets called very rarely
o/$(MODE)/libc/calls/sigcrashsig.o: private \
CFLAGS += \
-Os
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/calls/getcontext.o: libc/calls/getcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
+2 -1
View File
@@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
t.sn[5] = 0;
if (IsLinux()) {
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
if (sys_ioctl(fd, TIOCGPTN, &pty))
return -1;
t.sn[5] = 'p';
t.sn[6] = 't';
t.sn[7] = 's';
+3 -1
View File
@@ -237,7 +237,9 @@ int sys_munlock(const void *, size_t) libcesque;
int sys_munlockall(void) libcesque;
int sys_personality(uint64_t) libcesque;
int sys_ptrace(int, ...) libcesque;
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque;
int sysctlbyname(const char *, void *, size_t *, void *, size_t) libcesque;
int sysctlnametomib(const char *, int *, size_t *) libcesque;
int tmpfd(void) libcesque;
int touch(const char *, unsigned) libcesque;
int unveil(const char *, const char *) libcesque;
+4 -2
View File
@@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
* @asyncsignalsafe
*/
int cfsetspeed(struct termios *t, uint32_t speed) {
if (cfsetispeed(t, speed) == -1) return -1;
if (cfsetospeed(t, speed) == -1) return -1;
if (cfsetispeed(t, speed) == -1)
return -1;
if (cfsetospeed(t, speed) == -1)
return -1;
return 0;
}
+6 -3
View File
@@ -33,7 +33,8 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
char16_t var[4];
if (len && path[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong();
if (len + 2 > PATH_MAX)
return enametoolong();
path[len + 0] = u'\\';
path[len + 1] = u'\0';
}
@@ -84,7 +85,9 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
textwindows int sys_chdir_nt(const char *path) {
int len;
char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
if ((len = __mkntpath(path, path16)) == -1)
return -1;
if (!len)
return enoent();
return sys_chdir_nt_impl(path16, len);
}
+10 -5
View File
@@ -24,11 +24,16 @@
textwindows int _check_signal(bool restartable) {
int status;
if (_check_cancel() == -1) return -1;
if (!_weaken(__sig_check)) return 0;
if (!(status = _weaken(__sig_check)())) return 0;
if (_check_cancel() == -1) return -1;
if (status == 2 && restartable) return 0;
if (_check_cancel() == -1)
return -1;
if (!_weaken(__sig_check))
return 0;
if (!(status = _weaken(__sig_check)()))
return 0;
if (_check_cancel() == -1)
return -1;
if (status == 2 && restartable)
return 0;
return eintr();
}
+3 -2
View File
@@ -53,7 +53,7 @@ static dontinline int __clk_tck_init(void) {
cmd[0] = 1; // CTL_KERN
cmd[1] = 12; // KERN_CLOCKRATE
len = sizeof(clock);
if (sys_sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
if (sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
x = clock.hz;
} else {
x = -1;
@@ -61,7 +61,8 @@ static dontinline int __clk_tck_init(void) {
} else {
x = __getauxval(AT_CLKTCK).value;
}
if (x < 1) x = 100;
if (x < 1)
x = 100;
clk_tck = x;
return x;
}
+1 -1
View File
@@ -23,7 +23,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "libc/time.h"
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real,
int64_t real_coarse, int64_t boot) {
+2 -1
View File
@@ -44,7 +44,8 @@ int sys_clock_gettime_mono(struct timespec *time) {
#ifdef __x86_64__
// intel architecture guarantees that a mapping exists between rdtsc &
// nanoseconds only if the cpu advertises invariant timestamps support
if (!X86_HAVE(INVTSC)) return -EINVAL;
if (!X86_HAVE(INVTSC))
return -EINVAL;
#endif
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick;
+6 -3
View File
@@ -60,14 +60,17 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
}
return 0;
} else if (clock == CLOCK_MONOTONIC) {
if (!ts) return 0;
if (!ts)
return 0;
return sys_clock_gettime_mono(ts);
} else if (clock == CLOCK_BOOTTIME) {
struct timeval x;
size_t n = sizeof(x);
int mib[] = {CTL_KERN, KERN_BOOTTIME};
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1;
if (ts) *ts = timeval_totimespec(timeval_sub(timeval_real(), x));
if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1)
return -1;
if (ts)
*ts = timeval_totimespec(timeval_sub(timeval_real(), x));
return 0;
} else {
return -EINVAL;
+2 -1
View File
@@ -57,7 +57,8 @@ int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
clock_gettime(time_clock, &start);
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req);
if (timespec_cmp(start, deadline) >= 0) return 0;
if (timespec_cmp(start, deadline) >= 0)
return 0;
remain = timespec_sub(deadline, start);
if (timespec_cmp(remain, quantum) > 0) {
waitfor = timespec_sub(remain, quantum);
+8 -4
View File
@@ -32,10 +32,13 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
uint32_t msdelay;
struct timespec now;
for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1;
if (timespec_cmp(now, abs) >= 0) return 0;
if (sys_clock_gettime_nt(clock, &now))
return -1;
if (timespec_cmp(now, abs) >= 0)
return 0;
msdelay = timespec_tomillis(timespec_sub(abs, now));
if (_park_norestart(msdelay, waitmask)) return -1;
if (_park_norestart(msdelay, waitmask))
return -1;
}
}
@@ -48,7 +51,8 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
if (flags & TIMER_ABSTIME) {
abs = *req;
} else {
if ((rc = sys_clock_gettime_nt(clock, &now))) goto BailOut;
if ((rc = sys_clock_gettime_nt(clock, &now)))
goto BailOut;
abs = timespec_add(now, *req);
}
rc = sys_clock_nanosleep_nt_impl(clock, abs, m);
+2 -1
View File
@@ -46,7 +46,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
} else {
int rc;
struct timespec beg;
if (rem) sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
if (rem)
sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
struct timeval rel = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &rel);
if (rc == -1 && rem && errno == EINTR) {
+2 -1
View File
@@ -30,7 +30,8 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(int fd, int fildes) {
if (fd + 0u >= g_fds.n) return ebadf();
if (fd + 0u >= g_fds.n)
return ebadf();
struct Fd *f = g_fds.p + fd;
switch (f->kind) {
case kFdZip:
+4 -2
View File
@@ -97,12 +97,14 @@ int close(int fd) {
BLOCK_SIGNALS;
__fds_lock();
rc = close_impl(fd);
if (!__vforked) __releasefd(fd);
if (!__vforked)
__releasefd(fd);
__fds_unlock();
ALLOW_SIGNALS;
} else {
rc = close_impl(fd);
if (!__vforked) __releasefd(fd);
if (!__vforked)
__releasefd(fd);
}
STRACE("close(%d) → %d% m", fd, rc);
return rc;
Loaded 100 of 3958 files, more files were not shown because too many files have changed in this diff. Show more