1 | | | import 'dart:async'; |
2 | | |
|
3 | | | import 'package:meta/meta.dart'; |
4 | | |
|
5 | | | import '../_impl/xplat/_time_stamp.dart'; |
6 | | | import '../exceptions/task_canceled_exception.dart'; |
7 | | | import '../stats/perf_counter.dart'; |
8 | | | import '../worker/worker.dart'; |
9 | | | import 'task.dart'; |
10 | | | import 'worker_pool.dart'; |
11 | | |
|
12 | | | /// [WorkerTask] registered in the [WorkerPool]. |
13 | | | abstract base class WorkerTask<T, W extends Worker> implements Task<T> { |
14 | | 8 | WorkerTask(this._counter) : submitted = microsecTimeStamp(); |
15 | | |
|
16 | | | final int submitted; |
17 | | | int? _scheduled; |
18 | | | int? _finished; |
19 | | | int? _canceled; |
20 | | |
|
21 | | | final PerfCounter? _counter; |
22 | | |
|
23 | | 4 | @override |
24 | | 4 | bool get isCanceled => _canceled != null; |
25 | | |
|
26 | | 1 | @override |
27 | | 2 | bool get isPending => _scheduled == null && _canceled == null; |
28 | | |
|
29 | | 2 | @override |
30 | | | bool get isFinished => |
31 | | 6 | _scheduled != null && _finished != null && _canceled == null; |
32 | | |
|
33 | | 2 | @override |
34 | | | bool get isRunning => |
35 | | 4 | _scheduled != null && _finished == null && _canceled == null; |
36 | | |
|
37 | | 1 | @override |
38 | | 1 | Duration get runningTime => _scheduled == null |
39 | | | ? Duration.zero |
40 | | 0 | : Duration( |
41 | | | microseconds: |
42 | | 0 | (_canceled ?? _finished ?? microsecTimeStamp()) - _scheduled!); |
43 | | |
|
44 | | 0 | @override |
45 | | 0 | Duration get waitTime => Duration( |
46 | | | microseconds: |
47 | | 0 | (_scheduled ?? _canceled ?? microsecTimeStamp()) - submitted); |
48 | | |
|
49 | | | final _done = Completer<void>(); |
50 | | |
|
51 | | 1 | @override |
52 | | 2 | Future<void> get done => _done.future; |
53 | | |
|
54 | | | TaskCanceledException? _canceledException; |
55 | | 8 | TaskCanceledException? get canceledException => _canceledException; |
56 | | |
|
57 | | 4 | void throwIfCanceled() { |
58 | | 5 | if (_canceledException != null) throw _canceledException!; |
59 | | | } |
60 | | |
|
61 | | 2 | @override |
62 | | | void cancel([String? message]) { |
63 | | 4 | _canceled ??= microsecTimeStamp(); |
64 | | 4 | _canceledException ??= TaskCanceledException(message); |
65 | | 2 | if (_scheduled == null) { |
66 | | | // task will not be scheduled, make sure it reports as errored |
67 | | 2 | _fail(); |
68 | | | } |
69 | | | } |
70 | | |
|
71 | | 4 | void _success(bool res) { |
72 | | 8 | _finished ??= microsecTimeStamp(); |
73 | | 8 | _counter?.update(_finished! - _scheduled!, res); |
74 | | 16 | if (!_done.isCompleted) _done.complete(); |
75 | | | } |
76 | | |
|
77 | | 2 | void _fail([Object? _]) { |
78 | | 4 | _finished ??= microsecTimeStamp(); |
79 | | 2 | _counter?.update(_finished! - _scheduled!, false); |
80 | | 8 | if (!_done.isCompleted) _done.complete(); |
81 | | | } |
82 | | |
|
83 | | 4 | Future<void> run(W worker) { |
84 | | 8 | _scheduled ??= microsecTimeStamp(); |
85 | | 16 | return execute(worker).then(_success, onError: _fail); |
86 | | | } |
87 | | |
|
88 | | | Future<bool> execute(W worker); |
89 | | | } |
90 | | |
|
91 | | | @internal |
92 | | | extension WorkerTaskExt on WorkerTask { |
93 | | 0 | void fail() => _fail(); |
94 | | | } |