Update preset.
[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  * \defgroup kern_msg Message box IPC
36  * \ingroup kern
37  * \{
38  *
39  * \brief Simple inter-process messaging system
40  *
41  * This module implements a common system for executing
42  * a user defined action calling a hook function.
43  *
44  * A message port is an abstraction used to exchange information
45  * asynchronously between processes or other entities such as
46  * interrupts and call-back functions.
47  *
48  * This form of IPC is higher-level than bare signals and
49  * semaphores, because it sets a policy for exchanging
50  * structured data with well-defined synchronization and
51  * ownership semantics.
52  *
53  * Before using it, a message port must be initialized by
54  * calling msg_initPort(), which associates the port with
55  * an Event object, which can be setup to signal a process
56  * or invoke a call-back hook.
57  *
58  * A process or interrupt routine can deliver messages to any
59  * message port by calling msg_put().  By sending a message,
60  * the sender temporarly or permanently transfers ownership
61  * of its associated data to the receiver.
62  *
63  * Queuing a message to a port automatically triggers the
64  * associated Event to notify the receiver.  When the
65  * receiver wakes up, it usually invokes msg_get() to pick
66  * the next message from the port.
67  *
68  * \note
69  * When you put a message into a port, such message becomes
70  * unavailable until you retrieve it using msg_get(), eg.
71  * you must not delete it or put it into another port.
72  *
73  * Message ports can hold any number of pending messages,
74  * and receivers usually process them in FIFO order.
75  * Other scheduling policies are possible, but not implemented
76  * in this API.
77  *
78  * After the receiver has done processing a message, it replies
79  * it back to the sender with msg_reply(), which transfer
80  * ownership back to the original sender.  Replies are delivered
81  * to a reply port, which is nothing more than another MsgPort
82  * structure designated by the sender.
83  *
84  * Returning messages to senders is not mandatory, but it provides
85  * a convenient way to provide some kind of result and simplify
86  * the resource allocation scheme at the same time.
87  *
88  * When using signals to receive messages in a process, you
89  * call sig_wait() in an event-loop to wake up when messages
90  * are delivered to any of your ports.  When your process
91  * wakes up with the port signal active, multiple messages
92  * may already have queued up at the message port, and the
93  * process must process them all before returning to sleep.
94  * Signals don't keep a nesting count.
95  *
96  * A simple message loop works like this:
97  *
98  * \code
99  *      // Our message port.
100  *      static MsgPort test_port;
101  *
102  *      // A test message with two parameters and a result.
103  *      typedef struct
104  *      {
105  *              Msg msg;
106  *
107  *              int x, y;
108  *              int result;
109  *      } TestMsg;
110  *
111  *
112  *  PROC_DEFINE_STACK(sender_stack, KERN_MINSTACKSIZE);
113  *
114  *      // A process that sends two messages and waits for replies.
115  *      static void sender_proc(void)
116  *      {
117  *              MsgPort test_reply_port;
118  *              TestMsg msg1;
119  *              TestMsg msg2;
120  *              Msg *reply;
121  *
122  *              msg_initPort(&test_reply_port,
123  *                      event_createSignal(proc_current(), SIG_SINGLE);
124  *
125  *              // Fill-in first message and send it out.
126  *              msg1.x = 3;
127  *              msg1.y = 2;
128  *              msg1.msg.replyPort = &test_reply_port;
129  *              msg_put(&test_port, &msg1.msg);
130  *
131  *              // Fill-in second message and send it out too.
132  *              msg2.x = 5;
133  *              msg2.y = 4;
134  *              msg2.msg.replyPort = &test_reply_port;
135  *              msg_put(&test_port, &msg2.msg);
136  *
137  *              // Wait for a reply...
138  *              sig_wait(SIG_SINGLE);
139  *
140         reply = containerof(msg_get(&test_reply_port), TestMsg, msg);
141  *              ASSERT(reply != NULL);
142  *              ASSERT(reply->result == 5);
143  *
144  *              // Get reply to second message.
145  *              while (!(reply = containerof(msg_get(&test_reply_port), TestMsg, msg)))
146  *              {
147  *                      // Not yet, be patient and wait some more.
148  *                      sig_wait(SIG_SINGLE);
149  *              }
150  *
151  *              ASSERT(reply->result == 9);
152  *      }
153  *
154  *
155  *      // Receive messages and do something boring with them.
156  *      static void receiver_proc(void)
157  *      {
158  *              msg_initPort(&test_port,
159  *                      event_createSignal(proc_current(), SIG_EXAMPLE);
160  *
161  *              proc_new(sender_proc, NULL,sizeof(sender_stack), sender_stack);
162  *
163  *              for (;;)
164  *              {
165  *                      sigmask_t sigs = sig_wait(SIG_EXAMPLE | more_signals);
166  *
167  *                      if (sigs & SIG_EXAMPLE)
168  *                      {
169  *                              TestMsg *emsg;
170  *                              while((emsg = containerof(msg_get(&test_port), TestMsg, msg)))
171  *                              {
172  *                                      // Do something with the message
173  *                                      emsg->result = emsg->x + emsg->y;
174  *                                      msg_reply(emsg->msg);
175  *                              }
176  *                      }
177  *              }
178  *      }
179  * \endcode
180  *
181  * \author Bernie Innocenti <bernie@codewiz.org>
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 /** \} */ //defgroup kern_msg
295
296 int msg_testRun(void);
297 int msg_testSetup(void);
298 int msg_testTearDown(void);
299
300 #endif /* KERN_MSG_H */