Use one event per blocking type in Nanos6

This commit is contained in:
Rodrigo Arias 2022-09-01 17:02:02 +02:00
parent 5c45323354
commit ac1ae8e69d
18 changed files with 568 additions and 458 deletions

View File

@ -37,7 +37,7 @@ window_pixel_size 1
window_labels_to_draw 1 window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } } window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } } window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 40 window_filter_module evt_type 1 45
window_filter_module evt_type_label 1 "CPU: Context switches of the ACTIVE thread" window_filter_module evt_type_label 1 "CPU: Context switches of the ACTIVE thread"
window_synchronize 1 window_synchronize 1

View File

@ -37,7 +37,7 @@ window_pixel_size 1
window_labels_to_draw 1 window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } } window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } } window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 40 window_filter_module evt_type 1 45
window_filter_module evt_type_label 1 "Thread: Context switches of the CURRENT thread" window_filter_module evt_type_label 1 "Thread: Context switches of the CURRENT thread"
window_synchronize 1 window_synchronize 1

View File

@ -162,14 +162,20 @@ KCI Is back in the CPU due to a context switch
6Ha Attaches to Nanos6 as external thread 6Ha Attaches to Nanos6 as external thread
6HA Detaches from Nanos6 as external thread 6HA Detaches from Nanos6 as external thread
6s[ Begins to spawn a function via spawnFunction() 6F[ Begins to spawn a function via spawnFunction()
6s] Ends spawning a function 6F] Ends spawning a function
6Dr Begins the registration of a task's accesses 6Dr Begins the registration of a task's accesses
6DR Ends the registration of a task's accesses 6DR Ends the registration of a task's accesses
6Du Begins the unregistration of a task's accesses 6Du Begins the unregistration of a task's accesses
6DU Ends the unregistration of a task's accesses 6DU Ends the unregistration of a task's accesses
6Bu Begins to unblock the given task 6Bu Begins to unblock a task
6BU Ends unblocking the given task 6BU Ends unblocking a task
6Bb Begins to block the current task via blockCurrentTask()
6BB Ends blocking the current task via blockCurrentTask()
6Bw Enters taskWait()
6BW Exits taskWait()
6Bf Enters taskFor()
6BF Exits taskFor()
``` ```

View File

@ -53,6 +53,10 @@ task. It is only shown when the task is in the running state. This view
is specially useful to identify task in a distributed workload, which is specially useful to identify task in a distributed workload, which
spans several nodes. spans several nodes.
As the zero value in Paraver gets hidden, we use the rank+1 value
instead. Therefore the rank numeric value go from 1 to the number of
ranks (inclusive).
## Subsystem view ## Subsystem view
The subsystem view attempts to provide a general overview of what Nanos6 The subsystem view attempts to provide a general overview of what Nanos6
@ -95,7 +99,7 @@ Task subsystem
: The **Task** subsystem contains the code that controls the life cycle : The **Task** subsystem contains the code that controls the life cycle
of tasks. It contains the following sections: of tasks. It contains the following sections:
- **Running**: Executing the body of the task (user defined code). - **Body**: Executing the body of the task (user defined code).
- **Spawning function**: Spawning a function as task (it will be - **Spawning function**: Spawning a function as task (it will be
submitted to the scheduler for later execution). submitted to the scheduler for later execution).

75
emu.h
View File

