zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 899bb2a0 (42803B) - Raw


      1 // This file provides the system interface functions for Linux matching those
      2 // that are provided by libc, whether or not libc is linked. The following
      3 // abstractions are made:
      4 // * Work around kernel bugs and limitations. For example, see sendmmsg.
      5 // * Implement all the syscalls in the same way that libc functions will
      6 //   provide `rename` when only the `renameat` syscall exists.
      7 // * Does not support POSIX thread cancellation.
      8 const std = @import("../std.zig");
      9 const builtin = @import("builtin");
     10 const assert = std.debug.assert;
     11 const maxInt = std.math.maxInt;
     12 const elf = std.elf;
     13 const vdso = @import("linux/vdso.zig");
     14 const dl = @import("../dynamic_library.zig");
     15 
     16 pub usingnamespace switch (builtin.arch) {
     17     .i386 => @import("linux/i386.zig"),
     18     .x86_64 => @import("linux/x86_64.zig"),
     19     .aarch64 => @import("linux/arm64.zig"),
     20     .arm => @import("linux/arm-eabi.zig"),
     21     .riscv64 => @import("linux/riscv64.zig"),
     22     .mipsel => @import("linux/mipsel.zig"),
     23     else => struct {},
     24 };
     25 pub usingnamespace @import("bits.zig");
     26 pub const tls = @import("linux/tls.zig");
     27 
     28 /// Set by startup code, used by `getauxval`.
     29 pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
     30 
     31 /// See `std.elf` for the constants.
     32 pub fn getauxval(index: usize) usize {
     33     const auxv = elf_aux_maybe orelse return 0;
     34     var i: usize = 0;
     35     while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
     36         if (auxv[i].a_type == index)
     37             return auxv[i].a_un.a_val;
     38     }
     39     return 0;
     40 }
     41 
     42 /// Get the errno from a syscall return value, or 0 for no error.
     43 pub fn getErrno(r: usize) u12 {
     44     const signed_r = @bitCast(isize, r);
     45     return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0;
     46 }
     47 
     48 pub fn dup2(old: i32, new: i32) usize {
     49     if (@hasDecl(@This(), "SYS_dup2")) {
     50         return syscall2(SYS_dup2, @bitCast(usize, @as(isize, old)), @bitCast(usize, @as(isize, new)));
     51     } else {
     52         if (old == new) {
     53             if (std.debug.runtime_safety) {
     54                 const rc = syscall2(SYS_fcntl, @bitCast(usize, @as(isize, old)), F_GETFD);
     55                 if (@bitCast(isize, rc) < 0) return rc;
     56             }
     57             return @intCast(usize, old);
     58         } else {
     59             return syscall3(SYS_dup3, @bitCast(usize, @as(isize, old)), @bitCast(usize, @as(isize, new)), 0);
     60         }
     61     }
     62 }
     63 
     64 pub fn dup3(old: i32, new: i32, flags: u32) usize {
     65     return syscall3(SYS_dup3, @bitCast(usize, @as(isize, old)), @bitCast(usize, @as(isize, new)), flags);
     66 }
     67 
     68 // TODO https://github.com/ziglang/zig/issues/265
     69 pub fn chdir(path: [*]const u8) usize {
     70     return syscall1(SYS_chdir, @ptrToInt(path));
     71 }
     72 
     73 // TODO https://github.com/ziglang/zig/issues/265
     74 pub fn chroot(path: [*]const u8) usize {
     75     return syscall1(SYS_chroot, @ptrToInt(path));
     76 }
     77 
     78 // TODO https://github.com/ziglang/zig/issues/265
     79 pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
     80     return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
     81 }
     82 
     83 pub fn fork() usize {
     84     if (@hasDecl(@This(), "SYS_fork")) {
     85         return syscall0(SYS_fork);
     86     } else {
     87         return syscall2(SYS_clone, SIGCHLD, 0);
     88     }
     89 }
     90 
     91 /// This must be inline, and inline call the syscall function, because if the
     92 /// child does a return it will clobber the parent's stack.
     93 /// It is advised to avoid this function and use clone instead, because
     94 /// the compiler is not aware of how vfork affects control flow and you may
     95 /// see different results in optimized builds.
     96 pub inline fn vfork() usize {
     97     return @call(.{ .modifier = .always_inline }, syscall0, .{SYS_vfork});
     98 }
     99 
    100 pub fn futimens(fd: i32, times: *const [2]timespec) usize {
    101     return utimensat(fd, null, times, 0);
    102 }
    103 
    104 // TODO https://github.com/ziglang/zig/issues/265
    105 pub fn utimensat(dirfd: i32, path: ?[*]const u8, times: *const [2]timespec, flags: u32) usize {
    106     return syscall4(SYS_utimensat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(times), flags);
    107 }
    108 
    109 pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
    110     return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
    111 }
    112 
    113 pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize {
    114     return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val));
    115 }
    116 
    117 pub fn getcwd(buf: [*]u8, size: usize) usize {
    118     return syscall2(SYS_getcwd, @ptrToInt(buf), size);
    119 }
    120 
    121 pub fn getdents(fd: i32, dirp: [*]u8, len: usize) usize {
    122     return syscall3(
    123         SYS_getdents,
    124         @bitCast(usize, @as(isize, fd)),
    125         @ptrToInt(dirp),
    126         std.math.min(len, maxInt(c_int)),
    127     );
    128 }
    129 
    130 pub fn getdents64(fd: i32, dirp: [*]u8, len: usize) usize {
    131     return syscall3(
    132         SYS_getdents64,
    133         @bitCast(usize, @as(isize, fd)),
    134         @ptrToInt(dirp),
    135         std.math.min(len, maxInt(c_int)),
    136     );
    137 }
    138 
    139 pub fn inotify_init1(flags: u32) usize {
    140     return syscall1(SYS_inotify_init1, flags);
    141 }
    142 
    143 pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
    144     return syscall3(SYS_inotify_add_watch, @bitCast(usize, @as(isize, fd)), @ptrToInt(pathname), mask);
    145 }
    146 
    147 pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
    148     return syscall2(SYS_inotify_rm_watch, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, wd)));
    149 }
    150 
    151 // TODO https://github.com/ziglang/zig/issues/265
    152 pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
    153     if (@hasDecl(@This(), "SYS_readlink")) {
    154         return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
    155     } else {
    156         return syscall4(SYS_readlinkat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
    157     }
    158 }
    159 
    160 // TODO https://github.com/ziglang/zig/issues/265
    161 pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
    162     return syscall4(SYS_readlinkat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
    163 }
    164 
    165 // TODO https://github.com/ziglang/zig/issues/265
    166 pub fn mkdir(path: [*]const u8, mode: u32) usize {
    167     if (@hasDecl(@This(), "SYS_mkdir")) {
    168         return syscall2(SYS_mkdir, @ptrToInt(path), mode);
    169     } else {
    170         return syscall3(SYS_mkdirat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(path), mode);
    171     }
    172 }
    173 
    174 // TODO https://github.com/ziglang/zig/issues/265
    175 pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
    176     return syscall3(SYS_mkdirat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), mode);
    177 }
    178 
    179 // TODO https://github.com/ziglang/zig/issues/265
    180 pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize {
    181     return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
    182 }
    183 
    184 // TODO https://github.com/ziglang/zig/issues/265
    185 pub fn umount(special: [*]const u8) usize {
    186     return syscall2(SYS_umount2, @ptrToInt(special), 0);
    187 }
    188 
    189 // TODO https://github.com/ziglang/zig/issues/265
    190 pub fn umount2(special: [*]const u8, flags: u32) usize {
    191     return syscall2(SYS_umount2, @ptrToInt(special), flags);
    192 }
    193 
    194 pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: u64) usize {
    195     if (@hasDecl(@This(), "SYS_mmap2")) {
    196         // Make sure the offset is also specified in multiples of page size
    197         if ((offset & (MMAP2_UNIT - 1)) != 0)
    198             return @bitCast(usize, @as(isize, -EINVAL));
    199 
    200         return syscall6(
    201             SYS_mmap2,
    202             @ptrToInt(address),
    203             length,
    204             prot,
    205             flags,
    206             @bitCast(usize, @as(isize, fd)),
    207             @truncate(usize, offset / MMAP2_UNIT),
    208         );
    209     } else {
    210         return syscall6(
    211             SYS_mmap,
    212             @ptrToInt(address),
    213             length,
    214             prot,
    215             flags,
    216             @bitCast(usize, @as(isize, fd)),
    217             offset,
    218         );
    219     }
    220 }
    221 
    222 pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
    223     return syscall3(SYS_mprotect, @ptrToInt(address), length, protection);
    224 }
    225 
    226 pub fn munmap(address: [*]const u8, length: usize) usize {
    227     return syscall2(SYS_munmap, @ptrToInt(address), length);
    228 }
    229 
    230 pub fn poll(fds: [*]pollfd, n: nfds_t, timeout: i32) usize {
    231     if (@hasDecl(@This(), "SYS_poll")) {
    232         return syscall3(SYS_poll, @ptrToInt(fds), n, @bitCast(u32, timeout));
    233     } else {
    234         return syscall6(
    235             SYS_ppoll,
    236             @ptrToInt(fds),
    237             n,
    238             @ptrToInt(if (timeout >= 0)
    239                 &timespec{
    240                     .tv_sec = @divTrunc(timeout, 1000),
    241                     .tv_nsec = @rem(timeout, 1000) * 1000000,
    242                 }
    243             else
    244                 null),
    245             0,
    246             0,
    247             NSIG / 8,
    248         );
    249     }
    250 }
    251 
    252 pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
    253     return syscall3(SYS_read, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
    254 }
    255 
    256 pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
    257     return syscall5(
    258         SYS_preadv,
    259         @bitCast(usize, @as(isize, fd)),
    260         @ptrToInt(iov),
    261         count,
    262         @truncate(usize, offset),
    263         @truncate(usize, offset >> 32),
    264     );
    265 }
    266 
    267 pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize {
    268     return syscall6(
    269         SYS_preadv2,
    270         @bitCast(usize, @as(isize, fd)),
    271         @ptrToInt(iov),
    272         count,
    273         @truncate(usize, offset),
    274         @truncate(usize, offset >> 32),
    275         flags,
    276     );
    277 }
    278 
    279 pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
    280     return syscall3(SYS_readv, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count);
    281 }
    282 
    283 pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
    284     return syscall3(SYS_writev, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count);
    285 }
    286 
    287 pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
    288     return syscall5(
    289         SYS_pwritev,
    290         @bitCast(usize, @as(isize, fd)),
    291         @ptrToInt(iov),
    292         count,
    293         @truncate(usize, offset),
    294         @truncate(usize, offset >> 32),
    295     );
    296 }
    297 
    298 pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize {
    299     return syscall6(
    300         SYS_pwritev2,
    301         @bitCast(usize, @as(isize, fd)),
    302         @ptrToInt(iov),
    303         count,
    304         @truncate(usize, offset),
    305         @truncate(usize, offset >> 32),
    306         flags,
    307     );
    308 }
    309 
    310 // TODO https://github.com/ziglang/zig/issues/265
    311 pub fn rmdir(path: [*]const u8) usize {
    312     if (@hasDecl(@This(), "SYS_rmdir")) {
    313         return syscall1(SYS_rmdir, @ptrToInt(path));
    314     } else {
    315         return syscall3(SYS_unlinkat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(path), AT_REMOVEDIR);
    316     }
    317 }
    318 
    319 // TODO https://github.com/ziglang/zig/issues/265
    320 pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
    321     if (@hasDecl(@This(), "SYS_symlink")) {
    322         return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
    323     } else {
    324         return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(new));
    325     }
    326 }
    327 
    328 // TODO https://github.com/ziglang/zig/issues/265
    329 pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
    330     return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, @as(isize, newfd)), @ptrToInt(newpath));
    331 }
    332 
    333 // TODO https://github.com/ziglang/zig/issues/265
    334 pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
    335     return syscall4(SYS_pread, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
    336 }
    337 
    338 // TODO https://github.com/ziglang/zig/issues/265
    339 pub fn access(path: [*]const u8, mode: u32) usize {
    340     if (@hasDecl(@This(), "SYS_access")) {
    341         return syscall2(SYS_access, @ptrToInt(path), mode);
    342     } else {
    343         return syscall4(SYS_faccessat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(path), mode, 0);
    344     }
    345 }
    346 
    347 // TODO https://github.com/ziglang/zig/issues/265
    348 pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32, flags: u32) usize {
    349     return syscall4(SYS_faccessat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), mode, flags);
    350 }
    351 
    352 pub fn pipe(fd: *[2]i32) usize {
    353     if (builtin.arch == .mipsel) {
    354         return syscall_pipe(fd);
    355     } else if (@hasDecl(@This(), "SYS_pipe")) {
    356         return syscall1(SYS_pipe, @ptrToInt(fd));
    357     } else {
    358         return syscall2(SYS_pipe2, @ptrToInt(fd), 0);
    359     }
    360 }
    361 
    362 pub fn pipe2(fd: *[2]i32, flags: u32) usize {
    363     return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
    364 }
    365 
    366 pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
    367     return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
    368 }
    369 
    370 pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
    371     return syscall4(SYS_pwrite, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
    372 }
    373 
    374 // TODO https://github.com/ziglang/zig/issues/265
    375 pub fn rename(old: [*]const u8, new: [*]const u8) usize {
    376     if (@hasDecl(@This(), "SYS_rename")) {
    377         return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
    378     } else if (@hasDecl(@This(), "SYS_renameat")) {
    379         return syscall4(SYS_renameat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(old), @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(new));
    380     } else {
    381         return syscall5(SYS_renameat2, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(old), @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(new), 0);
    382     }
    383 }
    384 
    385 pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
    386     if (@hasDecl(@This(), "SYS_renameat")) {
    387         return syscall4(
    388             SYS_renameat,
    389             @bitCast(usize, @as(isize, oldfd)),
    390             @ptrToInt(old),
    391             @bitCast(usize, @as(isize, newfd)),
    392             @ptrToInt(new),
    393         );
    394     } else {
    395         return syscall5(
    396             SYS_renameat2,
    397             @bitCast(usize, @as(isize, oldfd)),
    398             @ptrToInt(old),
    399             @bitCast(usize, @as(isize, newfd)),
    400             @ptrToInt(new),
    401             0,
    402         );
    403     }
    404 }
    405 
    406 // TODO https://github.com/ziglang/zig/issues/265
    407 pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
    408     return syscall5(
    409         SYS_renameat2,
    410         @bitCast(usize, @as(isize, oldfd)),
    411         @ptrToInt(oldpath),
    412         @bitCast(usize, @as(isize, newfd)),
    413         @ptrToInt(newpath),
    414         flags,
    415     );
    416 }
    417 
    418 // TODO https://github.com/ziglang/zig/issues/265
    419 pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
    420     if (@hasDecl(@This(), "SYS_open")) {
    421         return syscall3(SYS_open, @ptrToInt(path), flags, perm);
    422     } else {
    423         return syscall4(
    424             SYS_openat,
    425             @bitCast(usize, @as(isize, AT_FDCWD)),
    426             @ptrToInt(path),
    427             flags,
    428             perm,
    429         );
    430     }
    431 }
    432 
    433 // TODO https://github.com/ziglang/zig/issues/265
    434 pub fn create(path: [*]const u8, perm: usize) usize {
    435     return syscall2(SYS_creat, @ptrToInt(path), perm);
    436 }
    437 
    438 // TODO https://github.com/ziglang/zig/issues/265
    439 pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
    440     // dirfd could be negative, for example AT_FDCWD is -100
    441     return syscall4(SYS_openat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), flags, mode);
    442 }
    443 
    444 /// See also `clone` (from the arch-specific include)
    445 pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
    446     return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
    447 }
    448 
    449 /// See also `clone` (from the arch-specific include)
    450 pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
    451     return syscall2(SYS_clone, flags, child_stack_ptr);
    452 }
    453 
    454 pub fn close(fd: i32) usize {
    455     return syscall1(SYS_close, @bitCast(usize, @as(isize, fd)));
    456 }
    457 
    458 /// Can only be called on 32 bit systems. For 64 bit see `lseek`.
    459 pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize {
    460     return syscall5(
    461         SYS__llseek,
    462         @bitCast(usize, @as(isize, fd)),
    463         @truncate(usize, offset >> 32),
    464         @truncate(usize, offset),
    465         @ptrToInt(result),
    466         whence,
    467     );
    468 }
    469 
    470 /// Can only be called on 64 bit systems. For 32 bit see `llseek`.
    471 pub fn lseek(fd: i32, offset: i64, whence: usize) usize {
    472     return syscall3(SYS_lseek, @bitCast(usize, @as(isize, fd)), @bitCast(usize, offset), whence);
    473 }
    474 
    475 pub fn exit(status: i32) noreturn {
    476     _ = syscall1(SYS_exit, @bitCast(usize, @as(isize, status)));
    477     unreachable;
    478 }
    479 
    480 pub fn exit_group(status: i32) noreturn {
    481     _ = syscall1(SYS_exit_group, @bitCast(usize, @as(isize, status)));
    482     unreachable;
    483 }
    484 
    485 pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
    486     return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags);
    487 }
    488 
    489 pub fn kill(pid: i32, sig: i32) usize {
    490     return syscall2(SYS_kill, @bitCast(usize, @as(isize, pid)), @bitCast(usize, @as(isize, sig)));
    491 }
    492 
    493 // TODO https://github.com/ziglang/zig/issues/265
    494 pub fn unlink(path: [*]const u8) usize {
    495     if (@hasDecl(@This(), "SYS_unlink")) {
    496         return syscall1(SYS_unlink, @ptrToInt(path));
    497     } else {
    498         return syscall3(SYS_unlinkat, @bitCast(usize, @as(isize, AT_FDCWD)), @ptrToInt(path), 0);
    499     }
    500 }
    501 
    502 // TODO https://github.com/ziglang/zig/issues/265
    503 pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
    504     return syscall3(SYS_unlinkat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), flags);
    505 }
    506 
    507 pub fn waitpid(pid: i32, status: *u32, flags: u32) usize {
    508     return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0);
    509 }
    510 
    511 var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
    512 
    513 // We must follow the C calling convention when we call into the VDSO
    514 const vdso_clock_gettime_ty = extern fn (i32, *timespec) usize;
    515 
    516 pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
    517     if (@hasDecl(@This(), "VDSO_CGT_SYM")) {
    518         const ptr = @atomicLoad(?*const c_void, &vdso_clock_gettime, .Unordered);
    519         if (ptr) |fn_ptr| {
    520             const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr);
    521             const rc = f(clk_id, tp);
    522             switch (rc) {
    523                 0, @bitCast(usize, @as(isize, -EINVAL)) => return rc,
    524                 else => {},
    525             }
    526         }
    527     }
    528     return syscall2(SYS_clock_gettime, @bitCast(usize, @as(isize, clk_id)), @ptrToInt(tp));
    529 }
    530 
    531 extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
    532     const ptr = @intToPtr(?*const c_void, vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM));
    533     // Note that we may not have a VDSO at all, update the stub address anyway
    534     // so that clock_gettime will fall back on the good old (and slow) syscall
    535     @atomicStore(?*const c_void, &vdso_clock_gettime, ptr, .Monotonic);
    536     // Call into the VDSO if available
    537     if (ptr) |fn_ptr| {
    538         const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr);
    539         return f(clk, ts);
    540     }
    541     return @bitCast(usize, @as(isize, -ENOSYS));
    542 }
    543 
    544 pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
    545     return syscall2(SYS_clock_getres, @bitCast(usize, @as(isize, clk_id)), @ptrToInt(tp));
    546 }
    547 
    548 pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
    549     return syscall2(SYS_clock_settime, @bitCast(usize, @as(isize, clk_id)), @ptrToInt(tp));
    550 }
    551 
    552 pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
    553     return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
    554 }
    555 
    556 pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
    557     return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
    558 }
    559 
    560 pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
    561     return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
    562 }
    563 
    564 pub fn setuid(uid: u32) usize {
    565     if (@hasDecl(@This(), "SYS_setuid32")) {
    566         return syscall1(SYS_setuid32, uid);
    567     } else {
    568         return syscall1(SYS_setuid, uid);
    569     }
    570 }
    571 
    572 pub fn setgid(gid: u32) usize {
    573     if (@hasDecl(@This(), "SYS_setgid32")) {
    574         return syscall1(SYS_setgid32, gid);
    575     } else {
    576         return syscall1(SYS_setgid, gid);
    577     }
    578 }
    579 
    580 pub fn setreuid(ruid: u32, euid: u32) usize {
    581     if (@hasDecl(@This(), "SYS_setreuid32")) {
    582         return syscall2(SYS_setreuid32, ruid, euid);
    583     } else {
    584         return syscall2(SYS_setreuid, ruid, euid);
    585     }
    586 }
    587 
    588 pub fn setregid(rgid: u32, egid: u32) usize {
    589     if (@hasDecl(@This(), "SYS_setregid32")) {
    590         return syscall2(SYS_setregid32, rgid, egid);
    591     } else {
    592         return syscall2(SYS_setregid, rgid, egid);
    593     }
    594 }
    595 
    596 pub fn getuid() u32 {
    597     if (@hasDecl(@This(), "SYS_getuid32")) {
    598         return @as(u32, syscall0(SYS_getuid32));
    599     } else {
    600         return @as(u32, syscall0(SYS_getuid));
    601     }
    602 }
    603 
    604 pub fn getgid() u32 {
    605     if (@hasDecl(@This(), "SYS_getgid32")) {
    606         return @as(u32, syscall0(SYS_getgid32));
    607     } else {
    608         return @as(u32, syscall0(SYS_getgid));
    609     }
    610 }
    611 
    612 pub fn geteuid() u32 {
    613     if (@hasDecl(@This(), "SYS_geteuid32")) {
    614         return @as(u32, syscall0(SYS_geteuid32));
    615     } else {
    616         return @as(u32, syscall0(SYS_geteuid));
    617     }
    618 }
    619 
    620 pub fn getegid() u32 {
    621     if (@hasDecl(@This(), "SYS_getegid32")) {
    622         return @as(u32, syscall0(SYS_getegid32));
    623     } else {
    624         return @as(u32, syscall0(SYS_getegid));
    625     }
    626 }
    627 
    628 pub fn seteuid(euid: u32) usize {
    629     return setreuid(std.math.maxInt(u32), euid);
    630 }
    631 
    632 pub fn setegid(egid: u32) usize {
    633     return setregid(std.math.maxInt(u32), egid);
    634 }
    635 
    636 pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
    637     if (@hasDecl(@This(), "SYS_getresuid32")) {
    638         return syscall3(SYS_getresuid32, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
    639     } else {
    640         return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
    641     }
    642 }
    643 
    644 pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
    645     if (@hasDecl(@This(), "SYS_getresgid32")) {
    646         return syscall3(SYS_getresgid32, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
    647     } else {
    648         return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
    649     }
    650 }
    651 
    652 pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
    653     if (@hasDecl(@This(), "SYS_setresuid32")) {
    654         return syscall3(SYS_setresuid32, ruid, euid, suid);
    655     } else {
    656         return syscall3(SYS_setresuid, ruid, euid, suid);
    657     }
    658 }
    659 
    660 pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
    661     if (@hasDecl(@This(), "SYS_setresgid32")) {
    662         return syscall3(SYS_setresgid32, rgid, egid, sgid);
    663     } else {
    664         return syscall3(SYS_setresgid, rgid, egid, sgid);
    665     }
    666 }
    667 
    668 pub fn getgroups(size: usize, list: *u32) usize {
    669     if (@hasDecl(@This(), "SYS_getgroups32")) {
    670         return syscall2(SYS_getgroups32, size, @ptrToInt(list));
    671     } else {
    672         return syscall2(SYS_getgroups, size, @ptrToInt(list));
    673     }
    674 }
    675 
    676 pub fn setgroups(size: usize, list: *const u32) usize {
    677     if (@hasDecl(@This(), "SYS_setgroups32")) {
    678         return syscall2(SYS_setgroups32, size, @ptrToInt(list));
    679     } else {
    680         return syscall2(SYS_setgroups, size, @ptrToInt(list));
    681     }
    682 }
    683 
    684 pub fn getpid() i32 {
    685     return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
    686 }
    687 
    688 pub fn gettid() i32 {
    689     return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
    690 }
    691 
    692 pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
    693     return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
    694 }
    695 
    696 pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
    697     assert(sig >= 1);
    698     assert(sig != SIGKILL);
    699     assert(sig != SIGSTOP);
    700 
    701     const restorer_fn = if ((act.flags & SA_SIGINFO) != 0) restore_rt else restore;
    702     var ksa = k_sigaction{
    703         .sigaction = act.sigaction,
    704         .flags = act.flags | SA_RESTORER,
    705         .mask = undefined,
    706         .restorer = @ptrCast(extern fn () void, restorer_fn),
    707     };
    708     var ksa_old: k_sigaction = undefined;
    709     const ksa_mask_size = @sizeOf(@TypeOf(ksa_old.mask));
    710     @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), ksa_mask_size);
    711     const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), ksa_mask_size);
    712     const err = getErrno(result);
    713     if (err != 0) {
    714         return result;
    715     }
    716     if (oact) |old| {
    717         old.sigaction = ksa_old.sigaction;
    718         old.flags = @truncate(u32, ksa_old.flags);
    719         @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), ksa_mask_size);
    720     }
    721     return 0;
    722 }
    723 
    724 pub fn blockAllSignals(set: *sigset_t) void {
    725     _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
    726 }
    727 
    728 pub fn blockAppSignals(set: *sigset_t) void {
    729     _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
    730 }
    731 
    732 pub fn restoreSignals(set: *sigset_t) void {
    733     _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
    734 }
    735 
    736 pub fn sigaddset(set: *sigset_t, sig: u6) void {
    737     const s = sig - 1;
    738     (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
    739 }
    740 
    741 pub fn sigismember(set: *const sigset_t, sig: u6) bool {
    742     const s = sig - 1;
    743     return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
    744 }
    745 
    746 pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
    747     if (builtin.arch == .i386) {
    748         return socketcall(SC_getsockname, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) });
    749     }
    750     return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
    751 }
    752 
    753 pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
    754     if (builtin.arch == .i386) {
    755         return socketcall(SC_getpeername, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) });
    756     }
    757     return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
    758 }
    759 
    760 pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
    761     if (builtin.arch == .i386) {
    762         return socketcall(SC_socket, &[3]usize{ domain, socket_type, protocol });
    763     }
    764     return syscall3(SYS_socket, domain, socket_type, protocol);
    765 }
    766 
    767 pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
    768     if (builtin.arch == .i386) {
    769         return socketcall(SC_setsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen) });
    770     }
    771     return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
    772 }
    773 
    774 pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
    775     if (builtin.arch == .i386) {
    776         return socketcall(SC_getsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen) });
    777     }
    778     return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
    779 }
    780 
    781 pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {
    782     if (builtin.arch == .i386) {
    783         return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
    784     }
    785     return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
    786 }
    787 
    788 pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize {
    789     if (@typeInfo(usize).Int.bits > @typeInfo(@TypeOf(mmsghdr(undefined).msg_len)).Int.bits) {
    790         // workaround kernel brokenness:
    791         // if adding up all iov_len overflows a i32 then split into multiple calls
    792         // see https://www.openwall.com/lists/musl/2014/06/07/5
    793         const kvlen = if (vlen > IOV_MAX) IOV_MAX else vlen; // matches kernel
    794         var next_unsent: usize = 0;
    795         for (msgvec[0..kvlen]) |*msg, i| {
    796             var size: i32 = 0;
    797             const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned
    798             for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov, j| {
    799                 if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) {
    800                     // batch-send all messages up to the current message
    801                     if (next_unsent < i) {
    802                         const batch_size = i - next_unsent;
    803                         const r = syscall4(SYS_sendmmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags);
    804                         if (getErrno(r) != 0) return next_unsent;
    805                         if (r < batch_size) return next_unsent + r;
    806                     }
    807                     // send current message as own packet
    808                     const r = sendmsg(fd, &msg.msg_hdr, flags);
    809                     if (getErrno(r) != 0) return r;
    810                     // Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe.
    811                     msg.msg_len = @intCast(u32, r);
    812                     next_unsent = i + 1;
    813                     break;
    814                 }
    815             }
    816         }
    817         if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG_EOR)
    818             const batch_size = kvlen - next_unsent;
    819             const r = syscall4(SYS_sendmmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags);
    820             if (getErrno(r) != 0) return r;
    821             return next_unsent + r;
    822         }
    823         return kvlen;
    824     }
    825     return syscall4(SYS_sendmmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msgvec), vlen, flags);
    826 }
    827 
    828 pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
    829     if (builtin.arch == .i386) {
    830         return socketcall(SC_connect, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len });
    831     }
    832     return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len);
    833 }
    834 
    835 pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
    836     if (builtin.arch == .i386) {
    837         return socketcall(SC_recvmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
    838     }
    839     return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
    840 }
    841 
    842 pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
    843     if (builtin.arch == .i386) {
    844         return socketcall(SC_recvfrom, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen) });
    845     }
    846     return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
    847 }
    848 
    849 pub fn shutdown(fd: i32, how: i32) usize {
    850     if (builtin.arch == .i386) {
    851         return socketcall(SC_shutdown, &[2]usize{ @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)) });
    852     }
    853     return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)));
    854 }
    855 
    856 pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
    857     if (builtin.arch == .i386) {
    858         return socketcall(SC_bind, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len) });
    859     }
    860     return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len));
    861 }
    862 
    863 pub fn listen(fd: i32, backlog: u32) usize {
    864     if (builtin.arch == .i386) {
    865         return socketcall(SC_listen, &[2]usize{ @bitCast(usize, @as(isize, fd)), backlog });
    866     }
    867     return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog);
    868 }
    869 
    870 pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
    871     if (builtin.arch == .i386) {
    872         return socketcall(SC_sendto, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen) });
    873     }
    874     return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
    875 }
    876 
    877 pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
    878     if (builtin.arch == .i386) {
    879         return socketcall(SC_socketpair, &[4]usize{ @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]) });
    880     }
    881     return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
    882 }
    883 
    884 pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
    885     if (builtin.arch == .i386) {
    886         return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 });
    887     }
    888     return accept4(fd, addr, len, 0);
    889 }
    890 
    891 pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
    892     if (builtin.arch == .i386) {
    893         return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags });
    894     }
    895     return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags);
    896 }
    897 
    898 pub fn fstat(fd: i32, stat_buf: *Stat) usize {
    899     if (@hasDecl(@This(), "SYS_fstat64")) {
    900         return syscall2(SYS_fstat64, @bitCast(usize, @as(isize, fd)), @ptrToInt(stat_buf));
    901     } else {
    902         return syscall2(SYS_fstat, @bitCast(usize, @as(isize, fd)), @ptrToInt(stat_buf));
    903     }
    904 }
    905 
    906 // TODO https://github.com/ziglang/zig/issues/265
    907 pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
    908     if (@hasDecl(@This(), "SYS_stat64")) {
    909         return syscall2(SYS_stat64, @ptrToInt(pathname), @ptrToInt(statbuf));
    910     } else {
    911         return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
    912     }
    913 }
    914 
    915 // TODO https://github.com/ziglang/zig/issues/265
    916 pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
    917     if (@hasDecl(@This(), "SYS_lstat64")) {
    918         return syscall2(SYS_lstat64, @ptrToInt(pathname), @ptrToInt(statbuf));
    919     } else {
    920         return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
    921     }
    922 }
    923 
    924 // TODO https://github.com/ziglang/zig/issues/265
    925 pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
    926     if (@hasDecl(@This(), "SYS_fstatat64")) {
    927         return syscall4(SYS_fstatat64, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
    928     } else {
    929         return syscall4(SYS_fstatat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
    930     }
    931 }
    932 
    933 pub fn statx(dirfd: i32, path: [*]const u8, flags: u32, mask: u32, statx_buf: *Statx) usize {
    934     if (@hasDecl(@This(), "SYS_statx")) {
    935         return syscall5(
    936             SYS_statx,
    937             @bitCast(usize, @as(isize, dirfd)),
    938             @ptrToInt(path),
    939             flags,
    940             mask,
    941             @ptrToInt(statx_buf),
    942         );
    943     }
    944     return @bitCast(usize, @as(isize, -ENOSYS));
    945 }
    946 
    947 // TODO https://github.com/ziglang/zig/issues/265
    948 pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
    949     return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
    950 }
    951 
    952 // TODO https://github.com/ziglang/zig/issues/265
    953 pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
    954     return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
    955 }
    956 
    957 pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
    958     return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
    959 }
    960 
    961 // TODO https://github.com/ziglang/zig/issues/265
    962 pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
    963     return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
    964 }
    965 
    966 // TODO https://github.com/ziglang/zig/issues/265
    967 pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
    968     return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
    969 }
    970 
    971 // TODO https://github.com/ziglang/zig/issues/265
    972 pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
    973     return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
    974 }
    975 
    976 // TODO https://github.com/ziglang/zig/issues/265
    977 pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
    978     return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
    979 }
    980 
    981 // TODO https://github.com/ziglang/zig/issues/265
    982 pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
    983     return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
    984 }
    985 
    986 // TODO https://github.com/ziglang/zig/issues/265
    987 pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
    988     return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
    989 }
    990 
    991 // TODO https://github.com/ziglang/zig/issues/265
    992 pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
    993     return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
    994 }
    995 
    996 // TODO https://github.com/ziglang/zig/issues/265
    997 pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
    998     return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
    999 }
   1000 
   1001 // TODO https://github.com/ziglang/zig/issues/265
   1002 pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
   1003     return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
   1004 }
   1005 
   1006 pub fn sched_yield() usize {
   1007     return syscall0(SYS_sched_yield);
   1008 }
   1009 
   1010 pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {
   1011     const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, @as(isize, pid)), size, @ptrToInt(set));
   1012     if (@bitCast(isize, rc) < 0) return rc;
   1013     if (rc < size) @memset(@ptrCast([*]u8, set) + rc, 0, size - rc);
   1014     return 0;
   1015 }
   1016 
   1017 pub fn epoll_create() usize {
   1018     return epoll_create1(0);
   1019 }
   1020 
   1021 pub fn epoll_create1(flags: usize) usize {
   1022     return syscall1(SYS_epoll_create1, flags);
   1023 }
   1024 
   1025 pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: ?*epoll_event) usize {
   1026     return syscall4(SYS_epoll_ctl, @bitCast(usize, @as(isize, epoll_fd)), @intCast(usize, op), @bitCast(usize, @as(isize, fd)), @ptrToInt(ev));
   1027 }
   1028 
   1029 pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
   1030     return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
   1031 }
   1032 
   1033 pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
   1034     return syscall6(
   1035         SYS_epoll_pwait,
   1036         @bitCast(usize, @as(isize, epoll_fd)),
   1037         @ptrToInt(events),
   1038         @intCast(usize, maxevents),
   1039         @bitCast(usize, @as(isize, timeout)),
   1040         @ptrToInt(sigmask),
   1041         @sizeOf(sigset_t),
   1042     );
   1043 }
   1044 
   1045 pub fn eventfd(count: u32, flags: u32) usize {
   1046     return syscall2(SYS_eventfd2, count, flags);
   1047 }
   1048 
   1049 pub fn timerfd_create(clockid: i32, flags: u32) usize {
   1050     return syscall2(SYS_timerfd_create, @bitCast(usize, @as(isize, clockid)), flags);
   1051 }
   1052 
   1053 pub const itimerspec = extern struct {
   1054     it_interval: timespec,
   1055     it_value: timespec,
   1056 };
   1057 
   1058 pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
   1059     return syscall2(SYS_timerfd_gettime, @bitCast(usize, @as(isize, fd)), @ptrToInt(curr_value));
   1060 }
   1061 
   1062 pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
   1063     return syscall4(SYS_timerfd_settime, @bitCast(usize, @as(isize, fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
   1064 }
   1065 
   1066 pub fn unshare(flags: usize) usize {
   1067     return syscall1(SYS_unshare, flags);
   1068 }
   1069 
   1070 pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
   1071     return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
   1072 }
   1073 
   1074 pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
   1075     return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
   1076 }
   1077 
   1078 pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) usize {
   1079     return syscall2(SYS_sigaltstack, @ptrToInt(ss), @ptrToInt(old_ss));
   1080 }
   1081 
   1082 pub fn uname(uts: *utsname) usize {
   1083     return syscall1(SYS_uname, @ptrToInt(uts));
   1084 }
   1085 
   1086 // XXX: This should be weak
   1087 extern const __ehdr_start: elf.Ehdr = undefined;
   1088 
   1089 pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize {
   1090     if (builtin.link_libc) {
   1091         return std.c.dl_iterate_phdr(@ptrCast(std.c.dl_iterate_phdr_callback, callback), @ptrCast(?*c_void, data));
   1092     }
   1093 
   1094     const elf_base = @ptrToInt(&__ehdr_start);
   1095     const n_phdr = __ehdr_start.e_phnum;
   1096     const phdrs = (@intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff))[0..n_phdr];
   1097 
   1098     var it = dl.linkmap_iterator(phdrs) catch return 0;
   1099 
   1100     // The executable has no dynamic link segment, create a single entry for
   1101     // the whole ELF image
   1102     if (it.end()) {
   1103         var info = dl_phdr_info{
   1104             .dlpi_addr = elf_base,
   1105             .dlpi_name = "/proc/self/exe",
   1106             .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff),
   1107             .dlpi_phnum = __ehdr_start.e_phnum,
   1108         };
   1109 
   1110         return callback(&info, @sizeOf(dl_phdr_info), data);
   1111     }
   1112 
   1113     // Last return value from the callback function
   1114     var last_r: isize = 0;
   1115     while (it.next()) |entry| {
   1116         var dlpi_phdr: usize = undefined;
   1117         var dlpi_phnum: u16 = undefined;
   1118 
   1119         if (entry.l_addr != 0) {
   1120             const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr);
   1121             dlpi_phdr = entry.l_addr + elf_header.e_phoff;
   1122             dlpi_phnum = elf_header.e_phnum;
   1123         } else {
   1124             // This is the running ELF image
   1125             dlpi_phdr = elf_base + __ehdr_start.e_phoff;
   1126             dlpi_phnum = __ehdr_start.e_phnum;
   1127         }
   1128 
   1129         var info = dl_phdr_info{
   1130             .dlpi_addr = entry.l_addr,
   1131             .dlpi_name = entry.l_name,
   1132             .dlpi_phdr = @intToPtr([*]elf.Phdr, dlpi_phdr),
   1133             .dlpi_phnum = dlpi_phnum,
   1134         };
   1135 
   1136         last_r = callback(&info, @sizeOf(dl_phdr_info), data);
   1137         if (last_r != 0) break;
   1138     }
   1139 
   1140     return last_r;
   1141 }
   1142 
   1143 pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize {
   1144     return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p));
   1145 }
   1146 
   1147 pub fn io_uring_enter(fd: i32, to_submit: u32, min_complete: u32, flags: u32, sig: ?*sigset_t) usize {
   1148     return syscall6(SYS_io_uring_enter, @bitCast(usize, @as(isize, fd)), to_submit, min_complete, flags, @ptrToInt(sig), NSIG / 8);
   1149 }
   1150 
   1151 pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32) usize {
   1152     return syscall4(SYS_io_uring_register, @bitCast(usize, @as(isize, fd)), opcode, @ptrToInt(arg), nr_args);
   1153 }
   1154 
   1155 test "" {
   1156     if (builtin.os == .linux) {
   1157         _ = @import("linux/test.zig");
   1158     }
   1159 }