If a device driver expects more than one client at a time--as is often the case--a slightly different programming model is needed for system calls that can potentially block. Instead of blocking, the driver immediately sends a message to the FUSD framework that says, in essence, ``Don't unblock the client that issued this system call, but continue sending additional system call requests that might be coming from other clients.'' Driver callbacks can send this message to FUSD by returning the special value -FUSD_NOREPLY instead of a normal system call return value.
Before a callback blocks the caller by returning -FUSD_NOREPLY, it must save the fusd_file_info pointer that was provided to the callback as its first argument. Later, when an event occurs which allows the client's blocked system call to complete, the driver should call fusd_return(), which will unblock the calling process and complete its system call. fusd_return() takes two arguments:
Drivers should never call fusd_return more than once on a single fusd_file_info pointer. Doing so will have undefined results, similar to calling free() twice on the same pointer.
It also bears repeating that a callback can call either call fusd_return() explicitly or return a normal return value (i.e., not -FUSD_NOREPLY), but not both.
-FUSD_NOREPLY and fusd_return() make it easy for a driver to block a process, then unblock it later when data becomes available. When the callback returns -FUSD_NOREPLY, the driver is freed up to wait for other events, even though the process making the system call is still blocked. The driver can then wait for something to happen that unblocks the original caller--for example, another FUSD event, data from a serial port, or data from the network. (Recall from Section 7 that a FUSD driver can simultaneously wait for both FUSD and non-FUSD events.)
FUSD includes an example program, pager.c, which demonstrates these techniques. The pager driver implements a simple notification interface which lets any number of ``waiters'' wait for a signal from a ``notifier.'' All the waiters wait by trying to read from /dev/pager/notify. Those reads will block until a notifier writes the string page to /dev/pager/input. It's easy to try the application out--run the driver, and then open three other shells. In two of them, type cat /dev/pager/notify. The reads will block. Then, in the third shell, type echo page > /dev/pager/input--the other two shells should become unblocked.
Let's take a look at how this application is implemented, step by step.