Add an easy function for synchronous calls
[src/app-framework-binder.git] / src / jobs.c
index fa94ef1..17deb88 100644 (file)
@@ -18,6 +18,7 @@
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <signal.h>
 #include <time.h>
@@ -39,6 +40,9 @@
 #define sig_monitor(to,cb,arg)       (cb(0,arg))
 #endif
 
+#define EVENT_TIMEOUT_TOP      ((uint64_t)-1)
+#define EVENT_TIMEOUT_CHILD    ((uint64_t)10000)
+
 /** Internal shortcut for callback */
 typedef void (*job_cb_t)(int, void*, void *, void*);
 
@@ -61,6 +65,7 @@ struct events
 {
        struct events *next;
        struct sd_event *event;
+       uint64_t timeout;
        unsigned runs: 1;
 };
 
@@ -77,6 +82,15 @@ struct thread
        unsigned waits: 1;     /**< is waiting? */
 };
 
+/**
+ * Description of synchonous callback
+ */
+struct sync
+{
+       void (*callback)(int, void*);   /**< the synchrnous callback */
+       void *arg;                      /**< the argument of the callback */
+};
+
 /* synchronisation of threads */
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t  cond = PTHREAD_COND_INITIALIZER;
@@ -276,7 +290,7 @@ static void events_call(int signum, void *arg)
 {
        struct events *events = arg;
        if (!signum)
-               sd_event_run(events->event, (uint64_t) -1);
+               sd_event_run(events->event, events->timeout);
 }
 
 /**
@@ -291,6 +305,7 @@ static void thread_run(volatile struct thread *me)
        struct thread **prv;
        struct job *job;
        struct events *events;
+       uint64_t evto;
 
        /* initialize description of itself and link it in the list */
        me->tid = pthread_self();
@@ -300,9 +315,11 @@ static void thread_run(volatile struct thread *me)
        me->upper = current;
        if (current) {
                current->lowered = 1;
+               evto = EVENT_TIMEOUT_CHILD;
        } else {
                started++;
                sig_monitor_init_timeouts();
+               evto = EVENT_TIMEOUT_TOP;
        }
        me->next = threads;
        threads = (struct thread*)me;
@@ -341,6 +358,7 @@ static void thread_run(volatile struct thread *me)
                        if (events) {
                                /* run the events */
                                events->runs = 1;
+                               events->timeout = evto;
                                me->events = events;
                                pthread_mutex_unlock(&mutex);
                                sig_monitor(0, events_call, events);
@@ -442,7 +460,7 @@ int jobs_queue0(
  *                 or the signal number that broke the normal flow.
  *                 The remaining parameter is the parameter 'arg1'
  *                 given here.
- * @param arg1     The second argument for 'callback'
+ * @param arg      The second argument for 'callback'
  * @return 0 in case of success or -1 in case of error
  */
 int jobs_queue(
@@ -560,13 +578,25 @@ error:
 
 /**
  * Enter a synchronisation point: activates the job given by 'callback'
- * @param group the gro
+ * and 'closure' using 'group' and 'timeout' to control sequencing and
+ * execution time.
+ * @param group the group for sequencing jobs
+ * @param timeout the time in seconds allocated to the job
+ * @param callback the callback that will handle the job.
+ *                 it receives 3 parameters: 'signum' that will be 0
+ *                 on normal flow or the catched signal number in case
+ *                 of interrupted flow, the context 'closure' as given and
+ *                 a 'jobloop' reference that must be used when the job is
+ *                 terminated to unlock the current execution flow.
+ * @param closure the context completion closure for the callback
+ * @return 0 on success or -1 in case of error
  */
 int jobs_enter(
                void *group,
                int timeout,
                void (*callback)(int signum, void *closure, struct jobloop *jobloop),
-               void *closure)
+               void *closure
+)
 {
        
        struct job *job;
@@ -592,11 +622,16 @@ int jobs_enter(
        return 0;
 }
 
+/**
+ * Unlocks the execution flow designed by 'jobloop'.
+ * @param jobloop indication of the flow to unlock
+ * @return 0 in case of success of -1 on error
+ */
 int jobs_leave(struct jobloop *jobloop)
 {
        struct thread *t;
-       pthread_mutex_lock(&mutex);
 
+       pthread_mutex_lock(&mutex);
        t = threads;
        while (t && t != (struct thread*)jobloop)
                t = t->next;
@@ -611,6 +646,44 @@ int jobs_leave(struct jobloop *jobloop)
        return -!t;
 }
 
+/**
+ * Internal helper function for 'jobs_call'.
+ * @see jobs_call, jobs_enter, jobs_leave
+ */
+static void call_cb(int signum, void *closure, struct jobloop *jobloop)
+{
+       struct sync *sync = closure;
+       sync->callback(signum, sync->arg);
+       jobs_leave(jobloop);
+}
+
+/**
+ * Calls synchronously the job represented by 'callback' and 'arg1'
+ * for the 'group' and the 'timeout' and waits for its completion.
+ * @param group    The group of the job or NULL when no group.
+ * @param timeout  The maximum execution time in seconds of the job
+ *                 or 0 for unlimited time.
+ * @param callback The function to execute for achieving the job.
+ *                 Its first parameter is either 0 on normal flow
+ *                 or the signal number that broke the normal flow.
+ *                 The remaining parameter is the parameter 'arg1'
+ *                 given here.
+ * @param arg      The second argument for 'callback'
+ * @return 0 in case of success or -1 in case of error
+ */
+int jobs_call(
+               void *group,
+               int timeout,
+               void (*callback)(int, void*),
+               void *arg)
+{
+       struct sync sync;
+
+       sync.callback = callback;
+       sync.arg = arg;
+       return jobs_enter(group, timeout, call_cb, &sync);
+}
+
 /**
  * Gets a sd_event item for the current thread.
  * @return a sd_event or NULL in case of error