@@ -3,8 +3,10 @@ use std::str;
3
3
4
4
use rustc_middle:: ty:: layout:: LayoutOf ;
5
5
use rustc_span:: Symbol ;
6
+ use rustc_target:: abi:: Size ;
6
7
use rustc_target:: spec:: abi:: Abi ;
7
8
9
+ use crate :: concurrency:: cpu_affinity:: CpuAffinityMask ;
8
10
use crate :: shims:: alloc:: EvalContextExt as _;
9
11
use crate :: shims:: unix:: * ;
10
12
use crate :: * ;
@@ -571,6 +573,101 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
571
573
let result = this. nanosleep ( req, rem) ?;
572
574
this. write_scalar ( Scalar :: from_i32 ( result) , dest) ?;
573
575
}
576
+ "sched_getaffinity" => {
577
+ // Currently this function does not exist on all Unixes, e.g. on macOS.
578
+ if !matches ! ( & * this. tcx. sess. target. os, "linux" | "freebsd" | "android" ) {
579
+ throw_unsup_format ! (
580
+ "`sched_getaffinity` is not supported on {}" ,
581
+ this. tcx. sess. target. os
582
+ ) ;
583
+ }
584
+
585
+ let [ pid, cpusetsize, mask] =
586
+ this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
587
+ let pid = this. read_scalar ( pid) ?. to_u32 ( ) ?;
588
+ let cpusetsize = this. read_target_usize ( cpusetsize) ?;
589
+ let mask = this. read_pointer ( mask) ?;
590
+
591
+ // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
592
+ let thread_id = match pid {
593
+ 0 => this. active_thread ( ) ,
594
+ _ => throw_unsup_format ! ( "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)" ) ,
595
+ } ;
596
+
597
+ // The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
598
+ //
599
+ // - [u32; 32] on 32-bit platforms
600
+ // - [u64; 16] everywhere else
601
+ let chunk_size = CpuAffinityMask :: chunk_size ( & this. tcx . sess . target ) ;
602
+
603
+ if this. ptr_is_null ( mask) ? {
604
+ let einval = this. eval_libc ( "EFAULT" ) ;
605
+ this. set_last_error ( einval) ?;
606
+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , dest) ?;
607
+ } else if cpusetsize == 0 || cpusetsize. checked_rem ( chunk_size) . unwrap ( ) != 0 {
608
+ // we only copy whole chunks of size_of::<c_ulong>()
609
+ let einval = this. eval_libc ( "EINVAL" ) ;
610
+ this. set_last_error ( einval) ?;
611
+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , dest) ?;
612
+ } else if let Some ( cpuset) = this. machine . thread_cpu_affinity . get ( & thread_id) {
613
+ let cpuset = cpuset. clone ( ) ;
614
+ // we only copy whole chunks of size_of::<c_ulong>()
615
+ let byte_count = Ord :: min ( cpuset. as_slice ( ) . len ( ) , cpusetsize. try_into ( ) . unwrap ( ) ) ;
616
+ this. write_bytes_ptr ( mask, cpuset. as_slice ( ) [ ..byte_count] . iter ( ) . copied ( ) ) ?;
617
+ this. write_scalar ( Scalar :: from_i32 ( 0 ) , dest) ?;
618
+ } else {
619
+ // The thread whose ID is pid could not be found
620
+ let einval = this. eval_libc ( "ESRCH" ) ;
621
+ this. set_last_error ( einval) ?;
622
+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , dest) ?;
623
+ }
624
+ }
625
+ "sched_setaffinity" => {
626
+ // Currently this function does not exist on all Unixes, e.g. on macOS.
627
+ if !matches ! ( & * this. tcx. sess. target. os, "linux" | "freebsd" | "android" ) {
628
+ throw_unsup_format ! (
629
+ "`sched_setaffinity` is not supported on {}" ,
630
+ this. tcx. sess. target. os
631
+ ) ;
632
+ }
633
+
634
+ let [ pid, cpusetsize, mask] =
635
+ this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
636
+ let pid = this. read_scalar ( pid) ?. to_u32 ( ) ?;
637
+ let cpusetsize = this. read_target_usize ( cpusetsize) ?;
638
+ let mask = this. read_pointer ( mask) ?;
639
+
640
+ // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
641
+ let thread_id = match pid {
642
+ 0 => this. active_thread ( ) ,
643
+ _ => throw_unsup_format ! ( "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)" ) ,
644
+ } ;
645
+
646
+ #[ allow( clippy:: map_entry) ]
647
+ if this. ptr_is_null ( mask) ? {
648
+ let einval = this. eval_libc ( "EFAULT" ) ;
649
+ this. set_last_error ( einval) ?;
650
+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , dest) ?;
651
+ } else {
652
+ // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`
653
+ let bits_slice = this. read_bytes_ptr_strip_provenance ( mask, Size :: from_bytes ( cpusetsize) ) ?;
654
+ // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
655
+ let bits_array: [ u8 ; CpuAffinityMask :: CPU_MASK_BYTES ] =
656
+ std:: array:: from_fn ( |i| bits_slice. get ( i) . copied ( ) . unwrap_or ( 0 ) ) ;
657
+ match CpuAffinityMask :: from_array ( & this. tcx . sess . target , this. machine . num_cpus , bits_array) {
658
+ Some ( cpuset) => {
659
+ this. machine . thread_cpu_affinity . insert ( thread_id, cpuset) ;
660
+ this. write_scalar ( Scalar :: from_i32 ( 0 ) , dest) ?;
661
+ }
662
+ None => {
663
+ // The intersection between the mask and the available CPUs was empty.
664
+ let einval = this. eval_libc ( "EINVAL" ) ;
665
+ this. set_last_error ( einval) ?;
666
+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , dest) ?;
667
+ }
668
+ }
669
+ }
670
+ }
574
671
575
672
// Miscellaneous
576
673
"isatty" => {
0 commit comments