Introduce channels

This commit is contained in:
Rodrigo Arias 2021-10-21 16:15:29 +02:00
parent 13e6eabf33
commit fbfbb8fc0f
8 changed files with 443 additions and 365 deletions

View File

@ -24,7 +24,7 @@ dump: ovni.o dump.o parson.o
test_speed: test_speed.c ovni.o parson.o test_speed: test_speed.c ovni.o parson.o
emu: emu.o emu_ovni.o emu_nosv.o emu_nosv_ss.o ovni.o prv.o pcf.o parson.o emu: emu.o emu_ovni.o emu_nosv.o emu_nosv_ss.o ovni.o prv.o pcf.o parson.o chan.o
libovni.so: ovni.o parson.o libovni.so: ovni.o parson.o
$(LINK.c) -shared $^ -o $@ $(LINK.c) -shared $^ -o $@

176
chan.c Normal file
View File

@ -0,0 +1,176 @@
#include <assert.h>
#include "emu.h"
#include "prv.h"
void
chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock)
{
chan->n = 0;
chan->type = type;
chan->enabled = 0;
chan->badst = ST_NULL;
chan->ev = -1;
chan->prv = prv;
chan->clock = clock;
chan->t = -1;
chan->row = row;
chan->dirty = 0;
}
void
chan_enable(struct ovni_chan *chan, int enabled)
{
chan->enabled = enabled;
}
int
chan_is_enabled(struct ovni_chan *chan)
{
return chan->enabled;
}
void
chan_set(struct ovni_chan *chan, int st)
{
dbg("chan_set st=%d", st);
assert(chan->enabled);
assert(chan->dirty == 0);
if(chan->n == 0)
chan->n = 1;
chan->stack[chan->n] = st;
chan->t = *chan->clock;
chan->dirty = 1;
}
void
chan_push(struct ovni_chan *chan, int st)
{
dbg("chan_push st=%d", st);
assert(chan->enabled);
assert(chan->dirty == 0);
if(chan->n >= MAX_CHAN_STACK)
{
err("channel stack full\n");
exit(EXIT_FAILURE);
}
chan->stack[chan->n++] = st;
chan->t = *chan->clock;
chan->dirty = 1;
}
int
chan_pop(struct ovni_chan *chan, int expected_st)
{
int st;
dbg("chan_pop expexted_st=%d", expected_st);
assert(chan->enabled);
assert(chan->dirty == 0);
if(chan->n <= 0)
{
err("channel empty\n");
exit(EXIT_FAILURE);
}
st = chan->stack[chan->n - 1];
if(expected_st >= 0 && st != expected_st)
{
err("unexpected channel state %d (expected %d)\n",
st, expected_st);
exit(EXIT_FAILURE);
}
chan->n--;
chan->t = *chan->clock;
chan->dirty = 1;
return st;
}
void
chan_ev(struct ovni_chan *chan, int ev)
{
assert(chan->enabled);
assert(chan->dirty == 0);
assert(ev >= 0);
chan->ev = ev;
chan->t = *chan->clock;
chan->dirty = 1;
}
int
chan_get_st(struct ovni_chan *chan)
{
if(chan->enabled == 0)
return chan->badst;
assert(chan->n > 0);
return chan->stack[chan->n-1];
}
static void
emit_ev(struct ovni_chan *chan)
{
int new, last;
assert(chan->enabled);
assert(chan->ev != -1);
new = chan->ev;
last = chan_get_st(chan);
prv_ev(chan->prv, chan->row, chan->t-1, chan->type, new);
prv_ev(chan->prv, chan->row, chan->t, chan->type, last);
chan->ev = -1;
}
static void
emit_st(struct ovni_chan *chan)
{
int st;
assert(chan->enabled);
st = chan_get_st(chan);
prv_ev(chan->prv, chan->row, chan->t, chan->type, st);
}
/* Emits either the current state or punctual event in the PRV file */
void
chan_emit(struct ovni_chan *chan)
{
if(chan->dirty == 0)
return;
/* Emit badst if disabled */
if(chan->enabled == 0)
{
/* No punctual events allowed when disabled */
assert(chan->ev == -1);
emit_st(chan);
goto shower;
}
/* Otherwise, emit punctual event if any or the state */
if(chan->ev != -1)
emit_ev(chan);
else
emit_st(chan);
shower:
chan->dirty = 0;
}

