Repository navigation
Conversation
…tory once The driver appended <binary's directory>/include as a system directory ahead of the defaults paths.c computes -- a line from before paths.c existed. That directory holds the compiler's declarations-only <string.h>, which paths.c deliberately puts LAST so it cannot shadow the C library's; added early, it did, and every build-tree compile without -I lost the POSIX half of <string.h> (strtok_r, strlcpy, ...). Run from $PATH, argv[0] has no '/', and the directory was ./include -- wherever the user happened to be. It is now added only when paths.c found no support files, which is what it was for. With it gone, a directory named both by -I and by the defaults was searched twice in a row, and #include_next from the C library's <limits.h> found that same file again, include guard set, so INT_MAX was never defined (the libc build itself broke). GCC searches such a directory once, where -I put it, as a system directory; so does EmbCC now, by plat_same_dir: device and inode where the host has them (macOS, Linux), spelling elsewhere -- EmbLinkOS's newlib stat has no inodes. tests/golden/install.sh compiles <string.h> + <limits.h> with and without -I lib/libc/include; the first case fails on the old driver and the second on one without the dedupe. build.ebm regenerated for platform_posix.c's <sys/stat.h>.
The first of the POSIX layer EmbLinkOS needs to leave newlib behind --
the part that asks the operating system nothing new.
<string.h> strtok_r, strerror_r (XSI's), strsep, strlcpy, strlcat,
memmem; strcasestr, memrchr, strchrnul, explicit_bzero
<stdlib.h> setenv, unsetenv (declared before, never defined), putenv,
clearenv; the mkstemp family, mkdtemp, mktemp; realpath;
posix_memalign, memalign, reallocarray; qsort_r; getsubopt;
random/srandom/initstate/setstate, the *rand48 family and
rand_r, each giving glibc's sequence for a seed
modules <libgen.h>, <fnmatch.h>, <getopt.h> (getopt_long, and
permuting as glibc's and newlib's do), <search.h> (AVL
tsearch, a growing hsearch, the _r forms)
<features.h> decides what a C header declares beyond ISO C: everything
unless the program asked for ISO C alone, and GNU's additions hidden
too when it names a POSIX version and nothing more, as glibc does.
The environment owns what it allocates: the startup vector is copied on
the first change, setenv's strings are freed when replaced, putenv's
are the caller's and never are. realpath resolves a component at a time,
so ".." after a symlink leaves the link's target. The entropy behind
temporary names is one function now (__tmp_bits), which stdio's tmpnam
will share.
tests/exec/posix-strings.c holds the values glibc 2.36 printed for the
same calls, run against both on a Linux kernel; where they differ the
test says why (tree shape, a growing hash table). Its tree checks catch
an AVL delete that skips rebalancing.
<stdio.h> gains fdopen, fileno, fmemopen, open_memstream, getline, getdelim, dprintf, asprintf and their v forms, fseeko, ftello, ctermid, flockfile/ftrylockfile/funlockfile and the _unlocked functions, and GNU's fopencookie, setbuffer and setlinebuf. <err.h> is new; its messages begin with program_invocation_short_name, which Linux's startup now sets from argv[0]. What it took inside: a FILE may be something other than a descriptor -- four functions and a cookie, laid out as glibc's cookie_io_functions_t -- and the seven places stdio reached the backend go through one dispatcher each; the stream lock NESTS. flockfile(stdout) and then printf takes it twice, and the old lock, which is not recursive, deadlocked -- and on a target with no futex spun forever, every single-threaded program; freopen reopens the stream it is given. It closed it and called fopen, which handed back a different FILE, so freopen(.., stdout) left stdout closed; past FOPEN_MAX, streams come in chunks from the heap that are never freed, so the flush at exit cannot walk into a closed one. fmemopen follows glibc since 2.22 (where a NUL goes); open_memstream's length moves only when a write passes it, which is POSIX's rule and not glibc 2.36's. tests/exec/posix-stdio.c and posix-files.c (mkstemp, realpath through symlinks, freopen of stdout) run on our libc and, posix-stdio at least, on glibc, on a Linux kernel; linux-libc-exec.sh runs both, and posix-strings, with no -I.
EmbLD wrote every image it linked with the mode a plain file gets, 0644 under the usual umask -- so `embcc hello.c -o hello` on a Linux host made a program that could not be run, and a test that installed one in a guest as /bin/sh got EACCES from the kernel's exec. It now gets 0777 less the umask, as GNU ld gives its output: ELF executables, script-linked images and EMBX alike, through plat_make_executable (chmod where the host has modes, nothing in the ISO host layer).
os/backend.h gains POSIX's half: about a hundred primitives, each
shaped like the call it serves (dup, pipe, fcntl, fstat, the *at forms,
fork/execve/spawn/waitpid, sigaction and the masks, clocks, mmap, ppoll,
sockets, termios, ptys, uname and sysconf's questions), with Linux's
numbers for everything that needs one. A backend that cannot do one
still defines it, failing with ENOSYS: os/absent.inc is the list,
guarded per primitive, which the bare-metal and posixlike backends
include whole.
os/linux/posix.c implements every one as syscalls on both 64-bit ABIs,
the numbers read out of the kernel's own uapi headers: open's flags
translated where aarch64 moves them, the kernel's shorter termios and
utsname converted, a signal restorer placed as bytes (checked against
both assemblers), posix_spawn as fork + actions + execve with the
child's error returned over a close-on-exec pipe.
Above them, src/posix: <unistd.h>, <fcntl.h>, <sys/stat.h>,
<dirent.h> (`.` and `..` returned, positions kept), the *at functions,
the exec family with PATH search and the script rule, <sys/wait.h>,
<spawn.h>, system and popen on posix_spawn (so they work where fork
does not), <sys/mman.h>, poll and select, sockets, inet_pton/ntop,
getaddrinfo over the hosts file, the OS's resolver or a DNS client
(resolv.conf, search domains, TCP for truncated answers), termios and
ptys, the user and group files, sysconf and the rest. Every public
POSIX name is weak -- none is reserved to the implementation, and a
program's own `read` or `getline` must win. sys/types.h takes hosted
widths (64-bit ino_t and dev_t, 32-bit uids).
Signals are two models: the kernel's where it delivers (Linux) and
lib/libc's own elsewhere -- a handler table, a mask and a pending set,
so a blocked raise is delivered on unblock -- and abort now raises
SIGABRT first, ending the program even if a handler returns.
tests/exec/posix-{fd,process,signals,net}.c hold what glibc 2.36 gave
for the same calls on the same kernel (they were run against both);
posix-process is its own /bin/sh and child. linux-libc-exec.sh runs
all 19 of its programs on x86-64 and aarch64 Linux: 76 runs exit 42.
The EmbLinkOS backend now defines every primitive of os/backend.h. It
carries over what EmbLinkOS's newlib adapter (user/lib/syscalls.c,
spawn_compat.inc) worked out POSIX means on that kernel, under its
three honest categories -- REAL, VACUOUS (true whatever is done: a
mask where nothing is delivered), ABSENT (ENOSYS, never pretended):
paths normalized here ("..", ".", the 256-byte limit), the
working directory this library's, a child's named in its
spawn or by PWD
files O_CLOEXEC translated (the kernel's is 0x100000),
O_DIRECTORY and O_NOFOLLOW honoured by looking, rename the
kernel's atomic one -- it was unlink-then-rename, which a
crash between the two turned into a lost destination
directories a snapshot that grows until the kernel's silent
truncation is ruled out -- it was a fixed 512 entries
descriptors dup, dup2, pipes, close-on-exec and the status flags;
record locks ENOSYS
processes posix_spawn on the native actions (descriptor snapshot,
cwd, kept status), attributes refused; waitpid on owned
child handles, a cancelled wait EINTR; fork and exec
ENOSYS
time the RTC in seconds, uptime in milliseconds, a thread's CPU
time, each at the precision it has
memory mmap's refusals where the kernel cannot honour a request
network IPv4 sockets and the kernel's resolver; poll on fd_poll
terminals termios and the window size through terminal control
tests/golden/libc-backends.sh reads the primitives out of os/backend.h
and requires every backend -- bare metal (Cortex-M and AVR), posixlike,
Linux on both ABIs, EmbLinkOS -- to define all 139; it fails naming the
one a backend left out.
…efuse time: - tz.c reads TZ as POSIX writes it (quoted names, Mm.w.d / Jn / n rules, times past 24h or negative), and zone names as TZif files (v1-3, with the footer rule) under TZDIR or /usr/share/zoneinfo; no TZ is /etc/localtime, an unusable one is UTC. tzset sets tzname/timezone/daylight. - struct tm carries tm_gmtoff and tm_zone; strftime's %z and %Z read them. - mktime reads tm_isdst as glibc does on the mornings the clocks change. - strptime: the "C" locale's conversions and glibc's readings -- digits stop where one more could not fit, %I joins %p, %C with %y, and the fields a date implies (wday, yday, and a date from %U/%W + weekday). Every value refereed against glibc 2.36 on Linux; tests/exec/posix-time.c holds them and runs in linux-libc-exec on x86-64 and AArch64. spawn: - posix_spawn_file_actions_t and posix_spawnattr_t are handles: init allocates, destroy frees, NULL is EINVAL. - __os_spawn_flags names the attribute flags a backend honours; setflags refuses the rest with ENOTSUP instead of a spawn that ignores them. - posix_spawnp: the system's directories without PATH, and a file the kernel cannot run (ENOEXEC) is run by /bin/sh. EmbLinkOS backend: embk_empty_env for its crt0; libc-emblinkos also makes an empty libm.a, so -lm finds no other library's. libc.sh: the harness's kill (newlib's floor, always EINVAL) is left out, so posix-signals reaches the library's own -- all 366 programs pass.
What EmbLinkOS's own tests asked for, building every program it has against this library (LIBC=emblibc in EmbLinkOS): - kill of another process is ENOSYS where the kernel cannot signal one (ESRCH claimed there was none; mrsh's job control hung on it). - spawn: POSIX's EBADF for a descriptor at or past OPEN_MAX from the add call itself, and __os_spawn_check, a new primitive, lets a backend refuse at that moment what its spawn can never do (EmbLinkOS: more than 61 actions, a path past 255 bytes, fchdir, an open flag it has no bit for). - EmbLinkOS backend: getrlimit(RLIMIT_NOFILE) is the kernel's 64, and fcntl(F_SETFL) with a flag it cannot set is EINVAL, as that OS says. - getpass, with echo off; <malloc.h> (malloc_usable_size, mallinfo2, malloc_stats, valloc, pvalloc -- QuickJS sizes its heap with the first); <string.h> brings <strings.h> and <stdlib.h> <alloca.h>, as glibc's do; ARG_MAX gives way to a build's own. C++ on EmbLinkOS: make libcxx-emblinkos, and libc-emblinkos now also makes librt.a with lib/rt/unwind.c (-D__EMBCC_RT_UNWIND) -- its programs start with -nostartfiles, so nothing registers tables for libgcc's. Everything there is built with --unwind-tables: for x86_64-elf C code has none by default, and the unwinder's own frames need them or every throw ends where it starts. EMBLINKOS_ARCH=aarch64 builds the other set. Fixed on the way: - <filesystem> kept its own copy of __os_fileinfo, shorter than the backend's since the POSIX fields: every status() wrote past it (a hang). libc-backends.sh now compares libcxx's copies of the contract with it, structs and all 45 prototypes; it fails on the old copy. - 16-bit int: tz.c's 1 << 18 buffer and an unsigned-short compare that made week 0 a huge day number on AVR; malloc's 64 KB chunk constant. Tests: malloc-gnu.c (refereed against glibc), posix-process's EBADF; libc.sh 367, linux-libc-exec 84 runs, libcxx-std's struct tm is 56 bytes now, glibc's.
- newlib's limits.h guards itself with _LIBC_LIMITS_H_, the word this library's used both as its guard and to tell the compiler's half it was there. With newlib's headers first (tools/build-libstdcxx.sh puts them there) its #include_next reached ours, ours was already "done", and the compiler's half -- INT_MAX -- was never read: libsupc++ and the libstdc++ tests failed to compile. Ours has its own guard now, sets the shared word only when it is the first C library's half, and always passes the chain on. - posix-process read argc/argv before knowing it ran where a kernel passes them: on Xtensa and the ESP32-C3, whose startup promises no argc, argv[1] was a wild load. The /bin/sh behaviour is under EMBCC_TEST_HAS_FS with the rest of what needs a filesystem. Full matrix: 840/860; these were the two real failures. The others -- timeouts and one killed run, all on the busy machine -- pass alone, as do these two: libc-limits, libm-long-double, rt, sroa, stack-args, frameless, cxx-libstdcxx, cxx-libsupcxx, xtensa-exec, embsim-esp32c3, install, libc-system, big-functions, linux-libc-exec, exec-boards.
The bare-metal and posix-like backends implement __os_write by calling write, __os_sbrk by calling sbrk: those names are the program's or the board's (weak defaults it replaces), newlib-style. The POSIX layer defined them too, weakly, calling the primitives back, so whichever an image linked first won -- and when proc.o came first on Xtensa and MIPS, sbrk called __os_sbrk called sbrk until the stack ran out. open, close, read, write, lseek, isatty, _exit and sbrk move to os/posix-names.c, built for Linux and EmbLinkOS only.
- <pthread.h>: threads (create, join, detach, exit, once, atfork, GNU's tryjoin/timedjoin/setname/getname), attributes, the three kinds of mutex with timedlock and clocklock, condition variables with a clock and clockwait, read-write locks (readers first, as glibc's default), barriers, spin locks, keys with destructor rounds. What cannot be honoured is refused: process-shared objects, robust and priority mutexes ENOTSUP, cancellation ENOTSUP (no cancellation points), a policy other than SCHED_OTHER EPERM. - <semaphore.h>: unnamed semaphores; sem_open ENOSYS, pshared ENOTSUP. - One thread table (src/threads/pthread.c) serves both spellings, keys live in each thread's record (no TLS needed beneath them), and pthread_exit longjmps to its thread's start, where destructors run. fork runs atfork's handlers through a weak reference. C11's layer is rewritten on it, which fixes three bugs it had: - mtx_lock could sleep holding the lock: a lock freed between its try and its exchange was taken by the exchange and then slept on. The three-state loop is the standard one now. - mtx_timedlock and cnd_timedwait read C11's absolute TIME_UTC deadline as a duration -- decades, for any real deadline. - thrd_exit called exit(), ending the program from any thread. tss_* work now (they always failed). timespec_get reads the backend's real-time clock to the nanosecond, not __os_time's whole seconds, so "now plus 30 ms" is not already past. Linux threads get glibc's 8 MiB stacks, mapped on demand. Where there is no futex (one thread), a timed condition wait waits out its deadline instead of returning at once. tests/exec/posix-threads.c: glibc 2.36 and this library both exit 42 on x86-64 and AArch64 Linux; on the boards (no threads, maybe no clock) it checks what one thread can show.
- <regex.h>: POSIX basic and extended syntax with glibc's numbers and messages, GNU's \+ \? \| \< \> \b \B \w \W \s \S, back-references, REG_STARTEND; POSIX's leftmost-longest match by backtracking, a single-character repeat as a loop (no stack per character), and REG_ESPACE instead of a hang past 20 million steps at one position. tests/exec/posix-regex.c: 88 cases whose expected answers are glibc's own output for the same calls. - <glob.h>: every flag glibc has, braces and tildes included; <ftw.h>: nftw with FTW_ACTIONRETVAL, and ftw. - <syslog.h>: RFC 3164 lines to /dev/log. With no logger there, a line is not dropped as glibc drops it: /dev/console under LOG_CONS, else standard error -- EmbLinkOS has no syslog daemon and says a capability must never silently vanish. - <langinfo.h>, <nl_types.h>: the "C" locale's items, CODESET "UTF-8"; no message catalogs, catgets returns the program's own text. posix-glob.c (glob, nftw, ftw, syslog's LOG_PERROR line) and posix-regex.c run in linux-libc-exec with glibc's answers; on the boards they check what needs no filesystem. The manual lists it all.
glibc 2.34 folded those libraries into libc and keeps them as empty archives, so Makefiles still name them; EmbCC's libc has POSIX threads, the clocks and openpty in libc.a. The driver takes the names as its own, as it takes -lm, instead of "cannot find libpthread.a". A program that calls what the library lacks (dlopen) still fails the link, naming it. tests/golden/linux.sh links one through the driver and runs it.
…ak symbol A weak reference left undefined has no PC-relative address in a position-independent program, and EmbCC's x86-64 code addresses everything PC-relative: every EmbLinkOS app (linked PIE) that pulled in fork failed to link on __pthread_atfork_run. The thread library sets __atfork_hook when it is first used, or on pthread_atfork, so a program that never names a pthread function still does not link it -- and a forked child of a threaded program always learns it has one thread. On EmbLinkOS (LIBC=emblibc, its `test pthreads` running this tree's tests/exec/posix-threads.c): exit 42, beside cxxlib, posix, posix-shell, spawn/process-compat, fd-sharing, terminal, tcc, embbuild, env, tz.
…'s does 604db0f moved read, write, open, close and _exit there, out of the portable half this golden builds; without it the archive it checks for closure needs them from nowhere.
addend_for() restated x86-64's end-of-instruction bias for every kind but the absolute ones, so a TPOFF32 -- an offset from the thread pointer, not from the pc -- went out as `t-4` while the object said `t`. Assembled, every __thread access read four bytes below its variable. It now asks target_reloc_addend(), the function the object writer uses. asm-S.sh compared only how MANY relocations the two objects had; it now compares each code relocation's offset, type, symbol and addend, and has a __thread case.
The kernel starts a thread with no thread pointer and crt0 built a block for the first thread only, so errno was one variable that every thread wrote, and a __thread variable in a second thread faulted. crt0 now hands over the template it found (os/tls-template.h: image, filesz, memsz, align), after the first thread's pointer is in place. From then errno.c answers with a thread-local errno, and the backend's thread trampoline lays a copy of the template out on the new thread's own stack and installs it before the thread runs anything that could touch one. On the stack because then nothing has to free it after errno's last use; a template over 256 KiB makes pthread_create fail with EAGAIN. A crt0 that predates the hand-over leaves the template empty, and the library behaves as before: one errno, threads with no block. posix-threads.c: four threads each set errno and an initialised __thread variable, wait at a barrier, and read both back (glibc agrees; Linux, all ten boards at every -O, and EmbLinkOS's test pthreads pass). The spin-lock failure no longer returns 42, the success code.
The shell's expansions of a word, in its order: tildes, parameters
with every ${...} form, command substitution through /bin/sh -c (by
posix_spawn, its standard error dup2'd to /dev/null or closed when
there is none -- a redirection in the command makes a shell without
/dev/null exit), arithmetic with C's operators, field splitting on
IFS, pathname expansion, quote removal.
The field is built as a glob pattern: what came from quotes is
escaped, so glob reads it exactly, and an unmatched field loses its
backslashes, which is quote removal done at the right moment.
posix-wordexp.c: 105 strings with glibc 2.36's answers, except eleven
rows where glibc departs from the shell (bash --posix answers those):
''x'' is two words there, a quoted empty expansion WRDE_NOSPACE, $G
not globbed, % << > ?: stop the arithmetic silently, ${U-ok} under
WRDE_UNDEF an error, a failing command WRDE_NOSPACE. ${U:?} returns 0
in glibc and kills the program on the second call; here it is
WRDE_BADVAL. Under the Linux harness the test is its own /bin/sh.
glibc passes the rest; ours passes all on x86-64 and AArch64 Linux
and the vector/flag checks on all ten boards.
Any to any through Unicode: UTF-8, UTF-16/-32 (and LE, BE), UCS-2/-4 (and LE, BE), WCHAR_T, ASCII, ISO-8859-1, ISO-8859-15, CP1252. glibc's conventions, found by running it: unmarked UTF-16/UTF-32 follow the machine's order and write a mark (alone, if the first character does not fit), a reset writes it again, //IGNORE reports EILSEQ once it has converted the rest, //TRANSLIT wins when both are given. iconv-translit.h is what //TRANSLIT substitutes: glibc 2.36's C-locale replacements, read by converting every code point from U+00A0 to U+10FFFF to ASCII//TRANSLIT -- 1784 characters, kept as 963 runs; ours gives the same for every one. posix-iconv.c: 59 conversions with glibc's results, except two rows: names like Utf_8 are accepted, and UTF-8 past U+10FFFF is refused (glibc passes F4 90 80 80 through). Passes on glibc and on our x86-64 and AArch64 Linux, the ten boards, PowerPC, big-endian MIPS, SPARC and ColdFire.
…itution
`#define m a.m` gives `a.m` and never more (C11 6.10.3.4p2). The
inner `m` was left alone while m was being expanded, but nothing
remembered that: pre-expanded as an argument and substituted into
another macro's body, it was rescanned and expanded again -- once per
level, so `R(s.m)` through `R(x) Q(x)` read `s.a.a.a.m`. glibc's
<signal.h> and ours give siginfo_t's fields this way (si_pid is
_sifields._kill.si_pid), so `printf("%d", si.si_pid)` through any
variadic macro failed to compile.
A suppressed name is now written with a byte in front (the
preprocessor works on text), which expand_text copies through without
expanding and which is taken out where a line's expansion is finished,
and before # and ## see an argument's spelling.
macro-self-reference.c: through Q, R(Q), S(R(Q)), a variadic macro and
#, and the siginfo shape; clang gives 42, the old compiler refuses it.
setjmp's buffer with the signal mask beside it: sigsetjmp saves the mask when asked and then is setjmp -- it must be, only setjmp's own frame can be returned to twice -- and siglongjmp puts the mask back before it jumps, so a handler left by siglongjmp leaves its signal deliverable. (The two functions are stdlib/signal.c's, committed with the rest.) posix-sigjmp.c: saved and unsaved masks, and out of a handler twice; glibc agrees.
Measured against glibc 2.36's exported functions; what was missing and is now here, by area: POSIX and XSI: waitid, posix_fallocate, fexecve, nice and getpriority/setpriority, the sched_* parameter calls, getresuid and the rest (POSIX.1-2024), sigqueue, clock_getcpuclockid, POSIX timers (the kernel's for a signal on Linux; a thread waiting on a condition variable for SIGEV_THREAD and elsewhere), locale objects and every _l function (one locale: newlocale gives it for C, POSIX, C.UTF-8), wcscasecmp, wcpcpy, wcsdup, mbsnrtowcs, wcsnrtombs, wcwidth and wcswidth (glibc's C.UTF-8 widths for every code point, generated), a64l/l64a, swab, getw/putw, tempnam, strfmon, fmtmsg, getdate, the Bessel functions (FreeBSD's msun), utmpx, message queues and System V IPC (Linux), <aio.h> (a thread per request, as glibc), if_nametoindex and the rest of <net/if.h>, the hosts/services/protocols/networks databases one entry at a time and their _r lookups, ftok, shadow passwords, cuserid, ttyslot. Linux: <sys/syscall.h> generated from the kernel's headers, and syscall(); epoll, eventfd, timerfd, signalfd, inotify, sendfile, splice, tee, copy_file_range, memfd_create, close_range, statfs, sysinfo, prctl, mount, xattrs, affinity, unshare/setns, getauxval (a new seam primitive, __os_auxv), getifaddrs, prlimit. Each is ENOSYS elsewhere unless it means something without that kernel (sendfile copies, statfs comes from statvfs, close_range closes). GNU and BSD: error/error_at_line, gettext and its family (msgid in "C"), dlopen/dlsym/dlerror/dladdr and dl_iterate_phdr, <elf.h>, <fts.h>, random_r and drand48_r, ecvt/fcvt/gcvt, arc4random, secure_getenv, on_exit, rawmemchr, strerrorname_np and sigabbrev_np, fcloseall, the *_unlocked wide calls, getpwent_r/fgetpwent/putpwent and the group equivalents, getusershell, the large-file *64 names (macros and symbols), C23's narrowing arithmetic (rounded once, by round-to- odd), totalorder, payloads, canonicalize, fromfp; isinf returns the sign, as glibc's. posix-lib2.c and posix-linux2.c hold every answer to glibc 2.36's (each ran there first as a transcript, identical line for line but for dl_iterate_phdr in glibc's dynamically linked program); both pass on glibc and on ours for x86-64 and AArch64.
…nd arc4random only of a system Xtensa's wchar_t is 16 bits, as GCC's there, so 0x1F600 arrives as 0xF600 -- a private-use character, width 1 -- which is right; the test assumed 32 bits. And on a board arc4random's bytes come from its clock and entropy source, which EmbSim and QEMU give differently, so the Pico's corpus comparison saw posix-lib2 run 27 more instructions on one.
…thread _np - getcontext, setcontext, makecontext, swapcontext for x86-64 and AArch64: bytes with their disassembly, as setjmp's are (libc.sh now checks these too), generated by assembling the source with GNU as. The layout is the kernel's ucontext and glibc's ucontext_t, so a signal handler's third argument reads the same; on Linux the signal mask is saved and restored by rt_sigprocmask, elsewhere there is no kernel mask to keep. - sighold, sigrelse, sigignore, sigpause, sigset (XSI), bsd_signal, sysv_signal, ssignal/gsignal, sigblock/sigsetmask/siggetmask. - errno: all 133 of Linux's numbers in <errno.h>, each with glibc's message and name (strerror, strerrorname_np), read from glibc 2.36. - feenableexcept, fedisableexcept, fegetexcept (x87 and SSE both on x86-64; FPCR's optional trap bits on AArch64), fesetexcept, fetestexceptflag, fegetmode/fesetmode. - open_wmemstream; ulimit; <mntent.h>; <netinet/ether.h>; inet_lnaof, inet_netof, inet_makeaddr; canonicalize_file_name, euidaccess, lchmod, getpt, group_member, wcstoq; qecvt and the long double family; twalk_r. - pthread: setaffinity_np and getaffinity_np by each thread's kernel id, attr affinity applied as the thread starts, getattr_np with the real stack (a new seam primitive, __os_thread_stack), the default attributes, pthread_sigqueue, pthread_clockjoin_np, the mutexattr priority ceiling, and GNU's _np aliases. - Linux: preadv2, pwritev2, recvmmsg, sendmmsg, renameat2, execveat, tgkill, statx. posix-lib3.c holds glibc's answers (but for pthread_getattr_np on the first thread, which glibc cannot answer without /proc); posix-ucontext.c runs coroutines on x86-64 and AArch64 and agrees with glibc. Both pass on Linux (both architectures), the ten boards, PowerPC, MIPS, SPARC, ColdFire and Xtensa.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #167 (which is on #166). Until those merge, this diff includes their commits. This PR's own commits start at
asm: -S writes a thread-local's TPOFF32.asm: -S writes a thread-local's TPOFF32 without the PC-relative -4: a compiler bug.-SprintedR_X86_64_TPOFF32, t-4where the object hadt, so assembling-Soutput put every__threadaccess four bytes off.addend_for()now askstarget_reloc_addend(), which the object writer uses.asm-S.shhad compared only how many relocations the two objects held. It now compares each code relocation's offset, type, symbol and addend, and has a__threadcase. The new check fails on the old compiler.libc: errno per thread on EmbLinkOS, and every thread its own TLS block: EmbLinkOS's crt0 now hands over the TLS template (lib/libc/os/tls-template.h).errnobecomes thread-local, and the backend's thread trampoline lays a copy of the template on the new thread's stack before the thread runs. A crt0 that predates the hand-over leaves the template empty, and the library then behaves as before. The EmbLinkOS side is commitac79846on itsemblibcbranch, not pushed.libc: wordexp and wordfree: every expansion the shell does to a word, in the shell's order. Command substitution goes throughposix_spawnof/bin/sh -c.libc: iconv: any to any among UTF-8/16/32, UCS-2/4, WCHAR_T, ASCII, ISO-8859-1/15 and CP1252.//TRANSLITuses glibc's C-locale substitutions, identical for all 1784 characters.cpp: a macro's self-reference stays unexpanded through argument substitution: a compiler bug. With#define m a.m, the innermwas expanded again whenever the text went through another macro's arguments, soR(s.m)becames.a.a.a.m. glibc's and our<signal.h>definesi_pidthis way, which brokeprintf("%d", si.si_pid)inside any variadic macro. The name is now marked as not expandable (the preprocessor works on text, so the mark is a byte).macro-self-reference.ctests it: clang gives 42, and the old compiler refuses to compile it.libc: sigsetjmp and siglongjmp.libc: the rest of POSIX and XSI, Linux's interfaces, and much of GNU's: about 400 functions, found by comparing against glibc 2.36's exported symbols.waitid, POSIX timers, locale objects and every_lfunction,wcwidth(glibc's C.UTF-8 widths, generated), message queues, System V IPC,<aio.h>,fts,utmpx, shadow, the Bessel functions,getdate,strfmon,fmtmsg, and thenetdbenumerations and_rlookups.<sys/syscall.h>andsyscall(), epoll, eventfd, timerfd, signalfd, inotify,sendfile,memfd_create,statfs,sysinfo,prctl, affinity,getifaddrs, and a new seam primitive,__os_auxv. Elsewhere each isENOSYS, unless it has a meaning without that kernel.error(), gettext,dlopen/dl_iterate_phdr,<elf.h>,random_r,arc4random, the*64names, C23's narrowing math (rounded once, by round-to-odd),totalorder, payloads andfromfp.posix-lib2.candposix-linux2.chold glibc's answers, from transcripts identical line for line.libc: ucontext, XSI signals, traps, the errno table, mntent, ether, pthread _np:getcontext,setcontext,makecontextandswapcontexton x86-64 and AArch64, glibc's layout. The machine code is bytes generated with GNU as, andlibc.shchecks them against the assembler.sigholdtosigset) and the BSD masks;feenableexceptand the other trap and mode calls;open_wmemstream;<mntent.h>;<netinet/ether.h>;ulimit; theqecvtfamily;twalk_r._npcalls: affinity,getattr_np(a new seam primitive,__os_thread_stack),clockjoin_np, default attributes,pthread_sigqueue.preadv2,renameat2andstatx.posix-lib3.candposix-ucontext.chold glibc's answers.How it was checked
glibc 2.36 as referee on Linux QEMU:
posix-wordexp.c: 105 strings. Eleven rows follow bash--posixwhere glibc departs from the shell, each marked in the test.posix-iconv.c: 59 conversions, with two marked differences.errno/__threadcheck added toposix-threads.c.Boards:
posix-threads,posix-wordexpandposix-iconvpass at every -O on the ten boards ofexec-boards.sh, and the latter two on PowerPC, big-endian MIPS, SPARC and ColdFire.EmbLinkOS:
test pthreadspasses, as dotest accounts, which starts a dynamically linked app with a thread-localerrno, and the earlier console set.ucontext round: full matrix: 848 of 861 passed. All 13 failures were timeouts under load, and each passes run alone. Fuzz: seeds 10201-10500 on six boards, clean. EmbLinkOS builds on this library and passes its console set.
The round before: full matrix. Everything that failed in it passes alone, except two mistakes in my test:
wcwidthabove U+FFFF asked of Xtensa's 16-bitwchar_t, andarc4randomasked on a board, where EmbSim's and QEMU's instruction counts must agree. Both are fixed. Fuzz: seeds 9601-9900 on the first part and 9901-10200 on the whole, both clean.Not yet done
test fd-sharingstill fails now and then. An instrumented run shows a kernel ordering problem, not the library: the parent'sopen(O_TRUNC)is undone by an earlier child's descriptor being released afterwaitpidreturned. Details are in EmbLinkOS'sdocs/EMBLIBC.md.