26.02.2014 Views

Getting Started with QNX Neutrino - QNX Software Systems

Getting Started with QNX Neutrino - QNX Software Systems

Getting Started with QNX Neutrino - QNX Software Systems

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Handler routines<br />

© 2009, <strong>QNX</strong> <strong>Software</strong> <strong>Systems</strong> GmbH & Co. KG.<br />

Locking, unlocking, and combine message handling<br />

We saw the client side of a combine message when we looked at readblock() (in<br />

“Combine messages”). The client was able to atomically construct a message that<br />

contained multiple resource manager “submessages” — in the example, these were<br />

messages corresponding to the individual functions lseek() and read(). From the<br />

client’s perspective, the two (or more) functions were at least sent atomically (and, due<br />

to the nature of message passing, will be received atomically by the resource<br />

manager). What we haven’t yet talked about is how we ensure that the messages are<br />

processed atomically.<br />

This discussion applies not only to combine messages, but to all I/O messages<br />

received by the resource manager library (except the close message, which we’ll come<br />

back to shortly).<br />

Connect functions notes<br />

The very first thing that the resource manager library does is to lock the attribute<br />

structure corresponding to the resource being used by the received message. Then, it<br />

processes one or more submessages from the incoming message. Finally, it unlocks<br />

the attribute structure.<br />

This ensures that the incoming messages are handled atomically, for no other thread in<br />

the resource manager (in the case of a multithreaded resource manager, of course) can<br />

“jump in” and modify the resource while a thread is busy using it. Without the locking<br />

in place, two client threads could both issue what they believe to be an atomic<br />

combine message (say lseek() and read()). Since the resource manager might have two<br />

different threads running in it and processing messages, the two resource manager<br />

threads could possibly preempt each other, and the lseek() components could interfere<br />

<strong>with</strong> each other. With locking and unlocking, this is prevented, because each message<br />

that accesses a resource will be completed in its entirety atomically.<br />

Locking and unlocking the resource is handled by default helper functions<br />

(iofunc_lock_ocb_default() and iofunc_unlock_ocb_default()), which are placed in<br />

the I/O table at the lock_ocb and unlock_ocb positions. You can, of course, override<br />

these functions if you want to perform further actions during this locking and<br />

unlocking phase.<br />

Note that the resource is unlocked before the io_close() function is called. This is<br />

necessary because the io_close() function will free the OCB, which would effectively<br />

invalidate the pointer used to access the attributes structure, which is where the lock is<br />

stored! Also note that none of the connect functions do this locking, because the<br />

handle that’s passed to them does not have to be an attribute structure (and the locks<br />

are stored in the attribute structure).<br />

Before we dive into the individual messages, however, it’s worth pointing out that the<br />

connect functions all have an identical message structure (rearranged slightly, see<br />

for the original):<br />

struct _io_connect {<br />

228 Chapter 5 • Resource Managers April 30, 2009

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!