event: introduce event_select()
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 7 Mar 2011 18:34:01 +0000 (18:34 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 7 Mar 2011 18:34:01 +0000 (18:34 +0000)
Add the following primitive to wait the completion of multiple generic
events:

  int event_select(Event **evs, int n, ticks_t timeout);

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4757 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/mware/event.h

index 0111ef8cbfa37fbf866f11c0976fa7f3ecbc14f6..94121413e5dd690d81ef32c701defd14f74f5803 100644 (file)
  *  }
  *  \endcode
  *
+ * Example usage: wait multiple generic events via event_select()
+ * \code
+ * Event ev1;
+ * Event ev2;
+ *
+ * void event_notifier(void)
+ * {
+ *      Event *evs[] = { &ev1, &ev2 };
+ *
+ *      event_initGeneric(&ev1);
+ *      event_initGeneric(&ev2);
+ *
+ *      while (1)
+ *      {
+ *              int id = event_select(evs, countof(evs),
+ *                                      ms_to_ticks(100));
+ *              if (id < 0)
+ *              {
+ *                      kprintf("no IRQ\n");
+ *                      continue;
+ *              }
+ *              kprintf("IRQ %d happened\n", id);
+ *      }
+ * }
+ *
+ * void irq1_handler(void)
+ * {
+ *      // do something
+ *      ...
+ *
+ *      // notify the completion of event 1
+ *      event_do(&ev1);
+ * }
+ *
+ * void irq2_handler(void)
+ * {
+ *      // do something
+ *      ...
+ *
+ *      // notify the completion of event 2
+ *      event_do(&ev2);
+ * }
+ * \endcode
+ *
  * \author Bernie Innocenti <bernie@codewiz.org>
  */
 
@@ -242,6 +286,59 @@ INLINE void event_wait(Event *e)
 #endif
 }
 
+/**
+ * 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
+INLINE 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
+INLINE 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
+
+
 #if CONFIG_TIMER_EVENTS
 #include <drv/timer.h> /* timer_clock() */