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 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’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

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

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 <signal.h>

#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.

//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 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:

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 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.

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).