Sortix
Sortix Download Manual Development Source Code News Blog More

POSIX 2024 Changes

Jonas 'Sortie' Termansen on 2024-06-28

POSIX.1-2024 has just been released with a lot of exciting and interesting improvements and removals compared to POSIX-1.2008. The html version of the standard has not been uploaded yet as of this writing. The official list of new functions in the standard itself is very incomplete, so I combed through the CHANGE HISTORY sections in the official pdf, and I present you with the most accurate list of the changes so far.

Sortix is among the very first operating systems to implement most of the new interfaces. I had already implemented much of POSIX 2024 several years ago, and I just implemented a lot of the remaining interfaces in a weekend hackathon, with a few things still missing. Although Sortix only implements most parts of POSIX so far, the POSIX 2024 aspects are largely implemented or has been explicitly rejected.

If you want to try out the new POSIX 2024 features in practice, why not try out the latest Sortix nightly build?

#define _POSIX_C_SOURCE 202405L /* to use the new POSIX */
#define _XOPEN_SOURCE 800 /* to use the new XSI option */

Overview

New Functions New Features New Utilities Removed
_Fork()ABALTMON_x, ALTMON_xset -o pipefailasctime_r()
accept4()bind() port 0awk featuresctime_r()
aligned_alloc (C11)CMSG_LEN, CMSG_SPACEcd -efattach()
asprintf()ESOCKTNOSUPPORTdd iflags=fullblockfdetach()
dladdr()FD_CLOFORK, F_DUPFD_CLOFORKfind -print0 -iname -mountftw()
dup3()FNM_CASEFOLD, FNM_IGNORECASEgettextgetitimer()
<endian.h>F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKWhead -cgetmsg()
ffsl(), ffsll() (XSI)fopen() "ex"logger -fiptgetpmsg()
getentropy()f_owner_ex, F_OWNER_PGRP, F_OWNER_PIDmailx -Egets()
getlocalename_l()FTW_XDEV (XSI)make featuresgettimeofday()
getresgid() (XSI)GETENTROPY_MAXmsgfmtioctl()
getresuid() (XSI)LC_GLOBAL_LOCALEngettextisascii()
<libintl.h>LOG_UPTO (XSI)ps -w [1]isastream()
memmem() [1]M_1_SQRTPI, M_EGAMMA, M_PHIreadlink_longjmp()
mkostemp()MAP_ANONYMOUSrealpathposix_trace_*()
pipe2()M_*l <math.h>realpath -Eepthread_getconcurrency()
posix_close()MSG_CMSG_CLOEXEC, MSG_CMSG_CLOFORKread -dpthread_setconcurrency()
posix_devctl() (DC)M_SQRT1_3, M_SQRT3rm -dvputmsg()
posix_getdents()NSIG_MAXsed -E s///iputpmsg()
posix_spawn_file_actions_addchdir() (SPN)O_CLOFORKstty rows colsrand_r()
posix_spawn_file_actions_addfchdir() (SPN)_PC_FALLOCssty sizesetitimer()
ppoll()_PC_TEXTDOMAIN_MAXtail -r_setjmp()
pthread_cond_clockwait()POSIX_CLOSE_RESTARTtest -ef -nt -ot > <setpgrp()
pthread_mutex_clocklock()_POSIX_DEVICE_CONTROL (DC)timeoutsighold()
pthread_rwlock_clockrdlock()_POSIX_FALLOCulimit -HSacdnstvfsigignore()
pthread_rwlock_clockwrlock()POSIX_SPAWN_SETSID (SPN)xargs -r0siginterrupt()
ptsname_r() (XSI)PTHREAD_NULLxgettextsigpause()
qsort_r()posix_tnode (XSI)sigrelse()
quick_exit() (C11)reclen_tsigset()
reallocarray()REG_MINIMALtempnam()
secure_getenv()_SC_DEVICE_CONTROL (DC)test -a -o ( )
sem_clockwait()_SC_NPROCESSORS_CONFtoascii()
setresgid() (XSI)_SC_NPROCESSORS_ONLN_tolower()
setresuid() (XSI)_SC_NSIG_toupper()
sig2str()SEEK_DATA, SEEK_HOLEulimit()
<stdalign.h>SHM_FAILED (XSI)utime()
<stdatomic.h>SOCK_CLOEXEC, SOCK_CLOFORK, SOCK_NONBLOCKfort77(1)
<stdnoreturn.h>SO_DOMAIN, SO_PROTOCOLqmove(1)
str2sig()strftime %s %Ob %OBqselect(1)
strlcat()strptime %s %Ob %OB %Oh %F %g %G %u %V %z %Zqalter(1)
strlcpy()struct winsizeqmsg(1)
tcgetwinsize()TEXTDOMAIN_MAXqsig(1)
tcsetwinsize()time_t 64-bitqdel(1)
<threads.h> (C11)tm_gmtoff, tm_zoneqrerun(1)
vasprintf()WCOREDUMPqstat(1)
<uchar.h> (C11)qhold(1)
wcslcat()qrls(1)
wcslcpy()qsub(1)

