Skip to content

Commit

Permalink
added VamosTask for Python code
Browse files Browse the repository at this point in the history
  • Loading branch information
cnvogelg committed Oct 13, 2024
1 parent 657dc3d commit 944df9f
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 33 deletions.
2 changes: 1 addition & 1 deletion amitools/vamos/schedule/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .stack import Stack
from .task import NativeTask, TaskState
from .task import NativeTask, VamosTask, TaskState
from .scheduler import Scheduler
30 changes: 24 additions & 6 deletions amitools/vamos/schedule/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ def schedule(self):

# main loop
while True:
log_schedule.debug(
"schedule: current %s added %s ready %s waiting %s",
self.cur_task,
self.added_tasks,
self.ready_tasks,
self.waiting_tasks,
)

# nothing to do anymore?
if self.get_num_tasks() == 0:
break
Expand Down Expand Up @@ -81,8 +89,11 @@ def schedule(self):
old_task = self.cur_task
if old_task:
log_schedule.debug("run: switch out %s", old_task.name)
old_task.set_state(TaskState.TS_READY)
self.ready_tasks.append(old_task)
# if cur task still running (not waiting)
# then move it to ready list
if old_task.get_state() == TaskState.TS_RUN:
old_task.set_state(TaskState.TS_READY)
self.ready_tasks.append(old_task)

old_task.save_ctx()

Expand Down Expand Up @@ -123,7 +134,8 @@ def _find_run_task(self):
# keep current task
task = self.cur_task
log_schedule.debug("take: current task %s", task.name)
return task
if task.get_state() == TaskState.TS_READY:
return task

def _make_current(self, task):
self.cur_task = task
Expand All @@ -134,16 +146,18 @@ def wait_task(self, task):
"""set the given task into wait state"""
log_schedule.debug("wait_task: task %s", task.name)
self.waiting_tasks.append(task)
self.reschedule(task)
task.set_state(TaskState.TS_WAIT)
self.reschedule()

def wake_up_task(self, task):
"""take task from waiting list and allow him to schedule"""
log_schedule.debug("wake_up_task: task %s", task.name)
self.waiting_tasks.remove(task)
# add to front
self.ready_tasks.insert(0, task)
task.set_state(TaskState.TS_READY)
# directly reschedule
self.reschedule(task)
self.reschedule()

