blob: 19417d39818b1eba141d5bdb78540009c2a92569 [file]
// Copyright (c) 2025, 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:async';
import 'dart:ffi';
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:isolate';
import 'package:ffi/ffi.dart' as ffi;
import 'package:unix_api/src/libc_bindings.g.dart';
import 'package:unix_api/unix_api.dart';
import 'package:test/test.dart';
typedef pthread_create_callback = ffi.Void Function(ffi.Pointer<ffi.Void>);
void main() {
group('pthread', () {
late ffi.Arena arena;
setUp(() {
arena = ffi.Arena();
});
tearDown(() {
arena.releaseAll();
});
test('pthread_create/pthread_detach', () async {
final thread = arena<pthread_t>();
final c = Completer<void>();
final threadCallback = NativeCallable<pthread_create_callback>.listener((
ffi.Pointer<ffi.Void> arg,
) async {
c.complete();
});
pthread_create(
thread,
nullptr,
threadCallback.nativeFunction.cast(),
nullptr,
);
pthread_detach(thread.ref);
await c.future;
});
test('pthread_mutex_*', () async {
final mutex = arena<pthread_mutex_t>();
final time = arena<timespec>();
time.ref.tv_nsec = 0;
time.ref.tv_sec = 0;
expect(pthread_mutex_init(mutex, nullptr), 0);
expect(pthread_mutex_lock(mutex), 0);
await Isolate.run(() {
assert(
pthread_mutex_timedlock(mutex, time) ==
((Platform.isAndroid || Platform.isLinux) ? ETIMEDOUT : ENOSYS),
);
});
final lockTestIsolate = Isolate.run(() {
assert(pthread_mutex_lock(mutex) == 0);
});
pthread_mutex_unlock(mutex);
await lockTestIsolate;
assert(pthread_mutex_unlock(mutex) == 0); // Locked by Isolate.
expect(pthread_mutex_destroy(mutex), 0);
});
test('pthread_cond_*', () async {
final cond = arena<pthread_cond_t>();
final mutex = arena<pthread_mutex_t>();
final time = arena<timespec>();
time.ref.tv_nsec = 0;
time.ref.tv_sec = 0;
expect(pthread_mutex_init(mutex, nullptr), 0);
expect(pthread_cond_init(cond, nullptr), 0);
expect(pthread_mutex_lock(mutex), 0);
expect(pthread_cond_timedwait(cond, mutex, time), ETIMEDOUT);
expect(pthread_mutex_unlock(mutex), 0);
// Tests waiting on a signal.
var waitOnSignalDone = false;
Isolate.run(() {
assert(pthread_mutex_lock(mutex) == 0);
assert(pthread_cond_wait(cond, mutex) == 0);
assert(pthread_mutex_unlock(mutex) == 0);
}).whenComplete(() => waitOnSignalDone = true);
while (!waitOnSignalDone) {
expect(pthread_cond_signal(cond), 0);
await Future.delayed(const Duration());
}
// Tests waiting on a signal.
var waitOnSignalBroadcast = false;
Isolate.run(() {
assert(pthread_mutex_lock(mutex) == 0);
assert(pthread_cond_wait(cond, mutex) == 0);
assert(pthread_mutex_unlock(mutex) == 0);
}).whenComplete(() => waitOnSignalBroadcast = true);
while (!waitOnSignalBroadcast) {
expect(pthread_cond_broadcast(cond), 0);
await Future.delayed(const Duration());
}
expect(pthread_mutex_destroy(mutex), 0);
expect(pthread_cond_destroy(cond), 0);
});
});
}