1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +00:00

Reapply "Create _nullFuture and _falseFuture in the root zone."

Originally landed by https://dart-review.googlesource.com/c/sdk/+/49509
Reverted because an internal test is fragile and changes behavior when the bug is fixed.

Change-Id: I8516082e5741547c46aa521a91826846dc101303
Reviewed-on: https://dart-review.googlesource.com/63743
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Leaf Petersen <leafp@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2018-07-16 16:19:15 +00:00 committed by commit-bot@chromium.org
parent ce682638d9
commit 91ce347309
4 changed files with 58 additions and 9 deletions

View File

@ -34,6 +34,13 @@
* Re-enable `Iterable.whereType`. The method was disabled because code
was still being compiled in Dart 1 mode, and the function was
error-prone when used in that code.
* `dart:async`
* Changed an internal lazily-allocated reusable "null future" to always belong
to the root zone. This avoids race conditions where the first access to the
future determined which zone it would belong to. The zone is only used
for *scheduling* the callback of listeners, the listeners themselves will
run in the correct zone in any case.
Issue [#32556](http://dartbug.com/32556).
## 2.0.0-dev.67.0

View File

@ -148,10 +148,12 @@ abstract class FutureOr<T> {
*/
abstract class Future<T> {
/// A `Future<Null>` completed with `null`.
static final _Future<Null> _nullFuture = new _Future<Null>.value(null);
static final _Future<Null> _nullFuture =
new _Future<Null>.zoneValue(null, Zone.root);
/// A `Future<bool>` completed with `false`.
static final _Future<bool> _falseFuture = new _Future<bool>.value(false);
static final _Future<bool> _falseFuture =
new _Future<bool>.zoneValue(false, Zone.root);
/**
* Creates a future containing the result of calling [computation]

View File

@ -186,7 +186,7 @@ class _Future<T> implements Future<T> {
* Until the future is completed, the field may hold the zone that
* listener callbacks used to create this future should be run in.
*/
final Zone _zone = Zone.current;
final Zone _zone;
/**
* Either the result, a list of listeners or another future.
@ -206,20 +206,24 @@ class _Future<T> implements Future<T> {
var _resultOrListeners;
// This constructor is used by async/await.
_Future();
_Future() : _zone = Zone.current;
_Future.immediate(FutureOr<T> result) {
_Future.immediate(FutureOr<T> result) : _zone = Zone.current {
_asyncComplete(result);
}
_Future.immediateError(var error, [StackTrace stackTrace]) {
/** Creates a future with the value and the specified zone. */
_Future.zoneValue(T value, this._zone) {
_setValue(value);
}
_Future.immediateError(var error, [StackTrace stackTrace])
: _zone = Zone.current {
_asyncCompleteError(error, stackTrace);
}
/** Creates a future that is already completed with the value. */
_Future.value(T value) {
_setValue(value);
}
_Future.value(T value) : this.zoneValue(value, Zone.current);
bool get _mayComplete => _state == _stateIncomplete;
bool get _isPendingComplete => _state == _statePendingComplete;

View File

@ -0,0 +1,36 @@
// Copyright (c) 2013, 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 "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
import 'dart:async';
main() {
asyncStart(2);
() async {
var it = new StreamIterator(new Stream.fromIterable([]));
Expect.isFalse(await it.moveNext());
Future nullFuture;
Future falseFuture;
runZoned(() {
nullFuture = (new StreamController()..stream.listen(null).cancel()).done;
falseFuture = it.moveNext();
}, zoneSpecification: new ZoneSpecification(scheduleMicrotask:
(Zone self, ZoneDelegate parent, Zone zone, void f()) {
Expect.fail("Should not be called");
}));
nullFuture.then((value) {
Expect.isNull(value);
asyncEnd();
});
falseFuture.then((value) {
Expect.isFalse(value);
asyncEnd();
});
}();
}