Green additions means the interface is implemented in Sortix.
Red additions means the interface will not be implemented in Sortix.
Orange additions means the interface is optional and will not be implemented in Sortix.
Black additions means the interface still needs to be implemented in Sortix.
Green removals means the interfaced was never implemented in Sortix.
Orange removals means the interface remains implemented in Sortix as extensions.
[1] The implementation has not yet merged to main and is not in the nigtly build.
Last updated: 2024-12-16

New Functions

_Fork()

Status: Austin Group Bug #62 implemented 2024-06-23 in Sortix.

#include <unistd.h>
pid_t _Fork(void);

_Fork is an async signal safe version of fork that doesn't call pthread_at_fork handlers. Sortix doesn't have pthread_at_fork and fork just invokes _Fork directly.

accept4()

Status: Austin Group Bug #62 implemented 2013-03-19 in Sortix.

#include <sys/socket.h>
int accept4(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len, int flag);

accept4 is like accept but has a flags parameter that lets one set SOCK_NONBLOCK, SOCK_CLOEXEC, and CLO_CLOFORK.

aligned_alloc()

Status: C11 feature not yet implemented in Sortix.

#include <stdlib.h>
void *aligned_alloc(size_t alignment, size_t size);

aligned_alloc is a C11 function that allocates memory with the specified alignment. This interface is not yet implemented in Sortix because the malloc implementation does not yet support arbitrary alignment.

asprintf()

Status: Austin Group Bug #1496 implemented 2014-01-20 in Sortix.

#include <stdio.h>
int asprintf(char **restrict ptr, const char *restrict format, ...);
int vasprintf(char **restrict ptr, const char *restrict format, va_list ap);

asprintf formats the string and allocates the appropriate memory with malloc.

dladdr()

Status: Austin Group Bug #993 implemented 2024-06-23 in Sortix.

#include <dlfcn.h>
typedef struct {
  const char *dli_fname;
  void *dli_fbase;
  const char *dli_sname;
  void *dli_saddr;
} Dl_info_t;
int dladdr(const void *restrict addr, Dl_info_t *restrict dlip);

dladdr resolves an address to the shared object containing that address. It's unclear what value the Open Group saw in this interface since it only seems useful for debugging. I wonder if it adds constraints on the dynamic linking implementation. I can't think of anything useful a portable POSIX application can do with this information, although the austin group bug suggests it can be open files relative to the shared object (which seems a bit hacky).

POSIX.1-2024 appears to have made an editorial mistake and standardized the type as Dl_info_t (only available on Solaris and OmniOS) instead of Dl_info (which is available everywhere except AIX). OpenBSD since added Dl_info_t once they realized the mistake had been made. OpenBSD brought the issue up with POSIX in Austin Group Bug #1847, which was resolved by requiring both names.

Sortix does not have dynamic linking yet, but a stub dladdr has been added that fails at runtime.

dup3()

Status: Austin Group Bug #411 implemented 2013-09-23 in Sortix.

#include <unistd.h>
int dup3(int fildes, int fildes2, int flag);

dup3 duplicates a file descriptor and optionally sets the FD_NONBOCK, FD_CLOEXEC, and FD_CLOFORK flags on the new file descriptor.

<endian.h>

Status: Austin Group Bug #162 implemented 2013-02-14 in Sortix.

#include <endian.h>
#define BYTE_ORDER [LITTLE_ENDIAN or BIG_ENDIAN]
#define LITTLE_ENDIAN [...]
#define BIG_ENDIAN [...]
int16_t htobe16(uint16_t host_16bits);
uint32_t htobe32(uint32_t host_32bits);
uint64_t htobe64(uint64_t host_64bits);
uint16_t htole16(uint16_t host_16bits);
uint32_t htole32(uint32_t host_32bits);
uint64_t htole64(uint64_t host_64bits);

