blob: 9f7e24092d6d8d180388008134ea4be1284a3843 [file] [edit]
// Copyright (c) 2026, 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.
//
// Tests Isolate threading API.
//
// VMOptions=--experimental-shared-data
//
// SharedObjects=ffi_test_functions
import 'dart:async';
import 'dart:concurrent';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:dart_internal/isolate_group.dart' show IsolateGroup;
import "package:expect/async_helper.dart";
import 'package:expect/expect.dart';
import 'package:ffi/ffi.dart';
import 'dylib_utils.dart';
import 'threading_utils.dart';
@pragma('vm:shared')
final counter = Uint8List(1);
@pragma('vm:shared')
final dartSetCurrentThreadOwnsIsolate = DynamicLibrary.executable()
.lookup<NativeFunction<Void Function()>>("Dart_SetCurrentThreadOwnsIsolate")
.asFunction<void Function()>();
DynamicLibrary get ffiTestFunctions => DynamicLibrary.open(
"libffi_test_functions.${Platform.isMacOS ? 'dylib' : 'so'}",
);
typedef CallbackReturningIntNativeType = Int32 Function(Int32, Int32);
typedef TwoIntFnNativeType = Int32 Function(Pointer, Int32, Int32);
typedef TwoIntFnType = int Function(Pointer, int, int);
TwoIntFnType get callTwoIntFunction => ffiTestFunctions
.lookupFunction<TwoIntFnNativeType, TwoIntFnType>("CallTwoIntFunction");
int threadMain(Pointer<Void> data) {
print('threadMain started');
final callback =
NativeCallable<CallbackReturningIntNativeType>.isolateGroupBound((
int a,
int b,
) {
print('threadMain callback $a + $b');
return a + b;
}, exceptionalReturn: 1111);
print('created isolateGroupBound in threadMain and calling it');
Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));
callback.close();
final new_isolate = Isolate.create(debugName: "helper");
new_isolate.runSync(() {
dartSetCurrentThreadOwnsIsolate();
});
new_isolate.runSync(() {
print('Hello, new isolate!');
});
new_isolate.shutdownSync();
return 0;
}
Future<void> testRun() async {
{
final callback =
NativeCallable<CallbackReturningIntNativeType>.isolateGroupBound((
int a,
int b,
) {
print('testRun callback $a + $b');
return a + b;
}, exceptionalReturn: 1111);
Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));
callback.close();
}
if (Platform.isWindows) {
return; // pthread is not available on Windows.
}
final callback =
NativeCallable<IntPtr Function(Pointer<Void>)>.isolateGroupBound(
threadMain,
exceptionalReturn: -1,
);
final threadInfo = ThreadInfo();
Expect.equals(0, pthreadAttrInit(threadInfo.ptr_attr));
Expect.equals(
0,
pthreadCreate(
threadInfo.ptr_tid,
threadInfo.ptr_attr,
callback.nativeFunction,
threadInfo.ptr_data.cast<Void>(),
),
);
threadInfo.joinAndDestroy();
}
main(List<String> args, List<SendPort>? message) async {
if (Platform.isWindows) {
return; // pthread is not available on Windows.
}
asyncStart();
await testRun();
asyncEnd();
}