diff --git a/CHANGELOG.md b/CHANGELOG.md index 9acca14..7a52326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.0 + +- Add a closed state to `Mailbox`. + ## 0.2.0 - Lower SDK lower bound to 3.0.0. diff --git a/lib/mailbox.dart b/lib/mailbox.dart index 0871a7c..ae0ff47 100644 --- a/lib/mailbox.dart +++ b/lib/mailbox.dart @@ -47,6 +47,7 @@ class Mailbox { static const _stateEmpty = 0; static const _stateFull = 1; + static const _stateClosed = 2; static final finalizer = Finalizer((Pointer<_MailboxRepr> mailbox) { calloc.free(mailbox.ref.buffer); @@ -72,7 +73,7 @@ class Mailbox { final buffer = message.isEmpty ? nullptr : _toBuffer(message); _mutex.runLocked(() { if (_mailbox.ref.state != _stateEmpty) { - throw StateError('Mailbox is full'); + throw StateError('Mailbox is closed or full'); } _mailbox.ref.state = _stateFull; @@ -83,15 +84,36 @@ class Mailbox { }); } + /// Close a mailbox. + /// + /// If mailbox already contains a message then it will be dropped. + void close() => _mutex.runLocked(() { + if (_mailbox.ref.state == _stateFull) { + if (_mailbox.ref.bufferLength > 0) { + malloc.free(_mailbox.ref.buffer); + } + } + + _mailbox.ref.state = _stateClosed; + _mailbox.ref.buffer = nullptr; + _mailbox.ref.bufferLength = 0; + + _condVar.notify(); + }); + /// Take a message from the mailbox. /// /// If mailbox is empty this will synchronously block until message /// is available. Uint8List take() => _mutex.runLocked(() { - while (_mailbox.ref.state != _stateFull) { + while (_mailbox.ref.state == _stateEmpty) { _condVar.wait(_mutex); } + if (_mailbox.ref.state == _stateClosed) { + throw StateError('Mailbox is closed'); + } + final result = _toList(_mailbox.ref.buffer, _mailbox.ref.bufferLength); _mailbox.ref.state = _stateEmpty; diff --git a/pubspec.yaml b/pubspec.yaml index e16317f..bf93c3f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: native_synchronization description: Low level synchronization primitives built on dart:ffi. -version: 0.2.0 +version: 0.3.0 repository: https://github.com/dart-lang/native_synchronization environment: diff --git a/test/mailbox_test.dart b/test/mailbox_test.dart index 2400d56..9b32bfa 100644 --- a/test/mailbox_test.dart +++ b/test/mailbox_test.dart @@ -29,4 +29,25 @@ void main() { expect(value[41], equals(42)); expect(await helperResult, equals('success')); }); + + Future startHelperIsolateClose(Sendable sendableMailbox) { + return Isolate.run(() { + sleep(const Duration(milliseconds: 500)); + final mailbox = sendableMailbox.materialize(); + try { + mailbox.take(); + } catch (_) { + return 'success'; + } + return 'failed'; + }); + } + + test('mailbox close', () async { + final mailbox = Mailbox(); + mailbox.put(Uint8List(42)..[41] = 42); + mailbox.close(); + final helperResult = startHelperIsolateClose(mailbox.asSendable); + expect(await helperResult, equals('success')); + }); }