Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(581)

Unified Diff: sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart

Issue 11864016: Support web workers in dart2js. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/isolate/count_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart (revision 17062)
+++ sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart (working copy)
@@ -162,10 +162,8 @@
bool isWorkerDefined = globalWorker != null;
isWorker = !isWindowDefined && globalPostMessageDefined;
- supportsWorkers = false;
- // TODO(7795): Enable web workers when Timers are supported.
- // supportsWorkers = isWorker
- // || (isWorkerDefined && IsolateNatives.thisScript != null);
+ supportsWorkers = isWorker
+ || (isWorkerDefined && IsolateNatives.thisScript != null);
fromCommandLine = !isWindowDefined && !isWorker;
}
@@ -183,9 +181,14 @@
}
- /** Close the worker running this code if all isolates are done. */
+ /**
+ * Close the worker running this code if all isolates are done and
+ * there is no active timer.
+ */
void maybeCloseWorker() {
- if (isolates.isEmpty) {
+ if (isWorker
+ && isolates.isEmpty
+ && topEventLoop.activeTimerCount == 0) {
mainManager.postMessage(_serializeMessage({'command': 'close'}));
}
}
@@ -209,8 +212,7 @@
}
/**
- * Run [code] in the context of the isolate represented by [this]. Note this
- * is called from JavaScript (see $wrap_call in corejs.dart).
+ * Run [code] in the context of the isolate represented by [this].
*/
dynamic eval(Function code) {
var old = _globalState.currentContext;
@@ -253,9 +255,10 @@
/** Represent the event loop on a javascript thread (DOM or worker). */
class _EventLoop {
- Queue<_IsolateEvent> events;
+ final Queue<_IsolateEvent> events = new Queue<_IsolateEvent>();
+ int activeTimerCount = 0;
- _EventLoop() : events = new Queue<_IsolateEvent>();
+ _EventLoop();
void enqueue(isolate, fn, msg) {
events.addLast(new _IsolateEvent(isolate, fn, msg));
@@ -266,26 +269,28 @@
return events.removeFirst();
}
+ void checkOpenReceivePortsFromCommandLine() {
+ if (_globalState.rootContext != null
+ && _globalState.isolates.containsKey(_globalState.rootContext.id)
erikcorry 2013/01/16 09:09:58 Style guide prefers && at the end of a line so thi
+ && _globalState.fromCommandLine
+ && _globalState.rootContext.ports.isEmpty) {
+ // We want to reach here only on the main [_Manager] and only
+ // on the command-line. In the browser the isolate might
+ // still be alive due to DOM callbacks, but the presumption is
+ // that on the command-line, no future events can be injected
+ // into the event queue once it's empty. Node has setTimeout
+ // so this presumption is incorrect there. We think(?) that
+ // in d8 this assumption is valid.
+ throw new Exception("Program exited with open ReceivePorts.");
+ }
+ }
+
/** Process a single event, if any. */
bool runIteration() {
final event = dequeue();
if (event == null) {
- if (_globalState.isWorker) {
- _globalState.maybeCloseWorker();
- } else if (_globalState.rootContext != null &&
- _globalState.isolates.containsKey(
- _globalState.rootContext.id) &&
- _globalState.fromCommandLine &&
- _globalState.rootContext.ports.isEmpty) {
- // We want to reach here only on the main [_Manager] and only
- // on the command-line. In the browser the isolate might
- // still be alive due to DOM callbacks, but the presumption is
- // that on the command-line, no future events can be injected
- // into the event queue once it's empty. Node has setTimeout
- // so this presumption is incorrect there. We think(?) that
- // in d8 this assumption is valid.
- throw new Exception("Program exited with open ReceivePorts.");
- }
+ checkOpenReceivePortsFromCommandLine();
+ _globalState.maybeCloseWorker();
return false;
}
event.process();
@@ -311,8 +316,7 @@
}
/**
- * Call [_runHelper] but ensure that worker exceptions are propragated. Note
- * this is called from JavaScript (see $wrap_call in corejs.dart).
+ * Call [_runHelper] but ensure that worker exceptions are propragated.
*/
void run() {
if (!_globalState.isWorker) {
@@ -434,9 +438,17 @@
_globalState.currentManagerId = msg['id'];
Function entryPoint = _getJSFunctionFromName(msg['functionName']);
var replyTo = _deserializeMessage(msg['replyTo']);
- _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
+ var context = new _IsolateContext();
+ _globalState.topEventLoop.enqueue(context, function() {
_startIsolate(entryPoint, replyTo);
}, 'worker-start');
+ // Make sure we always have a current context in this worker.
+ // TODO(7907): This is currently needed because we're using
+ // Timers to implement Futures, and this isolate library
+ // implementation uses Futures. We should either stop using
+ // Futures in this library, or re-adapt if Futures get a
+ // different implementation.
+ _globalState.currentContext = context;
_globalState.topEventLoop.run();
break;
case 'spawn-worker':
@@ -733,10 +745,15 @@
'replyTo': replyTo});
if (_globalState.isWorker) {
- // communication from one worker to another go through the main worker:
+ // Communication from one worker to another go through the
+ // main worker.
_globalState.mainManager.postMessage(workerMessage);
} else {
- _globalState.managers[_workerId].postMessage(workerMessage);
+ // Deliver the message only if the worker is still alive.
+ _ManagerStub manager = _globalState.managers[_workerId];
+ if (manager != null) {
+ manager.postMessage(workerMessage);
+ }
}
});
}
@@ -1250,48 +1267,67 @@
class TimerImpl implements Timer {
final bool _once;
+ bool _inEventLoop = false;
int _handle;
TimerImpl(int milliseconds, void callback(Timer timer))
: _once = true {
- if (hasTimer() && !_globalState.isWorker) {
- _handle = JS('int', '#.setTimeout(#, #)',
- globalThis,
- convertDartClosureToJS(() => callback(this), 0),
- milliseconds);
- } else if (milliseconds != 0) {
- throw new UnsupportedError("Non DOM isolate with timer greater than 0.");
- } else {
+ if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) {
// This makes a dependency between the async library and the
// event loop of the isolate library. The compiler makes sure
// that the event loop is compiled if [Timer] is used.
+ // TODO(7907): In case of web workers, we need to use the event
+ // loop instead of setTimeout, to make sure the futures get executed in
+ // order.
_globalState.topEventLoop.enqueue(_globalState.currentContext, () {
callback(this);
}, 'timer');
+ _inEventLoop = true;
+ } else if (hasTimer()) {
+ _globalState.topEventLoop.activeTimerCount++;
+ void internalCallback() {
+ callback(this);
+ _handle = null;
+ _globalState.topEventLoop.activeTimerCount--;
+ }
+ _handle = JS('int', '#.setTimeout(#, #)',
+ globalThis,
+ convertDartClosureToJS(internalCallback, 0),
+ milliseconds);
+ } else {
+ assert(milliseconds > 0);
+ throw new UnsupportedError("Timer greater than 0.");
}
}
TimerImpl.repeating(int milliseconds, void callback(Timer timer))
: _once = false {
- if (hasTimer() && !_globalState.isWorker) {
+ if (hasTimer()) {
+ _globalState.topEventLoop.activeTimerCount++;
_handle = JS('int', '#.setInterval(#, #)',
globalThis,
- convertDartClosureToJS(() => callback(this), 0),
+ convertDartClosureToJS(() { callback(this); }, 0),
milliseconds);
} else {
- throw new UnsupportedError("Non DOM isolate with repeating timer.");
+ throw new UnsupportedError("Repeating timer.");
}
}
void cancel() {
- if (hasTimer() && !_globalState.isWorker) {
+ if (hasTimer()) {
+ if (_inEventLoop) {
+ throw new UnsupportedError("Timer in event loop cannot be canceled.");
+ }
+ if (_handle == null) return;
+ _globalState.topEventLoop.activeTimerCount--;
if (_once) {
JS('void', '#.clearTimeout(#)', globalThis, _handle);
} else {
JS('void', '#.clearInterval(#)', globalThis, _handle);
}
+ _handle = null;
} else {
- throw new UnsupportedError("Canceling a timer on a non DOM isolate.");
+ throw new UnsupportedError("Canceling a timer.");
}
}
}
« no previous file with comments | « no previous file | tests/isolate/count_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698