events: do not inline event_select()
[bertos.git] / bertos / mware / event.c
index 186315085c349ac7ca8b769ea9de974da705242e..72663037497b1d2106b14065af8e2fbe23d9b8c3 100644 (file)
@@ -41,6 +41,8 @@
 #include "cfg/cfg_signal.h"
 #include "cfg/cfg_timer.h"
 
+#include <drv/timer.h> /* timer_clock() */
+
 void event_hook_ignore(UNUSED_ARG(Event *, e))
 {
 }
@@ -69,3 +71,55 @@ void event_hook_generic(Event *e)
        e->Ev.Gen.completed = true;
        MEMORY_BARRIER;
 }
+
+/**
+ * Wait for multiple events
+ *
+ * On success return the offset in the \a evs vector of the Event that
+ * happened, -1 if the timeout expires.
+ *
+ * NOTE: timeout == 0 means no timeout.
+ */
+#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+int event_select(Event **evs, int n, ticks_t timeout)
+{
+       sigmask_t mask = (1 << n) - 1;
+       int i;
+
+       ASSERT(n <= SIG_USER_MAX);
+       for (i = 0; i < n; i++)
+       {
+               Event *e = evs[i];
+               /* Map each event to a distinct signal bit */
+               event_initSignal(e, proc_current(), 1 << i);
+       }
+       mask = timeout ? sig_waitTimeout(mask, timeout) : sig_wait(mask);
+       i = UINT8_LOG2(mask);
+
+       return i < n ? i : -1;
+}
+#else
+int event_select(Event **evs, int n, ticks_t timeout)
+{
+       ticks_t end = timer_clock() + timeout;
+       int i;
+
+       while (1)
+       {
+               for (i = 0; i < n; i++)
+               {
+                       Event *e = evs[i];
+                       if (ACCESS_SAFE(e->Ev.Gen.completed) == true)
+                       {
+                               e->Ev.Gen.completed = false;
+                               MEMORY_BARRIER;
+                               return i;
+                       }
+               }
+               if (timeout && TIMER_AFTER(timer_clock(), end))
+                       break;
+               cpu_relax();
+       }
+       return -1;
+}
+#endif