macOS v0.1.0

Source
macOS platform bindings

Installation

Add macOS to the [Dependencies] table of your package's Rux.toml:

[Dependencies]
macOS = { Namespace = "Rux", Version = "0.1.0" }

Standard packages are declared by hand: the registry does not serve them, so rux add Rux/macOS cannot add them.

Dependencies

Guide

macOS platform bindings: the Darwin ABI as libSystem publishes it, which on this system is the only interface Apple supports.

What it provides

ModuleCovers
Typesthe Darwin ABI's own types: ProcessId, FileDescriptor, FileMode, UserId, Timespec, Timeval
Errorsthe errno numbers, CurrentErrno, and the Normalize / IsError / Errno fold
LibSystemevery libSystem entry point this package binds, under the symbol it exports, including _NSGetArgc, _NSGetArgv and _NSGetEnviron
FileRead, Write, Close, OpenAt, Lseek, Fsync, Ftruncate, UnlinkAt, MkdirAt, RenameAt, Dup2, Pipe, the open flags, and the three standard descriptors
MemoryMmap, Munmap, Mprotect, Madvise, QueryPageSize, and the protection, mapping and advice flags
ClockClockGetTime, ClockGetResolution, GetTimeOfDay, Nanosleep, and the clock identifiers
EntropyGetRandom, which cannot fail and has no short count
ProcessExit and GetPid
Dynamicthe RTLD_* flags; dlopen, dlsym, dlclose and dlerror are in LibSystem
Threadpthread_create, pthread_join, pthread_detach, the pthread_attr_* stack-size calls, sched_yield, sysconf and SC_NPROCESSORS_ONLN, and pthread_threadid_np, linked from libSystem
Ulock__ulock_wait, __ulock_wake and their flags, the word operations every lock in Rux/Sync sleeps on
Spawnposix_spawnp, the posix_spawn_file_actions_* calls, waitpid, kill and fcntl
Socketthe BSD socket calls behind the same wrappers as Linux and FreeBSD, SO_NOSIGPIPE, and getaddrinfo, freeaddrinfo and AddressInfo
PollKqueue and KeventCall over libSystem's kqueue and kevent, Kevent, the EVFILT_* and EV_* flags, and FcntlInt with F_GETFL, F_SETFL and O_NONBLOCK

The module names describe where each declaration comes from; they are not part of an import path.

Apple does not support calling the kernel directly. The trap numbers are private, they have changed between releases, and on Apple Silicon the trap interface is not reachable from ordinary code at all. libSystem is the ABI, and this package binds it — which is what makes it different in kind from Rux/Linux and Rux/FreeBSD, whose kernels publish a stable numbering.

libSystem reports failure the way C does, with -1 and a positive errno reached through an accessor. Normalize folds those two into the one negative-error convention the other platform packages use, so IsError and Errno read the same on all three.

Nothing here is interchangeable with the other platform packages. AT_FDCWD is -2 on Darwin and -100 elsewhere; monotonic is clock 6 here, 1 on Linux, 4 on FreeBSD; RTLD_LOCAL is 4 and RTLD_GLOBAL is 8, where both other systems use 0 and 256. A value carried across compiles and means something else.

There is no Brk: Darwin's brk and sbrk have been unavailable to 64-bit code from the start. There is no Pipe2: Darwin has only pipe, so close-on-exec must be set afterwards. And Fsync is weaker here than elsewhere — it does not wait for the device to commit, which F_FULLFSYNC through fcntl is what does.

What is tested

Tests/Packages/macOS/Descriptors covers descriptor numbering, short reads and writes, end of file, size boundaries and the native error for each way of misusing a descriptor or a name. Tests/Packages/macOS/Mapping covers anonymous mappings, protection changes, advice, the requests the kernel refuses, and both edges of the reserved error-result window. Tests/Packages/macOS/Syscall covers the wrapper surface and the shared POSIX contract.

All of it compiles for both architectures, and none of it has ever run on a host that is not macOS. Until it does, the syscall numbers, flag values and errno constants here rest on published documentation rather than on a passing test.

The shared POSIX contract

Nothing here is interchangeable with Rux/Linux or Rux/FreeBSD, but the three are spelled the same, which is a different claim and a deliberate one. An equivalent call has the same wrapper name, the same parameter names and the same parameter shapes on all three systems, so a consumer such as Rux/FileSystem or Rux/Time writes one call site instead of a when #target.os ladder around three names for one idea. Tests/Unit/PlatformBindingContractTests.cpp compares the three packages' parsed sources and fails when they drift apart.

The values are the opposite: every constant is this system's own, and the same file asserts that the ones a reader might carry across really do differ.

Values and pointers

