def addSock(self, socket, on_connected, on_read, on_closed, on_failed, on_except): """Adds a socket. Called by a foreign thread""" handlers = 0 if on_connected != None: handlers += 1 if on_read != None: handlers += 1 if on_closed != None: handlers += 1 if on_failed != None: handlers += 1 if on_except != None: handlers += 1 with self.sock_meta_lock: if socket.fileno() in self.sockhandlers: print("ALREADY CONNECTED!!!!") return self.socks.append(socket) self.sockhandlers[socket._fileno] = (on_connected, on_read, on_closed, on_failed, on_except) self.sock_tcbs[socket._fileno] = S.loc.tcb self.handlers[socket._fileno] = handlers self.tid_to_sock[S.loc.tcb.tid].append(socket) if not socket.is_client and not socket.issued_on_connected: socket.issued_on_connected = True if on_connected != None: S.schedule(S.loc.tcb, on_connected, socket) S.loc.tcb.handlers += handlers
def deliver_reply_to(self, remote_tid: int, target_tid: int, obj: object, msg: SynchronousMessage): with self.metalock: try: tid_waiting_for_reply, callback = self.messages[msg.uuid] if tid_waiting_for_reply != target_tid: raise KeyError except KeyError: return # invalid! with S.syslock: try: tcb = S.tcbs[target_tid] except KeyError: return del self.messages[msg.uuid] self.uuids_by_tid[target_tid].remove(msg.uuid) if len(self.uuids_by_tid[target_tid]) == 0: del self.uuids_by_tid[target_tid] self.rev_uuids_by_tid[remote_tid].remove(msg.uuid) if len(self.rev_uuids_by_tid[remote_tid]) == 0: del self.rev_uuids_by_tid[remote_tid] tcb.handlers -= 1 S.schedule(tcb, callback, obj)
def run(self): while not self.terminated: time.sleep(1) with self.metalock: try: now = time.time() while self.events[0].run_at < now: handler = heapq.heappop(self.events) if handler.cancelled: handler.tcb.handlers -= 1 continue if handler.cyclic: S.schedule(handler.tcb, handler.callback) handler.run_at = now + handler.interval heapq.heappush(self.events, handler) else: S.schedule(handler.tcb, handler.callback) handler.tcb.handlers -= 1 # TODO: race condition? except IndexError: pass while self.pending_terminations.qsize() > 0: term = self.pending_terminations.get() with self.metalock: events = [] for handler in self.events: if handler.tcb != term: events.append(handler) heapq.heapify(events) self.events = events
def send_sync_to(self, from_tcb: TaskletControlBlock, target_tid: int, obj: object, handler: callable): """ Called from tasklet. Send a sync message from local tasklet to target tasklet """ if not S.isLocal(target_tid): raise NotImplementedError("No IPC for now, sorry!") smsg = SynchronousMessage(obj, from_tcb.tid, target_tid, self.uuidgen.next()) with S.syslock: if target_tid not in S.tcbs: S.schedule(from_tcb, handler, Tasklet.DoesNotExist) else: S.schedule(S.tcbs[target_tid], S.tcb_inst[target_tid].on_message, from_tcb.tid, smsg) with self.metalock: self.messages[smsg.uuid] = (from_tcb.tid, handler) self.rev_uuids_by_tid[target_tid].append(smsg.uuid) self.uuids_by_tid[from_tcb.tid].append(smsg.uuid) from_tcb.handlers += 1
def reply(self, obj: object): S.getSMP(self.sender).deliver_reply_to(self.target, self.sender, obj, self) # RIGHT NOW THIS DOES NOT REQUIRE ANY PATCHING #import yos.ipc #yos.ipc.SynchronousMessage = SynchronousMessageHandler
def get(key: str, result1: callable, catname: str = ''): with CatalogHandler.catalog_lock: try: val = CatalogHandler.catalog_root[catname][key] except KeyError: S.schedule(S.loc.tcb, result1, Catalog.NotFoundError) else: S.schedule(S.loc.tcb, result1, val)
def get(key: str, result1: callable, catname: str=''): with CatalogHandler.catalog_lock: try: val = CatalogHandler.catalog_root[catname][key] except KeyError: S.schedule(S.loc.tcb, result1, Catalog.NotFoundError) else: S.schedule(S.loc.tcb, result1, val)
def gather(keys, result1: callable, catname: str = ''): result = {} with CatalogHandler.catalog_lock: for key in keys: try: result[key] = CatalogHandler.catalog_root[catname][key] except KeyError: result[key] = Catalog.NotFoundError S.schedule(S.loc.tcb, result1, result)
def gather(keys, result1: callable, catname: str=''): result = {} with CatalogHandler.catalog_lock: for key in keys: try: result[key] = CatalogHandler.catalog_root[catname][key] except KeyError: result[key] = Catalog.NotFoundError S.schedule(S.loc.tcb, result1, result)
def open(tid: int, result1: callable): if not S.isLocal(tid): raise NotImplementedError("Sorry, no IPC yet") current_tcb = S.loc.tcb try: tcb = S.tcbs[tid] if not tcb.is_alive: raise KeyError except KeyError: S.schedule(current_tcb, result1, Tasklet.DoesNotExist) else: S.schedule(current_tcb, result1, Tasklet(tcb.tid, tcb.user, tcb.group, tcb.name))
def run(self): while not self.terminated: try: tcb, callable_, args, kwargs = self.events_to_process.get(True, 10) except queue.Empty: continue if tcb.is_alive: S.loc.tcb = tcb callable_(*args, **kwargs) tcb.pending -= 1 if tcb.shouldBeCollected(): tcb.is_alive = False S.onTaskletTerminated(tcb)
def run(self): while not self.terminated: try: tcb, callable_, args, kwargs = self.events_to_process.get( True, 10) except queue.Empty: continue if tcb.is_alive: S.loc.tcb = tcb callable_(*args, **kwargs) tcb.pending -= 1 if tcb.shouldBeCollected(): tcb.is_alive = False S.onTaskletTerminated(tcb)
def start(taskletCls, newname='Tasklet', newgroup=None, newuser=None, result1=None, *args, **kwargs): # Temporarily disable TCB, so that calling tasklet's context # is not used for misled API calls # essentially bug-prevention prev_tcb = S.loc.tcb S.loc.tcb = None task = taskletCls(*args, **kwargs) S.loc.tcb = prev_tcb current_tcb = prev_tcb if (newuser != None) and (current_tcb.user != 'SYSTEMYA'): raise Tasklet.AccessDenied('Cannot set user, not SYSTEMYA') newuser = newuser or current_tcb.user if (newgroup != None) and (current_tcb.group != 'admin'): raise Tasklet.AccessDenied('Cannot set group, not admin') newgroup = newgroup or current_tcb.group tid = S.getNextTID() tcb = TaskletControlBlock(tid, newuser, newgroup, newname) if isinstance(task, GCTasklet): tcb.is_gc_on = True S.registerNewTasklet(tcb, task) S.schedule(tcb, task.on_startup) if result1 != None: S.schedule(current_tcb, result1, Tasklet(tid, newuser, newgroup, newname))
def socket_closed(self, sock): """yNEP determined that socket is closed, purge it and tell yEEP""" fn = sock._fileno hdlr = self.sockhandlers[fn][2] if hdlr != None: if self.sock_tcbs[fn].is_alive: S.schedule(self.sock_tcbs[fn], hdlr, sock) with self.sock_meta_lock: tcb = self.sock_tcbs[fn] del self.sock_tcbs[fn] del self.sockhandlers[fn] self.socks.remove(sock) tcb.handlers -= self.handlers[fn] del self.handlers[fn] self.tid_to_sock[tcb.tid].remove(sock) if len(self.tid_to_sock[tcb.tid]) == 0: del self.tid_to_sock[tcb.tid]
def schedule(run_in, callback): self = TimerHandler.__new__(TimerHandler) self.__tep = S.getTEP(S.loc.tcb.tid) # following accessible to TEP self.tcb = S.loc.tcb self.teid = self.__tep.teidgen.next() self.callback = callback self.run_at = time.time() + run_in self.cancelled = False self.cyclic = False self.__tep.register(self) return self
def repeat(interval, callback): self = TimerHandler.__new__(TimerHandler) self.__tep = S.getTEP(S.loc.tcb.tid) # following accessible to TEP self.tcb = S.loc.tcb self.teid = self.__tep.teidgen.next() self.callback = callback self.run_at = time.time() + interval self.interval = interval self.cancelled = False self.cyclic = True self.__tep.register(self) return self
def terminate(self, result1=None): if self.user == 'SYSTEMYA': if result1 != None: S.schedule(S.loc.tcb, result1, Tasklet.AccessDenied) try: tcb = S.tcbs[self.tid] if not tcb.is_alive: raise KeyError except KeyError: if result1 != None: S.schedule(S.loc.tcb, result1, Tasklet.DoesNotExist) else: # OK, we got the tasklet, kill'em if result1 != None: if S.loc.tcb != tcb: S.schedule(S.loc.tcb, result1, True) S.onTaskletTerminated(tcb)
def send_to(tid, obj: object, result1: callable=None): if not S.isLocal(tid): raise NotImplementedError("Sorry, no IPC yet") current_tcb = S.loc.tcb try: tcb = S.tcbs[tid] if not tcb.is_alive: raise KeyError tcb_inst = S.tcb_inst[tid] except KeyError: if result1 != None: S.schedule(current_tcb, result1, Tasklet.DoesNotExist) else: if result1 != None: S.schedule(current_tcb, result1, Tasklet(tcb.tid, tcb.user, tcb.group, tcb.name)) S.schedule(tcb, tcb_inst.on_message, current_tcb.tid, obj)
def send_to(tid, obj: object, result1: callable = None): if not S.isLocal(tid): raise NotImplementedError("Sorry, no IPC yet") current_tcb = S.loc.tcb try: tcb = S.tcbs[tid] if not tcb.is_alive: raise KeyError tcb_inst = S.tcb_inst[tid] except KeyError: if result1 != None: S.schedule(current_tcb, result1, Tasklet.DoesNotExist) else: if result1 != None: S.schedule(current_tcb, result1, Tasklet(tcb.tid, tcb.user, tcb.group, tcb.name)) S.schedule(tcb, tcb_inst.on_message, current_tcb.tid, obj)
def send(self, obj: object, result1: int=None): current_tcb = S.loc.tcb try: tcb = S.tcbs[self.tid] if not tcb.is_alive: raise KeyError tcb_inst = S.tcb_inst[self.tid] except KeyError: if result1 != None: S.schedule(current_tcb, result1, Tasklet.DoesNotExist) else: S.schedule(tcb, tcb_inst.on_message, current_tcb.tid, obj) if result1 != None: S.schedule(current_tcb, result1, True)
def send(self, obj: object, result1: int = None): current_tcb = S.loc.tcb try: tcb = S.tcbs[self.tid] if not tcb.is_alive: raise KeyError tcb_inst = S.tcb_inst[self.tid] except KeyError: if result1 != None: S.schedule(current_tcb, result1, Tasklet.DoesNotExist) else: S.schedule(tcb, tcb_inst.on_message, current_tcb.tid, obj) if result1 != None: S.schedule(current_tcb, result1, True)
def send_sync_to(tid: int, obj: object, result1: callable): if not S.isLocal(tid): raise NotImplementedError("Sorry, no IPC yet") S.getSMP(S.loc.tcb.tid).send_sync_to(S.loc.tcb, tid, obj, result1)
def send_sync(self, obj: object, result1: callable): S.getSMP(S.loc.tcb.tid).send_sync_to(S.loc.tcb, self.tid, obj, result1)
def iter(self): # Prepare socket listing with self.sock_meta_lock: # terminate pending while self.waiting_terminations.qsize() > 0: tcb = self.waiting_terminations.get() for sock in list(self.tid_to_sock[tcb.tid]): # we need a copy of the list self.socket_closed(sock) try: sock.close() except OSError: pass for sock in self.socks: if sock.is_failed: self.socket_failed(sock) return readables = self.socks writables = [sock for sock in self.socks if len(sock.writebuf) > 0 or not sock.is_connected] exceptables = self.socks if len(readables) == len(writables) == len(exceptables) == 0: time.sleep(0.01) return try: rx, wx, ex = select(readables, writables, exceptables, 5) except OSError as e: # Go thru every socket, check if it's failed for sock in self.socks: try: select((sock, ), (), (), 0) except OSError: self.socket_failed(sock) return rx, wx, ex = (), (), () # Process readables for r in rx: fn = r._fileno data = r.handleRead() if r.is_closed: self.socket_closed(r) elif r.is_failed: self.socket_failed(r) else: h = self.sockhandlers[fn][1] if h != None: S.schedule(self.sock_tcbs[fn], h, r, data) for w in wx: if not w.is_connected: w.is_connected = True fn = w._fileno h = self.sockhandlers[fn][0] if h != None: S.schedule(self.sock_tcbs[fn], h, w) if len(w.writebuf) > 0: try: sl = w.socket.send(w.writebuf) # Problem! Python may still be holding a writelock # following line replaced del w.writebuf[:sl] w.writebuf = w.writebuf[sl:] except OSError: w.is_failed = True if len(w.writebuf) == 0 and w.close_on_all_write: w.socket.close() self.socket_closed(w) for e in ex: fn = e._fileno h = self.sockhandlers[fn][4] if h != None: S.schedule(self.sock_tcbs[fn], h, e)
kwargs = {} if len(elem) == 5: user, group, name, cls, args = elem kwargs = {} if len(elem) == 6: user, group, name, cls, args, kwargs = elem if isinstance(cls, str): # attempt an import try: mod = importlib.import_module('.'.join( cls.split('.')[:-1])) cls = getattr(mod, cls.split('.')[-1]) except (ImportError, AttributeError): print("INIT: Failed to import", cls) continue Tasklet.start(cls, name, group, user, None, *args, **kwargs) print("INIT:", len(self.initlist), "tasklets spawned, exiting") if __name__ == '__main__': S.startup() S.tidIssuer.adjustID(0) # 0th Page on 0th Frame # manual bootstrap here init = InitTasklet(initrd) tcb = TaskletControlBlock(0, 'SYSTEMYA', 'admin', 'init') S.registerNewTasklet(tcb, init) S.schedule(tcb, init.on_startup)
print ("INIT: Init v1.0 (part of System y) started") for elem in self.initlist: if len(elem) == 4: user, group, name, cls = elem; args = (); kwargs = {} if len(elem) == 5: user, group, name, cls, args = elem; kwargs = {} if len(elem) == 6: user, group, name, cls, args, kwargs = elem if isinstance(cls, str): # attempt an import try: mod = importlib.import_module('.'.join(cls.split('.')[:-1])) cls = getattr(mod, cls.split('.')[-1]) except (ImportError, AttributeError): print("INIT: Failed to import", cls) continue Tasklet.start(cls, name, group, user, None, *args, **kwargs) print("INIT:", len(self.initlist), "tasklets spawned, exiting") if __name__ == '__main__': S.startup() S.tidIssuer.adjustID(0) # 0th Page on 0th Frame # manual bootstrap here init = InitTasklet(initrd) tcb = TaskletControlBlock(0, 'SYSTEMYA', 'admin', 'init') S.registerNewTasklet(tcb, init) S.schedule(tcb, init.on_startup)
def register(self, on_readable, on_exception, on_connected, on_closed, on_failure): S.getNEP(S.loc.tcb).addSock(self, on_connected, on_readable, on_closed, on_failure, on_exception)
def iter(self): # Prepare socket listing with self.sock_meta_lock: # terminate pending while self.waiting_terminations.qsize() > 0: tcb = self.waiting_terminations.get() for sock in list(self.tid_to_sock[ tcb.tid]): # we need a copy of the list self.socket_closed(sock) try: sock.close() except OSError: pass for sock in self.socks: if sock.is_failed: self.socket_failed(sock) return readables = self.socks writables = [ sock for sock in self.socks if len(sock.writebuf) > 0 or not sock.is_connected ] exceptables = self.socks if len(readables) == len(writables) == len(exceptables) == 0: time.sleep(0.01) return try: rx, wx, ex = select(readables, writables, exceptables, 5) except OSError as e: # Go thru every socket, check if it's failed for sock in self.socks: try: select((sock, ), (), (), 0) except OSError: self.socket_failed(sock) return rx, wx, ex = (), (), () # Process readables for r in rx: fn = r._fileno data = r.handleRead() if r.is_closed: self.socket_closed(r) elif r.is_failed: self.socket_failed(r) else: h = self.sockhandlers[fn][1] if h != None: S.schedule(self.sock_tcbs[fn], h, r, data) for w in wx: if not w.is_connected: w.is_connected = True fn = w._fileno h = self.sockhandlers[fn][0] if h != None: S.schedule(self.sock_tcbs[fn], h, w) if len(w.writebuf) > 0: try: sl = w.socket.send(w.writebuf) # Problem! Python may still be holding a writelock # following line replaced del w.writebuf[:sl] w.writebuf = w.writebuf[sl:] except OSError: w.is_failed = True if len(w.writebuf) == 0 and w.close_on_all_write: w.socket.close() self.socket_closed(w) for e in ex: fn = e._fileno h = self.sockhandlers[fn][4] if h != None: S.schedule(self.sock_tcbs[fn], h, e)