3
3
4
4
from time import ticks_ms as ticks , ticks_diff , ticks_add
5
5
import sys , select
6
+ from select import POLLIN , POLLOUT
6
7
7
8
# Import TaskQueue and Task, preferring built-in C code over Python code
8
9
try :
@@ -54,7 +55,8 @@ def __next__(self):
54
55
# Use a SingletonGenerator to do it without allocating on the heap
55
56
def sleep_ms (t , sgen = SingletonGenerator ()):
56
57
assert sgen .state is None
57
- sgen .state = ticks_add (ticks (), max (0 , t ))
58
+ now = ticks ()
59
+ sgen .state = ticks_add (now , t ) if t > 0 else now
58
60
return sgen
59
61
60
62
@@ -66,7 +68,6 @@ def sleep(t):
66
68
################################################################################
67
69
# Queue and poller for stream IO
68
70
69
-
70
71
class IOQueue :
71
72
def __init__ (self ):
72
73
self .poller = select .poll ()
@@ -77,13 +78,13 @@ def _enqueue(self, s, idx):
77
78
entry = [None , None , s ]
78
79
entry [idx ] = cur_task
79
80
self .map [id (s )] = entry
80
- self .poller .register (s , select . POLLIN if idx == 0 else select . POLLOUT )
81
+ self .poller .register (s , POLLIN if idx == 0 else POLLOUT )
81
82
else :
82
83
sm = self .map [id (s )]
83
84
assert sm [idx ] is None
84
85
assert sm [1 - idx ] is not None
85
86
sm [idx ] = cur_task
86
- self .poller .modify (s , select . POLLIN | select . POLLOUT )
87
+ self .poller .modify (s , POLLIN | POLLOUT )
87
88
# Link task to this IOQueue so it can be removed if needed
88
89
cur_task .data = self
89
90
@@ -114,20 +115,20 @@ def wait_io_event(self, dt):
114
115
for s , ev in self .poller .ipoll (dt ):
115
116
sm = self .map [id (s )]
116
117
# print('poll', s, sm, ev)
117
- if ev & ~ select . POLLOUT and sm [0 ] is not None :
118
+ if ev & ~ POLLOUT and sm [0 ] is not None :
118
119
# POLLIN or error
119
120
_task_queue .push (sm [0 ])
120
121
sm [0 ] = None
121
- if ev & ~ select . POLLIN and sm [1 ] is not None :
122
+ if ev & ~ POLLIN and sm [1 ] is not None :
122
123
# POLLOUT or error
123
124
_task_queue .push (sm [1 ])
124
125
sm [1 ] = None
125
126
if sm [0 ] is None and sm [1 ] is None :
126
127
self ._dequeue (s )
127
128
elif sm [0 ] is None :
128
- self .poller .modify (s , select . POLLOUT )
129
+ self .poller .modify (s , POLLOUT )
129
130
else :
130
- self .poller .modify (s , select . POLLIN )
131
+ self .poller .modify (s , POLLIN )
131
132
132
133
133
134
################################################################################
@@ -153,24 +154,36 @@ def run_until_complete(main_task=None):
153
154
global cur_task
154
155
excs_all = (CancelledError , Exception ) # To prevent heap allocation in loop
155
156
excs_stop = (CancelledError , StopIteration ) # To prevent heap allocation in loop
157
+ queue_peek = _task_queue .peek
158
+ queue_pop = _task_queue .pop
159
+ wait_io_event = _io_queue .wait_io_event
156
160
while True :
157
- # Wait until the head of _task_queue is ready to run
158
- dt = 1
159
- while dt > 0 :
160
- dt = - 1
161
- t = _task_queue .peek ()
162
- if t :
163
- # A task waiting on _task_queue; "ph_key" is time to schedule task at
164
- dt = max (0 , ticks_diff (t .ph_key , ticks ()))
165
- elif not _io_queue .map :
166
- # No tasks can be woken so finished running
167
- cur_task = None
168
- return
169
- # print('(poll {})'.format(dt), len(_io_queue.map))
170
- _io_queue .wait_io_event (dt )
161
+ try :
162
+ # Wait until the head of _task_queue is ready to run
163
+ dt = 1
164
+ while dt > 0 :
165
+ dt = - 1
166
+ t = queue_peek ()
167
+ if t :
168
+ # A task waiting on _task_queue; "ph_key" is time to schedule task at
169
+ dt = ticks_diff (t .ph_key , ticks ())
170
+ dt = dt if dt > 0 else 0
171
+ elif not _io_queue .map :
172
+ # No tasks can be woken so finished running
173
+ cur_task = None
174
+ return
175
+ # print('(poll {})'.format(dt), len(_io_queue.map))
176
+ wait_io_event (dt )
177
+ except BaseException as exc :
178
+ try :
179
+ if main_task :
180
+ main_task .coro .throw (exc )
181
+ except StopIteration :
182
+ pass
183
+ raise
171
184
172
185
# Get next task to run and continue it
173
- t = _task_queue . pop ()
186
+ t = queue_pop ()
174
187
cur_task = t
175
188
try :
176
189
# Continue running the coroutine, it's responsible for rescheduling itself
0 commit comments