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.
9 * \brief Simple inter-process messaging system
11 * This module implements a common system for executing
12 * a user defined action calling a hook function.
16 * \author Bernardo Innocenti <bernie@develer.com>
21 *#* Revision 1.7 2005/02/09 21:48:30 bernie
24 *#* Revision 1.6 2005/01/22 04:20:26 bernie
25 *#* Write extensive documentation; Add simple locking.
27 *#* Revision 1.5 2004/11/28 23:20:25 bernie
28 *#* Remove obsolete INITLIST macro.
30 *#* Revision 1.4 2004/10/19 08:22:09 bernie
31 *#* msg_peek(): New function.
33 *#* Revision 1.3 2004/08/25 14:12:09 rasky
34 *#* Aggiornato il comment block dei log RCS
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.
39 *#* Revision 1.1 2004/06/06 15:11:08 bernie
40 *#* Import into DevLib.
47 #include <mware/list.h>
51 * Handle queues of messages associated an action.
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.
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.
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.
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.
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.
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
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.
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.
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.
100 * A simple message loop works like this:
103 * // Our message port.
104 * static MsgPort test_port;
106 * // A test message with two parameters and a result.
116 * // A process that sends two messages and waits for replies.
117 * static void sender_proc(void)
119 * MsgPort test_reply_port;
124 * msg_initPort(&reply_port,
125 * event_createSignal(proc_current(), SIGF_SINGLE);
127 * // Fill-in first message and send it out.
130 * msg1.msg.replyPort = &test_reply_port;
131 * msg_put(&test_port, &msg1);
133 * // Fill-in second message and send it out too.
136 * msg2.msg.replyPort = &test_reply_port;
137 * msg_put(&test_port, &msg1);
139 * // Wait for a reply...
140 * sig_wait(SIG_SINGLE);
142 * reply = (TestMsg *)msg_get(&test_reply_port);
143 * ASSERT(reply != NULL);
144 * ASSERT(reply->result == 5);
146 * // Get reply to second message.
147 * while (!(reply = (TestMsg *)msg_get(&test_reply_port))
149 * // Not yet, be patient and wait some more.
150 * sig_wait(SIG_SINGLE);
153 * ASSERT(reply->result == 9);
157 * // Receive messages and do something boring with them.
158 * static void receiver_proc(void)
160 * msg_initPort(&test_port,
161 * event_createSignal(proc_current(), SIGF_EXAMPLE);
163 * proc_new(sender_proc, (iptr_t)&test_port,
164 * sender_stack, sizeof(sender_stack);
168 * sigmask_t sigs = sig_wait(SIGF_EXAMPLE | more_signals);
170 * if (sigs & SIGF_EXAMPLE)
173 * while (emsg = (TestMsg *)msg_get(&test_port)
175 * // Do something with the message
176 * emsg->result = emsg->x + emsg->y;
177 * msg_reply((Msg *)msg);
184 typedef struct MsgPort
186 List queue; /*!< Messages queued at this port. */
187 Event event; /*!< Event to trigger when a message arrives. */
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 */
200 * Lock a message port.
202 * This is required before reading or manipulating
203 * any field of the MsgPort structure.
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().
209 * \todo Add a configurable policy for locking against
210 * interrupts and locking with semaphorse.
212 * \see msg_unlockPort()
214 INLINE void msg_lockPort(MsgPort *port)
220 * Unlock a message port.
222 * \see msg_lockPort()
224 INLINE void msg_unlockPort(MsgPort *port)
230 /*! Initialize a message port */
231 INLINE void msg_initPort(MsgPort *port, Event event)
233 LIST_INIT(&port->queue);
237 /*! Queue \a msg into \a port, triggering the associated event */
238 INLINE void msg_put(MsgPort *port, Msg *msg)
241 ADDTAIL(&port->queue, &msg->link);
242 msg_portUnlock(port);
244 event_do(&port->event);
248 * Get the first message from the queue of \a port.
250 * \return Pointer to the message or NULL if the port was empty.
252 INLINE Msg *msg_get(MsgPort *port)
257 msg = (Msg *)REMHEAD(&port->queue);
258 msg_portUnlock(port);
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)
269 msg = (Msg *)port->queue.head;
270 if (ISLISTEMPTY(&port->queue))
272 msg_portUnlock(port);
277 /*! Send back (reply) \a msg to its sender. */
278 INLINE void msg_reply(Msg *msg)
280 msg_put(msg->replyPort, msg);
283 #endif /* KERN_MSG_H */