From 928002830024b55181686f60751427e9a37edc5e Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Sun, 6 Feb 2022 20:22:57 -0800 Subject: [PATCH 1/5] Support std threads again by using pthread Priority and affinity are passed through special pthread attr functions which will be added to our libc fork. The current thread's priority also needs to be fetched since it is the default priority value. This is done using another new pthread function, though this value/mechanism isn't exposed as part of std's API. --- library/std/src/sys/unix/thread.rs | 23 +++++++- library/std/src/thread/mod.rs | 85 ++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index d191e1fe7a650..24eb46f558ef7 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -48,7 +48,12 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) -> io::Result { + pub unsafe fn new( + stack: usize, + p: Box, + #[cfg(target_os = "horizon")] priority: i32, + #[cfg(target_os = "horizon")] affinity: i32, + ) -> io::Result { let p = Box::into_raw(box p); let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); @@ -84,6 +89,13 @@ impl Thread { }; } + #[cfg(target_os = "horizon")] + { + // Set the priority and affinity values + assert_eq!(libc::pthread_attr_setpriority(&mut attr, priority), 0); + assert_eq!(libc::pthread_attr_setaffinity(&mut attr, affinity), 0); + } + let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); // Note: if the thread creation fails and this assert fails, then p will // be leaked. However, an alternative design could cause double-free @@ -200,7 +212,8 @@ impl Thread { target_os = "l4re", target_os = "emscripten", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "horizon" ))] pub fn set_name(_name: &CStr) { // Newlib, Emscripten, and VxWorks have no way to set a thread name. @@ -271,6 +284,12 @@ impl Drop for Thread { } } +/// Returns the current thread's priority value. +#[cfg(target_os = "horizon")] +pub(crate) fn current_priority() -> i32 { + unsafe { libc::pthread_getpriority() } +} + pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0a6a7cfe976cc..acaca85c08ccd 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -267,6 +267,12 @@ pub struct Builder { name: Option, // The size of the stack for the spawned thread in bytes stack_size: Option, + // The spawned thread's priority value + #[cfg(target_os = "horizon")] + priority: Option, + // The spawned thread's CPU affinity value + #[cfg(target_os = "horizon")] + affinity: Option, } impl Builder { @@ -290,7 +296,14 @@ impl Builder { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { - Builder { name: None, stack_size: None } + Builder { + name: None, + stack_size: None, + #[cfg(target_os = "horizon")] + priority: None, + #[cfg(target_os = "horizon")] + affinity: None, + } } /// Names the thread-to-be. Currently the name is used for identification @@ -346,6 +359,58 @@ impl Builder { self } + /// **armv6k-nintendo-3ds specific!** + /// + /// Sets the priority level for the new thread. + /// + /// Low values gives the thread higher priority. For userland apps, this has + /// to be within the range of 0x18 to 0x3F inclusive. The main thread usually + /// has a priority of 0x30, but not always. + /// + /// # Examples + /// ``` + /// use std::thread; + /// + /// let builder = thread::Builder::new().priority(0x30); + /// ``` + #[cfg(target_os = "horizon")] + #[unstable(feature = "horizon_thread_ext", issue = "none")] + pub fn priority(mut self, priority: i32) -> Builder { + self.priority = Some(priority); + self + } + + /// **armv6k-nintendo-3ds specific!** + /// + /// Sets the ID of the processor the thread should be run on. + /// + /// Processor IDs are labeled starting from 0. On Old3DS it must be <2, and + /// on New3DS it must be <4. Pass -1 to execute the thread on all CPUs and + /// -2 to execute the thread on the default CPU (set in the application's Exheader). + /// + /// *Processor #0 is the application core. It is always possible to create a thread on this + /// core. + /// *Processor #1 is the system core. If the CPU time limit is set, it is possible + /// to create a single thread on this core. + /// *Processor #2 is New3DS exclusive. Normal applications can create threads on + /// this core if the exheader kernel flags bitmask has 0x2000 set. + /// *Processor #3 is New3DS exclusive. Normal applications cannot create threads + /// on this core. + /// + /// # Examples + /// ``` + /// use std::thread; + /// + /// // Spawn on the application core + /// let builder = thread::Builder::new().affinity(0); + /// ``` + #[cfg(target_os = "horizon")] + #[unstable(feature = "horizon_thread_ext", issue = "none")] + pub fn affinity(mut self, affinity: i32) -> Builder { + self.affinity = Some(affinity); + self + } + /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -470,11 +535,19 @@ impl Builder { T: Send + 'a, 'scope: 'a, { - let Builder { name, stack_size } = self; + let stack_size = self.stack_size.unwrap_or_else(thread::min_stack); + + // If no priority value is specified, spawn with the same + // priority as the parent thread + #[cfg(target_os = "horizon")] + let priority = self.priority.unwrap_or_else(imp::current_priority); - let stack_size = stack_size.unwrap_or_else(thread::min_stack); + // If no affinity is specified, spawn on the default core (determined by + // the application's Exheader) + #[cfg(target_os = "horizon")] + let affinity = self.affinity.unwrap_or(-2); - let my_thread = Thread::new(name.map(|name| { + let my_thread = Thread::new(self.name.map(|name| { CString::new(name).expect("thread name may not contain interior null bytes") })); let their_thread = my_thread.clone(); @@ -531,6 +604,10 @@ impl Builder { mem::transmute::, Box>( Box::new(main), ), + #[cfg(target_os = "horizon")] + priority, + #[cfg(target_os = "horizon")] + affinity, )? }, thread: my_thread, From fe1cdcf80d4243a8a34930e99ee04ca64e4c555d Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Thu, 10 Feb 2022 21:12:10 -0800 Subject: [PATCH 2/5] Add "native options" concept to thread builder and make std::os::horizon::thread Also renamed "affinity" to "processor_id". --- library/std/src/os/horizon/mod.rs | 1 + library/std/src/os/horizon/thread.rs | 77 ++++++++++++++++++++ library/std/src/sys/hermit/thread.rs | 9 ++- library/std/src/sys/itron/thread.rs | 9 ++- library/std/src/sys/sgx/thread.rs | 9 ++- library/std/src/sys/unix/thread.rs | 42 ++++++++--- library/std/src/sys/unsupported/thread.rs | 9 ++- library/std/src/sys/wasi/thread.rs | 9 ++- library/std/src/sys/wasm/atomics/thread.rs | 9 ++- library/std/src/sys/windows/thread.rs | 9 ++- library/std/src/thread/mod.rs | 85 ++-------------------- 11 files changed, 172 insertions(+), 96 deletions(-) create mode 100644 library/std/src/os/horizon/thread.rs diff --git a/library/std/src/os/horizon/mod.rs b/library/std/src/os/horizon/mod.rs index 326d0ae9cb96d..c2182facb0658 100644 --- a/library/std/src/os/horizon/mod.rs +++ b/library/std/src/os/horizon/mod.rs @@ -4,3 +4,4 @@ pub mod fs; pub(crate) mod raw; +pub mod thread; diff --git a/library/std/src/os/horizon/thread.rs b/library/std/src/os/horizon/thread.rs new file mode 100644 index 0000000000000..faaa163e154c5 --- /dev/null +++ b/library/std/src/os/horizon/thread.rs @@ -0,0 +1,77 @@ +//! Nintendo 3DS-specific extensions to primitives in the [`std::thread`] module. +//! +//! All 3DS models have at least two CPU cores available to spawn threads on: +//! The application core (appcore) and the system core (syscore). The New 3DS +//! has an additional two cores, the first of which can also run user-created +//! threads. +//! +//! Threads spawned on the appcore are cooperative rather than preemptive. This +//! means that threads must explicitly yield control to other threads (whether +//! via synchronization primitives or explicit calls to `yield_now`) when they +//! are not actively performing work. Failure to do so may result in control +//! flow being stuck in an inactive thread while the other threads are powerless +//! to continue their work. +//! +//! However, it is possible to spawn one fully preemptive thread on the syscore +//! by using a service call to reserve a slice of time for a thread to run. +//! Attempting to run more than one thread at a time on the syscore will result +//! in an error. +//! +//! [`std::thread`]: crate::thread + +#![unstable(feature = "horizon_thread_ext", issue = "none")] + +/// Extensions on [`std::thread::Builder`] for the Nintendo 3DS. +/// +/// [`std::thread::Builder`]: crate::thread::Builder +pub trait BuilderExt: Sized { + /// Sets the priority level for the new thread. + /// + /// Low values gives the thread higher priority. For userland apps, this has + /// to be within the range of 0x18 to 0x3F inclusive. The main thread + /// usually has a priority of 0x30, but not always. + fn priority(self, priority: i32) -> Self; + + /// Sets the ID of the processor the thread should be run on. Threads on the 3DS are only + /// preemptive if they are on the system core. Otherwise they are cooperative (must yield to let + /// other threads run). + /// + /// Processor IDs are labeled starting from 0. On Old3DS it must be <2, and + /// on New3DS it must be <4. Pass -1 to execute the thread on all CPUs and + /// -2 to execute the thread on the default CPU (set in the application's Exheader). + /// + /// * Processor #0 is the application core. It is always possible to create + /// a thread on this core. + /// * Processor #1 is the system core. If the CPU time limit is set, it is + /// possible to create a single thread on this core. + /// * Processor #2 is New3DS exclusive. Normal applications can create + /// threads on this core only if the built application has proper external setup. + /// * Processor #3 is New3DS exclusive. Normal applications cannot create + /// threads on this core. + fn processor_id(self, processor_id: i32) -> Self; +} + +impl BuilderExt for crate::thread::Builder { + fn priority(mut self, priority: i32) -> Self { + self.native_options.priority = Some(priority); + self + } + + fn processor_id(mut self, processor_id: i32) -> Self { + self.native_options.processor_id = Some(processor_id); + self + } +} + +/// Get the current thread's priority level. Lower values correspond to higher +/// priority levels. +pub fn current_priority() -> i32 { + let thread_id = unsafe { libc::pthread_self() }; + let mut policy = 0; + let mut sched_param = libc::sched_param { sched_priority: 0 }; + + let result = unsafe { libc::pthread_getschedparam(thread_id, &mut policy, &mut sched_param) }; + assert_eq!(result, 0); + + sched_param.sched_priority +} diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index e53a1fea6a0dc..7b95b2d3472d7 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -55,7 +55,11 @@ impl Thread { } } - pub unsafe fn new(stack: usize, p: Box) -> io::Result { + pub unsafe fn new( + stack: usize, + p: Box, + _native_options: BuilderOptions, + ) -> io::Result { Thread::new_with_coreid(stack, p, -1 /* = no specific core */) } @@ -97,6 +101,9 @@ impl Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index d28f57f33be20..d1c0f50f6b6a3 100644 --- a/library/std/src/sys/itron/thread.rs +++ b/library/std/src/sys/itron/thread.rs @@ -83,7 +83,11 @@ impl Thread { /// # Safety /// /// See `thread::Builder::spawn_unchecked` for safety requirements. - pub unsafe fn new(stack: usize, p: Box) -> io::Result { + pub unsafe fn new( + stack: usize, + p: Box, + _native_options: BuilderOptions, + ) -> io::Result { let inner = Box::new(ThreadInner { start: UnsafeCell::new(ManuallyDrop::new(p)), lifecycle: AtomicUsize::new(LIFECYCLE_INIT), @@ -288,6 +292,9 @@ impl Drop for Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index d745a61961404..7cc017d784daa 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -104,7 +104,11 @@ pub mod wait_notify { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box) -> io::Result { + pub unsafe fn new( + _stack: usize, + p: Box, + _native_options: BuilderOptions, + ) -> io::Result { let mut queue_lock = task_queue::lock(); unsafe { usercalls::launch_thread()? }; let (task, handle) = task_queue::Task::new(p); @@ -137,6 +141,9 @@ impl Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 24eb46f558ef7..f37aa8c437826 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -51,8 +51,7 @@ impl Thread { pub unsafe fn new( stack: usize, p: Box, - #[cfg(target_os = "horizon")] priority: i32, - #[cfg(target_os = "horizon")] affinity: i32, + #[allow(unused)] native_options: BuilderOptions, ) -> io::Result { let p = Box::into_raw(box p); let mut native: libc::pthread_t = mem::zeroed(); @@ -91,9 +90,19 @@ impl Thread { #[cfg(target_os = "horizon")] { - // Set the priority and affinity values - assert_eq!(libc::pthread_attr_setpriority(&mut attr, priority), 0); - assert_eq!(libc::pthread_attr_setaffinity(&mut attr, affinity), 0); + // If no priority value is specified, spawn with the same priority + // as the parent thread. + let priority = native_options + .priority + .unwrap_or_else(crate::os::horizon::thread::current_priority); + let sched_param = libc::sched_param { sched_priority: priority }; + + // If no processor is specified, spawn on the default core. + // (determined by the application's Exheader) + let processor_id = native_options.processor_id.unwrap_or(-2); + + assert_eq!(libc::pthread_attr_setschedparam(&mut attr, &sched_param), 0); + assert_eq!(libc::pthread_attr_setprocessorid_np(&mut attr, processor_id), 0); } let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); @@ -284,10 +293,25 @@ impl Drop for Thread { } } -/// Returns the current thread's priority value. -#[cfg(target_os = "horizon")] -pub(crate) fn current_priority() -> i32 { - unsafe { libc::pthread_getpriority() } +#[derive(Debug)] +pub struct BuilderOptions { + /// The spawned thread's priority value + #[cfg(target_os = "horizon")] + pub(crate) priority: Option, + /// The processor to spawn the thread on. See [`os::horizon::thread::BuilderExt`]. + #[cfg(target_os = "horizon")] + pub(crate) processor_id: Option, +} + +impl Default for BuilderOptions { + fn default() -> Self { + BuilderOptions { + #[cfg(target_os = "horizon")] + priority: None, + #[cfg(target_os = "horizon")] + processor_id: None, + } + } } pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs index a8db251de2017..aaf56340c2992 100644 --- a/library/std/src/sys/unsupported/thread.rs +++ b/library/std/src/sys/unsupported/thread.rs @@ -10,7 +10,11 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { + pub unsafe fn new( + _stack: usize, + _p: Box, + _native_options: BuilderOptions, + ) -> io::Result { unsupported() } @@ -31,6 +35,9 @@ impl Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index e7a6ab4be826f..22dfe61362862 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -13,7 +13,11 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { + pub unsafe fn new( + _stack: usize, + _p: Box, + _native_options: BuilderOptions, + ) -> io::Result { unsupported() } @@ -66,6 +70,9 @@ impl Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index 714b704922794..dd90edf374ea0 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -10,7 +10,11 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { + pub unsafe fn new( + _stack: usize, + _p: Box, + _native_options: BuilderOptions, + ) -> io::Result { unsupported() } @@ -40,6 +44,9 @@ impl Thread { pub fn join(self) {} } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index c5c9e97e646fb..bcc032767feb2 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -21,7 +21,11 @@ pub struct Thread { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) -> io::Result { + pub unsafe fn new( + stack: usize, + p: Box, + _native_options: BuilderOptions, + ) -> io::Result { let p = Box::into_raw(box p); // FIXME On UNIX, we guard against stack sizes that are too small but @@ -98,6 +102,9 @@ impl Thread { } } +#[derive(Debug)] +pub struct BuilderOptions; + pub fn available_parallelism() -> io::Result { let res = unsafe { let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index acaca85c08ccd..64a7b197532af 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -267,12 +267,9 @@ pub struct Builder { name: Option, // The size of the stack for the spawned thread in bytes stack_size: Option, - // The spawned thread's priority value - #[cfg(target_os = "horizon")] - priority: Option, - // The spawned thread's CPU affinity value - #[cfg(target_os = "horizon")] - affinity: Option, + // Other OS-specific fields. These can be set via extension traits, usually + // found in std::os. + pub(crate) native_options: imp::BuilderOptions, } impl Builder { @@ -296,14 +293,7 @@ impl Builder { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { - Builder { - name: None, - stack_size: None, - #[cfg(target_os = "horizon")] - priority: None, - #[cfg(target_os = "horizon")] - affinity: None, - } + Builder { name: None, stack_size: None, native_options: imp::BuilderOptions::default() } } /// Names the thread-to-be. Currently the name is used for identification @@ -359,58 +349,6 @@ impl Builder { self } - /// **armv6k-nintendo-3ds specific!** - /// - /// Sets the priority level for the new thread. - /// - /// Low values gives the thread higher priority. For userland apps, this has - /// to be within the range of 0x18 to 0x3F inclusive. The main thread usually - /// has a priority of 0x30, but not always. - /// - /// # Examples - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new().priority(0x30); - /// ``` - #[cfg(target_os = "horizon")] - #[unstable(feature = "horizon_thread_ext", issue = "none")] - pub fn priority(mut self, priority: i32) -> Builder { - self.priority = Some(priority); - self - } - - /// **armv6k-nintendo-3ds specific!** - /// - /// Sets the ID of the processor the thread should be run on. - /// - /// Processor IDs are labeled starting from 0. On Old3DS it must be <2, and - /// on New3DS it must be <4. Pass -1 to execute the thread on all CPUs and - /// -2 to execute the thread on the default CPU (set in the application's Exheader). - /// - /// *Processor #0 is the application core. It is always possible to create a thread on this - /// core. - /// *Processor #1 is the system core. If the CPU time limit is set, it is possible - /// to create a single thread on this core. - /// *Processor #2 is New3DS exclusive. Normal applications can create threads on - /// this core if the exheader kernel flags bitmask has 0x2000 set. - /// *Processor #3 is New3DS exclusive. Normal applications cannot create threads - /// on this core. - /// - /// # Examples - /// ``` - /// use std::thread; - /// - /// // Spawn on the application core - /// let builder = thread::Builder::new().affinity(0); - /// ``` - #[cfg(target_os = "horizon")] - #[unstable(feature = "horizon_thread_ext", issue = "none")] - pub fn affinity(mut self, affinity: i32) -> Builder { - self.affinity = Some(affinity); - self - } - /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -537,16 +475,6 @@ impl Builder { { let stack_size = self.stack_size.unwrap_or_else(thread::min_stack); - // If no priority value is specified, spawn with the same - // priority as the parent thread - #[cfg(target_os = "horizon")] - let priority = self.priority.unwrap_or_else(imp::current_priority); - - // If no affinity is specified, spawn on the default core (determined by - // the application's Exheader) - #[cfg(target_os = "horizon")] - let affinity = self.affinity.unwrap_or(-2); - let my_thread = Thread::new(self.name.map(|name| { CString::new(name).expect("thread name may not contain interior null bytes") })); @@ -604,10 +532,7 @@ impl Builder { mem::transmute::, Box>( Box::new(main), ), - #[cfg(target_os = "horizon")] - priority, - #[cfg(target_os = "horizon")] - affinity, + self.native_options, )? }, thread: my_thread, From 1fb2f72a7e425b63c1f4a8a86114fe4690d90b81 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Sun, 13 Feb 2022 18:43:31 -0800 Subject: [PATCH 3/5] Add std::os::horizon::thread::current_processor --- library/std/src/os/horizon/thread.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/library/std/src/os/horizon/thread.rs b/library/std/src/os/horizon/thread.rs index faaa163e154c5..479b7073c6b76 100644 --- a/library/std/src/os/horizon/thread.rs +++ b/library/std/src/os/horizon/thread.rs @@ -32,13 +32,14 @@ pub trait BuilderExt: Sized { /// usually has a priority of 0x30, but not always. fn priority(self, priority: i32) -> Self; - /// Sets the ID of the processor the thread should be run on. Threads on the 3DS are only - /// preemptive if they are on the system core. Otherwise they are cooperative (must yield to let - /// other threads run). + /// Sets the ID of the processor the thread should be run on. Threads on the + /// 3DS are only preemptive if they are on the system core. Otherwise they + /// are cooperative (must yield to let other threads run). /// /// Processor IDs are labeled starting from 0. On Old3DS it must be <2, and /// on New3DS it must be <4. Pass -1 to execute the thread on all CPUs and - /// -2 to execute the thread on the default CPU (set in the application's Exheader). + /// -2 to execute the thread on the default CPU (set in the application's + /// Exheader). /// /// * Processor #0 is the application core. It is always possible to create /// a thread on this core. @@ -75,3 +76,13 @@ pub fn current_priority() -> i32 { sched_param.sched_priority } + +/// Get the current thread's processor ID. +/// +/// * Processor #0 is the application core. +/// * Processor #1 is the system core. +/// * Processor #2 is New3DS exclusive. +/// * Processor #3 is New3DS exclusive. +pub fn current_processor() -> i32 { + unsafe { libc::pthread_getprocessorid_np() } +} From 6b97b2cf89d17b4e9c550d4dfb232e1b7887184e Mon Sep 17 00:00:00 2001 From: Mark Drobnak Date: Sat, 25 Jun 2022 17:38:33 -0700 Subject: [PATCH 4/5] Add Default impl derive for thread BuilderOptions on other platforms --- library/std/src/sys/hermit/thread.rs | 2 +- library/std/src/sys/itron/thread.rs | 2 +- library/std/src/sys/sgx/thread.rs | 2 +- library/std/src/sys/unsupported/thread.rs | 2 +- library/std/src/sys/wasi/thread.rs | 2 +- library/std/src/sys/wasm/atomics/thread.rs | 2 +- library/std/src/sys/windows/thread.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index 7b95b2d3472d7..30a2d8e82e564 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -101,7 +101,7 @@ impl Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index d1c0f50f6b6a3..7b9798e417d67 100644 --- a/library/std/src/sys/itron/thread.rs +++ b/library/std/src/sys/itron/thread.rs @@ -292,7 +292,7 @@ impl Drop for Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub mod guard { diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index 7cc017d784daa..df3dfaccd6137 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -141,7 +141,7 @@ impl Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs index aaf56340c2992..9946906f85aa1 100644 --- a/library/std/src/sys/unsupported/thread.rs +++ b/library/std/src/sys/unsupported/thread.rs @@ -35,7 +35,7 @@ impl Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 22dfe61362862..60b985203d665 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -70,7 +70,7 @@ impl Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index dd90edf374ea0..9c27dad88ff4c 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -44,7 +44,7 @@ impl Thread { pub fn join(self) {} } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index bcc032767feb2..c774f269c04dd 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -102,7 +102,7 @@ impl Thread { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct BuilderOptions; pub fn available_parallelism() -> io::Result { From bfd108dcabdcad49f8fade0e696e9fc6df4047f4 Mon Sep 17 00:00:00 2001 From: Mark Drobnak Date: Mon, 11 Jul 2022 20:36:37 -0700 Subject: [PATCH 5/5] Seal the BuilderExt trait --- library/std/src/os/horizon/thread.rs | 7 ++++++- library/std/src/thread/mod.rs | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/horizon/thread.rs b/library/std/src/os/horizon/thread.rs index 479b7073c6b76..19a8aa1524868 100644 --- a/library/std/src/os/horizon/thread.rs +++ b/library/std/src/os/horizon/thread.rs @@ -21,10 +21,15 @@ #![unstable(feature = "horizon_thread_ext", issue = "none")] +use crate::sealed::Sealed; + /// Extensions on [`std::thread::Builder`] for the Nintendo 3DS. /// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +/// /// [`std::thread::Builder`]: crate::thread::Builder -pub trait BuilderExt: Sized { +pub trait BuilderExt: Sized + Sealed { /// Sets the priority level for the new thread. /// /// Low values gives the thread higher priority. For userland apps, this has diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 64a7b197532af..87fcd2bd3021d 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -272,6 +272,10 @@ pub struct Builder { pub(crate) native_options: imp::BuilderOptions, } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for Builder {} + impl Builder { /// Generates the base configuration for spawning a thread, from which /// configuration methods can be chained.