@@ -110,18 +110,36 @@ pub mod futures_0_3;
110
110
use std:: cell:: { Cell , RefCell } ;
111
111
use std:: fmt;
112
112
use std:: rc:: Rc ;
113
+ #[ cfg( target_feature = "atomics" ) ]
113
114
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
114
115
use std:: sync:: Arc ;
116
+ #[ cfg( target_feature = "atomics" ) ]
117
+ use std:: sync:: Mutex ;
115
118
116
119
use futures:: executor:: { self , Notify , Spawn } ;
117
120
use futures:: future;
118
121
use futures:: prelude:: * ;
119
122
use futures:: sync:: oneshot;
120
- use js_sys:: { Atomics , Function , Int32Array , Promise , SharedArrayBuffer } ;
123
+ use js_sys:: { Function , Promise } ;
124
+ #[ cfg( target_feature = "atomics" ) ]
125
+ use js_sys:: { Atomics , Int32Array , SharedArrayBuffer , WebAssembly } ;
121
126
use wasm_bindgen:: prelude:: * ;
127
+ #[ cfg( target_feature = "atomics" ) ]
128
+ use wasm_bindgen:: JsCast ;
122
129
130
+ #[ cfg( target_feature = "atomics" ) ]
123
131
mod polyfill;
124
132
133
+ macro_rules! console_log {
134
+ ( $( $t: tt) * ) => ( log( & format_args!( $( $t) * ) . to_string( ) ) )
135
+ }
136
+
137
+ #[ wasm_bindgen]
138
+ extern "C" {
139
+ #[ wasm_bindgen( js_namespace = console) ]
140
+ fn log ( s : & str ) ;
141
+ }
142
+
125
143
/// A Rust `Future` backed by a JavaScript `Promise`.
126
144
///
127
145
/// This type is constructed with a JavaScript `Promise` object and translates
@@ -255,7 +273,8 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
255
273
resolve,
256
274
reject,
257
275
notified : Cell :: new ( State :: Notified ) ,
258
- waker : Arc :: new ( Waker :: new ( SharedArrayBuffer :: new ( 4 ) , false ) ) ,
276
+ #[ cfg( target_feature = "atomics" ) ]
277
+ waker : Arc :: new ( Waker :: new ( vec ! [ 0 ; 4 ] , false ) ) ,
259
278
} ) ) ;
260
279
} ) ;
261
280
@@ -275,6 +294,7 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
275
294
resolve : Function ,
276
295
reject : Function ,
277
296
297
+ #[ cfg( target_feature = "atomics" ) ]
278
298
// Struct to wake a future
279
299
waker : Arc < Waker > ,
280
300
}
@@ -307,38 +327,59 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
307
327
Waiting ( Arc < Package > ) ,
308
328
}
309
329
330
+ #[ cfg( target_feature = "atomics" ) ]
310
331
struct Waker {
311
- buffer : SharedArrayBuffer ,
332
+ array : Vec < i32 > ,
312
333
notified : AtomicBool ,
313
334
} ;
314
335
336
+ #[ cfg( target_feature = "atomics" ) ]
315
337
impl Waker {
316
- fn new ( buffer : SharedArrayBuffer , notified : bool ) -> Self {
317
- Self {
318
- buffer ,
338
+ fn new ( array : Vec < i32 > , notified : bool ) -> Self {
339
+ Waker {
340
+ array ,
319
341
notified : AtomicBool :: new ( notified) ,
320
342
}
321
343
}
322
344
}
323
345
346
+ #[ cfg( target_feature = "atomics" ) ]
324
347
impl Notify for Waker {
325
348
fn notify ( & self , id : usize ) {
349
+ console_log ! ( "Waker notify" ) ;
326
350
if !self . notified . swap ( true , Ordering :: SeqCst ) {
327
- let array = Int32Array :: new ( & self . buffer ) ;
351
+ console_log ! ( "Waker, inside if" ) ;
352
+ let memory_buffer = wasm_bindgen:: memory ( )
353
+ . dyn_into :: < WebAssembly :: Memory > ( )
354
+ . expect ( "Should cast a memory to WebAssembly::Memory" )
355
+ . buffer ( ) ;
356
+
357
+ let array_location = self . array . as_ptr ( ) as u32 / 4 ;
358
+ let array = Int32Array :: new ( & memory_buffer)
359
+ . subarray ( array_location, array_location + self . array . len ( ) as u32 ) ;
360
+
328
361
let _ = Atomics :: notify ( & array, id as u32 ) ;
329
362
}
330
363
}
331
364
}
332
365
366
+ #[ cfg( target_feature = "atomics" ) ]
333
367
fn poll_again ( package : Arc < Package > , id : usize ) {
368
+ console_log ! ( "poll_again called" ) ;
334
369
let me = match package. notified . replace ( State :: Notified ) {
335
370
// we need to schedule polling to resume, so keep going
336
- State :: Waiting ( me) => me,
371
+ State :: Waiting ( me) => {
372
+ console_log ! ( "poll_again Waiting" ) ;
373
+ me
374
+ } ,
337
375
338
376
// we were already notified, and were just notified again;
339
377
// having now coalesced the notifications we return as it's
340
378
// still someone else's job to process this
341
- State :: Notified => return ,
379
+ State :: Notified => {
380
+ console_log ! ( "poll_again Notified" ) ;
381
+ return ;
382
+ } ,
342
383
343
384
// the future was previously being polled, and we've just
344
385
// switched it to the "you're notified" state. We don't have
@@ -347,9 +388,21 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
347
388
// continue polling. For us, though, there's nothing else to do,
348
389
// so we bail out.
349
390
// later see
350
- State :: Polling => return ,
391
+ State :: Polling => {
392
+ console_log ! ( "poll_again Polling" ) ;
393
+ return ;
394
+ } ,
351
395
} ;
352
396
397
+ let memory_buffer = wasm_bindgen:: memory ( )
398
+ . dyn_into :: < WebAssembly :: Memory > ( )
399
+ . expect ( "Should cast a memory to WebAssembly::Memory" )
400
+ . buffer ( ) ;
401
+
402
+ let array_location = package. waker . array . as_ptr ( ) as u32 / 4 ;
403
+ let array = Int32Array :: new ( & memory_buffer)
404
+ . subarray ( array_location, array_location + package. waker . array . len ( ) as u32 ) ;
405
+
353
406
// Use `Promise.then` on a resolved promise to place our execution
354
407
// onto the next turn of the microtask queue, enqueueing our poll
355
408
// operation. We don't currently poll immediately as it turns out
@@ -358,19 +411,26 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
358
411
//
359
412
// Note that the `Rc`/`RefCell` trick here is basically to just
360
413
// ensure that our `Closure` gets cleaned up appropriately.
361
- let promise = polyfill:: wait_async ( Int32Array :: new ( & package . waker . buffer ) , id as u32 , 0 )
414
+ let promise = polyfill:: wait_async ( array , id as u32 , 0 )
362
415
. expect ( "Should create a Promise" ) ;
363
416
let slot = Rc :: new ( RefCell :: new ( None ) ) ;
364
417
let slot2 = slot. clone ( ) ;
365
418
let closure = Closure :: wrap ( Box :: new ( move |_| {
366
419
let myself = slot2. borrow_mut ( ) . take ( ) ;
367
420
debug_assert ! ( myself. is_some( ) ) ;
368
421
Package :: poll ( & me) ;
369
- } ) as Box < FnMut ( JsValue ) > ) ;
422
+ } ) as Box < dyn FnMut ( JsValue ) > ) ;
370
423
promise. then ( & closure) ;
371
424
* slot. borrow_mut ( ) = Some ( closure) ;
372
425
}
373
426
427
+ // No shared memory right now, wasm is single threaded, no need to worry
428
+ // about this!
429
+ #[ cfg( not( target_feature = "atomics" ) ) ]
430
+ unsafe impl Send for Package { }
431
+ #[ cfg( not( target_feature = "atomics" ) ) ]
432
+ unsafe impl Sync for Package { }
433
+
374
434
impl Package {
375
435
// Move the future contained in `me` as far forward as we can. This will
376
436
// do as much synchronous work as possible to complete the future,
@@ -386,7 +446,9 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
386
446
match me. notified . replace ( State :: Polling ) {
387
447
// We received a notification while previously polling, or
388
448
// this is the initial poll. We've got work to do below!
389
- State :: Notified => { }
449
+ State :: Notified => {
450
+ console_log ! ( "Package::poll Notified" ) ;
451
+ }
390
452
391
453
// We've gone through this loop once and no notification was
392
454
// received while we were executing work. That means we got
@@ -396,15 +458,31 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
396
458
// When the notification comes in it'll notify our task, see
397
459
// our `Waiting` state, and resume the polling process
398
460
State :: Polling => {
461
+ console_log ! ( "Package::poll Polling" ) ;
462
+
399
463
me. notified . set ( State :: Waiting ( me. clone ( ) ) ) ;
464
+
465
+ #[ cfg( target_feature = "atomics" ) ]
400
466
poll_again ( me. clone ( ) , 0 ) ;
467
+
401
468
break ;
402
469
}
403
470
404
- State :: Waiting ( _) => panic ! ( "shouldn't see waiting state!" ) ,
471
+ State :: Waiting ( _) => {
472
+ console_log ! ( "Package::poll Waiting" ) ;
473
+
474
+ panic ! ( "shouldn't see waiting state!" )
475
+ } ,
405
476
}
406
477
407
- let ( val, f) = match me. spawn . borrow_mut ( ) . poll_future_notify ( & me. waker , 0 ) {
478
+
479
+ #[ cfg( target_feature = "atomics" ) ]
480
+ let waker = & me. waker ;
481
+
482
+ #[ cfg( not( target_feature = "atomics" ) ) ]
483
+ let waker = me;
484
+
485
+ let ( val, f) = match me. spawn . borrow_mut ( ) . poll_future_notify ( waker, 0 ) {
408
486
// If the future is ready, immediately call the
409
487
// resolve/reject callback and then return as we're done.
410
488
Ok ( Async :: Ready ( value) ) => ( value, & me. resolve ) ,
@@ -420,6 +498,50 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
420
498
}
421
499
}
422
500
}
501
+
502
+ #[ cfg( not( target_feature = "atomics" ) ) ]
503
+ impl Notify for Package {
504
+ fn notify ( & self , _id : usize ) {
505
+ console_log ! ( "Package::notify Waiting" ) ;
506
+ let me = match self . notified . replace ( State :: Notified ) {
507
+ // we need to schedule polling to resume, so keep going
508
+ State :: Waiting ( me) => me,
509
+
510
+ // we were already notified, and were just notified again;
511
+ // having now coalesced the notifications we return as it's
512
+ // still someone else's job to process this
513
+ State :: Notified => return ,
514
+
515
+ // the future was previously being polled, and we've just
516
+ // switched it to the "you're notified" state. We don't have
517
+ // access to the future as it's being polled, so the future
518
+ // polling process later sees this notification and will
519
+ // continue polling. For us, though, there's nothing else to do,
520
+ // so we bail out.
521
+ // later see
522
+ State :: Polling => return ,
523
+ } ;
524
+
525
+ // Use `Promise.then` on a resolved promise to place our execution
526
+ // onto the next turn of the microtask queue, enqueueing our poll
527
+ // operation. We don't currently poll immediately as it turns out
528
+ // `futures` crate adapters aren't compatible with it and it also
529
+ // helps avoid blowing the stack by accident.
530
+ //
531
+ // Note that the `Rc`/`RefCell` trick here is basically to just
532
+ // ensure that our `Closure` gets cleaned up appropriately.
533
+ let promise = Promise :: resolve ( & JsValue :: undefined ( ) ) ;
534
+ let slot = Rc :: new ( RefCell :: new ( None ) ) ;
535
+ let slot2 = slot. clone ( ) ;
536
+ let closure = Closure :: wrap ( Box :: new ( move |_| {
537
+ let myself = slot2. borrow_mut ( ) . take ( ) ;
538
+ debug_assert ! ( myself. is_some( ) ) ;
539
+ Package :: poll ( & me) ;
540
+ } ) as Box < dyn FnMut ( JsValue ) > ) ;
541
+ promise. then ( & closure) ;
542
+ * slot. borrow_mut ( ) = Some ( closure) ;
543
+ }
544
+ }
423
545
}
424
546
425
547
/// Converts a Rust `Future` on a local task queue.
0 commit comments