Darwin records such as Timespec and Timeval are structural values and copy by value, and every call that reads or fills one takes its address: GetTimeOfDay(@time), ClockGetTime(ClockMonotonic, @time). That is the convention on all three POSIX packages. It is not the prettiest form available here — libSystem's C declarations would accept a reference, and this package used them until the divergence showed up as target branches in Rux/Time — but one shape across three systems is worth more than a borrow on one of them.

libSystem declarations retain raw pointers for nullable parameters, byte buffers, loader handles, and OS-owned storage. These pointers do not express ownership; use the documented close or unmap operation, or prefer Rux/Io and Rux/Memory for managed interfaces.

Platform

macOS only. Guard use behind a compile-time check, so a build for another target never resolves these declarations:

import Core::{ #target };

when #target.os == .macOS {
    import macOS::{ StdOut, Write };
}

Index

Types

NameSummary
KeventOne struct kevent as 64-bit macOS lays it out: a change to register or an event to report.
AddressInfoThe C library's addrinfo: one result of getaddrinfo, linked to the next.
SpawnFileActionsRoom for a posix_spawn_file_actions_t, which each C library sizes its own way and none larger than this.
PThreadA thread as the C library names it, pthread_t.
PThreadAttributesRoom for a pthread_attr_t, which each C library sizes its own way and none larger than this.
ProcessIdA process identifier, as getpid reports one.
FileDescriptorA file descriptor, as the kernel numbers one.
FileOffsetA byte offset within a file, 64 bits on every supported Apple target.
FileModeA file's type and permission bits.
UserIdA user identifier.
GroupIdA group identifier.
TimespecA duration or an instant, as seconds and nanoseconds.
TimevalA duration or an instant, as seconds and microseconds.

Functions

NameSummary
ClockGetTimeReads clockId into time.
ClockGetResolutionReads the resolution of clockId into resolution.
GetTimeOfDayReads the wall clock into time, to microsecond resolution.
NanosleepSuspends the caller for the requested duration.
GetRandomFills length bytes of buffer with unpredictable bytes.
CurrentErrnoThe calling thread's current errno value.
NormalizeFolds a libSystem result and the thread's errno into one value.
IsErrorWhether a normalized result is one of the reserved error values.
ErrnoThe error number a normalized result carries, or zero when it carries none.
ReadReads up to count bytes from fd into buffer.
WriteWrites up to count bytes from buffer to fd.
CloseCloses fd and releases what the kernel held for it.
OpenAtOpens path relative to directoryFd and returns a descriptor, or a negative error number.
LseekMoves the file offset of fd and returns where it ended up, or a negative error number.
GetcwdWrites the current working directory's absolute path into buffer, NUL-terminated.
ChdirMakes path the process's working directory.
ReadlinkAtReads the text a symbolic link holds into buffer.
FstatFills statBuffer with what the kernel knows about the file behind fd.
FstatAtFills statBuffer with what the kernel knows about the file path names.
FchmodAtSets the permission bits of the file path names.
UtimensAtSets the access and modification times of the file path names.
LinkAtCreates a hard link: newPath becomes a second name for the file oldPath names.
SymlinkAtCreates a symbolic link at linkPath holding target as its text.
Getdirentries64Reads directory entries from fd into buffer, and returns the bytes filled, zero at the end, or a negative error number.
FsyncFlushes everything written to fd toward the storage device.
FtruncateSets the length of the file behind fd to length.
UnlinkAtRemoves the name path from its directory.
MkdirAtCreates a directory named path with permission bits mode.
RenameAtRenames oldPath to newPath, each resolved against its own directory descriptor.
Dup2Makes newFd a copy of oldFd, closing whatever newFd was.
PipeCreates a pipe and writes its two descriptors into descriptors.
getpagesizeReports the system page size, in bytes.
_NSGetArgcThe address of the process's argument count.
_NSGetArgvThe address of the process's argument vector.
_NSGetExecutablePathCopies the path of the process's executable into buffer, NUL-terminated.
_NSGetEnvironThe address of the process's environment vector.
dlopenLoads a shared object and returns a handle to it, or null on failure.
dlsymFinds a symbol in a loaded object and returns its address, or null.
dlcloseDrops one reference to a loaded object, unloading it when the last one goes.
dlerrorReports the most recent loader error and clears it, or returns null when there is none.
MmapCreates a mapping and returns its address, or a negative error number.
MunmapReleases the mapping that begins at address and spans length bytes.
MprotectChanges what may be done with the pages covering a range.
MadviseTells the kernel how the pages covering a range are about to be used.
QueryPageSizeThe size of a page, asked of libSystem.
FcntlIntPerforms command on a descriptor with an integer argument.
KqueueOpens a kqueue.
KeventCallApplies changeCount changes, then waits until an event is ready or timeout passes, filling events.
ExitEnds the calling process with code.
GetPidThe calling process's own identifier.
SocketOpens a socket.
ConnectConnects a socket to address, waiting for a stream connection to be made.
BindGives a socket its local address.
ListenMakes a bound stream socket accept connections.
Accept4Accepts a waiting connection as a new socket.
SendToSends bytes on a socket, to address when it is not connected.
ReceiveFromReceives bytes from a socket, and where they came from.
ShutdownEnds one or both directions of a connection.
SetSocketOptionSets a socket option.
GetSocketNameReads a socket's local address.
GetPeerNameReads the address of a connected socket's peer.
getaddrinfoLooks up the addresses of a host and service.
freeaddrinfoFrees the results of getaddrinfo.
posix_spawnpStarts file, found through PATH when it has no slash, as a child process.
posix_spawn_file_actions_initInitializes an empty list of file actions.
posix_spawn_file_actions_destroyReleases what posix_spawn_file_actions_init and the actions added since set up.
posix_spawn_file_actions_adddup2Adds an action duplicating fd onto newFd in the child.
posix_spawn_file_actions_addopenAdds an action opening path as fd in the child.
posix_spawn_file_actions_addchdir_npAdds an action changing the child's working directory to path.
waitpidWaits for a child to change state, and reports how it finished.
killSends a signal to a process.
fcntlPerforms a control operation on a descriptor, such as setting its flags with F_SETFD.
pthread_createStarts a thread running start(argument).
pthread_joinWaits for a thread to finish and releases it.
pthread_detachLets a thread release itself when it finishes, so nothing has to join it.
pthread_attr_initInitializes thread attributes to the defaults.
pthread_attr_setstacksizeSets the stack size a thread started with these attributes gets.
pthread_attr_destroyReleases what pthread_attr_init set up.
pthread_threadid_npReads the system-wide identifier of a thread, or of the calling thread when thread is zero.
sched_yieldGives up the processor so another ready thread can run.
sysconfReads a system configuration value.
__ulock_waitSleeps while *address equals value, until a wake, a signal or the timeout.
__ulock_wakeWakes a thread, or all of them with ULF_WAKE_ALL, sleeping on address.

