@@ -100,21 +100,50 @@ var Aff = function () {
100
100
}
101
101
}
102
102
103
+ var schedule = function ( ) {
104
+ var limit = 1024 ;
105
+ var size = 0 ;
106
+ var ix = 0 ;
107
+ var queue = new Array ( limit ) ;
108
+ var draining = false ;
109
+
110
+ return function ( cb ) {
111
+ var i , thunk ;
112
+ if ( size === limit ) {
113
+ throw new Error ( "[Aff] Scheduler full" ) ;
114
+ }
115
+ queue [ ( ix + size ) % limit ] = cb ;
116
+ size ++ ;
117
+
118
+ if ( ! draining ) {
119
+ draining = true ;
120
+ while ( size ) {
121
+ size -- ;
122
+ thunk = queue [ ix ] ;
123
+ queue [ ix ] = void 0 ;
124
+ ix = ( ix + 1 ) % limit ;
125
+ thunk ( ) ;
126
+ }
127
+ draining = false ;
128
+ }
129
+ } ;
130
+ } ( ) ;
131
+
103
132
// Fiber state machine
104
- var BLOCKED = 0 ; // No effect is running .
105
- var PENDING = 1 ; // An async effect is running .
106
- var RETURN = 2 ; // The current stack has returned .
107
- var CONTINUE = 3 ; // Run the next effect.
108
- var BINDSTEP = 4 ; // Apply the next bind .
133
+ var SUSPENDED = 0 ; // Suspended, pending a join .
134
+ var CONTINUE = 1 ; // Interpret the next instruction .
135
+ var BINDSTEP = 2 ; // Apply the next bind .
136
+ var PENDING = 3 ; // An async effect is running .
137
+ var RETURN = 4 ; // The current stack has returned .
109
138
var KILLFORKS = 5 ; // Killing supervised forks.
110
139
var COMPLETED = 6 ; // The entire fiber has completed.
111
140
112
- function runFiber ( util , suspended , aff , completeCb ) {
141
+ function runFiber ( util , initStatus , aff , completeCb ) {
113
142
// Monotonically increasing tick, increased on each asynchronous turn.
114
143
var runTick = 0 ;
115
144
116
145
// The current branch of the state machine.
117
- var status = CONTINUE ;
146
+ var status = initStatus ;
118
147
119
148
// The current point of interest for the state machine branch.
120
149
var step = aff ; // Successful step
@@ -146,10 +175,10 @@ var Aff = function () {
146
175
// Temporary bindings for the various branches.
147
176
var tmp , result , attempt , canceler ;
148
177
149
- function launchChildFiber ( fid , suspended , child ) {
178
+ function launchChildFiber ( fid , childStatus , child ) {
150
179
forkCount ++ ;
151
180
var blocked = true ;
152
- var fiber = runFiber ( util , suspended , child , function ( ) {
181
+ var fiber = runFiber ( util , childStatus , child , function ( ) {
153
182
forkCount -- ;
154
183
if ( blocked ) {
155
184
blocked = false ;
@@ -178,7 +207,7 @@ var Aff = function () {
178
207
forks = { } ;
179
208
forkCount = 0 ;
180
209
for ( var i = 0 , len = killId ; i < len ; i ++ ) {
181
- kills [ i ] = runFiber ( util , false , kills [ i ] , function ( ) {
210
+ kills [ i ] = runFiber ( util , CONTINUE , kills [ i ] , function ( ) {
182
211
delete kills [ i ] ;
183
212
killId -- ;
184
213
if ( killId === 0 ) {
@@ -190,7 +219,7 @@ var Aff = function () {
190
219
return new Aff ( SYNC , function ( ) {
191
220
for ( var k in kills ) {
192
221
if ( kills . hasOwnProperty ( k ) ) {
193
- runFiber ( util , false , kills [ k ] . kill ( error ) , function ( ) { } ) ;
222
+ runFiber ( util , CONTINUE , kills [ k ] . kill ( error ) , function ( ) { } ) ;
194
223
}
195
224
}
196
225
} ) ;
@@ -252,7 +281,6 @@ var Aff = function () {
252
281
break ;
253
282
254
283
case SYNC :
255
- status = BLOCKED ;
256
284
result = runSync ( util . left , util . right , step . _1 ) ;
257
285
if ( util . isLeft ( result ) ) {
258
286
status = RETURN ;
@@ -267,41 +295,30 @@ var Aff = function () {
267
295
break ;
268
296
269
297
case ASYNC :
270
- status = BLOCKED ;
271
- canceler = runAsync ( util . left , step . _1 , function ( result ) {
298
+ status = PENDING ;
299
+ step = runAsync ( util . left , step . _1 , function ( result ) {
272
300
return function ( ) {
273
301
if ( runTick !== localRunTick ) {
274
302
return ;
275
- }
276
- tmp = status ;
277
- if ( util . isLeft ( result ) ) {
278
- status = RETURN ;
279
- fail = result ;
280
- } else if ( bhead === null ) {
281
- status = RETURN ;
282
- step = result ;
283
303
} else {
284
- status = BINDSTEP ;
285
- step = util . fromRight ( result ) ;
286
- }
287
- // We only need to invoke `run` if the subsequent block has
288
- // switch the status to PENDING. Otherwise the callback was
289
- // resolved synchronously, and the current loop can continue
290
- // normally.
291
- if ( tmp === PENDING ) {
292
- run ( ++ runTick ) ;
293
- } else {
294
- localRunTick = ++ runTick ;
304
+ runTick ++ ;
295
305
}
306
+ schedule ( function ( ) {
307
+ if ( util . isLeft ( result ) ) {
308
+ status = RETURN ;
309
+ fail = result ;
310
+ } else if ( bhead === null ) {
311
+ status = RETURN ;
312
+ step = result ;
313
+ } else {
314
+ status = BINDSTEP ;
315
+ step = util . fromRight ( result ) ;
316
+ }
317
+ run ( runTick ) ;
318
+ } ) ;
296
319
} ;
297
320
} ) ;
298
- // If the callback was resolved synchronously, the status will have
299
- // switched to CONTINUE, and we should not move on to PENDING.
300
- if ( status === BLOCKED ) {
301
- status = PENDING ;
302
- step = canceler ;
303
- }
304
- break ;
321
+ return ;
305
322
306
323
// Enqueue the current stack of binds and continue
307
324
case CATCH :
@@ -375,7 +392,7 @@ var Aff = function () {
375
392
}
376
393
break ;
377
394
378
- // If we have a bracket, we should enqueue the finalizer branch ,
395
+ // If we have a bracket, we should enqueue the handlers ,
379
396
// and continue with the success branch only if the fiber has
380
397
// not been interrupted. If the bracket acquisition failed, we
381
398
// should not run either.
@@ -393,6 +410,8 @@ var Aff = function () {
393
410
}
394
411
break ;
395
412
413
+ // Enqueue the appropriate handler. We increase the bracket count
414
+ // because it should be cancelled.
396
415
case BRACKETED :
397
416
bracket ++ ;
398
417
attempts = new Aff ( CONS , new Aff ( FINALIZED , step ) , attempts . _2 ) ;
@@ -447,14 +466,16 @@ var Aff = function () {
447
466
if ( util . isLeft ( step ) && ! joins ) {
448
467
setTimeout ( function ( ) {
449
468
// Guard on joins because a completely synchronous fiber can
450
- // still have an observer.
469
+ // still have an observer which was added after-the-fact .
451
470
if ( ! joins ) {
452
471
throw util . fromLeft ( step ) ;
453
472
}
454
473
} , 0 ) ;
455
474
}
456
475
return ;
457
- case BLOCKED : return ;
476
+ case SUSPENDED :
477
+ status = CONTINUE ;
478
+ break ;
458
479
case PENDING : return ;
459
480
}
460
481
}
@@ -479,12 +500,11 @@ var Aff = function () {
479
500
var killCb = function ( ) {
480
501
return cb ( util . right ( void 0 ) ) ;
481
502
} ;
482
- if ( suspended ) {
483
- suspended = false ;
503
+ switch ( status ) {
504
+ case SUSPENDED :
484
505
status = COMPLETED ;
485
506
interrupt = util . left ( error ) ;
486
- }
487
- switch ( status ) {
507
+ /* fallthrough */
488
508
case COMPLETED :
489
509
canceler = nonCanceler ;
490
510
killCb ( ) ( ) ;
@@ -524,20 +544,25 @@ var Aff = function () {
524
544
525
545
var join = new Aff ( ASYNC , function ( cb ) {
526
546
return function ( ) {
527
- if ( suspended ) {
528
- suspended = false ;
547
+ var canceler ;
548
+ switch ( status ) {
549
+ case SUSPENDED :
550
+ canceler = addJoinCallback ( cb ) ;
529
551
run ( runTick ) ;
530
- }
531
- if ( status === COMPLETED ) {
532
- joins = true ;
552
+ break ;
553
+ case COMPLETED :
554
+ canceler = nonCanceler ;
555
+ joins = true ;
533
556
cb ( step ) ( ) ;
534
- return nonCanceler ;
557
+ break ;
558
+ default :
559
+ canceler = addJoinCallback ( cb ) ;
535
560
}
536
- return addJoinCallback ( cb ) ;
561
+ return canceler ;
537
562
} ;
538
563
} ) ;
539
564
540
- if ( suspended === false ) {
565
+ if ( status === CONTINUE ) {
541
566
run ( runTick ) ;
542
567
}
543
568
@@ -592,7 +617,7 @@ var Aff = function () {
592
617
// collect all the fibers first.
593
618
kills [ count ++ ] = function ( aff ) {
594
619
return function ( ) {
595
- return runFiber ( util , false , aff , function ( result ) {
620
+ return runFiber ( util , CONTINUE , aff , function ( result ) {
596
621
count -- ;
597
622
if ( fail === null && util . isLeft ( result ) ) {
598
623
fail = result ;
@@ -817,7 +842,7 @@ var Aff = function () {
817
842
// tree.
818
843
fibers [ fid ] = function ( aff , completeCb ) {
819
844
return new Aff ( THUNK , function ( ) {
820
- return runFiber ( util , false , aff , completeCb ) ;
845
+ return runFiber ( util , CONTINUE , aff , completeCb ) ;
821
846
} ) ;
822
847
} ( tmp , resolve ( step ) ) ;
823
848
}
@@ -869,7 +894,7 @@ var Aff = function () {
869
894
// We can drop the fibers here because we are only canceling join
870
895
// attempts, which are synchronous anyway.
871
896
for ( var kid = 0 , n = killId ; kid < n ; kid ++ ) {
872
- runFiber ( util , false , kills [ kid ] . kill ( error ) , function ( ) { } ) ;
897
+ runFiber ( util , CONTINUE , kills [ kid ] . kill ( error ) , function ( ) { } ) ;
873
898
}
874
899
875
900
var newKills = kill ( error , root , cb ) ;
@@ -879,7 +904,7 @@ var Aff = function () {
879
904
return function ( ) {
880
905
for ( var kid in newKills ) {
881
906
if ( newKills . hasOwnProperty ( kid ) ) {
882
- runFiber ( util , false , newKills [ kid ] . kill ( killError ) , function ( ) { } ) ;
907
+ runFiber ( util , CONTINUE , newKills [ kid ] . kill ( killError ) , function ( ) { } ) ;
883
908
}
884
909
}
885
910
return nonCanceler ;
@@ -945,9 +970,9 @@ exports._bind = function (aff) {
945
970
} ;
946
971
} ;
947
972
948
- exports . _fork = function ( suspended ) {
973
+ exports . _fork = function ( status ) {
949
974
return function ( aff ) {
950
- return Aff . Fork ( suspended , aff ) ;
975
+ return Aff . Fork ( status , aff ) ;
951
976
} ;
952
977
} ;
953
978
@@ -1026,9 +1051,9 @@ exports._delay = function () {
1026
1051
} ;
1027
1052
} ( ) ;
1028
1053
1029
- exports . _launchAff = function ( util , suspended , aff ) {
1054
+ exports . _launchAff = function ( util , status , aff ) {
1030
1055
return function ( ) {
1031
- return Aff . runFiber ( util , suspended , aff , function ( ) { } ) ;
1056
+ return Aff . runFiber ( util , status , aff , function ( ) { } ) ;
1032
1057
} ;
1033
1058
} ;
1034
1059
0 commit comments