2022-09-19 12:39:02 +02:00
|
|
|
/* Copyright (c) 2022 Barcelona Supercomputing Center (BSC)
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
#include "uthash.h"
|
|
|
|
#include "utlist.h"
|
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
#include "chan.h"
|
2022-07-01 17:54:18 +02:00
|
|
|
#include "emu.h"
|
|
|
|
#include "emu_task.h"
|
2022-09-29 15:34:44 +02:00
|
|
|
#include "ovni.h"
|
2022-07-01 17:54:18 +02:00
|
|
|
#include "prv.h"
|
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
struct task *
|
|
|
|
task_find(struct task *tasks, uint32_t task_id)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
|
|
|
struct task *task = NULL;
|
2022-09-01 17:02:02 +02:00
|
|
|
HASH_FIND_INT(tasks, &task_id, task);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
return task;
|
|
|
|
}
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
struct task_type *
|
|
|
|
task_type_find(struct task_type *types, uint32_t type_id)
|
|
|
|
{
|
2022-07-01 17:54:18 +02:00
|
|
|
struct task_type *type = NULL;
|
2022-09-01 17:02:02 +02:00
|
|
|
HASH_FIND_INT(types, &type_id, type);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
void
|
2022-09-21 12:59:31 +02:00
|
|
|
task_create(struct ovni_emu *emu, struct task_info *info,
|
2022-09-29 15:34:44 +02:00
|
|
|
uint32_t type_id, uint32_t task_id)
|
2022-09-01 17:02:02 +02:00
|
|
|
{
|
|
|
|
/* Ensure the task id is new */
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task_find(info->tasks, task_id) != NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot create task: task_id %u already exists\n",
|
2022-09-29 15:34:44 +02:00
|
|
|
task_id);
|
2022-09-01 17:02:02 +02:00
|
|
|
|
|
|
|
/* Ensure the type exists */
|
|
|
|
struct task_type *type = task_type_find(info->types, type_id);
|
2022-09-29 15:34:44 +02:00
|
|
|
if (type == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot create task: unknown type id %u\n", type_id);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
struct task *task = calloc(1, sizeof(struct task));
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task == NULL)
|
2022-07-01 17:54:18 +02:00
|
|
|
die("calloc failed\n");
|
|
|
|
|
|
|
|
task->id = task_id;
|
|
|
|
task->type = type;
|
|
|
|
task->state = TASK_ST_CREATED;
|
|
|
|
task->thread = NULL;
|
|
|
|
|
|
|
|
/* Add the new task to the hash table */
|
2022-09-01 17:02:02 +02:00
|
|
|
HASH_ADD_INT(info->tasks, id, task);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
dbg("new task created id=%d\n", task->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-21 12:59:31 +02:00
|
|
|
task_execute(struct ovni_emu *emu,
|
2022-09-29 15:34:44 +02:00
|
|
|
struct task_stack *stack, struct task *task)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot execute: task is NULL\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->state != TASK_ST_CREATED)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot execute task %u: state is not created\n", task->id);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->thread != NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task already has a thread assigned\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread->state != TH_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread state is not running\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->top == task)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread already has assigned task %u\n", task->id);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->top && stack->top->state != TASK_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot execute a nested task from a non-running task\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
task->state = TASK_ST_RUNNING;
|
2022-09-01 17:02:02 +02:00
|
|
|
task->thread = stack->thread;
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
DL_PREPEND(stack->tasks, task);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
dbg("task id=%u runs now\n", task->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-21 12:59:31 +02:00
|
|
|
task_pause(struct ovni_emu *emu,
|
2022-09-29 15:34:44 +02:00
|
|
|
struct task_stack *stack, struct task *task)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot pause: task is NULL\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->state != TASK_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot pause: task state is not running\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->thread == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot pause: task has no thread assigned\n");
|
2022-09-01 17:02:02 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread->state != TH_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot pause: thread state is not running\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->top != task)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread has assigned a different task\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread != task->thread)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task is assigned to a different thread\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
task->state = TASK_ST_PAUSED;
|
|
|
|
|
|
|
|
dbg("task id=%d pauses\n", task->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-21 12:59:31 +02:00
|
|
|
task_resume(struct ovni_emu *emu,
|
2022-09-29 15:34:44 +02:00
|
|
|
struct task_stack *stack, struct task *task)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot resume: task is NULL\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->state != TASK_ST_PAUSED)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task state is not paused\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->thread == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot resume: task has no thread assigned\n");
|
2022-09-01 17:02:02 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread->state != TH_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread is not running\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->top != task)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread has assigned a different task\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread != task->thread)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task is assigned to a different thread\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
task->state = TASK_ST_RUNNING;
|
|
|
|
|
|
|
|
dbg("task id=%d resumes\n", task->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-21 12:59:31 +02:00
|
|
|
task_end(struct ovni_emu *emu,
|
2022-09-29 15:34:44 +02:00
|
|
|
struct task_stack *stack, struct task *task)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot end: task is NULL\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->state != TASK_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task state is not running\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task->thread == NULL)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot end: task has no thread assigned\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread->state != TH_ST_RUNNING)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "cannot end task: thread is not running\n");
|
2022-09-01 17:02:02 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->top != task)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "thread has assigned a different task\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (stack->thread != task->thread)
|
2022-09-21 12:59:31 +02:00
|
|
|
edie(emu, "task is assigned to a different thread\n");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
task->state = TASK_ST_DEAD;
|
|
|
|
|
|
|
|
/* Don't unset the thread from the task, as it will be used
|
|
|
|
* later to ensure we switch to tasks of the same thread. */
|
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
DL_DELETE(stack->tasks, task);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
dbg("task id=%d ends\n", task->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
get_task_type_gid(const char *label)
|
|
|
|
{
|
|
|
|
uint32_t gid;
|
|
|
|
|
|
|
|
HASH_VALUE(label, strlen(label), gid);
|
|
|
|
|
|
|
|
/* Use non-negative values */
|
|
|
|
gid &= 0x7FFFFFFF;
|
|
|
|
|
2022-09-20 14:43:20 +02:00
|
|
|
/* Avoid bad colors for "Unlabeled0" */
|
|
|
|
gid += 123;
|
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (gid == 0)
|
2022-07-01 17:54:18 +02:00
|
|
|
gid++;
|
|
|
|
|
|
|
|
return gid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-01 17:02:02 +02:00
|
|
|
task_type_create(struct task_info *info, uint32_t type_id, const char *label)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
|
|
|
struct task_type *type;
|
|
|
|
/* Ensure the type id is new */
|
2022-09-01 17:02:02 +02:00
|
|
|
HASH_FIND_INT(info->types, &type_id, type);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (type != NULL)
|
2022-09-01 17:02:02 +02:00
|
|
|
die("a task type with id %u already exists\n", type_id);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
type = calloc(1, sizeof(*type));
|
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (type == NULL)
|
2022-09-01 17:02:02 +02:00
|
|
|
die("calloc failed");
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-01 17:02:02 +02:00
|
|
|
type->id = type_id;
|
2022-07-01 17:54:18 +02:00
|
|
|
|
2022-09-29 15:34:44 +02:00
|
|
|
if (type->id == 0)
|
2022-07-01 17:54:18 +02:00
|
|
|
die("invalid task type id %d\n", type->id);
|
|
|
|
|
|
|
|
type->gid = get_task_type_gid(label);
|
|
|
|
int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
|
2022-09-29 15:34:44 +02:00
|
|
|
if (n >= MAX_PCF_LABEL)
|
2022-09-01 17:02:02 +02:00
|
|
|
die("task type label too long: %s\n", label);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
/* Add the new task type to the hash table */
|
2022-09-01 17:02:02 +02:00
|
|
|
HASH_ADD_INT(info->types, id, type);
|
2022-07-01 17:54:18 +02:00
|
|
|
|
|
|
|
dbg("new task type created id=%d label=%s\n", type->id,
|
2022-09-29 15:34:44 +02:00
|
|
|
type->label);
|
2022-07-01 17:54:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-01 17:02:02 +02:00
|
|
|
task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
|
|
|
/* Emit types for all task types */
|
|
|
|
struct task_type *tt;
|
2022-09-29 15:34:44 +02:00
|
|
|
for (tt = types; tt != NULL; tt = tt->hh.next) {
|
2022-07-01 17:54:18 +02:00
|
|
|
struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
|
2022-09-29 15:34:44 +02:00
|
|
|
if (pcfvalue != NULL) {
|
2022-07-01 17:54:18 +02:00
|
|
|
/* Ensure the label is the same, so we know that
|
|
|
|
* no collision occurred */
|
2022-09-29 15:34:44 +02:00
|
|
|
if (strcmp(pcfvalue->label, tt->label) != 0)
|
2022-07-01 17:54:18 +02:00
|
|
|
die("collision occurred in task type labels\n");
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcf_add_value(pcftype, tt->gid, tt->label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct task *
|
2022-09-01 17:02:02 +02:00
|
|
|
task_get_running(struct task_stack *stack)
|
2022-07-01 17:54:18 +02:00
|
|
|
{
|
2022-09-01 17:02:02 +02:00
|
|
|
struct task *task = stack->top;
|
2022-09-29 15:34:44 +02:00
|
|
|
if (task && task->state == TASK_ST_RUNNING)
|
2022-07-01 17:54:18 +02:00
|
|
|
return task;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|