@@ -31,6 +31,7 @@ import comm;
31
31
import option:: { some, none} ;
32
32
import option = option:: t;
33
33
import ptr;
34
+ import c = ctypes;
34
35
35
36
export task;
36
37
export joinable_task;
@@ -46,7 +47,6 @@ export tr_success;
46
47
export tr_failure;
47
48
export get_task;
48
49
export spawn;
49
- export spawn_notify;
50
50
export spawn_joinable;
51
51
52
52
#[ abi = "rust-intrinsic" ]
@@ -55,6 +55,10 @@ native mod rusti {
55
55
fn task_sleep ( task : * rust_task , time_in_us : uint , & killed: bool ) ;
56
56
}
57
57
58
+ type rust_closure = {
59
+ fnptr : c:: intptr_t , envptr : c:: intptr_t
60
+ } ;
61
+
58
62
#[ link_name = "rustrt" ]
59
63
#[ abi = "cdecl" ]
60
64
native mod rustrt {
@@ -70,8 +74,7 @@ native mod rustrt {
70
74
71
75
fn migrate_alloc ( alloc : * u8 , target : task_id ) ;
72
76
73
- fn start_task ( id : task , closure : * u8 ) ;
74
-
77
+ fn start_task ( id : task , closure : * rust_closure ) ;
75
78
}
76
79
77
80
/* Section: Types */
@@ -93,13 +96,60 @@ A handle to a task
93
96
*/
94
97
type task = task_id ;
95
98
99
+ /*
100
+ Function: spawn
101
+
102
+ Creates and executes a new child task
103
+
104
+ Sets up a new task with its own call stack and schedules it to be
105
+ executed. Upon execution, the closure `f()` will be invoked.
106
+
107
+ Parameters:
108
+
109
+ f - A function to execute in the new task
110
+
111
+ Returns:
112
+
113
+ A handle to the new task
114
+ */
115
+ fn spawn ( -f : sendfn ( ) ) -> task unsafe {
116
+ let closure: * rust_closure = unsafe :: reinterpret_cast ( ptr:: addr_of ( f) ) ;
117
+ #debug ( "spawn: closure={%x,%x}" , ( * closure) . fnptr , ( * closure) . envptr ) ;
118
+ let id = rustrt:: new_task ( ) ;
119
+ rustrt:: start_task ( id, closure) ;
120
+ unsafe :: leak ( f) ;
121
+ ret id;
122
+ }
123
+
96
124
/*
97
125
Type: joinable_task
98
126
99
127
A task that sends notification upon termination
100
128
*/
101
129
type joinable_task = ( task , comm:: port < task_notification > ) ;
102
130
131
+ fn spawn_joinable ( -f : sendfn ( ) ) -> joinable_task {
132
+ resource notify_rsrc ( data : ( comm:: chan<task_notification>,
133
+ task,
134
+ @mutable task_result) ) {
135
+ let ( chan, task, tr) = data;
136
+ let msg = exit ( task, * tr) ;
137
+ comm:: send ( chan, msg) ;
138
+ }
139
+
140
+ let notify_port = comm:: port ( ) ;
141
+ let notify_chan = comm:: chan ( notify_port) ;
142
+ let g = sendfn[ copy notify_chan; move f] ( ) {
143
+ let this_task = rustrt:: get_task_id ( ) ;
144
+ let result = @mutable tr_failure;
145
+ let _rsrc = notify_rsrc ( ( notify_chan, this_task, result) ) ;
146
+ f ( ) ;
147
+ * result = tr_success; // rsrc will fire msg when fn returns
148
+ } ;
149
+ let task = spawn ( g) ;
150
+ ret ( task, notify_port) ;
151
+ }
152
+
103
153
/*
104
154
Tag: task_result
105
155
@@ -213,130 +263,6 @@ Unpin the current task and future child tasks
213
263
*/
214
264
fn unpin ( ) { rustrt:: unpin_task ( ) ; }
215
265
216
- /*
217
- Function: spawn
218
-
219
- Creates and executes a new child task
220
-
221
- Sets up a new task with its own call stack and schedules it to be executed.
222
- Upon execution the new task will call function `f` with the provided
223
- argument `data`.
224
-
225
- Function `f` is a bare function, meaning it may not close over any data, as do
226
- shared functions (fn@) and lambda blocks. `data` must be a uniquely owned
227
- type; it is moved into the new task and thus can no longer be accessed
228
- locally.
229
-
230
- Parameters:
231
-
232
- data - A unique-type value to pass to the new task
233
- f - A function to execute in the new task
234
-
235
- Returns:
236
-
237
- A handle to the new task
238
- */
239
- fn spawn < T : send > ( -data : T , f : fn ( T ) ) -> task {
240
- spawn_inner ( data, f, none)
241
- }
242
-
243
- /*
244
- Function: spawn_notify
245
-
246
- Create and execute a new child task, requesting notification upon its
247
- termination
248
-
249
- Immediately before termination, either on success or failure, the spawned
250
- task will send a <task_notification> message on the provided channel.
251
- */
252
- fn spawn_notify < T : send > ( -data : T , f : fn ( T ) ,
253
- notify : comm:: chan < task_notification > ) -> task {
254
- spawn_inner ( data, f, some ( notify) )
255
- }
256
-
257
- /*
258
- Function: spawn_joinable
259
-
260
- Create and execute a task which can later be joined with the <join> function
261
-
262
- This is a convenience wrapper around spawn_notify which, when paired
263
- with <join> can be easily used to spawn a task then wait for it to
264
- complete.
265
- */
266
- fn spawn_joinable < T : send > ( -data : T , f : fn ( T ) ) -> joinable_task {
267
- let p = comm:: port :: < task_notification > ( ) ;
268
- let id = spawn_notify ( data, f, comm:: chan :: < task_notification > ( p) ) ;
269
- ret ( id, p) ;
270
- }
271
-
272
- // FIXME: To transition from the unsafe spawn that spawns a shared closure to
273
- // the safe spawn that spawns a bare function we're going to write
274
- // barefunc-spawn on top of unsafe-spawn. Sadly, bind does not work reliably
275
- // enough to suite our needs (#1034, probably others yet to be discovered), so
276
- // we're going to copy the bootstrap data into a unique pointer, cast it to an
277
- // unsafe pointer then wrap up the bare function and the unsafe pointer in a
278
- // shared closure to spawn.
279
- //
280
- // After the transition this should all be rewritten.
281
-
282
- fn spawn_inner < T : send > ( -data : T , f : fn ( T ) ,
283
- notify : option < comm:: chan < task_notification > > )
284
- -> task unsafe {
285
-
286
- fn wrapper < T : send > ( data : * u8 , f : fn ( T ) ) unsafe {
287
- let data: ~T = unsafe :: reinterpret_cast ( data) ;
288
- f ( * data) ;
289
- }
290
-
291
- let data = ~data;
292
- let dataptr: * u8 = unsafe :: reinterpret_cast ( data) ;
293
- unsafe :: leak ( data) ;
294
- let wrapped = bind wrapper ( dataptr, f) ;
295
- ret unsafe_spawn_inner ( wrapped, notify) ;
296
- }
297
-
298
- // FIXME: This is the old spawn function that spawns a shared closure.
299
- // It is a hack and needs to be rewritten.
300
- fn unsafe_spawn_inner( -thunk : fn @( ) ,
301
- notify : option < comm:: chan < task_notification > > ) ->
302
- task unsafe {
303
- let id = rustrt:: new_task ( ) ;
304
-
305
- let raw_thunk: { code : uint , env : uint } = cast ( thunk) ;
306
-
307
- // set up the task pointer
308
- let task_ptr <- rust_task_ptr ( rustrt:: get_task_pointer ( id ) ) ;
309
-
310
- assert ( ptr:: null ( ) != ( * * task_ptr) . stack_ptr ) ;
311
-
312
- // copy the thunk from our stack to the new stack
313
- let sp : uint = cast ( ( * * task_ptr) . stack_ptr ) ;
314
- let ptrsize = sys:: size_of:: < * u8 > ( ) ;
315
- let thunkfn : * mutable uint = cast ( sp - ptrsize * 2 u ) ;
316
- let thunkenv : * mutable uint = cast ( sp - ptrsize ) ;
317
- * thunkfn = cast ( raw_thunk . code) ; ;
318
- * thunkenv = cast ( raw_thunk . env) ; ;
319
- // Advance the stack pointer. No need to align because
320
- // the native code will do that for us
321
- ( * * task_ptr ) . stack_ptr = cast ( sp - ptrsize * 2 u ) ;
322
-
323
- // set up notifications if they are enabled.
324
- alt notify {
325
- some ( c ) {
326
- ( * * task_ptr ) . notify_enabled = 1 ;
327
- ( * * task_ptr ) . notify_chan = c ;
328
- }
329
- none { }
330
- }
331
-
332
- // give the thunk environment's allocation to the new task
333
- rustrt:: migrate_alloc ( cast ( raw_thunk . env) , id ) ;
334
- rustrt:: start_task ( id , cast ( thunkfn ) ) ;
335
- // don't cleanup the thunk in this task
336
- unsafe :: leak ( thunk ) ;
337
- ret id;
338
- }
339
-
340
266
// Local Variables:
341
267
// mode: rust;
342
268
// fill-column: 78;
0 commit comments