doc: Update and clarify documentation for event handling module.
[bertos.git] / bertos / mware / event.h
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 1999, 2001, 2003 Bernie Innocenti <bernie@codewiz.org>
31  * -->
32  *
33  * \addtogroup event_handling
34  *
35  * \brief Events handling
36  *
37  * This module implements a common system for executing
38  * a user defined action calling a hook function.
39  *
40  *
41  *  Device drivers often need to wait the completion of some event, usually to
42  *  allow the hardware to accomplish some asynchronous task.
43  *
44  *  A common approach is to place a busy wait with a cpu_relax() loop that invokes
45  *  the architecture-specific instructions to say that we're not doing much with
46  *  the processor.
47  *
48  *  Although technically correct, the busy loop degrades the overall system
49  *  performance in presence of multiple processes and power consumption.
50  *
51  *  With the kernel the natural way to implement such wait/complete mechanism is to
52  *  use signals via sig_wait() and sig_post()/sig_send().
53  *
54  *  However, signals in BeRTOS are only available in presence of the kernel (that
55  *  is just a compile-time option). This means that each device driver must provide
56  *  two different interfaces to implement the wait/complete semantic: one with the
57  *  kernel and another without the kernel.
58  *
59  *  The purpose of the completion events is to provide a generic interface to
60  *  implement a synchronization mechanism to block the execution of code until a
61  *  specific event happens.
62  *
63  *  This interface does not depend on the presence of the kernel and it
64  *  automatically uses the appropriate event backend to provide the same
65  *  behaviour with or without the kernel.
66  *
67  *  Example usage (wait for a generic device driver initialization):
68  *  \code
69  *  static Event e;
70  *
71  *  static void irq_handler(void)
72  *  {
73  *      // Completion event has happened, resume the execution of init()
74  *      event_do(&e);
75  *  }
76  *
77  *  static void init(void)
78  *  {
79  *      // Declare the generic completion event
80  *      event_initGeneric(&e);
81  *      // Submit the hardware initialization request
82  *      async_hw_init();
83  *      // Wait for the completion of the event
84  *      event_wait(&e);
85  *  }
86  *  \endcode
87  *
88  * \author Bernie Innocenti <bernie@codewiz.org>
89  */
90
91 #ifndef KERN_EVENT_H
92 #define KERN_EVENT_H
93
94 #include <cfg/compiler.h>
95 #include "cfg/cfg_proc.h"
96 #include "cfg/cfg_signal.h"
97 #include "cfg/cfg_timer.h"
98
99 #include <cpu/power.h> /* cpu_relax() */
100
101 #if CONFIG_KERN
102         #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
103                 #include <kern/signal.h>
104         #endif
105
106         /* Forward decl */
107         struct Process;
108 #endif
109
110 /**
111  * \defgroup event_handling Events handling module
112  * \{
113  */
114
115
116 /// User defined callback type
117 typedef void (*Hook)(void *);
118
119 typedef struct Event
120 {
121         void (*action)(struct Event *);
122         union
123         {
124 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
125                 struct
126                 {
127                         struct Process *sig_proc;  /* Process to be signalled */
128                         sigbit_t        sig_bit;   /* Signal to send */
129                 } Sig;
130 #endif
131                 struct
132                 {
133                         Hook  func;         /* Pointer to softint hook */
134                         void *user_data;    /* Data to be passed back to user hook */
135                 } Int;
136
137                 struct
138                 {
139                         bool completed;             /* Generic event completion */
140                 } Gen;
141         } Ev;
142 } Event;
143
144 void event_hook_ignore(Event *event);
145 void event_hook_signal(Event *event);
146 void event_hook_softint(Event *event);
147 void event_hook_generic(Event *event);
148 void event_hook_generic_timeout(Event *event);
149
150 /** Initialize the event \a e as a no-op */
151 #define event_initNone(e) \
152         ((e)->action = event_hook_ignore)
153
154 /** Same as event_initNone(), but returns the initialized event */
155 INLINE Event event_createNone(void);
156 INLINE Event event_createNone(void)
157 {
158         Event e;
159         e.action = event_hook_ignore;
160         return e;
161 }
162
163 /** Initialize the event \a e with a software interrupt (call function \a f, with parameter \a u) */
164 #define event_initSoftint(e,f,u) \
165         ((e)->action = event_hook_softint,(e)->Ev.Int.func = (f), (e)->Ev.Int.user_data = (u))
166
167 /** Same as event_initSoftint(), but returns the initialized event */
168 INLINE Event event_createSoftint(Hook func, void *user_data)
169 {
170         Event e;
171         e.action = event_hook_softint;
172         e.Ev.Int.func = func;
173         e.Ev.Int.user_data = user_data;
174         return e;
175 }
176
177 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
178
179 /** Initialize the event \a e with a signal (send signal \a s to process \a p) */
180 #define event_initSignal(e,p,s) \
181         ((e)->action = event_hook_signal,(e)->Ev.Sig.sig_proc = (p), (e)->Ev.Sig.sig_bit = (s))
182
183 /** Same as event_initSignal(), but returns the initialized event */
184 INLINE Event event_createSignal(struct Process *proc, sigbit_t bit)
185 {
186         Event e;
187         e.action = event_hook_signal;
188         e.Ev.Sig.sig_proc = proc;
189         e.Ev.Sig.sig_bit = bit;
190         return e;
191 }
192
193 #endif
194
195 /**
196  * Prevent the compiler from optimizing access to the variable \a x, enforcing
197  * a refetch from memory. This also forbid from reordering successing instances
198  * of ACCESS_SAFE().
199  *
200  * TODO: move this to cfg/compiler.h
201  */
202 #define ACCESS_SAFE(x) (*(volatile typeof(x) *)&(x))
203
204 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
205 /** Initialize the generic sleepable event \a e */
206 #define event_initGeneric(e) \
207         event_initSignal(e, proc_current(), SIG_SYSTEM5)
208 #else
209 #define event_initGeneric(e) \
210         ((e)->action = event_hook_generic, (e)->Ev.Gen.completed = false)
211 #endif
212
213 /**
214  * Create a generic sleepable event.
215  *
216  * \return the properly initialized generic event structure.
217  */
218 INLINE Event event_createGeneric(void)
219 {
220         Event e;
221         event_initGeneric(&e);
222         return e;
223 }
224
225 /**
226  * Wait the completion of event \a e.
227  *
228  * This function releases the CPU the application is configured to use
229  * the kernel, otherwise it's just a busy wait.
230  * \note It's forbidden to use this function inside irq handling functions.
231  */
232 INLINE void event_wait(Event *e)
233 {
234 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
235         e->Ev.Sig.sig_proc = proc_current();
236         sig_wait(e->Ev.Sig.sig_bit);
237 #else
238         while (ACCESS_SAFE(e->Ev.Gen.completed) == false)
239                 cpu_relax();
240         e->Ev.Gen.completed = false;
241         MEMORY_BARRIER;
242 #endif
243 }
244
245 #if CONFIG_TIMER_EVENTS
246 #include <drv/timer.h> /* timer_clock() */
247
248 /* TODO: move these macros to drv/timer.h */
249 #define TIMER_AFTER(x, y) ((long)(y) - (long)(x) < 0)
250 #define TIMER_BEFORE(x, y) TIMER_AFTER(y, x)
251
252 /**
253  * Wait the completion of event \a e or \a timeout elapses.
254  *
255  * \note It's forbidden to use this function inside irq handling functions.
256  */
257 INLINE bool event_waitTimeout(Event *e, ticks_t timeout)
258 {
259 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
260         e->Ev.Sig.sig_proc = proc_current();
261         return (sig_waitTimeout(e->Ev.Sig.sig_bit, timeout) & SIG_TIMEOUT) ?
262                                 false : true;
263 #else
264         ticks_t end = timer_clock() + timeout;
265         bool ret;
266
267         while ((ACCESS_SAFE(e->Ev.Gen.completed) == false) ||
268                         TIMER_AFTER(timer_clock(), end))
269                 cpu_relax();
270         ret = e->Ev.Gen.completed;
271         e->Ev.Gen.completed = false;
272         MEMORY_BARRIER;
273
274         return ret;
275 #endif
276 }
277 #endif /* CONFIG_TIMER_EVENTS */
278
279 /**
280  * Trigger an event.
281  *
282  * Execute the callback function associated with event \a e.
283  *
284  * This function can be used also in interrupt routines, but only if the
285  * event was created as a signal or generic event.
286  */
287 INLINE void event_do(struct Event *e)
288 {
289         e->action(e);
290 }
291
292 /** \} */
293
294 #endif /* KERN_EVENT_H */