Skip to content

Commit

Permalink
Merge pull request 'fibers' (dart-lang#20) from fibers into main
Browse files Browse the repository at this point in the history
  • Loading branch information
antonbashir committed Nov 5, 2024
2 parents 29185f9 + 8011517 commit 41018d5
Show file tree
Hide file tree
Showing 27 changed files with 2,121 additions and 3,514 deletions.
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ AllowShortIfStatementsOnASingleLine: 'true'

# Put escaped newlines into the rightmost column.
AlignEscapedNewlinesLeft: false

ColumnLimit: 0
84 changes: 84 additions & 0 deletions runtime/tests/vm/dart/fiber/fiber_launch_suite.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import 'dart:fiber';
import 'dart:async';
import 'package:expect/expect.dart';

final tests = [
testEmpty,
testIdle,
testTerminated,
testFunction,
testClosure,
testFork,
testForks,
];

void testEmpty() {
Fiber.launch(() {});
}

void testIdle() {
Expect.throws(
() => Fiber.launch(() => Fiber.spawn(() => Fiber.reschedule())),
(error) => error is StateError && error.message == "There are no scheduled fibers and FiberProcessor idle function is not defined",
);
}

void testTerminated() {
Fiber.launch(() => Fiber.spawn(() => Fiber.reschedule()), terminate: true);
}

void testFunction() {
void entry() {
Expect.equals("argument", Fiber.current().argument.positioned(0));
}

Fiber.launch(entry, argument: ["argument"], terminate: true);
}

void testClosure() {
Fiber.launch(
() => Expect.equals("argument", Fiber.current().argument.positioned(0)),
argument: ["argument"],
terminate: true,
);
}

void testFork() {
void child() {
Expect.equals("child", Fiber.current().name);
Expect.equals("child", Fiber.current().argument.positioned(0));
}

void main() {
Expect.equals("main", Fiber.current().argument.positioned(0));
Fiber.spawn(child, name: "child", argument: ["child"]);
}

Fiber.launch(main, argument: ["main"], terminate: true);
}

void testForks() {
void child3() {
Expect.equals("child3", Fiber.current().name);
Expect.equals("child3", Fiber.current().argument.positioned(0));
}

void child2() {
Expect.equals("child2", Fiber.current().name);
Expect.equals("child2", Fiber.current().argument.positioned(0));
Fiber.spawn(child3, name: "child3", argument: ["child3"]);
}

void child1() {
Expect.equals("child1", Fiber.current().name);
Expect.equals("child1", Fiber.current().argument.positioned(0));
Fiber.spawn(child2, name: "child2", argument: ["child2"]);
}

void main() {
Expect.equals("main", Fiber.current().argument.positioned(0));
Fiber.spawn(child1, name: "child1", argument: ["child1"]);
}

Fiber.launch(main, argument: ["main"], terminate: true);
}
24 changes: 24 additions & 0 deletions runtime/tests/vm/dart/fiber/fiber_lifecycle_suite.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'dart:fiber';
import 'dart:async';
import 'package:expect/expect.dart';

final tests = [
testRecycle,
];

void testRecycle() {
Fiber.launch(
() {
var localState = "main";
final child = Fiber.child(
() => localState = "$localState -> child",
persistent: true,
);
Fiber.fork(child);
Expect.isTrue(child.state.finished);
Fiber.fork(child);
Expect.equals("main -> child -> child", localState);
},
terminate: true,
);
}
89 changes: 89 additions & 0 deletions runtime/tests/vm/dart/fiber/fiber_state_suite.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import 'dart:fiber';
import 'dart:async';
import 'package:expect/expect.dart';

final tests = [
testGlobalState,
testClosureState,
];

var globalStateValue = "";
void testGlobalState() {
void child() {
globalStateValue += "child -> ";
Fiber.reschedule();
globalStateValue += "child";
}

void main() {
globalStateValue = "";
globalStateValue += "main -> ";
Fiber.schedule(Fiber.current());
Fiber.spawn(child);
globalStateValue += "main -> ";
Fiber.reschedule();
Expect.equals("main -> child -> main -> child", globalStateValue);
}

Fiber.launch(main, terminate: true);
}

void testClosureState() {
var localState = "localState";
Fiber.launch(
() {
Expect.equals("localState", localState);
localState = "after fiber";
},
terminate: true,
);
Expect.equals("after fiber", localState);

localState = "localState";
Fiber.launch(
() {
Expect.equals("localState", localState);
localState = "after main fiber";
Fiber.schedule(Fiber.current());
Fiber.spawn(
() {
Expect.equals("after main fiber", localState);
localState = "after child fiber";
Fiber.reschedule();
Expect.equals("after child fiber after main fiber", localState);
localState = "finish";
},
name: "child",
);
Expect.equals("after child fiber", localState);
localState = "after child fiber after main fiber";
Fiber.suspend();
},
terminate: true,
);
Expect.equals("finish", localState);

localState = "level 1";
Fiber.launch(
() {
Expect.equals("level 1", localState);
localState = "level 2";
Fiber.spawn(
() {
Expect.equals("level 2", localState);
localState = "level 3";
Fiber.spawn(
() {
Expect.equals("level 3", localState);
localState = "level 4";
},
name: "child",
);
},
name: "child",
);
},
terminate: true,
);
Expect.equals("level 4", localState);
}
139 changes: 36 additions & 103 deletions runtime/tests/vm/dart/fiber/fiber_test.dart
Original file line number Diff line number Diff line change
@@ -1,107 +1,40 @@
import 'dart:fiber';
import 'dart:async';
import 'package:expect/expect.dart';

var globalState = "";

void main() {
testBase();
testClosures();
testRecycle();
}

void testBase() {
Fiber.launch(mainEntry, terminate: true);
}

void testRecycle() {
Fiber.launch(
() {
var localState = "main";
final child = Fiber.child(
() => localState = "$localState -> child",
persistent: true,
);
Fiber.fork(child);
Fiber.fork(child);
Expect.equals("main -> child -> child", localState);
},
terminate: true,
);
}

void mainEntry() {
globalState = "";
globalState += "main -> ";
Fiber.schedule(Fiber.current());
Fiber.spawn(childEntry);
globalState += "main -> ";
Fiber.reschedule();
Expect.equals("main -> child -> main -> child", globalState);
}

void childEntry() {
globalState += "child -> ";
Fiber.reschedule();
globalState += "child";
}

void testClosures() {
var localState = "localState";
Fiber.launch(
() {
Expect.equals("localState", localState);
localState = "after fiber";
},
terminate: true,
);
Expect.equals("after fiber", localState);

localState = "localState";
Fiber.launch(
() {
Expect.equals("localState", localState);
localState = "after main fiber";
Fiber.schedule(Fiber.current());
Fiber.spawn(
() {
Expect.equals("after main fiber", localState);
localState = "after child fiber";
Fiber.reschedule();
Expect.equals("after child fiber after main fiber", localState);
localState = "finish";
},
name: "child",
);
Expect.equals("after child fiber", localState);
localState = "after child fiber after main fiber";
Fiber.suspend();
},
terminate: true,
);
Expect.equals("finish", localState);

localState = "level 1";
Fiber.launch(
() {
Expect.equals("level 1", localState);
localState = "level 2";
Fiber.spawn(
() {
Expect.equals("level 2", localState);
localState = "level 3";
Fiber.spawn(
() {
Expect.equals("level 3", localState);
localState = "level 4";
},
name: "child",
);
},
name: "child",
);
},
terminate: true,
);
Expect.equals("level 4", localState);
import 'fiber_lifecycle_suite.dart' as lifecycle;
import 'fiber_launch_suite.dart' as launch;
import 'fiber_state_suite.dart' as state;

final suites = {
"launch": launch.tests,
"state": state.tests,
"lifecycle": lifecycle.tests,
};

void main(List<String> arguments) {
if (arguments.isEmpty) {
for (var suite in suites.entries) {
print("Processing suite: ${suite.key}");
for (var test in suite.value) {
final function = RegExp(r"Function 'test(.+)'").firstMatch(test.toString())!.group(1);
print("Processing test: test${function}");
test();
print("Test: test${function} finished");
}
print("Suite: ${suite.key} finished\n");
}
return;
}
final suite = suites[arguments[0]];
if (suite == null) return;
print("Processing suite: ${arguments[0]}");
for (var test in suite!) {
final function = RegExp(r"Function 'test(.+)'").firstMatch(test.toString())!.group(1);
if (arguments.length == 1 || function == arguments[1].toLowerCase()) {
print("Processing test: test${function}");
test();
print("Test: test${function} finished");
}
}
print("Suite: ${arguments[0]} finished");
}
Loading

0 comments on commit 41018d5

Please sign in to comment.