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