@@ -673,66 +673,87 @@ 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
696
716
/// have been woken by the same event, and if more than one futex was woken,
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 {
0 commit comments