aboutsummaryrefslogtreecommitdiff
path: root/threadlib/src/callbacks.c
diff options
context:
space:
mode:
Diffstat (limited to 'threadlib/src/callbacks.c')
-rwxr-xr-xthreadlib/src/callbacks.c134
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();
+}