1010
1111#![ allow( dead_code) ]
1212
13- use core :: prelude :: * ;
13+ use prelude :: v1 :: * ;
1414
15+ use alloc:: boxed:: FnBox ;
1516use cmp;
1617use ffi:: CString ;
1718use io;
@@ -20,13 +21,148 @@ use libc;
2021use mem;
2122use ptr;
2223use sys:: os;
23- use thunk:: Thunk ;
2424use time:: Duration ;
2525
2626use sys_common:: stack:: RED_ZONE ;
2727use sys_common:: thread:: * ;
2828
29- pub type rust_thread = libc:: pthread_t ;
29+ pub struct Thread {
30+ id : libc:: pthread_t ,
31+ }
32+
33+ // Some platforms may have pthread_t as a pointer in which case we still want
34+ // a thread to be Send/Sync
35+ unsafe impl Send for Thread { }
36+ unsafe impl Sync for Thread { }
37+
38+ impl Thread {
39+ pub unsafe fn new < ' a > ( stack : usize , p : Box < FnBox ( ) + ' a > )
40+ -> io:: Result < Thread > {
41+ let p = box p;
42+ let mut native: libc:: pthread_t = mem:: zeroed ( ) ;
43+ let mut attr: libc:: pthread_attr_t = mem:: zeroed ( ) ;
44+ assert_eq ! ( pthread_attr_init( & mut attr) , 0 ) ;
45+
46+ // Reserve room for the red zone, the runtime's stack of last resort.
47+ let stack_size = cmp:: max ( stack, RED_ZONE + min_stack_size ( & attr) ) ;
48+ match pthread_attr_setstacksize ( & mut attr, stack_size as libc:: size_t ) {
49+ 0 => { }
50+ n => {
51+ assert_eq ! ( n, libc:: EINVAL ) ;
52+ // EINVAL means |stack_size| is either too small or not a
53+ // multiple of the system page size. Because it's definitely
54+ // >= PTHREAD_STACK_MIN, it must be an alignment issue.
55+ // Round up to the nearest page and try again.
56+ let page_size = os:: page_size ( ) ;
57+ let stack_size = ( stack_size + page_size - 1 ) &
58+ ( -( page_size as isize - 1 ) as usize - 1 ) ;
59+ let stack_size = stack_size as libc:: size_t ;
60+ assert_eq ! ( pthread_attr_setstacksize( & mut attr, stack_size) , 0 ) ;
61+ }
62+ } ;
63+
64+ let ret = pthread_create ( & mut native, & attr, thread_start,
65+ & * p as * const _ as * mut _ ) ;
66+ assert_eq ! ( pthread_attr_destroy( & mut attr) , 0 ) ;
67+
68+ return if ret != 0 {
69+ Err ( io:: Error :: from_raw_os_error ( ret) )
70+ } else {
71+ mem:: forget ( p) ; // ownership passed to pthread_create
72+ Ok ( Thread { id : native } )
73+ } ;
74+
75+ #[ no_stack_check]
76+ extern fn thread_start ( main : * mut libc:: c_void ) -> * mut libc:: c_void {
77+ unsafe { start_thread ( main) ; }
78+ 0 as * mut _
79+ }
80+ }
81+
82+ pub fn yield_now ( ) {
83+ let ret = unsafe { sched_yield ( ) } ;
84+ debug_assert_eq ! ( ret, 0 ) ;
85+ }
86+
87+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
88+ pub fn set_name ( name : & str ) {
89+ // pthread wrapper only appeared in glibc 2.12, so we use syscall
90+ // directly.
91+ extern {
92+ fn prctl ( option : libc:: c_int , arg2 : libc:: c_ulong ,
93+ arg3 : libc:: c_ulong , arg4 : libc:: c_ulong ,
94+ arg5 : libc:: c_ulong ) -> libc:: c_int ;
95+ }
96+ const PR_SET_NAME : libc:: c_int = 15 ;
97+ let cname = CString :: new ( name) . unwrap_or_else ( |_| {
98+ panic ! ( "thread name may not contain interior null bytes" )
99+ } ) ;
100+ unsafe {
101+ prctl ( PR_SET_NAME , cname. as_ptr ( ) as libc:: c_ulong , 0 , 0 , 0 ) ;
102+ }
103+ }
104+
105+ #[ cfg( any( target_os = "freebsd" ,
106+ target_os = "dragonfly" ,
107+ target_os = "bitrig" ,
108+ target_os = "openbsd" ) ) ]
109+ pub fn set_name ( name : & str ) {
110+ extern {
111+ fn pthread_set_name_np ( tid : libc:: pthread_t ,
112+ name : * const libc:: c_char ) ;
113+ }
114+ let cname = CString :: new ( name) . unwrap ( ) ;
115+ unsafe {
116+ pthread_set_name_np ( pthread_self ( ) , cname. as_ptr ( ) ) ;
117+ }
118+ }
119+
120+ #[ cfg( any( target_os = "macos" , target_os = "ios" ) ) ]
121+ pub fn set_name ( name : & str ) {
122+ extern {
123+ fn pthread_setname_np ( name : * const libc:: c_char ) -> libc:: c_int ;
124+ }
125+ let cname = CString :: new ( name) . unwrap ( ) ;
126+ unsafe {
127+ pthread_setname_np ( cname. as_ptr ( ) ) ;
128+ }
129+ }
130+
131+ pub fn sleep ( dur : Duration ) {
132+ if dur < Duration :: zero ( ) {
133+ return Thread :: yield_now ( )
134+ }
135+ let seconds = dur. num_seconds ( ) ;
136+ let ns = dur - Duration :: seconds ( seconds) ;
137+ let mut ts = libc:: timespec {
138+ tv_sec : seconds as libc:: time_t ,
139+ tv_nsec : ns. num_nanoseconds ( ) . unwrap ( ) as libc:: c_long ,
140+ } ;
141+
142+ // If we're awoken with a signal then the return value will be -1 and
143+ // nanosleep will fill in `ts` with the remaining time.
144+ unsafe {
145+ while libc:: nanosleep ( & ts, & mut ts) == -1 {
146+ assert_eq ! ( os:: errno( ) , libc:: EINTR ) ;
147+ }
148+ }
149+ }
150+
151+ pub fn join ( self ) {
152+ unsafe {
153+ let ret = pthread_join ( self . id , ptr:: null_mut ( ) ) ;
154+ mem:: forget ( self ) ;
155+ debug_assert_eq ! ( ret, 0 ) ;
156+ }
157+ }
158+ }
159+
160+ impl Drop for Thread {
161+ fn drop ( & mut self ) {
162+ let ret = unsafe { pthread_detach ( self . id ) } ;
163+ debug_assert_eq ! ( ret, 0 ) ;
164+ }
165+ }
30166
31167#[ cfg( all( not( target_os = "linux" ) ,
32168 not( target_os = "macos" ) ,
@@ -183,128 +319,6 @@ pub mod guard {
183319 }
184320}
185321
186- pub unsafe fn create ( stack : usize , p : Thunk ) -> io:: Result < rust_thread > {
187- let p = box p;
188- let mut native: libc:: pthread_t = mem:: zeroed ( ) ;
189- let mut attr: libc:: pthread_attr_t = mem:: zeroed ( ) ;
190- assert_eq ! ( pthread_attr_init( & mut attr) , 0 ) ;
191-
192- // Reserve room for the red zone, the runtime's stack of last resort.
193- let stack_size = cmp:: max ( stack, RED_ZONE + min_stack_size ( & attr) as usize ) ;
194- match pthread_attr_setstacksize ( & mut attr, stack_size as libc:: size_t ) {
195- 0 => { }
196- n => {
197- assert_eq ! ( n, libc:: EINVAL ) ;
198- // EINVAL means |stack_size| is either too small or not a
199- // multiple of the system page size. Because it's definitely
200- // >= PTHREAD_STACK_MIN, it must be an alignment issue.
201- // Round up to the nearest page and try again.
202- let page_size = os:: page_size ( ) ;
203- let stack_size = ( stack_size + page_size - 1 ) &
204- ( -( page_size as isize - 1 ) as usize - 1 ) ;
205- assert_eq ! ( pthread_attr_setstacksize( & mut attr,
206- stack_size as libc:: size_t) , 0 ) ;
207- }
208- } ;
209-
210- let ret = pthread_create ( & mut native, & attr, thread_start,
211- & * p as * const _ as * mut _ ) ;
212- assert_eq ! ( pthread_attr_destroy( & mut attr) , 0 ) ;
213-
214- return if ret != 0 {
215- Err ( io:: Error :: from_raw_os_error ( ret) )
216- } else {
217- mem:: forget ( p) ; // ownership passed to pthread_create
218- Ok ( native)
219- } ;
220-
221- #[ no_stack_check]
222- extern fn thread_start ( main : * mut libc:: c_void ) -> * mut libc:: c_void {
223- start_thread ( main) ;
224- 0 as * mut _
225- }
226- }
227-
228- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
229- pub unsafe fn set_name ( name : & str ) {
230- // pthread wrapper only appeared in glibc 2.12, so we use syscall directly.
231- extern {
232- fn prctl ( option : libc:: c_int , arg2 : libc:: c_ulong , arg3 : libc:: c_ulong ,
233- arg4 : libc:: c_ulong , arg5 : libc:: c_ulong ) -> libc:: c_int ;
234- }
235- const PR_SET_NAME : libc:: c_int = 15 ;
236- let cname = CString :: new ( name) . unwrap_or_else ( |_| {
237- panic ! ( "thread name may not contain interior null bytes" )
238- } ) ;
239- prctl ( PR_SET_NAME , cname. as_ptr ( ) as libc:: c_ulong , 0 , 0 , 0 ) ;
240- }
241-
242- #[ cfg( any( target_os = "freebsd" ,
243- target_os = "dragonfly" ,
244- target_os = "bitrig" ,
245- target_os = "openbsd" ) ) ]
246- pub unsafe fn set_name ( name : & str ) {
247- extern {
248- fn pthread_set_name_np ( tid : libc:: pthread_t , name : * const libc:: c_char ) ;
249- }
250- let cname = CString :: new ( name) . unwrap ( ) ;
251- pthread_set_name_np ( pthread_self ( ) , cname. as_ptr ( ) ) ;
252- }
253-
254- #[ cfg( any( target_os = "macos" , target_os = "ios" ) ) ]
255- pub unsafe fn set_name ( name : & str ) {
256- extern {
257- fn pthread_setname_np ( name : * const libc:: c_char ) -> libc:: c_int ;
258- }
259- let cname = CString :: new ( name) . unwrap ( ) ;
260- pthread_setname_np ( cname. as_ptr ( ) ) ;
261- }
262-
263- pub unsafe fn join ( native : rust_thread ) {
264- assert_eq ! ( pthread_join( native, ptr:: null_mut( ) ) , 0 ) ;
265- }
266-
267- pub unsafe fn detach ( native : rust_thread ) {
268- assert_eq ! ( pthread_detach( native) , 0 ) ;
269- }
270-
271- pub unsafe fn yield_now ( ) {
272- assert_eq ! ( sched_yield( ) , 0 ) ;
273- }
274-
275- pub fn sleep ( dur : Duration ) {
276- unsafe {
277- if dur < Duration :: zero ( ) {
278- return yield_now ( )
279- }
280- let seconds = dur. num_seconds ( ) ;
281- let ns = dur - Duration :: seconds ( seconds) ;
282- let mut ts = libc:: timespec {
283- tv_sec : seconds as libc:: time_t ,
284- tv_nsec : ns. num_nanoseconds ( ) . unwrap ( ) as libc:: c_long ,
285- } ;
286- // If we're awoken with a signal then the return value will be -1 and
287- // nanosleep will fill in `ts` with the remaining time.
288- while dosleep ( & mut ts) == -1 {
289- assert_eq ! ( os:: errno( ) , libc:: EINTR ) ;
290- }
291- }
292-
293- #[ cfg( target_os = "linux" ) ]
294- unsafe fn dosleep ( ts : * mut libc:: timespec ) -> libc:: c_int {
295- extern {
296- fn clock_nanosleep ( clock_id : libc:: c_int , flags : libc:: c_int ,
297- request : * const libc:: timespec ,
298- remain : * mut libc:: timespec ) -> libc:: c_int ;
299- }
300- clock_nanosleep ( libc:: CLOCK_MONOTONIC , 0 , ts, ts)
301- }
302- #[ cfg( not( target_os = "linux" ) ) ]
303- unsafe fn dosleep ( ts : * mut libc:: timespec ) -> libc:: c_int {
304- libc:: nanosleep ( ts, ts)
305- }
306- }
307-
308322// glibc >= 2.15 has a __pthread_get_minstack() function that returns
309323// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
310324// storage. We need that information to avoid blowing up when a small stack
@@ -319,7 +333,7 @@ pub fn sleep(dur: Duration) {
319333// but that caused Debian to detect an unnecessarily strict versioned
320334// dependency on libc6 (#23628).
321335#[ cfg( target_os = "linux" ) ]
322- fn min_stack_size ( attr : * const libc:: pthread_attr_t ) -> libc :: size_t {
336+ fn min_stack_size ( attr : * const libc:: pthread_attr_t ) -> usize {
323337 use dynamic_lib:: DynamicLibrary ;
324338 use sync:: { Once , ONCE_INIT } ;
325339
@@ -337,16 +351,16 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
337351 } ) ;
338352
339353 match unsafe { __pthread_get_minstack } {
340- None => PTHREAD_STACK_MIN ,
341- Some ( f) => unsafe { f ( attr) } ,
354+ None => PTHREAD_STACK_MIN as usize ,
355+ Some ( f) => unsafe { f ( attr) as usize } ,
342356 }
343357}
344358
345359// No point in looking up __pthread_get_minstack() on non-glibc
346360// platforms.
347361#[ cfg( not( target_os = "linux" ) ) ]
348- fn min_stack_size ( _: * const libc:: pthread_attr_t ) -> libc :: size_t {
349- PTHREAD_STACK_MIN
362+ fn min_stack_size ( _: * const libc:: pthread_attr_t ) -> usize {
363+ PTHREAD_STACK_MIN as usize
350364}
351365
352366extern {
0 commit comments