Skip to content

Commit

Permalink
RDART-1028: Use Zone.current.bindUnaryCallbackGuarded for RawReceive…
Browse files Browse the repository at this point in the history
…Port.handler (#1683)

* Use Zone.current.bindUnaryCallbackGuarded for RawReceivePort.handler

* Update CHANGELOG

* Add comment explaining fix
  • Loading branch information
nielsenko authored May 23, 2024
1 parent 2dd3bff commit 86ad06c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Fixed
* Private fields did not work with default values. (Issue [#1663](https://github.com/realm/realm-dart/issues/1663))
* Invoke scheduler callback on Zone.current. (Issue [#1676](https://github.com/realm/realm-dart/issues/1676))

* Having links in a nested collections would leave the file inconsistent if the top object is removed. (Core 14.7.0)

Expand Down
42 changes: 27 additions & 15 deletions packages/realm_dart/lib/src/scheduler.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2022 MongoDB, Inc.
// SPDX-License-Identifier: Apache-2.0

import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';
import 'package:realm_dart/src/logging.dart';
Expand All @@ -20,25 +21,36 @@ class Scheduler {

Scheduler._() {
_receivePortFinalizer.attach(this, _receivePort, detach: this);

_receivePort.handler = (dynamic message) {
if (message is List) {
// currently the only `message as List` is from the logger.
final category = LogCategory.fromString(message[0] as String);
final level = LogLevel.values[message[1] as int];
final text = message[2] as String;
Realm.logger.raise((category: category, level: level, message: text));
} else if (message is int) {
realmCore.invokeScheduler(message);
} else {
Realm.logger.log(LogLevel.error, 'Unexpected Scheduler message type: ${message.runtimeType} - $message');
}
};

// There be dragons here!!!
//
// As of Dart 3.4 (Flutter 3.22) we started seeing uncaught exceptions on
// the receivePort handler (issue #1676), stating that:
// "argument value for 'return_value' is null" in
// RealmLibrary.realm_scheduler_perform_work, but obviously a void method
// don't return anything, so this is really a Dart issue.
//
// However, by ensuring the callback happens in the current zone (as it
// rightfully should), and using bindUnaryCallbackGuarded, we can avoid
// these.
_receivePort.handler = Zone.current.bindUnaryCallbackGuarded(_handle);
final sendPort = _receivePort.sendPort;
handle = realmCore.createScheduler(Isolate.current.hashCode, sendPort.nativePort);
}

void _handle(dynamic message) {
if (message is List) {
// currently the only `message as List` is from the logger.
final category = LogCategory.fromString(message[0] as String);
final level = LogLevel.values[message[1] as int];
final text = message[2] as String;
Realm.logger.raise((category: category, level: level, message: text));
} else if (message is int) {
realmCore.invokeScheduler(message);
} else {
Realm.logger.log(LogLevel.error, 'Unexpected Scheduler message type: ${message.runtimeType} - $message');
}
}

void stop() {
if (handle.released) {
return;
Expand Down

0 comments on commit 86ad06c

Please sign in to comment.