Four Approaches for Applications to Access Hardware Resources
Polling Method
In polling mode, applications continuously check whether data is available.
- When calling the
openfunction, passingO_NONBLOCKsets non-blocking mode. - During a
readcall, if data exists in the driver, it returns immediately with the data; otherwise, it returns an error right away.
int device_fd = open(argv[1], O_RDWR | O_NONBLOCK);
Blocking Sleep-Wakeup Mechanism
With this approach, the application waits until the driver provides data.
- The
openfunction is called withoutO_NONBLOCK. - If data is present during a
read, it returns immediately. Otherwise, the process sleeps in kernel space and resumes execution once the driver signals availability of data.
int device_fd = open(argv[1], O_RDWR);
Event Monitoring with poll/select
These functions allow specifying timeout periods. They return either when conditions are met or upon expiration of the timeout.
- First, use
opento obtain a file descriptor. - Instead of calling
readdirectly, invokepollorselectwith a defined timeout. - Based on their return status, proceed to call
readwhich will then fetch data instantly. - Both
pollandselectsupport monitoring multiple file descriptors and various types of events.
To configure polling:
- Specify the target file descriptor.
- Define the event type (
POLLINfor read readiness,POLLOUTfor write readiness).
#include <poll.h>
struct pollfd monitor_list[1];
int device_fd = open(argv[1], O_RDWR | O_NONBLOCK);
monitor_list[0].fd = device_fd;
monitor_list[0].events = POLLIN;
monitor_list[0].revents = 0;
int result = poll(monitor_list, 1, 5000); // Wait up to 5 seconds
Asynchronous Notification
Asynchronous notification allows the application to perform other tasks while receiving automatic alerts from drivers when data becomes available.
Key aspects of signal delivery:
- Signal Source: Device driver
- Signal Type: Typically
SIGIO - Delivery Mechanism: Kernel-provided signaling APIs
- Recipient: Application process (must register itself)
- Response Action: Execution of a custom signal handler
- Handler Registration: Associating the handler with the specific signal
Implementation steps:
void handle_signal(int sig_num)
{
struct input_event evt;
while (read(device_fd, &evt, sizeof(evt)) == sizeof(evt))
{
printf("Event received: type=0x%x, code=0x%x, value=0x%x\n",
evt.type, evt.code, evt.value);
}
}
/* Register signal handler */
signal(SIGIO, handle_signal);
/* Open device in non-blocking mode */
device_fd = open(argv[1], O_RDWR | O_NONBLOCK);
/* Inform driver about application's PID */
fcntl(device_fd, F_SETOWN, getpid());
/* Enable asynchronous notifications */
int current_flags = fcntl(device_fd, F_GETFL);
fcntl(device_fd, F_SETFL, current_flags | FASYNC);