Additional information for using the saRecvQueue call in a

library.

(Logical change 1.41)


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@119 fd59a12c-fef9-0310-b244-a6a79926bd2f
This commit is contained in:
Steven Dake 2004-07-23 22:15:04 +00:00
parent 61d7f71031
commit c6a4b25b12

View File

@ -665,6 +665,111 @@ responses should be of:
struct res_clm_trackstart
----------------------------------------------------------------------
Using one file descriptor for async and sync requests at the same time
----------------------------------------------------------------------
A library may include async events but must also be able to handle
sync request/responses on the same fd. This is achieved via the
saRecvQueue() api call.
1. First have a look at exec/amf.c::saAmfInitialize.
This function creates a queue to store responses that are not to be
handled by the syncronous function, but instead meant to be handled by
the dispatch (async) function.
/*
* An inq is needed to store async messages while waiting for a
* sync response
*/
error = saQueueInit (&amfInstance->inq, 512, sizeof (void *));
if (error != SA_OK) {
goto error_put_destroy;
}
2. Next have a look at exec/amf.c::saAmfProtectionGroupTrackStart.
This function must ensure that it gets a particular response, even when
it may receive a request for a dispatch (async call). To solve this,
the function queues the message on amfInstance->inq. It will only
return a message in &req_amf_protectiongrouptrackstart once a message
with MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART defined in header->id of
the response is received.
error = saSendRetry (amfInstance->fd,
&req_amf_protectiongrouptrackstart,
sizeof (struct req_amf_protectiongrouptrackstart),
MSG_NOSIGNAL);
if (error != SA_OK) {
goto error_unlock;
}
^^^^^^ This code sends the request
error = saRecvQueue (amfInstance->fd, &message,
&amfInstance->inq, MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART);
^^^^^^^^ This is the API which waits for a particular
response. It will wait until a message with the header
MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART is received. Any other
message it queues for the dispatch function to read the inq.
3. Finally have a look at the exec/amf/saAmfDispatch function.
saQueueIsEmpty(&amfInstance->inq, &empty);
if (empty == 0) {
/*
* Queue is not empty, read data from queue
*/
saQueueItemGet (&amfInstance->inq, (void *)&queue_msg);
msg = *queue_msg;
memcpy (&dispatch_data, msg, msg->size);
saQueueItemRemove (&amfInstance->inq);
} else {
/*
* Queue empty, read response from socket
*/
error = saRecvRetry (amfInstance->fd, &dispatch_data.header,
sizeof (struct message_header), MSG_WAITALL |
MSG_NOSIGNAL);
if (error != SA_OK) {
goto error_unlock;
}
if (dispatch_data.header.size > sizeof (struct
message_header)) {
error = saRecvRetry (amfInstance->fd,
&dispatch_data.data,
dispatch_data.header.size - sizeof (struct
message_header),
MSG_WAITALL | MSG_NOSIGNAL);
if (error != SA_OK) {
goto error_unlock;
}
}
}
This code basically checks if the queue is empty, then reads from the
queue if there is a request, otherwise it reads from the socket.
You might ask why doesn't the poll (not shown) block if there are
messages in the queue but none in the socket. It doesn't block because
every time a saRecvQueue queues a message, it sends a request to the
executive (activate poll) which then sends a dummy message back to the
library (activate poll) which keeps poll from blocking. The dummy
message is ignored by the dispatch function.
Not a great approach (the activate poll stuff). I have an idea to fix
it though. Before a poll is ever done, the inq could be checked to see
if it is empty. If there are messages on the inq, the dispatch function
would not call poll, but instead indicate to the dispatch function to
dispatch messages.
Fortunately most of this activate poll mess is hidden from the library
developer in saRecvQueue (this does the activate poll stuff). The
develoepr simply has to be aware that the activate poll message is
coming and ignore it appropriately.
------------
some notes
------------