diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index b18de1a..47bbb21 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(emu STATIC nanos6/create.c nanos6/event.c nanos6/pvt.c + nanos6/finish.c ) add_executable(ovniemu ovniemu.c) diff --git a/src/emu/emu.c b/src/emu/emu.c index 4498b27..881febf 100644 --- a/src/emu/emu.c +++ b/src/emu/emu.c @@ -160,9 +160,15 @@ emu_step(struct emu *emu) int emu_finish(struct emu *emu) { + if (model_finish(&emu->model, emu) != 0) { + err("model_finish failed"); + return -1; + } + if (recorder_finish(&emu->recorder) != 0) { err("recorder_finish failed"); return -1; } + return 0; } diff --git a/src/emu/model.c b/src/emu/model.c index d6af3dd..4bda566 100644 --- a/src/emu/model.c +++ b/src/emu/model.c @@ -105,3 +105,22 @@ model_event(struct model *model, struct emu *emu, int index) return 0; } + +int +model_finish(struct model *model, struct emu *emu) +{ + for (int i = 0; i < MAX_MODELS; i++) { + if (!model->enabled[i]) + continue; + + struct model_spec *spec = model->spec[i]; + if (spec->finish == NULL) + continue; + + if (spec->finish(emu) != 0) { + err("finish failed for model '%c'", (char) i); + return -1; + } + } + return 0; +} diff --git a/src/emu/model.h b/src/emu/model.h index c5333d2..f2d821d 100644 --- a/src/emu/model.h +++ b/src/emu/model.h @@ -14,6 +14,7 @@ struct model_spec { emu_hook_t *create; emu_hook_t *connect; emu_hook_t *event; + emu_hook_t *finish; }; #define MAX_MODELS 256 @@ -31,5 +32,6 @@ int model_probe(struct model *model, struct emu *emu); int model_create(struct model *model, struct emu *emu); int model_connect(struct model *model, struct emu *emu); int model_event(struct model *model, struct emu *emu, int index); +int model_finish(struct model *model, struct emu *emu); #endif /* MODEL_H */ diff --git a/src/emu/nanos6/finish.c b/src/emu/nanos6/finish.c new file mode 100644 index 0000000..ce240df --- /dev/null +++ b/src/emu/nanos6/finish.c @@ -0,0 +1,44 @@ +#include "nanos6_priv.h" + +static int +end_lint(struct emu *emu) +{ + struct system *sys = &emu->system; + + /* Ensure we run out of subsystem states */ + for (struct thread *t = sys->threads; t; t = t->gnext) { + struct nanos6_thread *th = EXT(t, '6'); + struct chan *ch = &th->ch[CH_SUBSYSTEM]; + int stacked = ch->data.stack.n; + if (stacked > 0) { + struct value top; + if (chan_read(ch, &top) != 0) { + err("chan_read failed for subsystem"); + return -1; + } + + err("thread %d ended with %d stacked nanos6 subsystems, top=\"%s\"\n", + t->tid, stacked, ss_name(top.i)); + return -1; + } + } + + return 0; +} + +int +nanos6_finish(struct emu *emu) +{ + if (finish_pvt(emu) != 0) { + err("finish_pvt failed"); + return -1; + } + + /* When running in linter mode perform additional checks */ + if (emu->args.linter_mode && end_lint(emu) != 0) { + err("end_lint failed"); + return -1; + } + + return 0; +} diff --git a/src/emu/nanos6/nanos6_priv.h b/src/emu/nanos6/nanos6_priv.h index ddb39c2..7a410b0 100644 --- a/src/emu/nanos6/nanos6_priv.h +++ b/src/emu/nanos6/nanos6_priv.h @@ -98,7 +98,10 @@ int nanos6_probe(struct emu *emu); int nanos6_create(struct emu *emu); int nanos6_connect(struct emu *emu); int nanos6_event(struct emu *emu); +int nanos6_finish(struct emu *emu); int init_pvt(struct emu *emu); +int finish_pvt(struct emu *emu); +const char *ss_name(int ss); #endif /* NANOS6_PRIV_H */ diff --git a/src/emu/nanos6/probe.c b/src/emu/nanos6/probe.c index 72befa6..0deb9a6 100644 --- a/src/emu/nanos6/probe.c +++ b/src/emu/nanos6/probe.c @@ -7,6 +7,7 @@ struct model_spec model_nanos6 = { .connect = nanos6_connect, .event = nanos6_event, .probe = nanos6_probe, + .finish = nanos6_finish, }; int diff --git a/src/emu/nanos6/pvt.c b/src/emu/nanos6/pvt.c index 94efe83..8f7b429 100644 --- a/src/emu/nanos6/pvt.c +++ b/src/emu/nanos6/pvt.c @@ -1,6 +1,12 @@ #include "nanos6_priv.h" /* TODO: Assign types on runtime and generate configs */ + +static const char *pvt_name[CT_MAX] = { + [CT_TH] = "thread", + [CT_CPU] = "cpu", +}; + static const int pvt_type[] = { [CH_TASKID] = 35, [CH_TYPE] = 36, @@ -240,3 +246,48 @@ init_pvt(struct emu *emu) return 0; } + +int +finish_pvt(struct emu *emu) +{ + struct system *sys = &emu->system; + + /* Emit task types for all channel types and processes */ + for (enum chan_type ct = 0; ct < CHAN_MAXTYPE; ct++) { + struct pvt *pvt = recorder_find_pvt(&emu->recorder, pvt_name[ct]); + if (pvt == NULL) { + err("cannot find pvt with name '%s'", pvt_name[ct]); + return -1; + } + struct pcf *pcf = pvt_get_pcf(pvt); + long typeid = pvt_type[CH_TYPE]; + struct pcf_type *pcftype = pcf_find_type(pcf, typeid); + + for (struct proc *p = sys->procs; p; p = p->gnext) { + struct nanos6_proc *nanos6proc = EXT(p, '6'); + struct task_info *info = &nanos6proc->task_info; + if (task_create_pcf_types(pcftype, info->types) != 0) { + err("task_create_pcf_types failed"); + return -1; + } + } + } + + return 0; +} + +const char * +ss_name(int ss) +{ + static const char *unknown = "(unknown)"; + const char *name = unknown; + const struct pcf_value_label *pv; + for (pv = &nanos6_ss_values[0]; pv->label; pv++) { + if (pv->value == ss) { + name = pv->label; + break; + } + } + + return name; +} diff --git a/src/emu/task.c b/src/emu/task.c index df438b2..4ce6a27 100644 --- a/src/emu/task.c +++ b/src/emu/task.c @@ -5,6 +5,7 @@ #include "uthash.h" #include "utlist.h" +#include "pcf.h" struct task * task_find(struct task *tasks, uint32_t task_id) @@ -281,24 +282,31 @@ task_type_create(struct task_info *info, uint32_t type_id, const char *label) return 0; } -//void -//task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types) -//{ -// /* Emit types for all task types */ -// for (struct task_type *tt = types; tt != NULL; tt = tt->hh.next) { -// struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid); -// if (pcfvalue != NULL) { -// /* Ensure the label is the same, so we know that -// * no collision occurred */ -// if (strcmp(pcfvalue->label, tt->label) != 0) -// die("collision occurred in task type labels"); -// else -// continue; -// } -// -// pcf_add_value(pcftype, tt->gid, tt->label); -// } -//} +int +task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types) +{ + int ret = 0; + + /* Emit types for all task types */ + for (struct task_type *tt = types; tt != NULL; tt = tt->hh.next) { + struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid); + if (pcfvalue != NULL) { + /* Ensure the label is the same, so we know that + * no collision occurred */ + if (strcmp(pcfvalue->label, tt->label) != 0) { + err("collision occurred in task type labels: %s and %s", + pcfvalue->label, tt->label); + ret = -1; + } else { + continue; + } + } + + pcf_add_value(pcftype, tt->gid, tt->label); + } + + return ret; +} struct task * task_get_running(struct task_stack *stack) diff --git a/src/emu/task.h b/src/emu/task.h index 2047240..e35efd2 100644 --- a/src/emu/task.h +++ b/src/emu/task.h @@ -64,7 +64,7 @@ int task_end(struct task_stack *stack, struct task *task); struct task_type *task_type_find(struct task_type *types, uint32_t type_id); int task_type_create(struct task_info *info, uint32_t type_id, const char *label); -//void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types); +int task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types); struct task *task_get_running(struct task_stack *stack); #endif /* TASK_H */ diff --git a/test/emu/nanos6/CMakeLists.txt b/test/emu/nanos6/CMakeLists.txt index f0e056c..5a6f819 100644 --- a/test/emu/nanos6/CMakeLists.txt +++ b/test/emu/nanos6/CMakeLists.txt @@ -7,4 +7,4 @@ ovni_test(nested-tasks-bad.c SHOULD_FAIL ovni_test(task-types.c MP) ovni_test(blocking.c MP) ovni_test(ss-mismatch.c SHOULD_FAIL - REGEX "thread [0-9]\\+ ended with 1 extra stacked nanos6 subsystems, top=\"Worker: Looking for work\"") + REGEX "thread [0-9]\\+ ended with 1 stacked nanos6 subsystems, top=\"Worker: Looking for work\"")