From 25a1301bc18dcb811f69b29861ad928369b12713 Mon Sep 17 00:00:00 2001 From: Armin Luntzer <armin.luntzer@univie.ac.at> Date: Mon, 20 Mar 2017 17:12:13 +0100 Subject: [PATCH] add concept of data processing network --- include/data_proc_net.h | 32 +++ include/data_proc_task.h | 3 +- include/data_proc_tracker.h | 32 ++- init/main.c | 18 ++ lib/Makefile | 1 + lib/data_proc_net.c | 356 +++++++++++++++++++++++++ lib/data_proc_task.c | 7 +- lib/data_proc_tracker.c | 148 +++++++++-- samples/Kconfig | 5 + samples/Makefile | 1 + samples/proc_chain/Makefile | 27 ++ samples/proc_chain/proc_chain_demo.c | 374 +++++++++++++++++++++++++++ 12 files changed, 977 insertions(+), 27 deletions(-) create mode 100644 include/data_proc_net.h create mode 100644 lib/data_proc_net.c create mode 100644 samples/proc_chain/Makefile create mode 100644 samples/proc_chain/proc_chain_demo.c diff --git a/include/data_proc_net.h b/include/data_proc_net.h new file mode 100644 index 0000000..f7a5dab --- /dev/null +++ b/include/data_proc_net.h @@ -0,0 +1,32 @@ +/** + * @file include/data_proc_net.h + */ + +#ifndef _DATA_PROC_NET_H_ +#define _DATA_PROC_NET_H_ + +#include <kernel/types.h> +#include <list.h> +#include <data_proc_tracker.h> + + + +/* these are the reserved processing node identifiers */ +#define PN_OP_NODE_IN 0xFFFFFFFF +#define PN_OP_NODE_OUT 0x00000000 + + +struct proc_net; + +int pt_track_execute_next(struct proc_tracker *pt); +void pn_input_task(struct proc_net *pn, struct proc_task *t); +int pn_process_next(struct proc_net *pn); +int pn_process_inputs(struct proc_net *pn); + +int pn_create_output_node(struct proc_net *pn, + int (*op)(unsigned long op_code, struct proc_task *)); +int pn_add_node(struct proc_net *pn, struct proc_tracker *pt); +struct proc_net *pn_create(size_t n_in_tasks_crit, size_t n_out_tasks_crit); +void pn_destroy(struct proc_net *pn); + +#endif /* _DATA_PROC_NET_H_ */ diff --git a/include/data_proc_task.h b/include/data_proc_task.h index 6145283..a72542e 100644 --- a/include/data_proc_task.h +++ b/include/data_proc_task.h @@ -5,7 +5,8 @@ #ifndef _DATA_PROC_TASK_H_ #define _DATA_PROC_TASK_H_ - +#include <kernel/types.h> +#include <list.h> struct proc_task { diff --git a/include/data_proc_tracker.h b/include/data_proc_tracker.h index c3a391b..e8ee2e9 100644 --- a/include/data_proc_tracker.h +++ b/include/data_proc_tracker.h @@ -5,20 +5,42 @@ #ifndef _DATA_PROC_TRACKER_H_ #define _DATA_PROC_TRACKER_H_ +#include <kernel/types.h> +#include <list.h> +#include <data_proc_task.h> -struct proc_tracker; +struct proc_tracker { + struct list_head tasks; + size_t n_tasks; + size_t n_tasks_crit; + unsigned long op_code; + + int (*op)(unsigned long op_code, struct proc_task *); + + + struct list_head node; /* to be used for external tracking */ +}; + + +unsigned long pt_track_get_id(struct proc_tracker *pt); + int pt_track_get_usage(struct proc_tracker *pt); +int pt_track_level_critical(struct proc_tracker *pt); + int pt_track_put(struct proc_tracker *pt, struct proc_task *t); -struct proc_task pt_track_get(struct proc_tracker *pt); +int pt_track_put_force(struct proc_tracker *pt, struct proc_task *t); -void pt_track_sort_seq(struct proc_tracker *pt) +struct proc_task *pt_track_get(struct proc_tracker *pt); -struct proc_tracker *pt_track_create(size_t nmemb); +void pt_track_sort_seq(struct proc_tracker *pt); -int pt_track_expand(struct proc_tracker *pt, size_t nmemb); +struct proc_tracker *pt_track_create(int (*op)(unsigned long op_code, + struct proc_task *), + unsigned long op_code, + size_t n_tasks_crit); void pt_track_destroy(struct proc_tracker *pt); diff --git a/init/main.c b/init/main.c index 6819227..d5136ab 100644 --- a/init/main.c +++ b/init/main.c @@ -17,6 +17,7 @@ #include <kernel/sysctl.h> + #define MSG "MAIN: " void module_image_load_embedded(void); @@ -34,6 +35,12 @@ static void kernel_init(void) } + + + + + + #ifdef CONFIG_TARGET_COMPILER_BOOT_CODE int main(void) @@ -41,6 +48,7 @@ int main(void) void *addr; struct elf_module m; + kernel_init(); /* load the embedded AR image */ @@ -80,8 +88,18 @@ int main(void) modules_list_loaded(); #endif + + + + + + + +#if 0 /* load all available Xentium kernels from the embedded modules image */ module_load_xen_kernels(); + while(1); +#endif return 0; } diff --git a/lib/Makefile b/lib/Makefile index 2405f0c..e45e8cf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,3 +7,4 @@ lib-y += string.o lib-y += elf.o lib-y += data_proc_tracker.o lib-y += data_proc_task.o +lib-y += data_proc_net.o diff --git a/lib/data_proc_net.c b/lib/data_proc_net.c new file mode 100644 index 0000000..543ce06 --- /dev/null +++ b/lib/data_proc_net.c @@ -0,0 +1,356 @@ +/** + * @file lib/data_proc_net.c + * + * + * This is a data processing network + * + */ + +#include <kernel/printk.h> +#include <kernel/kmem.h> +#include <kernel/kernel.h> + +#include <errno.h> + +#include <data_proc_net.h> + + +struct proc_net { + struct proc_tracker *in; + struct proc_tracker *out; + + struct list_head nodes; + + size_t n; +}; + + +static int pn_dummy_op(unsigned long op_code, struct proc_task *pt) +{ + return 0; +} + +/** + * @brief locate a tracker by op code + * + * @returns tracker or NULL if not found + * + * @note this is not very efficient, especially for large numbers of nodes... + */ + +static struct proc_tracker *pn_find_tracker(struct proc_net *pn, + unsigned long op_code) +{ + struct proc_tracker *p_elem; + + + list_for_each_entry(p_elem, &pn->nodes, node) + if (p_elem->op_code == op_code) + return p_elem; + + + return NULL; +} + + + +int pn_process_next(struct proc_net *pn) +{ + struct proc_task *t = NULL; + struct proc_tracker *pt; + static struct proc_tracker *pt_out; + + unsigned long op; + + + if (!pt_out) + pt = list_entry(pn->nodes.next, struct proc_tracker, node); + + /* locate the first tracker that holds at least one task and process it + * ideally, this would be sorted so that the most critical tracker + * was the first item + * XXX implement that sometime... + */ + + list_for_each_entry(pt, &pn->nodes, node) { + + t = pt_track_get(pt); + + if (t) + break; + } + + + while (1) { + if (!t) + break; /* nothing to do */ + + /* current step's op code */ + op = pt_get_pend_step_op_code(t); + + /* XXX maybe eval return code, e.g. for signalling abort of + * current task node processing */ + pt->op(op, t); + + + pt_next_pend_step_done(t); + + /* next steps's op code */ + op = pt_get_pend_step_op_code(t); + + if (!op) { + pt_track_put(pn->out, t); + } else if (pt_out->op_code != op) { + pt_out = pn_find_tracker(pn, op); + + /* this should not happen */ + if (!pt_out) { + pr_crit("Error, no such op code, " + "destroying task\n"); + + pt_destroy(t); + + /* reset */ + pt_out = list_entry(pn->nodes.next, + struct proc_tracker, node); + + t = pt_track_get(pt); + continue; + } + } + + /* move to next matching node */ + pt_track_put(pt_out, t); + + t = pt_track_get(pt); + } + + /* move processing task to end of queue */ + /* XXX should insert that based on critical level/fill state */ + if (pt) + list_move_tail(&pt->node, &pn->nodes); + + + return 0; +} + + + + + +/** + * @brief add a task to the input of the network + */ + +void pn_input_task(struct proc_net *pn, struct proc_task *t) +{ + if (!pn) + return; + + if (!t) + return; + + BUG_ON(pt_track_put_force(pn->in, t)); +} + + +/** + * @brief assign input tasks to their first processing node + * + * @returns 0 or -1 on error (e.g. no processing nodes defined) + */ + +int pn_process_inputs(struct proc_net *pn) +{ + unsigned long op; + + struct proc_task *t; + static struct proc_tracker *pt; + + + if (list_empty(&pn->nodes)) + return -1; + + if (!pt) + pt = list_entry(pn->nodes.next, struct proc_tracker, node); + + while (1) { + t = pt_track_get(pn->in); + + if (!t) + break; + + op = pt_get_pend_step_op_code(t); + + if (pt->op_code != op) { + pt = pn_find_tracker(pn, op); + if (!pt) { + pr_crit("Error, no such op code, " + "destroying task\n"); + + pt_destroy(t); + + /* reset */ + pt = list_entry(pn->nodes.next, + struct proc_tracker, node); + + t = pt_track_get(pt); + continue; + } + } + + BUG_ON(pt_track_put(pt, t)); + } + + + return 0; +} + + +/** + * @brief create an output node of the network + * + * @returns 0 on success, -ENOMEM on alloc error + * + * @note this destroys the previous output node on success only, otherwise the + * original node is left intact + */ + +int pn_create_output_node(struct proc_net *pn, + int (*op)(unsigned long op_code, struct proc_task *)) + +{ + struct proc_tracker *pt; + + + pt = pt_track_create(op, PN_OP_NODE_OUT, 1); + + if (!pt) + return -ENOMEM; + + if (pn->out) + pt_track_destroy(pn->out); + + return 0; +} + + +/** + * @brief add a tracker node to a processing network + * + * @returns 0 on success, -EINVAL on error + */ + +int pn_add_node(struct proc_net *pn, struct proc_tracker *pt) + +{ + if (!pn) + return -EINVAL; + + if (!pt) + return -EINVAL; + + if (pt->op_code == PN_OP_NODE_IN) + return -EINVAL; + + if (pt->op_code == PN_OP_NODE_OUT) + return -EINVAL; + + + list_add_tail(&pt->node, &pn->nodes); + + pn->n++; + + return 0; +} + + +/** + * @brief create a processing network with an input and output node + * + * @param n_input_tasks_critical critical level of input task + * @param n_output_tasks_critical critical level of output task + * + * @return processing network or NULL on error + * + * @note this creates a default output node that does nothing and just + * accumulates tasks + */ + +struct proc_net *pn_create(size_t n_in_tasks_crit, size_t n_out_tasks_crit) +{ + struct proc_net *pn; + + + if (!n_in_tasks_crit) + return NULL; + + if (!n_out_tasks_crit) + return NULL; + + pn = (struct proc_net *) kzalloc(sizeof(struct proc_net)); + + if (!pn) + goto error; + + + /* the input node just accepts tasks and distributes them to the + * appropriate trackers in the network + */ + pn->in = pt_track_create(pn_dummy_op, PN_OP_NODE_IN, 1); + + if (!pn->in) + goto cleanup; + + /* create a default output node that does nothing */ + pn->out = pt_track_create(pn_dummy_op, PN_OP_NODE_OUT, 1); + if (!pn->out) + goto cleanup; + + + INIT_LIST_HEAD(&pn->nodes); + + + return pn; + +cleanup: + pt_track_destroy(pn->in); + pt_track_destroy(pn->out); + + kfree(pn); + +error: + return NULL; +} + + +/** + * @brief destroy a processing network + * + * @param pn a struct proc_net + * + * + * @note the data pointers in the processing tasks are untouched, + * see also pt_destroy() + */ + +void pn_destroy(struct proc_net *pn) +{ + struct proc_tracker *p_elem; + struct proc_tracker *p_tmp; + + + if (!pn) + return; + + list_for_each_entry_safe(p_elem, p_tmp, &pn->nodes, node) { + list_del(&p_elem->node); + pt_track_destroy(p_elem); + } + + + pt_track_destroy(pn->in); + pt_track_destroy(pn->out); + + kfree(pn); +} diff --git a/lib/data_proc_task.c b/lib/data_proc_task.c index 33e3966..6f51742 100644 --- a/lib/data_proc_task.c +++ b/lib/data_proc_task.c @@ -40,10 +40,10 @@ #include <kernel/types.h> #include <kernel/kmem.h> #include <errno.h> -#include <list.h> #include <data_proc_task.h> + #define MSG "PT: " @@ -204,6 +204,8 @@ unsigned long pt_get_pend_step_op_code(struct proc_task *t) { struct proc_step *s; + if (!t) + return 0; if (list_empty(&t->todo)) return 0; @@ -467,6 +469,9 @@ void pt_destroy(struct proc_task *t) struct proc_step *p_elem; + if (!t) + return; + list_for_each_entry(p_elem, &t->todo, node) kfree(p_elem->op_info); diff --git a/lib/data_proc_tracker.c b/lib/data_proc_tracker.c index 5dc2324..708ba05 100644 --- a/lib/data_proc_tracker.c +++ b/lib/data_proc_tracker.c @@ -12,16 +12,37 @@ #include <kernel/log2.h> #include <kernel/types.h> #include <errno.h> -#include <list.h> -#include <data_proc_task.h> +#include <data_proc_tracker.h> -struct proc_tracker { - struct list_head tasks; - size_t n; -}; +/** + * @brief returns the op code of the tracker + * + * @param pt a struct proc_tracker + * + * @returns the op code + */ + +unsigned long pt_track_get_op_code(struct proc_tracker *pt) +{ + return pt->op_code; +} + + +/** + * @brief check if the tracker is above its critical number of tasks + * + * @param pt a struct proc_tracker + * + * @returns 1 if critical, 0 if not + */ + +int pt_track_level_critical(struct proc_tracker *pt) +{ + return (pt->n_tasks >= pt->n_tasks_crit); +} /** @@ -34,7 +55,7 @@ struct proc_tracker { int pt_track_get_usage(struct proc_tracker *pt) { - return pt->n; + return pt->n_tasks; } @@ -46,9 +67,47 @@ int pt_track_get_usage(struct proc_tracker *pt) * @param t a pointer to a task * * @returns 0 on success, -EINVAL on error + * + * @note if the pending step op code of the task does not match the op code of + * the tracker, it is rejected */ int pt_track_put(struct proc_tracker *pt, struct proc_task *t) +{ + unsigned long op; + + + if (!pt) + return -EINVAL; + + if (!t) + return -EINVAL; + + op = pt_get_pend_step_op_code(t); + + if (op != pt->op_code) + return -1; + + list_add_tail(&t->node, &pt->tasks); + + pt->n_tasks++; + + return 0; +} + + +/** + * @brief add a new item to the processing tracker, regardless of op code + * + * @param pt a struct processing_tracker + * + * @param t a pointer to a task + * + * @returns 0 on success, -EINVAL on error + * + */ + +int pt_track_put_force(struct proc_tracker *pt, struct proc_task *t) { if (!pt) return -EINVAL; @@ -58,7 +117,7 @@ int pt_track_put(struct proc_tracker *pt, struct proc_task *t) list_add_tail(&t->node, &pt->tasks); - pt->n++; + pt->n_tasks++; return 0; } @@ -85,12 +144,39 @@ struct proc_task *pt_track_get(struct proc_tracker *pt) list_del(&t->node); - pt->n--; + pt->n_tasks--; return t; } + +/** + * @brief execute next item in processing tracker + * + * @param pt a struct processing_tracker + * + * @return -ENOEXEC if no execution (task list empty), otherwise return code of + * associated op() function + */ + +int pt_track_execute_next(struct proc_tracker *pt) +{ + struct proc_task *t; + + + if (list_empty(&pt->tasks)) + return -ENOEXEC; + + + t = list_entry(pt->tasks.next, struct proc_task, node); + + return pt->op(pt->op_code, t); +} + + + + /** * @brief sort the tasks by order of sequence number * @param pt a struct processing_tracker @@ -107,22 +193,39 @@ void pt_track_sort_seq(struct proc_tracker *pt) /** * @brief create a processing tracker * - * @param nmemb the number of elements to track + * @param the function executing the op of this tracker + * @param data optional data to pass to the the tracker + * @param op_code the identfier of this tracker + * @param tasks_crit the number of tasks after which the tracker is + * considered filled to a critical level, must be at least 1 * * @return processing tracker or NULL on error */ -struct proc_tracker *pt_track_create(size_t nmemb) +struct proc_tracker *pt_track_create(int (*op)(unsigned long op_code, + struct proc_task *), + unsigned long op_code, size_t n_tasks_crit) { struct proc_tracker *pt; + if (!op) + return NULL; + + if (!n_tasks_crit) + return NULL; + + pt = (struct proc_tracker *) kzalloc(sizeof(struct proc_tracker)); if (!pt) return NULL; - pt->n = 0; + pt->op = op; + + pt->n_tasks_crit = n_tasks_crit; + + pt->op_code = op_code; INIT_LIST_HEAD(&pt->tasks); @@ -131,19 +234,24 @@ struct proc_tracker *pt_track_create(size_t nmemb) /** - * @brief destroy a processing tracker + * @brief destroy a processing tracker and everything it tracks * * @param pt a struct processing_tracker - * - * @return -1 if tracker is not empty, 0 on success */ -int pt_track_destroy(struct proc_tracker *pt) +void pt_track_destroy(struct proc_tracker *pt) { - if (list_filled(&pt->tasks)) - return -1; + struct proc_task *t; - kfree(pt); - return 0; + if (!pt) + return; + + while (list_filled(&pt->tasks)) { + t = pt_track_get(pt); + + pt_destroy(t); + } + + kfree(pt); } diff --git a/samples/Kconfig b/samples/Kconfig index 91214c8..b69434e 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -23,4 +23,9 @@ config SAMPLE_CHUNK help Build a sample demonstrating the use of the chunk memory allocator. +config SAMPLE_PROC_CHAIN + bool "Build processing chain sample code" + help + Build a sample demonstrating how to create a processing chain. + endif # SAMPLES diff --git a/samples/Makefile b/samples/Makefile index 541459d..c8b523e 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SAMPLE_SYSCTL) += sysctl/ obj-$(CONFIG_SAMPLE_MM) += mm/ obj-$(CONFIG_SAMPLE_CHUNK) += chunk/ +obj-$(CONFIG_SAMPLE_PROC_CHAIN) += proc_chain/ diff --git a/samples/proc_chain/Makefile b/samples/proc_chain/Makefile new file mode 100644 index 0000000..2601c9e --- /dev/null +++ b/samples/proc_chain/Makefile @@ -0,0 +1,27 @@ +# kbuild trick to avoid linker error. Can be omitted if a module is built. +obj- := dummy.o + +hostprogs-$(CONFIG_SAMPLE_PROC_CHAIN) := proc_chain_demo + +# I guess I'm too stupid to figure out the proper way to do this +# (but maybe there is none) + +ifdef CROSS_COMPILE +HOSTCC := $(CROSS_COMPILE)gcc +HOSTLD := $(CROSS_COMPILE)ld +endif + + +HOSTCFLAGS_proc_chain_demo.o += -I$(objtree)/include +proc_chain_demo-objs := proc_chain_demo.o + +ifndef CROSS_COMPILE +EXTRAPFLAG = -m32 +else +EXTRAPFLAG = +endif + +HOSTCFLAGS_proc_chain_demo.o += $(EXTRAFLAG) +HOSTLOADLIBES_proc_chain_demo += $(EXTRAFLAG) $(objtree)/lib/lib.a + +always := $(hostprogs-y) diff --git a/samples/proc_chain/proc_chain_demo.c b/samples/proc_chain/proc_chain_demo.c new file mode 100644 index 0000000..e25ddb5 --- /dev/null +++ b/samples/proc_chain/proc_chain_demo.c @@ -0,0 +1,374 @@ +/** + * This creates a number processing nodes representing Xentium kernel + * processing stages. Two special trackers are used for input and output. + * + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + + +#include <data_proc_task.h> +#include <data_proc_tracker.h> +#include <data_proc_net.h> + + +#include <kernel/kernel.h> + + +void *kzalloc(size_t size); +void kfree(void *ptr); +int printk(const char *fmt, ...); + +int pn_prepare_nodes(struct proc_net *pn); +void pn_new_input_task(struct proc_net *pn); + +int op_add(unsigned long op_code, struct proc_task *pt); +int op_sub(unsigned long op_code, struct proc_task *pt); +int op_mul(unsigned long op_code, struct proc_task *pt); +int op_output(unsigned long op_code, struct proc_task *pt); + + +int printk(const char *fmt, ...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vprintf(fmt, args); + va_end(args); + + return ret; +} + +void *kzalloc(size_t size) +{ + return calloc(size, 1); +} + +void kfree(void *ptr) +{ + free(ptr); +} + + + + +/* special op codes */ +#define OP_INPUT 0xFFFFFFFF +#define OP_OUTPUT 0x00000000 +/* a random base for op codes for this demo */ +#define OP_BASE 0x10000000 + +#define TASKS 5 +#define NODES (STEPS + 2) /* one per steps/op code + input + output */ + +#define NODE_IN STEPS +#define NODE_OUT (STEPS + 1) + + + + + + + +#if 0 +void proc_tasks_prepare(void) +{ + + int i; + int j; + int go; + int op; + + struct proc_task *pt; + struct proc_tracker **ptt_nodes; + + + + + /* allocate references to the intermediate nodes */ + ptt_nodes = (struct proc_tracker **) + kzalloc(NODES * sizeof(struct proc_tracker *)); + + BUG_ON(!ptt_nodes); + + /* create the intermediate tracker nodes, their ID is an op code*/ + for (i = 0; i < STEPS; i++) { + ptt_nodes[i] = pt_track_create(OP_BASE + i); + BUG_ON(!ptt_nodes[i]); + + } + + /* create the input and output nodes */ + + ptt_nodes[NODE_IN] = pt_track_create(OP_INPUT); + BUG_ON(!ptt_nodes[NODE_IN]); + ptt_nodes[NODE_OUT] = pt_track_create(OP_OUTPUT); + BUG_ON(!ptt_nodes[NODE_OUT]); + + + /* create a number of individual tasks and define some processing steps, + * then add the to the input stage + */ + + for (i = 0; i < TASKS; i++) { + /* create a task holding at most STEPS steps */ + pt = pt_create(NULL, 0, STEPS, 0, i); + BUG_ON(!pt); + + /* activate all steps with different op-codes */ + for (j = 0; j < STEPS; j++) + BUG_ON(pt_add_step(pt, OP_BASE + j, NULL)); + + /* add the task to the input tracker */ + pt_track_put(ptt_nodes[NODE_IN], pt); + } + + + /* now process the tasks, we "schedule" by looping over all the + * trackers until none have pending tasks left + */ + + go = 1; + while (go) { + go = 0; + for (i = 0; i < NODES; i++) { + while (1) { /* keep processing while the node holds + tasks */ + pt = pt_track_get(ptt_nodes[i]); + if (!pt) + break; + + printk("Processing task in node %d\n", i); + go++; /* our indicator */ + + switch (i) { + case NODE_IN: + /* the input node, just moves the task + * into the first processing node based + * on the first processing step op code + */ + op = pt_get_pend_step_op_code(pt); + printk("IN: move task to node %d\n", + op - OP_BASE); + /* in our demo, we get the correct node + * by calculating it from the OP_BASE + */ + pt_track_put(ptt_nodes[op - OP_BASE], pt); + break; + + case NODE_OUT: /* output node */ + printk("OUT: destroy task\n"); + pt_destroy(pt); + break; + + default: /* processing node */ + op = pt_get_pend_step_op_code(pt); + printk("PROC: simulating processing " + "operation %d\n", op - OP_BASE); + /* this step is now complete */ + pt_next_pend_step_done(pt); + + op = pt_get_pend_step_op_code(pt); + if (op) { + printk("PROC: move task to node" + " %d\n", + op - OP_BASE); + pt_track_put(ptt_nodes[op - OP_BASE], pt); + } else { + printk("PROC: last step, moving" + " to output node"); + pt_track_put(ptt_nodes[NODE_OUT], pt); + } + + break; + } + } + + } + printk("Scheduling cycle complete\n"); + } + + printk("Processing complete\n"); + + + + +#if 0 + pt_dump_steps_todo(pt); + pt_dump_steps_done(pt); + + + pt_next_pend_step_done(pt); + pt_next_pend_step_done(pt); + pt_dump_steps_todo(pt); + pt_dump_steps_done(pt); + + + pt_next_pend_step_done(pt); + pt_dump_steps_todo(pt); + pt_dump_steps_done(pt); + + pt_rewind_steps_done(pt); + + pt_dump_steps_todo(pt); +#endif + + + + for (i = 0; i < NODES; i++) + pt_track_destroy(ptt_nodes[i]); + + kfree(ptt_nodes); + +} + +#endif + +#define CRIT_LEVEL 10 +#define CRIT_IN CRIT_LEVEL +#define CRIT_OUT CRIT_LEVEL + +#define OP_ADD 0x1234 +#define OP_SUB 0x1235 +#define OP_MUL 0x1236 + +#define STEPS 3 + + + +int op_output(unsigned long op_code, struct proc_task *pt) +{ + printk("OUT: op code %d\n", op_code); + + return 0; +} + + +int op_add(unsigned long op_code, struct proc_task *pt) +{ + printk("ADD: op code %d\n", op_code); + + return 0; +} + +int op_sub(unsigned long op_code, struct proc_task *pt) +{ + printk("SUB: op code %d\n", op_code); + + return 0; +} + +int op_mul(unsigned long op_code, struct proc_task *pt) +{ + printk("MUL: op code %d\n", op_code); + + return 0; +} + + +int pn_prepare_nodes(struct proc_net *pn) +{ + struct proc_tracker *pt; + + + /* create and add processing node trackers for the each operation */ + + pt = pt_track_create(op_add, OP_ADD, CRIT_LEVEL); + BUG_ON(!pt); + BUG_ON(pn_add_node(pn, pt)); + + pt = pt_track_create(op_sub, OP_SUB, CRIT_LEVEL); + BUG_ON(!pt); + BUG_ON(pn_add_node(pn, pt)); + + pt = pt_track_create(op_mul, OP_MUL, CRIT_LEVEL); + BUG_ON(!pt); + + BUG_ON(pn_add_node(pn, pt)); + + BUG_ON(pn_create_output_node(pn, op_output)); + + return 0; +} + + + +void pn_new_input_task(struct proc_net *pn) +{ + struct proc_task *t; + + static int seq; + + + t = pt_create(NULL, 0, STEPS, 0, seq++); + + BUG_ON(!t); + + BUG_ON(pt_add_step(t, OP_ADD, NULL)); + BUG_ON(pt_add_step(t, OP_SUB, NULL)); + BUG_ON(pt_add_step(t, OP_MUL, NULL)); + + + pn_input_task(pn, t); +} + +void pn_new_input_task2(struct proc_net *pn) +{ + struct proc_task *t; + + static int seq; + + + t = pt_create(NULL, 0, STEPS, 0, seq++); + + BUG_ON(!t); + + BUG_ON(pt_add_step(t, OP_MUL, NULL)); + BUG_ON(pt_add_step(t, OP_SUB, NULL)); + BUG_ON(pt_add_step(t, OP_ADD, NULL)); + + + pn_input_task(pn, t); +} + + + + + +int main(int argc, char **argv) +{ + + struct proc_net *pn; + + + pn = pn_create(CRIT_IN, CRIT_OUT); + + BUG_ON(!pn); + + pn_prepare_nodes(pn); + + + pn_new_input_task(pn); + pn_new_input_task2(pn); + + + pn_process_inputs(pn); + + pn_process_next(pn); + pn_process_next(pn); + pn_process_next(pn); + pn_process_next(pn); + pn_process_next(pn); + pn_process_next(pn); + + + + return 0; +} + -- GitLab