2020-07-08 06:49:38 -06:00
|
|
|
__all__ = ["Process", "Timeline"]
|
|
|
|
|
|
|
|
|
|
|
|
class Process:
|
2020-07-08 11:30:06 -06:00
|
|
|
def __init__(self, *, is_comb):
|
|
|
|
self.is_comb = is_comb
|
|
|
|
|
|
|
|
self.reset()
|
|
|
|
|
2020-07-08 06:49:38 -06:00
|
|
|
def reset(self):
|
2020-07-08 11:30:06 -06:00
|
|
|
self.runnable = self.is_comb
|
|
|
|
self.passive = True
|
2020-07-08 06:49:38 -06:00
|
|
|
|
|
|
|
def run(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class Timeline:
|
|
|
|
def __init__(self):
|
|
|
|
self.now = 0.0
|
|
|
|
self.deadlines = dict()
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self.now = 0.0
|
|
|
|
self.deadlines.clear()
|
|
|
|
|
|
|
|
def at(self, run_at, process):
|
|
|
|
assert process not in self.deadlines
|
|
|
|
self.deadlines[process] = run_at
|
|
|
|
|
|
|
|
def delay(self, delay_by, process):
|
|
|
|
if delay_by is None:
|
|
|
|
run_at = self.now
|
|
|
|
else:
|
|
|
|
run_at = self.now + delay_by
|
|
|
|
self.at(run_at, process)
|
|
|
|
|
|
|
|
def advance(self):
|
|
|
|
nearest_processes = set()
|
|
|
|
nearest_deadline = None
|
|
|
|
for process, deadline in self.deadlines.items():
|
|
|
|
if deadline is None:
|
|
|
|
if nearest_deadline is not None:
|
|
|
|
nearest_processes.clear()
|
|
|
|
nearest_processes.add(process)
|
|
|
|
nearest_deadline = self.now
|
|
|
|
break
|
|
|
|
elif nearest_deadline is None or deadline <= nearest_deadline:
|
|
|
|
assert deadline >= self.now
|
|
|
|
if nearest_deadline is not None and deadline < nearest_deadline:
|
|
|
|
nearest_processes.clear()
|
|
|
|
nearest_processes.add(process)
|
|
|
|
nearest_deadline = deadline
|
|
|
|
|
|
|
|
if not nearest_processes:
|
|
|
|
return False
|
|
|
|
|
|
|
|
for process in nearest_processes:
|
|
|
|
process.runnable = True
|
|
|
|
del self.deadlines[process]
|
|
|
|
self.now = nearest_deadline
|
|
|
|
|
|
|
|
return True
|