<endian.h> solves all of your endian conversion needs.

ffsl(), ffsll()

Status: Austin Group Bug #617 implemented 2013-07-12 in Sortix.

#include <strings.h>
int ffsl(long i);
int ffsll(long long i);

ffsl() and ffsll() are long and long long variants of ffs that returns the index of the first set bit (counting from the least significant bit starting from 1).

getentropy()

Status: Austin Group Bug #1134 implemented 2014-07-14 in Sortix.

#include <limits.h>
#define GETENTROPY_MAX [...]
#include <unistd.h>
int getentropy(void *buffer, size_t length);

getentropy returns up to GETENTROPY_MAX of cryptographically secure randomness, useful to initialize a random number generator.

Sortix has all the kernel facilities to supply random numbers, but it does not yet have a method for gathering entropy, and the randomness is only secure if you manually seeded your operating system entropy.

getlocalename_l()

Status: Austin Group Bug #1220 implemented 2024-06-23 in Sortix.

#include <locale.h>
#define LC_GLOBAL_LOCALE [...]
const char *getlocalename_l(int category, locale_t locobj);

getlocalename_l returns the name of the locale specified by the category and locale object (or LC_GLOBAL_LOCALE for the global locale).

Sortix doesn't fully implement locales but the function behaves appropriately for the default C / POSIX locale.

getresgid(), getresuid(), setresgid(), setresuid() (XSI)

Status: Austin Group Bug #1344 & #1666 optionally not implemented in Sortix.

#include <unistd.h>
int getresgid(gid_t *restrict rgid, gid_t *restrict egid, gid_t *restrict sgid);
int getresuid(uid_t *restrict ruid, uid_t *restrict euid, uid_t *restrict suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
int setresuid(uid_t ruid, uid_t euid, uid_t suid);

These are optional XSI extensions for getting and setting the user and group values atomically for the process.

Sortix is not yet secure for multi-user uses and intentionally does not have the concept of setuid/setgid executables, and therefore does not have the concept of the saved uid/gids. For these reasons, implementing these optional system calls has been postponed.

<libintl.h>

Status: Austin Group Bug #1122 implemented a long time in Sortix by porting gettext.

#include <libintl.h>
char *bindtextdomain(const char *, const char *);
char *bind_textdomain_codeset(const char *, const char *);
char *dcgettext(const char *, const char *, int);
char *dcgettext_l(const char *, const char *, int, locale_t);
char *dcngettext(const char *, const char *, const char *, unsigned long int, int);
char *dcngettext_l(const char *, const char *, const char *, unsigned long int, int, locale_t);
char *dgettext(const char *, const char *);
char *dgettext_l(const char *, const char *, locale_t);
char *dngettext(const char *, const char *, const char *, unsigned long int);
char *dngettext_l(const char *, const char *, const char *, unsigned long int, locale_t);
char *gettext(const char *);
char *gettext_l(const char *, locale_t);
char *ngettext(const char *, const char *, unsigned long int);
char *ngettext_l(const char *, const char *, unsigned long int, locale_t);
char *textdomain(const char *);

POSIX has standardized the key interfaces in libintl from gettext, which Sortix has had a port of for a long time.

memmem()

Status: Austin Group Bug #1061 implemented in the Sortix volatile build and is not merged to main yet.

#include <string.h>
void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);

This interface has not yet been merged to Sortix main and is not available in the nightly builds, but is available in the volatile builds.

I still need to remember the fast algorithm for memmem which I learned in university and I'm having fun figuring it out from first principles, but I didn't solve it fully yet, and decided to focus on the rest of POSIX 2024. No spoilers please but come back later. :)

mkostemp()

Status: Austin Group Bug #411 & #1318 & #1350 implemented 2015-02-06 in Sortix.

#include <stdlib.h>
int mkostemp(char *template, int flag);

mkostemp() creates a temporary file like mkstemp but allows one to set additional O_ flags on the open() call.

pipe2()

Status: Austin Group Bug #411 implemented 2024-01-15 in Sortix.

#include <unistd.h>
int pipe2(int fildes[2], int flag);

pipe2() creates a pair of file descriptors constituting a pipe like pipe() but lets one set the O_NONBLOCK, O_CLOEXEC, and O_CLOFORK flags.

