Messages that should be connect messages but aren't

Updated: April 19, 2023

Here's an interesting point you may have noticed. Consider the client's prototype for chown() shown below.

int
chown (const char *path,
       uid_t owner,
       gid_t group);

Remember, a connect message always contains a pathname and is either a one-shot message or establishes a context for further I/O messages.

So, why isn't there a connect message for the client's chown() function? In fact, why is there an I/O message?!? There's certainly no file descriptor implied in the client's prototype!

The answer is, “to make your life simpler!”

Imagine if functions like chown(), chmod(), stat(), and others required the resource manager to look up the pathname and then perform some kind of work. (This is, by the way, the way it was implemented in QNX 4.) The usual problems with this are:

In any event, what happens under QNX Neutrino is that the client constructs a combine message—really just a single message that comprises multiple resource manager messages. Without combine messages, we could simulate chown() with something like this:

int
chown (const char *path, uid_t owner, gid_t group)
{
    int fd, sts;

    if ((fd = open (path, O_RDWR)) == -1) {
        return (-1);
    }
    sts = fchown (fd, owner, group);
    close (fd);
    return (sts);
}

where fchown() is the file-descriptor-based version of chown(). The problem here is that we are now issuing three function calls (and three separate message passing transactions), and incurring the overhead of open() and close() on the client side.

With combine messages, under QNX Neutrino a single message that looks like this is constructed directly by the client's chown() library call:

Figure 1. A combine message.

The message has two parts, a connect part (similar to what the client's open() would have generated) and an I/O part (the equivalent of the message generated by the fchown()). There is no equivalent of the close() because we implied that in our particular choice of connect messages. We used the _IO_CONNECT_COMBINE_CLOSE message, which effectively states “Open this pathname, use the file descriptor you got for handling the rest of the message, and when you run off the end or encounter an error, close the file descriptor.”

The resource manager that you write doesn't have a clue that the client called chown() or that the client did a distinct open(), followed by an fchown(), followed by a close(). It's all hidden by the base-layer library.