@@ -8,12 +8,14 @@ use crate::thread::{NanosleepRelativeResult, Timespec};
8
8
#[ cfg( all( target_env = "gnu" , fix_y2038) ) ]
9
9
use crate :: timespec:: LibcTimespec ;
10
10
use core:: mem:: MaybeUninit ;
11
+ use core:: sync:: atomic:: AtomicU32 ;
11
12
#[ cfg( linux_kernel) ]
12
13
use {
14
+ super :: futex:: FutexOperation ,
13
15
crate :: backend:: conv:: { borrowed_fd, ret_c_int, ret_usize} ,
14
16
crate :: fd:: BorrowedFd ,
15
17
crate :: pid:: Pid ,
16
- crate :: thread:: { FutexFlags , FutexOperation } ,
18
+ crate :: thread:: FutexFlags ,
17
19
crate :: utils:: as_mut_ptr,
18
20
} ;
19
21
#[ cfg( not( any(
@@ -415,15 +417,87 @@ pub(crate) fn setresgid_thread(
415
417
unsafe { ret ( setresgid ( rgid. as_raw ( ) , egid. as_raw ( ) , sgid. as_raw ( ) ) ) }
416
418
}
417
419
418
- // TODO: This could be de-multiplexed.
419
420
#[ cfg( linux_kernel) ]
420
- pub ( crate ) unsafe fn futex (
421
- uaddr : * mut u32 ,
421
+ pub ( crate ) unsafe fn futex_val2 (
422
+ uaddr : * const AtomicU32 ,
422
423
op : FutexOperation ,
423
424
flags : FutexFlags ,
424
425
val : u32 ,
425
- utime : * const Timespec ,
426
- uaddr2 : * mut u32 ,
426
+ val2 : u32 ,
427
+ uaddr2 : * const AtomicU32 ,
428
+ val3 : u32 ,
429
+ ) -> io:: Result < usize > {
430
+ // the least significant four bytes of the timeout pointer are used as `val2`.
431
+ // ["the kernel casts the timeout value first to unsigned long, then to uint32_t"](https://man7.org/linux/man-pages/man2/futex.2.html),
432
+ // so we perform that exact conversion in reverse to create the pointer.
433
+ let timeout = val2 as usize as * const Timespec ;
434
+
435
+ #[ cfg( all(
436
+ target_pointer_width = "32" ,
437
+ not( any( target_arch = "aarch64" , target_arch = "x86_64" ) )
438
+ ) ) ]
439
+ {
440
+ // TODO: Upstream this to the libc crate.
441
+ #[ allow( non_upper_case_globals) ]
442
+ const SYS_futex_time64 : i32 = linux_raw_sys:: general:: __NR_futex_time64 as i32 ;
443
+
444
+ syscall ! {
445
+ fn futex_time64(
446
+ uaddr: * const AtomicU32 ,
447
+ futex_op: c:: c_int,
448
+ val: u32 ,
449
+ timeout: * const Timespec ,
450
+ uaddr2: * const AtomicU32 ,
451
+ val3: u32
452
+ ) via SYS_futex_time64 -> c:: ssize_t
453
+ }
454
+
455
+ ret_usize ( futex_time64 (
456
+ uaddr,
457
+ op as i32 | flags. bits ( ) as i32 ,
458
+ val,
459
+ timeout,
460
+ uaddr2,
461
+ val3,
462
+ ) )
463
+ }
464
+
465
+ #[ cfg( any(
466
+ target_pointer_width = "64" ,
467
+ target_arch = "aarch64" ,
468
+ target_arch = "x86_64"
469
+ ) ) ]
470
+ {
471
+ syscall ! {
472
+ fn futex(
473
+ uaddr: * const AtomicU32 ,
474
+ futex_op: c:: c_int,
475
+ val: u32 ,
476
+ timeout: * const linux_raw_sys:: general:: __kernel_timespec,
477
+ uaddr2: * const AtomicU32 ,
478
+ val3: u32
479
+ ) via SYS_futex -> c:: c_long
480
+ }
481
+
482
+ ret_usize ( futex (
483
+ uaddr,
484
+ op as i32 | flags. bits ( ) as i32 ,
485
+ val,
486
+ timeout. cast ( ) ,
487
+ uaddr2,
488
+ val3,
489
+ ) as isize )
490
+ }
491
+ }
492
+
493
+ #[ cfg( linux_kernel) ]
494
+ pub ( crate ) unsafe fn futex_timeout (
495
+ uaddr : * const AtomicU32 ,
496
+ op : FutexOperation ,
497
+ flags : FutexFlags ,
498
+ val : u32 ,
499
+ timeout : * const Timespec ,
500
+ uaddr2 : * const AtomicU32 ,
427
501
val3 : u32 ,
428
502
) -> io:: Result < usize > {
429
503
#[ cfg( all(
@@ -437,11 +511,11 @@ pub(crate) unsafe fn futex(
437
511
438
512
syscall ! {
439
513
fn futex_time64(
440
- uaddr: * mut u32 ,
514
+ uaddr: * const AtomicU32 ,
441
515
futex_op: c:: c_int,
442
516
val: u32 ,
443
517
timeout: * const Timespec ,
444
- uaddr2: * mut u32 ,
518
+ uaddr2: * const AtomicU32 ,
445
519
val3: u32
446
520
) via SYS_futex_time64 -> c:: ssize_t
447
521
}
@@ -450,15 +524,15 @@ pub(crate) unsafe fn futex(
450
524
uaddr,
451
525
op as i32 | flags. bits ( ) as i32 ,
452
526
val,
453
- utime ,
527
+ timeout ,
454
528
uaddr2,
455
529
val3,
456
530
) )
457
531
. or_else ( |err| {
458
532
// See the comments in `rustix_clock_gettime_via_syscall` about
459
533
// emulation.
460
534
if err == io:: Errno :: NOSYS {
461
- futex_old ( uaddr, op, flags, val, utime , uaddr2, val3)
535
+ futex_old_timespec ( uaddr, op, flags, val, timeout , uaddr2, val3)
462
536
} else {
463
537
Err ( err)
464
538
}
@@ -473,11 +547,11 @@ pub(crate) unsafe fn futex(
473
547
{
474
548
syscall ! {
475
549
fn futex(
476
- uaddr: * mut u32 ,
550
+ uaddr: * const AtomicU32 ,
477
551
futex_op: c:: c_int,
478
552
val: u32 ,
479
553
timeout: * const linux_raw_sys:: general:: __kernel_timespec,
480
- uaddr2: * mut u32 ,
554
+ uaddr2: * const AtomicU32 ,
481
555
val3: u32
482
556
) via SYS_futex -> c:: c_long
483
557
}
@@ -486,7 +560,7 @@ pub(crate) unsafe fn futex(
486
560
uaddr,
487
561
op as i32 | flags. bits ( ) as i32 ,
488
562
val,
489
- utime . cast ( ) ,
563
+ timeout . cast ( ) ,
490
564
uaddr2,
491
565
val3,
492
566
) as isize )
@@ -498,35 +572,45 @@ pub(crate) unsafe fn futex(
498
572
target_pointer_width = "32" ,
499
573
not( any( target_arch = "aarch64" , target_arch = "x86_64" ) )
500
574
) ) ]
501
- unsafe fn futex_old (
502
- uaddr : * mut u32 ,
575
+ unsafe fn futex_old_timespec (
576
+ uaddr : * const AtomicU32 ,
503
577
op : FutexOperation ,
504
578
flags : FutexFlags ,
505
579
val : u32 ,
506
- utime : * const Timespec ,
507
- uaddr2 : * mut u32 ,
580
+ timeout : * const Timespec ,
581
+ uaddr2 : * const AtomicU32 ,
508
582
val3 : u32 ,
509
583
) -> io:: Result < usize > {
510
584
syscall ! {
511
585
fn futex(
512
- uaddr: * mut u32 ,
586
+ uaddr: * const AtomicU32 ,
513
587
futex_op: c:: c_int,
514
588
val: u32 ,
515
589
timeout: * const linux_raw_sys:: general:: __kernel_old_timespec,
516
- uaddr2: * mut u32 ,
590
+ uaddr2: * const AtomicU32 ,
517
591
val3: u32
518
592
) via SYS_futex -> c:: c_long
519
593
}
520
594
521
- let old_utime = linux_raw_sys:: general:: __kernel_old_timespec {
522
- tv_sec : ( * utime) . tv_sec . try_into ( ) . map_err ( |_| io:: Errno :: INVAL ) ?,
523
- tv_nsec : ( * utime) . tv_nsec . try_into ( ) . map_err ( |_| io:: Errno :: INVAL ) ?,
595
+ let old_timeout = if timeout. is_null ( ) {
596
+ None
597
+ } else {
598
+ Some ( linux_raw_sys:: general:: __kernel_old_timespec {
599
+ tv_sec : ( * timeout) . tv_sec . try_into ( ) . map_err ( |_| io:: Errno :: INVAL ) ?,
600
+ tv_nsec : ( * timeout)
601
+ . tv_nsec
602
+ . try_into ( )
603
+ . map_err ( |_| io:: Errno :: INVAL ) ?,
604
+ } )
524
605
} ;
525
606
ret_usize ( futex (
526
607
uaddr,
527
608
op as i32 | flags. bits ( ) as i32 ,
528
609
val,
529
- & old_utime,
610
+ old_timeout
611
+ . as_ref ( )
612
+ . map ( |timeout| timeout as * const linux_raw_sys:: general:: __kernel_old_timespec )
613
+ . unwrap_or ( core:: ptr:: null ( ) ) ,
530
614
uaddr2,
531
615
val3,
532
616
) as isize )
0 commit comments