11//! Thread startup and shutdown.
2+ //!
3+ //! Why does this api look like `thread::join(t)` instead of `t.join()`? Either
4+ //! way could work, but free functions help emphasize that this API's
5+ //! [`Thread`] differs from `std::thread::Thread`. It does not detach or free
6+ //! its resources on drop, and does not guarantee validity. That gives users
7+ //! more control when creating efficient higher-level abstractions like
8+ //! pthreads or `std::thread::Thread`.
29
310#[ cfg( not( feature = "nightly" ) ) ]
411use crate :: ptr:: { with_exposed_provenance_mut, without_provenance_mut, Polyfill as _} ;
@@ -48,6 +55,16 @@ impl Thread {
4855 Self ( raw. expose_provenance ( ) as libc:: pthread_t )
4956 }
5057
58+ /// Convert to `Self` from a raw non-null pointer.
59+ ///
60+ /// # Safety
61+ ///
62+ /// `raw` must be a valid non-null thread pointer.
63+ #[ inline]
64+ pub unsafe fn from_raw_unchecked ( raw : * mut c_void ) -> Self {
65+ Self :: from_raw ( raw)
66+ }
67+
5168 /// Convert to `Self` from a raw non-null pointer that was returned from
5269 /// `Thread::to_raw_non_null`.
5370 #[ inline]
@@ -83,29 +100,33 @@ impl Thread {
83100///
84101/// # Safety
85102///
86- /// `fn_(arg)` on the new thread must have defined behavior, and the return
87- /// value must be valid to use on the eventual joining thread.
103+ /// The values of `args` must be valid to send to the new thread, `fn_(args)`
104+ /// on the new thread must have defined behavior, and the return value must be
105+ /// valid to send to other threads.
88106pub unsafe fn create (
89- fn_ : unsafe fn ( & mut [ * mut c_void ] ) -> Option < NonNull < c_void > > ,
107+ fn_ : unsafe fn ( & mut [ Option < NonNull < c_void > > ] ) -> Option < NonNull < c_void > > ,
90108 args : & [ Option < NonNull < c_void > > ] ,
91109 stack_size : usize ,
92110 guard_size : usize ,
93111) -> io:: Result < Thread > {
94112 extern "C" fn start ( thread_arg_ptr : * mut c_void ) -> * mut c_void {
95113 unsafe {
96114 // Unpack the thread arguments.
97- let num_args = thread_arg_ptr. cast :: < * mut c_void > ( ) . read ( ) . addr ( ) ;
98- let thread_args =
99- slice:: from_raw_parts_mut ( thread_arg_ptr. cast :: < * mut c_void > ( ) , num_args + 2 ) ;
100- let fn_: unsafe fn ( & mut [ * mut c_void ] ) -> Option < NonNull < c_void > > =
115+ let thread_arg_ptr = thread_arg_ptr. cast :: < Option < NonNull < c_void > > > ( ) ;
116+ let num_args = match thread_arg_ptr. read ( ) {
117+ Some ( ptr) => ptr. as_ptr ( ) . addr ( ) ,
118+ None => 0 ,
119+ } ;
120+ let thread_args = slice:: from_raw_parts_mut ( thread_arg_ptr, num_args + 2 ) ;
121+ let fn_: unsafe fn ( & mut [ Option < NonNull < c_void > > ] ) -> Option < NonNull < c_void > > =
101122 transmute ( thread_args[ 1 ] ) ;
102123 let args = & mut thread_args[ 2 ..] ;
103124
104125 // Call the user's function.
105126 let return_value = fn_ ( args) ;
106127
107128 // Free the thread argument memory.
108- libc:: free ( thread_arg_ptr) ;
129+ libc:: free ( thread_arg_ptr. cast :: < c_void > ( ) ) ;
109130
110131 // Return the return value.
111132 match return_value {
@@ -155,6 +176,40 @@ pub unsafe fn create(
155176 }
156177}
157178
179+ /// Marks a thread as “detached”.
180+ ///
181+ /// Detached threads free their own resources automatically when they
182+ /// exit, rather than when they are joined.
183+ ///
184+ /// # Safety
185+ ///
186+ /// `thread` must point to a valid thread record that has not yet been detached
187+ /// and will not be joined.
188+ #[ inline]
189+ pub unsafe fn detach ( thread : Thread ) {
190+ let thread = thread. 0 ;
191+
192+ assert_eq ! ( libc:: pthread_detach( thread) , 0 ) ;
193+ }
194+
195+ /// Waits for a thread to finish.
196+ ///
197+ /// The return value is the value returned from the call to the `fn_` passed to
198+ /// `create_thread`.
199+ ///
200+ /// # Safety
201+ ///
202+ /// `thread` must point to a valid thread record that has not already been
203+ /// detached or joined.
204+ pub unsafe fn join ( thread : Thread ) -> Option < NonNull < c_void > > {
205+ let thread = thread. 0 ;
206+
207+ let mut return_value: * mut c_void = null_mut ( ) ;
208+ assert_eq ! ( libc:: pthread_join( thread, & mut return_value) , 0 ) ;
209+
210+ NonNull :: new ( return_value)
211+ }
212+
158213/// Registers a function to call when the current thread exits.
159214#[ cfg( feature = "thread-at-exit" ) ]
160215pub fn at_exit ( func : Box < dyn FnOnce ( ) > ) {
@@ -235,7 +290,8 @@ pub fn current_tls_addr(module: usize, offset: usize) -> *mut c_void {
235290///
236291/// `thread` must point to a valid thread record.
237292#[ inline]
238- pub unsafe fn thread_stack ( thread : Thread ) -> ( * mut c_void , usize , usize ) {
293+ #[ must_use]
294+ pub unsafe fn stack ( thread : Thread ) -> ( * mut c_void , usize , usize ) {
239295 let thread = thread. 0 ;
240296
241297 let mut attr: libc:: pthread_attr_t = zeroed ( ) ;
@@ -254,40 +310,6 @@ pub unsafe fn thread_stack(thread: Thread) -> (*mut c_void, usize, usize) {
254310 ( stack_addr, stack_size, guard_size)
255311}
256312
257- /// Marks a thread as “detached”.
258- ///
259- /// Detached threads free their own resources automatically when they
260- /// exit, rather than when they are joined.
261- ///
262- /// # Safety
263- ///
264- /// `thread` must point to a valid thread record that has not yet been detached
265- /// and will not be joined.
266- #[ inline]
267- pub unsafe fn detach ( thread : Thread ) {
268- let thread = thread. 0 ;
269-
270- assert_eq ! ( libc:: pthread_detach( thread) , 0 ) ;
271- }
272-
273- /// Waits for a thread to finish.
274- ///
275- /// The return value is the value returned from the call to the `fn_` passed to
276- /// `create_thread`.
277- ///
278- /// # Safety
279- ///
280- /// `thread` must point to a valid thread record that has not already been
281- /// detached or joined.
282- pub unsafe fn join ( thread : Thread ) -> Option < NonNull < c_void > > {
283- let thread = thread. 0 ;
284-
285- let mut return_value: * mut c_void = null_mut ( ) ;
286- assert_eq ! ( libc:: pthread_join( thread, & mut return_value) , 0 ) ;
287-
288- NonNull :: new ( return_value)
289- }
290-
291313/// Return the default stack size for new threads.
292314#[ inline]
293315#[ must_use]
0 commit comments