|
|
@ -7,47 +7,49 @@ if __debug__:
|
|
|
|
|
|
|
|
|
|
|
|
type_gen = type((lambda: (yield))())
|
|
|
|
type_gen = type((lambda: (yield))())
|
|
|
|
|
|
|
|
|
|
|
|
class EventLoop:
|
|
|
|
q = []
|
|
|
|
|
|
|
|
cnt = 0
|
|
|
|
|
|
|
|
last_sleep = 0 # For performance stats
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
def call_soon(callback, *args):
|
|
|
|
self.q = []
|
|
|
|
call_at(0, callback, *args)
|
|
|
|
self.cnt = 0
|
|
|
|
|
|
|
|
self.last_sleep = 0 # For performance stats
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def call_soon(self, callback, *args):
|
|
|
|
def call_later(delay, callback, *args):
|
|
|
|
self.call_at(0, callback, *args)
|
|
|
|
call_at(utime.ticks_us() + delay, callback, *args)
|
|
|
|
|
|
|
|
|
|
|
|
def call_later(self, delay, callback, *args):
|
|
|
|
def call_at(time, callback, *args):
|
|
|
|
self.call_at(utime.ticks_us() + delay, callback, *args)
|
|
|
|
global cnt
|
|
|
|
|
|
|
|
|
|
|
|
def call_at(self, time, callback, *args):
|
|
|
|
|
|
|
|
# Including self.cnt is a workaround per heapq docs
|
|
|
|
|
|
|
|
if __debug__:
|
|
|
|
if __debug__:
|
|
|
|
log.debug("Scheduling %s", (int(time), self.cnt, callback, args))
|
|
|
|
log.debug("Scheduling %s", (int(time), cnt, callback, args))
|
|
|
|
uheapq.heappush(self.q, (int(time), self.cnt, callback, args))
|
|
|
|
# Including self.cnt is a workaround per heapq docs
|
|
|
|
self.cnt += 1
|
|
|
|
uheapq.heappush(q, (int(time), cnt, callback, args))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cnt += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wait(delay):
|
|
|
|
|
|
|
|
global last_sleep
|
|
|
|
|
|
|
|
|
|
|
|
def wait(self, delay):
|
|
|
|
|
|
|
|
# Default wait implementation, to be overriden in subclasses
|
|
|
|
|
|
|
|
# with IO scheduling
|
|
|
|
|
|
|
|
if __debug__:
|
|
|
|
if __debug__:
|
|
|
|
log.debug("Sleeping for: %s", delay)
|
|
|
|
log.debug("Sleeping for: %s", delay)
|
|
|
|
self.last_sleep = delay
|
|
|
|
|
|
|
|
|
|
|
|
last_sleep = delay
|
|
|
|
utime.sleep_us(delay)
|
|
|
|
utime.sleep_us(delay)
|
|
|
|
|
|
|
|
|
|
|
|
def run_forever(self):
|
|
|
|
def run_forever():
|
|
|
|
|
|
|
|
global q, cnt
|
|
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
while True:
|
|
|
|
if self.q:
|
|
|
|
if q:
|
|
|
|
t, cnt, cb, args = uheapq.heappop(self.q)
|
|
|
|
t, cnt, cb, args = uheapq.heappop(q)
|
|
|
|
if __debug__:
|
|
|
|
if __debug__:
|
|
|
|
log.debug("Next coroutine to run: %s", (t, cnt, cb, args))
|
|
|
|
log.debug("Next coroutine to run: %s", (t, cnt, cb, args))
|
|
|
|
# __main__.mem_info()
|
|
|
|
|
|
|
|
tnow = utime.ticks_us()
|
|
|
|
tnow = utime.ticks_us()
|
|
|
|
delay = t - tnow
|
|
|
|
delay = t - tnow
|
|
|
|
if delay > 0:
|
|
|
|
if delay > 0:
|
|
|
|
self.wait(delay)
|
|
|
|
wait(delay)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.wait(-1)
|
|
|
|
wait(-1)
|
|
|
|
# Assuming IO completion scheduled some tasks
|
|
|
|
# Assuming IO completion scheduled some tasks
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
if callable(cb):
|
|
|
|
if callable(cb):
|
|
|
@ -86,39 +88,29 @@ class EventLoop:
|
|
|
|
# self.remove_writer(arg.fileno())
|
|
|
|
# self.remove_writer(arg.fileno())
|
|
|
|
|
|
|
|
|
|
|
|
elif isinstance(ret, type_gen):
|
|
|
|
elif isinstance(ret, type_gen):
|
|
|
|
self.call_soon(ret)
|
|
|
|
call_soon(ret)
|
|
|
|
elif ret is None:
|
|
|
|
elif ret is None:
|
|
|
|
# Just reschedule
|
|
|
|
# Just reschedule
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
assert False, "Unsupported coroutine yield value: %r (of type %r)" % (ret, type(ret))
|
|
|
|
assert False, "Unsupported yield value: %r (of type %r)" % (ret, type(ret))
|
|
|
|
except StopIteration as e:
|
|
|
|
except StopIteration as e:
|
|
|
|
if __debug__:
|
|
|
|
if __debug__:
|
|
|
|
log.debug("Coroutine finished: %s", cb)
|
|
|
|
log.debug("Coroutine finished: %s", cb)
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
self.call_later(delay, cb, *args)
|
|
|
|
call_later(delay, cb, *args)
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
# def run_until_complete(self, coro):
|
|
|
|
def run_until_complete(self, coro):
|
|
|
|
# def _run_and_stop():
|
|
|
|
def _run_and_stop():
|
|
|
|
# yield from coro
|
|
|
|
yield from coro
|
|
|
|
# yield StopLoop(0)
|
|
|
|
yield StopLoop(0)
|
|
|
|
# self.call_soon(_run_and_stop())
|
|
|
|
self.call_soon(_run_and_stop())
|
|
|
|
# self.run_forever()
|
|
|
|
self.run_forever()
|
|
|
|
# class SysCall:
|
|
|
|
'''
|
|
|
|
# def __init__(self, *args):
|
|
|
|
#def close(self):
|
|
|
|
# self.args = args
|
|
|
|
# pass
|
|
|
|
# def handle(self):
|
|
|
|
|
|
|
|
# raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
class SysCall:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args):
|
|
|
|
|
|
|
|
self.args = args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle(self):
|
|
|
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Optimized syscall with 1 arg
|
|
|
|
# Optimized syscall with 1 arg
|
|
|
|
class SysCall1:
|
|
|
|
class SysCall1:
|
|
|
@ -137,22 +129,22 @@ class StopLoop(SysCall1):
|
|
|
|
class Sleep(SysCall1):
|
|
|
|
class Sleep(SysCall1):
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class IORead(SysCall1):
|
|
|
|
# class IORead(SysCall1):
|
|
|
|
pass
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
|
|
class IOWrite(SysCall1):
|
|
|
|
# class IOWrite(SysCall1):
|
|
|
|
pass
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
|
|
class IOReadDone(SysCall1):
|
|
|
|
# class IOReadDone(SysCall1):
|
|
|
|
pass
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
|
|
class IOWriteDone(SysCall1):
|
|
|
|
# class IOWriteDone(SysCall1):
|
|
|
|
pass
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
|
|
_event_loop = None
|
|
|
|
# _event_loop = None
|
|
|
|
_event_loop_class = EventLoop
|
|
|
|
# _event_loop_class = EventLoop
|
|
|
|
def get_event_loop():
|
|
|
|
# def get_event_loop():
|
|
|
|
global _event_loop
|
|
|
|
# global _event_loop
|
|
|
|
if _event_loop is None:
|
|
|
|
# if _event_loop is None:
|
|
|
|
_event_loop = _event_loop_class()
|
|
|
|
# _event_loop = _event_loop_class()
|
|
|
|
return _event_loop
|
|
|
|
# return _event_loop
|
|
|
|