Silent some gcc "no previous prototype" build warnings.
[bertos.git] / bertos / kern / msg.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 2004 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 1999,2001 Bernie Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  *
35  * This module implements a common system for executing
36  * a user defined action calling a hook function.
37  *
38  * \version $Id$
39  *
40  * \author Bernie Innocenti <bernie@codewiz.org>
41  *
42  * \brief Simple inter-process messaging system
43  *
44  * Handle queues of messages associated an action.
45  *
46  * A message port is an abstraction used to exchange information
47  * asynchronously between processes or other entities such as
48  * interrupts and call-back functions.
49  *
50  * This form of IPC is higher-level than bare signals and
51  * semaphores, because it sets a policy for exchanging
52  * structured data with well-defined synchronization and
53  * ownership semantics.
54  *
55  * Before using it, a message port must be initialized by
56  * calling msg_initPort(), which associates the port with
57  * an Event object, which can be setup to signal a process
58  * or invoke a call-back hook.
59  *
60  * A process or interrupt routine can deliver messages to any
61  * message port by calling msg_put().  By sending a message,
62  * the sender temporarly or permanently transfers ownership
63  * of its associated data to the receiver.
64  *
65  * Queuing a message to a port automatically triggers the
66  * associated Event to notify the receiver.  When the
67  * receiver wakes up, it usually invokes msg_get() to pick
68  * the next message from the port.
69  *
70  * \note
71  * When you put a message into a port, such message becomes
72  * unavailable until you retrieve it using msg_get(), eg.
73  * you must not delete it or put it into another port.
74  *
75  * Message ports can hold any number of pending messages,
76  * and receivers usually process them in FIFO order.
77  * Other scheduling policies are possible, but not implemented
78  * in this API.
79  *
80  * After the receiver has done processing a message, it replies
81  * it back to the sender with msg_reply(), which transfer
82  * ownership back to the original sender.  Replies are delivered
83  * to a reply port, which is nothing more than another MsgPort
84  * structure designated by the sender.
85  *
86  * Returning messages to senders is not mandatory, but it provides
87  * a convenient way to provide some kind of result and simplify
88  * the resource allocation scheme at the same time.
89  *
90  * When using signals to receive messages in a process, you
91  * call sig_wait() in an event-loop to wake up when messages
92  * are delivered to any of your ports.  When your process
93  * wakes up with the port signal active, multiple messages
94  * may already have queued up at the message port, and the
95  * process must process them all before returning to sleep.
96  * Signals don't keep a nesting count.
97  *
98  * A simple message loop works like this:
99  *
100  * \code
101  *      // Our message port.
102  *      static MsgPort test_port;
103  *
104  *      // A test message with two parameters and a result.
105  *      typedef struct
106  *      {
107  *              Msg msg;
108  *
109  *              int x, y;
110  *              int result;
111  *      } TestMsg;
112  *
113  *
114  *  PROC_DEFINE_STACK(sender_stack, KERN_MINSTACKSIZE);
115  *
116  *      // A process that sends two messages and waits for replies.
117  *      static void sender_proc(void)
118  *      {
119  *              MsgPort test_reply_port;
120  *              TestMsg msg1;
121  *              TestMsg msg2;
122  *              Msg *reply;
123  *
124  *              msg_initPort(&test_reply_port,
125  *                      event_createSignal(proc_current(), SIG_SINGLE);
126  *
127  *              // Fill-in first message and send it out.
128  *              msg1.x = 3;
129  *              msg1.y = 2;
130  *              msg1.msg.replyPort = &test_reply_port;
131  *              msg_put(&test_port, &msg1.msg);
132  *
133  *              // Fill-in second message and send it out too.
134  *              msg2.x = 5;
135  *              msg2.y = 4;
136  *              msg2.msg.replyPort = &test_reply_port;
137  *              msg_put(&test_port, &msg2.msg);
138  *
139  *              // Wait for a reply...
140  *              sig_wait(SIG_SINGLE);
141  *
142         reply = containerof(msg_get(&test_reply_port), TestMsg, msg);
143  *              ASSERT(reply != NULL);
144  *              ASSERT(reply->result == 5);
145  *
146  *              // Get reply to second message.
147  *              while (!(reply = containerof(msg_get(&test_reply_port), TestMsg, msg)))
148  *              {
149  *                      // Not yet, be patient and wait some more.
150  *                      sig_wait(SIG_SINGLE);
151  *              }
152  *
153  *              ASSERT(reply->result == 9);
154  *      }
155  *
156  *
157  *      // Receive messages and do something boring with them.
158  *      static void receiver_proc(void)
159  *      {
160  *              msg_initPort(&test_port,
161  *                      event_createSignal(proc_current(), SIG_EXAMPLE);
162  *
163  *              proc_new(sender_proc, NULL,sizeof(sender_stack), sender_stack);
164  *
165  *              for (;;)
166  *              {
167  *                      sigmask_t sigs = sig_wait(SIG_EXAMPLE | more_signals);
168  *
169  *                      if (sigs & SIG_EXAMPLE)
170  *                      {
171  *                              TestMsg *emsg;
172  *                              while((emsg = containerof(msg_get(&test_port), TestMsg, msg)))
173  *                              {
174  *                                      // Do something with the message
175  *                                      emsg->result = emsg->x + emsg->y;
176  *                                      msg_reply(emsg->msg);
177  *                              }
178  *                      }
179  *              }
180  *      }
181  * \endcode
182  *
183  * $WIZ$ module_name = "msg"
184  * $WIZ$ module_depends = "event", "signal", "kernel"
185  */
186
187
188 #ifndef KERN_MSG_H
189 #define KERN_MSG_H
190
191 #include <mware/event.h>
192 #include <struct/list.h>
193 #include <kern/proc.h>
194
195 typedef struct MsgPort
196 {
197         List  queue;   /**< Messages queued at this port. */
198         Event event;   /**< Event to trigger when a message arrives. */
199 } MsgPort;
200
201
202 typedef struct Msg
203 {
204         Node     link;      /**< Link into message port queue. */
205         MsgPort *replyPort; /**< Port to which the msg is to be replied. */
206         /* User data may follow */
207 } Msg;
208
209
210 /**
211  * Lock a message port.
212  *
213  * This is required before reading or manipulating
214  * any field of the MsgPort structure.
215  *
216  * \note Ports may be locked multiple times and each
217  *       call to msg_lockPort() must be paired with
218  *       a corresponding call to msg_unlockPort().
219  *
220  * \todo Add a configurable policy for locking against
221  *       interrupts and locking with semaphorse.
222  *
223  * \see msg_unlockPort()
224  */
225 INLINE void msg_lockPort(UNUSED_ARG(MsgPort *, port))
226 {
227         proc_forbid();
228 }
229
230 /**
231  * Unlock a message port.
232  *
233  * \see msg_lockPort()
234  */
235 INLINE void msg_unlockPort(UNUSED_ARG(MsgPort *, port))
236 {
237         proc_permit();
238 }
239
240
241 /** Initialize a message port */
242 INLINE void msg_initPort(MsgPort *port, Event event)
243 {
244         LIST_INIT(&port->queue);
245         port->event = event;
246 }
247
248 /** Queue \a msg into \a port, triggering the associated event */
249 INLINE void msg_put(MsgPort *port, Msg *msg)
250 {
251         msg_lockPort(port);
252         ADDTAIL(&port->queue, &msg->link);
253         msg_unlockPort(port);
254
255         event_do(&port->event);
256 }
257
258 /**
259  * Get the first message from the queue of \a port.
260  *
261  * \return Pointer to the message or NULL if the port was empty.
262  */
263 INLINE Msg *msg_get(MsgPort *port)
264 {
265         Msg *msg;
266
267         msg_lockPort(port);
268         msg = (Msg *)list_remHead(&port->queue);
269         msg_unlockPort(port);
270
271         return msg;
272 }
273
274 /** Peek the first message in the queue of \a port, or NULL if the port is empty. */
275 INLINE Msg *msg_peek(MsgPort *port)
276 {
277         Msg *msg;
278
279         msg_lockPort(port);
280         msg = (Msg *)port->queue.head.succ;
281         if (LIST_EMPTY(&port->queue))
282                 msg = NULL;
283         msg_unlockPort(port);
284
285         return msg;
286 }
287
288 /** Send back (reply) \a msg to its sender. */
289 INLINE void msg_reply(Msg *msg)
290 {
291         msg_put(msg->replyPort, msg);
292 }
293
294 int msg_testRun(void);
295 int msg_testSetup(void);
296 int msg_testTearDown(void);
297
298 #endif /* KERN_MSG_H */