posix_close()

Status: Austin Group Bug #529 will not be implemented in Sortix.

#include <unistd.h>
#define POSIX_CLOSE_RESTART [...]
int posix_close(int fildes, int flag);

close() should be used instead. POSIX 2024 defined this replacement interface because some broken legacy operating systems could fail with EINTR in close() on slow devices, instead of returning 0 and either completing the operation in the background or aborting it.

However, this means most programs need to be updated to use the more complicated alternative function instead for no practical gain, which isn't going to happen. The standard has added a lot of complexity where none needs to exist, which is rejected in Sortix. I don't want to contribute to this mess. close() never fails with EINTR on Sortix.

posix_devctl() (DC)

Status: Austin Group Bug #729 is optional and will not be implemented in Sortix.

#include <devctl.h>
int posix_devctl(int fildes, int dcmd, void *restrict dev_data_ptr,
                 size_t nbyte, int *restrict dev_info_ptr);

ioctl() should be used instead. POSIX 2024 defined this optional function as a replacement for ioctl() but never defined any way for portable applications to actually use it. I tend to like explicitly specifying the size of the input object. The dev_info_ptr parameter is especially useless as its semantics are not defined, and often the desired output does not necessarily fit in an int type.

The ioctl() interface is fine and this alternative function is rejected in Sortix as it is optional in POSIX 2024.

posix_getdents()

Status: Austin Group Bug #697 won't be implemented for now in Sortix.

#include <dirent.h>
typedef [...] reclen_t;
struct posix_dent {
  ino_t d_ino;
  reclen_t d_reclen;
  unsigned char d_type;
  char d_name[];
};
ssize_t posix_getdents(int fildes, void *buf, size_t nbyte, int flags);

readdir() should be used instead. readdirents() is a similar Sortix-specific system call that will likely be replaced with something else in the future. This new posix_getdents function is due to a mess of divergent getdents() functions. It is unfortunate they used struct posix_dent instead of struct dirent as they did not want to mandate the addition of the common d_type field in struct dirent. However, posix_getdents is decent and may be implemented in the future in Sortix.

posix_spawn_file_actions_addchdir(), posix_spawn_file_actions_addfchdir() (SPN)

Status: Austin Group Bug #1208 is optional and is not implemented in Sortix.

#include <spawn.h>
int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t *restrict file_actions, const char *restrict path);
int posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t *file_actions, int fildes);

These optional new interfaces set the working directory for the new process when using posix_spawn. Sortix does not implement the optional posix_spawn interface at this time.

ppoll()

Status: Austin Group Bug #1263 implemented 2012-12-29 in Sortix.

#include <poll.h>
int ppoll(struct pollfd fds[], nfds_t nfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask);

ppoll is like poll but atomically applies another signal mask while waiting for the requested conditions to occur. Importantly ppoll makes it possible to safely handle signals in the main loop without race conditions. All signals can be blocked by default and then unblocked in the ppoll invocation, where the signal handlers run without racing with other code at a safe point, and the ppoll loop will wake afterwards so the signal can be fully handled.

pthread_cond_clockwait(), pthread_mutex_clocklock(), pthread_rwlock_clockrdlock(), pthread_rwlock_clockwrlock(), sem_clockwait()

Status: Austin Group Bug #1216 implemented 2024-06-23 in Sortix.

#include <pthread.h>
int pthread_cond_clockwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, clockid_t clock_id, const struct timespec *restrict abstime);
int pthread_mutex_clocklock(pthread_mutex_t *restrict mutex, clockid_t clock_id, const struct timespec *restrict abstime);
int pthread_rwlock_clockrdlock(pthread_rwlock_t *restrict rwlock, clockid_t clock_id, const struct timespec *restrict abstime);
int pthread_rwlock_clockwrlock(pthread_rwlock_t *restrict rwlock, clockid_t clock_id, const struct timespec *restrict abstime);
#include <semaphore.h>
int sem_clockwait(sem_t *restrict sem, clockid_t clock_id, const struct timespec *restrict abstime);

These interfaces wait for a thread operation with an absolute timeout, but allow one to specify which clock to use. Importantly this lets one specify the newly-mandatory CLOCK_MONOTONIC which lets one calculate the correct time to wake, without worrying about CLOCk_REALTIME moving backwards or forwards.

ptsname_r() (XSI)

Status: Austin Group Bug #508 implemented 2016-11-29 in Sortix.

