blob: 05f179468b60ff8fc9b6ea70350f37e9bca50c3d [file] [log] [blame]
// Copyright (c) 2019, 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.
//
// Sample illustrating resource management with an implicit pool in the zone.
import 'dart:ffi';
import 'package:expect/expect.dart';
import 'pool.dart';
import '../dylib_utils.dart';
main() {
final ffiTestDynamicLibrary =
dlopenPlatformSpecific("ffi_test_dynamic_library");
final MemMove = ffiTestDynamicLibrary.lookupFunction<
Void Function(Pointer<Void>, Pointer<Void>, IntPtr),
void Function(Pointer<Void>, Pointer<Void>, int)>("MemMove");
// To ensure resources are freed, wrap them in a [using] call.
usePool(() {
final p = currentPool.allocate<Int64>(count: 2);
p[0] = 24;
MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
print(p[1]);
Expect.equals(24, p[1]);
});
// Resources are freed also when abnormal control flow occurs.
try {
usePool(() {
final p = currentPool.allocate<Int64>(count: 2);
p[0] = 25;
MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), 8);
print(p[1]);
Expect.equals(25, p[1]);
throw Exception("Some random exception");
});
} on RethrownError catch (e) {
// Note that exceptions are wrapped when using zones.
print("Caught exception: ${e.original}");
}
// In a pool multiple resources can be allocated, which will all be freed
// at the end of the scope.
usePool(() {
final p = currentPool.allocate<Int64>(count: 2);
final p2 = currentPool.allocate<Int64>(count: 2);
p[0] = 1;
p[1] = 2;
MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
Expect.equals(1, p2[0]);
Expect.equals(2, p2[1]);
});
// If the resource allocation happens in a different scope, it is in the
// same zone, so it's lifetime is automatically managed by the pool.
f1() {
return currentPool.allocate<Int64>(count: 2);
}
usePool(() {
final p = f1();
final p2 = f1();
p[0] = 1;
p[1] = 2;
MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
Expect.equals(1, p2[0]);
Expect.equals(2, p2[1]);
});
// Using Strings.
usePool(() {
final p = "Hello world!".toUtf8(currentPool);
print(p.contents());
});
final allocateResource = ffiTestDynamicLibrary.lookupFunction<
Pointer<SomeResource> Function(),
Pointer<SomeResource> Function()>("AllocateResource");
final useResource = ffiTestDynamicLibrary.lookupFunction<
Void Function(Pointer<SomeResource>),
void Function(Pointer<SomeResource>)>("UseResource");
final releaseResource = ffiTestDynamicLibrary.lookupFunction<
Void Function(Pointer<SomeResource>),
void Function(Pointer<SomeResource>)>("ReleaseResource");
// Using an FFI call to release a resource.
usePool(() {
final r = currentPool.using(allocateResource(), releaseResource);
useResource(r);
});
// Using an FFI call to release a resource with abnormal control flow.
try {
usePool(() {
final r = currentPool.using(allocateResource(), releaseResource);
useResource(r);
throw Exception("Some random exception");
});
// Resource has been freed.
} on RethrownError catch (e) {
// Note that exceptions are wrapped when using zones.
print("Caught exception: ${e.original}");
}
}
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}