@ -104,40 +104,30 @@ enum nodes_state {
* CTF implementation. */ * CTF implementation. */
enum nanos6_ss_state { enum nanos6_ss_state {
ST_NANOS6_NULL = 0, /* IDLE */ ST_NANOS6_NULL = 0, /* IDLE */
/* RUNTIME */ ST_NANOS6_TASK_BODY = 3, /* TASK */
ST_NANOS6_TASK_CREATING = 8, /* TASK_CREATE */
ST_NANOS6_TASK_SUBMIT = 10, /* TASK_SUBMIT */
ST_NANOS6_TASK_SPAWNING = 18, /* SPAWN_FUNCTION */
ST_NANOS6_SCHED_HUNGRY = 2, /* BUSY_WAIT */ ST_NANOS6_SCHED_HUNGRY = 2, /* BUSY_WAIT */
ST_NANOS6_TASK_RUNNING = 3, /* TASK */ ST_NANOS6_SCHED_ADDING = 6, /* SCHEDULER_ADD_TASK */
ST_NANOS6_SCHED_SERVING = 20, /* SCHEDULER_LOCK_SERVING */
ST_NANOS6_DEP_REG = 4, /* DEPENDENCY_REGISTER */ ST_NANOS6_DEP_REG = 4, /* DEPENDENCY_REGISTER */
ST_NANOS6_DEP_UNREG = 5, /* DEPENDENCY_UNREGISTER */ ST_NANOS6_DEP_UNREG = 5, /* DEPENDENCY_UNREGISTER */
ST_NANOS6_SCHED_SUBMITTING = 6, /* SCHEDULER_ADD_TASK */ ST_NANOS6_BLK_TASKWAIT = 12, /* TASK_WAIT */
/* SCHEDULER_GET_TASK */ ST_NANOS6_BLK_WAITFOR = 13, /* WAIT_FOR */
ST_NANOS6_CREATING = 8, /* TASK_CREATE */ ST_NANOS6_BLK_BLOCKING = 16, /* BLOCKING_API_BLOCK */
/* TASK_ARGS_INIT */ ST_NANOS6_BLK_UNBLOCKING = 17, /* BLOCKING_API_UNBLOCK */
ST_NANOS6_SUBMIT = 10, /* TASK_SUBMIT */
/* TASKFOR_INIT */
ST_NANOS6_TASKWAIT = 12, /* TASK_WAIT */
ST_NANOS6_WAITFOR = 13, /* WAIT_FOR */
/* LOCK */
/* UNLOCK */
ST_NANOS6_BLOCKING = 16, /* BLOCKING_API_BLOCK */
ST_NANOS6_UNBLOCKING = 17, /* BLOCKING_API_UNBLOCK */
ST_NANOS6_SPAWNING = 18, /* SPAWN_FUNCTION */
/* SCHEDULER_LOCK_ENTER */
ST_NANOS6_SCHED_SERVING = 20, /* SCHEDULER_LOCK_SERVING */
ST_NANOS6_ATTACHED,
EV_NANOS6_SCHED_RECV, EV_NANOS6_SCHED_RECV = 50,
EV_NANOS6_SCHED_SEND, EV_NANOS6_SCHED_SEND = 51,
EV_NANOS6_SCHED_SELF, EV_NANOS6_SCHED_SELF = 52,
}; };
/* Possible reasons for Nanos6 tasks becoming running or not running */ enum nanos6_thread_state {
enum nanos6_task_run_reason ST_NANOS6_TH_EXTERNAL = 1,
{ ST_NANOS6_TH_WORKER,
TB_EXEC_OR_END = -1, ST_NANOS6_TH_LEADER,
TB_BLOCKING_API = 0, ST_NANOS6_TH_MAIN
TB_TASKWAIT = 1,
TB_WAITFOR = 2
}; };
enum kernel_cs_state { enum kernel_cs_state {
@ -169,6 +159,20 @@ struct task {
struct task *prev; struct task *prev;
}; };
struct task_info {
/* Both hash maps of all known tasks and types */
struct task_type *types;
struct task *tasks;
};
struct task_stack {
union {
struct task *top; /* Synctactic sugar */
struct task *tasks;
};
struct ovni_ethread *thread;
};
#define MAX_CHAN_STACK 128 #define MAX_CHAN_STACK 128
enum chan_track { enum chan_track {
@ -207,6 +211,7 @@ enum chan {
CHAN_NANOS6_TYPE, CHAN_NANOS6_TYPE,
CHAN_NANOS6_SUBSYSTEM, CHAN_NANOS6_SUBSYSTEM,
CHAN_NANOS6_RANK, CHAN_NANOS6_RANK,
CHAN_NANOS6_THREAD,
CHAN_KERNEL_CS, CHAN_KERNEL_CS,
@ -249,7 +254,8 @@ static const int chan_to_prvtype[CHAN_MAX] = {
[CHAN_NANOS6_TYPE] = 36, [CHAN_NANOS6_TYPE] = 36,
[CHAN_NANOS6_SUBSYSTEM] = 37, [CHAN_NANOS6_SUBSYSTEM] = 37,
[CHAN_NANOS6_RANK] = 38, [CHAN_NANOS6_RANK] = 38,
[CHAN_KERNEL_CS] = 40, [CHAN_NANOS6_THREAD] = 39,
[CHAN_KERNEL_CS] = 45,
}; };
struct ovni_chan { struct ovni_chan {
@ -335,8 +341,8 @@ struct ovni_ethread {
* structures */ * structures */
/* Task stacks, top ones are the tasks currently runnable. */ /* Task stacks, top ones are the tasks currently runnable. */
struct task *nosv_task_stack; struct task_stack nosv_task_stack;
struct task *nanos6_task_stack; struct task_stack nanos6_task_stack;
/* 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];
@ -376,11 +382,8 @@ struct ovni_eproc {
/* ------ Subsystem specific data --------*/ /* ------ Subsystem specific data --------*/
/* TODO: Use dynamic allocation */ /* TODO: Use dynamic allocation */
struct task_type *nosv_types; struct task_info nosv_task_info;
struct task *nosv_tasks; struct task_info nanos6_task_info;
struct task_type *nanos6_types;
struct task *nanos6_tasks;
}; };

View File

@ -30,7 +30,6 @@ hook_init_nanos6(struct ovni_emu *emu)
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_cpu *cpu; struct ovni_cpu *cpu;
struct ovni_chan **uth, **ucpu; struct ovni_chan **uth, **ucpu;
size_t i;
int row; int row;
FILE *prv_th, *prv_cpu; FILE *prv_th, *prv_cpu;
int64_t *clock; int64_t *clock;
@ -40,7 +39,7 @@ hook_init_nanos6(struct ovni_emu *emu)
prv_cpu = emu->prv_cpu; prv_cpu = emu->prv_cpu;
/* Init the channels in all threads */ /* Init the channels in all threads */
for(i=0; i<emu->total_nthreads; i++) for(size_t i=0; i<emu->total_nthreads; i++)
{ {
th = emu->global_thread[i]; th = emu->global_thread[i];
row = th->gindex + 1; row = th->gindex + 1;
@ -51,10 +50,11 @@ hook_init_nanos6(struct ovni_emu *emu)
chan_th_init(th, uth, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_ACTIVE, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_ACTIVE, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NANOS6_THREAD, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
} }
/* Init the Nanos6 channels in all cpus */ /* Init the Nanos6 channels in all cpus */
for(i=0; i<emu->total_ncpus; i++) for(size_t i=0; i<emu->total_ncpus; i++)
{ {
cpu = emu->global_cpu[i]; cpu = emu->global_cpu[i];
row = cpu->gindex + 1; row = cpu->gindex + 1;
@ -64,46 +64,38 @@ hook_init_nanos6(struct ovni_emu *emu)
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NANOS6_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NANOS6_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NANOS6_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NANOS6_THREAD, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
}
/* Init task stack */
for(size_t i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
th->nanos6_task_stack.thread = th;
} }
} }
/* --------------------------- pre ------------------------------- */ /* --------------------------- pre ------------------------------- */
static void static void
task_not_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reason reason) chan_task_stopped(struct ovni_emu *emu, char tr)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
th = emu->cur_thread; th = emu->cur_thread;
if(task->state == TASK_ST_RUNNING)
die("task is still running\n");
chan_set(&th->chan[CHAN_NANOS6_TASKID], 0); chan_set(&th->chan[CHAN_NANOS6_TASKID], 0);
chan_set(&th->chan[CHAN_NANOS6_TYPE], 0); chan_set(&th->chan[CHAN_NANOS6_TYPE], 0);
if(emu->cur_loom->rank_enabled) if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NANOS6_RANK], 0); chan_set(&th->chan[CHAN_NANOS6_RANK], 0);
// Check the reason /* Only exit the task body when finishing */
switch (reason) if(tr == 'e')
{ chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY);
case TB_EXEC_OR_END:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_RUNNING);
break;
case TB_BLOCKING_API:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_BLOCKING);
break;
case TB_TASKWAIT:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASKWAIT);
break;
case TB_WAITFOR:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_WAITFOR);
break;
}
} }
static void static void
task_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reason reason) chan_task_running(struct ovni_emu *emu, struct task *task, char tr)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_eproc *proc; struct ovni_eproc *proc;
@ -126,65 +118,150 @@ task_running(struct ovni_emu *emu, struct task *task, enum nanos6_task_run_reaso
if(emu->cur_loom->rank_enabled) if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NANOS6_RANK], proc->rank + 1); chan_set(&th->chan[CHAN_NANOS6_RANK], proc->rank + 1);
// Check the reason /* Only enter the body of the task when we begin the execution */
switch (reason) if(tr == 'x')
{ chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY);
case TB_EXEC_OR_END:
chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_RUNNING);
break;
case TB_BLOCKING_API:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_BLOCKING);
break;
case TB_TASKWAIT:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASKWAIT);
break;
case TB_WAITFOR:
chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_WAITFOR);
break;
}
} }
static void static void
task_switch(struct ovni_emu *emu, struct task *prev_task, chan_task_switch(struct ovni_emu *emu,
struct task *next_task, int newtask) struct task *prev, struct task *next)
{ {
struct ovni_ethread *th; struct ovni_ethread *th = emu->cur_thread;
th = emu->cur_thread; if(!prev || !next)
if(!prev_task || !next_task)
die("cannot switch to or from a NULL task\n"); die("cannot switch to or from a NULL task\n");
if(prev_task == next_task) if(prev == next)
die("cannot switch to the same task\n"); die("cannot switch to the same task\n");
if(newtask && prev_task->state != TASK_ST_RUNNING) if(next->id == 0)
die("previous task must not be no longer running\n");
if(!newtask && prev_task->state != TASK_ST_DEAD)
die("previous task must be dead\n");
if(next_task->state != TASK_ST_RUNNING)
die("next task must be running\n");
if(next_task->id == 0)
die("next task id cannot be 0\n"); die("next task id cannot be 0\n");
if(next_task->type->gid == 0) if(next->type->gid == 0)
die("next task type id cannot be 0\n"); die("next task type id cannot be 0\n");
if(prev_task->thread != next_task->thread) if(prev->thread != next->thread)
die("cannot switch to a task of another thread\n"); die("cannot switch to a task of another thread\n");
/* No need to change the rank as we will switch to tasks from same stack */ /* No need to change the rank as we will switch to tasks from
chan_set(&th->chan[CHAN_NANOS6_TASKID], next_task->id); * same thread */
chan_set(&th->chan[CHAN_NANOS6_TASKID], next->id);
/* FIXME: We should emit a PRV event even if we are switching to /* FIXME: We should emit a PRV event even if we are switching to
* the same type event, to mark the end of the current task. For * the same type event, to mark the end of the current task. For
* now we only emit a new type if we switch to a type with a * now we only emit a new type if we switch to a type with a
* different gid. */ * different gid. */
if(prev_task->type->gid != next_task->type->gid) if(prev->type->gid != next->type->gid)
chan_set(&th->chan[CHAN_NANOS6_TYPE], next_task->type->gid); chan_set(&th->chan[CHAN_NANOS6_TYPE], next->type->gid);
}
static void
update_task_state(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) < 4)
die("missing task id in payload\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
struct ovni_ethread *th = emu->cur_thread;
struct ovni_eproc *proc = emu->cur_proc;
struct task_info *info = &proc->nanos6_task_info;
struct task_stack *stack = &th->nanos6_task_stack;
struct task *task = task_find(info->tasks, task_id);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
switch(emu->cur_ev->header.value)
{
case 'x': task_execute(stack, task); break;
case 'e': task_end(stack, task); break;
case 'p': task_pause(stack, task); break;
case 'r': task_resume(stack, task); break;
default:
die("unexpected Nanos6 task event value %c\n",
emu->cur_ev->header.value);
}
}
static char
expand_transition_value(struct ovni_emu *emu, int was_running, int runs_now)
{
char tr = emu->cur_ev->header.value;
/* Ensure we don't clobber the value */
if(tr == 'X' || tr == 'E')
die("unexpected event value %c\n", tr);
/* Modify the event value to detect nested transitions */
if(tr == 'x' && was_running)
tr = 'X'; /* Execute a new nested task */
else if(tr == 'e' && runs_now)
tr = 'E'; /* End a nested task */
return tr;
}
static void
update_task_channels(struct ovni_emu *emu,
char tr, struct task *prev, struct task *next)
{
switch(tr)
{
case 'x':
case 'r':
chan_task_running(emu, next, tr);
break;
case 'e':
case 'p':
chan_task_stopped(emu, tr);
break;
/* Additional nested transitions */
case 'X':
case 'E':
chan_task_switch(emu, prev, next);
break;
default:
die("unexpected transition value %c\n", tr);
}
}
static void
update_task(struct ovni_emu *emu)
{
struct ovni_ethread *th = emu->cur_thread;
struct task_stack *stack = &th->nanos6_task_stack;
struct task *prev = task_get_running(stack);
/* Update the emulator state, but don't modify the channels */
update_task_state(emu);
struct task *next = task_get_running(stack);
int was_running = (prev != NULL);
int runs_now = (next != NULL);
char tr = expand_transition_value(emu, was_running, runs_now);
/* Update the channels now */
update_task_channels(emu, tr, prev, next);
}
static void
create_task(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) != 8)
die("cannot create task: unexpected payload size\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
uint32_t type_id = emu->cur_ev->payload.u32[1];
struct task_info *info = &emu->cur_proc->nanos6_task_info;
task_create(info, type_id, task_id);
} }
static void static void
@ -192,87 +269,53 @@ pre_task(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan_th; struct ovni_chan *chan_th;
struct task **task_map = &emu->cur_proc->nanos6_tasks;
struct task_type **type_map = &emu->cur_proc->nanos6_types;
struct task **task_stack = &emu->cur_thread->nanos6_task_stack;
struct task *prev_running = task_get_running(*task_stack);
int was_running_task = (prev_running != NULL);
th = emu->cur_thread; th = emu->cur_thread;
chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM]; chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM];
/* Update the emulator state, but don't modify the channels yet */
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'c': task_create(emu->cur_ev->payload.i32[0], emu->cur_ev->payload.i32[1], task_map, type_map); break; /* We use the 'c' event to create the task and switch
case 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; * the subsystem all in one step because the timing here
case 'e': task_end(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; * is critical. */
case 'b': task_pause(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; case 'c':
case 'u': task_resume(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; chan_push(chan_th, ST_NANOS6_TASK_CREATING);
case 'C': break; create_task(emu);
default:
abort();
}
struct task *next_running = task_get_running(*task_stack);
int runs_task_now = (next_running != NULL);
/* Now that we know if the emulator was running a task before
* or if it's running one now, update the channels accordingly. */
switch(emu->cur_ev->header.value)
{
case 'x': /* Execute: either a nested task or a new one */
if(was_running_task)
task_switch(emu, prev_running, next_running, 1);
else
task_running(emu, next_running, TB_EXEC_OR_END);
break; break;
case 'e': /* End: either a nested task or the last one */ case 'C':
if(runs_task_now) chan_pop(chan_th, ST_NANOS6_TASK_CREATING);
task_switch(emu, prev_running, next_running, 0);
else
task_not_running(emu, prev_running, TB_EXEC_OR_END);
break; break;
case 'b': /* Block */ case 'x':
task_not_running(emu, prev_running, emu->cur_ev->payload.i32[1]); case 'e':
break; case 'r':
case 'u': /* Unblock */ case 'p': /* Wet floor */
task_running(emu, next_running, emu->cur_ev->payload.i32[1]); update_task(emu);
break;
case 'c': /* Create */
chan_push(chan_th, ST_NANOS6_CREATING);
break;
case 'C': /* Create end */
chan_pop(chan_th, ST_NANOS6_CREATING);
break; break;
default: default:
break; die("unexpected event value %c\n",
emu->cur_ev->header.value);
} }
} }
static void static void
pre_type(struct ovni_emu *emu) pre_type(struct ovni_emu *emu)
{ {
uint8_t *data; if(emu->cur_ev->header.value != 'c')
die("unexpected event value %c\n",
emu->cur_ev->header.value);
switch(emu->cur_ev->header.value) if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{ die("expecting a jumbo event\n");
case 'c':
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{
err("expecting a jumbo event\n");
abort();
}
data = &emu->cur_ev->payload.jumbo.data[0]; uint8_t *data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t *typeid = (uint32_t *) data; uint32_t typeid = *(uint32_t *) data;
data += sizeof(*typeid); data += 4;
const char *label = (const char *) data;
task_type_create(*typeid, label, &emu->cur_proc->nanos6_types); const char *label = (const char *) data;
break;
default: struct ovni_eproc *proc = emu->cur_proc;
break;
} task_type_create(&proc->nanos6_task_info, typeid, label);
} }
static void static void
@ -287,9 +330,9 @@ pre_deps(struct ovni_emu *emu)
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'r': chan_push(chan_th, ST_NANOS6_DEP_REG); break; case 'r': chan_push(chan_th, ST_NANOS6_DEP_REG); break;
case 'R': chan_pop(chan_th, ST_NANOS6_DEP_REG); break; case 'R': chan_pop (chan_th, ST_NANOS6_DEP_REG); break;
case 'u': chan_push(chan_th, ST_NANOS6_DEP_UNREG); break; case 'u': chan_push(chan_th, ST_NANOS6_DEP_UNREG); break;
case 'U': chan_pop(chan_th, ST_NANOS6_DEP_UNREG); break; case 'U': chan_pop (chan_th, ST_NANOS6_DEP_UNREG); break;
default: break; default: break;
} }
} }
@ -305,8 +348,14 @@ pre_blocking(struct ovni_emu *emu)
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'u': chan_push(chan_th, ST_NANOS6_UNBLOCKING); break; case 'b': chan_push(chan_th, ST_NANOS6_BLK_BLOCKING); break;
case 'U': chan_pop(chan_th, ST_NANOS6_UNBLOCKING); break; case 'B': chan_pop (chan_th, ST_NANOS6_BLK_BLOCKING); break;
case 'u': chan_push(chan_th, ST_NANOS6_BLK_UNBLOCKING); break;
case 'U': chan_pop (chan_th, ST_NANOS6_BLK_UNBLOCKING); break;
case 'w': chan_push(chan_th, ST_NANOS6_BLK_TASKWAIT); break;
case 'W': chan_pop (chan_th, ST_NANOS6_BLK_TASKWAIT); break;
case 'f': chan_push(chan_th, ST_NANOS6_BLK_WAITFOR); break;
case 'F': chan_pop (chan_th, ST_NANOS6_BLK_WAITFOR); break;
default: break; default: break;
} }
} }
@ -334,20 +383,24 @@ pre_sched(struct ovni_emu *emu)
} }
static void static void
pre_thread_type(struct ovni_emu *emu) pre_thread(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_chan *chan_th; struct ovni_chan *chan_th;
th = emu->cur_thread; th = emu->cur_thread;
chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM]; chan_th = &th->chan[CHAN_NANOS6_THREAD];
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'a': chan_push(chan_th, ST_NANOS6_ATTACHED); break; case 'e': chan_push(chan_th, ST_NANOS6_TH_EXTERNAL); break;
case 'A': chan_pop (chan_th, ST_NANOS6_ATTACHED); break; case 'E': chan_pop (chan_th, ST_NANOS6_TH_EXTERNAL); break;
case 's': chan_push(chan_th, ST_NANOS6_SPAWNING); break; case 'w': chan_push(chan_th, ST_NANOS6_TH_WORKER); break;
case 'S': chan_pop (chan_th, ST_NANOS6_SPAWNING); break; case 'W': chan_pop (chan_th, ST_NANOS6_TH_WORKER); break;
case 'l': chan_push(chan_th, ST_NANOS6_TH_LEADER); break;
case 'L': chan_pop (chan_th, ST_NANOS6_TH_LEADER); break;
case 'm': chan_push(chan_th, ST_NANOS6_TH_MAIN); break;
case 'M': chan_pop (chan_th, ST_NANOS6_TH_MAIN); break;
default: break; default: break;
} }
} }
@ -406,8 +459,8 @@ hook_pre_nanos6(struct ovni_emu *emu)
case 'T': pre_task(emu); break; case 'T': pre_task(emu); break;
case 'Y': pre_type(emu); break; case 'Y': pre_type(emu); break;
case 'S': pre_sched(emu); break; case 'S': pre_sched(emu); break;
case 'U': pre_ss(emu, ST_NANOS6_SUBMIT); break; case 'U': pre_ss(emu, ST_NANOS6_TASK_SUBMIT); break;
case 'H': pre_thread_type(emu); break; case 'H': pre_thread(emu); break;
case 'D': pre_deps(emu); break; case 'D': pre_deps(emu); break;
case 'B': pre_blocking(emu); break; case 'B': pre_blocking(emu); break;
default: default:
@ -417,27 +470,6 @@ hook_pre_nanos6(struct ovni_emu *emu)
check_affinity(emu); check_affinity(emu);
} }
char *nanos6_ss_names[] = {
[ST_NANOS6_NULL] = "ST_NANOS6_NULL",
[ST_NANOS6_SCHED_HUNGRY] = "ST_NANOS6_SCHED_HUNGRY",
[ST_NANOS6_TASK_RUNNING] = "ST_NANOS6_TASK_RUNNING",
[ST_NANOS6_DEP_REG] = "ST_NANOS6_DEP_REG",
[ST_NANOS6_DEP_UNREG] = "ST_NANOS6_DEP_UNREG",
[ST_NANOS6_SCHED_SUBMITTING] = "ST_NANOS6_SCHED_SUBMITTING",
[ST_NANOS6_CREATING] = "ST_NANOS6_CREATING",
[ST_NANOS6_SUBMIT] = "ST_NANOS6_SUBMIT",
[ST_NANOS6_TASKWAIT] = "ST_NANOS6_TASKWAIT",
[ST_NANOS6_WAITFOR] = "ST_NANOS6_WAITFOR",
[ST_NANOS6_BLOCKING] = "ST_NANOS6_BLOCKING",
[ST_NANOS6_UNBLOCKING] = "ST_NANOS6_UNBLOCKING",
[ST_NANOS6_SPAWNING] = "ST_NANOS6_SPAWNING",
[ST_NANOS6_SCHED_SERVING] = "ST_NANOS6_SCHED_SERVING",
[ST_NANOS6_ATTACHED] = "ST_NANOS6_ATTACHED",
[EV_NANOS6_SCHED_RECV] = "EV_NANOS6_SCHED_RECV",
[EV_NANOS6_SCHED_SEND] = "EV_NANOS6_SCHED_SEND",
[EV_NANOS6_SCHED_SELF] = "EV_NANOS6_SCHED_SELF",
};
static void static void
end_lint(struct ovni_emu *emu) end_lint(struct ovni_emu *emu)
{ {
@ -449,8 +481,19 @@ end_lint(struct ovni_emu *emu)
if(ch->n != 1) if(ch->n != 1)
{ {
int top = ch->stack[ch->n - 1]; int top = ch->stack[ch->n - 1];
char *name = nanos6_ss_names[top];
die("thread %d ended with %d extra stacked nanos6 subsystems, top=%s\n", struct pcf_value_label *pv;
char *name = "(unknown)";
for(pv = &nanos6_ss_values[0]; pv->label; pv++)
{
if(pv->value == top)
{
name = pv->label;
break;
}
}
die("thread %d ended with %d extra stacked nanos6 subsystems, top=\"%s\"\n",
th->tid, ch->n - 1, name); th->tid, ch->n - 1, name);
} }
} }
@ -472,7 +515,7 @@ hook_end_nanos6(struct ovni_emu *emu)
for(size_t j = 0; j < loom->nprocs; j++) for(size_t j = 0; j < loom->nprocs; j++)
{ {
struct ovni_eproc *proc = &loom->proc[j]; struct ovni_eproc *proc = &loom->proc[j];
task_create_pcf_types(pcftype, proc->nanos6_types); task_create_pcf_types(pcftype, proc->nanos6_task_info.types);
} }
} }
} }

