C Programming

Poll() Function in C Language

When we use files, the integrity of the file and the data that we read and write to it depends on the good programming practices that are applied to these operations. A good practice in the file read, write, and close operations is to query or wait for the availability of the file to perform a particular action on it.

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 learned in a practical example with code snippets and images where we’ll see step by step 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:

int poll (struct pollfd *fds, nfds_t nfds, int timeout);

Description of the Poll() Function in 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 pollfd type. Each polled file must have its own structure with a pointer to the array. The structures that are used by poll() are of pollfd type and they 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 discussion, 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 input argument timeout specifies the query mode. If this parameter is sent with 0, poll() performs a simple query without waiting. If it is 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 that 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 specified time in timeout has elapsed. In 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 <signal.h>

#include <poll.h>

How to Use Poll() as a Simple Query Function in the C Language

In this example, we will show you step by step how to use the poll() function in the query single mode. To do this, we create two files named “file1” and “file2” in the “Documents” directory which we 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 the void main() type and define in it the “struct_fds” array with two structures of the “pollfd” type 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 output argument, we send the “fd” integer. Then, we copy the descriptor that is returned in it 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 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 informing 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. Next, we see the code for this exampleꓽ

//Step 1

#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 are trying 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”. Then, we compile 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 the C Language

In the following image, you can see a structure of this type and the function that each of its members performs:

struct pollfd {
               int fd;                      //file descriptor
               short events;                //polling flag
               short revents;               //return flag
               };

The events member is a short data type that stores a bitmask indicating what query you want to perform on the file. Next, we see a table with each of the flags and the query they perform.

Flag Query
POLLIN There is data to read.
POLLPRI There is 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, 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 different query situations and observed the different results that this function returns in GCC.

About the author

Julio Cesar

Julio Cesar is a 42 years old programmer with 8 years of experience in embedded systems development, 6 years developing firmware for user interfaces in C and C++. Additionally he has 2 years of experience developing scripts for network devices and 3 years as developer of high frequency PCB (Printed Circuit Board).