Skip to content
Browse files

implemented future cancellation in generators runtime

  • Loading branch information...
1 parent 6f375c7 commit 7fec8256e07f44419e2f5d26641ec9cd5a077b92 @bjouhier bjouhier committed Jun 14, 2012
Showing with 51 additions and 62 deletions.
  1. +51 −62 lib/generators/runtime.js
View
113 lib/generators/runtime.js
@@ -9,35 +9,14 @@ if (typeof console === 'undefined') global.console = {
// container for the context that the runtime maintains across async calls
var globals = require('streamline/lib/globals');
+var future = require("streamline/lib/util/future").future;
(function(exports) {
function trap(ex) {
if (globals.context && globals.context.errorHandler) globals.context.errorHandler(ex);
else throw ex;
}
-
- function future(fn, args, i) {
- var err, result, done, q = [];
- args = Array.prototype.slice.call(args);
- args[i] = function(e, r) {
- err = e, result = r, done = true;
- q && q.forEach(function(f) {
- try {
- f(e, r);
- } catch (ex) {
- trap(ex);
- }
- });
- q = null;
- };
- fn.apply(this, args);
- return function memoize(cb) {
- if (!cb) return memoize;
- if (done) cb(err, result);
- else q.push(cb)
- }
- }
-
+
var GENERATOR_PROTO = Object.getPrototypeOf((function() {
yield;
})());
@@ -50,54 +29,64 @@ var globals = require('streamline/lib/globals');
function run(fn, args, idx) {
var cb = args[idx],
- g, cx = globals.context;
+ g, cx = globals.context,
+ fut = globals.future;
function resume(err, val) {
+ for (var f = fut; f; f = f.prev) {
+ if (f.cancelled) err = new Error("cancelled");
+ }
globals.context = cx;
- while (g) {
- try {
- val = err ? g.throw(err) : g.send(val);
- err = null;
- // if we get PENDING, the current call completed with a pending I/O
- // resume will be called again when the I/O completes. So just save the context and return here.
- if (val === PENDING) {
- cx = globals.context;
- return;
- }
- // if we get [PENDING, e, r], the current call invoked its callback synchronously
- // we just loop to send/throw what the callback gave us.
- if (val && val[0] === PENDING) {
- err = val[1];
- val = val[2];
- }
- // else, if g yielded a value which is not a generator, g is done.
- // so we unwind it we send val to the parent generator (or through cb if we are at the top)
- else if (!isGenerator(val)) {
+ var oldFut = globals.future;
+ globals.future = fut;
+ try {
+ while (g) {
+ try {
+ val = err ? g.throw(err) : g.send(val);
+ err = null;
+ // if we get PENDING, the current call completed with a pending I/O
+ // resume will be called again when the I/O completes. So just save the context and return here.
+ if (val === PENDING) {
+ cx = globals.context;
+ return;
+ }
+ // if we get [PENDING, e, r], the current call invoked its callback synchronously
+ // we just loop to send/throw what the callback gave us.
+ if (val && val[0] === PENDING) {
+ err = val[1];
+ val = val[2];
+ }
+ // else, if g yielded a value which is not a generator, g is done.
+ // so we unwind it we send val to the parent generator (or through cb if we are at the top)
+ else if (!isGenerator(val)) {
+ g.close();
+ g = g.prev;
+ }
+ // else, we got a new generator which means that g called another generator function
+ // the new generator become current and we loop with g.send(undefined) (equiv to g.next())
+ else {
+ val.prev = g;
+ g = val;
+ val = undefined;
+ }
+ } catch (ex) {
+ // the send/throw call failed.
+ // we unwind the current generator and we rethrow into the parent generator (or through cb if at the top)
g.close();
g = g.prev;
- }
- // else, we got a new generator which means that g called another generator function
- // the new generator become current and we loop with g.send(undefined) (equiv to g.next())
- else {
- val.prev = g;
- g = val;
+ err = makeError(ex);
val = undefined;
}
+ }
+ // we have exhausted the stack of generators.
+ // return the result or error through the callback.
+ try {
+ cb(err, val);
} catch (ex) {
- // the send/throw call failed.
- // we unwind the current generator and we rethrow into the parent generator (or through cb if at the top)
- g.close();
- g = g.prev;
- err = makeError(ex);
- val = undefined;
+ trap(ex);
}
- }
- // we have exhausted the stack of generators.
- // return the result or error through the callback.
- try {
- cb(err, val);
- } catch (ex) {
- trap(ex);
+ } finally {
+ globals.future = oldFut;
}
}
// set resume as the new callback

0 comments on commit 7fec825

Please sign in to comment.
Something went wrong with that request. Please try again.