View File

@ -74,18 +74,21 @@ hook_init_nosv(struct ovni_emu *emu)
chan_cpu_init(cpu, ucpu, CHAN_NOSV_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NOSV_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NOSV_SUBSYSTEM, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
} }
/* Init task stack */
for(i=0; i<emu->total_nthreads; i++)
{
th = emu->global_thread[i];
th->nosv_task_stack.thread = th;
}
} }
/* --------------------------- pre ------------------------------- */ /* --------------------------- pre ------------------------------- */
static void static void
task_not_running(struct ovni_emu *emu, struct task *task) chan_task_stopped(struct ovni_emu *emu)
{ {
struct ovni_ethread *th; struct ovni_ethread *th = emu->cur_thread;
th = emu->cur_thread;
if(task->state == TASK_ST_RUNNING)
die("task is still running\n");
chan_set(&th->chan[CHAN_NOSV_TASKID], 0); chan_set(&th->chan[CHAN_NOSV_TASKID], 0);
chan_set(&th->chan[CHAN_NOSV_TYPE], 0); chan_set(&th->chan[CHAN_NOSV_TYPE], 0);
@ -94,11 +97,12 @@ task_not_running(struct ovni_emu *emu, struct task *task)
if(emu->cur_loom->rank_enabled) if(emu->cur_loom->rank_enabled)
chan_set(&th->chan[CHAN_NOSV_RANK], 0); chan_set(&th->chan[CHAN_NOSV_RANK], 0);
/* XXX: Do we need this transition? */
chan_pop(&th->chan[CHAN_NOSV_SUBSYSTEM], ST_NOSV_TASK_RUNNING); chan_pop(&th->chan[CHAN_NOSV_SUBSYSTEM], ST_NOSV_TASK_RUNNING);
} }
static void static void
task_running(struct ovni_emu *emu, struct task *task) chan_task_running(struct ovni_emu *emu, struct task *task)
{ {
struct ovni_ethread *th; struct ovni_ethread *th;
struct ovni_eproc *proc; struct ovni_eproc *proc;
@ -126,123 +130,179 @@ task_running(struct ovni_emu *emu, struct task *task)
} }
static void static void
task_switch(struct ovni_emu *emu, struct task *prev_task, chan_task_switch(struct ovni_emu *emu,
struct task *next_task, int newtask) struct task *prev, struct task *next)
{ {
struct ovni_ethread *th; struct ovni_ethread *th = emu->cur_thread;
th = emu->cur_thread; if(!prev || !next)
if(!prev_task || !next_task)
die("cannot switch to or from a NULL task\n"); die("cannot switch to or from a NULL task\n");
if(prev_task == next_task) if(prev == next)
die("cannot switch to the same task\n"); die("cannot switch to the same task\n");
if(newtask && prev_task->state != TASK_ST_RUNNING) if(next->id == 0)
die("previous task must not be no longer running\n");
if(!newtask && prev_task->state != TASK_ST_DEAD)
die("previous task must be dead\n");
if(next_task->state != TASK_ST_RUNNING)
die("next task must be running\n");
if(next_task->id == 0)
die("next task id cannot be 0\n"); die("next task id cannot be 0\n");
if(next_task->type->gid == 0) if(next->type->gid == 0)
die("next task type id cannot be 0\n"); die("next task type id cannot be 0\n");
if(prev_task->thread != next_task->thread) if(prev->thread != next->thread)
die("cannot switch to a task of another thread\n"); die("cannot switch to a task of another thread\n");
/* No need to change the rank or app ID, as we can only switch /* No need to change the rank or app ID, as we can only switch
* to tasks of the same thread */ * to tasks of the same thread */
chan_set(&th->chan[CHAN_NOSV_TASKID], next_task->id); chan_set(&th->chan[CHAN_NOSV_TASKID], next->id);
/* FIXME: We should emit a PRV event even if we are switching to /* FIXME: We should emit a PRV event even if we are switching to
* the same type event, to mark the end of the current task. For * the same type event, to mark the end of the current task. For
* now we only emit a new type if we switch to a type with a * now we only emit a new type if we switch to a type with a
* different gid. */ * different gid. */
if(prev_task->type->gid != next_task->type->gid) if(prev->type->gid != next->type->gid)
chan_set(&th->chan[CHAN_NOSV_TYPE], next_task->type->gid); chan_set(&th->chan[CHAN_NOSV_TYPE], next->type->gid);
}
static void
update_task_state(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) < 4)
die("missing task id in payload\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
struct ovni_ethread *th = emu->cur_thread;
struct ovni_eproc *proc = emu->cur_proc;
struct task_info *info = &proc->nosv_task_info;
struct task_stack *stack = &th->nosv_task_stack;
struct task *task = task_find(info->tasks, task_id);
if(task == NULL)
die("cannot find task with id %u\n", task_id);
switch(emu->cur_ev->header.value)
{
case 'x': task_execute(stack, task); break;
case 'e': task_end(stack, task); break;
case 'p': task_pause(stack, task); break;
case 'r': task_resume(stack, task); break;
default:
die("unexpected Nanos6 task event value %c\n",
emu->cur_ev->header.value);
}
}
static char
expand_transition_value(struct ovni_emu *emu, int was_running, int runs_now)
{
char tr = emu->cur_ev->header.value;
/* Ensure we don't clobber the value */
if(tr == 'X' || tr == 'E')
die("unexpected event value %c\n", tr);
/* Modify the event value to detect nested transitions */
if(tr == 'x' && was_running)
tr = 'X'; /* Execute a new nested task */
else if(tr == 'e' && runs_now)
tr = 'E'; /* End a nested task */
return tr;
}
static void
update_task_channels(struct ovni_emu *emu,
char tr, struct task *prev, struct task *next)
{
switch(tr)
{
case 'x': chan_task_running(emu, next); break;
case 'r': chan_task_running(emu, next); break;
case 'e': chan_task_stopped(emu); break;
case 'p': chan_task_stopped(emu); break;
/* Additional nested transitions */
case 'X': chan_task_switch(emu, prev, next); break;
case 'E': chan_task_switch(emu, prev, next); break;
default:
die("unexpected transition value %c\n", tr);
}
}
static void
update_task(struct ovni_emu *emu)
{
struct ovni_ethread *th = emu->cur_thread;
struct task_stack *stack = &th->nosv_task_stack;
struct task *prev = task_get_running(stack);
/* Update the emulator state, but don't modify the channels */
update_task_state(emu);
struct task *next = task_get_running(stack);
int was_running = (prev != NULL);
int runs_now = (next != NULL);
char tr = expand_transition_value(emu, was_running, runs_now);
/* Update the channels now */
update_task_channels(emu, tr, prev, next);
}
static void
create_task(struct ovni_emu *emu)
{
if(ovni_payload_size(emu->cur_ev) != 8)
die("cannot create task: unexpected payload size\n");
uint32_t task_id = emu->cur_ev->payload.u32[0];
uint32_t type_id = emu->cur_ev->payload.u32[1];
struct task_info *info = &emu->cur_proc->nosv_task_info;
task_create(info, type_id, task_id);
} }
static void static void
pre_task(struct ovni_emu *emu) pre_task(struct ovni_emu *emu)
{ {
struct task **task_map = &emu->cur_proc->nosv_tasks;
struct task_type **type_map = &emu->cur_proc->nosv_types;
struct task **task_stack = &emu->cur_thread->nosv_task_stack;
struct task *prev_running = task_get_running(*task_stack);
int was_running_task = (prev_running != NULL);
/* Update the emulator state, but don't modify the channels yet */
switch(emu->cur_ev->header.value) switch(emu->cur_ev->header.value)
{ {
case 'c': task_create(emu->cur_ev->payload.i32[0], emu->cur_ev->payload.i32[1], task_map, type_map); break; case 'c':
case 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; create_task(emu);
case 'e': task_end(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'p': task_pause(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
case 'r': task_resume(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break;
default:
abort();
}
struct task *next_running = task_get_running(*task_stack);
int runs_task_now = (next_running != NULL);
/* Now that we know if the emulator was running a task before
* or if it's running one now, update the channels accordingly. */
switch(emu->cur_ev->header.value)
{
case 'x': /* Execute: either a nested task or a new one */
if(was_running_task)
task_switch(emu, prev_running, next_running, 1);
else
task_running(emu, next_running);
break; break;
case 'e': /* End: either a nested task or the last one */ case 'x':
if(runs_task_now) case 'e':
task_switch(emu, prev_running, next_running, 0); case 'r':
else case 'p': /* Wet floor */
task_not_running(emu, prev_running); update_task(emu);
break;
case 'p': /* Pause */
task_not_running(emu, prev_running);
break;
case 'r': /* Resume */
task_running(emu, next_running);
break; break;
default: default:
break; die("unexpected event value %c\n",
emu->cur_ev->header.value);
} }
} }
static void static void
pre_type(struct ovni_emu *emu) pre_type(struct ovni_emu *emu)
{ {
uint8_t *data; if(emu->cur_ev->header.value != 'c')
die("unexpected event value %c\n",
emu->cur_ev->header.value);
switch(emu->cur_ev->header.value) if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{ die("expecting a jumbo event\n");
case 'c':
if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0)
{
err("expecting a jumbo event\n");
abort();
}
data = &emu->cur_ev->payload.jumbo.data[0]; uint8_t *data = &emu->cur_ev->payload.jumbo.data[0];
uint32_t *typeid = (uint32_t *) data; uint32_t typeid = *(uint32_t *) data;
data += sizeof(*typeid); data += 4;
const char *label = (const char *) data;
task_type_create(*typeid, label, &emu->cur_proc->nosv_types); const char *label = (const char *) data;
break;
default: struct ovni_eproc *proc = emu->cur_proc;
break;
} task_type_create(&proc->nosv_task_info, typeid, label);
} }
static void static void
@ -437,7 +497,7 @@ hook_end_nosv(struct ovni_emu *emu)
for(size_t j = 0; j < loom->nprocs; j++) for(size_t j = 0; j < loom->nprocs; j++)
{ {
struct ovni_eproc *proc = &loom->proc[j]; struct ovni_eproc *proc = &loom->proc[j];
task_create_pcf_types(pcftype, proc->nosv_types); task_create_pcf_types(pcftype, proc->nosv_task_info.types);
} }
} }
} }

