4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
30 * Copyright 1999,2001 Bernie Innocenti <bernie@codewiz.org>
35 * \defgroup kern_msg Message box IPC
39 * \brief Simple inter-process messaging system
41 * This module implements a common system for executing
42 * a user defined action calling a hook function.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
96 * A simple message loop works like this:
99 * // Our message port.
100 * static MsgPort test_port;
102 * // A test message with two parameters and a result.
112 * PROC_DEFINE_STACK(sender_stack, KERN_MINSTACKSIZE);
114 * // A process that sends two messages and waits for replies.
115 * static void sender_proc(void)
117 * MsgPort test_reply_port;
122 * msg_initPort(&test_reply_port,
123 * event_createSignal(proc_current(), SIG_SINGLE);
125 * // Fill-in first message and send it out.
128 * msg1.msg.replyPort = &test_reply_port;
129 * msg_put(&test_port, &msg1.msg);
131 * // Fill-in second message and send it out too.
134 * msg2.msg.replyPort = &test_reply_port;
135 * msg_put(&test_port, &msg2.msg);
137 * // Wait for a reply...
138 * sig_wait(SIG_SINGLE);
140 reply = containerof(msg_get(&test_reply_port), TestMsg, msg);
141 * ASSERT(reply != NULL);
142 * ASSERT(reply->result == 5);
144 * // Get reply to second message.
145 * while (!(reply = containerof(msg_get(&test_reply_port), TestMsg, msg)))
147 * // Not yet, be patient and wait some more.
148 * sig_wait(SIG_SINGLE);
151 * ASSERT(reply->result == 9);
155 * // Receive messages and do something boring with them.
156 * static void receiver_proc(void)
158 * msg_initPort(&test_port,
159 * event_createSignal(proc_current(), SIG_EXAMPLE);
161 * proc_new(sender_proc, NULL,sizeof(sender_stack), sender_stack);
165 * sigmask_t sigs = sig_wait(SIG_EXAMPLE | more_signals);
167 * if (sigs & SIG_EXAMPLE)
170 * while((emsg = containerof(msg_get(&test_port), TestMsg, msg)))
172 * // Do something with the message
173 * emsg->result = emsg->x + emsg->y;
174 * msg_reply(emsg->msg);
181 * \author Bernie Innocenti <bernie@codewiz.org>
183 * $WIZ$ module_name = "msg"
184 * $WIZ$ module_depends = "event", "signal", "kernel"
191 #include <mware/event.h>
192 #include <struct/list.h>
193 #include <kern/proc.h>
195 typedef struct MsgPort
197 List queue; /**< Messages queued at this port. */
198 Event event; /**< Event to trigger when a message arrives. */
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 */
211 * Lock a message port.
213 * This is required before reading or manipulating
214 * any field of the MsgPort structure.
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().
220 * \todo Add a configurable policy for locking against
221 * interrupts and locking with semaphorse.
223 * \see msg_unlockPort()
225 INLINE void msg_lockPort(UNUSED_ARG(MsgPort *, port))
231 * Unlock a message port.
233 * \see msg_lockPort()
235 INLINE void msg_unlockPort(UNUSED_ARG(MsgPort *, port))
241 /** Initialize a message port */
242 INLINE void msg_initPort(MsgPort *port, Event event)
244 LIST_INIT(&port->queue);
248 /** Queue \a msg into \a port, triggering the associated event */
249 INLINE void msg_put(MsgPort *port, Msg *msg)
252 ADDTAIL(&port->queue, &msg->link);
253 msg_unlockPort(port);
255 event_do(&port->event);
259 * Get the first message from the queue of \a port.
261 * \return Pointer to the message or NULL if the port was empty.
263 INLINE Msg *msg_get(MsgPort *port)
268 msg = (Msg *)list_remHead(&port->queue);
269 msg_unlockPort(port);
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)
280 msg = (Msg *)port->queue.head.succ;
281 if (LIST_EMPTY(&port->queue))
283 msg_unlockPort(port);
288 /** Send back (reply) \a msg to its sender. */
289 INLINE void msg_reply(Msg *msg)
291 msg_put(msg->replyPort, msg);
294 /** \} */ //defgroup kern_msg
296 int msg_testRun(void);
297 int msg_testSetup(void);
298 int msg_testTearDown(void);
300 #endif /* KERN_MSG_H */