@@ -22,6 +22,7 @@ use alloc::boxed::Box;
22
22
use core:: mem;
23
23
use core:: uint;
24
24
use libc;
25
+ use thunk:: { Thunk } ;
25
26
26
27
use stack;
27
28
use stack_overflow;
@@ -60,8 +61,8 @@ fn start_thread(main: *mut libc::c_void) -> imp::rust_thread_return {
60
61
unsafe {
61
62
stack:: record_os_managed_stack_bounds ( 0 , uint:: MAX ) ;
62
63
let handler = stack_overflow:: Handler :: new ( ) ;
63
- let f: Box < proc ( ) > = mem:: transmute ( main) ;
64
- ( * f ) ( ) ;
64
+ let f: Box < Thunk > = mem:: transmute ( main) ;
65
+ f . invoke ( ( ) ) ;
65
66
drop ( handler) ;
66
67
mem:: transmute ( 0 as imp:: rust_thread_return )
67
68
}
@@ -113,23 +114,29 @@ impl Thread<()> {
113
114
/// to finish executing. This means that even if `join` is not explicitly
114
115
/// called, when the `Thread` falls out of scope its destructor will block
115
116
/// waiting for the OS thread.
116
- pub fn start < T : Send > ( main : proc ( ) : Send -> T ) -> Thread < T > {
117
+ pub fn start < T , F > ( main : F ) -> Thread < T >
118
+ where T : Send , F : FnOnce ( ) -> T , F : Send
119
+ {
117
120
Thread :: start_stack ( DEFAULT_STACK_SIZE , main)
118
121
}
119
122
120
123
/// Performs the same functionality as `start`, but specifies an explicit
121
124
/// stack size for the new thread.
122
- pub fn start_stack < T : Send > ( stack : uint , main : proc ( ) : Send -> T ) -> Thread < T > {
123
-
125
+ pub fn start_stack < T , F > ( stack : uint , main : F ) -> Thread < T >
126
+ where T : Send , F : FnOnce ( ) -> T , F : Send
127
+ {
124
128
// We need the address of the packet to fill in to be stable so when
125
129
// `main` fills it in it's still valid, so allocate an extra box to do
126
130
// so.
127
131
let packet = box None ;
128
132
let packet2: * mut Option < T > = unsafe {
129
133
* mem:: transmute :: < & Box < Option < T > > , * const * mut Option < T > > ( & packet)
130
134
} ;
131
- let main = proc ( ) unsafe { * packet2 = Some ( main ( ) ) ; } ;
132
- let native = unsafe { imp:: create ( stack, box main) } ;
135
+ let native = unsafe {
136
+ imp:: create ( stack, Thunk :: new ( move |: | {
137
+ * packet2 = Some ( main. call_once ( ( ) ) ) ;
138
+ } ) )
139
+ } ;
133
140
134
141
Thread {
135
142
native : native,
@@ -144,15 +151,19 @@ impl Thread<()> {
144
151
/// This corresponds to creating threads in the 'detached' state on unix
145
152
/// systems. Note that platforms may not keep the main program alive even if
146
153
/// there are detached thread still running around.
147
- pub fn spawn ( main : proc ( ) : Send ) {
154
+ pub fn spawn < F > ( main : F )
155
+ where F : FnOnce ( ) + Send
156
+ {
148
157
Thread :: spawn_stack ( DEFAULT_STACK_SIZE , main)
149
158
}
150
159
151
160
/// Performs the same functionality as `spawn`, but explicitly specifies a
152
161
/// stack size for the new thread.
153
- pub fn spawn_stack ( stack : uint , main : proc ( ) : Send ) {
162
+ pub fn spawn_stack < F > ( stack : uint , main : F )
163
+ where F : FnOnce ( ) + Send
164
+ {
154
165
unsafe {
155
- let handle = imp:: create ( stack, box main) ;
166
+ let handle = imp:: create ( stack, Thunk :: new ( main) ) ;
156
167
imp:: detach ( handle) ;
157
168
}
158
169
}
@@ -190,8 +201,6 @@ impl<T: Send> Drop for Thread<T> {
190
201
#[ cfg( windows) ]
191
202
#[ allow( non_snake_case) ]
192
203
mod imp {
193
- use core:: prelude:: * ;
194
-
195
204
use alloc:: boxed:: Box ;
196
205
use core:: cmp;
197
206
use core:: mem;
@@ -200,6 +209,7 @@ mod imp {
200
209
use libc:: types:: os:: arch:: extra:: { LPSECURITY_ATTRIBUTES , SIZE_T , BOOL ,
201
210
LPVOID , DWORD , LPDWORD , HANDLE } ;
202
211
use stack:: RED_ZONE ;
212
+ use thunk:: Thunk ;
203
213
204
214
pub type rust_thread = HANDLE ;
205
215
pub type rust_thread_return = DWORD ;
@@ -217,8 +227,9 @@ mod imp {
217
227
}
218
228
}
219
229
220
- pub unsafe fn create ( stack : uint , p : Box < proc ( ) : Send > ) -> rust_thread {
221
- let arg: * mut libc:: c_void = mem:: transmute ( p) ;
230
+ pub unsafe fn create ( stack : uint , p : Thunk ) -> rust_thread {
231
+ let arg: * mut libc:: c_void = mem:: transmute ( box p) ;
232
+
222
233
// FIXME On UNIX, we guard against stack sizes that are too small but
223
234
// that's because pthreads enforces that stacks are at least
224
235
// PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
@@ -234,7 +245,7 @@ mod imp {
234
245
235
246
if ret as uint == 0 {
236
247
// be sure to not leak the closure
237
- let _p: Box < proc ( ) : Send > = mem:: transmute ( arg) ;
248
+ let _p: Box < Thunk > = mem:: transmute ( arg) ;
238
249
panic ! ( "failed to spawn native thread: {}" , ret) ;
239
250
}
240
251
return ret;
@@ -279,6 +290,7 @@ mod imp {
279
290
use core:: ptr;
280
291
use libc:: consts:: os:: posix01:: { PTHREAD_CREATE_JOINABLE , PTHREAD_STACK_MIN } ;
281
292
use libc;
293
+ use thunk:: Thunk ;
282
294
283
295
use stack:: RED_ZONE ;
284
296
@@ -409,7 +421,7 @@ mod imp {
409
421
}
410
422
}
411
423
412
- pub unsafe fn create ( stack : uint , p : Box < proc ( ) : Send > ) -> rust_thread {
424
+ pub unsafe fn create ( stack : uint , p : Thunk ) -> rust_thread {
413
425
let mut native: libc:: pthread_t = mem:: zeroed ( ) ;
414
426
let mut attr: libc:: pthread_attr_t = mem:: zeroed ( ) ;
415
427
assert_eq ! ( pthread_attr_init( & mut attr) , 0 ) ;
@@ -437,13 +449,13 @@ mod imp {
437
449
} ,
438
450
} ;
439
451
440
- let arg: * mut libc:: c_void = mem:: transmute ( p) ;
452
+ let arg: * mut libc:: c_void = mem:: transmute ( box p) ; // must box since sizeof(p)=2*uint
441
453
let ret = pthread_create ( & mut native, & attr, super :: thread_start, arg) ;
442
454
assert_eq ! ( pthread_attr_destroy( & mut attr) , 0 ) ;
443
455
444
456
if ret != 0 {
445
457
// be sure to not leak the closure
446
- let _p: Box < proc ( ) : Send > = mem:: transmute ( arg) ;
458
+ let _p: Box < Box < FnOnce ( ) + Send > > = mem:: transmute ( arg) ;
447
459
panic ! ( "failed to spawn native thread: {}" , ret) ;
448
460
}
449
461
native
@@ -531,17 +543,17 @@ mod tests {
531
543
use super :: Thread ;
532
544
533
545
#[ test]
534
- fn smoke ( ) { Thread :: start ( proc ( ) { } ) . join ( ) ; }
546
+ fn smoke ( ) { Thread :: start ( move || { } ) . join ( ) ; }
535
547
536
548
#[ test]
537
- fn data ( ) { assert_eq ! ( Thread :: start( proc ( ) { 1 i } ) . join( ) , 1 ) ; }
549
+ fn data ( ) { assert_eq ! ( Thread :: start( move|| { 1 i } ) . join( ) , 1 ) ; }
538
550
539
551
#[ test]
540
- fn detached ( ) { Thread :: spawn ( proc ( ) { } ) }
552
+ fn detached ( ) { Thread :: spawn ( move || { } ) }
541
553
542
554
#[ test]
543
555
fn small_stacks ( ) {
544
- assert_eq ! ( 42 i, Thread :: start_stack( 0 , proc ( ) 42 i) . join( ) ) ;
545
- assert_eq ! ( 42 i, Thread :: start_stack( 1 , proc ( ) 42 i) . join( ) ) ;
556
+ assert_eq ! ( 42 i, Thread :: start_stack( 0 , move|| 42 i) . join( ) ) ;
557
+ assert_eq ! ( 42 i, Thread :: start_stack( 1 , move|| 42 i) . join( ) ) ;
546
558
}
547
559
}
0 commit comments