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

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 if (shouldSerialize) {
392 message = _serializeMessage(message);
393 replyTo = _serializeMessage(replyTo);
394 }
395 _globalState.topEventLoop.enqueue(isolate, () {
396 if (_receivePort._callback != null) {
397 if (shouldSerialize) {
eub 2012/02/10 21:20:57 I liked your previous version with the serialize-d
Siggi Cherem (dart-lang) 2012/02/10 22:09:22 Me too - when I did some testing, I realized that
eub 2012/02/10 22:11:50 Can we come up with a simple comment explaining to
398 message = _deserializeMessage(message);
399 replyTo = _deserializeMessage(replyTo);
400 }
401 _receivePort._callback(message, replyTo);
402 }
403 }, 'receive ' + message);
404 }
405
406 bool operator ==(var other) => (other is NativeJsSendPort) &&
407 (_receivePort == other._receivePort);
408
409 int hashCode() => _receivePort._id;
410 }
411
412 /** A send port that delivers messages via worker.postMessage. */
413 class WorkerSendPort extends BaseSendPort implements SendPort {
414 final int _workerId;
415 final int _receivePortId;
416
417 const WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
418 : super(isolateId);
419
420 void send(var message, [SendPort replyTo = null]) {
421 checkReplyTo(replyTo);
422 final workerMessage = _serializeMessage({
423 'command': 'message',
424 'port': this,
425 'msg': message,
426 'replyTo': replyTo});
427
428 if (_globalState.isWorker) {
429 // communication from one worker to another go through the main worker:
430 _globalState.mainWorker.postMessage(workerMessage);
431 } else {
432 _globalState.workers[_workerId].postMessage(workerMessage);
433 }
434 }
435
436 bool operator ==(var other) {
437 return (other is WorkerSendPort) &&
359 (_workerId == other._workerId) && 438 (_workerId == other._workerId) &&
360 (_isolateId == other._isolateId) && 439 (_isolateId == other._isolateId) &&
361 (_receivePortId == other._receivePortId); 440 (_receivePortId == other._receivePortId);
362 } 441 }
363 442
364 int hashCode() { 443 int hashCode() {
444 // TODO(sigmund): use a standard hash when we get one available in corelib.
365 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; 445 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId;
366 } 446 }
367
368 final int _receivePortId;
369 final int _isolateId;
370 final int _workerId;
371 } 447 }
372 448
373 /** Default factory for receive ports. */ 449 /** Default factory for receive ports. */
374 class ReceivePortFactory { 450 class ReceivePortFactory {
375 451
376 factory ReceivePort() { 452 factory ReceivePort() {
377 return new ReceivePortImpl(); 453 return new ReceivePortImpl();
378 } 454 }
379 455
380 factory ReceivePort.singleShot() { 456 factory ReceivePort.singleShot() {
381 return new ReceivePortSingleShotImpl(); 457 return new ReceivePortSingleShotImpl();
382 } 458 }
383 } 459 }
384 460
385 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ 461 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */
386 class ReceivePortImpl implements ReceivePort { 462 class ReceivePortImpl implements ReceivePort {
463 int _id;
464 Function _callback;
465 static int _nextFreeId = 1;
466
387 ReceivePortImpl() 467 ReceivePortImpl()
388 : _id = _nextFreeId++ { 468 : _id = _nextFreeId++ {
389 _globalState.currentContext.register(_id, this); 469 _globalState.currentContext.register(_id, this);
390 } 470 }
391 471
392 void receive(void onMessage(var message, SendPort replyTo)) { 472 void receive(void onMessage(var message, SendPort replyTo)) {
393 _callback = onMessage; 473 _callback = onMessage;
394 } 474 }
395 475
396 void close() { 476 void close() {
397 _callback = null; 477 _callback = null;
398 _globalState.currentContext.unregister(_id); 478 _globalState.currentContext.unregister(_id);
399 } 479 }
400 480
401 /**
402 * Returns a fresh [SendPort]. The implementation is not allowed to cache
403 * existing ports.
404 */
405 SendPort toSendPort() { 481 SendPort toSendPort() {
406 return new SendPortImpl( 482 return new NativeJsSendPort(this, _globalState.currentContext.id);
407 _globalState.currentWorkerId, _globalState.currentContext.id, _id);
408 } 483 }
409
410 int _id;
411 Function _callback;
412
413 static int _nextFreeId = 1;
414 } 484 }
415 485
416 /** Implementation of a single-shot [ReceivePort]. */ 486 /** Implementation of a single-shot [ReceivePort]. */
417 class ReceivePortSingleShotImpl implements ReceivePort { 487 class ReceivePortSingleShotImpl implements ReceivePort {
418 488
419 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { } 489 ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { }
420 490
421 void receive(void callback(var message, SendPort replyTo)) { 491 void receive(void callback(var message, SendPort replyTo)) {
422 _port.receive((var message, SendPort replyTo) { 492 _port.receive((var message, SendPort replyTo) {
423 _port.close(); 493 _port.close();
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { 614 _globalState.topEventLoop.enqueue(new IsolateContext(), function() {
545 var replyTo = _deserializeMessage(serializedReplyTo); 615 var replyTo = _deserializeMessage(serializedReplyTo);
546 IsolateNatives._startIsolate(runnerObject, replyTo); 616 IsolateNatives._startIsolate(runnerObject, replyTo);
547 }, 'worker-start'); 617 }, 'worker-start');
548 _globalState.topEventLoop.run(); 618 _globalState.topEventLoop.run();
549 break; 619 break;
550 case 'spawn-worker': 620 case 'spawn-worker':
551 _spawnWorker(msg['factoryName'], msg['replyPort']); 621 _spawnWorker(msg['factoryName'], msg['replyPort']);
552 break; 622 break;
553 case 'message': 623 case 'message':
554 _sendMessage(msg['workerId'], msg['isolateId'], msg['portId'], 624 msg['port'].send(msg['msg'], msg['replyTo']);
555 msg['msg'], msg['replyTo']);
556 _globalState.topEventLoop.run(); 625 _globalState.topEventLoop.run();
557 break; 626 break;
558 case 'close': 627 case 'close':
559 _log("Closing Worker"); 628 _log("Closing Worker");
560 _globalState.workers.remove(sender.id); 629 _globalState.workers.remove(sender.id);
561 sender.terminate(); 630 sender.terminate();
562 _globalState.topEventLoop.run(); 631 _globalState.topEventLoop.run();
563 break; 632 break;
564 case 'log': 633 case 'log':
565 _log(msg['msg']); 634 _log(msg['msg']);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 }, 'nonworker start'); 700 }, 'nonworker start');
632 } 701 }
633 702
634 /** Given a ready-to-start runnable, start running it. */ 703 /** Given a ready-to-start runnable, start running it. */
635 static void _startIsolate(Isolate isolate, SendPort replyTo) { 704 static void _startIsolate(Isolate isolate, SendPort replyTo) {
636 _fillStatics(_globalState.currentContext); 705 _fillStatics(_globalState.currentContext);
637 ReceivePort port = new ReceivePort(); 706 ReceivePort port = new ReceivePort();
638 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 707 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
639 isolate._run(port); 708 isolate._run(port);
640 } 709 }
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 } 710 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698