def add_task(self, task):
"""add a new task and prepare for execution.
Expand All @@ -160,15 +174,19 @@ def add_task(self, task):
def rem_task(self, task):
# find task: is it current? removing myself...
if self.cur_task == task:
log_schedule.debug("rem_task: cur_task %s", task.name)
self.cur_task = None
# in ready list?
elif task in self.ready_tasks:
log_schedule.debug("rem_task: ready %s", task.name)
self.ready_tasks.remove(task)
# in waiting list?
elif task in self.waiting_tasks:
log_schedule.debug("rem_task: waiting %s", task.name)
self.waiting_tasks.remove(task)
# in added list?
elif task in self.added_tasks:
log_schedule.debug("rem_task: added %s", task.name)
self.added_tasks.remove(task)
# not found
else:
Expand All @@ -181,6 +199,6 @@ def rem_task(self, task):
task.free()
return True

def reschedule(self, task):
def reschedule(self):
"""callback from tasks to reschedule"""
self.main_glet.switch()
83 changes: 64 additions & 19 deletions amitools/vamos/schedule/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ class TaskState(Enum):
class TaskBase:
"""basic structure for both native and Pyhton tasks"""

def __init__(self, name, machine):
def __init__(self, name, machine, stack):
self.name = name
self.machine = machine
self.runtime = Runtime(machine)
self.stack = stack
# state
self.state = TaskState.TS_INVALID
self.scheduler = None
Expand All @@ -42,17 +43,23 @@ def config(self, scheduler, slice_cycles):
self.glet = greenlet.greenlet(self.start)

def slice_hook(run_state):
self.scheduler.reschedule(self)
self.scheduler.reschedule()

self.runtime.set_slice_hook(slice_cycles, slice_hook)

def set_state(self, state):
"""the scheduler assigns a new state"""
self.state = state

def get_state(self):
return self.state

def get_name(self):
return self.name

def get_stack(self):
return self.stack

def get_run_state(self):
"""if task is running then you can get the current run state"""
return self.runtime.get_current_run_state()
Expand All @@ -62,15 +69,17 @@ def get_exit_code(self):

def reschedule(self):
"""give up this tasks execution and allow the scheduler to run another task"""
self.scheduler.reschedule(self)
self.scheduler.reschedule()

def forbid(self):
"""do not switch away from my task until permit() is called"""
self.forbid_cnt += 1
log_schedule.debug("%s: forbid (cnt=%d)", self.name, self.forbid_cnt)

def permit(self):
"""re-enable task switching"""
self.forbid_cnt -= 1
log_schedule.debug("%s: permit (cnt=%d)", self.name, self.forbid_cnt)
if self.forbid_cnt == 0:
# if a schedule was triggered during the forbid state then reschedule
if self.forbid_reschedule:
Expand Down Expand Up @@ -98,11 +107,13 @@ def wait(self, sigmask):
self.sigmask_wait = sigmask

# go waiting. reschedule
log_schedule.debug("%s: enter wait", self.name)
self.scheduler.wait_task(self)

# we will return here if we were removed from waiting list
# and our got mask is not empty anymore
got_mask = self.sigmask_received & sigmask
log_schedule.debug("%s: leave wait. got_mask=%x", self.name, got_mask)

# now reset wait mask
self.sigmask_wait = 0
Expand All @@ -114,50 +125,56 @@ def get_signal(self):

def set_signal(self, new_signals, sigmask):
"""set some of our signals"""
log_schedule.debug("%s: set_signal(%x, %x)", self.name, new_signals, sigmask)
self.sigmask_received = new_signals | (self.sigmask_received & ~sigmask)
# check if task is waiting for some of the signals
if self.sigmask_wait != 0:
got_mask = self.sigmask_received & self.sigmask_wait
if got_mask != 0:
log_schedule.debug("%s: set_signal -> wake me up", self.name)
self.scheduler.wake_up_task(self)
# return current mask
log_schedule.debug(
"%s: set_signal -> sigmask=%x", self.name, self.sigmask_received
)
return self.sigmask_received

def free(self):
"""clean up task resources, e.g. stack"""
pass
self.stack.free()

def start(self):
"""run the task until it ends. it might be interrupted by reschedule() calls"""
pass

def run(self, *args, **kw_args):
def sub_run(self, *args, **kw_args):
"""execute m68k code in your task"""
# inject own stack if needed
if not self.runtime.is_running() and "sp" not in kw_args:
kw_args["sp"] = self.stack.get_initial_sp()
return self.runtime.run(*args, **kw_args)

def switch(self):
self.glet.switch()

def save_ctx(self):
if self.runtime.is_running():
log_schedule.debug("%s: save cpu context", self)
log_schedule.debug("%s: save cpu context", self.name)
self.cpu_ctx = self.machine.cpu.get_cpu_context()

def restore_ctx(self):
if self.runtime.is_running():
log_schedule.debug("%s: restore cpu context", self)
log_schedule.debug("%s: restore cpu context", self.name)
self.machine.cpu.set_cpu_context(self.cpu_ctx)


class NativeTask(TaskBase):
"""a task that runs native m68k code"""

def __init__(
self, name, machine, init_pc, stack, start_regs=None, return_regs=None
self, name, machine, stack, init_pc, start_regs=None, return_regs=None
):
super().__init__(name, machine)
super().__init__(name, machine, stack)
self.init_pc = init_pc
self.stack = stack
if start_regs is None:
start_regs = {}
if return_regs is None:
Expand All @@ -168,7 +185,7 @@ def __init__(

def __repr__(self):
return (
"NativeTask(%r, init_pc=%06x, stack=%r, start_regs=%r, return_regs=%r)"
"NativeTask(%s, init_pc=%06x, stack=%r, start_regs=%r, return_regs=%r)"
% (
super().__repr__(),
self.init_pc,
Expand All @@ -178,29 +195,26 @@ def __repr__(self):
)
)

def free(self):
if self.stack:
self.stack.free()

def start(self):
pc = self.init_pc
sp = self.get_init_sp()
set_regs = self.start_regs
get_regs = self.return_regs
log_schedule.debug("%s: start native code. pc=%06x sp=%06x", self.name, pc, sp)
self.run_state = self.runtime.start(
pc, sp, set_regs=set_regs, get_regs=get_regs
)
self.exit_code = self.run_state.regs[REG_D0]
log_schedule.debug(
"%s: done native code. exit_code=%d", self.name, self.exit_code
)
# at the end of execution remove myself
if self.scheduler:
self.scheduler.rem_task(self)

def get_init_pc(self):
return self.init_pc

def get_stack(self):
return self.stack

def get_init_sp(self):
return self.stack.get_initial_sp()

Expand All @@ -212,3 +226,34 @@ def get_return_regs(self):

def get_run_result(self):
return self.run_state


class VamosTask(TaskBase):
"""a task running Python code that may use 68k code in sub runs"""

def __init__(self, name, machine, stack, run_func=None):
"""either supply a run function and an optional own stack"""
super().__init__(name, machine, stack)
self.run_func = run_func
self.stack = stack

def __repr__(self):
return "VamosTask(%s, run_func=%r)" % (super().__repr__(), self.run_func)

def run(self):
"""overload your own code here"""
return 0

def start(self):
# either run run() func or method
log_schedule.debug("%s: start Python code", self.name)
if self.run_func:
self.exit_code = self.run_func(self)
else:
self.exit_code = self.run()
log_schedule.debug(
"%s: done Python code. exit_code=%d", self.name, self.exit_code
)
# at the end of execution remove myself
if self.scheduler:
self.scheduler.rem_task(self)
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ tox
black
build
machine68k
greenlet
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pytest
pytest-benchmark
machine68k
greenlet
Loading

0 comments on commit 944df9f

Please sign in to comment.