diff options
Diffstat (limited to 'threadlib/src/callbacks.c')
-rwxr-xr-x | threadlib/src/callbacks.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/threadlib/src/callbacks.c b/threadlib/src/callbacks.c new file mode 100755 index 0000000..1385992 --- /dev/null +++ b/threadlib/src/callbacks.c @@ -0,0 +1,134 @@ +/* +* +* callbacks.c +* implementation of the callback FIFO +* +* this is the (modified) FIFO of the idle callbacks from pd_devel_0.38 +* (implemented in m_sched.c) +*/ + +#include "threadlib.h" + +// global callback fifo +t_fifo * h_callback_fifo = NULL; + +// global clock callback to trigger +// the callback fifo +t_clock *h_callback_clock = NULL; + +/* linked list of callbacks + * callback will be freed after returning 0 */ +typedef struct _sched_callback +{ + struct _sched_callback* next; /* next callback in ringbuffer / in fifo */ + t_int (*function) (t_int* argv); + t_int* argv; + t_int argc; +} t_sched_callback; + +// forward declaration +static void h_run_callbacks(); + +void h_init_callbacks() +{ + h_callback_fifo = fifo_init(); + h_callback_clock = clock_new(NULL, (t_method)h_run_callbacks); +} + +void h_free_callbacks() +{ + clock_free(h_callback_clock); + fifo_destroy(h_callback_fifo); +} + +void h_set_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc) +{ + t_sched_callback* new = (t_sched_callback*) getbytes + (sizeof(t_sched_callback)); + + new->function = callback; + new->argv = (t_int*) copybytes (argv, argc * sizeof (t_int)); + new->argc = argc; + new->next = NULL; + + fifo_put(h_callback_fifo, new); + + // TODO find solution without lock + sys_lock(); + clock_delay(h_callback_clock, 0); + sys_unlock(); +} + +static t_sched_callback *ringbuffer_head; + +void h_run_callbacks() +{ + t_sched_callback * new_callback; + + sys_unlock(); + + /* append idle callback to ringbuffer */ + + while ( (new_callback = (t_sched_callback*) fifo_get(h_callback_fifo)) ) + { + t_sched_callback * next; + + /* set the next field to NULL ... it might be set in the fifo */ + new_callback->next = NULL; + if (ringbuffer_head == NULL) + { + ringbuffer_head = new_callback; + } + else + { + next = ringbuffer_head; + while (next->next != 0) + next = next->next; + next->next = new_callback; + } + } + + if (ringbuffer_head != NULL) + { + t_sched_callback * idle_callback = ringbuffer_head; + t_sched_callback * last = NULL; + t_sched_callback * next; + + do + { + int status; + + sys_lock(); + status = (idle_callback->function)(idle_callback->argv); + sys_unlock(); + + switch (status) + { + /* callbacks returning 0 will be deleted */ + case 0: + next = idle_callback->next; + freebytes (idle_callback->argv, idle_callback->argc); + freebytes ((void*)idle_callback, sizeof(t_sched_callback)); + + if (last == NULL) + ringbuffer_head = next; + else + last->next = next; + + idle_callback = next; + + /* callbacks returning 1 will be run again */ + case 1: + break; + + /* callbacks returning 2 will be run during the next idle callback */ + case 2: + last = idle_callback; + idle_callback = idle_callback->next; + } + } + while (idle_callback != NULL); + } + + sys_lock(); +} |