#include <stdlib.h>
int ptsname_r(int fildes, char *name, size_t namesize);

ptsname_r is a thread-safe version of ptsname that lets one obtain the name of an allocated pseudo-terminal.

qsort_r()

Status: Austin Group Bug #900 implemented 2024-03-09 in Sortix.

#include <stdlib.h>
void qsort_r(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *, void *), void *arg);

qsort_r is a version of qsort that lets one provide a context pointer to the comparison function, which is a thread-safe way to provide additional data to the comparison function

reallocarray()

Status: Austin Group Bug #1218 implemented 2014-06-20 in Sortix.

#include <stdlib.h>
void *reallocarray(void *ptr, size_t nelem, size_t elsize);

reallocarray reallocates an array with a multiplication check to catch overflows, much like how calloc provides a multiplication check for malloc. reallocarray can also be used for the initial allocation without the zeroing semantics of calloc.

secure_getenv()

Status: Austin Group Bug #922 implemented 2024-06-23 in Sortix.

#include <stdlib.h>
char *secure_getenv(const char *name);

secure_getenv is like getenv but returns NULL if the program is a setuid or setgid executable where the environment is not trusted. Sortix intentionally does not the setuid/setgid executable concept as a security improvement and secure_getenv is an alias for getenv.

sig2str(), str2sig()

Status: Austin Group Bug #1138 implemented 2024-06-23 in Sortix.

#include <signal.h>
int sig2str(int signum, char *str);
int str2sig(const char *restrict str, int *restrict pnum);

sig2str provides the symbolic "FOO" string name of the SIGFOO value, and str2sig returns the value of the SIGFOO signal by its symbolic "FOO" string name.

I love this. We need it for errno too. Bonus points if we're able to enumerate all the available signal and errno values.

<stdalign.h> (C11)

Status: C11 feature implemented LONG AGO in Sortix.

#include <stdalign.h>
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1

This header adds the new alignas and alignof keywords in C11. Sortix gets this header via GCC.

<stdatomic.h> (C11)

Status: C11 feature implemented LONG AGO in Sortix.

#include <stdatomic.h>
struct atomic_flag { ... };
typedef atomic_foo _Atomic foo;
enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst };
#define ATOMIC_{BOOL,CHAR,CHAR16_T,CHAR32_T,WCHAR_T,SHORT,INT,LONG,LLONG,POINTER}_LOCK_FREE [...]
#define ATOMIC_FLAG_INIT [...]
#define ATOMIC_VAR_INIT(value) [...] /* Obsolescent */
#define kill_dependency() [...]
_Bool atomic_compare_exchange_strong(volatile A *, C *, C);
_Bool atomic_compare_exchange_strong_explicit(volatile A *, C *, C, memory_order, memory_order);
_Bool atomic_compare_exchange_weak(volatile A *, C *, C);
_Bool atomic_compare_exchange_weak_explicit(volatile A *, C *, C, memory_order, memory_order);
C atomic_exchange(volatile A *, C);
C atomic_exchange_explicit(volatile A *, C, memory_order);
C atomic_fetch_add(volatile A *, M);
C atomic_fetch_add_explicit(volatile A *, M, memory_order);
C atomic_fetch_and(volatile A *, M);
C atomic_fetch_and_explicit(volatile A *, M, memory_order);
C atomic_fetch_or(volatile A *, M);
C atomic_fetch_or_explicit(volatile A *, M, memory_order);
C atomic_fetch_sub(volatile A *, M);
C atomic_fetch_sub_explicit(volatile A *, M, memory_order);
C atomic_fetch_xor(volatile A *, M);
C atomic_fetch_xor_explicit(volatile A *, M, memory_order);
void atomic_init(volatile A *, C);
_Bool atomic_is_lock_free(const volatile A *);
C atomic_load(const volatile A *);
C atomic_load_explicit(const volatile A *, memory_order);
void atomic_store(volatile A *, C);
void atomic_store_explicit(volatile A *, C, memory_order);
void atomic_flag_clear(volatile atomic_flag *);
void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
_Bool atomic_flag_test_and_set(volatile atomic_flag *);
_Bool atomic_flag_test_and_set_explicit(
volatile atomic_flag *, memory_order);
void atomic_signal_fence(memory_order);
void atomic_thread_fence(memory_order);

This header provides the C11 atomic operations. Sortix gets this header via GCC.

