messaging questions...
Matthew Dillon
dillon at apollo.backplane.com
Wed Nov 19 13:33:26 PST 2003
:So, in essence, we are differentiating between a blocking call [there
:is no blocking call per-se] and
:whether the receiver can process the request in a blocking manner. If
:it requires blocking processing
:then we complete the request asynchronously and tell the caller to move
:on.
:
:Essentially everything is "non-blocking" from the users perspective due
:to the ability to queue work
:up internally on a thread's work queue. That thread is not interacting
:with users directly though I would
:assume except maybe to deal with the reply port?
:
:How am I doing? :)
:
:This is a bit different from message passing as I am used to... but
:then I work with MPI all the time.
Yes, in a nutshell. Of course, there's some flexibility there. For
example, in order to make incremental commits DragonFly's current
syscall messaging actually will block (because we haven't rewritten the
kernel syscall backend to deal with the sync/async nature of the
messaging API). But eventually it will follow the semantics correctly.
Also, even if a target could execute something synchronously without
blocking it might decide to queue it anyway due to the complexity
of the operation.
So now you know what the target port's mp_beginmsg() function does, going
back to the front end API lwkt_domsg() and lwkt_sendmsg()... these
functions abstract the interface to the client so the client does not
have to worry about whether something returns EASYNC or not.
lwkt_domsg() looks like this. It basically always returns synchrously
and is allowed to block. If it sees an async result from the target
port function it will then wait for the message to be replied
synchronously, so EASYNC is never returned to the caller.
int
lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
msg->ms_flags &= ~(MSGF_ASYNC | MSGF_REPLY | MSGF_QUEUED);
msg->ms_reply_port = &curthread->td_msgport;
msg->ms_abortreq = 0;
if ((error = lwkt_beginmsg(port, msg)) == EASYNC) {
error = lwkt_waitmsg(msg);
}
return(error);
}
lwkt_sendmsg() looks like this. The caller is always able to assume
EASYNC when they call lwkt_sendmsg(). If the target port function in
fact is able to run the message synchrously, lwkt_sendmsg() will 'fake'
asynchronous operation by replying the message itself.
void
lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
msg->ms_flags |= MSGF_ASYNC;
msg->ms_flags &= ~(MSGF_REPLY | MSGF_QUEUED);
msg->ms_reply_port = &curthread->td_msgport;
msg->ms_abortreq = 0;
if ((error = lwkt_beginmsg(port, msg)) != EASYNC) {
lwkt_replymsg(msg, error);
}
}
The MSGF_ASYNC flag in the above functions serves only as a 'hint' to
the target port's mp_beginmsg function. The target port is free to
return a synchronous or asynchronous result code regardless of what
the client has requested. The client uses the lwkt_domsg() and
lwkt_sendmsg() API to properly abstract the client's wishes and to get
a deterministic 'always asynchronous' or 'always synchronous' result
independant of how the target port actually decides to deal with the
request.
-Matt
More information about the Kernel
mailing list