OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dartino 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 library fletchc.hub_main; | 5 library dartino_compiler.hub_main; |
6 | 6 |
7 import 'dart:collection' show | 7 import 'dart:collection' show |
8 Queue; | 8 Queue; |
9 | 9 |
10 import 'dart:io' hide | 10 import 'dart:io' hide |
11 exitCode, | 11 exitCode, |
12 stderr, | 12 stderr, |
13 stdin, | 13 stdin, |
14 stdout; | 14 stdout; |
15 | 15 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 int length = view.getUint32(offset, commandEndianness); | 126 int length = view.getUint32(offset, commandEndianness); |
127 offset += 4; | 127 offset += 4; |
128 argv.add(UTF8.decode(toUint8ListView(view, offset, length))); | 128 argv.add(UTF8.decode(toUint8ListView(view, offset, length))); |
129 offset += length; | 129 offset += length; |
130 } | 130 } |
131 return argv; | 131 return argv; |
132 } | 132 } |
133 } | 133 } |
134 | 134 |
135 // Class for sending client commands from the hub (main isolate) to the | 135 // Class for sending client commands from the hub (main isolate) to the |
136 // fletch c++ client. | 136 // dartino c++ client. |
137 class ClientCommandSender extends CommandSender { | 137 class ClientCommandSender extends CommandSender { |
138 final Sink<List<int>> sink; | 138 final Sink<List<int>> sink; |
139 | 139 |
140 ClientCommandSender(this.sink); | 140 ClientCommandSender(this.sink); |
141 | 141 |
142 void sendExitCode(int exitCode) { | 142 void sendExitCode(int exitCode) { |
143 new CommandBuffer<ClientCommandCode>() | 143 new CommandBuffer<ClientCommandCode>() |
144 ..addUint32(exitCode) | 144 ..addUint32(exitCode) |
145 ..sendOn(sink, ClientCommandCode.ExitCode); | 145 ..sendOn(sink, ClientCommandCode.ExitCode); |
146 } | 146 } |
147 | 147 |
148 void sendDataCommand(ClientCommandCode code, List<int> data) { | 148 void sendDataCommand(ClientCommandCode code, List<int> data) { |
149 new CommandBuffer<ClientCommandCode>() | 149 new CommandBuffer<ClientCommandCode>() |
150 ..addUint32(data.length) | 150 ..addUint32(data.length) |
151 ..addUint8List(data) | 151 ..addUint8List(data) |
152 ..sendOn(sink, code); | 152 ..sendOn(sink, code); |
153 } | 153 } |
154 | 154 |
155 void sendClose() { | 155 void sendClose() { |
156 throwInternalError("Client (C++) doesn't support ClientCommandCode.Close."); | 156 throwInternalError("Client (C++) doesn't support ClientCommandCode.Close."); |
157 } | 157 } |
158 | 158 |
159 void sendEventLoopStarted() { | 159 void sendEventLoopStarted() { |
160 throwInternalError( | 160 throwInternalError( |
161 "Client (C++) doesn't support ClientCommandCode.EventLoopStarted."); | 161 "Client (C++) doesn't support ClientCommandCode.EventLoopStarted."); |
162 } | 162 } |
163 } | 163 } |
164 | 164 |
165 Future main(List<String> arguments) async { | 165 Future main(List<String> arguments) async { |
166 // When running this program, -Dfletch.version must be provided on the Dart | 166 // When running this program, -Ddartino.version must be provided on the Dart |
167 // VM command line. | 167 // VM command line. |
168 assert(const String.fromEnvironment('fletch.version') != null); | 168 assert(const String.fromEnvironment('dartino.version') != null); |
169 | 169 |
170 mainArguments.addAll(arguments); | 170 mainArguments.addAll(arguments); |
171 configFileUri = Uri.base.resolve(arguments.first); | 171 configFileUri = Uri.base.resolve(arguments.first); |
172 File configFile = new File.fromUri(configFileUri); | 172 File configFile = new File.fromUri(configFileUri); |
173 Directory tmpdir = Directory.systemTemp.createTempSync("fletch_client"); | 173 Directory tmpdir = Directory.systemTemp.createTempSync("dartino_client"); |
174 | 174 |
175 File socketFile = new File("${tmpdir.path}/socket"); | 175 File socketFile = new File("${tmpdir.path}/socket"); |
176 try { | 176 try { |
177 socketFile.deleteSync(); | 177 socketFile.deleteSync(); |
178 } on FileSystemException catch (e) { | 178 } on FileSystemException catch (e) { |
179 // Ignored. There's no way to check if a socket file exists. | 179 // Ignored. There's no way to check if a socket file exists. |
180 } | 180 } |
181 | 181 |
182 ServerSocket server; | 182 ServerSocket server; |
183 | 183 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 } | 327 } |
328 session.hasActiveWorkerTask = true; | 328 session.hasActiveWorkerTask = true; |
329 return session.worker.performTask( | 329 return session.worker.performTask( |
330 combineTasks(initializer, task), clientConnection, userSession: session) | 330 combineTasks(initializer, task), clientConnection, userSession: session) |
331 .whenComplete(() { | 331 .whenComplete(() { |
332 session.hasActiveWorkerTask = false; | 332 session.hasActiveWorkerTask = false; |
333 }); | 333 }); |
334 } | 334 } |
335 } | 335 } |
336 | 336 |
337 /// Handles communication with the Fletch C++ client. | 337 /// Handles communication with the Dartino C++ client. |
338 class ClientConnection { | 338 class ClientConnection { |
339 /// Socket used for receiving and sending commands from/to the Fletch C++ | 339 /// Socket used for receiving and sending commands from/to the Dartino C++ |
340 /// client. | 340 /// client. |
341 final Socket socket; | 341 final Socket socket; |
342 | 342 |
343 /// Controller used to send commands to the from the ClientConnection to | 343 /// Controller used to send commands to the from the ClientConnection to |
344 /// anyone listening on ClientConnection.commands (see [commands] below). The | 344 /// anyone listening on ClientConnection.commands (see [commands] below). The |
345 /// only listener as of now is the WorkerConnection which typically forwards | 345 /// only listener as of now is the WorkerConnection which typically forwards |
346 /// the commands to the worker isolate. | 346 /// the commands to the worker isolate. |
347 final StreamController<ClientCommand> controller = | 347 final StreamController<ClientCommand> controller = |
348 new StreamController<ClientCommand>(); | 348 new StreamController<ClientCommand>(); |
349 | 349 |
350 final ClientLogger log; | 350 final ClientLogger log; |
351 | 351 |
352 /// The commandSender is used to send commands back to the Fletch C++ client. | 352 /// The commandSender is used to send commands back to the Dartino C++ client. |
353 ClientCommandSender commandSender; | 353 ClientCommandSender commandSender; |
354 | 354 |
355 StreamSubscription<ClientCommand> subscription; | 355 StreamSubscription<ClientCommand> subscription; |
356 Completer<Null> completer; | 356 Completer<Null> completer; |
357 | 357 |
358 Completer<List<String>> argumentsCompleter = new Completer<List<String>>(); | 358 Completer<List<String>> argumentsCompleter = new Completer<List<String>>(); |
359 | 359 |
360 /// The analysed version of the request from the client. | 360 /// The analysed version of the request from the client. |
361 /// Updated by [parseArguments]. | 361 /// Updated by [parseArguments]. |
362 AnalyzedSentence sentence; | 362 AnalyzedSentence sentence; |
363 | 363 |
364 /// Path to the fletch VM. Updated by [parseArguments]. | 364 /// Path to the dartino VM. Updated by [parseArguments]. |
365 String fletchVm; | 365 String dartinoVm; |
366 | 366 |
367 ClientConnection(this.socket, this.log); | 367 ClientConnection(this.socket, this.log); |
368 | 368 |
369 /// Stream of commands from the Fletch C++ client to the hub (main isolate). | 369 /// Stream of commands from the Dartino C++ client to the hub (main isolate). |
370 /// The commands are typically forwarded to a worker isolate, see | 370 /// The commands are typically forwarded to a worker isolate, see |
371 /// handleClientCommand. | 371 /// handleClientCommand. |
372 Stream<ClientCommand> get commands => controller.stream; | 372 Stream<ClientCommand> get commands => controller.stream; |
373 | 373 |
374 /// Completes when [endSession] is called. | 374 /// Completes when [endSession] is called. |
375 Future<Null> get done => completer.future; | 375 Future<Null> get done => completer.future; |
376 | 376 |
377 /// Completes with the command-line arguments from the client. | 377 /// Completes with the command-line arguments from the client. |
378 Future<List<String>> get arguments => argumentsCompleter.future; | 378 Future<List<String>> get arguments => argumentsCompleter.future; |
379 | 379 |
380 /// Start processing commands from the client. | 380 /// Start processing commands from the client. |
381 void start() { | 381 void start() { |
382 // Setup a command sender used to send responses from the hub (main isolate) | 382 // Setup a command sender used to send responses from the hub (main isolate) |
383 // back to the Fletch C++ client. | 383 // back to the Dartino C++ client. |
384 commandSender = new ClientCommandSender(socket); | 384 commandSender = new ClientCommandSender(socket); |
385 | 385 |
386 // Setup a listener for handling commands coming from the Fletch C++ | 386 // Setup a listener for handling commands coming from the Dartino C++ |
387 // client. | 387 // client. |
388 StreamTransformer<List<int>, ClientCommand> transformer = | 388 StreamTransformer<List<int>, ClientCommand> transformer = |
389 new ClientCommandTransformerBuilder().build(); | 389 new ClientCommandTransformerBuilder().build(); |
390 subscription = socket.transform(transformer).listen(null); | 390 subscription = socket.transform(transformer).listen(null); |
391 subscription | 391 subscription |
392 ..onData(handleClientCommand) | 392 ..onData(handleClientCommand) |
393 ..onError(handleClientCommandError) | 393 ..onError(handleClientCommandError) |
394 ..onDone(handleClientCommandsDone); | 394 ..onDone(handleClientCommandsDone); |
395 completer = new Completer<Null>(); | 395 completer = new Completer<Null>(); |
396 } | 396 } |
(...skipping 22 matching lines...) Expand all Loading... | |
419 // Cancel the subscription if an error occurred, this prevents | 419 // Cancel the subscription if an error occurred, this prevents |
420 // [handleCommandsDone] from being called and attempt to complete | 420 // [handleCommandsDone] from being called and attempt to complete |
421 // [completer]. | 421 // [completer]. |
422 subscription.cancel(); | 422 subscription.cancel(); |
423 } | 423 } |
424 | 424 |
425 void handleClientCommandsDone() { | 425 void handleClientCommandsDone() { |
426 completer.complete(); | 426 completer.complete(); |
427 } | 427 } |
428 | 428 |
429 // Send a command back to the Fletch C++ client. | 429 // Send a command back to the Dartino C++ client. |
430 void sendCommandToClient(ClientCommand command) { | 430 void sendCommandToClient(ClientCommand command) { |
431 switch (command.code) { | 431 switch (command.code) { |
432 case ClientCommandCode.Stdout: | 432 case ClientCommandCode.Stdout: |
433 commandSender.sendStdoutBytes(command.data); | 433 commandSender.sendStdoutBytes(command.data); |
434 break; | 434 break; |
435 | 435 |
436 case ClientCommandCode.Stderr: | 436 case ClientCommandCode.Stderr: |
437 commandSender.sendStderrBytes(command.data); | 437 commandSender.sendStderrBytes(command.data); |
438 break; | 438 break; |
439 | 439 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 } | 472 } |
473 } | 473 } |
474 commandSender.sendExitCode(exitCode); | 474 commandSender.sendExitCode(exitCode); |
475 endSession(); | 475 endSession(); |
476 } | 476 } |
477 | 477 |
478 AnalyzedSentence parseArguments(List<String> arguments) { | 478 AnalyzedSentence parseArguments(List<String> arguments) { |
479 Options options = Options.parse(arguments); | 479 Options options = Options.parse(arguments); |
480 Sentence sentence = | 480 Sentence sentence = |
481 parseSentence(options.nonOptionArguments, includesProgramName: true); | 481 parseSentence(options.nonOptionArguments, includesProgramName: true); |
482 // [programName] is the canonicalized absolute path to the fletch | 482 // [programName] is the canonicalized absolute path to the dartino |
483 // executable (the C++ program). | 483 // executable (the C++ program). |
484 String programName = sentence.programName; | 484 String programName = sentence.programName; |
485 String fletchVm = "$programName-vm"; | 485 String dartinoVm = "$programName-vm"; |
486 this.sentence = analyzeSentence(sentence, options); | 486 this.sentence = analyzeSentence(sentence, options); |
487 this.fletchVm = fletchVm; | 487 this.dartinoVm = dartinoVm; |
488 return this.sentence; | 488 return this.sentence; |
489 } | 489 } |
490 | 490 |
491 int reportErrorToClient(InputError error, StackTrace stackTrace) { | 491 int reportErrorToClient(InputError error, StackTrace stackTrace) { |
492 bool isInternalError = error.kind == DiagnosticKind.internalError; | 492 bool isInternalError = error.kind == DiagnosticKind.internalError; |
493 if (isInternalError && !crashReportRequested) { | 493 if (isInternalError && !crashReportRequested) { |
494 printLineOnStderr(requestBugReportOnOtherCrashMessage); | 494 printLineOnStderr(requestBugReportOnOtherCrashMessage); |
495 crashReportRequested = true; | 495 crashReportRequested = true; |
496 } | 496 } |
497 printLineOnStderr(error.asDiagnostic().formatMessage()); | 497 printLineOnStderr(error.asDiagnostic().formatMessage()); |
(...skipping 13 matching lines...) Expand all Loading... | |
511 final ManagedIsolate isolate; | 511 final ManagedIsolate isolate; |
512 | 512 |
513 /// A port used to send commands to the worker isolate. | 513 /// A port used to send commands to the worker isolate. |
514 SendPort sendPort; | 514 SendPort sendPort; |
515 | 515 |
516 /// A port used to read commands from the worker isolate. | 516 /// A port used to read commands from the worker isolate. |
517 ReceivePort receivePort; | 517 ReceivePort receivePort; |
518 | 518 |
519 /// workerCommands is an iterator over all the commands coming from the | 519 /// workerCommands is an iterator over all the commands coming from the |
520 /// worker isolate. These are typically the outbound messages destined for | 520 /// worker isolate. These are typically the outbound messages destined for |
521 /// the Fletch C++ client. | 521 /// the Dartino C++ client. |
522 /// It iterates over the data coming on the receivePort. | 522 /// It iterates over the data coming on the receivePort. |
523 StreamIterator<ClientCommand> workerCommands; | 523 StreamIterator<ClientCommand> workerCommands; |
524 | 524 |
525 /// When true, the worker can be shutdown by sending it a | 525 /// When true, the worker can be shutdown by sending it a |
526 /// ClientCommandCode.Signal command. Otherwise, it must be killed. | 526 /// ClientCommandCode.Signal command. Otherwise, it must be killed. |
527 bool eventLoopStarted = false; | 527 bool eventLoopStarted = false; |
528 | 528 |
529 /// Subscription for errors from [isolate]. | 529 /// Subscription for errors from [isolate]. |
530 StreamSubscription errorSubscription; | 530 StreamSubscription errorSubscription; |
531 | 531 |
(...skipping 17 matching lines...) Expand all Loading... | |
549 // TODO(ahe): Add this assertion: assert(isolate.wasKilled); | 549 // TODO(ahe): Add this assertion: assert(isolate.wasKilled); |
550 endSession(); | 550 endSession(); |
551 return; | 551 return; |
552 } | 552 } |
553 ClientCommand command = workerCommands.current; | 553 ClientCommand command = workerCommands.current; |
554 assert(command.code == ClientCommandCode.SendPort); | 554 assert(command.code == ClientCommandCode.SendPort); |
555 assert(command.data != null); | 555 assert(command.data != null); |
556 sendPort = command.data; | 556 sendPort = command.data; |
557 } | 557 } |
558 | 558 |
559 /// Attach to a fletch C++ client and forward commands to the worker isolate, | 559 /// Attach to a dartino C++ client and forward commands to the worker isolate, |
560 /// and vice versa. The returned future normally completes when the worker | 560 /// and vice versa. The returned future normally completes when the worker |
561 /// isolate sends ClientCommandCode.ClosePort, or if the isolate is killed due | 561 /// isolate sends ClientCommandCode.ClosePort, or if the isolate is killed due |
562 /// to ClientCommandCode.Signal arriving through client.commands. | 562 /// to ClientCommandCode.Signal arriving through client.commands. |
563 Future<int> attachClient( | 563 Future<int> attachClient( |
564 ClientConnection clientConnection, | 564 ClientConnection clientConnection, |
565 UserSession userSession) async { | 565 UserSession userSession) async { |
566 | 566 |
567 // Method for handling commands coming from the client. The commands are | 567 // Method for handling commands coming from the client. The commands are |
568 // typically forwarded to the worker isolate. | 568 // typically forwarded to the worker isolate. |
569 handleCommandsFromClient(ClientCommand command) { | 569 handleCommandsFromClient(ClientCommand command) { |
570 if (command.code == ClientCommandCode.Signal && !eventLoopStarted) { | 570 if (command.code == ClientCommandCode.Signal && !eventLoopStarted) { |
571 if (userSession != null) { | 571 if (userSession != null) { |
572 userSession.kill(clientConnection.printLineOnStderr); | 572 userSession.kill(clientConnection.printLineOnStderr); |
573 } else { | 573 } else { |
574 isolate.kill(); | 574 isolate.kill(); |
575 } | 575 } |
576 receivePort.close(); | 576 receivePort.close(); |
577 } else { | 577 } else { |
578 sendPort.send([command.code.index, command.data]); | 578 sendPort.send([command.code.index, command.data]); |
579 } | 579 } |
580 } | 580 } |
581 | 581 |
582 // Method for handling commands coming back from the worker isolate. | 582 // Method for handling commands coming back from the worker isolate. |
583 // It typically forwards them to the Fletch C++ client via the | 583 // It typically forwards them to the Dartino C++ client via the |
584 // clientConnection. | 584 // clientConnection. |
585 Future<int> handleCommandsFromWorker( | 585 Future<int> handleCommandsFromWorker( |
586 ClientConnection clientConnection) async { | 586 ClientConnection clientConnection) async { |
587 int exitCode = COMPILER_EXITCODE_CRASH; | 587 int exitCode = COMPILER_EXITCODE_CRASH; |
588 while (await workerCommands.moveNext()) { | 588 while (await workerCommands.moveNext()) { |
589 ClientCommand command = workerCommands.current; | 589 ClientCommand command = workerCommands.current; |
590 switch (command.code) { | 590 switch (command.code) { |
591 case ClientCommandCode.ClosePort: | 591 case ClientCommandCode.ClosePort: |
592 receivePort.close(); | 592 receivePort.close(); |
593 break; | 593 break; |
(...skipping 29 matching lines...) Expand all Loading... | |
623 } | 623 } |
624 if (userSession != null) { | 624 if (userSession != null) { |
625 userSession.kill(clientConnection.printLineOnStderr); | 625 userSession.kill(clientConnection.printLineOnStderr); |
626 } else { | 626 } else { |
627 isolate.kill(); | 627 isolate.kill(); |
628 } | 628 } |
629 receivePort.close(); | 629 receivePort.close(); |
630 }); | 630 }); |
631 errorSubscription.resume(); | 631 errorSubscription.resume(); |
632 | 632 |
633 // Start listening for commands coming from the Fletch C++ client (via | 633 // Start listening for commands coming from the Dartino C++ client (via |
634 // clientConnection). | 634 // clientConnection). |
635 // TODO(ahe): Add onDone event handler to detach the client. | 635 // TODO(ahe): Add onDone event handler to detach the client. |
636 clientConnection.commands.listen(handleCommandsFromClient); | 636 clientConnection.commands.listen(handleCommandsFromClient); |
637 | 637 |
638 // Start processing commands coming from the worker. | 638 // Start processing commands coming from the worker. |
639 int exitCode = await handleCommandsFromWorker(clientConnection); | 639 int exitCode = await handleCommandsFromWorker(clientConnection); |
640 | 640 |
641 errorSubscription.pause(); | 641 errorSubscription.pause(); |
642 return exitCode; | 642 return exitCode; |
643 } | 643 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
676 log.error(error, stackTrace); | 676 log.error(error, stackTrace); |
677 }).then((_) { | 677 }).then((_) { |
678 log.done(); | 678 log.done(); |
679 }); | 679 }); |
680 | 680 |
681 // Indirectly send the task to be performed to the worker isolate via the | 681 // Indirectly send the task to be performed to the worker isolate via the |
682 // clientConnection. | 682 // clientConnection. |
683 clientConnection.sendCommandToWorker( | 683 clientConnection.sendCommandToWorker( |
684 new ClientCommand(ClientCommandCode.PerformTask, task)); | 684 new ClientCommand(ClientCommandCode.PerformTask, task)); |
685 | 685 |
686 // Forward commands between the C++ fletch client [clientConnection], and th e | 686 // Forward commands between the C++ dartino client [clientConnection], and t he |
Søren Gjesse
2016/02/03 12:06:54
Long line.
ricow1
2016/02/03 12:29:18
Done.
| |
687 // worker isolate `this`. Also, Intercept the signal command and | 687 // worker isolate `this`. Also, Intercept the signal command and |
688 // potentially kill the isolate (the isolate needs to tell if it is | 688 // potentially kill the isolate (the isolate needs to tell if it is |
689 // interuptible or needs to be killed, an example of the latter is, if | 689 // interuptible or needs to be killed, an example of the latter is, if |
690 // compiler is running). | 690 // compiler is running). |
691 int exitCode = await attachClient(clientConnection, userSession); | 691 int exitCode = await attachClient(clientConnection, userSession); |
692 // The verb (which was performed in the worker) is done. | 692 // The verb (which was performed in the worker) is done. |
693 log.note("After attachClient (exitCode = $exitCode)"); | 693 log.note("After attachClient (exitCode = $exitCode)"); |
694 | 694 |
695 if (endSession) { | 695 if (endSession) { |
696 // Return the isolate to the pool *before* shutting down the client. This | 696 // Return the isolate to the pool *before* shutting down the client. This |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
849 | 849 |
850 void error(error, StackTrace stackTrace) { | 850 void error(error, StackTrace stackTrace) { |
851 // TODO(ahe): Modify quit verb to report these errors. | 851 // TODO(ahe): Modify quit verb to report these errors. |
852 erroneousClients.add(this); | 852 erroneousClients.add(this); |
853 note("Crash (${arguments.join(' ')}).\n" | 853 note("Crash (${arguments.join(' ')}).\n" |
854 "${stringifyError(error, stackTrace)}"); | 854 "${stringifyError(error, stackTrace)}"); |
855 } | 855 } |
856 | 856 |
857 String toString() => "$id"; | 857 String toString() => "$id"; |
858 } | 858 } |
OLD | NEW |