View File

@ -24,24 +24,39 @@
#include "prv.h" #include "prv.h"
#include "chan.h" #include "chan.h"
struct task *
task_find(struct task *tasks, uint32_t task_id)
{
struct task *task = NULL;
HASH_FIND_INT(tasks, &task_id, task);
return task;
}
struct task_type *
task_type_find(struct task_type *types, uint32_t type_id)
{
struct task_type *type = NULL;
HASH_FIND_INT(types, &type_id, type);
return type;
}
void void
task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct task_type **type_map) task_create(struct task_info *info,
uint32_t type_id, uint32_t task_id)
{ {
/* Ensure the task id is new */ /* Ensure the task id is new */
struct task *task = NULL; if(task_find(info->tasks, task_id) != NULL)
HASH_FIND_INT(*task_map, &task_id, task); die("cannot create task: task_id %u already exists\n",
task_id);
if(task != NULL)
die("cannot create a task with id %u: already exists\n", task_id);
/* Ensure the type exists */ /* Ensure the type exists */
struct task_type *type = NULL; struct task_type *type = task_type_find(info->types, type_id);
HASH_FIND_INT(*type_map, &type_id, type);
if(type == NULL) if(type == NULL)
die("cannot create task: unknown type id %u\n", type_id); die("cannot create task: unknown type id %u\n", type_id);
task = calloc(1, sizeof(*task)); struct task *task = calloc(1, sizeof(struct task));
if(task == NULL) if(task == NULL)
die("calloc failed\n"); die("calloc failed\n");
@ -52,64 +67,59 @@ task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct t
task->thread = NULL; task->thread = NULL;
/* Add the new task to the hash table */ /* Add the new task to the hash table */
HASH_ADD_INT(*task_map, id, task); HASH_ADD_INT(info->tasks, id, task);
dbg("new task created id=%d\n", task->id); dbg("new task created id=%d\n", task->id);
} }
void void
task_execute(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack) task_execute(struct task_stack *stack, struct task *task)
{ {
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %u\n", task_id); die("cannot execute: task is NULL\n");
if(task->state != TASK_ST_CREATED) if(task->state != TASK_ST_CREATED)
die("cannot execute task %u: state is not created\n", task_id); die("cannot execute task %u: state is not created\n", task->id);
if(task->thread != NULL) if(task->thread != NULL)
die("task already has a thread assigned\n"); die("task already has a thread assigned\n");
if(cur_thread->state != TH_ST_RUNNING) if(stack->thread->state != TH_ST_RUNNING)
die("thread state is not running\n"); die("thread state is not running\n");
if(top == task) if(stack->top == task)
die("thread already has assigned task %u\n", task_id); die("thread already has assigned task %u\n", task->id);
if(top && top->state != TASK_ST_RUNNING) if(stack->top && stack->top->state != TASK_ST_RUNNING)
die("cannot execute a nested task from a non-running task\n"); die("cannot execute a nested task from a non-running task\n");
task->state = TASK_ST_RUNNING; task->state = TASK_ST_RUNNING;
task->thread = cur_thread; task->thread = stack->thread;
DL_PREPEND(*thread_task_stack, task); DL_PREPEND(stack->tasks, task);
dbg("task id=%u runs now\n", task->id); dbg("task id=%u runs now\n", task->id);
} }
void void
task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack) task_pause(struct task_stack *stack, struct task *task)
{ {
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %u\n", task_id); die("cannot pause: task is NULL\n");
if(task->state != TASK_ST_RUNNING) if(task->state != TASK_ST_RUNNING)
die("task state is not running\n"); die("cannot pause: task state is not running\n");
if(cur_thread->state != TH_ST_RUNNING) if(task->thread == NULL)
die("thread state is not running\n"); die("cannot pause: task has no thread assigned\n");
if(top != task) if(stack->thread->state != TH_ST_RUNNING)
die("cannot pause: thread state is not running\n");
if(stack->top != task)
die("thread has assigned a different task\n"); die("thread has assigned a different task\n");
if(cur_thread != task->thread) if(stack->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; task->state = TASK_ST_PAUSED;
@ -118,25 +128,24 @@ task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task
} }
void void
task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack) task_resume(struct task_stack *stack, struct task *task)
{ {
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %u\n", task_id); die("cannot resume: task is NULL\n");
if(task->state != TASK_ST_PAUSED) if(task->state != TASK_ST_PAUSED)
die("task state is not paused\n"); die("task state is not paused\n");
if(cur_thread->state != TH_ST_RUNNING) if(task->thread == NULL)
die("cannot resume: task has no thread assigned\n");
if(stack->thread->state != TH_ST_RUNNING)
die("thread is not running\n"); die("thread is not running\n");
if(top != task) if(stack->top != task)
die("thread has assigned a different task\n"); die("thread has assigned a different task\n");
if(cur_thread != task->thread) if(stack->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; task->state = TASK_ST_RUNNING;
@ -145,25 +154,24 @@ task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **tas
} }
void void
task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack) task_end(struct task_stack *stack, struct task *task)
{ {
struct task *top = *thread_task_stack;
struct task *task = NULL;
HASH_FIND_INT(*task_map, &task_id, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %u\n", task_id); die("cannot end: task is NULL\n");
if(task->state != TASK_ST_RUNNING) if(task->state != TASK_ST_RUNNING)
die("task state is not running\n"); die("task state is not running\n");
if(cur_thread->state != TH_ST_RUNNING) if(task->thread == NULL)
die("thread is not running\n"); die("cannot end: task has no thread assigned\n");
if(top != task) if(stack->thread->state != TH_ST_RUNNING)
die("cannot end task: thread is not running\n");
if(stack->top != task)
die("thread has assigned a different task\n"); die("thread has assigned a different task\n");
if(cur_thread != task->thread) if(stack->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_DEAD; task->state = TASK_ST_DEAD;
@ -171,7 +179,7 @@ task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_m
/* Don't unset the thread from the task, as it will be used /* Don't unset the thread from the task, as it will be used
* later to ensure we switch to tasks of the same thread. */ * later to ensure we switch to tasks of the same thread. */
DL_DELETE(*thread_task_stack, task); DL_DELETE(stack->tasks, task);
dbg("task id=%d ends\n", task->id); dbg("task id=%d ends\n", task->id);
} }
@ -193,27 +201,21 @@ get_task_type_gid(const char *label)
} }
void void
task_type_create(uint32_t typeid, const char *label, struct task_type **type_map) task_type_create(struct task_info *info, uint32_t type_id, const char *label)
{ {
struct task_type *type; struct task_type *type;
/* Ensure the type id is new */ /* Ensure the type id is new */
HASH_FIND_INT(*type_map, &typeid, type); HASH_FIND_INT(info->types, &type_id, type);
if(type != NULL) if(type != NULL)
{ die("a task type with id %u already exists\n", type_id);
err("A task type with id %d already exists\n", typeid);
abort();
}
type = calloc(1, sizeof(*type)); type = calloc(1, sizeof(*type));
if(type == NULL) if(type == NULL)
{ die("calloc failed");
perror("calloc");
abort();
}
type->id = typeid; type->id = type_id;
if(type->id == 0) if(type->id == 0)
die("invalid task type id %d\n", type->id); die("invalid task type id %d\n", type->id);
@ -221,21 +223,21 @@ task_type_create(uint32_t typeid, const char *label, struct task_type **type_map
type->gid = get_task_type_gid(label); type->gid = get_task_type_gid(label);
int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label); int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
if(n >= MAX_PCF_LABEL) if(n >= MAX_PCF_LABEL)
die("task label too long: %s\n", label); die("task type label too long: %s\n", label);
/* Add the new task type to the hash table */ /* Add the new task type to the hash table */
HASH_ADD_INT(*type_map, id, type); HASH_ADD_INT(info->types, id, type);
dbg("new task type created id=%d label=%s\n", type->id, dbg("new task type created id=%d label=%s\n", type->id,
type->label); type->label);
} }
void void
task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map) task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
{ {
/* Emit types for all task types */ /* Emit types for all task types */
struct task_type *tt; struct task_type *tt;
for(tt = type_map; tt != NULL; tt = tt->hh.next) for(tt = types; tt != NULL; tt = tt->hh.next)
{ {
struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid); struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
if(pcfvalue != NULL) if(pcfvalue != NULL)
@ -253,9 +255,9 @@ task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map)
} }
struct task * struct task *
task_get_running(struct task *task_stack) task_get_running(struct task_stack *stack)
{ {
struct task *task = task_stack; struct task *task = stack->top;
if(task && task->state == TASK_ST_RUNNING) if(task && task->state == TASK_ST_RUNNING)
return task; return task;

View File

@ -20,13 +20,18 @@
#include "emu.h" #include "emu.h"
void task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct task_type **type_map); struct task *task_find(struct task *tasks, uint32_t task_id);
void task_execute(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack);
void task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack); void task_create(struct task_info *info, uint32_t type_id, uint32_t task_id);
void task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack); void task_execute(struct task_stack *stack, struct task *task);
void task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack); void task_pause(struct task_stack *stack, struct task *task);
void task_type_create(uint32_t typeid, const char *label, struct task_type **type_map); void task_resume(struct task_stack *stack, struct task *task);
void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map); void task_end(struct task_stack *stack, struct task *task);
struct task *task_get_running(struct task *task_stack);
struct task_type *task_type_find(struct task_type *types, uint32_t type_id);
void 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);
struct task *task_get_running(struct task_stack *stack);
#endif /* OVNI_EMU_TASK_H */ #endif /* OVNI_EMU_TASK_H */

