Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

This closes #11. Add extra warnings and seat-belts when awaits and

defers are being abused, like with mutliple calls per deferral, or a
reentry to a dead await block.  We still want to allo multi-use of a
deferral, and do that in the case of a Rendezvous with the id(1,true)
feature.
  • Loading branch information...
commit 040674ed4613176276ffc1b323781bd4fd3379b5 1 parent ff90140
@maxtaco authored
View
8 iced.md
@@ -593,7 +593,7 @@ control flows, so we've included it in the main runtime library.
The `Rendezvous` is similar to a blocking condition variable (or a
"Hoare sytle monitor") in threaded programming.
-#### iced.Rendezvous.id(i).defer slots...
+#### iced.Rendezvous.id(i,[multi]).defer slots...
Associate a new deferral with the given Rendezvous, whose deferral ID
is `i`, and whose callbacks slots are supplied as `slots`. Those
@@ -603,6 +603,12 @@ fed to a function expecting a callback. As soon as that callback
fires (and the deferral is fulfilled), the provided slots will be
filled with the arguments to that callback.
+Also, note the optional boolean flag `multi`. By default, a function
+generated by `defer` can be called only once, and will generate an
+error on subsequent calls. Only with the `mutli` flag set to `true`
+(and only in the case of a `Rendezvous`), can this restriction be
+relaxed.
+
#### iced.Rendezvous.defer slots...
You don't need to explicitly assign an ID to a deferral generated from a
View
32 lib/coffee-script/iced.js
@@ -36,7 +36,7 @@
catchExceptions: 'catchExceptions',
runtime_modes: ["node", "inline", "window", "none"]
};
- intern.makeDeferReturn = function(obj, defer_args, id, trace_template) {
+ intern.makeDeferReturn = function(obj, defer_args, id, trace_template, multi) {
var k, ret, trace, v;
trace = {};
for (k in trace_template) {
@@ -45,12 +45,18 @@
}
trace[C.lineno] = defer_args != null ? defer_args[C.lineno] : void 0;
ret = function() {
- var inner_args, _ref;
+ var inner_args, o, _ref;
inner_args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (defer_args != null) {
if ((_ref = defer_args.assign_fn) != null) _ref.apply(null, inner_args);
}
- return obj._fulfill(id, trace);
+ if (obj) {
+ o = obj;
+ if (!multi) obj = null;
+ return o._fulfill(id, trace);
+ } else {
+ return intern._warn("deferral was is dead at " + (intern._trace_to_string(trace)));
+ }
};
ret[C.trace] = trace;
return ret;
@@ -72,9 +78,7 @@
return "" + fn + " (" + tr[C.filename] + ":" + (tr[C.lineno] + 1) + ")";
};
intern._warn = function(m) {
- if (typeof console !== "undefined" && console !== null) {
- return console.log("ICED warning: " + m);
- }
+ return typeof console !== "undefined" && console !== null ? console.log("ICED warning: " + m) : void 0;
};
runtime.Deferrals = Deferrals = (function() {
@@ -95,7 +99,7 @@
this.continuation = null;
return c(this.ret);
} else {
- return intern._warn("Deferral underrun for " + (intern._trace_to_string(this.trace)));
+ return intern._warn("Entered dead Deferral at " + (intern._trace_to_string(trace)));
}
};
@@ -148,13 +152,14 @@
RvId.name = 'RvId';
- function RvId(rv, id) {
+ function RvId(rv, id, multi) {
this.rv = rv;
this.id = id;
+ this.multi = multi;
}
RvId.prototype.defer = function(defer_args) {
- return this.rv._deferWithId(this.id, defer_args);
+ return this.rv._deferWithId(this.id, defer_args, this.multi);
};
return RvId;
@@ -177,10 +182,11 @@
return this.deferWithId(id, defer_args);
};
- Rendezvous.prototype.id = function(i) {
+ Rendezvous.prototype.id = function(i, multi) {
var ret;
+ if (multi == null) multi = false;
ret = {};
- ret[C.deferrals] = new RvId(this, i);
+ ret[C.deferrals] = new RvId(this, i, multi);
return ret;
};
@@ -194,9 +200,9 @@
}
};
- Rendezvous.prototype._deferWithId = function(id, defer_args) {
+ Rendezvous.prototype._deferWithId = function(id, defer_args, multi) {
this.count++;
- return intern.makeDeferReturn(this, defer_args, id, {});
+ return intern.makeDeferReturn(this, defer_args, id, {}, multi);
};
return Rendezvous;
View
29 src/iced.coffee
@@ -53,7 +53,7 @@ exports.generator = generator = (intern, compiletime, runtime) ->
#
# Support and libraries for runtime behavior
#
- intern.makeDeferReturn = (obj, defer_args, id, trace_template) ->
+ intern.makeDeferReturn = (obj, defer_args, id, trace_template, multi) ->
trace = {}
for k,v of trace_template
@@ -62,7 +62,12 @@ exports.generator = generator = (intern, compiletime, runtime) ->
ret = (inner_args...) ->
defer_args?.assign_fn?.apply(null, inner_args)
- obj._fulfill id, trace
+ if obj
+ o = obj
+ obj = null unless multi
+ o._fulfill id, trace
+ else
+ intern._warn "deferral was is dead at #{intern._trace_to_string trace}"
ret[C.trace] = trace
@@ -90,8 +95,7 @@ exports.generator = generator = (intern, compiletime, runtime) ->
"#{fn} (#{tr[C.filename]}:#{tr[C.lineno] + 1})"
intern._warn = (m) ->
- if console?
- console.log "ICED warning: #{m}"
+ console?.log "ICED warning: #{m}"
#### Deferrals
#
@@ -113,7 +117,7 @@ exports.generator = generator = (intern, compiletime, runtime) ->
@continuation = null
c @ret
else
- intern._warn "Deferral underrun for #{intern._trace_to_string @trace}"
+ intern._warn "Entered dead Deferral at #{intern._trace_to_string trace}"
_fulfill : (id, trace) ->
if --@count > 0
@@ -156,9 +160,9 @@ exports.generator = generator = (intern, compiletime, runtime) ->
# RvId -- A helper class the allows deferalls to take on an ID
# when used with Rendezvous
class RvId
- constructor: (@rv,@id)->
+ constructor: (@rv,@id,@multi)->
defer: (defer_args) ->
- @rv._deferWithId @id, defer_args
+ @rv._deferWithId @id, defer_args, @multi
# Public interface
#
@@ -175,9 +179,12 @@ exports.generator = generator = (intern, compiletime, runtime) ->
id = @defer_id++
@deferWithId id, defer_args
- id: (i) ->
+ # id -- assign an ID to a deferral, and also toggle the multi
+ # bit on the deferral. By default, this bit is off.
+ id: (i, multi) ->
+ multi = false unless multi?
ret = {}
- ret[C.deferrals] = new RvId(this, i)
+ ret[C.deferrals] = new RvId(this, i, multi)
ret
# Private Interface
@@ -189,9 +196,9 @@ exports.generator = generator = (intern, compiletime, runtime) ->
else
@completed.push id
- _deferWithId: (id, defer_args) ->
+ _deferWithId: (id, defer_args, multi) ->
@count++
- intern.makeDeferReturn this, defer_args, id, {}
+ intern.makeDeferReturn this, defer_args, id, {}, multi
#### stackWalk
#
View
20 test/iced_advanced.coffee
@@ -130,3 +130,23 @@ if require?
await foo defer()
cb(check, {})
+
+##----------------------------------------------------------------------
+
+ atest "multi", (cb) ->
+
+ fun = (c) ->
+ await setTimeout defer(), 10
+ c()
+ await setTimeout defer(), 10
+ c()
+
+ rv = new iced.Rendezvous
+ c = rv.id(1,true).defer()
+ fun(c)
+ await rv.wait defer()
+ await rv.wait defer()
+ cb(true, {})
+
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.