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

Unified Diff: lib/fletch/fletch.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 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 | « lib/ffi/utf.dart ('k') | lib/fletch_embedded.platform » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/fletch/fletch.dart
diff --git a/lib/fletch/fletch.dart b/lib/fletch/fletch.dart
deleted file mode 100644
index f1ddafb223d44308083f31b6e056cb0bddbbd6a6..0000000000000000000000000000000000000000
--- a/lib/fletch/fletch.dart
+++ /dev/null
@@ -1,559 +0,0 @@
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE.md file.
-
-library dart.fletch;
-
-import 'dart:fletch._system' as fletch;
-
-/// Fibers are lightweight co-operative multitask units of execution. They
-/// are scheduled on top of OS-level threads, but they are cheap to create
-/// and block.
-class Fiber {
-
- // We keep track of the top of the coroutine stack and
- // the list of other fibers that are waiting for this
- // fiber to exit.
- Coroutine _coroutine;
- List<Fiber> _joiners;
-
- // When a fiber exits, we keep the result of running
- // its code around so we can return to other fibers
- // that join it.
- bool _isDone = false;
- var _result;
-
- // The ready fibers are linked together.
- Fiber _previous;
- Fiber _next;
-
- // We do not use an initializer for [_current] to ensure we can treeshake
- // the [Fiber] class.
- static Fiber _current;
- static Fiber _idleFibers;
-
- Fiber._initial() {
- _previous = this;
- _next = this;
- }
-
- Fiber._forked(entry) {
- current; // Force initialization of fiber sub-system.
- _coroutine = new Coroutine((ignore) {
- fletch.runToEnd(entry);
- });
- }
-
- static Fiber get current {
- var current = _current;
- if (current != null) return current;
- return _current = new Fiber._initial();
- }
-
- static Fiber fork(entry) {
- Fiber fiber = new Fiber._forked(entry);
- _markReady(fiber);
- return fiber;
- }
-
- static void yield() {
- // Handle messages so that fibers that are blocked on receiving
- // messages can wake up.
- Process._handleMessages();
- _current._coroutine = Coroutine._coroutineCurrent();
- _schedule(_current._next);
- }
-
- static void exit([value]) {
- // If we never created a fiber, we can just go ahead and halt now.
- if (_current == null) fletch.halt();
-
- _current._exit(value);
- }
-
- join() {
- // If the fiber is already done, we just return the result.
- if (_isDone) return _result;
-
- // Add the current fiber to the list of fibers waiting
- // to join [this] fiber.
- Fiber fiber = _current;
- if (_joiners == null) {
- _joiners = [ fiber ];
- } else {
- _joiners.add(fiber);
- }
-
- // Suspend the current fiber and change to the scheduler.
- // When we get back, the [this] fiber has exited and we
- // can go ahead and return the result.
- Fiber next = _suspendFiber(fiber, false);
- fiber._coroutine = Coroutine._coroutineCurrent();
- _schedule(next);
- return _result;
- }
-
- void _exit(value) {
- Fiber fiber = this;
- List<Fiber> joiners = fiber._joiners;
- if (joiners != null) {
- for (Fiber joiner in joiners) _resumeFiber(joiner);
- joiners.clear();
- }
-
- fiber._isDone = true;
- fiber._result = value;
-
- // Suspend the current fiber. It will never wake up again.
- Fiber next = _suspendFiber(fiber, true);
- fiber._coroutine = null;
- _schedule(next);
- }
-
- static void _resumeFiber(Fiber fiber) {
- _idleFibers = _unlink(fiber);
- _markReady(fiber);
- }
-
- static void _markReady(Fiber fiber) {
- _current = _link(fiber, _current);
- }
-
- static Fiber _link(Fiber fiber, Fiber list) {
- if (list == null) {
- fiber._next = fiber;
- fiber._previous = fiber;
- return fiber;
- }
-
- Fiber next = list._next;
- list._next = fiber;
- next._previous = fiber;
- fiber._previous = list;
- fiber._next = next;
- return list;
- }
-
- static Fiber _unlink(Fiber fiber) {
- Fiber next = fiber._next;
- if (identical(fiber, next)) {
- return null;
- }
-
- Fiber previous = fiber._previous;
- previous._next = next;
- next._previous = previous;
- return next;
- }
-
- static Fiber _suspendFiber(Fiber fiber, bool exiting) {
- Fiber current = _current = _unlink(fiber);
-
- if (exiting) {
- fiber._next = null;
- fiber._previous = null;
- } else {
- _idleFibers = _link(fiber, _idleFibers);
- }
-
- if (current != null) return current;
-
- // If we don't have any idle fibers, halt.
- if (exiting && _idleFibers == null) fletch.halt();
-
- while (true) {
- Process._handleMessages();
- // A call to _handleMessages can handle more messages than signaled, so
- // we can get a following false-positive wakeup. If no new _current is
- // set, simply yield again.
- current = _current;
- if (current != null) return current;
- fletch.yield(fletch.InterruptKind.yield.index);
- }
- }
-
- static void _yieldTo(Fiber from, Fiber to) {
- from._coroutine = Coroutine._coroutineCurrent();
- _schedule(to);
- }
-
- // TODO(kasperl): This is temporary debugging support. We
- // should probably replace this support for passing in an
- // id of some sort when forking a fiber.
- static int _count = 0;
- int _index = _count++;
- toString() => "fiber:$_index";
-
- static void _schedule(Fiber to) {
- _current = to;
- fletch.coroutineChange(to._coroutine, null);
- }
-}
-
-class Coroutine {
-
- // TODO(kasperl): The VM has assumptions about the layout
- // of coroutine fields. We should validate that the code
- // agrees with those assumptions.
- var _stack;
- var _caller;
-
- Coroutine(entry) {
- _stack = _coroutineNewStack(this, entry);
- }
-
- bool get isSuspended => identical(_caller, null);
- bool get isRunning => !isSuspended && !isDone;
- bool get isDone => identical(_caller, this);
-
- call(argument) {
- if (!isSuspended) throw "Cannot call non-suspended coroutine";
- _caller = _coroutineCurrent();
- var result = fletch.coroutineChange(this, argument);
-
- // If the called coroutine is done now, we clear the
- // stack reference in it so the memory can be reclaimed.
- if (isDone) {
- _stack = null;
- } else {
- _caller = null;
- }
- return result;
- }
-
- static yield(value) {
- Coroutine caller = _coroutineCurrent()._caller;
- if (caller == null) throw "Cannot yield outside coroutine";
- return fletch.coroutineChange(caller, value);
- }
-
- _coroutineStart(entry) {
- // The first call to changeStack is actually skipped but we need
- // it to make sure the newly started coroutine is suspended in
- // exactly the same way as we do when yielding.
- var argument = fletch.coroutineChange(0, 0);
- var result = entry(argument);
-
- // Mark this coroutine as done and change back to the caller.
- Coroutine caller = _caller;
- _caller = this;
- fletch.coroutineChange(caller, result);
- }
-
- @fletch.native external static _coroutineCurrent();
- @fletch.native external static _coroutineNewStack(coroutine, entry);
-}
-
-class ProcessDeath {
- final Process process;
- final int _reason;
-
- ProcessDeath._(this.process, this._reason);
-
- DeathReason get reason => DeathReason.values[_reason];
-}
-
-// TODO: Keep these in sync with src/vm/process.h:Signal::Kind
-enum DeathReason {
- CompileTimeError,
- Terminated,
- UncaughtException,
- UnhandledSignal,
- Killed,
-}
-
-class Process {
- // This is the address of the native process/4 so that it fits in a Smi.
- final int _nativeProcessHandle;
-
- bool operator==(other) {
- return
- other is Process &&
- other._nativeProcessHandle == _nativeProcessHandle;
- }
-
- int get hashCode => _nativeProcessHandle.hashCode;
-
- @fletch.native bool link() {
- throw fletch.nativeError;
- }
-
- @fletch.native void unlink() {
- switch (fletch.nativeError) {
- case fletch.wrongArgumentType:
- throw new StateError("Cannot unlink from parent process.");
- default:
- throw fletch.nativeError;
- }
- }
-
- @fletch.native bool monitor(Port port) {
- switch (fletch.nativeError) {
- case fletch.wrongArgumentType:
- throw new StateError("The argument to monitor must be a Port object.");
- default:
- throw fletch.nativeError;
- }
- }
-
- @fletch.native void unmonitor(Port port) {
- switch (fletch.nativeError) {
- case fletch.wrongArgumentType:
- throw new StateError(
- "The argument to unmonitor must be a Port object.");
- default:
- throw fletch.nativeError;
- }
- }
-
- @fletch.native void kill() {
- throw fletch.nativeError;
- }
-
- static Process spawn(Function fn, [argument]) {
- if (!isImmutable(fn)) {
- throw new ArgumentError(
- 'The closure passed to Process.spawn() must be immutable.');
- }
-
- if (!isImmutable(argument)) {
- throw new ArgumentError(
- 'The optional argument passed to Process.spawn() must be immutable.');
- }
-
- return _spawn(_entry, fn, argument, true, true, null);
- }
-
- static Process spawnDetached(Function fn, {Port monitor}) {
- if (!isImmutable(fn)) {
- throw new ArgumentError(
- 'The closure passed to Process.spawnDetached() must be immutable.');
- }
-
- return _spawn(_entry, fn, null, true, false, monitor);
- }
-
- /**
- * Divide the elements in [arguments] into a matching number of processes
- * with [fn] as entry. The current process blocks until all processes have
- * terminated.
- *
- * The elements in [arguments] can be any immutable (see [isImmutable])
- * object.
- *
- * The function [fn] must be a top-level or static function.
- */
- static List divide(fn(argument), List arguments) {
- if (fn == null) {
- throw new ArgumentError.notNull("fn");
- }
- if (!isImmutable(fn)) {
- throw new ArgumentError.value(
- fn, "fn", "Closure passed to Process.divide must be immutable.");
- }
- if (arguments == null) {
- throw new ArgumentError.notNull("arguments");
- }
-
- int length = arguments.length;
- for (int i = 0; i < length; i++) {
- if (!isImmutable(arguments[i])) {
- throw new ArgumentError.value(
- arguments[i], "@$i",
- "Cannot pass mutable arguments to subprocess via Process.divide.");
- }
- }
-
- List channels = new List(length);
- for (int i = 0; i < length; i++) {
- channels[i] = new Channel();
-
- final argument = arguments[i];
- final port = new Port(channels[i]);
- Process.spawnDetached(() {
- try {
- Process.exit(value: fn(argument), to: port);
- } finally {
- // TODO(kustermann): Handle error properly. Once we do this, we can
- // remove the 'fn == null' check above.
- Process.exit(to: port);
- }
- });
- }
- for (int i = 0; i < length; i++) {
- channels[i] = channels[i].receive();
- }
- return channels;
- }
-
- /**
- * Exit the current process. If a non-null [to] port is provided,
- * the process will send the provided [value] to the [to] port as
- * its final action.
- */
- static void exit({value, Port to}) {
- try {
- if (to != null) to._sendExit(value);
- } finally {
- fletch.yield(fletch.InterruptKind.terminate.index);
- }
- }
-
- // Low-level entry for spawned processes.
- static void _entry(fn, argument) {
- if (argument == null) {
- fletch.runToEnd(fn);
- } else {
- fletch.runToEnd(() => fn(argument));
- }
- }
-
- // Low-level helper function for spawning.
- @fletch.native static Process _spawn(Function entry,
- Function fn,
- argument,
- bool linkToChild,
- bool linkFromChild,
- Port monitor) {
- throw new ArgumentError();
- }
-
- static void _handleMessages() {
- Channel channel;
- while ((channel = _queueGetChannel()) != null) {
- var message = _queueGetMessage();
- if (message is ProcessDeath) {
- message = _queueSetupProcessDeath(message);
- }
- channel.send(message);
- }
- }
-
- @fletch.native external static Process get current;
- @fletch.native external static _queueGetMessage();
- @fletch.native external static _queueSetupProcessDeath(ProcessDeath message);
- @fletch.native external static Channel _queueGetChannel();
-}
-
-// Ports allow you to send messages to a channel. Ports are
-// are transferable and can be sent between processes.
-class Port {
- // A Smi stores the aligned pointer to the C++ port object.
- final int _port;
-
- factory Port(Channel channel) {
- return Port._create(channel);
- }
-
- // TODO(kasperl): Temporary debugging aid.
- int get id => _port;
-
- // Send a message to the channel. Not blocking.
- @fletch.native void send(message) {
- switch (fletch.nativeError) {
- case fletch.wrongArgumentType:
- throw new ArgumentError();
- case fletch.illegalState:
- throw new StateError("Port is closed.");
- default:
- throw fletch.nativeError;
- }
- }
-
- @fletch.native void _sendExit(value) {
- throw new StateError("Port is closed.");
- }
-
- @fletch.native external static Port _create(Channel channel);
-}
-
-class Channel {
- Fiber _receiver; // TODO(kasperl): Should this be a queue too?
-
- // TODO(kasperl): Maybe make this a bit smarter and store
- // the elements in a growable list? Consider allowing bounds
- // on the queue size.
- _ChannelEntry _head;
- _ChannelEntry _tail;
-
- // Deliver the message synchronously. If the receiver
- // isn't ready to receive yet, the sender blocks.
- void deliver(message) {
- Fiber sender = Fiber.current;
- _enqueue(new _ChannelEntry(message, sender));
- Fiber next = Fiber._suspendFiber(sender, false);
- // TODO(kasperl): Should we yield to receiver if possible?
- Fiber._yieldTo(sender, next);
- }
-
- // Send a message to the channel. Not blocking.
- void send(message) {
- _enqueue(new _ChannelEntry(message, null));
- }
-
- // Receive a message. If no messages are available
- // the receiver blocks.
- receive() {
- if (_receiver != null) {
- throw new StateError("Channel cannot have multiple receivers (yet).");
- }
-
- if (_head == null) {
- Fiber receiver = Fiber.current;
- _receiver = receiver;
- Fiber next = Fiber._suspendFiber(receiver, false);
- Fiber._yieldTo(receiver, next);
- }
-
- return _dequeue();
- }
-
- _enqueue(_ChannelEntry entry) {
- if (_tail == null) {
- _head = _tail = entry;
- } else {
- _tail = _tail.next = entry;
- }
-
- // Signal the receiver (if any).
- Fiber receiver = _receiver;
- if (receiver != null) {
- _receiver = null;
- Fiber._resumeFiber(receiver);
- }
- }
-
- _dequeue() {
- _ChannelEntry entry = _head;
- _ChannelEntry next = entry.next;
- _head = next;
- if (next == null) _tail = next;
- Fiber sender = entry.sender;
- if (sender != null) Fiber._resumeFiber(sender);
- return entry.message;
- }
-}
-
-class _ChannelEntry {
- final message;
- final Fiber sender;
- _ChannelEntry next;
- _ChannelEntry(this.message, this.sender);
-}
-
-bool isImmutable(Object object) => _isImmutable(object);
-
-@fletch.native external bool _isImmutable(String string);
-
-/// Returns a channel that will receive a message in [milliseconds]
-/// milliseconds.
-// TODO(sigurdm): Move this function?
-Channel sleep(int milliseconds) {
- if (milliseconds is! int) throw new ArgumentError(milliseconds);
- Channel channel = new Channel();
- Port port = new Port(channel);
- _sleep(milliseconds, port);
- return channel;
-}
-
-@fletch.native external void _sleep(int milliseconds, Port port);
« no previous file with comments | « lib/ffi/utf.dart ('k') | lib/fletch_embedded.platform » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698