from select import select from sys import stdin, stdout class Kernel: def __init__(self): self.select_read = [] self.select_write = [] self.sockets = {} self.events = [] def open(self, fd): try: if self.sockets[fd] != None: raise 'socket already open' except: pass socket = Closure(self, fd) self.sockets[fd] = socket return socket def close(self, fd): if self.sockets[fd] == None: raise 'socket already closed' self.sockets[fd] = None if fd in self.select_read: self.select_read.remove(fd) if fd in self.select_write: self.select_write.remove(fd) def trigger(self, fd): if self.sockets[fd].canread(): self.select_write.append(fd) if self.sockets[fd].canwrite(): self.select_read.append(fd) def schedule(self, event): self.events.append(event) def step(self): if self.events: event = self.events[0] del self.events[0] event.trigger() if self.select_read or self.select_write: if self.events: timeout = 0 else: timeout = None # TODO extend for alarms canread, canwrite, haveerrors = select(self.select_read, self.select_write, [], timeout) for fd in canwrite: self.select_write.remove(fd) self.sockets[fd].read() for fd in canread: self.select_read.remove(fd) self.sockets[fd].write(1) def run(self): while self.events or self.select_read or self.select_write: self.step() kernel = Kernel() class Port: def __init__(self, module): self.peer = None self.module = module self.obj = None def canread(self): return self.peer.obj != None def canwrite(self): return self.obj == None def read(self): if self.peer.obj == None: raise 'no object present' obj = self.peer.obj self.peer.obj = None self.peer.schedule() return obj def write(self, obj): if self.obj != None: raise 'object already present' self.obj = obj self.peer.schedule() def schedule(self): kernel.schedule(self) def trigger(self): self.module.trigger() def connect(self, peer): if self.peer != None or peer.peer != None: raise 'already connected' self.peer = peer; peer.peer = self; self.schedule() self.peer.schedule() class Closure(Port): def __init__(self, module, closure): self.closure = closure Port.__init__(self, module) # better way? def trigger(self): self.module.trigger(self.closure) class Add: def __init__(self): self.a = Port(self) self.b = Port(self) self.c = Port(self) def trigger(self): if self.a.canread() and self.b.canread() and self.c.canwrite(): self.c.write(self.a.read() + self.b.read()) class Times: def __init__(self): self.a = Port(self) self.b = Port(self) self.c = Port(self) def trigger(self): if self.a.canread() and self.b.canread() and self.c.canwrite(): self.c.write(self.a.read() * self.b.read()) class Reader: def __init__(self, file=stdin): self.file = file self.ready = Port(self) self.ready.connect(kernel.open(file.fileno())) self.output = Port(self) def trigger(self): if self.output.canwrite() and self.ready.canread(): self.ready.read() # dodgy line = self.file.readline() if line != '': self.output.write(line) else: self.ready.peer.obj=1 # hack class Writer: def __init__(self, file=stdout): self.file = file self.ready = Port(self) self.ready.connect(kernel.open(file.fileno())) self.input = Port(self) def close(self): kernel.close(fd) def trigger(self): if self.input.canread() and self.ready.canwrite(): self.ready.write(1) # dodgy - should be non-blocking, buffered self.file.write(self.input.read()) class Func: def __init__(self): self.input = Port(self) self.output = Port(self) def trigger(self): if self.input.canread() and self.output.canwrite(): self.output.write(self.func(self.input.read())) # override me! def func(self, input): return input class Int(Func): def func(self, input): return int(input) class Str(Func): def func(self, input): return str(input)+"\n" class Yes: def __init__(self, value): self.output = Port(self) self.value = value def trigger(self): if self.output.canwrite(): self.output.write(self.value) class Main: def __init__(self): yes = Yes(2) printer = Writer() add = Add() reader = Reader() atoi = Int() itoa = Str() reader.output.connect(atoi.input) atoi.output.connect(add.a) yes.output.connect(add.b) add.c.connect(itoa.input) itoa.output.connect(printer.input) Main() kernel.run()