next up previous
Next: Implementing Blocking System Calls Up: FUSD: A Linux Framework Previous: Writing ioctl Callbacks

Subsections


Integrating FUSD With Your Application Using fusd_dispatch()

The example applications we've seen so far have something in common: after initialization and device registration, they call fusd_run(). This gives up control of the program's flow, turning it over to the FUSD library instead. This worked fine for our simple example programs, but doesn't work in a real program that needs to wait for events other than FUSD callbacks. For this reason, our framework provides another way to activate callbacks that does not require the driver to give up control of its main().

Using fusd_dispatch()

Recall from Section 4.1 that fusd_register returns a file descriptor for every device that is successfully registered. This file descriptor can be used to activate device callbacks ``manually,'' without passing control of the application to fusd_run(). Whenever the file descriptor becomes readable according to select(2), it should be passed to fusd_dispatch(), which in turn will activate callbacks in the same way that fusd_run() does. In other words, an application can:

  1. Save the file descriptors returned by fusd_register();
  2. Add those FUSD file descriptors to an fd_set that is passed to select, along with any other file descriptors that might be interesting to the application; and
  3. Pass every FUSD file descriptor that select indicates is readable to fusd_dispatch.

fusd_dispatch() returns 0 if at least one callback was successfully activated. On error, -1 is returned with errno set appropriately. fusd_dispatch() will never block--if no messages are available from the kernel, it will return -1 with errno set to EAGAIN.

Helper Functions for Constructing an fd_set

The FUSD library provides two (optional) utility functions that can make it easier to write applications that integrate FUSD into their own select() loops. Specifically:


\begin{Program}
% latex2html id marker 643\listinginput[5]{1}{drums3.c.example...
...: Waiting for both FUSD and non-FUSD events in a
{\tt select} loop}\end{Program}

The excerpt of drums3.c shown in Program 9 demonstrates the use of these helper functions. This program is similar to the earlier drums.c example: it creates a number of musical instruments such as /dev/drums/bam and /dev/drums/boom. However, in addition to servicing its musical callbacks, the driver also prints a prompt to standard input asking how ``loud'' the drums should be. Instead of turning control of main() over to fusd_run() as in the previous examples, drums3 uses select() to simultaneously watch its FUSD file descriptors and standard input. It responds to input from both sources.

On lines 2-5, an fd_set and its associated ``max'' value are initialized to contain stdin's file descriptor. On line 9, we use fusd_fdset_add to add the FUSD file descriptors for all registered devices. (Not shown in this excerpt is the device registration, which is the same as the registration code we saw in drums.c.) On line 13 we call select, which blocks until one of the fd's in the set is readable. On lines 17 and 18, we check to see if standard input is readable; if so, a function is called which reads the user's response from standard input and prints a new prompt. Finally, on line 21, we call fusd_dispatch_fdset, which in turn will activate the callbacks for devices that have pending system calls waiting to be serviced.

It's worth reiterating that drivers are not required to use the FUSD helper functions fusd_fdset_add and fusd_dispatch_fdset. If it's more convenient, a driver can manually save all of the file descriptors returned by fusd_register, construct its own fd_set, and then call fusd_dispatch on each descriptor that is readable. This method is sometimes required for integration with other frameworks that want to take over your main(). For example, the event-driven GTK user interface framework is event-driven and requires that you pass control of your main to it. However, it does allow you to give it a file descriptor and a function pointer, saying ``Call this callback when select indicates this file descriptor has become readable.'' A GTK application that implements FUSD devices can work by giving GTK all the FUSD file descriptors individually, and calling fusd_dispatch() when GTK calls the associated callbacks.


next up previous
Next: Implementing Blocking System Calls Up: FUSD: A Linux Framework Previous: Writing ioctl Callbacks