View File

@ -11,13 +11,22 @@ let
mpi = last.impi; mpi = last.impi;
#mpi = last.openmpi; #mpi = last.openmpi;
nanos6 = (prev.nanos6Git.override { #nanos6 = (prev.nanos6Git.override {
gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git"; # gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git";
gitBranch = "ovni_instr"; # gitBranch = "ovni_instr";
extrae = null; # extrae = null;
}).overrideAttrs (old: { #}).overrideAttrs (old: {
# buildInputs = old.buildInputs ++ [ last.ovni ];
# patches = [ ./0001-Emit-a-fill-event-at-shutdown.patch ];
# configureFlags = old.configureFlags ++ [
# "--with-ovni=${last.ovni}"
# ];
#});
nanos6 = prev.nanos6Git.overrideAttrs (old: {
src = ~/bsc/nanos6;
version = "local";
buildInputs = old.buildInputs ++ [ last.ovni ]; buildInputs = old.buildInputs ++ [ last.ovni ];
patches = [ ./0001-Emit-a-fill-event-at-shutdown.patch ];
configureFlags = old.configureFlags ++ [ configureFlags = old.configureFlags ++ [
"--with-ovni=${last.ovni}" "--with-ovni=${last.ovni}"
]; ];
@ -30,7 +39,7 @@ let
clangUnwrapped = prev.clangOmpss2Unwrapped.overrideAttrs ( clangUnwrapped = prev.clangOmpss2Unwrapped.overrideAttrs (
old: old:
rec { rec {
src = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2; src = ../../ovni-misc/kk2/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2;
#src = fetchTarball { #src = fetchTarball {
# url = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2; # url = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2;
#}; #};
@ -89,5 +98,5 @@ let
}); });
in in
bsc.ovni-rt #bsc.ovni-rt
#bsc.ompss2.clang bsc.ompss2.clang

16
ovni.c
View File

@ -54,7 +54,7 @@ create_trace_stream(void)
int written = snprintf(path, PATH_MAX, "%s/thread.%d", int written = snprintf(path, PATH_MAX, "%s/thread.%d",
rproc.procdir, rthread.tid); rproc.procdir, rthread.tid);
if(written >= PATH_MAX) if(written >= PATH_MAX)
die("thread trace path too long: %s/thread.%d\n", die("thread trace path too long: %s/thread.%d\n",
rproc.procdir, rthread.tid); rproc.procdir, rthread.tid);
@ -80,7 +80,7 @@ proc_metadata_store(JSON_Value *meta, const char *procdir)
if(meta == NULL) if(meta == NULL)
die("process metadata not initialized\n"); die("process metadata not initialized\n");
if(snprintf(path, PATH_MAX, "%s/metadata.json", procdir) >= PATH_MAX) if(snprintf(path, PATH_MAX, "%s/metadata.json", procdir) >= PATH_MAX)
die("metadata path too long: %s/metadata.json\n", die("metadata path too long: %s/metadata.json\n",
procdir); procdir);
@ -111,7 +111,7 @@ ovni_add_cpu(int index, int phyid)
int first_time = 0; int first_time = 0;
/* Find the CPU array and create it if needed */ /* Find the CPU array and create it if needed */
JSON_Array *cpuarray = json_object_dotget_array(meta, "cpus"); JSON_Array *cpuarray = json_object_dotget_array(meta, "cpus");
if(cpuarray == NULL) if(cpuarray == NULL)
@ -289,7 +289,7 @@ move_thread_to_final(const char *src, const char *dst)
} }
while((bytes = fread(buffer, 1, sizeof(buffer), infile)) > 0) while((bytes = fread(buffer, 1, sizeof(buffer), infile)) > 0)
fwrite(buffer, 1, bytes, outfile); fwrite(buffer, 1, bytes, outfile);
fclose(outfile); fclose(outfile);
fclose(infile); fclose(infile);
@ -466,11 +466,11 @@ ovni_thread_isready(void)
static inline static inline
uint64_t clock_tsc_now(void) uint64_t clock_tsc_now(void)
{ {
uint32_t lo, hi; uint32_t lo, hi;
/* RDTSC copies contents of 64-bit TSC into EDX:EAX */ /* RDTSC copies contents of 64-bit TSC into EDX:EAX */
__asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi)); __asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t) hi << 32 | lo; return (uint64_t) hi << 32 | lo;
} }
#endif #endif

