X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fmware%2Fevent.h;h=e6a8b1ee9debea065afbb70026e0db7bd92098bb;hb=024bf80e5f29e4de00d0813d23a4d3b67245ead7;hp=e640105669490d7d7c25d8c5f731202ac5098f83;hpb=1e5e45887029f15c8a3ea43edf162ed93d3f25b1;p=bertos.git diff --git a/bertos/mware/event.h b/bertos/mware/event.h index e6401056..e6a8b1ee 100644 --- a/bertos/mware/event.h +++ b/bertos/mware/event.h @@ -30,12 +30,15 @@ * Copyright 1999, 2001, 2003 Bernie Innocenti * --> * + * \defgroup event_handling Event handling module + * \ingroup core + * \{ + * * \brief Events handling * * This module implements a common system for executing * a user defined action calling a hook function. * - * NOTE: Generic completion events * * Device drivers often need to wait the completion of some event, usually to * allow the hardware to accomplish some asynchronous task. @@ -64,7 +67,7 @@ * behaviour with or without the kernel. * * Example usage (wait for a generic device driver initialization): - * \verbatim + * \code * static Event e; * * static void irq_handler(void) @@ -82,44 +85,84 @@ * // Wait for the completion of the event * event_wait(&e); * } - * \endverbatim + * \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 + * + * $WIZ$ module_name = "event" */ #ifndef KERN_EVENT_H #define KERN_EVENT_H -#include #include "cfg/cfg_proc.h" #include "cfg/cfg_signal.h" #include "cfg/cfg_timer.h" +#include #include /* cpu_relax() */ -#if CONFIG_KERN - #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS - #include - #endif - - /* Forward decl */ - struct Process; +#if CONFIG_KERN && CONFIG_KERN_SIGNALS +#include +/* Forward decl */ +struct Process; #endif - -/// User defined callback type -typedef void (*Hook)(void *); - typedef struct Event { void (*action)(struct Event *); union { -#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS +#if CONFIG_KERN && CONFIG_KERN_SIGNALS struct { struct Process *sig_proc; /* Process to be signalled */ sigbit_t sig_bit; /* Signal to send */ + Signal sig; /* Local signal structure (used by generic event) */ } Sig; #endif struct @@ -139,14 +182,13 @@ void event_hook_ignore(Event *event); void event_hook_signal(Event *event); void event_hook_softint(Event *event); void event_hook_generic(Event *event); -void event_hook_generic_timeout(Event *event); +void event_hook_generic_signal(Event *event); /** Initialize the event \a e as a no-op */ #define event_initNone(e) \ ((e)->action = event_hook_ignore) /** Same as event_initNone(), but returns the initialized event */ -INLINE Event event_createNone(void); INLINE Event event_createNone(void) { Event e; @@ -168,8 +210,7 @@ INLINE Event event_createSoftint(Hook func, void *user_data) return e; } -#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS - +#if CONFIG_KERN && CONFIG_KERN_SIGNALS /** Initialize the event \a e with a signal (send signal \a s to process \a p) */ #define event_initSignal(e,p,s) \ ((e)->action = event_hook_signal,(e)->Ev.Sig.sig_proc = (p), (e)->Ev.Sig.sig_bit = (s)) @@ -184,21 +225,17 @@ INLINE Event event_createSignal(struct Process *proc, sigbit_t bit) return e; } -#endif - /** - * Prevent the compiler from optimizing access to the variable \a x, enforcing - * a refetch from memory. This also forbid from reordering successing instances - * of ACCESS_SAFE(). - * - * TODO: move this to cfg/compiler.h + * Signal used to implement generic events. */ -#define ACCESS_SAFE(x) (*(volatile typeof(x) *)&(x)) +#define EVENT_GENERIC_SIGNAL SIG_SYSTEM6 -#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS /** Initialize the generic sleepable event \a e */ -#define event_initGeneric(e) \ - event_initSignal(e, proc_current(), SIG_SYSTEM5) +#define event_initGeneric(e) \ + ((e)->action = event_hook_generic_signal, \ + (e)->Ev.Sig.sig_proc = proc_current(), \ + (e)->Ev.Sig.sig_bit = EVENT_GENERIC_SIGNAL, \ + (e)->Ev.Sig.sig.wait = 0, (e)->Ev.Sig.sig.recv = 0) #else #define event_initGeneric(e) \ ((e)->action = event_hook_generic, (e)->Ev.Gen.completed = false) @@ -218,12 +255,16 @@ INLINE Event event_createGeneric(void) /** * Wait the completion of event \a e. + * + * This function releases the CPU the application is configured to use + * the kernel, otherwise it's just a busy wait. + * \note It's forbidden to use this function inside irq handling functions. */ INLINE void event_wait(Event *e) { -#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS +#if CONFIG_KERN_SIGNALS e->Ev.Sig.sig_proc = proc_current(); - sig_wait(e->Ev.Sig.sig_bit); + sig_waitSignal(&e->Ev.Sig.sig, EVENT_GENERIC_SIGNAL); #else while (ACCESS_SAFE(e->Ev.Gen.completed) == false) cpu_relax(); @@ -232,42 +273,38 @@ INLINE void event_wait(Event *e) #endif } -#if CONFIG_TIMER_EVENTS -#include /* timer_clock() */ - -/* TODO: move these macros to drv/timer.h */ -#define TIMER_AFTER(x, y) ((long)(y) - (long)(x) < 0) -#define TIMER_BEFORE(x, y) TIMER_AFTER(y, x) +/** + * 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. + * + * \attention The API is work in progress and may change in future versions. + */ +int event_select(Event **evs, int n, ticks_t timeout); /** * Wait the completion of event \a e or \a timeout elapses. + * + * \note It's forbidden to use this function inside irq handling functions. */ -INLINE bool event_waitTimeout(Event *e, ticks_t timeout) -{ -#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS - e->Ev.Sig.sig_proc = proc_current(); - return (sig_waitTimeout(e->Ev.Sig.sig_bit, timeout) & SIG_TIMEOUT) ? - false : true; -#else - ticks_t end = timer_clock() + timeout; - bool ret; +bool event_waitTimeout(Event *e, ticks_t timeout); - while ((ACCESS_SAFE(e->Ev.Gen.completed) == false) || - TIMER_AFTER(timer_clock(), end)) - cpu_relax(); - ret = e->Ev.Gen.completed; - e->Ev.Gen.completed = false; - MEMORY_BARRIER; - - return ret; -#endif -} -#endif /* CONFIG_TIMER_EVENTS */ - -/** Trigger an event */ +/** + * Trigger an event. + * + * Execute the callback function associated with event \a e. + * + * This function can be used also in interrupt routines, but only if the + * event was created as a signal or generic event. + */ INLINE void event_do(struct Event *e) { e->action(e); } +/** \} */ + #endif /* KERN_EVENT_H */