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

Side by Side Diff: frog/lib/isolate.dart

Issue 9317068: isolate lib: small refactor to distinguish protocols at the port level (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: '' Created 8 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * A native object that is shared across isolates. This object is visible to all 6 * A native object that is shared across isolates. This object is visible to all
7 * isolates running on the same worker (either UI or background web worker). 7 * isolates running on the same worker (either UI or background web worker).
8 * 8 *
9 * This is code that is intended to 'escape' the isolate boundaries in order to 9 * This is code that is intended to 'escape' the isolate boundaries in order to
10 * implement the semantics of friendly isolates in JavaScript. Without this we 10 * implement the semantics of friendly isolates in JavaScript. Without this we
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 Function fn; 319 Function fn;
320 String message; 320 String message;
321 321
322 IsolateEvent(this.isolate, this.fn, this.message); 322 IsolateEvent(this.isolate, this.fn, this.message);
323 323
324 void process() { 324 void process() {
325 isolate.eval(fn); 325 isolate.eval(fn);
326 } 326 }
327 } 327 }
328 328
329 /** Implementation of a send port on top of JavaScript. */ 329 /** Common functionality to all send ports. */
330 class SendPortImpl implements SendPort { 330 class BaseSendPort implements SendPort {
331 /** Id for the destination isolate. */
332 final int _isolateId;
331 333
332 const SendPortImpl(this._workerId, this._isolateId, this._receivePortId); 334 BaseSendPort(this._isolateId);
333
334 void send(var message, [SendPort replyTo = null]) {
335 if (replyTo !== null && !(replyTo is SendPortImpl)) {
336 throw "SendPort::send: Illegal replyTo type.";
337 }
338 IsolateNatives._sendMessage(_workerId, _isolateId, _receivePortId,
339 _serializeMessage(message), _serializeMessage(replyTo));
340 }
341
342 // TODO(sigmund): get rid of _sendNow (still used in corelib code)
343 void _sendNow(var message, replyTo) { send(message, replyTo); }
344 335
345 ReceivePortSingleShotImpl call(var message) { 336 ReceivePortSingleShotImpl call(var message) {
346 final result = new ReceivePortSingleShotImpl(); 337 final result = new ReceivePortSingleShotImpl();
347 this.send(message, result.toSendPort()); 338 this.send(message, result.toSendPort());
348 return result; 339 return result;
349 } 340 }
350 341
351 ReceivePortSingleShotImpl _callNow(var message) { 342 static void checkReplyTo(SendPort replyTo) {
352 final result = new ReceivePortSingleShotImpl(); 343 if (replyTo !== null && replyTo is! NativeJsSendPort
353 send(message, result.toSendPort()); 344 && replyTo is! WorkerSendPort) {
354 return result; 345 throw "SendPort.send: Illegal replyTo port type.";
346 }
355 } 347 }
356 348
357 bool operator==(var other) { 349 // TODO(sigmund): replace the current SendPort.call with the following:
358 return (other is SendPortImpl) && 350 //Future call(var message) {
351 //  final completer = new Completer();
352 //  final port = new ReceivePort.singleShot();
353 //  send(message, port.toSendPort());
354 //  port.receive((value, ignoreReplyTo) {
355 //    if (value is Exception) {
356 //  completer.completeException(value);
357 // } else {
358 // completer.complete(value);
359 // }
360 // });
361 //  return completer.future;
362 //}
363
364 abstract void send(var message, [SendPort replyTo]);
365 abstract bool operator ==(var other);
366 abstract int hashCode();
367 }
368
369 /** A send port that delivers messages in-memory via native JavaScript calls. */
370 class NativeJsSendPort extends BaseSendPort implements SendPort {
371 final ReceivePortImpl _receivePort;
372
373 const NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId);
374
375 void send(var message, [SendPort replyTo = null]) {
376 checkReplyTo(replyTo);
377 // Check that the isolate still runs and the port is still open
378 final isolate = _globalState.isolates[_isolateId];
379 if (isolate == null) return;
380 if (_receivePort._callback == null) return;
381
382 // We force serialization/deserialization as a simple way to ensure isolate
383 // communication restrictions are respected between isolates that live in
384 // the same worker. NativeJsSendPort delivers both messages from the same
385 // worker and messages from other workers. In particular, messages sent from
386 // a worker via a WorkerSendPort are received at [_processWorkerMessage] and
387 // forwarded to a native port. In such cases, here we'll see
388 // [_globalState.currentContext == null].
389 final shouldSerialize = _globalState.currentContext != null
390 && _globalState.currentContext.id != _isolateId;
391 var msg = message;
392 var reply = replyTo;
393 if (shouldSerialize) {
394 msg = _serializeMessage(msg);
395 reply = _serializeMessage(reply);
396 }
397 _globalState.topEventLoop.enqueue(isolate, () {
398 if (_receivePort._callback != null) {
399 if (shouldSerialize) {
400 msg = _deserializeMessage(msg);
401 reply = _deserializeMessage(reply);
402 }
403 _receivePort._callback(msg, reply);
404 }
405 }, 'receive ' + message);
406 }
407
408 bool operator ==(var other) => (other is NativeJsSendPort) &&
409 (_receivePort == other._receivePort);
410
411 int hashCode() => _receivePort._id;
412 }
413
414 /** A send port that delivers messages via worker.postMessage. */
415 class WorkerSendPort extends BaseSendPort implements SendPort {
416 final int _workerId;
417 final int _receivePortId;
418
419 const WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
420 : super(isolateId);
421
422 void send(var message, [SendPort replyTo = null]) {
423 checkReplyTo(replyTo);
424 final workerMessage = _serializeMessage({
425 'command': 'message',
426 'port': this,
427 'msg': message,
428 'replyTo': replyTo});
429
430 if (_globalState.isWorker) {
431 // communication from one worker to another go through the main worker:
432 _globalState.mainWorker.postMessage(workerMessage);
433 } else {
434 _globalState.workers[_workerId].postMessage(workerMessage);
435 }
436 }
437
438 bool operator ==(var other) {
439 return (other is WorkerSendPort) &&
359 (_workerId == other._workerId) && 440 (_workerId == other._workerId) &&
360 (_isolateId == other._isolateId) && 441 (_isolateId == other._isolateId) &&
361 (_receivePortId == other._receivePortId); 442 (_receivePortId == other._receivePortId);
362 } 443 }
363 444
364 int hashCode() { 445 int hashCode() {
446 // TODO(sigmund): use a standard hash when we get one available in corelib.
365 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; 447 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId;
366 } 448 }
367
368 final int _receivePortId;
369 final int _isolateId;
370 final int _workerId;
371 } 449 }
372 450
373 /** Default factory for receive ports. */ 451 /** Default factory for receive ports. */
374 class ReceivePortFactory { 452 class ReceivePortFactory {
375 453
376 factory ReceivePort() { 454 factory ReceivePort() {
377 return new ReceivePortImpl(); 455 return new ReceivePortImpl();
378 } 456 }
379 457
380 factory ReceivePort.singleShot() { 458 factory ReceivePort.singleShot() {
381 return new ReceivePortSingleShotImpl(); 459 return new ReceivePortSingleShotImpl();
382 } 460 }
383 } 461 }
384 462
385 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ 463 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */
386 class ReceivePortImpl implements ReceivePort { 464 class ReceivePortImpl implements ReceivePort {
465 int _id;
466 Function _callback;
467 static int _nextFreeId = 1;
468
387 ReceivePortImpl() 469 ReceivePortImpl()
388 : _id = _nextFreeId++ { 470 : _id = _nextFreeId++ {
389 _globalState.currentContext.register(_id, this); 471 _globalState.currentContext.register(_id, this);
390 } 472 }
391 473
392 void receive(void onMessage(var message, SendPort replyTo)) { 474 void receive(void onMessage(var message, SendPort replyTo)) {
393 _callback = onMessage; 475 _callback = onMessage;
394 } 476 }
395 477
396 void close() { 478 void close() {
397 _callback = null; 479 _callback = null;
398 _globalState.currentContext.unregister(_id); 480 _globalState.currentContext.unregister(_id);
399 } 481 }
400 482
401 /**
402 * Returns a fresh [SendPort]. The implementation is not allowed to cache
403 * existing ports.
404 */
405 SendPort toSendPort() { 483 SendPort toSendPort() {
406 return new SendPortImpl( 484 return new NativeJsSendPort(this, _globalState.currentContext.id);
407 _globalState.currentWorkerId, _globalState.currentContext.id, _id);
408 } 485 }
409
410 int _id;
411 Function _callback;
412
413 static int _nextFreeId = 1;
414 } 486 }
415 487
416 /** Implementation of a single-shot [ReceivePort]. */ 488 /** Implementation of a single-shot [ReceivePort]. */
417 class ReceivePortSingleShotImpl implements ReceivePort { 489 class ReceivePortSingleShotImpl implements ReceivePort {
418 490
419 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { } 491 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { }
420 492
421 void receive(void callback(var message, SendPort replyTo)) { 493 void receive(void callback(var message, SendPort replyTo)) {
422 _port.receive((var message, SendPort replyTo) { 494 _port.receive((var message, SendPort replyTo) {
423 _port.close(); 495 _port.close();
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { 616 _globalState.topEventLoop.enqueue(new IsolateContext(), function() {
545 var replyTo = _deserializeMessage(serializedReplyTo); 617 var replyTo = _deserializeMessage(serializedReplyTo);
546 IsolateNatives._startIsolate(runnerObject, replyTo); 618 IsolateNatives._startIsolate(runnerObject, replyTo);
547 }, 'worker-start'); 619 }, 'worker-start');
548 _globalState.topEventLoop.run(); 620 _globalState.topEventLoop.run();
549 break; 621 break;
550 case 'spawn-worker': 622 case 'spawn-worker':
551 _spawnWorker(msg['factoryName'], msg['replyPort']); 623 _spawnWorker(msg['factoryName'], msg['replyPort']);
552 break; 624 break;
553 case 'message': 625 case 'message':
554 _sendMessage(msg['workerId'], msg['isolateId'], msg['portId'], 626 msg['port'].send(msg['msg'], msg['replyTo']);
555 msg['msg'], msg['replyTo']);
556 _globalState.topEventLoop.run(); 627 _globalState.topEventLoop.run();
557 break; 628 break;
558 case 'close': 629 case 'close':
559 _log("Closing Worker"); 630 _log("Closing Worker");
560 _globalState.workers.remove(sender.id); 631 _globalState.workers.remove(sender.id);
561 sender.terminate(); 632 sender.terminate();
562 _globalState.topEventLoop.run(); 633 _globalState.topEventLoop.run();
563 break; 634 break;
564 case 'log': 635 case 'log':
565 _log(msg['msg']); 636 _log(msg['msg']);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 }, 'nonworker start'); 702 }, 'nonworker start');
632 } 703 }
633 704
634 /** Given a ready-to-start runnable, start running it. */ 705 /** Given a ready-to-start runnable, start running it. */
635 static void _startIsolate(Isolate isolate, SendPort replyTo) { 706 static void _startIsolate(Isolate isolate, SendPort replyTo) {
636 _fillStatics(_globalState.currentContext); 707 _fillStatics(_globalState.currentContext);
637 ReceivePort port = new ReceivePort(); 708 ReceivePort port = new ReceivePort();
638 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 709 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
639 isolate._run(port); 710 isolate._run(port);
640 } 711 }
641
642 static void _sendMessage(int workerId, int isolateId, int receivePortId,
643 message, replyTo) {
644 // Both the message and the replyTo are already serialized.
645 if (workerId == _globalState.currentWorkerId) {
646 var isolate = _globalState.isolates[isolateId];
647 if (isolate == null) return; // Isolate has been closed.
648 var receivePort = isolate.lookup(receivePortId);
649 if (receivePort == null) return; // ReceivePort has been closed.
650 _globalState.topEventLoop.enqueue(isolate, () {
651 if (receivePort._callback != null) {
652 receivePort._callback(
653 _deserializeMessage(message), _deserializeMessage(replyTo));
654 }
655 }, 'receive ' + message);
656 } else {
657 var worker;
658 // communication between workers go through the main worker
659 if (_globalState.isWorker) {
660 worker = _globalState.mainWorker;
661 } else {
662 // TODO(sigmund): make sure this works
663 worker = _globalState.workers[workerId];
664 }
665 worker.postMessage(_serializeMessage({
666 'command': 'message',
667 'workerId': workerId,
668 'isolateId': isolateId,
669 'portId': receivePortId,
670 'msg': message,
671 'replyTo': replyTo }));
672 }
673 }
674 } 712 }
OLDNEW
« no previous file with comments | « corelib/src/implementation/promise_implementation.dart ('k') | frog/lib/isolate_serialization.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698