BeRTOS
|
Simple inter-process messaging system. More...
Functions | |
void | msg_lockPort (UNUSED_ARG(MsgPort *, port)) |
Lock a message port. | |
void | msg_unlockPort (UNUSED_ARG(MsgPort *, port)) |
Unlock a message port. | |
void | msg_initPort (MsgPort *port, Event event) |
Initialize a message port. | |
void | msg_put (MsgPort *port, Msg *msg) |
Queue msg into port, triggering the associated event. | |
Msg * | msg_get (MsgPort *port) |
Get the first message from the queue of port. | |
Msg * | msg_peek (MsgPort *port) |
Peek the first message in the queue of port, or NULL if the port is empty. | |
void | msg_reply (Msg *msg) |
Send back (reply) msg to its sender. |
Simple inter-process messaging system.
This module implements a common system for executing a user defined action calling a hook function.
A message port is an abstraction used to exchange information asynchronously between processes or other entities such as interrupts and call-back functions.
This form of IPC is higher-level than bare signals and semaphores, because it sets a policy for exchanging structured data with well-defined synchronization and ownership semantics.
Before using it, a message port must be initialized by calling msg_initPort(), which associates the port with an Event object, which can be setup to signal a process or invoke a call-back hook.
A process or interrupt routine can deliver messages to any message port by calling msg_put(). By sending a message, the sender temporarly or permanently transfers ownership of its associated data to the receiver.
Queuing a message to a port automatically triggers the associated Event to notify the receiver. When the receiver wakes up, it usually invokes msg_get() to pick the next message from the port.
Message ports can hold any number of pending messages, and receivers usually process them in FIFO order. Other scheduling policies are possible, but not implemented in this API.
After the receiver has done processing a message, it replies it back to the sender with msg_reply(), which transfer ownership back to the original sender. Replies are delivered to a reply port, which is nothing more than another MsgPort structure designated by the sender.
Returning messages to senders is not mandatory, but it provides a convenient way to provide some kind of result and simplify the resource allocation scheme at the same time.
When using signals to receive messages in a process, you call sig_wait() in an event-loop to wake up when messages are delivered to any of your ports. When your process wakes up with the port signal active, multiple messages may already have queued up at the message port, and the process must process them all before returning to sleep. Signals don't keep a nesting count.
A simple message loop works like this:
// Our message port. static MsgPort test_port; // A test message with two parameters and a result. typedef struct { Msg msg; int x, y; int result; } TestMsg; PROC_DEFINE_STACK(sender_stack, KERN_MINSTACKSIZE); // A process that sends two messages and waits for replies. static void sender_proc(void) { MsgPort test_reply_port; TestMsg msg1; TestMsg msg2; Msg *reply; msg_initPort(&test_reply_port, event_createSignal(proc_current(), SIG_SINGLE); // Fill-in first message and send it out. msg1.x = 3; msg1.y = 2; msg1.msg.replyPort = &test_reply_port; msg_put(&test_port, &msg1.msg); // Fill-in second message and send it out too. msg2.x = 5; msg2.y = 4; msg2.msg.replyPort = &test_reply_port; msg_put(&test_port, &msg2.msg); // Wait for a reply... sig_wait(SIG_SINGLE); reply = containerof(msg_get(&test_reply_port), TestMsg, msg); ASSERT(reply != NULL); ASSERT(reply->result == 5); // Get reply to second message. while (!(reply = containerof(msg_get(&test_reply_port), TestMsg, msg))) { // Not yet, be patient and wait some more. sig_wait(SIG_SINGLE); } ASSERT(reply->result == 9); } // Receive messages and do something boring with them. static void receiver_proc(void) { msg_initPort(&test_port, event_createSignal(proc_current(), SIG_EXAMPLE); proc_new(sender_proc, NULL,sizeof(sender_stack), sender_stack); for (;;) { sigmask_t sigs = sig_wait(SIG_EXAMPLE | more_signals); if (sigs & SIG_EXAMPLE) { TestMsg *emsg; while((emsg = containerof(msg_get(&test_port), TestMsg, msg))) { // Do something with the message emsg->result = emsg->x + emsg->y; msg_reply(emsg->msg); } } } }
Msg* msg_get | ( | MsgPort * | port | ) | [inline] |
void msg_lockPort | ( | UNUSED_ARG(MsgPort *, port) | ) | [inline] |
Lock a message port.
This is required before reading or manipulating any field of the MsgPort structure.
Msg* msg_peek | ( | MsgPort * | port | ) | [inline] |
void msg_reply | ( | Msg * | msg | ) | [inline] |
void msg_unlockPort | ( | UNUSED_ARG(MsgPort *, port) | ) | [inline] |