10
10
11
11
#![ allow( dead_code) ]
12
12
13
- use core :: prelude :: * ;
13
+ use prelude :: v1 :: * ;
14
14
15
+ use alloc:: boxed:: FnBox ;
15
16
use cmp;
16
17
use ffi:: CString ;
17
18
use io;
@@ -20,13 +21,148 @@ use libc;
20
21
use mem;
21
22
use ptr;
22
23
use sys:: os;
23
- use thunk:: Thunk ;
24
24
use time:: Duration ;
25
25
26
26
use sys_common:: stack:: RED_ZONE ;
27
27
use sys_common:: thread:: * ;
28
28
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
+ }
30
166
31
167
#[ cfg( all( not( target_os = "linux" ) ,
32
168
not( target_os = "macos" ) ,
@@ -183,128 +319,6 @@ pub mod guard {
183
319
}
184
320
}
185
321
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
-
308
322
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
309
323
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
310
324
// storage. We need that information to avoid blowing up when a small stack
@@ -319,7 +333,7 @@ pub fn sleep(dur: Duration) {
319
333
// but that caused Debian to detect an unnecessarily strict versioned
320
334
// dependency on libc6 (#23628).
321
335
#[ 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 {
323
337
use dynamic_lib:: DynamicLibrary ;
324
338
use sync:: { Once , ONCE_INIT } ;
325
339
@@ -337,16 +351,16 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
337
351
} ) ;
338
352
339
353
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 } ,
342
356
}
343
357
}
344
358
345
359
// No point in looking up __pthread_get_minstack() on non-glibc
346
360
// platforms.
347
361
#[ 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
350
364
}
351
365
352
366
extern {
0 commit comments