<stdnoreturn.h> (C11)

Status: C11 feature implemented LONG AGO in Sortix.

#include <sdtdnoreturn.h>
#define noreturn _Noreturn

This header adds the new noreturn keyword in C11 that marks a function as never returning, allowing compiler optimizations. Sortix gets this header via GCC.

strlcat(), strlcpy(), wcslcat(), wcslcpy()

Status: Austin Group Bug #986 implemented 2013-07-11 in Sortix.

#include <string.h>
size_t strlcat(char *restrict dst, const char *restrict src, size_t dstsize);
size_t strlcpy(char *restrict dst, const char *restrict src, size_t dstsize);
#include <wchar.h>
size_t wcslcat(wchar_t *restrict dst, const wchar_t *restrict src, size_t dstsize);
size_t wcslcpy(wchar_t *restrict dst, const wchar_t *restrict src, size_t dstsize);

These are alternatives to strcpy and strcat that truncates the string if it does not fit in the destination buffer, returning the originally intended string length which lets one catch the overflow. These are useful for formatting strings into fixed sized buffers, as opposed to strncpy that might not null terminate the string. Unbounded allocations should prefer strdup, asprintf, or open_memstream to ensure the allocation is done as part of the string creation to avoid buffer overflows.

tcgetwinsize(), tcsetwinsize()

Status: Austin Group Bug #1151 implemented in the Sortix volatile build and is not merged to main yet.

#include <termios.h>
struct winsize {
  unsigned short ws_row;
  unsigned short ws_col;
};
int tcgetwinsize(int fildes, struct winsize *winsize_p);
int tcsetwinsize(int fildes, const struct winsize *winsize_p);

These allow one to get and set the window size of a terminal, which is especially useful for pseudo-terminals. tcgetwinsize is implemented in Sortix but tcsetwinsize has not been merged to main yet. It will be merged as soon as an overnight volatile test build has completed without issue.

The Sortix struct winsize uses size_t instead of unsigned short and also has the size_t ws_xpixel and size_t ws_ypixel fields. The structure should probably be aligned with POSIX's data types in a future incompatible ABI change.

<threads.h> (C11)

Status: C11 feature not yet implemented in Sortix.

#include <threads.h>
#define thread_local _Thread_local
#define ONCE_FLAG_INIT [..]
#define TSS_DTOR_ITERATIONS [...]
typedef [...] cnd_t;
typedef [...] mtx_t;
typedef [...] once_flag;
typedef [...] thrd_t;
typedef [...] tss_t;
typedef int (*thrd_start_t)(void*);
enum { mtx_plain, mtx_recursive, mtx_timed, thrd_busy, thrd_error, thrd_nomem, thrd_success, thrd_timedout };
void call_once(once_flag *, void (*)(void));
int cnd_broadcast(cnd_t *);
void cnd_destroy(cnd_t *);
int cnd_init(cnd_t *);
int cnd_signal(cnd_t *);
int cnd_timedwait(cnd_t * restrict, mtx_t * restrict,
int const struct timespec * restrict);
int cnd_wait(cnd_t *, mtx_t *);
void mtx_destroy(mtx_t *);
int mtx_init(mtx_t *, int);
int mtx_lock(mtx_t *);
int mtx_timedlock(mtx_t * restrict, const struct timespec * restrict);
int mtx_trylock(mtx_t *);
int mtx_unlock(mtx_t *);
int thrd_create(thrd_t *, thrd_start_t, void *);
thrd_t thrd_current(void);
int thrd_detach(thrd_t);
int thrd_equal(thrd_t, thrd_t);
_Noreturn void thrd_exit(int);
int thrd_join(thrd_t, int *);
int thrd_sleep(const struct timespec *, struct timespec *);
void thrd_yield(void);
int tss_create(tss_t *, tss_dtor_t);
void tss_delete(tss_t);
void *tss_get(tss_t);
int tss_set(tss_t, void *);

This header adds the new C11 threads API. Sortix does not yet implement this API as nothing needs it yet but Sortix has the pthread API.

<uchar.h> (C11)

Status: C11 feature not yet implemented in Sortix.

#include <uchar.h>
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
size_t c16rtomb(char *restrict, char16_t, mbstate_t *restrict);
size_t c32rtomb(char *restrict, char32_t, mbstate_t *restrict);
size_t mbrtoc16(char16_t *restrict, const char *restrict, size_t, mbstate_t *restrict);
size_t mbrtoc32(char32_t *restrict, const char *restrict, size_t, mbstate_t *restrict);

