This article will help you understand the poll mechanism of interrupt key driver

while (1)
{
read(fd, &key_val, 1);
printf("key_val = 0x%x\n", key_val);
}
  • In the absence of the poll mechanism, most of the time the program is in the sleep position in read. If we don't want the program to stop at this position, but want to read when a key is pressed, so we write the poll function. The test program calls the poll function to determine whether to execute the read function according to the return value.
  • The role of the poll mechanism: it is equivalent to a timer. It sets a certain time to make the process wait for resources. If the interrupt is still in sleep (waiting queue) when the time is up, the poll mechanism will wake up the interrupt and obtain resources once

1.poll mechanism kernel framework

  • As shown in the following figure, when using the poll or select function on the user layer, like the open and read functions, you need to enter the kernel sys_ In the poll function, next we analyze sys_poll function to understand the poll mechanism (located in / fs/select.c)

[ Article welfare] the editor recommends his own Linux kernel technology exchange group:[ 891587639 ]I have sorted out some good learning books and video materials to share in the group files. If necessary, I can add them by myself!!! The top 100 members of the group receive an additional value 699 kernel package (including video tutorials, e-books, practical projects and codes)

Learning through train:

Linux kernel source code / memory tuning / file system / process management / device driver / network protocol stack - learning video tutorial - Tencent classroom ke.qq.com/course/4032547?flowToken=1040236​ke.qq.com/course/4032547? flowToken=1040236​ke.qq.com/course/4032547?flowToken=1040236​ke.qq.com/course/4032547?flowToken=1041712​ke.qq.com/course/4032547? flowToken=1041712​ke.qq.com/course/4032547?flowToken=1041712​ke.qq.com/course/4032547? flowToken=1041712​ke.qq.com/course/4032547?flowToken=1041712​ke.qq.com/course/4032547? flowToken=1041712


Kernel data through train:

Linux kernel source code technology learning route + video tutorial code materials: docs.qq.com/doc/DTkZRWXRFcWx1bWVx docs.qq.com/doc/dtkzrwxrfcwx1bwvx docs.qq.com/doc/DTkZRWXRFcWx1bWVx docs.qq.com/doc/DYXdLeWZSakRRUnFW docs.qq.com/doc/dyxdlewzsakrrunfw docs.qq.com/doc/dyxfobefja0p4 Bunu docs.qq.com/doc/DYXJzcENMd21uTk56 docs.qq.com/doc/DYXdLeWZSakRRUnFW docs.qq.com/doc/DYXFObEFJa0p4bUNU uploading Re upload cancel

1.1 sys_ The poll code is as follows:

asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout_msecs)
{
        if (timeout_msecs > 0)    //Parameter timeout > 0
    {
         timeout_jiffies = msecs_to_jiffies(timeout_msecs);  //How many counts are needed to calculate the timeout time by frequency
    }
    else
    {
          timeout_jiffies = timeout_msecs;    //If the timeout time is 0, assign value directly
       }
  return do_sys_poll(ufds, nfds, &timeout_jiffies);   //Call do_sys_poll. 
}

1.2 then enter do_ sys_ Poll (in fs/select.c):

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
{
  ... ...
  /*Initialize a poll_wqueues variable table*/
  poll_initwait(&table);
  ... ...
  fdcount = do_poll(nfds, head, &table, timeout);
  ... ... 
}

1.3 entering poll_ The initwait function mainly implements the following sentence, which will be analyzed later:

table ->pt-> qproc=__pollwait;    //__ pollwait will be the poll in the driven poll function_ The wait function uses:

1.4 then enter do_poll function, (in fs/select.c):

static int do_poll(unsigned int nfds,  struct poll_list *list, struct poll_wqueues *wait,  s64 *timeout)
{
  ......
       for (;;)
   {
    ......
    set_current_state(TASK_INTERRUPTIBLE);       //Set to wait queue status
    ......
       for (; pfd != pfd_end; pfd++) {             //The for loop runs multiple poll mechanisms
                   /*Substitute the pfd and pt parameters into the poll function registered in our driver*/
                        if (do_pollfd(pfd, pt))     //If non-0 is returned, count + +, and then exit
              {  count++;
                           pt = NULL; } }

    ......

    /*count Non-0(.poll function returns non-0), timeout count to 0, and there is a signal waiting*/

       if (count || !*timeout || signal_pending(current))
                            break;
    ......
  
    /*Enter the sleep state, and exit only when the timeout count reaches 0 or is interrupted to wake up,*/
         __timeout = schedule_timeout(__timeout);

    ......

   }

__set_current_state(TASK_RUNNING);  //Start operation
return count;

}

1.4.1 do above_ How does the pollfd function substitute the pfd and pt parameters? The code is as follows (located in fs/select.c):

static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
      ......
         if (file->f_op && file->f_op->poll)
         mask = file->f_op->poll(file, pwait);
      ......

return mask;
}
  • Above: File - > F_ OP is the file in our driver_ Opration structure, as shown in the following figure:

  • So do_pollfd(pfd, pt) executes our driver poll(pfd, pt) function (start analyzing. poll function in Section 2)

