Support for nested tasks

This commit is contained in:
David Alvarez 2021-12-07 18:56:05 +01:00 committed by Rodrigo Arias
parent ce9a68fc7e
commit a8b1256375
4 changed files with 55 additions and 45 deletions

7
chan.c
View File

@ -209,13 +209,6 @@ chan_set(struct ovni_chan *chan, int st)
} }
} }
void
chan_enable_and_set(struct ovni_chan *chan, int st)
{
chan_enable(chan, 1);
chan_set(chan, st);
}
void void
chan_push(struct ovni_chan *chan, int st) chan_push(struct ovni_chan *chan, int st)
{ {

3
chan.h
View File

@ -56,9 +56,6 @@ chan_is_enabled(struct ovni_chan *chan);
void void
chan_set(struct ovni_chan *chan, int st); chan_set(struct ovni_chan *chan, int st);
void
chan_enable_and_set(struct ovni_chan *chan, int st);
void void
chan_push(struct ovni_chan *chan, int st); chan_push(struct ovni_chan *chan, int st);

6
emu.h
View File

@ -112,6 +112,10 @@ struct nosv_task {
struct ovni_ethread *thread; struct ovni_ethread *thread;
enum nosv_task_state state; enum nosv_task_state state;
UT_hash_handle hh; UT_hash_handle hh;
/* List handle for nested task support */
struct nosv_task *next;
struct nosv_task *prev;
}; };
struct nosv_task_type { struct nosv_task_type {
@ -284,6 +288,8 @@ struct ovni_ethread {
/* nosv task */ /* nosv task */
struct nosv_task *task; struct nosv_task *task;
/* nosv effective task, which is what is currently executing */
struct nosv_task *running_task;
/* Channels are used to output the emulator state in PRV */ /* Channels are used to output the emulator state in PRV */
struct ovni_chan chan[CHAN_MAX]; struct ovni_chan chan[CHAN_MAX];

View File

@ -16,6 +16,7 @@
*/ */
#include "uthash.h" #include "uthash.h"
#include "utlist.h"
#include "ovni.h" #include "ovni.h"
#include "emu.h" #include "emu.h"
@ -80,7 +81,7 @@ static void
pre_task_create(struct ovni_emu *emu) pre_task_create(struct ovni_emu *emu)
{ {
struct nosv_task *task, *p = NULL; struct nosv_task *task, *p = NULL;
task = calloc(1, sizeof(*task)); task = calloc(1, sizeof(*task));
if(task == NULL) if(task == NULL)
@ -106,8 +107,6 @@ pre_task_create(struct ovni_emu *emu)
/* Add the new task to the hash table */ /* Add the new task to the hash table */
HASH_ADD_INT(emu->cur_proc->tasks, id, task); HASH_ADD_INT(emu->cur_proc->tasks, id, task);
emu->cur_task = task;
dbg("new task created id=%d\n", task->id); dbg("new task created id=%d\n", task->id);
} }
@ -138,9 +137,8 @@ pre_task_execute(struct ovni_emu *emu)
task->state = TASK_ST_RUNNING; task->state = TASK_ST_RUNNING;
task->thread = emu->cur_thread; task->thread = emu->cur_thread;
emu->cur_thread->task = task; DL_PREPEND(emu->cur_thread->task, task);
emu->cur_thread->running_task = task;
emu->cur_task = task;
dbg("task id=%d runs now\n", task->id); dbg("task id=%d runs now\n", task->id);
} }
@ -170,9 +168,9 @@ pre_task_pause(struct ovni_emu *emu)
if(emu->cur_thread != task->thread) if(emu->cur_thread != task->thread)
die("task is assigned to a different thread\n"); die("task is assigned to a different thread\n");
task->state = TASK_ST_PAUSED; emu->cur_thread->running_task = NULL;
emu->cur_task = task; task->state = TASK_ST_PAUSED;
dbg("task id=%d pauses\n", task->id); dbg("task id=%d pauses\n", task->id);
} }
@ -202,9 +200,9 @@ pre_task_resume(struct ovni_emu *emu)
if(emu->cur_thread != task->thread) if(emu->cur_thread != task->thread)
die("task is assigned to a different thread\n"); die("task is assigned to a different thread\n");
task->state = TASK_ST_RUNNING; emu->cur_thread->running_task = task;
emu->cur_task = task; task->state = TASK_ST_RUNNING;
dbg("task id=%d resumes\n", task->id); dbg("task id=%d resumes\n", task->id);
} }
@ -237,13 +235,25 @@ pre_task_end(struct ovni_emu *emu)
task->state = TASK_ST_DEAD; task->state = TASK_ST_DEAD;
task->thread = NULL; task->thread = NULL;
emu->cur_thread->task = NULL; DL_DELETE(emu->cur_thread->task, task);
emu->cur_thread->running_task = emu->cur_thread->task;
emu->cur_task = task;
dbg("task id=%d ends\n", task->id); dbg("task id=%d ends\n", task->id);
} }
static void
pre_task_not_running(struct ovni_emu *emu)
{
struct ovni_ethread *th;
th = emu->cur_thread;
chan_set(&th->chan[CHAN_NOSV_TASKID], 0);
chan_set(&th->chan[CHAN_NOSV_TYPEID], 0);
chan_set(&th->chan[CHAN_NOSV_APPID], 0);
chan_pop(&th->chan[CHAN_NOSV_SUBSYSTEM], ST_NOSV_TASK_RUNNING);
}
static void static void
pre_task_running(struct ovni_emu *emu, struct nosv_task *task) pre_task_running(struct ovni_emu *emu, struct nosv_task *task)
{ {
@ -273,28 +283,35 @@ pre_task_running(struct ovni_emu *emu, struct nosv_task *task)
} }
static void static void
pre_task_not_running(struct ovni_emu *emu) pre_task_switch(struct ovni_emu *emu, struct nosv_task *prev_task, struct nosv_task *next_task)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_eproc *proc;
assert(prev_task);
assert(next_task);
assert(prev_task != next_task);
th = emu->cur_thread; th = emu->cur_thread;
proc = emu->cur_proc;
chan_set(&th->chan[CHAN_NOSV_TASKID], 0); assert(next_task->id > 0);
chan_set(&th->chan[CHAN_NOSV_TYPEID], 0); assert(next_task->type_id > 0);
chan_set(&th->chan[CHAN_NOSV_APPID], 0); assert(proc->appid > 0);
if(emu->cur_loom->rank_enabled) chan_set(&th->chan[CHAN_NOSV_TASKID], next_task->id);
chan_set(&th->chan[CHAN_NOSV_RANK], 0);
chan_pop(&th->chan[CHAN_NOSV_SUBSYSTEM], ST_NOSV_TASK_RUNNING); if (prev_task->type_id != next_task->type_id)
chan_set(&th->chan[CHAN_NOSV_TYPEID], next_task->type_id);
} }
static void static void
pre_task(struct ovni_emu *emu) pre_task(struct ovni_emu *emu)
{ {
struct nosv_task *task; struct nosv_task *prev_task, *next_task;
task = emu->cur_task; assert(emu->cur_thread);
prev_task = emu->cur_thread->running_task;
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
@ -307,19 +324,16 @@ pre_task(struct ovni_emu *emu)
abort(); abort();
} }
switch(emu->cur_ev->header.value) next_task = emu->cur_thread->running_task;
{
case 'x': // Unless we're creating a task, register the switch
case 'r': if (emu->cur_ev->header.value != 'c') {
pre_task_running(emu, task); if(!next_task)
break;
case 'p':
case 'e':
pre_task_not_running(emu); pre_task_not_running(emu);
break; else if(!prev_task)
case 'c': pre_task_running(emu, next_task);
default: else
break; pre_task_switch(emu, prev_task, next_task);
} }
} }
@ -350,7 +364,7 @@ pre_type_create(struct ovni_emu *emu)
err("A task type with id %d already exists\n", *typeid); err("A task type with id %d already exists\n", *typeid);
abort(); abort();
} }
type = calloc(1, sizeof(*type)); type = calloc(1, sizeof(*type));
if(type == NULL) if(type == NULL)