Use a hash of the type label to derive the gid

This avoids different processes running tasks with the same type label
to have different colors.
This commit is contained in:
Rodrigo Arias 2022-06-02 15:28:04 +02:00
parent fa9196fd63
commit b0f693360c
4 changed files with 120 additions and 111 deletions

22
emu.h
View File

@ -107,9 +107,16 @@ enum kernel_cs_state {
struct ovni_ethread; struct ovni_ethread;
struct ovni_eproc; struct ovni_eproc;
struct nosv_task_type {
uint32_t id; /* Per-process identifier, same as nOS-V */
uint32_t gid; /* Global identifier computed from the label */
char label[MAX_PCF_LABEL];
UT_hash_handle hh;
};
struct nosv_task { struct nosv_task {
int id; uint32_t id;
int type_id; struct nosv_task_type *type;
struct ovni_ethread *thread; struct ovni_ethread *thread;
enum nosv_task_state state; enum nosv_task_state state;
UT_hash_handle hh; UT_hash_handle hh;
@ -119,13 +126,6 @@ struct nosv_task {
struct nosv_task *prev; struct nosv_task *prev;
}; };
struct nosv_task_type {
int gid; /* Global identifier */
int id; /* Per-process identifier */
char label[MAX_PCF_LABEL];
UT_hash_handle hh;
};
#define MAX_CHAN_STACK 128 #define MAX_CHAN_STACK 128
enum chan_track { enum chan_track {
@ -151,7 +151,7 @@ enum chan {
CHAN_OVNI_FLUSH, CHAN_OVNI_FLUSH,
CHAN_NOSV_TASKID, CHAN_NOSV_TASKID,
CHAN_NOSV_TYPEID, CHAN_NOSV_TYPE,
CHAN_NOSV_APPID, CHAN_NOSV_APPID,
CHAN_NOSV_SUBSYSTEM, CHAN_NOSV_SUBSYSTEM,
CHAN_NOSV_RANK, CHAN_NOSV_RANK,
@ -192,7 +192,7 @@ static const int chan_to_prvtype[CHAN_MAX][CHAN_MAXTYPE] = {
[CHAN_OVNI_CPU] = { 15, -1 }, [CHAN_OVNI_CPU] = { 15, -1 },
[CHAN_OVNI_FLUSH] = { 16, 66 }, [CHAN_OVNI_FLUSH] = { 16, 66 },
[CHAN_NOSV_TASKID] = { 20, 70 }, [CHAN_NOSV_TASKID] = { 20, 70 },
[CHAN_NOSV_TYPEID] = { 21, 71 }, [CHAN_NOSV_TYPE] = { 21, 71 },
[CHAN_NOSV_APPID] = { 22, 72 }, [CHAN_NOSV_APPID] = { 22, 72 },
[CHAN_NOSV_SUBSYSTEM] = { 23, 73 }, [CHAN_NOSV_SUBSYSTEM] = { 23, 73 },
[CHAN_NOSV_RANK] = { 24, 74 }, [CHAN_NOSV_RANK] = { 24, 74 },

View File

@ -49,7 +49,7 @@ hook_init_nosv(struct ovni_emu *emu)
uth = &emu->th_chan; uth = &emu->th_chan;
chan_th_init(th, uth, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NOSV_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
chan_th_init(th, uth, CHAN_NOSV_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock); chan_th_init(th, uth, CHAN_NOSV_RANK, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_th, clock);
@ -68,7 +68,7 @@ hook_init_nosv(struct ovni_emu *emu)
ucpu = &emu->cpu_chan; ucpu = &emu->cpu_chan;
chan_cpu_init(cpu, ucpu, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NOSV_TASKID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NOSV_TYPEID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NOSV_TYPE, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock);
chan_cpu_init(cpu, ucpu, CHAN_NOSV_APPID, CHAN_TRACK_TH_RUNNING, 0, 0, 1, row, prv_cpu, clock); chan_cpu_init(cpu, ucpu, CHAN_NOSV_APPID, 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_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);
@ -80,30 +80,33 @@ hook_init_nosv(struct ovni_emu *emu)
static void static void
pre_task_create(struct ovni_emu *emu) pre_task_create(struct ovni_emu *emu)
{ {
struct nosv_task *task, *p = NULL; uint32_t task_id = emu->cur_ev->payload.u32[0];
uint32_t type_id = emu->cur_ev->payload.u32[1];
/* Ensure the task id is new */
struct nosv_task *task = NULL;
HASH_FIND_INT(emu->cur_proc->tasks, &task_id, task);
if(task != NULL)
die("a task with id %u already exists\n", task_id);
/* Ensure the type exists */
struct nosv_task_type *type = NULL;
HASH_FIND_INT(emu->cur_proc->types, &type_id, type);
if(type == NULL)
die("unknown task type id %u\n", type_id);
task = calloc(1, sizeof(*task)); task = calloc(1, sizeof(*task));
if(task == NULL) if(task == NULL)
{ die("calloc failed\n");
perror("calloc");
abort();
}
task->id = emu->cur_ev->payload.i32[0]; task->id = task_id;
task->type_id = emu->cur_ev->payload.i32[1]; task->type = type;
task->state = TASK_ST_CREATED; task->state = TASK_ST_CREATED;
task->thread = NULL; task->thread = NULL;
/* Ensure the task id is new */
HASH_FIND_INT(emu->cur_proc->tasks, &task->id, p);
if(p != NULL)
{
err("A task with id %d already exists\n", p->id);
abort();
}
/* Add the new task to the hash table */ /* Add the new task to the hash table */
HASH_ADD_INT(emu->cur_proc->tasks, id, task); HASH_ADD_INT(emu->cur_proc->tasks, id, task);
@ -113,16 +116,14 @@ pre_task_create(struct ovni_emu *emu)
static void static void
pre_task_execute(struct ovni_emu *emu) pre_task_execute(struct ovni_emu *emu)
{ {
struct nosv_task *task, *top; struct nosv_task *top = emu->cur_thread->task_stack;
int taskid; uint32_t taskid = emu->cur_ev->payload.u32[0];
top = emu->cur_thread->task_stack;
taskid = emu->cur_ev->payload.i32[0];
struct nosv_task *task = NULL;
HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task); HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %d\n", taskid); die("cannot find task with id %u\n", taskid);
if(task->state != TASK_ST_CREATED) if(task->state != TASK_ST_CREATED)
die("task state is not created\n"); die("task state is not created\n");
@ -134,7 +135,7 @@ pre_task_execute(struct ovni_emu *emu)
die("thread state is not running\n"); die("thread state is not running\n");
if(top == task) if(top == task)
die("thread already has assigned task %d\n", taskid); die("thread already has assigned task %u\n", taskid);
if(top && top->state != TASK_ST_RUNNING) if(top && 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");
@ -144,22 +145,20 @@ pre_task_execute(struct ovni_emu *emu)
DL_PREPEND(emu->cur_thread->task_stack, task); DL_PREPEND(emu->cur_thread->task_stack, task);
dbg("task id=%d runs now\n", task->id); dbg("task id=%u runs now\n", task->id);
} }
static void static void
pre_task_pause(struct ovni_emu *emu) pre_task_pause(struct ovni_emu *emu)
{ {
struct nosv_task *task, *top; struct nosv_task *top = emu->cur_thread->task_stack;
int taskid; uint32_t taskid = emu->cur_ev->payload.u32[0];
top = emu->cur_thread->task_stack;
taskid = emu->cur_ev->payload.i32[0];
struct nosv_task *task = NULL;
HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task); HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %d\n", taskid); die("cannot find task with id %u\n", taskid);
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");
@ -181,16 +180,14 @@ pre_task_pause(struct ovni_emu *emu)
static void static void
pre_task_resume(struct ovni_emu *emu) pre_task_resume(struct ovni_emu *emu)
{ {
struct nosv_task *task, *top; struct nosv_task *top = emu->cur_thread->task_stack;
int taskid; uint32_t taskid = emu->cur_ev->payload.u32[0];
top = emu->cur_thread->task_stack;
taskid = emu->cur_ev->payload.i32[0];
struct nosv_task *task = NULL;
HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task); HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %d\n", taskid); die("cannot find task with id %u\n", taskid);
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");
@ -212,16 +209,14 @@ pre_task_resume(struct ovni_emu *emu)
static void static void
pre_task_end(struct ovni_emu *emu) pre_task_end(struct ovni_emu *emu)
{ {
struct nosv_task *task, *top; struct nosv_task *top = emu->cur_thread->task_stack;
int taskid; uint32_t taskid = emu->cur_ev->payload.u32[0];
top = emu->cur_thread->task_stack;
taskid = emu->cur_ev->payload.i32[0];
struct nosv_task *task = NULL;
HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task); HASH_FIND_INT(emu->cur_proc->tasks, &taskid, task);
if(task == NULL) if(task == NULL)
die("cannot find task with id %d\n", taskid); die("cannot find task with id %u\n", taskid);
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");
@ -250,7 +245,7 @@ pre_task_not_running(struct ovni_emu *emu)
th = emu->cur_thread; th = emu->cur_thread;
chan_set(&th->chan[CHAN_NOSV_TASKID], 0); chan_set(&th->chan[CHAN_NOSV_TASKID], 0);
chan_set(&th->chan[CHAN_NOSV_TYPEID], 0); chan_set(&th->chan[CHAN_NOSV_TYPE], 0);
chan_set(&th->chan[CHAN_NOSV_APPID], 0); chan_set(&th->chan[CHAN_NOSV_APPID], 0);
if(emu->cur_loom->rank_enabled) if(emu->cur_loom->rank_enabled)
@ -271,14 +266,14 @@ pre_task_running(struct ovni_emu *emu, struct nosv_task *task)
if(task->id <= 0) if(task->id <= 0)
die("task id must be positive\n"); die("task id must be positive\n");
if(task->type_id <= 0) if(task->type->gid <= 0)
die("task type id must be positive\n"); die("task type gid must be positive\n");
if(proc->appid <= 0) if(proc->appid <= 0)
die("app id must be positive\n"); die("app id must be positive\n");
chan_set(&th->chan[CHAN_NOSV_TASKID], task->id); chan_set(&th->chan[CHAN_NOSV_TASKID], task->id);
chan_set(&th->chan[CHAN_NOSV_TYPEID], task->type_id); chan_set(&th->chan[CHAN_NOSV_TYPE], task->type->gid);
chan_set(&th->chan[CHAN_NOSV_APPID], proc->appid); chan_set(&th->chan[CHAN_NOSV_APPID], proc->appid);
if(emu->cur_loom->rank_enabled) if(emu->cur_loom->rank_enabled)
@ -304,7 +299,7 @@ pre_task_switch(struct ovni_emu *emu, struct nosv_task *prev_task,
if(next_task->id <= 0) if(next_task->id <= 0)
die("next task id must be positive\n"); die("next task id must be positive\n");
if(next_task->type_id <= 0) if(next_task->type->gid <= 0)
die("next task type id must be positive\n"); die("next task type id must be positive\n");
chan_set(&th->chan[CHAN_NOSV_TASKID], next_task->id); chan_set(&th->chan[CHAN_NOSV_TASKID], next_task->id);
@ -312,9 +307,12 @@ pre_task_switch(struct ovni_emu *emu, struct nosv_task *prev_task,
/* No need to change the rank, as we can only switch to tasks of /* No need to change the rank, as we can only switch to tasks of
* the same loom (with same rank) */ * the same loom (with same rank) */
/* Only emit the new type if necessary */ /* FIXME: We should emit a PRV event even if we are switching to
if(prev_task->type_id != next_task->type_id) * the same type event, to mark the end of the current task. For
chan_set(&th->chan[CHAN_NOSV_TYPEID], next_task->type_id); * 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);
} }
static void static void
@ -350,13 +348,17 @@ pre_task(struct ovni_emu *emu)
} }
static uint32_t static uint32_t
get_task_type_gid(struct ovni_emu *emu, struct ovni_eproc *proc, uint32_t id) get_task_type_gid(const char *label)
{ {
/* Don't use emu->cur_proc, so we can use it at any point */ uint32_t gid;
uint32_t gid = id * emu->total_nprocs + proc->gindex;
HASH_VALUE(label, strlen(label), gid);
/* Use non-negative values */
gid &= 0x7FFFFFFF;
if (gid == 0) if (gid == 0)
die("invalid global task type id %d\n", gid); gid++;
return gid; return gid;
} }
@ -402,7 +404,7 @@ pre_type_create(struct ovni_emu *emu)
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);
type->gid = get_task_type_gid(emu, emu->cur_proc, type->id); 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 label too long: %s\n", label);
@ -604,21 +606,22 @@ hook_pre_nosv(struct ovni_emu *emu)
static void static void
create_pcf_task_types(struct ovni_eproc *proc, struct pcf_type *pcftype) create_pcf_task_types(struct ovni_eproc *proc, struct pcf_type *pcftype)
{ {
char buf[MAX_PCF_LABEL];
/* Emit types for all task types */ /* Emit types for all task types */
struct nosv_task_type *tt; struct nosv_task_type *tt;
for(tt = proc->types; tt != NULL; tt=tt->hh.next) for(tt = proc->types; tt != NULL; tt=tt->hh.next)
{ {
/* Use a unique identifier for the task types */ struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
int value = tt->gid; if(pcfvalue != NULL)
int n = snprintf(buf, MAX_PCF_LABEL, "%s (%d)", {
tt->label, tt->id); /* Ensure the label is the same, so we know that
* no collision occurred */
if(strcmp(pcfvalue->label, tt->label) != 0)
die("collision occurred in task type labels\n");
else
continue;
}
if(n >= MAX_PCF_LABEL) pcf_add_value(pcftype, tt->gid, tt->label);
die("generated label too long: %s\n", buf);
pcf_add_value(pcftype, value, buf);
} }
} }
@ -629,7 +632,7 @@ hook_end_nosv(struct ovni_emu *emu)
for(enum chan_type ct = 0; ct < CHAN_MAXTYPE; ct++) for(enum chan_type ct = 0; ct < CHAN_MAXTYPE; ct++)
{ {
struct pcf_file *pcf = &emu->pcf[ct]; struct pcf_file *pcf = &emu->pcf[ct];
int typeid = chan_to_prvtype[CHAN_NOSV_TYPEID][ct]; int typeid = chan_to_prvtype[CHAN_NOSV_TYPE][ct];
struct pcf_type *pcftype = pcf_find_type(pcf, typeid); struct pcf_type *pcftype = pcf_find_type(pcf, typeid);
for(size_t i = 0; i < emu->trace.nlooms; i++) for(size_t i = 0; i < emu->trace.nlooms; i++)

68
pcf.c
View File

@ -188,7 +188,7 @@ struct pcf_value_label (*pcf_chan_value_labels[CHAN_MAX])[] = {
[CHAN_OVNI_FLUSH] = &ovni_flush_values, [CHAN_OVNI_FLUSH] = &ovni_flush_values,
[CHAN_NOSV_TASKID] = &default_values, [CHAN_NOSV_TASKID] = &default_values,
[CHAN_NOSV_TYPEID] = &default_values, [CHAN_NOSV_TYPE] = &default_values,
[CHAN_NOSV_APPID] = &default_values, [CHAN_NOSV_APPID] = &default_values,
[CHAN_NOSV_SUBSYSTEM] = &nosv_ss_values, [CHAN_NOSV_SUBSYSTEM] = &nosv_ss_values,
[CHAN_NOSV_RANK] = &default_values, [CHAN_NOSV_RANK] = &default_values,
@ -212,7 +212,7 @@ char *pcf_chan_name[CHAN_MAX] = {
[CHAN_OVNI_FLUSH] = "Flushing state", [CHAN_OVNI_FLUSH] = "Flushing state",
[CHAN_NOSV_TASKID] = "nOS-V TaskID", [CHAN_NOSV_TASKID] = "nOS-V TaskID",
[CHAN_NOSV_TYPEID] = "nOS-V task TypeID", [CHAN_NOSV_TYPE] = "nOS-V task type",
[CHAN_NOSV_APPID] = "nOS-V task AppID", [CHAN_NOSV_APPID] = "nOS-V task AppID",
[CHAN_NOSV_SUBSYSTEM] = "nOS-V subsystem", [CHAN_NOSV_SUBSYSTEM] = "nOS-V subsystem",
[CHAN_NOSV_RANK] = "MPI rank", [CHAN_NOSV_RANK] = "MPI rank",
@ -244,7 +244,7 @@ int pcf_chan_suffix[CHAN_MAX][CHAN_MAXTYPE] = {
[CHAN_OVNI_FLUSH] = { CUR_TH, RUN_TH }, [CHAN_OVNI_FLUSH] = { CUR_TH, RUN_TH },
[CHAN_NOSV_TASKID] = { RUN_TH, RUN_TH }, [CHAN_NOSV_TASKID] = { RUN_TH, RUN_TH },
[CHAN_NOSV_TYPEID] = { RUN_TH, RUN_TH }, [CHAN_NOSV_TYPE] = { RUN_TH, RUN_TH },
[CHAN_NOSV_APPID] = { RUN_TH, RUN_TH }, [CHAN_NOSV_APPID] = { RUN_TH, RUN_TH },
[CHAN_NOSV_SUBSYSTEM] = { ACT_TH, RUN_TH }, [CHAN_NOSV_SUBSYSTEM] = { ACT_TH, RUN_TH },
[CHAN_NOSV_RANK] = { RUN_TH, RUN_TH }, [CHAN_NOSV_RANK] = { RUN_TH, RUN_TH },
@ -385,30 +385,38 @@ pcf_find_type(struct pcf_file *pcf, int type_id)
struct pcf_type * struct pcf_type *
pcf_add_type(struct pcf_file *pcf, int type_id, const char *label) pcf_add_type(struct pcf_file *pcf, int type_id, const char *label)
{ {
struct pcf_type *type; struct pcf_type *pcftype;
type = pcf_find_type(pcf, type_id); pcftype = pcf_find_type(pcf, type_id);
if(type != NULL) if(pcftype != NULL)
die("PCF type %d already defined\n", type_id); die("PCF type %d already defined\n", type_id);
type = calloc(1, sizeof(struct pcf_type)); pcftype = calloc(1, sizeof(struct pcf_type));
if(pcftype == NULL)
if(type == NULL)
die("calloc failed: %s\n", strerror(errno)); die("calloc failed: %s\n", strerror(errno));
type->id = type_id; pcftype->id = type_id;
type->values = NULL; pcftype->values = NULL;
type->nvalues = 0; pcftype->nvalues = 0;
if(snprintf(type->label, MAX_PCF_LABEL,
"%s", label) >= MAX_PCF_LABEL)
{
die("PCF label too long\n");
}
HASH_ADD_INT(pcf->types, id, type); int len = snprintf(pcftype->label, MAX_PCF_LABEL, "%s", label);
if(len >= MAX_PCF_LABEL)
die("PCF type label too long\n");
return type; HASH_ADD_INT(pcf->types, id, pcftype);
return pcftype;
}
struct pcf_value *
pcf_find_value(struct pcf_type *type, int value)
{
struct pcf_value *pcfvalue;
HASH_FIND_INT(type->values, &value, pcfvalue);
return pcfvalue;
} }
/** Adds a new value to the given pcf_type. The label can be disposed /** Adds a new value to the given pcf_type. The label can be disposed
@ -419,30 +427,26 @@ pcf_add_type(struct pcf_file *pcf, int type_id, const char *label)
struct pcf_value * struct pcf_value *
pcf_add_value(struct pcf_type *type, int value, const char *label) pcf_add_value(struct pcf_type *type, int value, const char *label)
{ {
struct pcf_value *pv; struct pcf_value *pcfvalue = pcf_find_value(type, value);
HASH_FIND_INT(type->values, &value, pv); if(pcfvalue != NULL)
if(pv != NULL)
die("PCF value %d already in type %d\n", value, type->id); die("PCF value %d already in type %d\n", value, type->id);
pv = calloc(1, sizeof(struct pcf_value)); pcfvalue = calloc(1, sizeof(struct pcf_value));
if(pcfvalue == NULL)
if(pv == NULL)
die("calloc failed: %s\n", strerror(errno)); die("calloc failed: %s\n", strerror(errno));
pv->value = value; pcfvalue->value = value;
int len = snprintf(pv->label, MAX_PCF_LABEL, "%s", label);
int len = snprintf(pcfvalue->label, MAX_PCF_LABEL, "%s", label);
if(len >= MAX_PCF_LABEL) if(len >= MAX_PCF_LABEL)
die("PCF label too long\n"); die("PCF value label too long\n");
HASH_ADD_INT(type->values, value, pv); HASH_ADD_INT(type->values, value, pcfvalue);
type->nvalues++; type->nvalues++;
return pv; return pcfvalue;
} }
/** Writes the defined event and values to the PCF file. */ /** Writes the defined event and values to the PCF file. */

2
pcf.h
View File

@ -64,4 +64,6 @@ struct pcf_type *pcf_add_type(struct pcf_file *pcf, int type_id,
struct pcf_value *pcf_add_value(struct pcf_type *type, int value, struct pcf_value *pcf_add_value(struct pcf_type *type, int value,
const char *label); const char *label);
struct pcf_value *pcf_find_value(struct pcf_type *type, int value);
#endif /* OVNI_PCF_H */ #endif /* OVNI_PCF_H */