| ... | @@ -673,23 +673,43 @@ pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize { | ... | @@ -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 { | 676 | // The 4th parameter to the v1 futex syscall can either be an optional |
| 677 | return syscall4(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val)), @intFromPtr(timeout)); | 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 { | 694 | /// Three-argument variation of the v1 futex call. Only suitable for a |
| 681 | return syscall3(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val))); | 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 | /// The thread wakes if a futex_wake() is performed at any uaddr. | 707 | /// The thread wakes if a futex_wake() is performed at any uaddr. |
| 686 | /// The syscall returns immediately if any waiter has *uaddr != val. | 708 | /// The syscall returns immediately if any futex has *uaddr != val. |
| 687 | /// timeout is an optional timeout value for the operation. | 709 | /// timeout is an optional, absolute timeout value for the operation. |
| 688 | /// Each waiter has individual flags. | 710 | /// The `flags` argument is for future use and currently should be `.{}`. |
| 689 | /// The `flags` argument for the syscall should be used solely for specifying | 711 | /// Flags for private futexes, sizes, etc. should be set on the |
| 690 | /// the timeout as realtime, if needed. | 712 | /// individual flags of each `futex2_waitone`. |
| 691 | /// Flags for private futexes, sizes, etc. should be used on the | | |
| 692 | /// individual flags of each waiter. | | |
| 693 | /// | 713 | /// |
| 694 | /// Returns the array index of one of the woken futexes. | 714 | /// Returns the array index of one of the woken futexes. |
| 695 | /// No further information is provided: any number of other futexes may also | 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,42 +717,43 @@ pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { |
| 697 | /// the returned index may refer to any one of them. | 717 | /// the returned index may refer to any one of them. |
| 698 | /// (It is not necessaryily the futex with the smallest index, nor the one | 718 | /// (It is not necessaryily the futex with the smallest index, nor the one |
| 699 | /// most recently woken, nor...) | 719 | /// most recently woken, nor...) |
| | 720 | /// |
| | 721 | /// Requires at least kernel v5.16. |
| 700 | pub fn futex2_waitv( | 722 | pub fn futex2_waitv( |
| 701 | /// List of futexes to wait on. | 723 | futexes: [*]const futex2_waitone, |
| 702 | waiters: [*]futex_waitv, | 724 | /// Length of `futexes`. Max of FUTEX2_WAITONE_MAX. |
| 703 | /// Length of `waiters`. | | |
| 704 | nr_futexes: u32, | 725 | nr_futexes: u32, |
| 705 | /// Flag for timeout (monotonic/realtime). | 726 | flags: FUTEX2_FLAGS_WAITV, |
| 706 | flags: u32, | 727 | /// Optional absolute timeout. Always 64-bit, even on 32-bit platforms. |
| 707 | /// Optional absolute timeout. | 728 | timeout: ?*const kernel_timespec, |
| 708 | timeout: ?*const timespec, | | |
| 709 | /// Clock to be used for the timeout, realtime or monotonic. | 729 | /// Clock to be used for the timeout, realtime or monotonic. |
| 710 | clockid: clockid_t, | 730 | clockid: clockid_t, |
| 711 | ) usize { | 731 | ) usize { |
| 712 | return syscall5( | 732 | return syscall5( |
| 713 | .futex_waitv, | 733 | .futex_waitv, |
| 714 | @intFromPtr(waiters), | 734 | @intFromPtr(futexes), |
| 715 | nr_futexes, | 735 | nr_futexes, |
| 716 | flags, | 736 | @as(u32, @bitCast(flags)), |
| 717 | @intFromPtr(timeout), | 737 | @intFromPtr(timeout), |
| 718 | @bitCast(@as(isize, @intFromEnum(clockid))), | 738 | @intFromEnum(clockid), |
| 719 | ); | 739 | ); |
| 720 | } | 740 | } |
| 721 | | 741 | |
| 722 | /// Wait on a futex. | 742 | /// Wait on a single futex. |
| 723 | /// Identical to the traditional `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the | 743 | /// Identical to the futex v1 `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the |
| 724 | /// futex2 familiy of calls. | 744 | /// futex2 family of calls. |
| | 745 | /// |
| | 746 | /// Requires at least kernel v6.7. |
| 725 | pub fn futex2_wait( | 747 | pub fn futex2_wait( |
| 726 | /// Address of the futex to wait on. | 748 | /// Address of the futex to wait on. |
| 727 | uaddr: *const anyopaque, | 749 | uaddr: *const anyopaque, |
| 728 | /// Value of `uaddr`. | 750 | /// Value of `uaddr`. |
| 729 | val: usize, | 751 | val: usize, |
| 730 | /// Bitmask. | 752 | /// Bitmask to match against incoming wakeup masks. Must not be zero. |
| 731 | mask: usize, | 753 | mask: usize, |
| 732 | /// `FUTEX2` flags. | 754 | flags: FUTEX2_FLAGS, |
| 733 | flags: u32, | 755 | /// Optional absolute timeout. Always 64-bit, even on 32-bit platforms. |
| 734 | /// Optional absolute timeout. | 756 | timeout: ?*const kernel_timespec, |
| 735 | timeout: ?*const timespec, | | |
| 736 | /// Clock to be used for the timeout, realtime or monotonic. | 757 | /// Clock to be used for the timeout, realtime or monotonic. |
| 737 | clockid: clockid_t, | 758 | clockid: clockid_t, |
| 738 | ) usize { | 759 | ) usize { |
| ... | @@ -741,52 +762,55 @@ pub fn futex2_wait( | ... | @@ -741,52 +762,55 @@ pub fn futex2_wait( |
| 741 | @intFromPtr(uaddr), | 762 | @intFromPtr(uaddr), |
| 742 | val, | 763 | val, |
| 743 | mask, | 764 | mask, |
| 744 | flags, | 765 | @as(u32, @bitCast(flags)), |
| 745 | @intFromPtr(timeout), | 766 | @intFromPtr(timeout), |
| 746 | @bitCast(@as(isize, @intFromEnum(clockid))), | 767 | @intFromEnum(clockid), |
| 747 | ); | 768 | ); |
| 748 | } | 769 | } |
| 749 | | 770 | |
| 750 | /// Wake a number of futexes. | 771 | /// Wake (subset of) waiters on given futex. |
| 751 | /// Identical to the traditional `FUTEX.FUTEX_WAIT_BITSET` op, except it is part of the | 772 | /// Identical to the traditional `FUTEX.FUTEX_WAKE_BITSET` op, except it is part of the |
| 752 | /// futex2 family of calls. | 773 | /// futex2 family of calls. |
| | 774 | /// |
| | 775 | /// Requires at least kernel v6.7. |
| 753 | pub fn futex2_wake( | 776 | pub fn futex2_wake( |
| 754 | /// Address of the futex(es) to wake. | 777 | /// Futex to wake |
| 755 | uaddr: *const anyopaque, | 778 | uaddr: *const anyopaque, |
| 756 | /// Bitmask | 779 | /// Bitmask to match against waiters. |
| 757 | mask: usize, | 780 | mask: usize, |
| 758 | /// Number of the futexes to wake. | 781 | /// Maximum number of waiters on the futex to wake. |
| 759 | nr: i32, | 782 | nr_wake: i32, |
| 760 | /// `FUTEX2` flags. | 783 | flags: FUTEX2_FLAGS, |
| 761 | flags: u32, | | |
| 762 | ) usize { | 784 | ) usize { |
| 763 | return syscall4( | 785 | return syscall4( |
| 764 | .futex_wake, | 786 | .futex_wake, |
| 765 | @intFromPtr(uaddr), | 787 | @intFromPtr(uaddr), |
| 766 | mask, | 788 | mask, |
| 767 | @bitCast(@as(isize, nr)), | 789 | @as(u32, @bitCast(nr_wake)), |
| 768 | flags, | 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 | /// Identical to `FUTEX.CMP_REQUEUE`, except it is part of the futex2 family of calls. | 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 | pub fn futex2_requeue( | 798 | pub fn futex2_requeue( |
| 775 | /// Array describing the source and destination futex. | 799 | /// The source and destination futexes. Must be a 2-element array. |
| 776 | waiters: [*]futex_waitv, | 800 | waiters: [*]const futex2_waitone, |
| 777 | /// Unused. | 801 | /// Currently unused. |
| 778 | flags: u32, | 802 | flags: FUTEX2_FLAGS_REQUEUE, |
| 779 | /// Number of futexes to wake. | 803 | /// Maximum number of waiters to wake on the source futex. |
| 780 | nr_wake: i32, | 804 | nr_wake: i32, |
| 781 | /// Number of futexes to requeue. | 805 | /// Maximum number of waiters to transfer to the destination futex. |
| 782 | nr_requeue: i32, | 806 | nr_requeue: i32, |
| 783 | ) usize { | 807 | ) usize { |
| 784 | return syscall4( | 808 | return syscall4( |
| 785 | .futex_requeue, | 809 | .futex_requeue, |
| 786 | @intFromPtr(waiters), | 810 | @intFromPtr(waiters), |
| 787 | flags, | 811 | @as(u32, @bitCast(flags)), |
| 788 | @bitCast(@as(isize, nr_wake)), | 812 | @as(u32, @bitCast(nr_wake)), |
| 789 | @bitCast(@as(isize, nr_requeue)), | 813 | @as(u32, @bitCast(nr_requeue)), |
| 790 | ); | 814 | ); |
| 791 | } | 815 | } |
| 792 | | 816 | |
| ... | @@ -3385,37 +3409,97 @@ pub const FALLOC = struct { | ... | @@ -3385,37 +3409,97 @@ pub const FALLOC = struct { |
| 3385 | pub const FL_UNSHARE_RANGE = 0x40; | 3409 | pub const FL_UNSHARE_RANGE = 0x40; |
| 3386 | }; | 3410 | }; |
| 3387 | | 3411 | |
| 3388 | pub const FUTEX = struct { | 3412 | // Futex v1 API commands. See futex man page for each command's |
| 3389 | pub const WAIT = 0; | 3413 | // interpretation of the futex arguments. |
| 3390 | pub const WAKE = 1; | 3414 | pub const FUTEX_COMMAND = enum(u7) { |
| 3391 | pub const FD = 2; | 3415 | WAIT = 0, |
| 3392 | pub const REQUEUE = 3; | 3416 | WAKE = 1, |
| 3393 | pub const CMP_REQUEUE = 4; | 3417 | FD = 2, |
| 3394 | pub const WAKE_OP = 5; | 3418 | REQUEUE = 3, |
| 3395 | pub const LOCK_PI = 6; | 3419 | CMP_REQUEUE = 4, |
| 3396 | pub const UNLOCK_PI = 7; | 3420 | WAKE_OP = 5, |
| 3397 | pub const TRYLOCK_PI = 8; | 3421 | LOCK_PI = 6, |
| 3398 | pub const WAIT_BITSET = 9; | 3422 | UNLOCK_PI = 7, |
| 3399 | pub const WAKE_BITSET = 10; | 3423 | TRYLOCK_PI = 8, |
| 3400 | pub const WAIT_REQUEUE_PI = 11; | 3424 | WAIT_BITSET = 9, |
| 3401 | pub const CMP_REQUEUE_PI = 12; | 3425 | WAKE_BITSET = 10, |
| 3402 | | 3426 | WAIT_REQUEUE_PI = 11, |
| 3403 | pub const PRIVATE_FLAG = 128; | 3427 | CMP_REQUEUE_PI = 12, |
| 3404 | | 3428 | }; |
| 3405 | pub const CLOCK_REALTIME = 256; | 3429 | |
| 3406 | | 3430 | /// Futex v1 API command and flags for the `futex_op` parameter |
| 3407 | /// Max numbers of elements in a `futex_waitv` array. | 3431 | pub const FUTEX_OP = packed struct(u32) { |
| 3408 | pub const WAITV_MAX = 128; | 3432 | cmd: FUTEX_COMMAND, |
| 3409 | }; | 3433 | private: bool, |
| 3410 | | 3434 | realtime: bool = false, // realtime clock vs. monotonic clock |
| 3411 | pub const FUTEX2 = struct { | 3435 | _reserved: u23 = 0, |
| 3412 | pub const SIZE_U8 = 0x00; | 3436 | }; |
| 3413 | pub const SIZE_U16 = 0x01; | 3437 | |
| 3414 | pub const SIZE_U32 = 0x02; | 3438 | /// Futex v1 FUTEX_WAKE_OP `val3` operation: |
| 3415 | pub const SIZE_U64 = 0x03; | 3439 | pub const FUTEX_WAKE_OP = packed struct(u32) { |
| 3416 | pub const NUMA = 0x04; | 3440 | cmd: FUTEX_WAKE_OP_CMD, |
| 3417 | | 3441 | /// From C API `FUTEX_OP_ARG_SHIFT`: Use (1 << oparg) as operand |
| 3418 | pub const PRIVATE = FUTEX.PRIVATE_FLAG; | 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 | pub const PROT = struct { | 3505 | pub const PROT = struct { |
| ... | @@ -9281,17 +9365,17 @@ pub const PTRACE = struct { | ... | @@ -9281,17 +9365,17 @@ pub const PTRACE = struct { |
| 9281 | pub const GET_SYSCALL_INFO = 0x420e; | 9365 | pub const GET_SYSCALL_INFO = 0x420e; |
| 9282 | }; | 9366 | }; |
| 9283 | | 9367 | |
| 9284 | /// A waiter for vectorized wait. | 9368 | /// For futex2_waitv and futex2_requeue. Arrays of `futex2_waitone` allow |
| 9285 | pub const futex_waitv = extern struct { | 9369 | /// waiting on multiple futexes in one call. |
| 9286 | // Expected value at uaddr | 9370 | pub const futex2_waitone = extern struct { |
| | 9371 | /// Expected value at uaddr, should match size of futex. |
| 9287 | val: u64, | 9372 | val: u64, |
| 9288 | /// User address to wait on. | 9373 | /// User address to wait on. Top-bits must be 0 on 32-bit. |
| 9289 | uaddr: u64, | 9374 | uaddr: u64, |
| 9290 | /// Flags for this waiter. | 9375 | /// Flags for this waiter. |
| 9291 | flags: u32, | 9376 | flags: FUTEX2_FLAGS, |
| 9292 | /// Reserved member to preserve alignment. | 9377 | /// Reserved member to preserve alignment. |
| 9293 | /// Should be 0. | 9378 | __reserved: u32 = 0, |
| 9294 | __reserved: u32, | | |
| 9295 | }; | 9379 | }; |
| 9296 | | 9380 | |
| 9297 | pub const cache_stat_range = extern struct { | 9381 | pub const cache_stat_range = extern struct { |