| ... | ... | @@ -673,23 +673,43 @@ pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize { |
| 673 | 673 | } |
| 674 | 674 | } |
| 675 | 675 | |
| 676 | | pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*const timespec) usize { |
| 677 | | return syscall4(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val)), @intFromPtr(timeout)); |
| 676 | // The 4th parameter to the v1 futex syscall can either be an optional |
| 677 | // pointer to a timespec, or a uint32, depending on which "op" is being |
| 678 | // performed. |
| 679 | pub const futex_param4 = extern union { |
| 680 | timeout: ?*const timespec, |
| 681 | /// On all platforms only the bottom 32-bits of `val2` are relevant. |
| 682 | /// This is 64-bit to match the pointer in the union. |
| 683 | val2: usize, |
| 684 | }; |
| 685 | |
| 686 | /// The futex v1 syscall, see also the newer the futex2_{wait,wakeup,requeue,waitv} syscalls. |
| 687 | /// |
| 688 | /// The futex_op parameter is a sub-command and flags. The sub-command |
| 689 | /// defines which of the subsequent paramters are relevant. |
| 690 | pub fn futex(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32, val2timeout: futex_param4, uaddr2: ?*const anyopaque, val3: u32) usize { |
| 691 | return syscall6(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val, @intFromPtr(val2timeout.timeout), @intFromPtr(uaddr2), val3); |
| 678 | 692 | } |
| 679 | 693 | |
| 680 | | pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { |
| 681 | | return syscall3(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val))); |
| 694 | /// Three-argument variation of the v1 futex call. Only suitable for a |
| 695 | /// futex_op that ignores the remaining arguments (e.g., FUTUX_OP.WAKE). |
| 696 | pub fn futex_3arg(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32) usize { |
| 697 | return syscall3(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val); |
| 682 | 698 | } |
| 683 | 699 | |
| 684 | | /// Given an array of `futex_waitv`, wait on each uaddr. |
| 700 | /// Four-argument variation on the v1 futex call. Only suitable for |
| 701 | /// futex_op that ignores the remaining arguments (e.g., FUTEX_OP.WAIT). |
| 702 | pub fn futex_4arg(uaddr: *const anyopaque, futex_op: FUTEX_OP, val: u32, timeout: ?*const timespec) usize { |
| 703 | return syscall4(.futex, @intFromPtr(uaddr), @as(u32, @bitCast(futex_op)), val, @intFromPtr(timeout)); |
| 704 | } |
| 705 | |
| 706 | /// Given an array of `futex2_waitone`, wait on each uaddr. |
| 685 | 707 | /// The thread wakes if a futex_wake() is performed at any uaddr. |
| 686 | | /// The syscall returns immediately if any waiter has *uaddr != val. |
| 687 | | /// timeout is an optional timeout value for the operation. |
| 688 | | /// Each waiter has individual flags. |
| 689 | | /// The `flags` argument for the syscall should be used solely for specifying |
| 690 | | /// the timeout as realtime, if needed. |
| 691 | | /// Flags for private futexes, sizes, etc. should be used on the |
| 692 | | /// individual flags of each waiter. |
| 708 | /// The syscall returns immediately if any futex has *uaddr != val. |
| 709 | /// timeout is an optional, absolute timeout value for the operation. |
| 710 | /// The `flags` argument is for future use and currently should be `.{}`. |
| 711 | /// Flags for private futexes, sizes, etc. should be set on the |
| 712 | /// individual flags of each `futex2_waitone`. |
| 693 | 713 | /// |
| 694 | 714 | /// Returns the array index of one of the woken futexes. |
| 695 | 715 | /// No further information is provided: any number of other futexes may also |
| ... | ... | @@ -697,42 +717,43 @@ pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { |
| 697 | 717 | /// the returned index may refer to any one of them. |
| 698 | 718 | /// (It is not necessaryily the futex with the smallest index, nor the one |
| 699 | 719 | /// most recently woken, nor...) |
| 720 | /// |
| 721 | /// Requires at least kernel v5.16. |
| 700 | 722 | pub fn futex2_waitv( |
| 701 | | /// List of futexes to wait on. |
| 702 | | waiters: [*]futex_waitv, |
| 703 | | /// Length of `waiters`. |
| 723 | futexes: [*]const futex2_waitone, |
| 724 | /// Length of `futexes`. Max of FUTEX2_WAITONE_MAX. |
| 704 | 725 | nr_futexes: u32, |
| 705 | | /// Flag for timeout (monotonic/realtime). |
| 706 | | flags: u32, |
| 707 | | /// Optional absolute timeout. |
| 708 | | timeout: ?*const timespec, |
| 726 | flags: FUTEX2_FLAGS_WAITV, |
| 727 | /// Optional absolute timeout. Always 64-bit, even on 32-bit platforms. |
| 728 | timeout: ?*const kernel_timespec, |
| 709 | 729 | /// Clock to be used for the timeout, realtime or monotonic. |
| 710 | 730 | clockid: clockid_t, |
| 711 | 731 | ) usize { |
| 712 | 732 | return syscall5( |
| 713 | 733 | .futex_waitv, |
| 714 | | @intFromPtr(waiters), |
| 734 | @intFromPtr(futexes), |
| 715 | 735 | nr_futexes, |
| 716 | | flags, |
| 736 | @as(u32, @bitCast(flags)), |
| 717 | 737 | @intFromPtr(timeout), |
| 718 | | @bitCast(@as(isize, @intFromEnum(clockid))), |
| 738 | @intFromEnum(clockid), |
| 719 | 739 | ); |
| 720 | 740 | } |
| 721 | 741 | |
| 722 | | /// Wait on a futex. |
| 723 | | /// Identical to the traditional `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the |
| 724 | | /// futex2 familiy of calls. |
| 742 | /// Wait on a single futex. |
| 743 | /// Identical to the futex v1 `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the |
| 744 | /// futex2 family of calls. |
| 745 | /// |
| 746 | /// Requires at least kernel v6.7. |
| 725 | 747 | pub fn futex2_wait( |
| 726 | 748 | /// Address of the futex to wait on. |
| 727 | 749 | uaddr: *const anyopaque, |
| 728 | 750 | /// Value of `uaddr`. |
| 729 | 751 | val: usize, |
| 730 | | /// Bitmask. |
| 752 | /// Bitmask to match against incoming wakeup masks. Must not be zero. |
| 731 | 753 | mask: usize, |
| 732 | | /// `FUTEX2` flags. |
| 733 | | flags: u32, |
| 734 | | /// Optional absolute timeout. |
| 735 | | timeout: ?*const timespec, |
| 754 | flags: FUTEX2_FLAGS, |
| 755 | /// Optional absolute timeout. Always 64-bit, even on 32-bit platforms. |
| 756 | timeout: ?*const kernel_timespec, |
| 736 | 757 | /// Clock to be used for the timeout, realtime or monotonic. |
| 737 | 758 | clockid: clockid_t, |
| 738 | 759 | ) usize { |
| ... | ... | @@ -741,52 +762,55 @@ pub fn futex2_wait( |
| 741 | 762 | @intFromPtr(uaddr), |
| 742 | 763 | val, |
| 743 | 764 | mask, |
| 744 | | flags, |
| 765 | @as(u32, @bitCast(flags)), |
| 745 | 766 | @intFromPtr(timeout), |
| 746 | | @bitCast(@as(isize, @intFromEnum(clockid))), |
| 767 | @intFromEnum(clockid), |
| 747 | 768 | ); |
| 748 | 769 | } |
| 749 | 770 | |
| 750 | | /// Wake a number of futexes. |
| 751 | | /// Identical to the traditional `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the |
| 771 | /// Wake (subset of) waiters on given futex. |
| 772 | /// Identical to the traditional `FUTEX.FUTEX_WAKE_BITSET` op, except it is part of the |
| 752 | 773 | /// futex2 family of calls. |
| 774 | /// |
| 775 | /// Requires at least kernel v6.7. |
| 753 | 776 | pub fn futex2_wake( |
| 754 | | /// Address of the futex(es) to wake. |
| 777 | /// Futex to wake |
| 755 | 778 | uaddr: *const anyopaque, |
| 756 | | /// Bitmask |
| 779 | /// Bitmask to match against waiters. |
| 757 | 780 | mask: usize, |
| 758 | | /// Number of the futexes to wake. |
| 759 | | nr: i32, |
| 760 | | /// `FUTEX2` flags. |
| 761 | | flags: u32, |
| 781 | /// Maximum number of waiters on the futex to wake. |
| 782 | nr_wake: i32, |
| 783 | flags: FUTEX2_FLAGS, |
| 762 | 784 | ) usize { |
| 763 | 785 | return syscall4( |
| 764 | 786 | .futex_wake, |
| 765 | 787 | @intFromPtr(uaddr), |
| 766 | 788 | mask, |
| 767 | | @bitCast(@as(isize, nr)), |
| 768 | | flags, |
| 789 | @as(u32, @bitCast(nr_wake)), |
| 790 | @as(u32, @bitCast(flags)), |
| 769 | 791 | ); |
| 770 | 792 | } |
| 771 | 793 | |
| 772 | | /// Requeue a waiter from one futex to another. |
| 794 | /// Wake and/or requeue waiter(s) from one futex to another. |
| 773 | 795 | /// Identical to `FUTEX.CMP_REQUEUE`, except it is part of the futex2 family of calls. |
| 796 | /// |
| 797 | /// Requires at least kernel v6.7. |
| 774 | 798 | pub fn futex2_requeue( |
| 775 | | /// Array describing the source and destination futex. |
| 776 | | waiters: [*]futex_waitv, |
| 777 | | /// Unused. |
| 778 | | flags: u32, |
| 779 | | /// Number of futexes to wake. |
| 799 | /// The source and destination futexes. Must be a 2-element array. |
| 800 | waiters: [*]const futex2_waitone, |
| 801 | /// Currently unused. |
| 802 | flags: FUTEX2_FLAGS_REQUEUE, |
| 803 | /// Maximum number of waiters to wake on the source futex. |
| 780 | 804 | nr_wake: i32, |
| 781 | | /// Number of futexes to requeue. |
| 805 | /// Maximum number of waiters to transfer to the destination futex. |
| 782 | 806 | nr_requeue: i32, |
| 783 | 807 | ) usize { |
| 784 | 808 | return syscall4( |
| 785 | 809 | .futex_requeue, |
| 786 | 810 | @intFromPtr(waiters), |
| 787 | | flags, |
| 788 | | @bitCast(@as(isize, nr_wake)), |
| 789 | | @bitCast(@as(isize, nr_requeue)), |
| 811 | @as(u32, @bitCast(flags)), |
| 812 | @as(u32, @bitCast(nr_wake)), |
| 813 | @as(u32, @bitCast(nr_requeue)), |
| 790 | 814 | ); |
| 791 | 815 | } |
| 792 | 816 | |
| ... | ... | @@ -3385,37 +3409,97 @@ pub const FALLOC = struct { |
| 3385 | 3409 | pub const FL_UNSHARE_RANGE = 0x40; |
| 3386 | 3410 | }; |
| 3387 | 3411 | |
| 3388 | | pub const FUTEX = struct { |
| 3389 | | pub const WAIT = 0; |
| 3390 | | pub const WAKE = 1; |
| 3391 | | pub const FD = 2; |
| 3392 | | pub const REQUEUE = 3; |
| 3393 | | pub const CMP_REQUEUE = 4; |
| 3394 | | pub const WAKE_OP = 5; |
| 3395 | | pub const LOCK_PI = 6; |
| 3396 | | pub const UNLOCK_PI = 7; |
| 3397 | | pub const TRYLOCK_PI = 8; |
| 3398 | | pub const WAIT_BITSET = 9; |
| 3399 | | pub const WAKE_BITSET = 10; |
| 3400 | | pub const WAIT_REQUEUE_PI = 11; |
| 3401 | | pub const CMP_REQUEUE_PI = 12; |
| 3402 | | |
| 3403 | | pub const PRIVATE_FLAG = 128; |
| 3404 | | |
| 3405 | | pub const CLOCK_REALTIME = 256; |
| 3406 | | |
| 3407 | | /// Max numbers of elements in a `futex_waitv` array. |
| 3408 | | pub const WAITV_MAX = 128; |
| 3409 | | }; |
| 3410 | | |
| 3411 | | pub const FUTEX2 = struct { |
| 3412 | | pub const SIZE_U8 = 0x00; |
| 3413 | | pub const SIZE_U16 = 0x01; |
| 3414 | | pub const SIZE_U32 = 0x02; |
| 3415 | | pub const SIZE_U64 = 0x03; |
| 3416 | | pub const NUMA = 0x04; |
| 3417 | | |
| 3418 | | pub const PRIVATE = FUTEX.PRIVATE_FLAG; |
| 3412 | // Futex v1 API commands. See futex man page for each command's |
| 3413 | // interpretation of the futex arguments. |
| 3414 | pub const FUTEX_COMMAND = enum(u7) { |
| 3415 | WAIT = 0, |
| 3416 | WAKE = 1, |
| 3417 | FD = 2, |
| 3418 | REQUEUE = 3, |
| 3419 | CMP_REQUEUE = 4, |
| 3420 | WAKE_OP = 5, |
| 3421 | LOCK_PI = 6, |
| 3422 | UNLOCK_PI = 7, |
| 3423 | TRYLOCK_PI = 8, |
| 3424 | WAIT_BITSET = 9, |
| 3425 | WAKE_BITSET = 10, |
| 3426 | WAIT_REQUEUE_PI = 11, |
| 3427 | CMP_REQUEUE_PI = 12, |
| 3428 | }; |
| 3429 | |
| 3430 | /// Futex v1 API command and flags for the `futex_op` parameter |
| 3431 | pub const FUTEX_OP = packed struct(u32) { |
| 3432 | cmd: FUTEX_COMMAND, |
| 3433 | private: bool, |
| 3434 | realtime: bool = false, // realtime clock vs. monotonic clock |
| 3435 | _reserved: u23 = 0, |
| 3436 | }; |
| 3437 | |
| 3438 | /// Futex v1 FUTEX_WAKE_OP `val3` operation: |
| 3439 | pub const FUTEX_WAKE_OP = packed struct(u32) { |
| 3440 | cmd: FUTEX_WAKE_OP_CMD, |
| 3441 | /// From C API `FUTEX_OP_ARG_SHIFT`: Use (1 << oparg) as operand |
| 3442 | arg_shift: bool = false, |
| 3443 | cmp: FUTEX_WAKE_OP_CMP, |
| 3444 | oparg: u12, |
| 3445 | cmdarg: u12, |
| 3446 | }; |
| 3447 | |
| 3448 | /// Futex v1 cmd for FUTEX_WAKE_OP `val3` command. |
| 3449 | pub const FUTEX_WAKE_OP_CMD = enum(u3) { |
| 3450 | /// uaddr2 = oparg |
| 3451 | SET = 0, |
| 3452 | /// uaddr2 += oparg |
| 3453 | ADD = 1, |
| 3454 | /// uaddr2 |= oparg |
| 3455 | OR = 2, |
| 3456 | /// uaddr2 &= ~oparg |
| 3457 | ANDN = 3, |
| 3458 | /// uaddr2 ^= oparg |
| 3459 | XOR = 4, |
| 3460 | }; |
| 3461 | |
| 3462 | /// Futex v1 comparison op for FUTEX_WAKE_OP `val3` cmp |
| 3463 | pub const FUTEX_WAKE_OP_CMP = enum(u4) { |
| 3464 | EQ = 0, |
| 3465 | NE = 1, |
| 3466 | LT = 2, |
| 3467 | LE = 3, |
| 3468 | GT = 4, |
| 3469 | GE = 5, |
| 3470 | }; |
| 3471 | |
| 3472 | /// Max numbers of elements in a `futex2_waitone` array. |
| 3473 | pub const FUTEX2_WAITONE_MAX = 128; |
| 3474 | |
| 3475 | /// For futex v2 API, the size of the futex at the uaddr. v1 futex are |
| 3476 | /// always implicitly U32. As of kernel v6.14, only U32 is implemented |
| 3477 | /// for v2 futexes. |
| 3478 | pub const FUTEX2_SIZE = enum(u2) { |
| 3479 | U8 = 0, |
| 3480 | U16 = 1, |
| 3481 | U32 = 2, |
| 3482 | U64 = 3, |
| 3483 | }; |
| 3484 | |
| 3485 | /// As of kernel 6.14 there are no defined flags to futex2_waitv. |
| 3486 | pub const FUTEX2_FLAGS_WAITV = packed struct(u32) { |
| 3487 | _reserved: u32 = 0, |
| 3488 | }; |
| 3489 | |
| 3490 | /// As of kernel 6.14 there are no defined flags to futex2_requeue. |
| 3491 | pub const FUTEX2_FLAGS_REQUEUE = packed struct(u32) { |
| 3492 | _reserved: u32 = 0, |
| 3493 | }; |
| 3494 | |
| 3495 | /// Flags for futex v2 APIs (futex2_wait, futex2_wake, futex2_requeue, but |
| 3496 | /// not the futex2_waitv syscall, but also used in the futex2_waitone struct). |
| 3497 | pub const FUTEX2_FLAGS = packed struct(u32) { |
| 3498 | size: FUTEX2_SIZE, |
| 3499 | numa: bool = false, |
| 3500 | _reserved: u4 = 0, |
| 3501 | private: bool, |
| 3502 | _undefined: u24 = 0, |
| 3419 | 3503 | }; |
| 3420 | 3504 | |
| 3421 | 3505 | pub const PROT = struct { |
| ... | ... | @@ -9281,17 +9365,17 @@ pub const PTRACE = struct { |
| 9281 | 9365 | pub const GET_SYSCALL_INFO = 0x420e; |
| 9282 | 9366 | }; |
| 9283 | 9367 | |
| 9284 | | /// A waiter for vectorized wait. |
| 9285 | | pub const futex_waitv = extern struct { |
| 9286 | | // Expected value at uaddr |
| 9368 | /// For futex2_waitv and futex2_requeue. Arrays of `futex2_waitone` allow |
| 9369 | /// waiting on multiple futexes in one call. |
| 9370 | pub const futex2_waitone = extern struct { |
| 9371 | /// Expected value at uaddr, should match size of futex. |
| 9287 | 9372 | val: u64, |
| 9288 | | /// User address to wait on. |
| 9373 | /// User address to wait on. Top-bits must be 0 on 32-bit. |
| 9289 | 9374 | uaddr: u64, |
| 9290 | 9375 | /// Flags for this waiter. |
| 9291 | | flags: u32, |
| 9376 | flags: FUTEX2_FLAGS, |
| 9292 | 9377 | /// Reserved member to preserve alignment. |
| 9293 | | /// Should be 0. |
| 9294 | | __reserved: u32, |
| 9378 | __reserved: u32 = 0, |
| 9295 | 9379 | }; |
| 9296 | 9380 | |
| 9297 | 9381 | pub const cache_stat_range = extern struct { |