Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(436)

Side by Side Diff: lib/async/async_patch.dart

Issue 1375373004: Use the event-handler for timers. (Closed) Base URL: git@github.com:dart-lang/fletch.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/shared/natives.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Fletch 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.md file. 3 // BSD-style license that can be found in the LICENSE.md file.
4 4
5 import 'dart:_fletch_system' as fletch; 5 import 'dart:_fletch_system' as fletch;
6 import 'dart:fletch'; 6 import 'dart:fletch';
7 import 'dart:fletch.os' as os; 7 import 'dart:fletch.os' as os;
8 import 'dart:math'; 8 import 'dart:math';
9 9
10 const patch = "patch"; 10 const patch = "patch";
11 11
12 Channel _eventQueue; 12 Channel _eventQueue;
13 _FletchTimer _timers;
14 int _numberOfEvents = 0; 13 int _numberOfEvents = 0;
15 14
16 void _handleEvents() { 15 void _handleEvents() {
17 while (_numberOfEvents > 0) { 16 while (_numberOfEvents > 0) {
18 var event = _eventQueue.receive(); 17 var event = _eventQueue.receive();
19 _numberOfEvents--; 18 _numberOfEvents--;
20 event(); 19 event();
21 } 20 }
22 _eventQueue = null; 21 _eventQueue = null;
23 } 22 }
24 23
25 Channel _ensureEventQueue() { 24 Channel _ensureEventQueue() {
26 if (_eventQueue == null) { 25 if (_eventQueue == null) {
27 _eventQueue = new Channel(); 26 _eventQueue = new Channel();
28 Fiber.fork(_handleEvents); 27 Fiber.fork(_handleEvents);
29 } 28 }
30 return _eventQueue; 29 return _eventQueue;
31 } 30 }
32 31
33 @patch class _AsyncRun { 32 @patch class _AsyncRun {
34 @patch static void _scheduleImmediate(void callback()) { 33 @patch static void _scheduleImmediate(void callback()) {
35 _numberOfEvents++; 34 _numberOfEvents++;
36 _ensureEventQueue().send(callback); 35 _ensureEventQueue().send(callback);
37 } 36 }
38 } 37 }
39 38
40 final int _maxWaitTimeInMilliseconds = 1000;
41
42 final int _baseTime = new DateTime.now().millisecondsSinceEpoch;
43
44 int get _currentTimestamp { 39 int get _currentTimestamp {
45 return new DateTime.now().millisecondsSinceEpoch - _baseTime; 40 return new DateTime.now().millisecondsSinceEpoch;
46 } 41 }
47 42
48 // TODO(ager): This is a pretty horrible implementation. We should get 43 // TODO(ajohnsen): We should create a heap-like structure in Dart, so we only
49 // this integrated with the event loop. For now this is enough to show 44 // have one active port/channel per process.
50 // that we can implement async on top of our current primitives.
51 class _FletchTimer implements Timer { 45 class _FletchTimer implements Timer {
52 final int _milliseconds; 46 final int _milliseconds;
53 var _callback; 47 var _callback;
54 int _timestamp = 0; 48 int _timestamp = 0;
55 _FletchTimer _next; 49 _FletchTimer _next;
56 bool _isActive = true; 50 bool _isActive = true;
57 bool _hasActiveWaitFiber = false; 51 Channel _channel;
52 Port _port;
58 53
59 bool get _isPeriodic => _milliseconds >= 0; 54 bool get _isPeriodic => _milliseconds >= 0;
60 55
61 _FletchTimer(this._timestamp, this._callback) 56 _FletchTimer(this._timestamp, this._callback)
62 : _milliseconds = -1 { 57 : _milliseconds = -1 {
58 _channel = new Channel();
59 _port = new Port(_channel);
63 _schedule(); 60 _schedule();
64 _forkWaitFiber();
65 } 61 }
66 62
67 _FletchTimer.periodic(this._timestamp, 63 _FletchTimer.periodic(this._timestamp,
68 void callback(Timer timer), 64 void callback(Timer timer),
69 this._milliseconds) { 65 this._milliseconds) {
70 _callback = () { callback(this); }; 66 _callback = () { callback(this); };
67 _channel = new Channel();
68 _port = new Port(_channel);
71 _schedule(); 69 _schedule();
72 _forkWaitFiber();
73 }
74
75 void _forkWaitFiber() {
76 if (_timers != this) return;
77 assert(!_hasActiveWaitFiber);
78 _hasActiveWaitFiber = true;
79 Fiber.fork(() {
80 var milliseconds = _timestamp - _currentTimestamp;
81 if (milliseconds < 0) milliseconds = 0;
82 // Cap the sleep time so that a timer that is set way in the
83 // future will not cause the system to keep running if it is
84 // cancelled.
85 if (milliseconds > _maxWaitTimeInMilliseconds) {
86 milliseconds = _maxWaitTimeInMilliseconds;
87 }
88
89 Channel channel = new Channel();
90 Port port = new Port(channel);
91 Process.spawn((int milliseconds) {
92 os.sleep(milliseconds);
93 port.send(null);
94 }, milliseconds);
95 channel.receive();
96
97 _hasActiveWaitFiber = false;
98 _fireExpiredTimers();
99 });
100 }
101
102 void _fireExpiredTimers() {
103 // Skip cancelled timers.
104 while (_timers != null && !_timers._isActive) _timers = _timers._next;
105 if (_timers != null) {
106 // If first timer is expired, fire it and reschedule if it is
107 // periodic.
108 if (_currentTimestamp >= _timers._timestamp) {
109 _AsyncRun._scheduleImmediate(_timers._callback);
110 var current = _timers;
111 _timers = _timers._next;
112 if (current._isPeriodic) current._reschedule();
113 }
114 // Spin up a timer fiber if there isn't already one for
115 // the next timer to fire.
116 if (_timers != null && !_timers._hasActiveWaitFiber) {
117 _timers._forkWaitFiber();
118 }
119 }
120 } 70 }
121 71
122 void _schedule() { 72 void _schedule() {
123 var lastWithSmallerTimestamp = null; 73 Fiber.fork(() {
124 for (_FletchTimer current = _timers; 74 int value = _channel.receive();
125 current != null; 75 if (value == 0 && _isActive) {
126 current = current._next) { 76 _callback();
127 if (current._timestamp > _timestamp) break; 77 if (_isPeriodic) {
128 lastWithSmallerTimestamp = current; 78 _reschedule();
129 } 79 } else {
130 if (lastWithSmallerTimestamp == null) { 80 _isActive = false;
131 _next = _timers; 81 }
132 _timers = this; 82 }
133 } else { 83 });
134 _next = lastWithSmallerTimestamp._next; 84 _scheduleTimeout(_timestamp, _port);
135 lastWithSmallerTimestamp._next = this;
136 }
137 } 85 }
138 86
139 void _reschedule() { 87 void _reschedule() {
140 assert(_isPeriodic); 88 assert(_isPeriodic);
141 _timestamp = _currentTimestamp + _milliseconds; 89 _timestamp += _milliseconds;
142 _schedule(); 90 _schedule();
143 } 91 }
144 92
145 void cancel() { 93 void cancel() {
94 _scheduleTimeout(-1, _port);
95 _port.send(-1);
146 _isActive = false; 96 _isActive = false;
147 } 97 }
148 98
149 bool get isActive => _isActive; 99 bool get isActive => _isActive;
100
101 @fletch.native external static void _scheduleTimeout(int timeout, Port port);
150 } 102 }
151 103
152 @patch class Timer { 104 @patch class Timer {
153 @patch static Timer _createTimer(Duration duration, void callback()) { 105 @patch static Timer _createTimer(Duration duration, void callback()) {
154 int milliseconds = max(0, duration.inMilliseconds); 106 int milliseconds = max(0, duration.inMilliseconds);
155 return new _FletchTimer(_currentTimestamp + milliseconds, callback); 107 return new _FletchTimer(_currentTimestamp + milliseconds, callback);
156 } 108 }
157 109
158 @patch static Timer _createPeriodicTimer(Duration duration, 110 @patch static Timer _createPeriodicTimer(Duration duration,
159 void callback(Timer timer)) { 111 void callback(Timer timer)) {
160 int milliseconds = max(0, duration.inMilliseconds); 112 int milliseconds = max(0, duration.inMilliseconds);
161 return new _FletchTimer.periodic(_currentTimestamp + milliseconds, 113 return new _FletchTimer.periodic(_currentTimestamp + milliseconds,
162 callback, 114 callback,
163 milliseconds); 115 milliseconds);
164 } 116 }
165 } 117 }
OLDNEW
« no previous file with comments | « no previous file | src/shared/natives.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698