33
chan.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef OVNI_CHAN_H
#define OVNI_CHAN_H
#include "emu.h"
void
chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock);
void
chan_enable(struct ovni_chan *chan, int enabled);
int
chan_is_enabled(struct ovni_chan *chan);
void
chan_set(struct ovni_chan *chan, int st);
void
chan_push(struct ovni_chan *chan, int st);
int
chan_pop(struct ovni_chan *chan, int expected_st);
void
chan_ev(struct ovni_chan *chan, int ev);
int
chan_get_st(struct ovni_chan *chan);
void
chan_emit(struct ovni_chan *chan);
#endif /* OVNI_CHAN_H */

55
emu.c
View File

@ -17,6 +17,7 @@
#include "emu.h" #include "emu.h"
#include "prv.h" #include "prv.h"
#include "pcf.h" #include "pcf.h"
#include "chan.h"
/* Obtains the corrected clock of the given event */ /* Obtains the corrected clock of the given event */
int64_t int64_t
@ -75,6 +76,18 @@ find_thread(struct ovni_eproc *proc, pid_t tid)
return NULL; return NULL;
} }
static void
emit_channels(struct ovni_emu *emu)
{
struct ovni_ethread *th;
int i;
th = emu->cur_thread;
for(i=0; i<CHAN_MAX; i++)
chan_emit(&th->chan[i]);
}
static void static void
hook_pre(struct ovni_emu *emu) hook_pre(struct ovni_emu *emu)
{ {
@ -99,6 +112,8 @@ hook_emit(struct ovni_emu *emu)
{ {
//emu_emit(emu); //emu_emit(emu);
emit_channels(emu);
switch(emu->cur_ev->header.model) switch(emu->cur_ev->header.model)
{ {
case 'O': hook_emit_ovni(emu); case 'O': hook_emit_ovni(emu);
@ -665,6 +680,44 @@ emu_virtual_ev(struct ovni_emu *emu, char *mcv)
trace->nvirtual++; trace->nvirtual++;
} }
static void
init_thread(struct ovni_emu *emu, struct ovni_ethread *th)
{
int i, row;
row = th->gindex + 1;
for(i=0; i<CHAN_MAX; i++)
{
chan_init(&th->chan[i], row, type, emu->prv_thread,
&emu->delta_clock);
}
}
static void
init_threads(struct ovni_emu *emu)
{
struct ovni_loom *loom;
struct ovni_eproc *proc;
struct ovni_ethread *thread;
int i, j, k;
for(i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
thread = &proc->thread[k];
init_thread(emu, thread);
}
}
}
}
static void static void
emu_init(struct ovni_emu *emu, int argc, char *argv[]) emu_init(struct ovni_emu *emu, int argc, char *argv[])
{ {
@ -689,6 +742,8 @@ emu_init(struct ovni_emu *emu, int argc, char *argv[])
open_prvs(emu, emu->tracedir); open_prvs(emu, emu->tracedir);
open_pcfs(emu, emu->tracedir); open_pcfs(emu, emu->tracedir);
init_threads(emu);
} }
static void static void

65
emu.h
View File

@ -64,7 +64,54 @@ struct nosv_task_type {
UT_hash_handle hh; UT_hash_handle hh;
}; };
#define MAX_SS_STACK 128 #define MAX_CHAN_STACK 128
struct ovni_chan {
/* Number of states in the stack */
int n;
/* Stack of states */
int stack[MAX_CHAN_STACK];
/* 1 if enabled, 0 if not. */
int enabled;
/* What state should be shown in errors */
int badst;
/* Punctual event: -1 if not used */
int ev;
/* Emit events of this type */
int type;
/* A pointer to a clock to sample the time */
int64_t *clock;
/* The time of the last state or event */
int64_t t;
/* Paraver row */
int row;
/* 1 if channel needs flush to PRV */
int dirty;
/* Where should the events be written to? */
FILE *prv;
};
enum chan {
/* Ovni */
CHAN_OVNI_STATE = 0,
CHAN_OVNI_TID,
CHAN_OVNI_PID,
/* nOS-V */
CHAN_NOSV_TASK_ID,
CHAN_NOSV_SS, /* Subsystem */
CHAN_MAX
};
/* All PRV event types */ /* All PRV event types */
enum prv_type { enum prv_type {
@ -105,22 +152,14 @@ struct ovni_ethread {
/* Current cpu */ /* Current cpu */
struct ovni_cpu *cpu; struct ovni_cpu *cpu;
/* Number of subsystem states in the stack */
int nss;
/* Stack of subsystem states */
int ss[MAX_SS_STACK];
int ss_event;
/* FIXME: Use a table with registrable pointers to custom data /* FIXME: Use a table with registrable pointers to custom data
* structures */ * structures */
/* nosv task */ /* nosv task */
struct nosv_task *task; struct nosv_task *task;
/* Should we print the subsystem? */ /* Channels are used to output the emulator state in PRV */
int show_ss; struct ovni_chan chan[CHAN_MAX];
}; };
/* State of each emulated process */ /* State of each emulated process */
@ -180,10 +219,6 @@ struct ovni_cpu {
/* The threads the cpu is currently running */ /* The threads the cpu is currently running */
size_t nthreads; size_t nthreads;
struct ovni_ethread *thread[OVNI_MAX_THR]; struct ovni_ethread *thread[OVNI_MAX_THR];
///* Each channel emits events in the PRV file */
//int nchannels;
//struct ovni_channel *channel;
}; };
/* ----------------------- trace ------------------------ */ /* ----------------------- trace ------------------------ */

View File

@ -5,6 +5,7 @@
#include "ovni_trace.h" #include "ovni_trace.h"
#include "emu.h" #include "emu.h"
#include "prv.h" #include "prv.h"
#include "chan.h"
enum nosv_prv_type { enum nosv_prv_type {
PRV_TYPE_PROCID PRV_TYPE_PROCID
@ -15,6 +16,28 @@ struct hook_entry {
void (*hook)(struct ovni_emu *); void (*hook)(struct ovni_emu *);
}; };
/* --------------------------- init ------------------------------- */
void
hook_nosv_init(struct ovni_emu *emu)
{
struct ovni_ethread *th;
int i, row, type;
FILE *prv;
int64_t *clock;
for(i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
row = th->gindex + 1;
//chan_init(struct ovni_chan *chan, int row, int type, FILE *prv, int64_t *clock)
chan_init(th->chan[CHAN_NOSV_TASK_ID], row, PTT_TASK_ID, prv,
clock);
}
}
/* --------------------------- pre ------------------------------- */ /* --------------------------- pre ------------------------------- */
static void static void
@ -286,6 +309,11 @@ emit_task(struct ovni_emu *emu)
void void
hook_emit_nosv(struct ovni_emu *emu) hook_emit_nosv(struct ovni_emu *emu)
{ {
struct ovni_ethread *th;
int i;
th = emu->cur_thread;
switch(emu->cur_ev->header.class) switch(emu->cur_ev->header.class)
{ {
case 'T': emit_task(emu); break; case 'T': emit_task(emu); break;

View File

@ -5,6 +5,7 @@
#include "ovni_trace.h" #include "ovni_trace.h"
#include "emu.h" #include "emu.h"
#include "prv.h" #include "prv.h"
#include "chan.h"
/* This module manages the nos-v subsystem (ss) events, to track which /* This module manages the nos-v subsystem (ss) events, to track which
* actions are being performed by each thread at a given time. A stack * actions are being performed by each thread at a given time. A stack
@ -12,94 +13,34 @@
* execution. Events such as task received by a thread are emitted as * execution. Events such as task received by a thread are emitted as
* fake events with very short period. */ * fake events with very short period. */
/* --------------------------- ss helpers ------------------------------- */
static void
ss_init(struct ovni_ethread *t)
{
t->nss = 0;
t->show_ss = 0;
}
static void
ss_push(struct ovni_ethread *t, int st)
{
if(t->nss >= MAX_SS_STACK)
{
err("thread %d subsystem stack full\n", t->tid);
exit(EXIT_FAILURE);
}
t->ss[t->nss] = st;
t->nss++;
}
static int
ss_pop(struct ovni_ethread *t, int expected_st)
{
int st;
if(t->nss <= 0)
{
err("thread %d subsystem stack empty\n", t->tid);
exit(EXIT_FAILURE);
}
st = t->ss[t->nss - 1];
if(st > 0 && st != expected_st)
{
err("thread %d expected subsystem state %d (got %d)\n",
t->tid, expected_st, st);
exit(EXIT_FAILURE);
}
t->nss--;
return st;
}
static void
ss_ev(struct ovni_ethread *th, int ev)
{
th->ss_event = ev;
}
static int
ss_last_st(struct ovni_ethread *th)
{
if(th->nss == 0)
return ST_NULL;
return th->ss[th->nss - 1];
}
/* --------------------------- pre ------------------------------- */ /* --------------------------- pre ------------------------------- */
static void static void
pre_sched(struct ovni_emu *emu) pre_sched(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan;
th = emu->cur_thread; th = emu->cur_thread;
chan = &th->chan[CHAN_NOSV_SS];
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'h': case 'h':
ss_push(th, ST_SCHED_HUNGRY); chan_push(chan, ST_SCHED_HUNGRY);
break; break;
case 'f': /* Fill: no longer hungry */ case 'f': /* Fill: no longer hungry */
ss_pop(th, ST_SCHED_HUNGRY); chan_pop(chan, ST_SCHED_HUNGRY);
break; break;
case '[': /* Server enter */ case '[': /* Server enter */
ss_push(th, ST_SCHED_SERVING); chan_push(chan, ST_SCHED_SERVING);
break; break;
case ']': /* Server exit */ case ']': /* Server exit */
ss_pop(th, ST_SCHED_SERVING); chan_pop(chan, ST_SCHED_SERVING);
break; break;
case '@': ss_ev(th, EV_SCHED_SELF); break; case '@': chan_ev(chan, EV_SCHED_SELF); break;
case 'r': ss_ev(th, EV_SCHED_RECV); break; case 'r': chan_ev(chan, EV_SCHED_RECV); break;
case 's': ss_ev(th, EV_SCHED_SEND); break; case 's': chan_ev(chan, EV_SCHED_SEND); break;
default: default:
break; break;
} }
@ -109,12 +50,15 @@ static void
pre_submit(struct ovni_emu *emu) pre_submit(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan;
th = emu->cur_thread; th = emu->cur_thread;
chan = &th->chan[CHAN_NOSV_SS];
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case '[': ss_push(th, ST_SCHED_SUBMITTING); break; case '[': chan_push(chan, ST_SCHED_SUBMITTING); break;
case ']': ss_pop(th, ST_SCHED_SUBMITTING); break; case ']': chan_pop(chan, ST_SCHED_SUBMITTING); break;
default: default:
break; break;
} }
@ -124,94 +68,30 @@ static void
pre_memory(struct ovni_emu *emu) pre_memory(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan;
th = emu->cur_thread; th = emu->cur_thread;
chan = &th->chan[CHAN_NOSV_SS];
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case '[': ss_push(th, ST_MEM_ALLOCATING); break; case '[': chan_push(chan, ST_MEM_ALLOCATING); break;
case ']': ss_pop(th, ST_MEM_ALLOCATING); break; case ']': chan_pop(chan, ST_MEM_ALLOCATING); break;
default: default:
break; break;
} }
} }
/* Hook for the virtual "thread changed" event */
static void
pre_thread_change(struct ovni_emu *emu)
{
struct ovni_ethread *th;
th = emu->cur_thread;
/* Only print the subsystem if the thread is running */
if(th->state == TH_ST_RUNNING)
th->show_ss = 1;
else
th->show_ss = 0;
}
static void
pre_thread(struct ovni_emu *emu)
{
switch(emu->cur_ev->header.value)
{
case 'c': pre_thread_change(emu); break;
default:
break;
}
}
/* Hook for the virtual "cpu changed" event */
static void
pre_cpu_change(struct ovni_emu *emu)
{
struct ovni_ethread *th;
th = emu->cur_thread;
/* Only print the subsystem if the thread is running */
if(th->state == TH_ST_RUNNING)
th->show_ss = 1;
else
th->show_ss = 0;
}
static void
pre_cpu(struct ovni_emu *emu)
{
switch(emu->cur_ev->header.value)
{
case 'c': pre_thread_change(emu); break;
default:
break;
}
}
void void
hook_pre_nosv_ss(struct ovni_emu *emu) hook_pre_nosv_ss(struct ovni_emu *emu)
{ {
switch(emu->cur_ev->header.model) assert(emu->cur_ev->header.model == 'V');
switch(emu->cur_ev->header.class)
{ {
/* Listen for virtual events as well */ case 'S': pre_sched(emu); break;
case '*': case 'U': pre_submit(emu); break;
switch(emu->cur_ev->header.class) case 'M': pre_memory(emu); break;
{
case 'H': pre_thread(emu); break;
case 'C': pre_cpu(emu); break;
default:
break;
}
break;
case 'V':
switch(emu->cur_ev->header.class)
{
case 'S': pre_sched(emu); break;
case 'U': pre_submit(emu); break;
case 'M': pre_memory(emu); break;
default:
break;
}
break;
default: default:
break; break;
} }
@ -219,173 +99,15 @@ hook_pre_nosv_ss(struct ovni_emu *emu)
/* --------------------------- emit ------------------------------- */ /* --------------------------- emit ------------------------------- */
static void
emit_thread_state(struct ovni_emu *emu, struct ovni_ethread *th,
int type, int st)
{
int row;
row = th->gindex + 1;
prv_ev_thread(emu, row, type, st);
}
static void
emit_cpu_state(struct ovni_emu *emu, struct ovni_ethread *th,
int type, int st)
{
/* Detect multiple threads */
if(th->cpu && th->cpu->nthreads > 1)
st = ST_BAD;
prv_ev_autocpu(emu, type, st);
}
static void
emit_thread_event(struct ovni_emu *emu, struct ovni_ethread *th,
int type, int st)
{
int64_t t0, t1;
int row;
int prev_st;
row = th->gindex + 1;
t0 = emu->delta_time - 1;
t1 = emu->delta_time;
prev_st = ss_last_st(th);
/* Fake event using 1 nanosecond in the past */
prv_ev_thread_raw(emu, row, t0, type, st);
prv_ev_thread_raw(emu, row, t1, type, prev_st);
}
static void
emit_cpu_event(struct ovni_emu *emu, struct ovni_ethread *th,
int type, int st)
{
int64_t t0, t1;
int row;
int prev_st;
row = th->gindex + 1;
t0 = emu->delta_time - 1;
t1 = emu->delta_time;
prev_st = ss_last_st(th);
/* Detect multiple threads */
if(th->cpu && th->cpu->nthreads > 1)
{
st = ST_BAD;
prev_st = ST_BAD;
}
/* Fake event using 1 nanosecond in the past */
prv_ev_autocpu_raw(emu, t0, type, st);
prv_ev_autocpu_raw(emu, t1, type, prev_st);
}
static void
emit_thread_changed(struct ovni_emu *emu)
{
dbg("emit_thread_changed\n")
}
static void
emit_cpu_changed(struct ovni_emu *emu)
{
dbg("emit_cpu_changed\n")
//int i;
//struct ovni_loom *loom;
//struct ovni_cpu *cpu;
///* Detect multiple threads */
//loom = emu->cur_loom;
//assert(loom->nupdated_cpus > 0);
//for(i=0; i<loom->nupdated_cpus; i++)
//{
// cpu = loom->updated_cpu[i];
// if(cpu->nthreads > 1)
// {
// prv_stream_disable(cpu->ss_stream);
// }
//}
}
void void
hook_emit_nosv_ss(struct ovni_emu *emu) hook_emit_nosv_ss(struct ovni_emu *emu)
{ {
/* We need to emit events when a thread notifies us that the subsystem
* has changed, but also when the thread is paused, or scheduled to
* another CPU, as the CPU view must be updated as well. */
switch(emu->cur_ev->header.model)
{
/* Listen for virtual events as well */
case '*':
switch(emu->cur_ev->header.class)
{
case 'H':
switch(emu->cur_ev->header.value)
{
case 'c': emit_thread_changed(emu); break;
default: break;
}
break;
case 'C':
switch(emu->cur_ev->header.value)
{
case 'c': emit_cpu_changed(emu); break;
default: break;
}
break;
default: break;
}
break;
case 'V':
switch(emu->cur_ev->header.class)
{
case 'S': pre_sched(emu); break;
case 'U': pre_submit(emu); break;
case 'M': pre_memory(emu); break;
default:
break;
}
break;
default:
break;
}
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan;
th = emu->cur_thread; th = emu->cur_thread;
if(th->show_ss == 0) chan_emit(&th->chan[CHAN_NOSV_SS]);
{
emit_thread_state(emu, th, PTT_SUBSYSTEM, ST_NULL);
return;
}
/* Only emit a state if needed */
if(th->ss_event != EV_NULL)
{
emit_thread_event(emu, th, PTT_SUBSYSTEM,
th->ss_event);
emit_cpu_event(emu, th, PTC_SUBSYSTEM,
th->ss_event);
return;
}
emit_thread_state(emu, th, PTT_SUBSYSTEM, ss_last_st(th));
emit_cpu_state(emu, th, PTC_SUBSYSTEM, ss_last_st(th));
} }
/* --------------------------- post ------------------------------- */ /* --------------------------- post ------------------------------- */
@ -393,5 +115,4 @@ hook_emit_nosv_ss(struct ovni_emu *emu)
void void
hook_post_nosv_ss(struct ovni_emu *emu) hook_post_nosv_ss(struct ovni_emu *emu)
{ {
emu->cur_thread->ss_event = EV_NULL;
} }

View File

@ -1,12 +1,35 @@
#include "ovni.h" #include "ovni.h"
#include "emu.h" #include "emu.h"
#include "prv.h" #include "prv.h"
#include "chan.h"
#include <assert.h> #include <assert.h>
/* The emulator ovni module provides the execution model by tracking the thread /* The emulator ovni module provides the execution model by tracking the thread
* state and which threads run in each CPU */ * state and which threads run in each CPU */
/* --------------------------- pre ------------------------------- */
static void
thread_set_channel_enabled(struct ovni_ethread *th, int enabled)
{
int i;
for(i=0; i<CHAN_MAX; i++)
chan_enable(&th->chan[i], enabled);
}
static void
thread_set_state(struct ovni_ethread *th, int state)
{
int enabled;
th->state = state;
enabled = (state == TH_ST_RUNNING ? 1 : 0);
thread_set_channel_enabled(th, enabled);
}
void void
update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu) update_cpu(struct ovni_emu *emu, struct ovni_cpu *cpu)
{ {
@ -88,7 +111,6 @@ emu_cpu_remove_thread(struct ovni_emu *emu, struct ovni_cpu *cpu, struct ovni_et
update_cpu(emu, cpu); update_cpu(emu, cpu);
} }
static void static void
print_threads_state(struct ovni_loom *loom) print_threads_state(struct ovni_loom *loom)
{ {
@ -116,61 +138,64 @@ print_threads_state(struct ovni_loom *loom)
} }
static void static void
ev_thread_execute(struct ovni_emu *emu) pre_thread_execute(struct ovni_emu *emu)
{ {
struct ovni_cpu *cpu; struct ovni_cpu *cpu;
struct ovni_ethread *th;
int cpuid; int cpuid;
th = emu->cur_thread;
/* The thread cannot be already running */ /* The thread cannot be already running */
assert(emu->cur_thread->state != TH_ST_RUNNING); assert(th->state != TH_ST_RUNNING);
cpuid = emu->cur_ev->payload.i32[0]; cpuid = emu->cur_ev->payload.i32[0];
//dbg("thread %d runs in cpuid %d\n", emu->cur_thread->tid, //dbg("thread %d runs in cpuid %d\n", th->tid,
// cpuid); // cpuid);
cpu = emu_get_cpu(emu->cur_loom, cpuid); cpu = emu_get_cpu(emu->cur_loom, cpuid);
emu->cur_thread->state = TH_ST_RUNNING; thread_set_state(th, TH_ST_RUNNING);
emu->cur_thread->cpu = cpu; th->cpu = cpu;
emu_cpu_add_thread(emu, cpu, emu->cur_thread); emu_cpu_add_thread(emu, cpu, th);
} }
static void static void
ev_thread_end(struct ovni_emu *emu) pre_thread_end(struct ovni_emu *emu)
{ {
assert(emu->cur_thread->state == TH_ST_RUNNING); assert(emu->cur_thread->state == TH_ST_RUNNING);
assert(emu->cur_thread->cpu); assert(emu->cur_thread->cpu);
emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
emu->cur_thread->state = TH_ST_DEAD; thread_set_state(emu->cur_thread, TH_ST_DEAD);
emu->cur_thread->cpu = NULL; emu->cur_thread->cpu = NULL;
} }
static void static void
ev_thread_pause(struct ovni_emu *emu) pre_thread_pause(struct ovni_emu *emu)
{ {
assert(emu->cur_thread->state == TH_ST_RUNNING); assert(emu->cur_thread->state == TH_ST_RUNNING);
assert(emu->cur_thread->cpu); assert(emu->cur_thread->cpu);
emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu_cpu_remove_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
emu->cur_thread->state = TH_ST_PAUSED; thread_set_state(emu->cur_thread, TH_ST_PAUSED);
} }
static void static void
ev_thread_resume(struct ovni_emu *emu) pre_thread_resume(struct ovni_emu *emu)
{ {
assert(emu->cur_thread->state == TH_ST_PAUSED); assert(emu->cur_thread->state == TH_ST_PAUSED);
assert(emu->cur_thread->cpu); assert(emu->cur_thread->cpu);
emu_cpu_add_thread(emu, emu->cur_thread->cpu, emu->cur_thread); emu_cpu_add_thread(emu, emu->cur_thread->cpu, emu->cur_thread);
emu->cur_thread->state = TH_ST_RUNNING; thread_set_state(emu->cur_thread, TH_ST_RUNNING);
} }
static void static void
ev_thread(struct ovni_emu *emu) pre_thread(struct ovni_emu *emu)
{ {
struct ovni_ev *ev; struct ovni_ev *ev;
struct ovni_cpu *cpu; struct ovni_cpu *cpu;
@ -193,27 +218,19 @@ ev_thread(struct ovni_emu *emu)
ev->payload.u32[2]); ev->payload.u32[2]);
break; break;
case 'x': ev_thread_execute(emu); break; case 'x': pre_thread_execute(emu); break;
case 'e': ev_thread_end(emu); break; case 'e': pre_thread_end(emu); break;
case 'p': ev_thread_pause(emu); break; case 'p': pre_thread_pause(emu); break;
case 'r': ev_thread_resume(emu); break; case 'r': pre_thread_resume(emu); break;
default: default:
err("unknown thread event value %c\n", err("unknown thread event value %c\n",
ev->header.value); ev->header.value);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* All but create events change the thread and CPU state: inject two
* virtual events to notify other modules. The order is important. */
if(ev->header.value != 'c')
{
emu_virtual_ev(emu, "*Hc");
emu_virtual_ev(emu, "*Cc");
}
} }
static void static void
ev_affinity_set(struct ovni_emu *emu) pre_affinity_set(struct ovni_emu *emu)
{ {
int cpuid; int cpuid;
struct ovni_cpu *newcpu; struct ovni_cpu *newcpu;
@ -235,7 +252,7 @@ ev_affinity_set(struct ovni_emu *emu)
} }
static void static void
ev_affinity_remote(struct ovni_emu *emu) pre_affinity_remote(struct ovni_emu *emu)
{ {
int cpuid, tid; int cpuid, tid;
struct ovni_cpu *newcpu; struct ovni_cpu *newcpu;
@ -279,13 +296,13 @@ ev_affinity_remote(struct ovni_emu *emu)
} }
static void static void
ev_affinity(struct ovni_emu *emu) pre_affinity(struct ovni_emu *emu)
{ {
//emu_emit(emu); //emu_emit(emu);
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 's': ev_affinity_set(emu); break; case 's': pre_affinity_set(emu); break;
case 'r': ev_affinity_remote(emu); break; case 'r': pre_affinity_remote(emu); break;
default: default:
dbg("unknown affinity event value %c\n", dbg("unknown affinity event value %c\n",
emu->cur_ev->header.value); emu->cur_ev->header.value);
@ -303,8 +320,8 @@ hook_pre_ovni(struct ovni_emu *emu)
switch(emu->cur_ev->header.class) switch(emu->cur_ev->header.class)
{ {
case 'H': ev_thread(emu); break; case 'H': pre_thread(emu); break;
case 'A': ev_affinity(emu); break; case 'A': pre_affinity(emu); break;
case 'B': case 'B':
//dbg("burst %c\n", emu->cur_ev->header.value); //dbg("burst %c\n", emu->cur_ev->header.value);
break; break;
@ -317,21 +334,26 @@ hook_pre_ovni(struct ovni_emu *emu)
//print_threads_state(emu); //print_threads_state(emu);
} }
/* --------------------------- emit ------------------------------- */
static void static void
emit_thread_state(struct ovni_emu *emu) emit_thread_state(struct ovni_emu *emu)
{ {
int row, st, tid; int i, row;
struct ovni_ethread *th;
st = emu->cur_thread->state; th = emu->cur_thread;
row = emu->cur_thread->gindex + 1; row = th->gindex + 1;
tid = emu->cur_thread->tid;
prv_ev_thread(emu, row, PTT_THREAD_STATE, st); prv_ev_thread(emu, row, PTT_THREAD_STATE, th->state);
if(st == TH_ST_RUNNING) if(th->state == TH_ST_RUNNING)
prv_ev_thread(emu, row, PTT_THREAD_TID, tid); prv_ev_thread(emu, row, PTT_THREAD_TID, th->tid);
else else
prv_ev_thread(emu, row, PTT_THREAD_TID, 0); prv_ev_thread(emu, row, PTT_THREAD_TID, 0);
chan_set(&th->chan[CHAN_OVNI_TID], th->tid);
} }
static void static void
@ -390,6 +412,8 @@ emit_current_pid(struct ovni_emu *emu)
void void
hook_emit_ovni(struct ovni_emu *emu) hook_emit_ovni(struct ovni_emu *emu)
{ {
int i;
if(emu->cur_ev->header.model != 'O') if(emu->cur_ev->header.model != 'O')
return; return;
@ -405,8 +429,14 @@ hook_emit_ovni(struct ovni_emu *emu)
default: default:
break; break;
} }
/* Emit all enabled channels */
for(i=0; i<CHAN_MAX; i++)
chan_emit(&emu->cur_thread->chan[i]);
} }
/* --------------------------- post ------------------------------- */
/* Reset thread state */ /* Reset thread state */
static void static void
post_virtual_thread(struct ovni_emu *emu) post_virtual_thread(struct ovni_emu *emu)