Characteristics of resource managers
As we saw in our examples (above), the key to the flexibility of the resource
managers is that all the functionality of the resource manager is
accessed using standard POSIX function calls—we didn't use
special
functions when talking to the serial port.
But what if you need to do something special,
something
very device-specific?
For example, setting the baud rate on a serial port is an operation that's
very specific to the serial port resource manager—it's totally
meaningless to the filesystem resource manager.
Likewise, setting the file position via
lseek() is useful in a
filesystem, but meaningless in a serial port.
The solution POSIX chose for this is simple.
Some functions, like lseek(), simply return an error code on a
device that doesn't support them.
Then there's the catch-all
(and non-POSIX) device control function, called
devctl(),
that allows device-specific functionality to be provided.
Devices that don't understand the particular devctl() command
simply return an error, just as devices that don't understand the lseek()
command would.
Since we've mentioned lseek() and devctl() as two common commands, it's worthwhile to note that pretty much all file-descriptor (or FILE * stream) function calls are supported by resource managers.
This naturally leads us to the conclusion that resource managers will be
dealing almost exclusively with file-descriptor based function calls.
Since QNX OS is a message-passing operating system,
it follows that the POSIX functions get translated into messages, which are then
sent to resource managers.
It is this POSIX-function to message-passing
translation
trick that lets us decouple clients from resource managers.
All a resource manager has to do is handle certain well-defined messages.
All a client has to do is generate the same well-defined
messages that the resource manager is expecting to receive and handle.
translation layeras thin as possible. For example, when a client does an open() and gets back a file descriptor, the file descriptor is in fact the connection ID! This connection ID (file descriptor) gets used in the client's C library functions (such as read()) where a message is created and sent to the resource manager.