1.4.2 when the poll enters the sleep state, who will wake it up? This is to analyze our driver. Poll function (Section 2 starts to analyze. Poll function)

2. Write the driver. poll function and analyze the. poll function:

  • Add the following code to the driver in the previous section:
#include <linux/poll. h> / / add header file
  
 /*   .poll Drive function: third_poll        */
static unsigned int third_poll(struct file *fp, poll_table * wait)  //fp: file wait:
{
         unsigned int mask =0; 
         poll_wait(fp, &button_wait, wait);
         if(even_press)              //Interrupt event flag, 1: exit sleep state 0: enter sleep state 
         mask |= POLLIN | POLLRDNORM ;
         return mask;     //When timeout, it is returned to the application layer as 0, and when it is awakened, it returns POLLIN | POLLRDNORM;

}

 

static struct file_operations third_drv_fops={
         .owner = THIS_MODULE,
         .open = third_drv_open,
         .read = third_drv_read,
       .release=third_drv_class,   
       .poll = third_poll,           //Create. poll function
};

2.1 in our section 1.4 do_ The poll function has the following code:

if (do_pollfd(pfd, pt))     //If non-0 is returned, count + +, and then exit
{      
     count++;
        pt = NULL;
         }
  • And it is analyzed in 1.4.1 that: do_pollfd(pfd, pt) is the driver third_poll() function,
  • So when we have a key pressed, the driver function third_poll() will return a mask non-0 value, and then in the kernel function do_ The count in the poll is + +, and the poll mechanism exits sleep

2.2 analyze how the poll mechanism in the kernel is awakened by the interrupt in the driver

  • In the drive function third_ There is the following sentence in poll():
poll_wait(fp, &button_wait, wait);

  • As shown in the figure above, substitute the parameter, poll_wait() is executed: P - > qproc (FILP, button_wait, P);
  • It just corresponds to our section 1.3:
table ->pt-> qproc=__pollwait;
  • So poll_ The wait() function calls:__ pollwait(filp, button_wait, p);
  • Then let's analyze it__ Pollwait function. The pollwait code is as follows:
static void __pollwait(struct file  *filp, wait_queue_head_t  *wait_address,poll_table  *p)
{
   ... ...
   //Mount the current process to & Entry - > wait
   init_waitqueue_entry(&entry->wait, current);

   //Add & Entry - > wait to the button_wait interrupt
   add_wait_queue(wait_address, &entry->wait);

}
  • It adds the poll process to the button_wait in the interrupt queue. In this way, when a key is pressed, the button will wake up in the interrupt service function_ The wait interrupt will also wake up the poll mechanism and make the poll mechanism restart the process sleep count

2.3 introduction to return value of driver.poll function

When the sleep state is interrupted, the return mask is 0
When running, return: mask |= POLLIN | POLLRDNORM
The parameters have the following meanings:

  • So POLLIN | POLLRDNORM: common data readable | priority with data readable
  • The mask returns to the poll function of the application layer,

3. Improve the test procedure (third)_ poll_ Text. C (add poll function)

  • In linux, you can use man poll to see how the poll function is used
  • The prototype of the poll function is as follows (# include < poll. H>):
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

Parameter introduction:

1) *fds: is a poll descriptor structure array (can handle multiple polls), and the structure pollfd is as follows:

struct pollfd {
               int   fd;         /* file descriptor File descriptor*/
               short events;     /* requested events Requested event*/
               short revents;    /* returned events Event returned (function return value)*/
           };
  • The events and events value parameters are as follows:

2) nfds: indicates the number of poll. If there is one, fill in 1

3) timeout: how many ms are timed

Return value introduction:

  1. The return value is 0: indicates timeout or fd file descriptor cannot be opened
  2. The return value is - 1: indicating an error
  3. When the return value is > 0, these are the following constants:

  • The final improved test code is as follows:
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <poll. h> / / add the poll header file


/*useg:    thirdtext   */
int main(int argc,char **argv)
{
  int fd,ret;
  unsigned int val=0;
  struct pollfd fds;                          //Define the structure of poll file description               
  fd=open("/dev/buttons",O_RDWR);          

 if(fd<0)
        {printf("can't open!!!\n");
        return -1;}

  fds.fd=fd;                   
  fds.events= POLLIN;           //The request type is normal or priority, with data readable

 while(1)
 {

       ret=poll(&fds,1,5000) ;           //A poll, timed for 5000ms, enters the sleep state
                  if(ret==0)                        //overtime
                   {
                             printf("time out \r\n");
                   }
                   else if(ret>0)                   //The poll mechanism is awakened, indicating that there is data readable
                   {
                            read(fd,&val,1);         //Read a value
                            printf("key_val=0X%x\r\n",val);
                   }  
 }
 return 0;
}

The effect is as follows:

Tags: Linux poll

Posted by DimeDropper on Fri, 12 Aug 2022 21:05:06 +0300