27
pcf.c
View File

@ -81,12 +81,6 @@ const uint32_t pcf_def_palette[] = {
const uint32_t *pcf_palette = pcf_def_palette; const uint32_t *pcf_palette = pcf_def_palette;
const int pcf_palette_len = ARRAY_LEN(pcf_def_palette); const int pcf_palette_len = ARRAY_LEN(pcf_def_palette);
/* Only used to generate tables */
struct pcf_value_label {
int value;
char *label;
};
/* ------------------ Value labels --------------------- */ /* ------------------ Value labels --------------------- */
struct pcf_value_label default_values[] = { struct pcf_value_label default_values[] = {
@ -181,20 +175,19 @@ struct pcf_value_label kernel_cs_values[] = {
struct pcf_value_label nanos6_ss_values[] = { struct pcf_value_label nanos6_ss_values[] = {
{ ST_NULL, "No subsystem" }, { ST_NULL, "No subsystem" },
{ ST_TOO_MANY_TH, "Unknown: multiple threads running" }, { ST_TOO_MANY_TH, "Unknown: multiple threads running" },
{ ST_NANOS6_TASK_RUNNING, "Task: Running" }, { ST_NANOS6_TASK_BODY, "Task: Running body" },
{ ST_NANOS6_SPAWNING, "Task: Spawning function" }, { ST_NANOS6_TASK_CREATING, "Task: Creating" },
{ ST_NANOS6_CREATING, "Task: Creating" }, { ST_NANOS6_TASK_SUBMIT, "Task: Submitting" },
{ ST_NANOS6_SUBMIT, "Task: Submitting" }, { ST_NANOS6_TASK_SPAWNING, "Task: Spawning function" },
{ ST_NANOS6_SCHED_HUNGRY, "Scheduler: Waiting for tasks" }, { ST_NANOS6_SCHED_HUNGRY, "Scheduler: Waiting for ready tasks" },
{ ST_NANOS6_SCHED_SERVING, "Scheduler: Serving tasks" }, { ST_NANOS6_SCHED_SERVING, "Scheduler: Serving tasks" },
{ ST_NANOS6_SCHED_SUBMITTING, "Scheduler: Adding ready tasks" }, { ST_NANOS6_SCHED_ADDING, "Scheduler: Adding ready tasks" },
{ ST_NANOS6_ATTACHED, "Threading: Attached as external thread" },
{ ST_NANOS6_DEP_REG, "Dependency: Registering" }, { ST_NANOS6_DEP_REG, "Dependency: Registering" },
{ ST_NANOS6_DEP_UNREG, "Dependency: Unregistering" }, { ST_NANOS6_DEP_UNREG, "Dependency: Unregistering" },
{ ST_NANOS6_TASKWAIT, "Blocking: Taskwait" }, { ST_NANOS6_BLK_TASKWAIT, "Blocking: Taskwait" },
{ ST_NANOS6_BLOCKING, "Blocking: Blocking current task" }, { ST_NANOS6_BLK_BLOCKING, "Blocking: Blocking current task" },
{ ST_NANOS6_UNBLOCKING, "Blocking: Unblocking remote task" }, { ST_NANOS6_BLK_UNBLOCKING, "Blocking: Unblocking remote task" },
{ ST_NANOS6_WAITFOR, "Blocking: Wait For" }, { ST_NANOS6_BLK_WAITFOR, "Blocking: Wait For" },
{ EV_NANOS6_SCHED_SEND, "EV Scheduler: Send task" }, { EV_NANOS6_SCHED_SEND, "EV Scheduler: Send task" },
{ EV_NANOS6_SCHED_RECV, "EV Scheduler: Recv task" }, { EV_NANOS6_SCHED_RECV, "EV Scheduler: Recv task" },
{ EV_NANOS6_SCHED_SELF, "EV Scheduler: Self-assign task" }, { EV_NANOS6_SCHED_SELF, "EV Scheduler: Self-assign task" },

8
pcf.h
View File

@ -50,6 +50,14 @@ struct pcf_file {
struct pcf_type *types; struct pcf_type *types;
}; };
/* Only used to generate tables */
struct pcf_value_label {
int value;
char *label;
};
extern struct pcf_value_label nanos6_ss_values[];
void pcf_open(struct pcf_file *pcf, char *path, int chantype); void pcf_open(struct pcf_file *pcf, char *path, int chantype);
void pcf_write(struct pcf_file *pcf); void pcf_write(struct pcf_file *pcf);

View File

@ -21,4 +21,4 @@ ovni_test(task-types.c MP)
ovni_test(blocking.c MP) ovni_test(blocking.c MP)
ovni_test(subsystems.c MP) ovni_test(subsystems.c MP)
ovni_test(ss-mismatch.c SHOULD_FAIL ovni_test(ss-mismatch.c SHOULD_FAIL
REGEX "thread [0-9]\\+ ended with 1 extra stacked nanos6 subsystems, top=ST_NANOS6_SCHED_HUNGRY") REGEX "thread [0-9]\\+ ended with 1 extra stacked nanos6 subsystems, top=\"Scheduler: Waiting for ready tasks\"")

View File

@ -26,16 +26,19 @@ main(void)
int us = 500; int us = 500;
uint32_t typeid = 1; uint32_t typeid = 1;
uint32_t taskid = 1;
instr_nanos6_type_create(typeid); instr_nanos6_type_create(typeid);
instr_nanos6_task_create_and_execute(1, typeid); instr_nanos6_task_create_and_execute(taskid, typeid);
usleep(us); usleep(us);
instr_nanos6_block_enter(1); instr_nanos6_block_enter();
instr_nanos6_task_pause(taskid);
usleep(us); usleep(us);
instr_nanos6_block_exit(1); instr_nanos6_task_resume(taskid);
instr_nanos6_block_exit();
usleep(us); usleep(us);
instr_nanos6_task_end(1); instr_nanos6_task_end(taskid);
instr_end(); instr_end();

View File

@ -45,6 +45,9 @@ instr_nanos6_type_create(int32_t typeid)
INSTR_2ARG(instr_nanos6_task_create, "6Tc", int32_t, id, uint32_t, typeid) INSTR_2ARG(instr_nanos6_task_create, "6Tc", int32_t, id, uint32_t, typeid)
INSTR_0ARG(instr_nanos6_task_create_end, "6TC") INSTR_0ARG(instr_nanos6_task_create_end, "6TC")
INSTR_1ARG(instr_nanos6_task_execute, "6Tx", int32_t, id) INSTR_1ARG(instr_nanos6_task_execute, "6Tx", int32_t, id)
INSTR_1ARG(instr_nanos6_task_pause, "6Tp", int32_t, id)
INSTR_1ARG(instr_nanos6_task_resume, "6Tr", int32_t, id)
INSTR_1ARG(instr_nanos6_task_end, "6Te", int32_t, id)
static inline void static inline void
instr_nanos6_task_create_and_execute(int32_t id, uint32_t typeid) instr_nanos6_task_create_and_execute(int32_t id, uint32_t typeid)
@ -54,46 +57,14 @@ instr_nanos6_task_create_and_execute(int32_t id, uint32_t typeid)
instr_nanos6_task_execute(id); instr_nanos6_task_execute(id);
} }
INSTR_2ARG(instr_nanos6_task_block, "6Tb", int32_t, id, int32_t, reason) INSTR_0ARG(instr_nanos6_block_enter, "6Bb")
INSTR_2ARG(instr_nanos6_task_unblock, "6Tu", int32_t, id, int32_t, reason) INSTR_0ARG(instr_nanos6_block_exit, "6BB")
INSTR_0ARG(instr_nanos6_unblock_enter, "6Bb")
static inline void INSTR_0ARG(instr_nanos6_unblock_exit, "6BB")
instr_nanos6_block_enter(int32_t id) INSTR_0ARG(instr_nanos6_taskwait_enter, "6Bw")
{ INSTR_0ARG(instr_nanos6_taskwait_exit, "6BW")
instr_nanos6_task_block(id, 0); INSTR_0ARG(instr_nanos6_waitfor_enter, "6Bf")
} INSTR_0ARG(instr_nanos6_waitfor_exit, "6BF")
static inline void
instr_nanos6_block_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 0);
}
static inline void
instr_nanos6_task_wait_enter(int32_t id)
{
instr_nanos6_task_block(id, 1);
}
static inline void
instr_nanos6_task_wait_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 1);
}
static inline void
instr_nanos6_waitfor_enter(int32_t id)
{
instr_nanos6_task_block(id, 2);
}
static inline void
instr_nanos6_waitfor_exit(int32_t id)
{
instr_nanos6_task_unblock(id, 2);
}
INSTR_1ARG(instr_nanos6_task_end, "6Te", int32_t, id)
INSTR_0ARG(instr_nanos6_sched_receive_task, "6Sr") INSTR_0ARG(instr_nanos6_sched_receive_task, "6Sr")
INSTR_0ARG(instr_nanos6_sched_assign_task, "6Ss") INSTR_0ARG(instr_nanos6_sched_assign_task, "6Ss")

