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

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 final int _isolateId;
eub 2012/02/09 01:13:42 id of destination?
Siggi Cherem (dart-lang) 2012/02/10 00:16:41 Yes. Added a comment.
331 332
332 const SendPortImpl(this._workerId, this._isolateId, this._receivePortId); 333 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 334
345 ReceivePortSingleShotImpl call(var message) { 335 ReceivePortSingleShotImpl call(var message) {
346 final result = new ReceivePortSingleShotImpl(); 336 final result = new ReceivePortSingleShotImpl();
347 this.send(message, result.toSendPort()); 337 this.send(message, result.toSendPort());
348 return result; 338 return result;
349 } 339 }
350 340
351 ReceivePortSingleShotImpl _callNow(var message) { 341 static void checkReplyTo(SendPort replyTo) {
352 final result = new ReceivePortSingleShotImpl(); 342 if (replyTo !== null && replyTo is! NativeJsSendPort
353 send(message, result.toSendPort()); 343 && replyTo is! WorkerSendPort) {
354 return result; 344 throw "SendPort.send: Illegal replyTo port type.";
345 }
355 } 346 }
356 347
357 bool operator==(var other) { 348 // TODO(sigmund): replace the current SendPort.call with the following:
358 return (other is SendPortImpl) && 349 //Future call(var message) {
350 //  final completer = new Completer();
351 //  final port = new ReceivePort.singleShot();
352 //  send(message, port.toSendPort());
353 //  port.receive((value, ignoreReplyTo) {
354 //    if (value is Exception) {
355 //  completer.completeException(value);
356 // } else {
357 // completer.complete(value);
358 // }
359 // });
360 //  return completer.future;
361 //}
362
363 abstract void send(var message, [SendPort replyTo]);
364 abstract bool operator ==(var other);
365 abstract int hashCode();
366 }
367
368 /** A send port that delivers messages in-memory via native JavaScript calls. */
369 class NativeJsSendPort extends BaseSendPort implements SendPort {
370 final ReceivePortImpl _receivePort;
371
372 const NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId);
373
374 void send(var message, [SendPort replyTo = null]) {
375 checkReplyTo(replyTo);
376 // Check that the isolate still runs and the port is still open
377 final isolate = _globalState.isolates[_isolateId];
378 if (isolate == null) return;
379 if (_receivePort._callback == null) return;
380
381 // messages from WorkerSendPorts get forwarded by [_processWorkerMessage],
382 // in that case we no isolate is currently active, and the message was
383 // already serialized and deserialized.
384 final shouldSerialize = _globalState.currentContext == null;
eub 2012/02/09 01:13:42 (Revisit per our discussion -- is this test backwa
Siggi Cherem (dart-lang) 2012/02/10 00:16:41 cleaned up. Should make more sense now :)
385 _globalState.topEventLoop.enqueue(isolate, () {
386 if (_receivePort._callback != null) {
387 if (shouldSerialize) {
388 // Force serialization/deserialization as a simple way to ensure
389 // isolate communication restrictions are respected.
390 message = _deserializeMessage(_serializeMessage(message));
391 replyTo = _deserializeMessage(_serializeMessage(replyTo));
392 }
393 _receivePort._callback(message, replyTo);
394 }
395 }, 'receive ' + message);
396 }
397
398 bool operator ==(var other) => (other is NativeJsSendPort) &&
399 (_receivePort == other._receivePort);
eub 2012/02/09 01:13:42 (Side note about Dart: this idiom strikes me as we
Siggi Cherem (dart-lang) 2012/02/10 00:16:41 yeah, it would be nice to have 'final' or 'sealed'
400
401 int hashCode() => _receivePort._id;
402 }
403
404 /** A send port that delivers messages via worker.postMessage. */
405 class WorkerSendPort extends BaseSendPort implements SendPort {
406 final int _workerId;
407 final int _receivePortId;
408
409 const WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
410 : super(isolateId);
411
412 void send(var message, [SendPort replyTo = null]) {
413 checkReplyTo(replyTo);
414 final workerMessage = _serializeMessage({
415 'command': 'message',
416 'port': this,
417 'msg': message,
418 'replyTo': replyTo});
419
420 if (_globalState.isWorker) {
421 // communication from one worker to another go through the main worker:
422 _globalState.mainWorker.postMessage(workerMessage);
423 } else {
424 _globalState.workers[_workerId].postMessage(workerMessage);
425 }
426 }
427
428 bool operator ==(var other) {
429 return (other is WorkerSendPort) &&
359 (_workerId == other._workerId) && 430 (_workerId == other._workerId) &&
360 (_isolateId == other._isolateId) && 431 (_isolateId == other._isolateId) &&
361 (_receivePortId == other._receivePortId); 432 (_receivePortId == other._receivePortId);
362 } 433 }
363 434
364 int hashCode() { 435 int hashCode() {
365 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; 436 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId;
eub 2012/02/09 01:13:42 If we believe these bit windows don't overlap, usi
Siggi Cherem (dart-lang) 2012/02/10 00:16:41 Done.
366 } 437 }
367
368 final int _receivePortId;
369 final int _isolateId;
370 final int _workerId;
371 } 438 }
372 439
373 /** Default factory for receive ports. */ 440 /** Default factory for receive ports. */
374 class ReceivePortFactory { 441 class ReceivePortFactory {
375 442
376 factory ReceivePort() { 443 factory ReceivePort() {
377 return new ReceivePortImpl(); 444 return new ReceivePortImpl();
378 } 445 }
379 446
380 factory ReceivePort.singleShot() { 447 factory ReceivePort.singleShot() {
381 return new ReceivePortSingleShotImpl(); 448 return new ReceivePortSingleShotImpl();
382 } 449 }
383 } 450 }
384 451
385 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ 452 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */
386 class ReceivePortImpl implements ReceivePort { 453 class ReceivePortImpl implements ReceivePort {
454 int _id;
455 Function _callback;
456 static int _nextFreeId = 1;
457
387 ReceivePortImpl() 458 ReceivePortImpl()
388 : _id = _nextFreeId++ { 459 : _id = _nextFreeId++ {
389 _globalState.currentContext.register(_id, this); 460 _globalState.currentContext.register(_id, this);
390 } 461 }
391 462
392 void receive(void onMessage(var message, SendPort replyTo)) { 463 void receive(void onMessage(var message, SendPort replyTo)) {
393 _callback = onMessage; 464 _callback = onMessage;
394 } 465 }
395 466
396 void close() { 467 void close() {
397 _callback = null; 468 _callback = null;
398 _globalState.currentContext.unregister(_id); 469 _globalState.currentContext.unregister(_id);
399 } 470 }
400 471
401 /**
402 * Returns a fresh [SendPort]. The implementation is not allowed to cache
403 * existing ports.
404 */
405 SendPort toSendPort() { 472 SendPort toSendPort() {
406 return new SendPortImpl( 473 return new NativeJsSendPort(this, _globalState.currentContext.id);
407 _globalState.currentWorkerId, _globalState.currentContext.id, _id);
408 } 474 }
409
410 int _id;
411 Function _callback;
412
413 static int _nextFreeId = 1;
414 } 475 }
415 476
416 /** Implementation of a single-shot [ReceivePort]. */ 477 /** Implementation of a single-shot [ReceivePort]. */
417 class ReceivePortSingleShotImpl implements ReceivePort { 478 class ReceivePortSingleShotImpl implements ReceivePort {
418 479
419 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { } 480 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { }
420 481
421 void receive(void callback(var message, SendPort replyTo)) { 482 void receive(void callback(var message, SendPort replyTo)) {
422 _port.receive((var message, SendPort replyTo) { 483 _port.receive((var message, SendPort replyTo) {
423 _port.close(); 484 _port.close();
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { 605 _globalState.topEventLoop.enqueue(new IsolateContext(), function() {
545 var replyTo = _deserializeMessage(serializedReplyTo); 606 var replyTo = _deserializeMessage(serializedReplyTo);
546 IsolateNatives._startIsolate(runnerObject, replyTo); 607 IsolateNatives._startIsolate(runnerObject, replyTo);
547 }, 'worker-start'); 608 }, 'worker-start');
548 _globalState.topEventLoop.run(); 609 _globalState.topEventLoop.run();
549 break; 610 break;
550 case 'spawn-worker': 611 case 'spawn-worker':
551 _spawnWorker(msg['factoryName'], msg['replyPort']); 612 _spawnWorker(msg['factoryName'], msg['replyPort']);
552 break; 613 break;
553 case 'message': 614 case 'message':
554 _sendMessage(msg['workerId'], msg['isolateId'], msg['portId'], 615 msg['port'].send(msg['msg'], msg['replyTo']);
555 msg['msg'], msg['replyTo']);
556 _globalState.topEventLoop.run(); 616 _globalState.topEventLoop.run();
557 break; 617 break;
558 case 'close': 618 case 'close':
559 _log("Closing Worker"); 619 _log("Closing Worker");
560 _globalState.workers.remove(sender.id); 620 _globalState.workers.remove(sender.id);
561 sender.terminate(); 621 sender.terminate();
562 _globalState.topEventLoop.run(); 622 _globalState.topEventLoop.run();
563 break; 623 break;
564 case 'log': 624 case 'log':
565 _log(msg['msg']); 625 _log(msg['msg']);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 }, 'nonworker start'); 691 }, 'nonworker start');
632 } 692 }
633 693
634 /** Given a ready-to-start runnable, start running it. */ 694 /** Given a ready-to-start runnable, start running it. */
635 static void _startIsolate(Isolate isolate, SendPort replyTo) { 695 static void _startIsolate(Isolate isolate, SendPort replyTo) {
636 _fillStatics(_globalState.currentContext); 696 _fillStatics(_globalState.currentContext);
637 ReceivePort port = new ReceivePort(); 697 ReceivePort port = new ReceivePort();
638 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 698 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
639 isolate._run(port); 699 isolate._run(port);
640 } 700 }
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 } 701 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698