In this Linuxhint article, you’ll learn how to use the poll() function to query or wait for a file to become available in order to perform a specific action. We’ll look at the syntax of this function, its input and output arguments, and the structures it uses. Then, we’ll apply what we’ve learned in a practical example with code snippets and images where we’ll see the step-by-step process on how to insert the headers, declare the necessary variables and structures, and call the poll() function to consult multiple files.
Syntax of the Poll() Function in the C Language
Description of the Poll() Function in the C Language
The poll() function polls one or more open files. The main feature of this function is that it supports polling multiple files and can be used as a query or wait function in read and write operations on pipes, sockets, shared memory objects, and common files.
The “fds” input argument specifies the pointer to an array of pointers to structures of type “pollfd”. Each polled file must have its own structure with a pointer to the array. The structures that are used by poll() are of type “pollfd” and specify the file descriptor and query type in their members and store the returned result via the predefined flags in the “poll.h” header. In the following, you will find a section with a complete description of the “pollfd” structure, its members, and the query and result flags.
The “nfds” input argument specifies the number of pointers to the “pollfd” structures that the array contains. The “timeout” input argument specifies the query mode. If this parameter is sent with 0, poll() performs a simple query without waiting. If specified with a positive value that is greater than 0, this function waits for the files to become available for the maximum time in milliseconds which is specified in this argument.
When the poll() function generates an error, it returns -1 in its output argument. In wait mode, it returns 0 if the time that is specified in timeout has elapsed. In the query mode, the poll() function returns the number of “pollfd” structures with positive results.
The poll() function and its structures are defined in the “poll.h” and “signal.h” files. To use them, we need to insert these headers into our code as follows:
#include <poll.h>
How to Use Poll() as a Simple Query Function in C Language
In this example, we will show you the step-by-step process on how to use the poll() function in a query single mode. To do this, we will create two files named “file1” and “file2” in the “Documents” directory which we will use as query files.
Step 1: Include the Headers
As a first step, we create a file with the “.c” extension and add to it the “stdio.h”, “unistd.h”, “fcntl.h”, “sys/stat.h”, “poll.h”, and “signal.h” headers.
Step 2: Declare the Structures and Variables
The second step is to open a main function of type void main() and define in it the “struct_fds” array with two structures of type “pollfd” and the “fd” integer to temporarily store the descriptor of the files.
Step 3: Open the Files
In this step, we open the files that we want to query. To do this, we call the open() function and specify the path of one of the files as the first argument and the O_RDWR flag as the second argument. This flag is used to assign the read and write permissions to the file.
As an output argument, we send the “fd” integer and the descriptor that is returned in it is copied into the “fd” member of the “struct_fds” structure corresponding to the file.
Step 4: Set the Polling
Now, we select the query that we want to perform with the poll() function. This is done by setting the appropriate flag in the member events of the struct_fds[x] struct. In this case, we check if both files are ready to perform the write operations by setting the POLLOUT flag in the member events of both structures.
Step 5: Call the Poll() Function
Now, we call the poll() function to perform the query on the two previously opened files. To do this, we pass the pointer to the “struct_fds” structure array as the first argument, the number of structures or files that we want to query as the second argument, and pass the value of 0 in timeout, since this is a simple query.
After the query, we use an “if” statement to determine if the result that is returned in the revents member is equal to the POLLOUT query flag. Using the printf() function, we display a message in the command console that informs whether the file is available for writing or not.
Step 6: Close the Files
In this step, we use the close() function to close the open files. Then, we see the code for this example.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//Step 2
void main(){
struct pollfd struct_fds[2];
int fd;
//Step 3
fd = open("Documents/file1", O_RDONLY);
struct_fds[0].fd = fd;
fd = open("Documents/file2", O_RDONLY);
struct_fds[1].fd = fd;
//Step 4
struct_fds[0].events = POLLOUT;
struct_fds[1].events = POLLOUT;
//Step 5
poll( struct_fds, 2, 0);
if ( struct_fds[0].revents == POLLOUT)
printf("The file1 can accept write operations.\n");
else
{
printf("The file1 cannot accept write operations.\n" );
printf("file1 revents = %i\n", struct_fds[0].revents );
}
if ( struct_fds[1].revents == POLLOUT)
printf("The file2 can accept write operations.\n" );
else
{
printf("The file2 cannot accept write operations.\n" );
printf("file2 revents = %i\n", struct_fds[1].revents );
}
//Step 6
sleep (15);
close (struct_fds[0].fd);
close (struct_fds[1].fd);
}
As the following figure shows, the result of the query returns the POLLOUT flag to revents, which is why they accept the write operations to both files.
Now, we comment the open() function that opens the “file1” file, compiles it, and runs the code. In this way, we try to write to a file that has not yet been opened. Therefore, the poll() function in the revents member of the “pollfd” structure corresponding to “file1” should return a result that is equal to 0.
Now, we specify a non-existent descriptor in the “fd” member of the structure corresponding to “file1”, compile it, and run the code.
As we can see in the figure, the poll() function member in this case returns the revents member corresponding to “file1” file with a value of 32 which corresponds to the POLLNVAL error.
The Pollfd Struct in C Language
In the following, you can see a structure of this type and the function that each of its members performs:
int fd; //file descriptor
short events; //polling flag
short revents; //return flag
};
The events member is a short data type that stores a bitmask which indicates what query you want to perform on the file. Then, we see a table with each of the flags and the query that they perform.
Flag | Query |
POLLIN | There is data to read |
POLLPRI | There is an urgent data to read |
POLLOUT | Writing now will not block |
POLLRDNORM | Normal data may be read |
POLLRDBAND | Priority data may be read |
POLLWRNORM | Writing now will not block |
POLLWRBAND | Priority data may be written |
The result of the query is returned in the revents member corresponding to the structure of each queried file. This member is a variable of type short in which the poll() function can return the following results:
Flag | Query |
POLLIN | The file is ready to be read |
POLLPRI | There is urgent data to read |
POLLOUT | The file is ready to be write |
POLLRDNORM | Normal data may be read |
POLLRDBAND | Priority data may be read |
POLLWRNORM | Writing now will not block |
POLLWRBAND | Priority data may be written |
POLLERR | An error occurred |
POLLNVAL | Invalid file identifier |
POLLHUP | In socket or pipes, it indicates that the other end closed the connection |
Conclusion
In this Linuxhint article, we learned how to use the poll() function to query multiple files and determine their availability for operations. We learned the syntax of this function and the input and output arguments it uses. We also showed you what kind of structure poll() uses and the function of each of its members. Then, we applied what we learned in a practical example where we simulated the different query situations and observed the different results that this function returns in GCC.