These functions convert multibyte strings to and from 16-bit and 32-bit unicode values. These functions don't seem particular useful as there are no APIs using the char16_t and char32_t types. These are not yet implemented in Sortix as nothing needs them.

New Features

A lot of new features have been added to the existing functions.

I'm yet to write sections for each of these features as I implement them in Sortix, but you can see their status in the above table. Please check back later as I'll update this page with the latest information as I continue to study POSIX.1-2024.

A few quick highlights:

bind() port 0

The bind() system call is now defined to allocate a random available port when the port number is set to 0.

FNMCASEFOLD, FNMIGNORECASE

The new fnmatch() flags FNM_CASEFOLD aka FNM_IGNORECASE compares the string case insensitively with the pattern.

F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW

POSIX has finally added per-file-descriptor advisory locks! POSIX has only ever had process-scope advisory locks with broken semantics on close(), which I refused to implement in Sortix.

MAP_ANONYMOUS

The MAP_ANONYMOUS aka MAP_ANON flag is now standardized and lets one allocate memory directly with mmap without a backing file.

O_CLOFORK

The O_CLOFORK open flag sets the FD_CLOFORK file descriptor flag which closes the file descriptor on fork() in the new process.

Sortix has had this feature fully implemented since 2013 and nothing had to change to implement the POSIX 2024 specification of this feature. Curiously it appears that Linux is refusing to implement this feature and I never actually used it in Sortix.

SEEK_DATA, SEEK_HOLE

These constants let lseek seek across unitialized sections of the file, which exposes the ability for implementations to omit storing default-zero-initialized sections of files.

time_t 64-bit

The 2038 32-bit time_t apocalypse has been canceled to contain SCP-8601.

New Utilities

A bunch of new utilities have been added along with a bunch of new options to existing utilities.

I'm yet to write sections for each of these features as I implement them in Sortix, but you can see their status in the above table. Please check back later as I'll update this page with the latest information as I continue to study POSIX.1-2024.

Removals

A lot of functions, features, and features have been declared obsolete and removed from the standard. This is a healthy part of the standard lifecycle where we gain a leaner standard and simpler future implementations. Sortix has benefited massively from not needing to implement legacy interfaces, which is why most of the removed interfaces were never implemented in Sortix in the first place.

Notably the removal of gettimeofday() essentially completes the many year long migration from the microsecond-precision struct timeval to the new nanosecond-precision struct timespec. Meanwhile the removal of many old signal functions completes the migration to the new real time signal function family and sigset_t.

A number of interfaces remain implemented in Sortix for various reasons:

  • asctime_r, ctime_r: The functions are considered deprecated and problematic in Sortix as they are poorly designed and the output format isn't very useful and they suffer from year 10000 problems. However, ports continue to rely too much on them rather than the C89 strftime and they cannot be removed at this time.
  • gettimeofday: Sortix uses exclusively nanosecond-precision struct timespec in the system call API and clock_gettime() is the modern replacement, but gettimeofday remains extremely popular in the ports collection and removing it is impossible and counterproductive.
  • ioctl: It's positive news that POSIX is getting out of the ioctl business as they never defined any ways to actually use the API. Sortix retains the API as Sortix heavily relies on it to provide access to driver facilities and other purposes as extensions. POSIX instead invented posix_devctl without defining any ways to actually use it, instead of realizing they probably should just let implementations innovate and standardize the resulting consensus.
  • rand_r: This interface is part of the conspiracy against good randomness and you should use arc4random instead (which POSIX failed to standardize but at at least we didn't get a posix_random mess). Unfortunately this function cannot be removed as the ports tree relies too much on it, but Sortix libc will issue a warning whenever it is used.
  • test -a -o ( ): Honestly I was shocked to learn these features were removed from the test program in the shell (aka [ ]) as my scripts heavily rely on them. Sortix will continue to provide them as they are useful and are very much needed for compatibility with the ports collection.
  • utime: This second-precision interface has been replaced by the nanosecond precision utimensat interface, however it remains heavily used by the ports collection and cannot be removed at this time.
Copyright 2011-2025 Jonas 'Sortie' Termansen and contributors.
Sortix's source code is free software under the ISC license.
#sortix on irc.sortix.org
@sortix_org