e640105669490d7d7c25d8c5f731202ac5098f83
[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  * \brief Events handling
34  *
35  * This module implements a common system for executing
36  * a user defined action calling a hook function.
37  *
38  *  NOTE: Generic completion events
39  *
40  *  Device drivers often need to wait the completion of some event, usually to
41  *  allow the hardware to accomplish some asynchronous task.
42  *
43  *  A common approach is to place a busy wait with a cpu_relax() loop that invokes
44  *  the architecture-specific instructions to say that we're not doing much with
45  *  the processor.
46  *
47  *  Although technically correct, the busy loop degrades the overall system
48  *  performance in presence of multiple processes and power consumption.
49  *
50  *  With the kernel the natural way to implement such wait/complete mechanism is to
51  *  use signals via sig_wait() and sig_post()/sig_send().
52  *
53  *  However, signals in BeRTOS are only available in presence of the kernel (that
54  *  is just a compile-time option). This means that each device driver must provide
55  *  two different interfaces to implement the wait/complete semantic: one with the
56  *  kernel and another without the kernel.
57  *
58  *  The purpose of the completion events is to provide a generic interface to
59  *  implement a synchronization mechanism to block the execution of code until a
60  *  specific event happens.
61  *
62  *  This interface does not depend on the presence of the kernel and it
63  *  automatically uses the appropriate event backend to provide the same
64  *  behaviour with or without the kernel.
65  *
66  *  Example usage (wait for a generic device driver initialization):
67  *  \verbatim
68  *  static Event e;
69  *
70  *  static void irq_handler(void)
71  *  {
72  *      // Completion event has happened, resume the execution of init()
73  *      event_do(&e);
74  *  }
75  *
76  *  static void init(void)
77  *  {
78  *      // Declare the generic completion event
79  *      event_initGeneric(&e);
80  *      // Submit the hardware initialization request
81  *      async_hw_init();
82  *      // Wait for the completion of the event
83  *      event_wait(&e);
84  *  }
85  *  \endverbatim
86  *
87  * \author Bernie Innocenti <bernie@codewiz.org>
88  */
89
90 #ifndef KERN_EVENT_H
91 #define KERN_EVENT_H
92
93 #include <cfg/compiler.h>
94 #include "cfg/cfg_proc.h"
95 #include "cfg/cfg_signal.h"
96 #include "cfg/cfg_timer.h"
97
98 #include <cpu/power.h> /* cpu_relax() */
99
100 #if CONFIG_KERN
101         #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
102                 #include <kern/signal.h>
103         #endif
104
105         /* Forward decl */
106         struct Process;
107 #endif
108
109
110 /// User defined callback type
111 typedef void (*Hook)(void *);
112
113 typedef struct Event
114 {
115         void (*action)(struct Event *);
116         union
117         {
118 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
119                 struct
120                 {
121                         struct Process *sig_proc;  /* Process to be signalled */
122                         sigbit_t        sig_bit;   /* Signal to send */
123                 } Sig;
124 #endif
125                 struct
126                 {
127                         Hook  func;         /* Pointer to softint hook */
128                         void *user_data;    /* Data to be passed back to user hook */
129                 } Int;
130
131                 struct
132                 {
133                         bool completed;             /* Generic event completion */
134                 } Gen;
135         } Ev;
136 } Event;
137
138 void event_hook_ignore(Event *event);
139 void event_hook_signal(Event *event);
140 void event_hook_softint(Event *event);
141 void event_hook_generic(Event *event);
142 void event_hook_generic_timeout(Event *event);
143
144 /** Initialize the event \a e as a no-op */
145 #define event_initNone(e) \
146         ((e)->action = event_hook_ignore)
147
148 /** Same as event_initNone(), but returns the initialized event */
149 INLINE Event event_createNone(void);
150 INLINE Event event_createNone(void)
151 {
152         Event e;
153         e.action = event_hook_ignore;
154         return e;
155 }
156
157 /** Initialize the event \a e with a software interrupt (call function \a f, with parameter \a u) */
158 #define event_initSoftint(e,f,u) \
159         ((e)->action = event_hook_softint,(e)->Ev.Int.func = (f), (e)->Ev.Int.user_data = (u))
160
161 /** Same as event_initSoftint(), but returns the initialized event */
162 INLINE Event event_createSoftint(Hook func, void *user_data)
163 {
164         Event e;
165         e.action = event_hook_softint;
166         e.Ev.Int.func = func;
167         e.Ev.Int.user_data = user_data;
168         return e;
169 }
170
171 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
172
173 /** Initialize the event \a e with a signal (send signal \a s to process \a p) */
174 #define event_initSignal(e,p,s) \
175         ((e)->action = event_hook_signal,(e)->Ev.Sig.sig_proc = (p), (e)->Ev.Sig.sig_bit = (s))
176
177 /** Same as event_initSignal(), but returns the initialized event */
178 INLINE Event event_createSignal(struct Process *proc, sigbit_t bit)
179 {
180         Event e;
181         e.action = event_hook_signal;
182         e.Ev.Sig.sig_proc = proc;
183         e.Ev.Sig.sig_bit = bit;
184         return e;
185 }
186
187 #endif
188
189 /**
190  * Prevent the compiler from optimizing access to the variable \a x, enforcing
191  * a refetch from memory. This also forbid from reordering successing instances
192  * of ACCESS_SAFE().
193  *
194  * TODO: move this to cfg/compiler.h
195  */
196 #define ACCESS_SAFE(x) (*(volatile typeof(x) *)&(x))
197
198 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
199 /** Initialize the generic sleepable event \a e */
200 #define event_initGeneric(e) \
201         event_initSignal(e, proc_current(), SIG_SYSTEM5)
202 #else
203 #define event_initGeneric(e) \
204         ((e)->action = event_hook_generic, (e)->Ev.Gen.completed = false)
205 #endif
206
207 /**
208  * Create a generic sleepable event.
209  *
210  * \return the properly initialized generic event structure.
211  */
212 INLINE Event event_createGeneric(void)
213 {
214         Event e;
215         event_initGeneric(&e);
216         return e;
217 }
218
219 /**
220  * Wait the completion of event \a e.
221  */
222 INLINE void event_wait(Event *e)
223 {
224 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
225         e->Ev.Sig.sig_proc = proc_current();
226         sig_wait(e->Ev.Sig.sig_bit);
227 #else
228         while (ACCESS_SAFE(e->Ev.Gen.completed) == false)
229                 cpu_relax();
230         e->Ev.Gen.completed = false;
231         MEMORY_BARRIER;
232 #endif
233 }
234
235 #if CONFIG_TIMER_EVENTS
236 #include <drv/timer.h> /* timer_clock() */
237
238 /* TODO: move these macros to drv/timer.h */
239 #define TIMER_AFTER(x, y) ((long)(y) - (long)(x) < 0)
240 #define TIMER_BEFORE(x, y) TIMER_AFTER(y, x)
241
242 /**
243  * Wait the completion of event \a e or \a timeout elapses.
244  */
245 INLINE bool event_waitTimeout(Event *e, ticks_t timeout)
246 {
247 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
248         e->Ev.Sig.sig_proc = proc_current();
249         return (sig_waitTimeout(e->Ev.Sig.sig_bit, timeout) & SIG_TIMEOUT) ?
250                                 false : true;
251 #else
252         ticks_t end = timer_clock() + timeout;
253         bool ret;
254
255         while ((ACCESS_SAFE(e->Ev.Gen.completed) == false) ||
256                         TIMER_AFTER(timer_clock(), end))
257                 cpu_relax();
258         ret = e->Ev.Gen.completed;
259         e->Ev.Gen.completed = false;
260         MEMORY_BARRIER;
261
262         return ret;
263 #endif
264 }
265 #endif /* CONFIG_TIMER_EVENTS */
266
267 /** Trigger an event */
268 INLINE void event_do(struct Event *e)
269 {
270         e->action(e);
271 }
272
273 #endif /* KERN_EVENT_H */