| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library schedule; | 5 library schedule; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:stack_trace/stack_trace.dart'; | 10 import 'package:stack_trace/stack_trace.dart'; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 setUp(); | 127 setUp(); |
| 128 } catch (e, stackTrace) { | 128 } catch (e, stackTrace) { |
| 129 // Even though the scheduling failed, we need to run the onException and | 129 // Even though the scheduling failed, we need to run the onException and |
| 130 // onComplete queues, so we set the schedule state to RUNNING. | 130 // onComplete queues, so we set the schedule state to RUNNING. |
| 131 _state = ScheduleState.RUNNING; | 131 _state = ScheduleState.RUNNING; |
| 132 throw new ScheduleError.from(this, e, stackTrace: stackTrace); | 132 throw new ScheduleError.from(this, e, stackTrace: stackTrace); |
| 133 } | 133 } |
| 134 | 134 |
| 135 _state = ScheduleState.RUNNING; | 135 _state = ScheduleState.RUNNING; |
| 136 return tasks._run(); | 136 return tasks._run(); |
| 137 }).catchError((e) { | 137 }).catchError((error, stackTrace) { |
| 138 _addError(e); | 138 _addError(error, stackTrace); |
| 139 return onException._run().catchError((innerError) { | 139 return onException._run().catchError((innerError, innerTrace) { |
| 140 // If an error occurs in a task in the onException queue, make sure it's | 140 // If an error occurs in a task in the onException queue, make sure it's |
| 141 // registered in the error list and re-throw it. We could also re-throw | 141 // registered in the error list and re-throw it. We could also re-throw |
| 142 // `e`; ultimately, all the errors will be shown to the user if any | 142 // `error`; ultimately, all the errors will be shown to the user if any |
| 143 // ScheduleError is thrown. | 143 // ScheduleError is thrown. |
| 144 _addError(innerError); | 144 _addError(innerError, innerTrace); |
| 145 throw innerError; | 145 throw innerError; |
| 146 }).then((_) { | 146 }).then((_) { |
| 147 // If there are no errors in the onException queue, re-throw the | 147 // If there are no errors in the onException queue, re-throw the |
| 148 // original error that caused it to run. | 148 // original error that caused it to run. |
| 149 throw e; | 149 throw error; |
| 150 }); | 150 }); |
| 151 }).whenComplete(() { | 151 }).whenComplete(() { |
| 152 return onComplete._run().catchError((e) { | 152 return onComplete._run().catchError((error, stackTrace) { |
| 153 // If an error occurs in a task in the onComplete queue, make sure it's | 153 // If an error occurs in a task in the onComplete queue, make sure it's |
| 154 // registered in the error list and re-throw it. | 154 // registered in the error list and re-throw it. |
| 155 _addError(e); | 155 _addError(error, stackTrace); |
| 156 throw e; | 156 throw error; |
| 157 }); | 157 }); |
| 158 }).whenComplete(() { | 158 }).whenComplete(() { |
| 159 if (_timeoutTimer != null) _timeoutTimer.cancel(); | 159 if (_timeoutTimer != null) _timeoutTimer.cancel(); |
| 160 _state = ScheduleState.DONE; | 160 _state = ScheduleState.DONE; |
| 161 }); | 161 }); |
| 162 } | 162 } |
| 163 | 163 |
| 164 /// Stop the current [TaskQueue] after the current task and any out-of-band | 164 /// Stop the current [TaskQueue] after the current task and any out-of-band |
| 165 /// tasks stop executing. If this is called before [this] has started running, | 165 /// tasks stop executing. If this is called before [this] has started running, |
| 166 /// no tasks in the [tasks] queue will be run. | 166 /// no tasks in the [tasks] queue will be run. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 /// The returned [Future] completes to the same value or error as [future]. | 248 /// The returned [Future] completes to the same value or error as [future]. |
| 249 /// | 249 /// |
| 250 /// [description] provides an optional description of the future, which is | 250 /// [description] provides an optional description of the future, which is |
| 251 /// used when generating error messages. | 251 /// used when generating error messages. |
| 252 /// | 252 /// |
| 253 /// The top-level `wrapFuture` function should usually be used in preference | 253 /// The top-level `wrapFuture` function should usually be used in preference |
| 254 /// to this in test code. | 254 /// to this in test code. |
| 255 Future wrapFuture(Future future, [String description]) { | 255 Future wrapFuture(Future future, [String description]) { |
| 256 var done = wrapAsync((fn) => fn(), description); | 256 var done = wrapAsync((fn) => fn(), description); |
| 257 | 257 |
| 258 future = future.then((result) => done(() => result)).catchError((e) { | 258 future = future.then((result) => done(() => result)) |
| 259 .catchError((error, stackTrace) { |
| 259 done(() { | 260 done(() { |
| 260 throw e; | 261 throw new ScheduleError.from(this, error, stackTrace: stackTrace); |
| 261 }); | 262 }); |
| 262 // wrapAsync will catch the first throw, so we throw [e] again so it | 263 // wrapAsync will catch the first throw, so we throw [e] again so it |
| 263 // propagates through the Future chain. | 264 // propagates through the Future chain. |
| 264 throw e; | 265 throw error; |
| 265 }); | 266 }); |
| 266 | 267 |
| 267 // Don't top-level the error, since it's already been signaled to the | 268 // Don't top-level the error, since it's already been signaled to the |
| 268 // schedule. | 269 // schedule. |
| 269 future.catchError((_) => null); | 270 future.catchError((_) => null); |
| 270 | 271 |
| 271 return future; | 272 return future; |
| 272 } | 273 } |
| 273 | 274 |
| 274 /// Returns a string representation of all errors registered on this schedule. | 275 /// Returns a string representation of all errors registered on this schedule. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 300 _timeoutTimer = null; | 301 _timeoutTimer = null; |
| 301 currentQueue._signalTimeout(new ScheduleError.from(this, "The schedule " | 302 currentQueue._signalTimeout(new ScheduleError.from(this, "The schedule " |
| 302 "timed out after $_timeout of inactivity.")); | 303 "timed out after $_timeout of inactivity.")); |
| 303 }); | 304 }); |
| 304 } | 305 } |
| 305 } | 306 } |
| 306 | 307 |
| 307 /// Register an error in the schedule's error list. This ensures that there | 308 /// Register an error in the schedule's error list. This ensures that there |
| 308 /// are no duplicate errors, and that all errors are wrapped in | 309 /// are no duplicate errors, and that all errors are wrapped in |
| 309 /// [ScheduleError]. | 310 /// [ScheduleError]. |
| 310 void _addError(error) { | 311 void _addError(error, [StackTrace stackTrace]) { |
| 311 if (error is ScheduleError && errors.contains(error)) return; | 312 error = new ScheduleError.from(this, error, stackTrace: stackTrace); |
| 312 _errors.add(new ScheduleError.from(this, error)); | 313 if (errors.contains(error)) return; |
| 314 _errors.add(error); |
| 313 } | 315 } |
| 314 } | 316 } |
| 315 | 317 |
| 316 /// An enum of states for a [Schedule]. | 318 /// An enum of states for a [Schedule]. |
| 317 class ScheduleState { | 319 class ScheduleState { |
| 318 /// The schedule can have tasks added to its queue, but is not yet running | 320 /// The schedule can have tasks added to its queue, but is not yet running |
| 319 /// them. | 321 /// them. |
| 320 static const SET_UP = const ScheduleState._("SET_UP"); | 322 static const SET_UP = const ScheduleState._("SET_UP"); |
| 321 | 323 |
| 322 /// The schedule is actively running tasks. This includes running tasks in | 324 /// The schedule is actively running tasks. This includes running tasks in |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 Future schedule(fn(), [String description]) { | 419 Future schedule(fn(), [String description]) { |
| 418 if (isRunning) { | 420 if (isRunning) { |
| 419 var task = _schedule.currentTask; | 421 var task = _schedule.currentTask; |
| 420 var wrappedFn = () => _schedule.wrapFuture( | 422 var wrappedFn = () => _schedule.wrapFuture( |
| 421 new Future.value().then((_) => fn())); | 423 new Future.value().then((_) => fn())); |
| 422 if (task == null) return wrappedFn(); | 424 if (task == null) return wrappedFn(); |
| 423 return task.runChild(wrappedFn, description); | 425 return task.runChild(wrappedFn, description); |
| 424 } | 426 } |
| 425 | 427 |
| 426 var task = new Task(() { | 428 var task = new Task(() { |
| 427 return new Future.sync(fn).catchError((e) { | 429 return new Future.sync(fn).catchError((e, stackTrace) { |
| 428 throw new ScheduleError.from(_schedule, e); | 430 throw new ScheduleError.from(_schedule, e, stackTrace: stackTrace); |
| 429 }); | 431 }); |
| 430 }, description, this); | 432 }, description, this); |
| 431 _contents.add(task); | 433 _contents.add(task); |
| 432 return task.result; | 434 return task.result; |
| 433 } | 435 } |
| 434 | 436 |
| 435 /// Runs all the tasks in this queue in order. | 437 /// Runs all the tasks in this queue in order. |
| 436 Future _run() { | 438 Future _run() { |
| 437 _schedule._currentQueue = this; | 439 _schedule._currentQueue = this; |
| 438 _schedule.heartbeat(); | 440 _schedule.heartbeat(); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 | 541 |
| 540 /// Notifies the queue that it has timed out and it needs to terminate | 542 /// Notifies the queue that it has timed out and it needs to terminate |
| 541 /// immediately with a timeout error. | 543 /// immediately with a timeout error. |
| 542 void _signalTimeout(ScheduleError error) { | 544 void _signalTimeout(ScheduleError error) { |
| 543 _pendingCallbacks.clear(); | 545 _pendingCallbacks.clear(); |
| 544 if (!isRunningTasks) { | 546 if (!isRunningTasks) { |
| 545 _noPendingCallbacksCompleter.completeError(error); | 547 _noPendingCallbacksCompleter.completeError(error); |
| 546 } else if (_taskFuture != null) { | 548 } else if (_taskFuture != null) { |
| 547 // Catch errors coming off the old task future, in case it completes after | 549 // Catch errors coming off the old task future, in case it completes after |
| 548 // timing out. | 550 // timing out. |
| 549 _taskFuture.substitute(new Future.error(error)).catchError((e) { | 551 _taskFuture.substitute(new Future.error(error)) |
| 550 _schedule._signalPostTimeoutError(e); | 552 .catchError((e, stackTrace) { |
| 553 _schedule._signalPostTimeoutError(e, stackTrace); |
| 551 }); | 554 }); |
| 552 } else { | 555 } else { |
| 553 // This branch probably won't be reached, but it's conceivable that the | 556 // This branch probably won't be reached, but it's conceivable that the |
| 554 // event loop might get pumped when _taskFuture is null but we haven't yet | 557 // event loop might get pumped when _taskFuture is null but we haven't yet |
| 555 // finished running all the tasks. | 558 // finished running all the tasks. |
| 556 _signalError(error); | 559 _signalError(error); |
| 557 } | 560 } |
| 558 } | 561 } |
| 559 | 562 |
| 560 String toString() => name; | 563 String toString() => name; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 /// The string description of the callback. | 609 /// The string description of the callback. |
| 607 String get description { | 610 String get description { |
| 608 if (_description == null) _description = _thunk(); | 611 if (_description == null) _description = _thunk(); |
| 609 return _description; | 612 return _description; |
| 610 } | 613 } |
| 611 | 614 |
| 612 String toString() => description; | 615 String toString() => description; |
| 613 | 616 |
| 614 PendingCallback._(this._thunk); | 617 PendingCallback._(this._thunk); |
| 615 } | 618 } |
| OLD | NEW |