Constants

NameSummary
ClockRealtimeCLOCK_REALTIME: wall-clock time, which can jump when the system clock is set.
ClockMonotonicCLOCK_MONOTONIC: time since boot, which never goes backwards.
ClockMonotonicRawCLOCK_MONOTONIC_RAW: like ClockMonotonic, but not adjusted by time synchronization.
RTLD_LAZYRTLD_LAZY: resolve a function symbol the first time it is called rather than at load.
RTLD_NOWRTLD_NOW: resolve every symbol before dlopen returns.
RTLD_LOCALRTLD_LOCAL: keep this object's symbols to itself, which is Darwin's default.
RTLD_GLOBALRTLD_GLOBAL: make this object's symbols available to objects loaded afterwards.
EPERMEPERM: the operation is not permitted to this caller.
ENOENTENOENT: no such file or directory.
ESRCHESRCH: no process has that identifier.
EINTREINTR: the call was interrupted by a signal before it did anything.
EIOEIO: a low-level input or output error.
ENXIOENXIO: no such device or address.
EBADFEBADF: the file descriptor is not open, or is not open for what was asked.
ENOMEMENOMEM: not enough memory to satisfy the request.
EACCESEACCES: permission denied.
EFAULTEFAULT: an address the call was given is outside the caller's address space.
EBUSYEBUSY: the resource is in use by something else.
EEXISTEEXIST: the file already exists.
EXDEVEXDEV: the two paths are on different file systems.
ENOTDIRENOTDIR: a path component that had to be a directory is not one.
EISDIREISDIR: the target is a directory and the operation is not one a directory accepts.
EINVALEINVAL: an argument is not valid.
EMFILEEMFILE: this process has too many descriptors open.
ENOSPCENOSPC: the device has no room left.
ESPIPEESPIPE: the descriptor is a pipe or socket and cannot be seeked.
EROFSEROFS: the file system is mounted read-only.
EPIPEEPIPE: the reading end of the pipe is closed.
EAGAINEAGAIN: the operation would block, and the descriptor was set not to.
ELOOPELOOP: too many symbolic links were followed resolving the path.
ENAMETOOLONGENAMETOOLONG: the path or a component of it is too long.
ENOSYSENOSYS: the system does not implement this call.
EOVERFLOWEOVERFLOW: a value is too large for the type the call reports it in.
ETIMEDOUTETIMEDOUT: the operation timed out.
MaximumErrnoThe largest error number the normalized error range holds.
StdInThe descriptor a process reads its input from, unless something reassigned it.
StdOutThe descriptor a process writes its output to.
StdErrThe descriptor a process writes its diagnostics to.
AtFdCwdAT_FDCWD: resolve a relative path against the current directory rather than a descriptor.
OpenReadOnlyO_RDONLY: open for reading only.
OpenWriteOnlyO_WRONLY: open for writing only.
OpenReadWriteO_RDWR: open for both reading and writing.
OpenCreateO_CREAT: create the file when it does not exist, which is when the mode argument is read.
OpenExclusiveO_EXCL: with OpenCreate, fail rather than open a file that already exists.
OpenTruncateO_TRUNC: truncate the file to nothing when opening it for writing.
OpenAppendO_APPEND: every write goes to the end.
OpenNonBlockingO_NONBLOCK: reads and writes report EAGAIN rather than waiting.
OpenCloseOnExecO_CLOEXEC: close this descriptor automatically when the process executes a new program.
OpenDirectoryO_DIRECTORY: fail unless the target is a directory.
SeekSetSEEK_SET: measure the new offset from the start of the file.
SeekCurrentSEEK_CUR: measure the new offset from the current one.
SeekEndSEEK_END: measure the new offset from the end of the file.
RemoveDirectoryAT_REMOVEDIR: make UnlinkAt remove a directory rather than a file.
SymlinkNoFollowAT_SYMLINK_NOFOLLOW: act on a symbolic link itself rather than on what it points at.
FollowSymlinksAT_SYMLINK_FOLLOW: make LinkAt link a symbolic link's target rather than the link.
SystemLibThe library every Darwin interface is reached through.
ProtectionNonePROT_NONE: the pages may not be touched at all.
ProtectionReadPROT_READ: the pages may be read.
ProtectionWritePROT_WRITE: the pages may be written.
ProtectionExecutePROT_EXEC: the pages may be executed.
MapSharedMAP_SHARED: writes are visible to other mappings of the same object and reach it.
MapPrivateMAP_PRIVATE: writes are private to this mapping and never reach the object.
MapFixedMAP_FIXED: place the mapping exactly at the requested address, replacing whatever was there.
MapAnonymousMAP_ANON: the mapping is backed by zeroed pages rather than by a file.
AdviseFreeMADV_FREE: the pages may be reclaimed, and read back as zero if they are.
AdviseDontNeedMADV_DONTNEED: the pages are not needed soon.
AdviseWillNeedMADV_WILLNEED: the pages will be read soon.
F_GETFLF_GETFL: the fcntl command that reads a descriptor's status flags.
F_SETFLF_SETFL: the fcntl command that sets a descriptor's status flags.
O_NONBLOCKO_NONBLOCK: the status flag that makes a call fail with EAGAIN rather than wait.
EVFILT_READEVFILT_READ: the filter that reports a descriptor with something to read, or a connection to accept.
EVFILT_WRITEEVFILT_WRITE: the filter that reports a descriptor a write would not wait on.
EV_ADDEV_ADD: add the change's filter, or update it.
EV_DELETEEV_DELETE: remove the change's filter.
EV_RECEIPTEV_RECEIPT: report each change as an event, with its outcome in data, rather than waiting.
EV_ERROREV_ERROR: set on an event that reports a failed change, with the error number in data.
EV_EOFEV_EOF: the peer has closed its side.
AF_INETAF_INET: the IPv4 address family.
AF_INET6AF_INET6: the IPv6 address family.
SOCK_STREAMSOCK_STREAM: a connected byte stream.
SOCK_DGRAMSOCK_DGRAM: individual datagrams.
SOL_SOCKETSOL_SOCKET: the level of the options every socket has.
SO_REUSEADDRSO_REUSEADDR: let a listening address be bound again while old connections to it wind down.
SO_RCVTIMEOSO_RCVTIMEO: how long a receive waits.
SO_SNDTIMEOSO_SNDTIMEO: how long a send waits.
IPPROTO_TCPIPPROTO_TCP: the level of TCP's options.
TCP_NODELAYTCP_NODELAY: send small writes at once rather than gathering them.
IPPROTO_IPV6IPPROTO_IPV6: the level of IPv6's options.
IPV6_V6ONLYIPV6_V6ONLY: accept only IPv6 on an IPv6 socket.
SO_NOSIGPIPESO_NOSIGPIPE: report a closed peer as an error rather than with SIGPIPE.
F_SETFDF_SETFD: the fcntl command that sets a descriptor's flags.
FD_CLOEXECFD_CLOEXEC: close the descriptor when the process starts another program.
WNOHANGWNOHANG: have waitpid return at once when the child has not finished.
SIGKILLSIGKILL: the signal that ends a process at once and cannot be caught.
SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN: the sysconf name for the number of processors currently online.
UL_COMPARE_AND_WAITUL_COMPARE_AND_WAIT: wait on a 32-bit word that holds the expected value.
ULF_WAKE_ALLULF_WAKE_ALL: wake every thread waiting on the word rather than one.
ULF_NO_ERRNOULF_NO_ERRNO: report failure as a negative error number rather than through errno.