The resource manager library handles combine messages by presenting each component of the message to the appropriate handler routines. For example, if we get a combine message that has an _IO_LSEEK and _IO_READ in it (e.g., readblock()), the library will call our io_lseek and io_read handlers for us in turn.
But let's see what happens in the resource manager when it's handling these messages. With multiple threads, both of the client's threads may very well have sent in their atomic combine messages. Two threads in the resource manager will now attempt to service those two messages. We again run into the same synchronization problem as we originally had on the client end—one thread can be partway through processing the message and can then be preempted by the other thread.
The solution? The resource manager library provides callouts to lock the OCB while processing any message (except _IO_CLOSE and _IO_UNBLOCK—we'll return to these). As an example, when processing the readblock() combine message, the resource manager library performs callouts in this order:
Therefore, in our scenario, the two threads within the resource manager would be mutually exclusive to each other by virtue of the lock—the first thread to acquire the lock would completely process the combine message, unlock the lock, and then the second thread would perform its processing.
Let's examine several of the issues that are associated with handling combine messages.