aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/reactor.py
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2016-05-25 11:37:40 -0400
committerKevin O'Connor <kevin@koconnor.net>2016-05-25 11:37:40 -0400
commitf582a36e4df16d5709943f7df17a900c8bcc12ab (patch)
tree628d927c4f3e19e54618f7f47c7a44af66bf0c2f /klippy/reactor.py
parent37a91e9c10648208de002c75df304e23ca89e256 (diff)
downloadkutter-f582a36e4df16d5709943f7df17a900c8bcc12ab.tar.gz
kutter-f582a36e4df16d5709943f7df17a900c8bcc12ab.tar.xz
kutter-f582a36e4df16d5709943f7df17a900c8bcc12ab.zip
Initial commit of source code.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'klippy/reactor.py')
-rw-r--r--klippy/reactor.py142
1 files changed, 142 insertions, 0 deletions
diff --git a/klippy/reactor.py b/klippy/reactor.py
new file mode 100644
index 00000000..e07c6440
--- /dev/null
+++ b/klippy/reactor.py
@@ -0,0 +1,142 @@
+# File descriptor and timer event helper
+#
+# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import select, time, math
+
+class ReactorTimer:
+ def __init__(self, callback, waketime):
+ self.callback = callback
+ self.waketime = waketime
+
+class ReactorFileHandler:
+ def __init__(self, fd, callback):
+ self.fd = fd
+ self.callback = callback
+ def fileno(self):
+ return self.fd
+
+class SelectReactor:
+ NOW = 0.
+ NEVER = 9999999999999999.
+ def __init__(self):
+ self._fds = []
+ self._timers = []
+ self._next_timer = self.NEVER
+ self._process = True
+ # Timers
+ def _note_time(self, t):
+ nexttime = t.waketime
+ if nexttime < self._next_timer:
+ self._next_timer = nexttime
+ def update_timer(self, t, nexttime):
+ t.waketime = nexttime
+ self._note_time(t)
+ def register_timer(self, callback, waketime = NEVER):
+ handler = ReactorTimer(callback, waketime)
+ timers = list(self._timers)
+ timers.append(handler)
+ self._timers = timers
+ self._note_time(handler)
+ return handler
+ def unregister_timer(self, handler):
+ timers = list(self._timers)
+ timers.pop(timers.index(handler))
+ self._timers = timers
+ def _check_timers(self, eventtime):
+ if eventtime < self._next_timer:
+ return min(1., max(.001, self._next_timer - eventtime))
+ self._next_timer = self.NEVER
+ for t in self._timers:
+ if eventtime >= t.waketime:
+ t.waketime = t.callback(eventtime)
+ self._note_time(t)
+ if eventtime >= self._next_timer:
+ return 0.
+ return min(1., max(.001, self._next_timer - time.time()))
+ # File descriptors
+ def register_fd(self, fd, callback):
+ handler = ReactorFileHandler(fd, callback)
+ self._fds.append(handler)
+ return handler
+ def unregister_fd(self, handler):
+ self._fds.pop(self._fds.index(handler))
+ # Main loop
+ def run(self):
+ self._process = True
+ eventtime = time.time()
+ while self._process:
+ timeout = self._check_timers(eventtime)
+ res = select.select(self._fds, [], [], timeout)
+ eventtime = time.time()
+ for fd in res[0]:
+ fd.callback(eventtime)
+ def end(self):
+ self._process = False
+
+class PollReactor(SelectReactor):
+ def __init__(self):
+ SelectReactor.__init__(self)
+ self._poll = select.poll()
+ self._fds = {}
+ # File descriptors
+ def register_fd(self, fd, callback):
+ handler = ReactorFileHandler(fd, callback)
+ fds = self._fds.copy()
+ fds[fd] = callback
+ self._fds = fds
+ self._poll.register(handler, select.POLLIN | select.POLLHUP)
+ return handler
+ def unregister_fd(self, handler):
+ self._poll.unregister(handler)
+ fds = self._fds.copy()
+ del fds[handler.fd]
+ self._fds = fds
+ # Main loop
+ def run(self):
+ self._process = True
+ eventtime = time.time()
+ while self._process:
+ timeout = int(math.ceil(self._check_timers(eventtime) * 1000.))
+ res = self._poll.poll(timeout)
+ eventtime = time.time()
+ for fd, event in res:
+ self._fds[fd](eventtime)
+
+class EPollReactor(SelectReactor):
+ def __init__(self):
+ SelectReactor.__init__(self)
+ self._epoll = select.epoll()
+ self._fds = {}
+ # File descriptors
+ def register_fd(self, fd, callback):
+ handler = ReactorFileHandler(fd, callback)
+ fds = self._fds.copy()
+ fds[fd] = callback
+ self._fds = fds
+ self._epoll.register(fd, select.EPOLLIN | select.EPOLLHUP)
+ return handler
+ def unregister_fd(self, handler):
+ self._epoll.unregister(handler.fd)
+ fds = self._fds.copy()
+ del fds[handler.fd]
+ self._fds = fds
+ # Main loop
+ def run(self):
+ self._process = True
+ eventtime = time.time()
+ while self._process:
+ timeout = self._check_timers(eventtime)
+ res = self._epoll.poll(timeout)
+ eventtime = time.time()
+ for fd, event in res:
+ self._fds[fd](eventtime)
+
+# Use the poll based reactor if it is available
+try:
+ select.poll
+ Reactor = PollReactor
+except:
+ Reactor = SelectReactor