Poll mechanism of character device

Source: Internet
Author: User

poll mechanism function: the equivalent of a timer, the time has not yet the resources to wake up the process.

The main purpose is: The process is set up for a period of time to wait for resources, if the time to the resource has not arrived, the process immediately from the sleep state wake up no longer waiting. Of course, this is only a situation where resources are useless for the process after that time.

The implementation process of the poll mechanism in the kernel:
The Sys_poll function is declared in the Include/linux/syscalls.h

The function defines the pre-Gahon asmlinkage, which means that these functions pass parameters through the stack rather than through registers. Asmlinkage long Sys_poll (struct POLLFD __user *ufds, unsigned int nfds,long timeout);
in the system call table Arch\arm\kernel\calls. Called in S

Call (Sys_poll)//One of the system invoke jump tables

The initialization of the system call table is in Arch/arm/kernel/entry-common. S medium

. equ nr_syscalls,0  //initializes the Nr_syscalls to 0#define call (x). equ nr_syscalls,nr_syscalls+1  //Defines call (x) as: Nr_ Syscalls = nr_syscalls  + 1#include "calls. S "//Will calls. S content package comes in, call (x) above already has the definition, here is equivalent executes several times nr_syscalls++, finally counted the system calls the number, and to Nr_syscalls carries on the 4 multiples to align, this trick, special is good! #undef CALL//REVOKE call macro defines the # define call (x). long x  //re-defines the macro for call and is also 4-byte aligned Arch/arm/kernel/entry-common. S medium: Sys_syscall:bicscno, R0, #__NR_OABI_SYSCALL_BASEcmpscno, #__NR_syscall-__nr_syscall_basecmpnescno, #NR_  syscalls@ Check rangestmloiasp, {R5, r6}@ shuffle Argsmovlor0, R1movlor1, R2movlor2, R3movlor3, R4ldrlopc, [TBL, Scno, LSL #2]bsys_ni_syscall
The final Sys_poll () function is equivalent to the following function: In the fs/select.c file, Syscall_define3 is a macro definition of a system call with 3 parameters
Syscall_define3 (poll, struct POLLFD __user *, UFDs, unsigned int, nfds,long, timeout_msecs) {... ret = Do_sys_poll (UFDs, Nfds, to);//Call ...}
Well, look at the underlying driver execution line when the application layer calls the poll function
"App:" Poll (); "Kernel:" Sys_polldo_sys_poll (struct POLLFD __user *ufds, unsigned int nfds,struct timespec *end_time) poll _initwait (&table); Init_poll_funcptr (&table->pt, __pollwait);-->pt->qproc = __pollwait; Initialize the QPROC function pointer so that he points to the __pollwait function Do_poll (Nfds, head, &table, End_time); for (;;) {for (; PFD! = Pfd_end; pfd++)//Query multiple drivers {if (DO_POLLFD (PFD, PT)),  mask = file->f_op->poll (file, pwait); ret Urn mask; The {//DO_POLLFD function is equivalent to calling the Xxx_poll function inside the driver, and the following is another analysis, the return value of mask nonzero, count++, the number of processes that recorded the wait event count++;p t = NULL;}} if (count | | | timed_out)//If Count is not 0 (there is a wait event has occurred) or timed_out is not 0 (there is a signal occurrence or timeout), then eject hibernation break;//the above conditions do not meet the following start into hibernation, if there is a waiting event occurred, Timeout or receive signal wake poll_schedule_timeout (Wait, task_interruptible, to, Slack)}
Analysis of the Xxx_poll () function inside the drive
Xxx_poll (struct file *file, poll_table *wait) poll_wait (file, &XXXX_WAITQ, wait);//////////////////////////////// static inline void poll_wait (struct file * Filp, wait_queue_head_t * wait_address, Poll_table *p) {if (P && wait_address) P->qproc (Filp, wait_address, p);//function poll_initwait () before the Qproc () function is set. The pollwait,__pollwait function simply hangs the current process into the waiting queue, just Add_wait_queue (wait_address, &entry->wait); not into hibernation}

Test driver: poll_dev.c

#include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h>//class_create#include < Mach/regs-gpio.h>//s3c2440_gpf1 #include <mach/hardware.h> #include <linux/interrupt.h>//wait_event _interruptible#include <linux/fs.h> #include <linux/poll.h>//poll/* define and initialize the wait queue header */static Declare_wait_ Queue_head (BUTTON_WAITQ); static struct class *buttondev_class;static struct device *buttons_device;static struct pin_ desc{unsigned int pin;unsigned int key_val;}; static struct Pin_desc Pins_desc[4] = {{s3c2410_gpf1,0x01},//S3C2410_GPF1 is the GPF1 pin for this "device" number dev_id{s3c2410_gpf4,0x02} , {s3c2410_gpf2,0x03},{s3c2410_gpf0,0x04},}; static int ev_press = 0;static unsigned char key_val;int major;/* interrupt handling function */static irqreturn_t handle_irq (int irq, void *de v_id) {struct Pin_desc *irq_pindesc = (struct Pin_desc *) dev_id;//unsigned int pinval;pinval = s3c2410_gpio_getpin (Irq_pindesc->pin);//Get Key value: Press to return key value 0/* key value: Press down, 0x01, 0x02, 0x03, 0x04 *//* key value: Release, 0x81, 0x82, 0x83, 0x */if (Pinval) {/* Release */key_val = 0x80 | (Irq_pindesc->key_val);} else{/* Press */key_val = Irq_pindesc->key_val;}   Ev_press = 1;/* Indicates that the interrupt has occurred */wake_up_interruptible (&AMP;BUTTON_WAITQ); /* wakes up the dormant process */return irq_handled;} static int Buttons_dev_open (struct inode * inode, struct file * Filp) {/* k1-eint1,k2-eint4,k3-eint2,k4-eint0 * config GPF1, GPF4, GPF2, GPF0 for the corresponding external interrupt pin * Irqt_bothedge should be changed to Irq_type_edge_both */request_irq (Irq_eint1, HANDLE_IRQ, Irq_type_edge_ Falling, "K1", &pins_desc[0]); REQUEST_IRQ (Irq_eint4, HANDLE_IRQ, irq_type_edge_falling, "K2", &pins_desc[1]) ; Request_irq (Irq_eint2, HANDLE_IRQ, irq_type_edge_falling, "K3", &pins_desc[2]); REQUEST_IRQ (IRQ_EINT0, Handle_ IRQ, irq_type_edge_falling, "K4", &pins_desc[3]); return 0;} static int buttons_dev_close (struct inode *inode, struct file *file) {FREE_IRQ (irq_eint1,&pins_desc[0]); FREE_IRQ ( Irq_eint4,&p ins_desc[1]); FREE_IRQ (irq_eint2,&pins_desc[2]); FREE_IRQ (irq_eint0,&pins_desc[3]); return 0;} Static ssize_t buttons_dev_read (struct file *file, char __user *user, size_t size,loff_t *ppos) {if (size! = 1) RETURN-EINV al;/* when no key is pressed, hibernate. * i.e. ev_press = 0;  * When a button is pressed, an interrupt occurs, and the interrupt handler function wakes up * i.e. ev_press = 1; * After wake up, continue to pass the data through the Copy_to_user function to the application */wait_event_interruptible (BUTTON_WAITQ, ev_press); Copy_to_user (User, & Key_val, 1);/* will ev_press clear 0 */ev_press = 0;return 1;} Key points///////////////////////////////////////static unsigned int buttons_dev_poll (struct File *file, poll_table *wait)//The function will trigger the poll mechanism {unsigned int mask = 0;/* The function once it is called, just hang the process on the BUTTON_WAITQ queue instead of immediately hibernate */poll_ Wait (file, &AMP;BUTTON_WAITQ, wait); /*** * Assuming that the process is also poll in the above function, has not timed out, assuming that there is an interruption at this time, the interrupt handler will ev_press set, and then wake up the corresponding process on the sleep queue ***//* process wake up, immediately down execution. Possible causes of Wakeup: Timeout/interrupt handling */if (ev_press) {Mask |= Pollin |  Pollrdnorm; /* have data readable */}/* if a button is pressed, mask |= Pollin |  Pollrdnorm, otherwise mask = 0 */return mask; }///////////////////////////////* File operations struct for character device */static const struct File_operations buttons_dev_fops = {. owner= this_module,.open= buttons_dev_open,.read= buttons_dev_read,.release = but Tons_dev_close,.poll = buttons_dev_poll,};/* Drive entry function */static int buttons_dev_init (void) {/* main device number set to 0 indicates that the main device number is automatically assigned by the system */m Ajor = Register_chrdev (0, "Buttons_dev", &buttons_dev_fops);/* Create Buttondev class */buttondev_class = Class_create (THIS_ MODULE, "Buttondev");/* Create a buttons device under the Buttondev class for the application to open the device */buttons_device = Device_create (Buttondev_class, NULL, MKDEV (Major, 0), NULL, "buttons");//return 0;} /* Drive Exit Function */static void buttons_dev_exit (void) {Unregister_chrdev (Major, "Buttons_dev");d Evice_unregister (buttons_  Device);  Unload the device under the class Class_destroy (Buttondev_class);//Unload Class}/* module loading and unloading function modification */module_init (buttons_dev_init); Module_exit (Buttons_dev_exit); Module_author ("Clbiao"); Module_description ("Just for Demon");  Module_license ("GPL"); Follow the GPL agreement

Test application: APP_POLL.C

/* The compilation instructions for the file are arm-linux-gcc-static-o app_poll app_poll.c */#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <poll.h>/* fourth_test */int main ( int argc, char *argv[]) {int fd;unsigned char key_val;struct pollfd fds;int ret;fd = open ("/dev/buttons", O_RDWR); if (FD < ; 0) {printf ("open error\n");} FDS.FD = fd;//queried file fds.events = Pollin; Expect to receive a poll_in value indicating that there is data while (1) {/* A value of 0 indicates that the call timed out and  no file descriptors were ready * PO The LL function returns 0 o'clock, indicating that the 5s time is up, and that during this time, no event occurred "data readable" */ret = poll (&fds,1,5000); if (ret = = 0) {printf (' time out\n ');} else/* If there is no timeout, read the key value */{read (fd,&key_val,1);p rintf ("Key_val = 0x%x\n", key_val);}} return 0;}
Test Results:



Summary: Poll flowchart


















Poll mechanism of character device

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.