blob: 9124231398a15f26094135c6368c5613e8b227f3 [file] [edit]
// Copyright (c) 2023, the Dart 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 file.
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:ffi/ffi.dart';
import 'package:native_synchronization/primitives.dart';
import 'package:native_synchronization/sendable.dart';
import 'package:test/test.dart';
void main() {
group('mutex', () {
test('simple', () {
final mutex = Mutex();
expect(mutex.runLocked(() => 42), equals(42));
});
Future<String> spawnHelperIsolate(
int ptrAddress, Sendable<Mutex> sendableMutex) {
return Isolate.run(() {
final ptr = Pointer<Uint8>.fromAddress(ptrAddress);
final mutex = sendableMutex.materialize();
while (true) {
sleep(const Duration(milliseconds: 10));
if (mutex.runLocked(() {
if (ptr.value == 2) {
return true;
}
ptr.value = 0;
sleep(const Duration(milliseconds: 500));
ptr.value = 1;
return false;
})) {
break;
}
}
return 'success';
});
}
test('isolate', () async {
await using((arena) async {
final ptr = arena.allocate<Uint8>(1);
final mutex = Mutex();
final helperResult = spawnHelperIsolate(ptr.address, mutex.asSendable);
while (true) {
final sw = Stopwatch()..start();
if (mutex.runLocked(() {
if (sw.elapsedMilliseconds > 300 && ptr.value == 1) {
ptr.value = 2;
return true;
}
return false;
})) {
break;
}
await Future<void>.delayed(const Duration(milliseconds: 10));
}
expect(await helperResult, equals('success'));
});
});
});
group('condvar', () {
Future<String> spawnHelperIsolate(
int ptrAddress,
Sendable<Mutex> sendableMutex,
Sendable<ConditionVariable> sendableCondVar) {
return Isolate.run(() {
final ptr = Pointer<Uint8>.fromAddress(ptrAddress);
final mutex = sendableMutex.materialize();
final condVar = sendableCondVar.materialize();
return mutex.runLocked(() {
ptr.value = 1;
while (ptr.value == 1) {
condVar.wait(mutex);
}
return ptr.value == 2 ? 'success' : 'failure';
});
});
}
test('isolate', () async {
await using((arena) async {
final ptr = arena.allocate<Uint8>(1);
final mutex = Mutex();
final condVar = ConditionVariable();
final helperResult = spawnHelperIsolate(
ptr.address, mutex.asSendable, condVar.asSendable);
while (true) {
final success = mutex.runLocked(() {
if (ptr.value == 1) {
ptr.value = 2;
condVar.notify();
return true;
}
return false;
});
if (success) {
break;
}
await Future<void>.delayed(const Duration(milliseconds: 20));
}
expect(await helperResult, equals('success'));
});
});
});
}