In other operating systems, this functionality is traditionally associated
with device drivers. But unlike device drivers, Neutrino's resource managers
don't require any special arrangements with the kernel. In fact, a
resource manager looks just like any other user-level program.
initialize the dispatch interface
register the pathname with the process manager
DO forever
receive a message
SWITCH on the type of message
CASE io_open:
perform io_open processing
ENDCASE
CASE io_read:
perform io_read processing
ENDCASE
CASE io_write:
perform io_write processing
ENDCASE
. // etc.
handle all other messages
. // that
may occur, performing
. // processing
as appropriate
ENDSWITCH
ENDDO
The architecture contains three parts:
1.A channel is created so that client programs can connect to
the resource manager to send it messages.
2.The pathname (or pathnames) that the resource manager is going
to be responsible for is registered with the process manager, so that it
can
resolve open requests for that particular pathname
to this resource manager.
3.Messages are received and processed.
Note: The library can hide lots of this. You don't have
to write the loop. You can just register handlers, and each handler
gets called when the right message comes. Rather like Java mouseEvents.
Combined Messages
Exchanging lots of little messages can be slow. Much nicer is
to group the messages into a single exchange. For example, a stat() is
the group open(), fstat(), close(). Readblock() is seek(), read().
The standard resource manager library recieves a group, and breaks it into
each message for you. You just recieve the individual messages, and
have no idea they are part of a group.
The first data structure is the context, It holds data used on a per-open basis, such as the current position into a file (the lseek() offset).
Because a resource manager may be responsible for more than one device
(e.g. devc-ser* may be responsible for /dev/ser1, /dev/ser2,
/dev/ser3, etc.), the attributes structure holds data on a per-device
basis. The attributes structure contains such items as the user and group
ID of
the owner of the device, the last modification time, etc.
For block I/O devices, one more structure is used. This is the mount structure, which contains data items that are global to the entire mount device.
The library assumes that you use the default structure types. You can add new members (AT THE BOTTOM) but not delete any mambers. Each member must have the standard semantics. Therfore f_pos better be in bytes, not blocks.
Code for a Resource Manager
See the qnx documentation at http://qdn.qnx.com/support/docs/neutrino_2.11_en/prog/resmgr.html#SIMPLE_ST_EG