#!/usr/bin/env python3importsysimportrandomfrompathlibimportPathclassOS:''' A minimal executable operating system model. Processes are state machines (Python generators) that can be paused or continued with local states being saved. '''''' We implement four system calls: - read: read a random bit value. - write: write a string to the buffer. - spawn: create a new state machine (process). '''SYSCALLS=['read','write','spawn']classProcess:''' A "freezed" state machine. The state (local variables, program counters, etc.) are stored in the generator object. '''def__init__(self,func,*args):# func should be a generator function. Calling# func(*args) returns a generator object.self._func=func(*args)# This return value is set by the OS's main loop.self.retval=Nonedefstep(self):''' Resume the process with OS-written return value, until the next system call is issued. '''syscall,args,*_=self._func.send(self.retval)self.retval=Nonereturnsyscall,argsdef__init__(self,src):# This is a hack: we directly execute the source# in the current Python runtime--and main is thus# available for calling.exec(src,globals())self.procs=[OS.Process(main)]self.buffer=''defrun(self):# Real operating systems waste all CPU cycles# (efficiently, by putting the CPU into sleep) when# there is no running process at the moment. Our model# terminates if there is nothing to run.whileself.procs:# There is also a pointer to the "current" process# in today's operating systems.current=random.choice(self.procs)try:# Operating systems handle interrupt and system# calls, and "assign" CPU to a process.matchcurrent.step():case'read',_:current.retval=random.choice([0,1])case'write',s:self.buffer+=scase'spawn',(fn,*args):self.procs+=[OS.Process(fn,*args)]case_:assert0exceptStopIteration:# The generator object terminates.self.procs.remove(current)returnself.bufferif__name__=='__main__':iflen(sys.argv)<2:print(f'Usage: {sys.argv[0]} file')exit(1)src=Path(sys.argv[1]).read_text()# Hack: patch sys_read(...) -> yield "sys_read", (...)forsyscallinOS.SYSCALLS:src=src.replace(f'sys_{syscall}',f'yield "{syscall}", ')stdout=OS(src).run()print(stdout)