pub fun errno() i32;
调用线程的当前 errno,作为正数
仅在返回值已经报告失败的调用后才有意义 - 成功调用不会清除 errno。
ret: 当前 errno
pub fun fail_errno() i64;
当前 errno 取反,用于 darwin OS 原语的返回
darwin 后端的外部约定是"失败时为负的 errno",这是它从陷阱结果寄存器直接读取数字时返回的内容。这是从 libSystem 约定重构此约定的唯一位置。
不应该存在没有设置 errno 的失败 libSystem 入口点,但这里的零对每个调用者来说都不可区分成功,因此它被报告为 EINVAL 而不是静默吞没。
ret: 取反的 errno,总是 < 0
pub ext fun read(fd: i32, buf: *u8, count: usize) i64
pub ext fun write(fd: i32, buf: *u8, count: usize) i64
pub ext fun openat(dirfd: i32, path: *u8, flags: i32, ...) i32
openat 是 C 可变参数:mode 参数仅在 flags 携带 O_CREAT 时被读取。在固定参数为三个的情况下声明它会在 apple arm64 上静默错误,后者将整个可变参数尾部在栈上传递,而固定的第三个参数会被降低到 x2(参见 mach 的 doc/language/ext-fun.md)。
pub ext fun close(fd: i32) i32
pub ext fun fsync(fd: i32) i32
pub ext fun lseek(fd: i32, offset: i64, whence: i32) i64
pub ext fun fstat(fd: i32, st: *u8) i32
pub ext fun fstatat(dirfd: i32, path: *u8, st: *u8, flags: i32) i32
pub ext fun fstat(fd: i32, st: *u8) i32
pub ext fun fstatat(dirfd: i32, path: *u8, st: *u8, flags: i32) i32
pub ext fun unlinkat(dirfd: i32, path: *u8, flags: i32) i32
pub ext fun renameat(olddir: i32, oldpath: *u8, newdir: i32, newpath: *u8) i32
pub ext fun symlink(target: *u8, linkpath: *u8) i32
pub ext fun mkdirat(dirfd: i32, path: *u8, mode: u32) i32
pub ext fun faccessat(dirfd: i32, path: *u8, mode: i32, flags: i32) i32
pub ext fun getcwd(buf: *u8, size: usize) *u8
getcwd(3) 替换了原始系统调用后端需要的 open(".") + fcntl(F_GETPATH) 舞蹈。它接受容量,因此被调用者会尊重调用者的缓冲区大小,而不是事后防御它。
ret: 成功时为 buf,或带有设置 errno 的 nil(size 太小时为 ERANGE)
pub ext fun pipe(fds: *i32) i32
pub ext fun signal(sig: i32, handler: usize) usize
安装进程范围的信号处理程序
signal(3) 对于 SIG_IGN 足够,并保持 darwin 在其支持的 libSystem 表面上,而不是重现平台的 sigaction 布局。
ret: 之前处理程序,或失败时带有设置 errno 的全一位
pub ext fun clock_gettime(clock_id: i32, ts: *u8) i32
时间
darwin 根本没有 clock_gettime BSD 陷阱。后端曾经调用系统调用 427 并将结果作为时间读取;无论当前 macOS 上的那个数字是什么,它都不是一个 - now() 返回 unix epoch 以下,三个 std.chrono.time 测试在很长一段时间内没有运行它们时一直在 darwin 上失败。
clock_gettime(3) 是真实的、公开的,自 macOS 10.12 起已发布;它是在用户空间中通过 mach_absolute_time() 和 commpage 实现的,而不是作为陷阱,这就是为什么寻找它的系统调用编号永远行不通的原因。10.12 比这些目标支持的硬件上运行的任何 macOS 都要旧,所以绑定它不会降低下限——与 os_sync_wait_on_address 不同,这就是线程层选择不同路径的原因。
这里的 timespec 与 shared.mach 声明的布局相同;仅作为 *u8 接受,以保持此模块没有反向依赖那个模块。
pub ext fun nanosleep(req: *u8, rem: *u8) i32
挂起调用线程指定的间隔
旧后端说"darwin 没有 nanosleep 系统调用"并使用了带有超时的 select。这对于 TRAP 表来说是正确的,对于 libSystem 来说是错误的,后者导出 nanosleep(3)。采用它还可以获取剩余时间参数,因此中断的睡眠可以恢复剩余部分,而不是提前返回或重新启动完整间隔。
req: 请求的间隔 rem: 被中断时填充未睡眠的剩余部分;可以是 nil ret: 0,或带有设置 errno 的 -1(信号切断睡眠时为 EINTR)
pub val PTHREAD_MUTEX_BYTES: usize = 64
不透明的 pthread 对象大小,来自 LP64 上的 <sys/_pthread/_pthread_types.h>。 每个对象是一个 long sig 后跟一个不透明字节数组: _PTHREAD_MUTEX_SIZE 56, _PTHREAD_COND_SIZE 40, _PTHREAD_ATTR_SIZE 56, _PTHREAD_ONCE_SIZE 8 这些是公共 ABI - 更改其中任何一个都会破坏系统上的每个编译 C 程序 - 因此它们被拼写为常量而不是探测。它们通过 shared.mach 中的测试断言运行时的自身行为。
pub val PTHREAD_COND_BYTES: usize = 48
pub val PTHREAD_ATTR_BYTES: usize = 64
pub val PTHREAD_ONCE_BYTES: usize = 16
pub val PTHREAD_CREATE_JOINABLE: i32 = 1
pthread_attr_setdetachstate 状态(<pthread.h>)
pub val PTHREAD_CREATE_DETACHED: i32 = 2
pub ext fun pthread_create(thread: *usize, attr: *u8, start: usize, arg: ptr) i32
start 是作为裸地址传递的 void *(*)(void *),与 windows 后端如何将 trampoline 传递给 CreateThread 匹配。
pub ext fun pthread_attr_init(attr: *u8) i32
pub ext fun pthread_attr_destroy(attr: *u8) i32
pub ext fun pthread_attr_setstacksize(attr: *u8, size: usize) i32
pub ext fun pthread_attr_setdetachstate(attr: *u8, state: i32) i32
pub ext fun pthread_mutex_init(m: *u8, attr: *u8) i32
pub ext fun pthread_mutex_lock(m: *u8) i32
pub ext fun pthread_mutex_unlock(m: *u8) i32
pub ext fun pthread_cond_init(c: *u8, attr: *u8) i32
pub ext fun pthread_cond_wait(c: *u8, m: *u8) i32
pub ext fun pthread_cond_broadcast(c: *u8) i32
pub ext fun pthread_once(once: *u8, init: usize) i32
init 是作为裸地址传递的 void (*)(void)。
pub ext fun umask(mask: u32) u32
设置文件模式创建掩码,返回之前的掩码
无法失败,不接触 errno。导入它以便测试可以将掩码固定为已知值,然后精确断言创建文件的模式,而不是断言一些依赖 umask 的子集——这就是模式断言能够捕获丢失的可变参数的原因。
pub ext fun fcntl(fd: i32, cmd: i32, ...) i32
fcntl 是 C 可变参数。双参数命令(F_GETFL, F_GETFD)根本不传递尾部,并且不带任何内容调用;F_SETFD / F_SETFL / F_DUPFD 传递单个 int。此模块传递的每个尾部都是 int 或指针,从不 float,这就是为什么在 SysV x86_64 腿上 AL 保持为零。