Doxygen fixes.
[bertos.git] / kern / msg.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999,2001 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \brief Simple inter-process messaging system
10  *
11  * This module implements a common system for executing
12  * a user defined action calling a hook function.
13  *
14  * \version $Id$
15  *
16  * \author Bernardo Innocenti <bernie@develer.com>
17  */
18
19 /*#*
20  *#* $Log$
21  *#* Revision 1.7  2005/02/09 21:48:30  bernie
22  *#* Doxygen fixes.
23  *#*
24  *#* Revision 1.6  2005/01/22 04:20:26  bernie
25  *#* Write extensive documentation; Add simple locking.
26  *#*
27  *#* Revision 1.5  2004/11/28 23:20:25  bernie
28  *#* Remove obsolete INITLIST macro.
29  *#*
30  *#* Revision 1.4  2004/10/19 08:22:09  bernie
31  *#* msg_peek(): New function.
32  *#*
33  *#* Revision 1.3  2004/08/25 14:12:09  rasky
34  *#* Aggiornato il comment block dei log RCS
35  *#*
36  *#* Revision 1.2  2004/08/14 19:37:57  rasky
37  *#* Merge da SC: macros.h, pool.h, BIT_CHANGE, nome dei processi, etc.
38  *#*
39  *#* Revision 1.1  2004/06/06 15:11:08  bernie
40  *#* Import into DevLib.
41  *#*
42  *#*/
43 #ifndef KERN_MSG_H
44 #define KERN_MSG_H
45
46 #include "event.h"
47 #include <mware/list.h>
48
49
50 /*!
51  * Handle queues of messages associated an action.
52  *
53  * A message port is an abstraction used to exchange information
54  * asynchronously between processes or other entities such as
55  * interrupts and call-back functions.
56  *
57  * This form of IPC is higher-level than bare signals and
58  * semaphores, because it sets a policy for exchanging
59  * structured data with well-defined synchronization and
60  * ownership semantics.
61  *
62  * Before using it, a message port must be initialized by
63  * calling msg_initPort(), which associates the port with
64  * an Event object, which can be setup to signal a process
65  * or invoke a call-back hook.
66  *
67  * A process or interrupt routine can deliver messages to any
68  * message port by calling msg_put().  By sending a message,
69  * the sender temporarly or permanently transfers ownership
70  * of its associated data to the receiver.
71  *
72  * Queuing a message to a port automatically triggers the
73  * associated Event to notify the receiver.  When the
74  * receiver wakes up, it usually invokes msg_get() to pick
75  * the next message from the port.
76  *
77  * Message ports can hold any number of pending messages,
78  * and receivers usually process them in FIFO order.
79  * Other scheduling policies are possible, but not implemented
80  * in this API.
81  *
82  * After the receiver has done processing a message, it replies
83  * it back to the sender with msg_reply(), which transfer
84  * ownership back to the original sender.  Replies are delivered
85  * to a reply port, which is nothing more than another MsgPort
86  * structure designated by the sender.
87  *
88  * Returning messages to senders is not mandatory, but it provides
89  * a convenient way to provide some kind of result and simplify
90  * the resource allocation scheme at the same time.
91  *
92  * When using signals to receive messages in a process, you
93  * call sig_wait() in an event-loop to wake up when messages
94  * are delivered to any of your ports.  When your process
95  * wakes up with the port signal active, multiple messages
96  * may already have queued up at the message port, and the
97  * process must process them all before returning to sleep.
98  * Signals don't keep a nesting count.
99  *
100  * A simple message loop works like this:
101  *
102  * \code
103  *      // Our message port.
104  *      static MsgPort test_port;
105  *
106  *      // A test message with two parameters and a result.
107  *      typedef struct
108  *      {
109  *              Msg msg;
110  *
111  *              int x, y;
112  *              int result;
113  *      } TestMsg;
114  *
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(&reply_port,
125  *                      event_createSignal(proc_current(), SIGF_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);
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, &msg1);
138  *
139  *              // Wait for a reply...
140  *              sig_wait(SIG_SINGLE);
141  *
142  *              reply = (TestMsg *)msg_get(&test_reply_port);
143  *              ASSERT(reply != NULL);
144  *              ASSERT(reply->result == 5);
145  *
146  *              // Get reply to second message.
147  *              while (!(reply = (TestMsg *)msg_get(&test_reply_port))
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(), SIGF_EXAMPLE);
162  *
163  *              proc_new(sender_proc, (iptr_t)&test_port,
164  *                      sender_stack, sizeof(sender_stack);
165  *
166  *              for (;;)
167  *              {
168  *                      sigmask_t sigs = sig_wait(SIGF_EXAMPLE | more_signals);
169  *
170  *                      if (sigs & SIGF_EXAMPLE)
171  *                      {
172  *                              TestMsg *emsg;
173  *                              while (emsg = (TestMsg *)msg_get(&test_port)
174  *                              {
175  *                                      // Do something with the message
176  *                                      emsg->result = emsg->x + emsg->y;
177  *                                      msg_reply((Msg *)msg);
178  *                              }
179  *                      }
180  *              }
181  *      }
182  * \endcode
183  */
184 typedef struct MsgPort
185 {
186         List  queue;   /*!< Messages queued at this port. */
187         Event event;   /*!< Event to trigger when a message arrives. */
188 } MsgPort;
189
190
191 typedef struct Msg
192 {
193         Node     link;      /*!< Link into message port queue. */
194         MsgPort *replyPort; /*!< Port to which the msg is to be replied. */
195         /* User data may follow */
196 } Msg;
197
198
199 /*!
200  * Lock a message port.
201  *
202  * This is required before reading or manipulating
203  * any field of the MsgPort structure.
204  *
205  * \note Ports may be locked multiple times and each
206  *       call to msg_lockPort() must be paired with
207  *       a corresponding call to msg_unlockPort().
208  *
209  * \todo Add a configurable policy for locking against
210  *       interrupts and locking with semaphorse.
211  *
212  * \see msg_unlockPort()
213  */
214 INLINE void msg_lockPort(MsgPort *port)
215 {
216         proc_forbid();
217 }
218
219 /*!
220  * Unlock a message port.
221  *
222  * \see msg_lockPort()
223  */
224 INLINE void msg_unlockPort(MsgPort *port)
225 {
226         proc_permit();
227 }
228
229
230 /*! Initialize a message port */
231 INLINE void msg_initPort(MsgPort *port, Event event)
232 {
233         LIST_INIT(&port->queue);
234         port->event = event;
235 }
236
237 /*! Queue \a msg into \a port, triggering the associated event */
238 INLINE void msg_put(MsgPort *port, Msg *msg)
239 {
240         msg_portLock(port);
241         ADDTAIL(&port->queue, &msg->link);
242         msg_portUnlock(port);
243
244         event_do(&port->event);
245 }
246
247 /*!
248  * Get the first message from the queue of \a port.
249  *
250  * \return Pointer to the message or NULL if the port was empty.
251  */
252 INLINE Msg *msg_get(MsgPort *port)
253 {
254         Msg *msg;
255
256         msg_portLock(port);
257         msg = (Msg *)REMHEAD(&port->queue);
258         msg_portUnlock(port);
259
260         return msg;
261 }
262
263 /*! Peek the first message in the queue of \a port, or NULL if the port is empty. */
264 INLINE Msg *msg_peek(MsgPort *port)
265 {
266         Msg *msg;
267
268         msg_portLock(port);
269         msg = (Msg *)port->queue.head;
270         if (ISLISTEMPTY(&port->queue))
271                 msg = NULL;
272         msg_portUnlock(port);
273
274         return msg;
275 }
276
277 /*! Send back (reply) \a msg to its sender. */
278 INLINE void msg_reply(Msg *msg)
279 {
280         msg_put(msg->replyPort, msg);
281 }
282
283 #endif /* KERN_MSG_H */