1
1
// Some temporary libuv hacks for servo
2
2
3
3
// UV2
4
+
5
+ // these are processed solely in the
6
+ // process_operation() crust fn below
4
7
enum uv_operation {
5
- op_async_init( [ u8 ] )
8
+ op_async_init( [ u8 ] ) ,
9
+ op_close( uv_handle , * ctypes:: void )
6
10
}
7
11
8
- type uv_async = {
9
- id : [ u8 ] ,
10
- loop : uv_loop
11
- } ;
12
+ enum uv_handle {
13
+ uv_async( [ u8 ] , uv_loop )
14
+ }
12
15
13
16
enum uv_msg {
14
17
// requests from library users
15
18
msg_run( comm:: chan < bool > ) ,
16
19
msg_run_in_bg( ) ,
17
- msg_loop_delete( ) ,
18
- msg_async_init( fn ~( uv_async ) , fn ~( uv_async ) ) ,
20
+ msg_async_init( fn ~( uv_handle ) , fn ~( uv_handle ) ) ,
19
21
msg_async_send( [ u8 ] ) ,
22
+ msg_close( uv_handle , fn ~( ) ) ,
20
23
21
24
// dispatches from libuv
22
25
uv_async_init( [ u8 ] , * ctypes:: void ) ,
23
- uv_async_send( [ u8 ] )
26
+ uv_async_send( [ u8 ] ) ,
27
+ uv_close( [ u8 ] ) ,
28
+ uv_end( )
24
29
}
25
30
26
31
type uv_loop_data = {
@@ -65,7 +70,10 @@ native mod rustrt {
65
70
loop : * ctypes:: void ,
66
71
data : * uv_loop_data ) ;
67
72
fn rust_uvtmp_uv_bind_op_cb ( loop : * ctypes:: void , cb : * u8 ) -> * ctypes:: void ;
73
+ fn rust_uvtmp_uv_stop_op_cb ( handle : * ctypes:: void ) ;
68
74
fn rust_uvtmp_uv_run ( loop_handle : * ctypes:: void ) ;
75
+ fn rust_uvtmp_uv_close ( handle : * ctypes:: void , cb : * u8 ) ;
76
+ fn rust_uvtmp_uv_close_async ( handle : * ctypes:: void ) ;
69
77
fn rust_uvtmp_uv_async_send ( handle : * ctypes:: void ) ;
70
78
fn rust_uvtmp_uv_async_init (
71
79
loop_handle : * ctypes:: void ,
@@ -74,7 +82,8 @@ native mod rustrt {
74
82
}
75
83
76
84
mod uv {
77
- export loop_new, run, run_in_bg, async_init, async_send;
85
+ export loop_new, run, close, run_in_bg, async_init, async_send,
86
+ timer_init;
78
87
79
88
// public functions
80
89
fn loop_new ( ) -> uv_loop unsafe {
@@ -129,10 +138,14 @@ mod uv {
129
138
// all state goes here
130
139
let handles: map:: map < [ u8 ] , * ctypes:: void > =
131
140
map:: new_bytes_hash ( ) ;
132
- let async_cbs: map:: map < [ u8 ] , fn ~( uv_async ) > =
141
+ let id_to_handle: map:: map < [ u8 ] , uv_handle > =
142
+ map:: new_bytes_hash ( ) ;
143
+ let async_cbs: map:: map < [ u8 ] , fn ~( uv_handle ) > =
133
144
map:: new_bytes_hash ( ) ;
134
145
let async_init_after_cbs: map:: map < [ u8 ] ,
135
- fn ~( uv_async ) > =
146
+ fn ~( uv_handle ) > =
147
+ map:: new_bytes_hash ( ) ;
148
+ let close_callbacks: map:: map < [ u8 ] , fn ~( ) > =
136
149
map:: new_bytes_hash ( ) ;
137
150
138
151
// the main loop that this task blocks on.
@@ -152,7 +165,9 @@ mod uv {
152
165
rustrt:: rust_uvtmp_uv_run ( loop_handle) ;
153
166
// when we're done, msg the
154
167
// end chan
168
+ rustrt:: rust_uvtmp_uv_stop_op_cb ( op_handle) ;
155
169
comm:: send ( end_chan, true ) ;
170
+ comm:: send ( rust_loop_chan, uv_end) ;
156
171
} ;
157
172
}
158
173
@@ -163,6 +178,34 @@ mod uv {
163
178
} ;
164
179
}
165
180
181
+ msg_close ( handle, cb) {
182
+ let id = get_id_from_handle ( handle) ;
183
+ close_callbacks. insert ( id, cb) ;
184
+ let handle_ptr = handles. get ( id) ;
185
+ let op = op_close ( handle, handle_ptr) ;
186
+
187
+ pass_to_libuv ( op_handle, operation_chan, op) ;
188
+ }
189
+ uv_close ( id) {
190
+ handles. remove ( id) ;
191
+ let handle = id_to_handle. get ( id) ;
192
+ id_to_handle. remove ( id) ;
193
+ alt handle {
194
+ uv_async( id, _) {
195
+ async_cbs. remove ( id) ;
196
+ }
197
+ _ {
198
+ fail "unknown form of uv_handle encountered "
199
+ + "in uv_close handler" ;
200
+ }
201
+ }
202
+ let cb = close_callbacks. get ( id) ;
203
+ close_callbacks. remove( id) ;
204
+ task:: spawn { ||
205
+ cb( ) ;
206
+ } ;
207
+ }
208
+
166
209
msg_async_init ( callback, after_cb) {
167
210
// create a new async handle
168
211
// with the id as the handle's
@@ -172,9 +215,7 @@ mod uv {
172
215
async_cbs. insert ( id, callback) ;
173
216
async_init_after_cbs. insert ( id, after_cb) ;
174
217
let op = op_async_init ( id) ;
175
- comm:: send ( operation_chan, op) ;
176
- rustrt:: rust_uvtmp_uv_async_send ( op_handle) ;
177
- io:: println ( "MSG_ASYNC_INIT" ) ;
218
+ pass_to_libuv ( op_handle, operation_chan, op) ;
178
219
}
179
220
uv_async_init ( id, async_handle) {
180
221
// libuv created a handle, which is
@@ -184,22 +225,25 @@ mod uv {
184
225
handles. insert ( id, async_handle) ;
185
226
let after_cb = async_init_after_cbs. get ( id) ;
186
227
async_init_after_cbs. remove ( id) ;
228
+ let async = uv_async ( id, rust_loop_chan) ;
229
+ id_to_handle. insert ( id, copy ( async ) ) ;
187
230
task:: spawn { ||
188
- let async: uv_async = {
189
- id: id,
190
- loop : rust_loop_chan
191
- } ;
192
231
after_cb ( async ) ;
193
232
} ;
194
233
}
195
234
196
235
msg_async_send ( id) {
197
236
let async_handle = handles. get ( id) ;
198
- rustrt :: rust_uvtmp_uv_async_send ( async_handle) ;
237
+ do_send ( async_handle) ;
199
238
}
200
239
uv_async_send ( id) {
201
240
let async_cb = async_cbs. get ( id) ;
202
- async_cb ( { id: id, loop : rust_loop_chan} ) ;
241
+ task:: spawn { ||
242
+ async_cb ( uv_async ( id, rust_loop_chan) ) ;
243
+ } ;
244
+ }
245
+ uv_end ( ) {
246
+ keep_going = false ;
203
247
}
204
248
205
249
_ { fail "unknown form of uv_msg received" ; }
@@ -222,42 +266,91 @@ mod uv {
222
266
223
267
fn async_init (
224
268
loop : uv_loop ,
225
- async_cb : fn ~( uv_async ) ,
226
- after_cb : fn ~( uv_async ) ) {
269
+ async_cb : fn ~( uv_handle ) ,
270
+ after_cb : fn ~( uv_handle ) ) {
227
271
let msg = msg_async_init ( async_cb, after_cb) ;
228
272
comm:: send ( loop , msg) ;
229
273
}
230
274
231
- fn async_send ( async : uv_async ) {
232
- comm:: send ( async . loop , msg_async_send ( async . id) ) ;
275
+ fn async_send ( async : uv_handle ) {
276
+ alt async {
277
+ uv_async ( id, loop ) {
278
+ comm:: send ( loop , msg_async_send ( id) ) ;
279
+ }
280
+ _ {
281
+ fail "attempting to call async_send() with a" +
282
+ " uv_async uv_handle" ;
283
+ }
284
+ }
285
+ }
286
+
287
+ fn close ( h : uv_handle , cb : fn ~( ) ) {
288
+ let loop_chan = get_loop_chan_from_handle ( h) ;
289
+ comm:: send ( loop_chan, msg_close ( h, cb) ) ;
290
+ }
291
+
292
+ fn timer_init ( loop : uv_loop , after_cb : fn ~( uv_handle ) ) {
293
+ let msg = msg_timer_init ( after_cb) ;
294
+ comm:: send ( loop , msg) ;
233
295
}
234
296
235
297
// internal functions
298
+ fn pass_to_libuv (
299
+ op_handle : * ctypes:: void ,
300
+ operation_chan : comm:: chan < uv_operation > ,
301
+ op : uv_operation ) unsafe {
302
+ comm:: send ( operation_chan, copy ( op) ) ;
303
+ do_send ( op_handle) ;
304
+ }
305
+ fn do_send ( h : * ctypes:: void ) {
306
+ rustrt:: rust_uvtmp_uv_async_send ( h) ;
307
+ }
236
308
fn gen_handle_id ( ) -> [ u8 ] {
237
309
ret rand:: mk_rng ( ) . gen_bytes ( 16 u) ;
238
310
}
239
311
fn get_handle_id_from ( buf : * u8 ) -> [ u8 ] unsafe {
240
312
ret vec:: unsafe:: from_buf ( buf, 16 u) ;
241
313
}
242
314
243
- fn get_loop_chan_from ( data : * uv_loop_data )
244
- -> comm :: chan < uv_msg > unsafe {
315
+ fn get_loop_chan_from_data ( data : * uv_loop_data )
316
+ -> uv_loop unsafe {
245
317
ret ( * data) . rust_loop_chan ;
246
318
}
247
319
320
+ fn get_loop_chan_from_handle ( handle : uv_handle )
321
+ -> uv_loop {
322
+ alt handle {
323
+ uv_async( id, loop ) {
324
+ ret loop;
325
+ }
326
+ _ {
327
+ fail "unknown form of uv_handle for get_loop_chan_from "
328
+ + " handle" ;
329
+ }
330
+ }
331
+ }
332
+
333
+ fn get_id_from_handle ( handle : uv_handle ) -> [ u8 ] {
334
+ alt handle {
335
+ uv_async( id, loop ) {
336
+ ret id;
337
+ }
338
+ _ {
339
+ fail "unknown form of uv_handle for get_id_from handle" ;
340
+ }
341
+ }
342
+ }
343
+
248
344
// crust
249
345
crust fn process_operation (
250
346
loop : * ctypes:: void ,
251
347
data : * uv_loop_data ) unsafe {
252
- io:: println ( "IN PROCESS_OPERATION" ) ;
253
348
let op_port = ( * data) . operation_port ;
254
- let loop_chan = get_loop_chan_from ( data) ;
349
+ let loop_chan = get_loop_chan_from_data ( data) ;
255
350
let op_pending = comm:: peek ( op_port) ;
256
351
while ( op_pending) {
257
- io:: println ( "OPERATION PENDING!" ) ;
258
352
alt comm:: recv ( op_port) {
259
353
op_async_init ( id) {
260
- io:: println ( "OP_ASYNC_INIT" ) ;
261
354
let id_ptr = vec:: unsafe:: to_ptr ( id) ;
262
355
let async_handle = rustrt:: rust_uvtmp_uv_async_init (
263
356
loop ,
@@ -267,21 +360,61 @@ mod uv {
267
360
id,
268
361
async_handle) ) ;
269
362
}
363
+ op_close ( handle, handle_ptr) {
364
+ handle_op_close ( handle, handle_ptr) ;
365
+ }
270
366
271
367
_ { fail "unknown form of uv_operation received" ; }
272
368
}
273
369
op_pending = comm:: peek ( op_port) ;
274
370
}
275
- io:: println ( "NO MORE OPERATIONS PENDING!" ) ;
371
+ }
372
+
373
+ fn handle_op_close ( handle : uv_handle , handle_ptr : * ctypes:: void ) {
374
+ // it's just like im doing C
375
+ alt handle {
376
+ uv_async( id, loop ) {
377
+ let cb = process_close_async;
378
+ rustrt:: rust_uvtmp_uv_close (
379
+ handle_ptr, cb) ;
380
+ }
381
+ _ {
382
+ fail "unknown form of uv_handle encountered " +
383
+ "in process_operation/op_close" ;
384
+ }
385
+ }
276
386
}
277
387
278
388
crust fn process_async_send ( id_buf : * u8 , data : * uv_loop_data )
279
389
unsafe {
280
390
let handle_id = get_handle_id_from ( id_buf) ;
281
- let loop_chan = get_loop_chan_from ( data) ;
391
+ let loop_chan = get_loop_chan_from_data ( data) ;
282
392
comm:: send ( loop_chan, uv_async_send ( handle_id) ) ;
283
393
}
284
394
395
+ fn process_close_common ( id : [ u8 ] , data : * uv_loop_data )
396
+ unsafe {
397
+ // notify the rust loop that their handle is closed, then
398
+ // the caller will invoke a per-handle-type c++ func to
399
+ // free allocated memory
400
+ let loop_chan = get_loop_chan_from_data ( data) ;
401
+ comm:: send ( loop_chan, uv_close ( id) ) ;
402
+ }
403
+
404
+ crust fn process_close_async (
405
+ id_buf : * u8 ,
406
+ handle_ptr : * ctypes:: void ,
407
+ data : * uv_loop_data )
408
+ unsafe {
409
+ let id = get_handle_id_from ( id_buf) ;
410
+ rustrt:: rust_uvtmp_uv_close_async ( handle_ptr) ;
411
+ // at this point, the handle and its data has been
412
+ // released. notify the rust loop to remove the
413
+ // handle and its data and call the user-supplied
414
+ // close cb
415
+ process_close_common ( id, data) ;
416
+ }
417
+
285
418
286
419
}
287
420
@@ -295,14 +428,31 @@ fn test_uvtmp_uv_new_loop_no_handles() {
295
428
#[ test]
296
429
fn test_uvtmp_uv_simple_async ( ) {
297
430
let test_loop = uv:: loop_new ( ) ;
298
- let cb: fn ~( uv_async ) = fn ~( h: uv_async) {
299
- io:: println ( "HELLO FROM ASYNC CALLBACK!" ) ;
300
- } ;
301
- uv:: async_init ( test_loop, cb) { |new_async|
302
- io:: println ( "NEW_ASYNC CREATED!" ) ;
431
+ let exit_port = comm:: port :: < bool > ( ) ;
432
+ let exit_chan = comm:: chan :: < bool > ( exit_port) ;
433
+ uv:: async_init ( test_loop, { |new_async|
434
+ uv:: close ( new_async) { ||
435
+ comm:: send ( exit_chan, true ) ;
436
+ } ;
437
+ } , { |new_async|
303
438
uv:: async_send ( new_async) ;
304
- } ;
439
+ } ) ;
440
+ uv:: run ( test_loop) ;
441
+ assert comm:: recv ( exit_port) ;
442
+ }
443
+
444
+ #[ test]
445
+ fn test_uvtmp_uv_timer ( ) {
446
+ let test_loop = uv:: loop_new ( ) ;
447
+ let exit_port = comm:: port :: < bool > ( ) ;
448
+ let exit_chan = comm:: chan :: < bool > ( exit_port) ;
449
+ uv:: timer ( test_loop, { |new_timer|
450
+ uv:: timer_start ( new_async) { ||
451
+ comm:: send ( exit_chan, true ) ;
452
+ } ;
453
+ } ) ;
305
454
uv:: run ( test_loop) ;
455
+ assert comm:: recv ( exit_port) ;
306
456
}
307
457
308
458
// END OF UV2
0 commit comments