Use one event per blocking type in Nanos6
This commit is contained in:
		
							parent
							
								
									5c45323354
								
							
						
					
					
						commit
						ac1ae8e69d
					
				| @ -37,7 +37,7 @@ window_pixel_size 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_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_synchronize 1 | ||||
| 
 | ||||
|  | ||||
| @ -37,7 +37,7 @@ window_pixel_size 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_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_synchronize 1 | ||||
| 
 | ||||
|  | ||||
| @ -162,14 +162,20 @@ KCI	Is back in the CPU due to a context switch | ||||
| 6Ha	Attaches to Nanos6 as external thread | ||||
| 6HA	Detaches from Nanos6 as external thread | ||||
| 
 | ||||
| 6s[	Begins to spawn a function via spawnFunction() | ||||
| 6s]	Ends spawning a function | ||||
| 6F[	Begins to spawn a function via spawnFunction() | ||||
| 6F]	Ends spawning a function | ||||
| 
 | ||||
| 6Dr	Begins 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	Ends the unregistration of a task's accesses | ||||
| 
 | ||||
| 6Bu	Begins to unblock the given task | ||||
| 6BU	Ends unblocking the given task | ||||
| 6Bu	Begins to unblock a 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() | ||||
| ``` | ||||
|  | ||||
| @ -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 | ||||
| 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 | ||||
| 
 | ||||
| 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 | ||||
| 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 | ||||
|   submitted to the scheduler for later execution). | ||||
|  | ||||
							
								
								
									
										75
									
								
								emu.h
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								emu.h
									
									
									
									
									
								
							| @ -104,40 +104,30 @@ enum nodes_state { | ||||
|  * CTF implementation. */ | ||||
| enum nanos6_ss_state { | ||||
| 	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_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_UNREG = 5,        /* DEPENDENCY_UNREGISTER */ | ||||
| 	ST_NANOS6_SCHED_SUBMITTING = 6, /* SCHEDULER_ADD_TASK */ | ||||
| 	                                /* SCHEDULER_GET_TASK */ | ||||
| 	ST_NANOS6_CREATING = 8,         /* TASK_CREATE */ | ||||
| 	                                /* TASK_ARGS_INIT */ | ||||
| 	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, | ||||
| 	ST_NANOS6_BLK_TASKWAIT = 12,    /* TASK_WAIT */ | ||||
| 	ST_NANOS6_BLK_WAITFOR = 13,     /* WAIT_FOR */ | ||||
| 	ST_NANOS6_BLK_BLOCKING = 16,    /* BLOCKING_API_BLOCK */ | ||||
| 	ST_NANOS6_BLK_UNBLOCKING = 17,  /* BLOCKING_API_UNBLOCK */ | ||||
| 
 | ||||
| 	EV_NANOS6_SCHED_RECV, | ||||
| 	EV_NANOS6_SCHED_SEND, | ||||
| 	EV_NANOS6_SCHED_SELF, | ||||
| 	EV_NANOS6_SCHED_RECV = 50, | ||||
| 	EV_NANOS6_SCHED_SEND = 51, | ||||
| 	EV_NANOS6_SCHED_SELF = 52, | ||||
| }; | ||||
| 
 | ||||
| /* Possible reasons for Nanos6 tasks becoming running or not running */ | ||||
| enum nanos6_task_run_reason | ||||
| { | ||||
| 	TB_EXEC_OR_END = -1, | ||||
| 	TB_BLOCKING_API = 0, | ||||
| 	TB_TASKWAIT = 1, | ||||
| 	TB_WAITFOR = 2 | ||||
| enum nanos6_thread_state { | ||||
| 	ST_NANOS6_TH_EXTERNAL = 1, | ||||
| 	ST_NANOS6_TH_WORKER, | ||||
| 	ST_NANOS6_TH_LEADER, | ||||
| 	ST_NANOS6_TH_MAIN | ||||
| }; | ||||
| 
 | ||||
| enum kernel_cs_state { | ||||
| @ -169,6 +159,20 @@ struct task { | ||||
| 	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 | ||||
| 
 | ||||
| enum chan_track { | ||||
| @ -207,6 +211,7 @@ enum chan { | ||||
| 	CHAN_NANOS6_TYPE, | ||||
| 	CHAN_NANOS6_SUBSYSTEM, | ||||
| 	CHAN_NANOS6_RANK, | ||||
| 	CHAN_NANOS6_THREAD, | ||||
| 
 | ||||
| 	CHAN_KERNEL_CS, | ||||
| 
 | ||||
| @ -249,7 +254,8 @@ static const int chan_to_prvtype[CHAN_MAX] = { | ||||
| 	[CHAN_NANOS6_TYPE]      = 36, | ||||
| 	[CHAN_NANOS6_SUBSYSTEM] = 37, | ||||
| 	[CHAN_NANOS6_RANK]      = 38, | ||||
| 	[CHAN_KERNEL_CS]        = 40, | ||||
| 	[CHAN_NANOS6_THREAD]    = 39, | ||||
| 	[CHAN_KERNEL_CS]        = 45, | ||||
| }; | ||||
| 
 | ||||
| struct ovni_chan { | ||||
| @ -335,8 +341,8 @@ struct ovni_ethread { | ||||
| 	 * structures */ | ||||
| 
 | ||||
| 	/* Task stacks, top ones are the tasks currently runnable. */ | ||||
| 	struct task *nosv_task_stack; | ||||
| 	struct task *nanos6_task_stack; | ||||
| 	struct task_stack nosv_task_stack; | ||||
| 	struct task_stack nanos6_task_stack; | ||||
| 
 | ||||
| 	/* Channels are used to output the emulator state in PRV */ | ||||
| 	struct ovni_chan chan[CHAN_MAX]; | ||||
| @ -376,11 +382,8 @@ struct ovni_eproc { | ||||
| 	/* ------ Subsystem specific data --------*/ | ||||
| 	/* TODO: Use dynamic allocation */ | ||||
| 
 | ||||
| 	struct task_type *nosv_types; | ||||
| 	struct task *nosv_tasks; | ||||
| 
 | ||||
| 	struct task_type *nanos6_types; | ||||
| 	struct task *nanos6_tasks; | ||||
| 	struct task_info nosv_task_info; | ||||
|     struct task_info nanos6_task_info; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										367
									
								
								emu_nanos6.c
									
									
									
									
									
								
							
							
						
						
									
										367
									
								
								emu_nanos6.c
									
									
									
									
									
								
							| @ -30,7 +30,6 @@ hook_init_nanos6(struct ovni_emu *emu) | ||||
| 	struct ovni_ethread *th; | ||||
| 	struct ovni_cpu *cpu; | ||||
| 	struct ovni_chan **uth, **ucpu; | ||||
| 	size_t i; | ||||
| 	int row; | ||||
| 	FILE *prv_th, *prv_cpu; | ||||
| 	int64_t *clock; | ||||
| @ -40,7 +39,7 @@ hook_init_nanos6(struct ovni_emu *emu) | ||||
| 	prv_cpu = emu->prv_cpu; | ||||
| 
 | ||||
| 	/* 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]; | ||||
| 		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_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_THREAD,    CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); | ||||
| 	} | ||||
| 
 | ||||
| 	/* 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]; | ||||
| 		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_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_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 ------------------------------- */ | ||||
| 
 | ||||
| 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; | ||||
| 	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_TYPE], 0); | ||||
| 
 | ||||
| 	if(emu->cur_loom->rank_enabled) | ||||
| 		chan_set(&th->chan[CHAN_NANOS6_RANK], 0); | ||||
| 
 | ||||
| 	// Check the reason
 | ||||
| 	switch (reason) | ||||
| 	{ | ||||
| 		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; | ||||
| 	} | ||||
|     /* Only exit the task body when finishing */ | ||||
|     if(tr == 'e') | ||||
|         chan_pop(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY); | ||||
| } | ||||
| 
 | ||||
| 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_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) | ||||
| 		chan_set(&th->chan[CHAN_NANOS6_RANK], proc->rank + 1); | ||||
| 
 | ||||
| 	// Check the reason
 | ||||
| 	switch (reason) | ||||
| 	{ | ||||
| 		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; | ||||
| 	} | ||||
|     /* Only enter the body of the task when we begin the execution */ | ||||
|     if(tr == 'x') | ||||
|         chan_push(&th->chan[CHAN_NANOS6_SUBSYSTEM], ST_NANOS6_TASK_BODY); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| task_switch(struct ovni_emu *emu, struct task *prev_task, | ||||
| 		struct task *next_task, int newtask) | ||||
| chan_task_switch(struct ovni_emu *emu, | ||||
| 		struct task *prev, struct task *next) | ||||
| { | ||||
| 	struct ovni_ethread *th; | ||||
| 	struct ovni_ethread *th = emu->cur_thread; | ||||
| 
 | ||||
| 	th = emu->cur_thread; | ||||
| 
 | ||||
| 	if(!prev_task || !next_task) | ||||
| 	if(!prev || !next) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(newtask && prev_task->state != TASK_ST_RUNNING) | ||||
| 		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) | ||||
| 	if(next->id == 0) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(prev_task->thread != next_task->thread) | ||||
| 	if(prev->thread != next->thread) | ||||
| 		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 */ | ||||
| 	chan_set(&th->chan[CHAN_NANOS6_TASKID], next_task->id); | ||||
| 	/* No need to change the rank as we will switch to tasks from
 | ||||
| 	 * same thread */ | ||||
| 	chan_set(&th->chan[CHAN_NANOS6_TASKID], next->id); | ||||
| 
 | ||||
| 	/* 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 | ||||
| 	 * now we only emit a new type if we switch to a type with a | ||||
| 	 * different gid. */ | ||||
| 	if(prev_task->type->gid != next_task->type->gid) | ||||
| 		chan_set(&th->chan[CHAN_NANOS6_TYPE], next_task->type->gid); | ||||
| 	if(prev->type->gid != next->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 | ||||
| @ -192,87 +269,53 @@ pre_task(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_ethread *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; | ||||
| 	chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM]; | ||||
| 
 | ||||
| 	/* Update the emulator state, but don't modify the channels yet */ | ||||
| 	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 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; | ||||
| 		case 'e': task_end(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; | ||||
| 		case 'b': task_pause(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; | ||||
| 		case 'u': task_resume(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; | ||||
| 		case 'C': 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, TB_EXEC_OR_END); | ||||
| 		/* We use the 'c' event to create the task and switch
 | ||||
| 		 * the subsystem all in one step because the timing here | ||||
| 		 * is critical. */ | ||||
| 		case 'c': | ||||
| 			chan_push(chan_th, ST_NANOS6_TASK_CREATING); | ||||
| 			create_task(emu); | ||||
| 			break; | ||||
| 		case 'e': /* End: either a nested task or the last one */ | ||||
| 			if(runs_task_now) | ||||
| 				task_switch(emu, prev_running, next_running, 0); | ||||
| 			else | ||||
| 				task_not_running(emu, prev_running, TB_EXEC_OR_END); | ||||
| 		case 'C': | ||||
| 			chan_pop(chan_th, ST_NANOS6_TASK_CREATING); | ||||
| 			break; | ||||
| 		case 'b': /* Block */ | ||||
| 			task_not_running(emu, prev_running, emu->cur_ev->payload.i32[1]); | ||||
| 			break; | ||||
| 		case 'u': /* Unblock */ | ||||
| 			task_running(emu, next_running, emu->cur_ev->payload.i32[1]); | ||||
| 			break; | ||||
| 		case 'c': /* Create */ | ||||
| 			chan_push(chan_th, ST_NANOS6_CREATING); | ||||
| 			break; | ||||
| 		case 'C': /* Create end */ | ||||
| 			chan_pop(chan_th, ST_NANOS6_CREATING); | ||||
| 		case 'x': | ||||
| 		case 'e': | ||||
| 		case 'r': | ||||
| 		case 'p': /* Wet floor */ | ||||
| 			update_task(emu); | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 			die("unexpected event value %c\n", | ||||
| 					emu->cur_ev->header.value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| 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) | ||||
| 	{ | ||||
| 		case 'c': | ||||
| 			if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) | ||||
| 			{ | ||||
| 				err("expecting a jumbo event\n"); | ||||
| 				abort(); | ||||
| 			} | ||||
| 	if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) | ||||
| 		die("expecting a jumbo event\n"); | ||||
| 
 | ||||
| 			data = &emu->cur_ev->payload.jumbo.data[0]; | ||||
| 			uint32_t *typeid = (uint32_t *) data; | ||||
| 			data += sizeof(*typeid); | ||||
| 			const char *label = (const char *) data; | ||||
| 			task_type_create(*typeid, label, &emu->cur_proc->nanos6_types); | ||||
| 			break; | ||||
| 		default: | ||||
| 			  break; | ||||
| 	} | ||||
| 	uint8_t *data = &emu->cur_ev->payload.jumbo.data[0]; | ||||
| 	uint32_t typeid = *(uint32_t *) data; | ||||
| 	data += 4; | ||||
| 
 | ||||
| 	const char *label = (const char *) data; | ||||
| 
 | ||||
| 	struct ovni_eproc *proc = emu->cur_proc; | ||||
| 
 | ||||
| 	task_type_create(&proc->nanos6_task_info, typeid, label); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -287,9 +330,9 @@ pre_deps(struct ovni_emu *emu) | ||||
| 	switch(emu->cur_ev->header.value) | ||||
| 	{ | ||||
| 		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_pop(chan_th, ST_NANOS6_DEP_UNREG); break; | ||||
| 		case 'U': chan_pop (chan_th, ST_NANOS6_DEP_UNREG); break; | ||||
| 		default: break; | ||||
| 	} | ||||
| } | ||||
| @ -305,8 +348,14 @@ pre_blocking(struct ovni_emu *emu) | ||||
| 
 | ||||
| 	switch(emu->cur_ev->header.value) | ||||
| 	{ | ||||
| 		case 'u': chan_push(chan_th, ST_NANOS6_UNBLOCKING); break; | ||||
| 		case 'U': chan_pop(chan_th, ST_NANOS6_UNBLOCKING); break; | ||||
| 		case 'b': chan_push(chan_th, ST_NANOS6_BLK_BLOCKING); 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; | ||||
| 	} | ||||
| } | ||||
| @ -334,20 +383,24 @@ pre_sched(struct ovni_emu *emu) | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| pre_thread_type(struct ovni_emu *emu) | ||||
| pre_thread(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_ethread *th; | ||||
| 	struct ovni_chan *chan_th; | ||||
| 
 | ||||
| 	th = emu->cur_thread; | ||||
| 	chan_th = &th->chan[CHAN_NANOS6_SUBSYSTEM]; | ||||
| 	chan_th = &th->chan[CHAN_NANOS6_THREAD]; | ||||
| 
 | ||||
| 	switch(emu->cur_ev->header.value) | ||||
| 	{ | ||||
| 		case 'a': chan_push(chan_th, ST_NANOS6_ATTACHED); break; | ||||
| 		case 'A': chan_pop (chan_th, ST_NANOS6_ATTACHED); break; | ||||
| 		case 's': chan_push(chan_th, ST_NANOS6_SPAWNING); break; | ||||
| 		case 'S': chan_pop (chan_th, ST_NANOS6_SPAWNING); break; | ||||
| 		case 'e': chan_push(chan_th, ST_NANOS6_TH_EXTERNAL); break; | ||||
| 		case 'E': chan_pop (chan_th, ST_NANOS6_TH_EXTERNAL); break; | ||||
| 		case 'w': chan_push(chan_th, ST_NANOS6_TH_WORKER); 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; | ||||
| 	} | ||||
| } | ||||
| @ -406,8 +459,8 @@ hook_pre_nanos6(struct ovni_emu *emu) | ||||
| 		case 'T': pre_task(emu); break; | ||||
| 		case 'Y': pre_type(emu); break; | ||||
| 		case 'S': pre_sched(emu); break; | ||||
| 		case 'U': pre_ss(emu, ST_NANOS6_SUBMIT); break; | ||||
| 		case 'H': pre_thread_type(emu); break; | ||||
| 		case 'U': pre_ss(emu, ST_NANOS6_TASK_SUBMIT); break; | ||||
| 		case 'H': pre_thread(emu); break; | ||||
| 		case 'D': pre_deps(emu); break; | ||||
| 		case 'B': pre_blocking(emu); break; | ||||
| 		default: | ||||
| @ -417,27 +470,6 @@ hook_pre_nanos6(struct ovni_emu *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 | ||||
| end_lint(struct ovni_emu *emu) | ||||
| { | ||||
| @ -449,8 +481,19 @@ end_lint(struct ovni_emu *emu) | ||||
| 		if(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); | ||||
| 		} | ||||
| 	} | ||||
| @ -472,7 +515,7 @@ hook_end_nanos6(struct ovni_emu *emu) | ||||
| 			for(size_t j = 0; j < loom->nprocs; 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										236
									
								
								emu_nosv.c
									
									
									
									
									
								
							
							
						
						
									
										236
									
								
								emu_nosv.c
									
									
									
									
									
								
							| @ -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_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 ------------------------------- */ | ||||
| 
 | ||||
| static void | ||||
| task_not_running(struct ovni_emu *emu, struct task *task) | ||||
| chan_task_stopped(struct ovni_emu *emu) | ||||
| { | ||||
| 	struct ovni_ethread *th; | ||||
| 	th = emu->cur_thread; | ||||
| 
 | ||||
| 	if(task->state == TASK_ST_RUNNING) | ||||
| 		die("task is still running\n"); | ||||
| 	struct ovni_ethread *th = emu->cur_thread; | ||||
| 
 | ||||
| 	chan_set(&th->chan[CHAN_NOSV_TASKID], 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) | ||||
| 		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); | ||||
| } | ||||
| 
 | ||||
| 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_eproc *proc; | ||||
| @ -126,123 +130,179 @@ task_running(struct ovni_emu *emu, struct task *task) | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| task_switch(struct ovni_emu *emu, struct task *prev_task, | ||||
| 		struct task *next_task, int newtask) | ||||
| chan_task_switch(struct ovni_emu *emu, | ||||
| 		struct task *prev, struct task *next) | ||||
| { | ||||
| 	struct ovni_ethread *th; | ||||
| 	struct ovni_ethread *th = emu->cur_thread; | ||||
| 
 | ||||
| 	th = emu->cur_thread; | ||||
| 
 | ||||
| 	if(!prev_task || !next_task) | ||||
| 	if(!prev || !next) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(newtask && prev_task->state != TASK_ST_RUNNING) | ||||
| 		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) | ||||
| 	if(next->id == 0) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(prev_task->thread != next_task->thread) | ||||
| 	if(prev->thread != next->thread) | ||||
| 		die("cannot switch to a task of another thread\n"); | ||||
| 
 | ||||
| 	/* No need to change the rank or app ID, as we can only switch
 | ||||
| 	 * 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
 | ||||
| 	 * 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 | ||||
| 	 * different gid. */ | ||||
| 	if(prev_task->type->gid != next_task->type->gid) | ||||
| 		chan_set(&th->chan[CHAN_NOSV_TYPE], next_task->type->gid); | ||||
| 	if(prev->type->gid != next->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 | ||||
| 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) | ||||
| 	{ | ||||
| 		case 'c': task_create(emu->cur_ev->payload.i32[0], emu->cur_ev->payload.i32[1], task_map, type_map); break; | ||||
| 		case 'x': task_execute(emu->cur_ev->payload.i32[0], emu->cur_thread, task_map, task_stack); break; | ||||
| 		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); | ||||
| 		case 'c': | ||||
| 			create_task(emu); | ||||
| 			break; | ||||
| 		case 'e': /* End: either a nested task or the last one */ | ||||
| 			if(runs_task_now) | ||||
| 				task_switch(emu, prev_running, next_running, 0); | ||||
| 			else | ||||
| 				task_not_running(emu, prev_running); | ||||
| 			break; | ||||
| 		case 'p': /* Pause */ | ||||
| 			task_not_running(emu, prev_running); | ||||
| 			break; | ||||
| 		case 'r': /* Resume */ | ||||
| 			task_running(emu, next_running); | ||||
| 		case 'x': | ||||
| 		case 'e': | ||||
| 		case 'r': | ||||
| 		case 'p': /* Wet floor */ | ||||
| 			update_task(emu); | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 			die("unexpected event value %c\n", | ||||
| 					emu->cur_ev->header.value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| 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) | ||||
| 	{ | ||||
| 		case 'c': | ||||
| 			if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) | ||||
| 			{ | ||||
| 				err("expecting a jumbo event\n"); | ||||
| 				abort(); | ||||
| 			} | ||||
| 	if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) | ||||
| 		die("expecting a jumbo event\n"); | ||||
| 
 | ||||
| 			data = &emu->cur_ev->payload.jumbo.data[0]; | ||||
| 			uint32_t *typeid = (uint32_t *) data; | ||||
| 			data += sizeof(*typeid); | ||||
| 			const char *label = (const char *) data; | ||||
| 			task_type_create(*typeid, label, &emu->cur_proc->nosv_types); | ||||
| 			break; | ||||
| 		default: | ||||
| 			  break; | ||||
| 	} | ||||
| 	uint8_t *data = &emu->cur_ev->payload.jumbo.data[0]; | ||||
| 	uint32_t typeid = *(uint32_t *) data; | ||||
| 	data += 4; | ||||
| 
 | ||||
| 	const char *label = (const char *) data; | ||||
| 
 | ||||
| 	struct ovni_eproc *proc = emu->cur_proc; | ||||
| 
 | ||||
| 	task_type_create(&proc->nosv_task_info, typeid, label); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -437,7 +497,7 @@ hook_end_nosv(struct ovni_emu *emu) | ||||
| 			for(size_t j = 0; j < loom->nprocs; 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										146
									
								
								emu_task.c
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								emu_task.c
									
									
									
									
									
								
							| @ -24,24 +24,39 @@ | ||||
| #include "prv.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 | ||||
| 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 */ | ||||
| 	struct task *task = NULL; | ||||
| 	HASH_FIND_INT(*task_map, &task_id, task); | ||||
| 
 | ||||
| 	if(task != NULL) | ||||
| 		die("cannot create a task with id %u: already exists\n", task_id); | ||||
| 	if(task_find(info->tasks, task_id) != NULL) | ||||
| 		die("cannot create task: task_id %u already exists\n", | ||||
| 				task_id); | ||||
| 
 | ||||
| 	/* Ensure the type exists */ | ||||
| 	struct task_type *type = NULL; | ||||
| 	HASH_FIND_INT(*type_map, &type_id, type); | ||||
| 
 | ||||
| 	struct task_type *type = task_type_find(info->types, type_id); | ||||
| 	if(type == NULL) | ||||
| 		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) | ||||
| 		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; | ||||
| 
 | ||||
| 	/* 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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		die("cannot find task with id %u\n", task_id); | ||||
| 		die("cannot execute: task is NULL\n"); | ||||
| 
 | ||||
| 	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) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(top == task) | ||||
| 		die("thread already has assigned task %u\n", task_id); | ||||
| 	if(stack->top == task) | ||||
| 		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"); | ||||
| 
 | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		die("cannot find task with id %u\n", task_id); | ||||
| 		die("cannot pause: task is NULL\n"); | ||||
| 
 | ||||
| 	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) | ||||
| 		die("thread state is not running\n"); | ||||
| 	if(task->thread == NULL) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(cur_thread != task->thread) | ||||
| 	if(stack->thread != task->thread) | ||||
| 		die("task is assigned to a different thread\n"); | ||||
| 
 | ||||
| 	task->state = TASK_ST_PAUSED; | ||||
| @ -118,25 +128,24 @@ task_pause(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		die("cannot find task with id %u\n", task_id); | ||||
| 		die("cannot resume: task is NULL\n"); | ||||
| 
 | ||||
| 	if(task->state != TASK_ST_PAUSED) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(top != task) | ||||
| 	if(stack->top != task) | ||||
| 		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"); | ||||
| 
 | ||||
| 	task->state = TASK_ST_RUNNING; | ||||
| @ -145,25 +154,24 @@ task_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **tas | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		die("cannot find task with id %u\n", task_id); | ||||
| 		die("cannot end: task is NULL\n"); | ||||
| 
 | ||||
| 	if(task->state != TASK_ST_RUNNING) | ||||
| 		die("task state is not running\n"); | ||||
| 
 | ||||
| 	if(cur_thread->state != TH_ST_RUNNING) | ||||
| 		die("thread is not running\n"); | ||||
| 	if(task->thread == NULL) | ||||
| 		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"); | ||||
| 
 | ||||
| 	if(cur_thread != task->thread) | ||||
| 	if(stack->thread != task->thread) | ||||
| 		die("task is assigned to a different thread\n"); | ||||
| 
 | ||||
| 	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
 | ||||
| 	 * 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); | ||||
| } | ||||
| @ -193,27 +201,21 @@ get_task_type_gid(const char *label) | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	/* Ensure the type id is new */ | ||||
| 	HASH_FIND_INT(*type_map, &typeid, type); | ||||
| 	HASH_FIND_INT(info->types, &type_id, type); | ||||
| 
 | ||||
| 	if(type != NULL) | ||||
| 	{ | ||||
| 		err("A task type with id %d already exists\n", typeid); | ||||
| 		abort(); | ||||
| 	} | ||||
| 		die("a task type with id %u already exists\n", type_id); | ||||
| 
 | ||||
| 	type = calloc(1, sizeof(*type)); | ||||
| 
 | ||||
| 	if(type == NULL) | ||||
| 	{ | ||||
| 		perror("calloc"); | ||||
| 		abort(); | ||||
| 	} | ||||
| 		die("calloc failed"); | ||||
| 
 | ||||
| 	type->id = typeid; | ||||
| 	type->id = type_id; | ||||
| 
 | ||||
| 	if(type->id == 0) | ||||
| 		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); | ||||
| 	int n = snprintf(type->label, MAX_PCF_LABEL, "%s", 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 */ | ||||
| 	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, | ||||
| 			type->label); | ||||
| } | ||||
| 
 | ||||
| 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 */ | ||||
| 	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); | ||||
| 		if(pcfvalue != NULL) | ||||
| @ -253,9 +255,9 @@ task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map) | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		return task; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										21
									
								
								emu_task.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								emu_task.h
									
									
									
									
									
								
							| @ -20,13 +20,18 @@ | ||||
| 
 | ||||
| #include "emu.h" | ||||
| 
 | ||||
| void task_create(uint32_t task_id, uint32_t type_id, struct task **task_map, struct task_type **type_map); | ||||
| 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_resume(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack); | ||||
| void task_end(uint32_t task_id, struct ovni_ethread *cur_thread, struct task **task_map, struct task **thread_task_stack); | ||||
| void task_type_create(uint32_t typeid, const char *label, struct task_type **type_map); | ||||
| void task_create_pcf_types(struct pcf_type *pcftype, struct task_type *type_map); | ||||
| struct task *task_get_running(struct task *task_stack); | ||||
| struct task *task_find(struct task *tasks, uint32_t task_id); | ||||
| 
 | ||||
| void task_create(struct task_info *info, uint32_t type_id, uint32_t task_id); | ||||
| void task_execute(struct task_stack *stack, struct task *task); | ||||
| void task_pause(struct task_stack *stack, struct task *task); | ||||
| void task_resume(struct task_stack *stack, struct task *task); | ||||
| void task_end(struct task_stack *stack, struct task *task); | ||||
| 
 | ||||
| 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 */ | ||||
|  | ||||
| @ -11,13 +11,22 @@ let | ||||
|     mpi = last.impi; | ||||
|     #mpi = last.openmpi; | ||||
| 
 | ||||
|     nanos6 = (prev.nanos6Git.override { | ||||
|       gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git"; | ||||
|       gitBranch = "ovni_instr"; | ||||
|       extrae = null; | ||||
|     }).overrideAttrs (old: { | ||||
|     #nanos6 = (prev.nanos6Git.override { | ||||
|     #  gitUrl = "ssh://git@bscpm03.bsc.es/nanos6/forks/nanos6-extern-001.git"; | ||||
|     #  gitBranch = "ovni_instr"; | ||||
|     #  extrae = null; | ||||
|     #}).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 ]; | ||||
|       patches = [ ./0001-Emit-a-fill-event-at-shutdown.patch ]; | ||||
|       configureFlags = old.configureFlags ++ [ | ||||
|         "--with-ovni=${last.ovni}" | ||||
|       ]; | ||||
| @ -30,7 +39,7 @@ let | ||||
|       clangUnwrapped = prev.clangOmpss2Unwrapped.overrideAttrs ( | ||||
|         old: | ||||
|         rec { | ||||
|           src = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2; | ||||
|           src = ../../ovni-misc/kk2/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2; | ||||
|           #src = fetchTarball { | ||||
|           #  url = ../kk/llvm-mono-d3d4f2bf231b9461a5881c5bf56659516d45e670.tar.bz2; | ||||
|           #}; | ||||
| @ -89,5 +98,5 @@ let | ||||
|   }); | ||||
| 
 | ||||
| in | ||||
|   bsc.ovni-rt | ||||
|   #bsc.ompss2.clang | ||||
|   #bsc.ovni-rt | ||||
|   bsc.ompss2.clang | ||||
|  | ||||
							
								
								
									
										16
									
								
								ovni.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								ovni.c
									
									
									
									
									
								
							| @ -54,7 +54,7 @@ create_trace_stream(void) | ||||
| 	int written = snprintf(path, PATH_MAX, "%s/thread.%d", | ||||
| 			rproc.procdir, rthread.tid); | ||||
| 
 | ||||
|        	if(written >= PATH_MAX) | ||||
| 	if(written >= PATH_MAX) | ||||
| 		die("thread trace path too long: %s/thread.%d\n", | ||||
| 				rproc.procdir, rthread.tid); | ||||
| 
 | ||||
| @ -80,7 +80,7 @@ proc_metadata_store(JSON_Value *meta, const char *procdir) | ||||
| 
 | ||||
| 	if(meta == NULL) | ||||
| 		die("process metadata not initialized\n"); | ||||
|         | ||||
| 
 | ||||
| 	if(snprintf(path, PATH_MAX, "%s/metadata.json", procdir) >= PATH_MAX) | ||||
| 		die("metadata path too long: %s/metadata.json\n", | ||||
| 				procdir); | ||||
| @ -111,7 +111,7 @@ ovni_add_cpu(int index, int phyid) | ||||
| 
 | ||||
| 	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"); | ||||
| 
 | ||||
| 	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) | ||||
| 	    fwrite(buffer, 1, bytes, outfile); | ||||
| 		fwrite(buffer, 1, bytes, outfile); | ||||
| 
 | ||||
| 	fclose(outfile); | ||||
| 	fclose(infile); | ||||
| @ -466,11 +466,11 @@ ovni_thread_isready(void) | ||||
| static inline | ||||
| uint64_t clock_tsc_now(void) | ||||
| { | ||||
|     uint32_t lo, hi; | ||||
| 	uint32_t lo, hi; | ||||
| 
 | ||||
|     /* RDTSC copies contents of 64-bit TSC into EDX:EAX */ | ||||
|     __asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi)); | ||||
|     return (uint64_t) hi << 32 | lo; | ||||
| 	/* RDTSC copies contents of 64-bit TSC into EDX:EAX */ | ||||
| 	__asm__ volatile("rdtsc" : "=a" (lo), "=d" (hi)); | ||||
| 	return (uint64_t) hi << 32 | lo; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										27
									
								
								pcf.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								pcf.c
									
									
									
									
									
								
							| @ -81,12 +81,6 @@ const uint32_t pcf_def_palette[] = { | ||||
| const uint32_t *pcf_palette = 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 --------------------- */ | ||||
| 
 | ||||
| struct pcf_value_label default_values[] = { | ||||
| @ -181,20 +175,19 @@ struct pcf_value_label kernel_cs_values[] = { | ||||
| struct pcf_value_label nanos6_ss_values[] = { | ||||
| 	{ ST_NULL,                    "No subsystem" }, | ||||
| 	{ ST_TOO_MANY_TH,             "Unknown: multiple threads running" }, | ||||
| 	{ ST_NANOS6_TASK_RUNNING,     "Task: Running" }, | ||||
| 	{ ST_NANOS6_SPAWNING,         "Task: Spawning function" }, | ||||
| 	{ ST_NANOS6_CREATING,         "Task: Creating" }, | ||||
| 	{ ST_NANOS6_SUBMIT,           "Task: Submitting" }, | ||||
| 	{ ST_NANOS6_SCHED_HUNGRY,     "Scheduler: Waiting for tasks" }, | ||||
| 	{ ST_NANOS6_TASK_BODY,        "Task: Running body" }, | ||||
| 	{ ST_NANOS6_TASK_CREATING,    "Task: Creating" }, | ||||
| 	{ ST_NANOS6_TASK_SUBMIT,      "Task: Submitting" }, | ||||
| 	{ ST_NANOS6_TASK_SPAWNING,    "Task: Spawning function" }, | ||||
| 	{ ST_NANOS6_SCHED_HUNGRY,     "Scheduler: Waiting for ready tasks" }, | ||||
| 	{ ST_NANOS6_SCHED_SERVING,    "Scheduler: Serving tasks" }, | ||||
| 	{ ST_NANOS6_SCHED_SUBMITTING, "Scheduler: Adding ready tasks" }, | ||||
| 	{ ST_NANOS6_ATTACHED,         "Threading: Attached as external thread" }, | ||||
| 	{ ST_NANOS6_SCHED_ADDING,     "Scheduler: Adding ready tasks" }, | ||||
| 	{ ST_NANOS6_DEP_REG,          "Dependency: Registering" }, | ||||
| 	{ ST_NANOS6_DEP_UNREG,        "Dependency: Unregistering" }, | ||||
| 	{ ST_NANOS6_TASKWAIT,         "Blocking: Taskwait" }, | ||||
| 	{ ST_NANOS6_BLOCKING,         "Blocking: Blocking current task" }, | ||||
| 	{ ST_NANOS6_UNBLOCKING,       "Blocking: Unblocking remote task" }, | ||||
| 	{ ST_NANOS6_WAITFOR,          "Blocking: Wait For" }, | ||||
| 	{ ST_NANOS6_BLK_TASKWAIT,     "Blocking: Taskwait" }, | ||||
| 	{ ST_NANOS6_BLK_BLOCKING,     "Blocking: Blocking current task" }, | ||||
| 	{ ST_NANOS6_BLK_UNBLOCKING,   "Blocking: Unblocking remote task" }, | ||||
| 	{ ST_NANOS6_BLK_WAITFOR,      "Blocking: Wait For" }, | ||||
| 	{ EV_NANOS6_SCHED_SEND,       "EV Scheduler: Send task" }, | ||||
| 	{ EV_NANOS6_SCHED_RECV,       "EV Scheduler: Recv task" }, | ||||
| 	{ EV_NANOS6_SCHED_SELF,       "EV Scheduler: Self-assign task" }, | ||||
|  | ||||
							
								
								
									
										8
									
								
								pcf.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								pcf.h
									
									
									
									
									
								
							| @ -50,6 +50,14 @@ struct pcf_file { | ||||
| 	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_write(struct pcf_file *pcf); | ||||
|  | ||||
| @ -21,4 +21,4 @@ ovni_test(task-types.c MP) | ||||
| ovni_test(blocking.c MP) | ||||
| ovni_test(subsystems.c MP) | ||||
| 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\"") | ||||
|  | ||||
| @ -26,16 +26,19 @@ main(void) | ||||
| 
 | ||||
| 	int us = 500; | ||||
| 	uint32_t typeid = 1; | ||||
| 	uint32_t taskid = 1; | ||||
| 
 | ||||
| 	instr_nanos6_type_create(typeid); | ||||
| 
 | ||||
| 	instr_nanos6_task_create_and_execute(1, typeid); | ||||
| 	instr_nanos6_task_create_and_execute(taskid, typeid); | ||||
| 	usleep(us); | ||||
| 	instr_nanos6_block_enter(1); | ||||
| 	instr_nanos6_block_enter(); | ||||
| 	instr_nanos6_task_pause(taskid); | ||||
| 	usleep(us); | ||||
| 	instr_nanos6_block_exit(1); | ||||
| 	instr_nanos6_task_resume(taskid); | ||||
| 	instr_nanos6_block_exit(); | ||||
| 	usleep(us); | ||||
| 	instr_nanos6_task_end(1); | ||||
| 	instr_nanos6_task_end(taskid); | ||||
| 
 | ||||
| 	instr_end(); | ||||
| 
 | ||||
|  | ||||
| @ -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_0ARG(instr_nanos6_task_create_end, "6TC") | ||||
| 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 | ||||
| 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_2ARG(instr_nanos6_task_block, "6Tb", int32_t, id, int32_t, reason) | ||||
| INSTR_2ARG(instr_nanos6_task_unblock, "6Tu", int32_t, id, int32_t, reason) | ||||
| 
 | ||||
| static inline void | ||||
| instr_nanos6_block_enter(int32_t id) | ||||
| { | ||||
| 	instr_nanos6_task_block(id, 0); | ||||
| } | ||||
| 
 | ||||
| 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_block_enter, "6Bb") | ||||
| INSTR_0ARG(instr_nanos6_block_exit, "6BB") | ||||
| INSTR_0ARG(instr_nanos6_unblock_enter, "6Bb") | ||||
| INSTR_0ARG(instr_nanos6_unblock_exit, "6BB") | ||||
| INSTR_0ARG(instr_nanos6_taskwait_enter, "6Bw") | ||||
| INSTR_0ARG(instr_nanos6_taskwait_exit, "6BW") | ||||
| INSTR_0ARG(instr_nanos6_waitfor_enter, "6Bf") | ||||
| INSTR_0ARG(instr_nanos6_waitfor_exit, "6BF") | ||||
| 
 | ||||
| INSTR_0ARG(instr_nanos6_sched_receive_task, "6Sr") | ||||
| INSTR_0ARG(instr_nanos6_sched_assign_task, "6Ss") | ||||
|  | ||||
| @ -43,16 +43,16 @@ main(void) | ||||
| 	instr_nanos6_sched_submit_exit(); usleep(us); | ||||
| 	instr_nanos6_enter_submit_task(); usleep(us); | ||||
| 	instr_nanos6_exit_submit_task(); usleep(us); | ||||
| 	instr_nanos6_block_enter(taskid); usleep(us); | ||||
| 	instr_nanos6_block_exit(taskid); usleep(us); | ||||
| 	instr_nanos6_waitfor_enter(taskid); usleep(us); | ||||
| 	instr_nanos6_waitfor_exit(taskid); usleep(us); | ||||
| 	instr_nanos6_block_enter(); usleep(us); | ||||
| 	instr_nanos6_block_exit(); usleep(us); | ||||
| 	instr_nanos6_waitfor_enter(); usleep(us); | ||||
| 	instr_nanos6_waitfor_exit(); usleep(us); | ||||
| 	instr_nanos6_register_accesses_enter(); usleep(us); | ||||
| 	instr_nanos6_register_accesses_exit(); usleep(us); | ||||
| 	instr_nanos6_unregister_accesses_enter(); usleep(us); | ||||
| 	instr_nanos6_unregister_accesses_exit(); usleep(us); | ||||
| 	instr_nanos6_task_wait_enter(taskid); usleep(us); | ||||
| 	instr_nanos6_task_wait_exit(taskid); usleep(us); | ||||
| 	instr_nanos6_taskwait_enter(); usleep(us); | ||||
| 	instr_nanos6_taskwait_exit(); usleep(us); | ||||
| 	instr_nanos6_spawn_function_enter(); usleep(us); | ||||
| 	instr_nanos6_spawn_function_exit(); usleep(us); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										3
									
								
								test/rt/nanos6/external-thread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								test/rt/nanos6/external-thread.c
									
									
									
									
									
										Normal 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. */ | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user