error("Not running in an async context, see http://prosody.im/doc/developers/async");
end
num = num or 1;
+ local waiting;
return function ()
+ if num == 0 then return; end -- already done
+ waiting = true;
coroutine.yield("wait");
end, function ()
num = num - 1;
- if num == 0 then
- if not runner_continue(thread) then
- error("done() called without wait()!");
+ if num == 0 and waiting then
+ runner_continue(thread);
+ elseif num < 0 then
+ error("done() called too many times");
+ end
+ end;
+end
+
+local function guarder()
+ local guards = {};
+ return function (id, func)
+ local thread = coroutine.running();
+ if not thread then
+ error("Not running in an async context, see http://prosody.im/doc/developers/async");
+ end
+ local guard = guards[id];
+ if not guard then
+ guard = {};
+ guards[id] = guard;
+ log("debug", "New guard!");
+ else
+ table.insert(guard, thread);
+ log("debug", "Guarded. %d threads waiting.", #guard)
+ coroutine.yield("wait");
+ end
+ local function exit()
+ local next_waiting = table.remove(guard, 1);
+ if next_waiting then
+ log("debug", "guard: Executing next waiting thread (%d left)", #guard)
+ runner_continue(next_waiting);
+ else
+ log("debug", "Guard off duty.")
+ guards[id] = nil;
end
end
+ if func then
+ func();
+ exit();
+ return;
+ end
+ return exit;
end;
end
n = #q;
end
self.state = state;
- if state ~= self.notified_state then
- self.notified_state = state;
+ if err or state ~= self.notified_state then
+ if err then
+ state = "error"
+ else
+ self.notified_state = state;
+ end
local handler = self.watchers[state];
if handler then handler(self, err); end
end
table.insert(self.queue, input);
end
-return { waiter = waiter, runner = runner };
+return { waiter = waiter, guarder = guarder, runner = runner };