.. This work is licensed under a Creative Commons Attribution 4.0 International License. | |
.. SPDX-License-Identifier: CC-BY-4.0 | |
.. CAUTION: this document is generated from source in doc/src/rtd. | |
.. To make changes edit the source and recompile the document. | |
.. Do NOT make changes directly to .rst or .md files. | |
============================================================================================ | |
Man Page: rmr_mt_call | |
============================================================================================ | |
RMR Library Functions | |
============================================================================================ | |
NAME | |
-------------------------------------------------------------------------------------------- | |
rmr_mt_call | |
SYNOPSIS | |
-------------------------------------------------------------------------------------------- | |
:: | |
#include <rmr/rmr.h> | |
extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* msg, int id, int timeout ); | |
DESCRIPTION | |
-------------------------------------------------------------------------------------------- | |
The rmr_mt_call function sends the user application message | |
to a remote endpoint, and waits for a corresponding response | |
message before returning control to the user application. The | |
user application supplies a completed message buffer, as it | |
would for a rmr_send_msg call, but unlike with a send, the | |
buffer returned will have the response from the application | |
that received the message. The thread invoking the | |
*rmr_mt_call()* will block until a message arrives or until | |
*timeout* milliseconds has passed; which ever comes first. | |
Using a timeout value of zero (0) will cause the thread to | |
block without a timeout. | |
The *id* supplied as the third parameter is an integer in the | |
range of 2 through 255 inclusive. This is a caller defined | |
"thread number" and is used to match the response message | |
with the correct user application thread. If the ID value is | |
not in the proper range, the attempt to make the call will | |
fail. | |
Messages which are received while waiting for the response | |
are queued on a *normal* receive queue and will be delivered | |
to the user application with the next invocation of | |
*rmr_mt_rcv()* or *rmr_rvv_msg().* by RMR, and are returned | |
to the user application when rmr_rcv_msg is invoked. These | |
messages are returned in the order received, one per call to | |
rmr_rcv_msg. | |
The Transaction ID | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
The user application is responsible for setting the value of | |
the transaction ID field before invoking *rmr_mt_call.* The | |
transaction ID is a RMR_MAX_XID byte field that is used to | |
match the response message when it arrives. RMR will compare | |
**all** of the bytes in the field, so the caller must ensure | |
that they are set correctly to avoid missing the response | |
message. The application which returns the response message | |
is also expected to ensure that the return buffer has the | |
matching transaction ID. This can be done transparently if | |
the application uses the *rmr_rts_msg()* function and does | |
not adjust the transaction ID. | |
Retries | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
The send operations in RMR will retry *soft* send failures | |
until one of three conditions occurs: | |
1. | |
The message is sent without error | |
2. | |
The underlying transport reports a *hard* failure | |
3. | |
The maximum number of retry loops has been attempted | |
A retry loop consists of approximately 1000 send attempts | |
**without** any intervening calls to *sleep()* or *usleep().* | |
The number of retry loops defaults to 1, thus a maximum of | |
1000 send attempts is performed before returning to the user | |
application. This value can be set at any point after RMr | |
initialisation using the *rmr_set_stimeout()* function | |
allowing the user application to completely disable retires | |
(set to 0), or to increase the number of retry loops. | |
Transport Level Blocking | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
The underlying transport mechanism used to send messages is | |
configured in *non-blocking* mode. This means that if a | |
message cannot be sent immediately the transport mechanism | |
will **not** pause with the assumption that the inability to | |
send will clear quickly (within a few milliseconds). This | |
means that when the retry loop is completely disabled (set to | |
0), that the failure to accept a message for sending by the | |
underlying mechanisms (software or hardware) will be reported | |
immediately to the user application. | |
It should be noted that depending on the underlying transport | |
mechanism being used, it is extremely likely that retry | |
conditions will happen during normal operations. These are | |
completely out of RMR's control, and there is nothing that | |
RMR can do to avoid or mitigate these other than by allowing | |
RMR to retry the send operation, and even then it is possible | |
(e.g., during connection reattempts), that a single retry | |
loop is not enough to guarantee a successful send. | |
RETURN VALUE | |
-------------------------------------------------------------------------------------------- | |
The rmr_mt_call function returns a pointer to a message | |
buffer with the state set to reflect the overall state of | |
call processing. If the state is RMR_OK then the buffer | |
contains the response message; otherwise the state indicates | |
the error encountered while attempting to send the message. | |
If no response message is received when the timeout period | |
has expired, a nil pointer will be returned (NULL). | |
ERRORS | |
-------------------------------------------------------------------------------------------- | |
These values are reflected in the state field of the returned | |
message. | |
RMR_OK | |
The call was successful and the message buffer references | |
the response message. | |
RMR_ERR_BADARG | |
An argument passed to the function was invalid. | |
RMR_ERR_CALLFAILED | |
The call failed and the value of *errno,* as described | |
below, should be checked for the specific reason. | |
RMR_ERR_NOENDPT | |
An endpoint associated with the message type could not be | |
found in the route table. | |
RMR_ERR_RETRY | |
The underlying transport mechanism was unable to accept | |
the message for sending. The user application can retry | |
the call operation if appropriate to do so. | |
The global "variable" *errno* will be set to one of the | |
following values if the overall call processing was not | |
successful. | |
ETIMEDOUT | |
Too many messages were queued before receiving the | |
expected response | |
ENOBUFS | |
The queued message ring is full, messages were dropped | |
EINVAL | |
A parameter was not valid | |
EAGAIN | |
The underlying message system wsa interrupted or the | |
device was busy; the message was **not** sent, and user | |
application should call this function with the message | |
again. | |
EXAMPLE | |
-------------------------------------------------------------------------------------------- | |
The following code bit shows one way of using the rmr_mt_call | |
function, and illustrates how the transaction ID must be set. | |
:: | |
int retries_left = 5; // max retries on dev not available | |
static rmr_mbuf_t* mbuf = NULL; // response msg | |
msg_t* pm; // appl message struct (payload) | |
// get a send buffer and reference the payload | |
mbuf = rmr_alloc_msg( mr, sizeof( pm->req ) ); | |
pm = (msg_t*) mbuf->payload; | |
// generate an xaction ID and fill in payload with data and msg type | |
rmr_bytes2xact( mbuf, xid, RMR_MAX_XID ); | |
snprintf( pm->req, sizeof( pm->req ), "{ \\"req\\": \\"num users\\"}" ); | |
mbuf->mtype = MT_USR_RESP; | |
msg = rmr_mt_call( mr, msg, my_id, 100 ); // wait up to 100ms | |
if( ! msg ) { // probably a timeout and no msg received | |
return NULL; // let errno trickle up | |
} | |
if( mbuf->state != RMR_OK ) { | |
while( retries_left-- > 0 && // loop as long as eagain | |
mbuf->state == RMR_ERR_RETRY && | |
(msg = rmr_mt_call( mr, msg )) != NULL && | |
mbuf->state != RMR_OK ) { | |
usleep( retry_delay ); | |
} | |
if( mbuf == NULL || mbuf->state != RMR_OK ) { | |
rmr_free_msg( mbuf ); // safe if nil | |
return NULL; | |
} | |
} | |
// do something with mbuf | |
SEE ALSO | |
-------------------------------------------------------------------------------------------- | |
rmr_alloc_msg(3), rmr_free_msg(3), rmr_init(3), | |
rmr_mt_rcv(3), rmr_payload_size(3), rmr_send_msg(3), | |
rmr_rcv_msg(3), rmr_rcv_specific(3), rmr_rts_msg(3), | |
rmr_ready(3), rmr_fib(3), rmr_has_str(3), | |
rmr_set_stimeout(3), rmr_tokenise(3), rmr_mk_ring(3), | |
rmr_ring_free(3) |