View File

@ -43,16 +43,16 @@ main(void)
instr_nanos6_sched_submit_exit(); usleep(us); instr_nanos6_sched_submit_exit(); usleep(us);
instr_nanos6_enter_submit_task(); usleep(us); instr_nanos6_enter_submit_task(); usleep(us);
instr_nanos6_exit_submit_task(); usleep(us); instr_nanos6_exit_submit_task(); usleep(us);
instr_nanos6_block_enter(taskid); usleep(us); instr_nanos6_block_enter(); usleep(us);
instr_nanos6_block_exit(taskid); usleep(us); instr_nanos6_block_exit(); usleep(us);
instr_nanos6_waitfor_enter(taskid); usleep(us); instr_nanos6_waitfor_enter(); usleep(us);
instr_nanos6_waitfor_exit(taskid); usleep(us); instr_nanos6_waitfor_exit(); usleep(us);
instr_nanos6_register_accesses_enter(); usleep(us); instr_nanos6_register_accesses_enter(); usleep(us);
instr_nanos6_register_accesses_exit(); usleep(us); instr_nanos6_register_accesses_exit(); usleep(us);
instr_nanos6_unregister_accesses_enter(); usleep(us); instr_nanos6_unregister_accesses_enter(); usleep(us);
instr_nanos6_unregister_accesses_exit(); usleep(us); instr_nanos6_unregister_accesses_exit(); usleep(us);
instr_nanos6_task_wait_enter(taskid); usleep(us); instr_nanos6_taskwait_enter(); usleep(us);
instr_nanos6_task_wait_exit(taskid); usleep(us); instr_nanos6_taskwait_exit(); usleep(us);
instr_nanos6_spawn_function_enter(); usleep(us); instr_nanos6_spawn_function_enter(); usleep(us);
instr_nanos6_spawn_function_exit(); usleep(us); instr_nanos6_spawn_function_exit(); usleep(us);

View File

@ -0,0 +1,3 @@
/* Create a test which unblocks a task from an external thread. This
* should break currently, as the instrumentation attempts to call
* ovni_ev_emit from a thread without initialization. */