A client uses
ionotify()
and
select()
to ask a resource manager
about the status of certain conditions (e.g. whether input data is available).
The conditions may or may not have been met.
The resource manager can be asked to:
- check the status of the conditions immediately, and return if any have been met
- deliver an event later on when a condition is met (this is referred to as arming the resource manager)
The select() function differs from ionotify() in that
most of the work is done in the library.
For example, the client code would be unaware that any event is involved,
nor would it be aware of the blocking function that waits for the event.
This is all hidden in the library code for select().
However, from a resource manager's point of view, there's no difference between
ionotify() and select(); they're handled with the same code.
For more information on the
ionotify()
and
select()
functions, see the QNX Neutrino C Library Reference.
Note:
If multiple threads in the same client perform simultaneous operations
with select() and ionotify(), notification races
may occur.
Since ionotify() and select() require the resource manager to do the same work,
they both send the _IO_NOTIFY message to the resource manager.
The io_notify handler is responsible for handling this message.
Let's start by looking at the format of the message itself:
struct _io_notify {
uint16_t type;
uint16_t combine_len;
int32_t action;
int32_t flags;
struct sigevent event;
};
struct _io_notify_reply {
uint32_t flags;
};
typedef union {
struct _io_notify i;
struct _io_notify_reply o;
} io_notify_t;
Note:
The code samples used in this chapter are not always POSIX-compliant.
As with all resource manager messages,
we've defined a union that contains the input structure (coming into the resource manager),
and a reply or output structure (going back to the client).
The io_notify handler is prototyped with the argument:
io_notify_t *msg
which is the pointer to the union containing the message.
The items in the input structure are:
- type
- combine_len
- action
- flags
- event
The type member has the value _IO_NOTIFY.
The combine_len field has meaning for a combine message; see the
Combine Messages
chapter.
The action member is used by the
iofunc_notify()
helper function to tell it whether it should:
- just check for conditions now
- check for conditions now, and if none are met, arm them
- just arm for transitions
Since iofunc_notify() looks at this, you don't have to worry about it.
The flags member contains the conditions that the client is interested in
and can be any mixture of the following:
- _NOTIFY_COND_INPUT
- This condition is met when there are one or more units of input data
available
(i.e. clients can now issue reads).
The number of units defaults to 1, but you can change it.
The definition of a unit is up to you:
for a character device such as a serial port, it would be a character;
for a POSIX message queue, it would be a message.
Each resource manager selects an appropriate object.
- _NOTIFY_COND_OUTPUT
- This condition is met when there's room in the output buffer
for one or more units of data (i.e. clients can now issue writes).
The number of units defaults to 1, but you can change it.
The definition of a unit is up to you —
some resource managers may default to an empty output buffer
while others may choose some percentage of the buffer empty.
- _NOTIFY_COND_OBAND
- The condition is met when one or more units of out-of-band data are
available.
The number of units defaults to 1, but you can change it.
The definition of out-of-band data is specific to the resource manager.
- _NOTIFY_COND_EXTEN
- The conditions are defined with the following extended flags:
- _NOTIFY_CONDE_RDNORM — normal data is available;
this is the same as _NOTIFY_COND_INPUT.
- _NOTIFY_CONDE_WRNORM — room for normal data;
this is the same as _NOTIFY_COND_OUTPUT.
- _NOTIFY_CONDE_RDBAND — out-of-band data is
available; this is the same as _NOTIFY_COND_OBAND.
- _NOTIFY_CONDE_PRI — priority data is available.
- _NOTIFY_CONDE_WRBAND — room for OOB data.
- _NOTIFY_CONDE_ERR — an error occurred on the
device or stream.
- _NOTIFY_CONDE_HUP — the device has been
disconnected.
- _NOTIFY_CONDE_NVAL — the file descriptor is
invalid.
The event member is what the resource manager delivers once a condition is met.
A resource manager needs to keep a list of clients that want to be notified as conditions are met,
along with the events to use to do the notifying.
When a condition is met,
the resource manager must traverse the list to look for clients that are interested in
that condition, and then deliver the appropriate event.
As well, if a client closes its file descriptor,
then any notification entries for that client must be removed from the list.
To make all this easier, the following structure and helper functions are provided for you
to use in a resource manager:
- iofunc_notify_t structure
- Contains the three notification lists, one for each possible condition.
Each is a list of the clients to be notified for that condition.
- iofunc_notify()
- Adds or removes notification entries; also polls for conditions.
Call this function inside your io_notify handler function.
- iofunc_notify_trigger()
- Sends notifications to queued clients.
Call this function when one or more conditions have been met.
- iofunc_notify_remove()
- Removes notification entries from the list.
Call this function when the client closes its file descriptor.
Note:
Don't return
_RESMGR_NOREPLY from an
io_notify handler, as it may be called multiple times
from a single message if handling multiple file descriptors from
a client call to
select()
or
poll().
This is handled for you if you're using
iofunc_notify().