Skip to content

Commit 80894f7

Browse files
authored
Add closed state to Mailbox (dart-archive/native_synchronization#26)
* Add closed state to Mailbox * Update documentation
1 parent dc5c91d commit 80894f7

File tree

4 files changed

+53
-6
lines changed

4 files changed

+53
-6
lines changed

pkgs/native_synchronization/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.0
2+
3+
- Add a closed state to `Mailbox`.
4+
15
## 0.2.0
26

37
- Lower SDK lower bound to 3.0.0.

pkgs/native_synchronization/lib/mailbox.dart

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class Mailbox {
4747

4848
static const _stateEmpty = 0;
4949
static const _stateFull = 1;
50+
static const _stateClosed = 2;
5051

5152
static final finalizer = Finalizer((Pointer<_MailboxRepr> mailbox) {
5253
calloc.free(mailbox.ref.buffer);
@@ -67,12 +68,13 @@ class Mailbox {
6768

6869
/// Place a message into the mailbox if has space for it.
6970
///
70-
/// If mailbox already contains a message then [put] will throw.
71+
/// If mailbox already contains a message or mailbox is closed then [put] will
72+
/// throw [StateError].
7173
void put(Uint8List message) {
7274
final buffer = message.isEmpty ? nullptr : _toBuffer(message);
7375
_mutex.runLocked(() {
7476
if (_mailbox.ref.state != _stateEmpty) {
75-
throw StateError('Mailbox is full');
77+
throw StateError('Mailbox is closed or full');
7678
}
7779

7880
_mailbox.ref.state = _stateFull;
@@ -83,15 +85,35 @@ class Mailbox {
8385
});
8486
}
8587

88+
/// Close a mailbox.
89+
///
90+
/// If mailbox already contains a message then [close] will drop the message.
91+
void close() => _mutex.runLocked(() {
92+
if (_mailbox.ref.state == _stateFull && _mailbox.ref.bufferLength > 0) {
93+
malloc.free(_mailbox.ref.buffer);
94+
}
95+
96+
_mailbox.ref.state = _stateClosed;
97+
_mailbox.ref.buffer = nullptr;
98+
_mailbox.ref.bufferLength = 0;
99+
100+
_condVar.notify();
101+
});
102+
86103
/// Take a message from the mailbox.
87104
///
88-
/// If mailbox is empty this will synchronously block until message
89-
/// is available.
105+
/// If mailbox is empty then [take] will synchronously block until message
106+
/// is available or mailbox is closed. If mailbox is closed then [take] will
107+
/// throw [StateError].
90108
Uint8List take() => _mutex.runLocked(() {
91-
while (_mailbox.ref.state != _stateFull) {
109+
while (_mailbox.ref.state == _stateEmpty) {
92110
_condVar.wait(_mutex);
93111
}
94112

113+
if (_mailbox.ref.state == _stateClosed) {
114+
throw StateError('Mailbox is closed');
115+
}
116+
95117
final result = _toList(_mailbox.ref.buffer, _mailbox.ref.bufferLength);
96118

97119
_mailbox.ref.state = _stateEmpty;

pkgs/native_synchronization/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: native_synchronization
22
description: Low level synchronization primitives built on dart:ffi.
3-
version: 0.2.0
3+
version: 0.3.0
44
repository: https://github.com/dart-lang/native_synchronization
55

66
environment:

pkgs/native_synchronization/test/mailbox_test.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,25 @@ void main() {
2929
expect(value[41], equals(42));
3030
expect(await helperResult, equals('success'));
3131
});
32+
33+
Future<String> startHelperIsolateClose(Sendable<Mailbox> sendableMailbox) {
34+
return Isolate.run(() {
35+
sleep(const Duration(milliseconds: 500));
36+
final mailbox = sendableMailbox.materialize();
37+
try {
38+
mailbox.take();
39+
} catch (_) {
40+
return 'success';
41+
}
42+
return 'failed';
43+
});
44+
}
45+
46+
test('mailbox close', () async {
47+
final mailbox = Mailbox();
48+
mailbox.put(Uint8List(42)..[41] = 42);
49+
mailbox.close();
50+
final helperResult = startHelperIsolateClose(mailbox.asSendable);
51+
expect(await helperResult, equals('success'));
52+
});
3253
}

0 commit comments

Comments
 (0)