Wait for a message or pulse on a channel
#include <sys/neutrino.h> int MsgReceive( int chid, void * msg, int bytes, struct _msg_info * info ); int MsgReceive_r( int chid, void * msg, int bytes, struct _msg_info * info );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The MsgReceive() and MsgReceive_r() kernel calls wait for a message or pulse to arrive on the channel identified by chid, and store the received data in the buffer pointed to by msg.
These functions are identical, except in the way they indicate errors; see the Returns section for details.
The number of bytes transferred is the minimum of that specified by both the sender and the receiver. The received data isn't allowed to overflow the receive buffer area provided.
The msg buffer must be big enough to contain a pulse. If it isn't, the functions indicate an error of EFAULT. |
If a message is waiting on the channel when you call MsgReceive(), the calling thread doesn't block, and the message is immediately copied. If a message isn't waiting, the calling thread enters the RECEIVE-blocked state until a message arrives.
If multiple messages are sent to a channel without a thread waiting to receive them, the messages are queued in priority order.
The thread's effective priority might change when it receives a message. For more information, see “Priority inheritance and messages” in the Interprocess Communication (IPC) chapter of the System Architecture guide. |
If you pass a non-NULL pointer for info, the functions store additional information about the message and the thread that sent it in the _msg_info structure that info points to. You can get this information later by calling MsgInfo().
On success, MsgReceive() and MsgReceive_r() return:
Don't reply to a pulse. |
In networked message-passing transactions, the most noticeable impact is on the server. The server receives the client's message from the server's local lsm-qnet.so. Note that the receive ID that comes back from MsgReceive() will have some differences, but you don't need to worry about the format of the receive ID — just treat it as a “magic cookie.”
When the server unblocks from its MsgReceive(), it may or may not have received as much of the message as it would in the local case. This is because of the way that message passing is defined — the client and the server agree on the size of the message transfer area (the transmit parameters passed to MsgSend() on the client end) and the size of the message receive area on the server's MsgReceive().
In a local message pass, the kernel would ordinarily limit the size of the transfer to the minimum of both sizes. But in the networked case, the message is received by the client's lsm-qnet.so into its own private buffers and then sent via transport to the remote lsm-qnet.so. Since the size of the server's receive data area can't be known in advance by the client's lsm-qnet.so when the message is sent, only a fixed maximum size (currently 8 KB) message is transferred between the client and the server.
This means, for example, that if the client sends 1 Mbyte of data and the server issues a MsgReceive() with a 1-Mbyte data area, then only the number of bytes determined by a network manager would in fact be transferred. The number of bytes transferred to the server is returned via the last parameter to MsgReceive() or a call to MsgInfo(), specifically the msglen member of struct _msg_info. The client doesn't notice this, because it's still blocked.
You can use the following code to ensure that the desired number of bytes are received. Note that this is handled for you automatically when you're using the resource manager library:
rcvid = MsgReceive(chid, msg, nbytes, &info); /* Doing a network transaction, and not all the message was sent, so get the rest... */ if (rcvid > 0 && info.srcmsglen > info.msglen && info.msglen < nbytes) { int n; if((n = MsgRead_r(rcvid, (char *) msg + info.msglen, nbytes - info.msglen, info.msglen)) < 0) { MsgError(rcvid, -n); continue; } info.msglen += n; }
The only difference between MsgReceive() and MsgReceive_r() is the way they indicate errors. On success, both functions return a positive rcvid if they received a message, or 0 if they received a pulse.
If an error occurs:
This error also occurs if the kernel tries to deliver a pulse to the server, but the size of the receive buffer is less than the size of a struct _pulse. The pulse is lost in this case.
Safety: | |
---|---|
Cancellation point | Yes |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
The maximum size for a one-part message-pass is SSIZE_MAX (i.e., 231 − 1) bytes.
ChannelCreate(), _msg_info, MsgError(), MsgInfo(), MsgRead(), MsgReadv(), MsgReceivePulse(), MsgReceivePulsev(), MsgReceivev(), MsgReply(), MsgReplyv(), MsgSend(), MsgWrite(), MsgWritev(), _pulse, TimerTimeout()
Message Passing chapter of Getting Started with QNX Neutrino