Linux Advanced Character Device driver poll method (select multi-channel monitoring principle and implementation)

Source: Internet
Author: User
Tags readable

1, what is the poll method, what is the function?


2. Select System Call (function)
Select system calls are used for multi-channel monitoring, and select blocks the calling process when no file satisfies the requirement.
int select (int maxfd, fd_set *readfds, Fd_set *writefds, fe_set *exceptfds, const struct Timeval *timeout)
Select System Invocation (Parameters)
1) Maxfd:
The range of file descriptors is 1 larger than the maximum file descriptor to be detected
2) Readfds:
Set of file descriptors that are read monitored
3) Writefds:
Set of file descriptors that are written to monitor
4) Exceptfds:
A set of file descriptors that are monitored abnormally;
5) Timeout:

Timer, timeout takes a different value, the call has a different performance:

The 1>timeout value is 0, regardless of whether a file satisfies the requirements, return immediately, no file satisfies the requirement to return 0, there is a file that satisfies the requirement to return a positive value.
2>timeout for Null,select will block the process until a file meets the requirements
The 3>timeout value is a positive integer, which is the maximum time to wait, that is, select to block the process in Timeout time.
3. Select System call (return value)
When the select call returns, the return value has the following conditions:
1) normally returns the number of file descriptors that meet the requirements;
2) After timeout wait, there is no file to meet the requirements, the return value is 0;
3) If select is interrupted by a signal, it will return-1 and set errno to Eintr.
4) If an error occurs, return-1 and set the corresponding errno.
4. Select system call (use method)
1) Add the files you want to monitor to the file descriptor set
2) call Select to start monitoring
3) Determine if the file has changed
The system provides 4 macros to describe the descriptor operation:
#include <sys/select.h>
void Fd_set (int FD, fd_set *fdset)
void fd_clr (int FD, fd_set *fdset)
void Fd_zero (Fd_set *fdset)
void Fd_isset (int FD, fd_set *fdset)
Macro Fd_set adds the file descriptor fd to the file description descriptor Fdset;
Macro FD_CLR clears the file descriptor fd from the file description descriptor Fdset;
Macro Fd_zero Empty file description descriptor Fdset;
Using Fd_isset to detect file descriptions after the call to select Descriptor Fdset file in FD has changed.
Fd_zero (&fds); Emptying the collection
Fd_set (Fd1,&fds); Setting descriptor
Fd_set (Fd2,&fds); Setting descriptor
maxfdp=fd1+1; Descriptor maximum value plus 1, assuming FD1&GT;FD2
Switch (select (maxfdp,&fds,null,null,&timeout))
Case-1: Exit ( -1); break; Select error, exiting the program
Case 0:break;
Default
if (Fd_isset (FD1,&AMP;FDS))//test fd1 is readable

5. Poll method

Applications often use select system calls, which can block processes. This call is implemented by the driver's poll method, with the prototype: unsigned int (*poll) (struct file *filp,poll_table *wait)

The poll device method is responsible for completing:
1) Use Poll_wait to add the wait queue to the poll_table.
2) Returns a mask that describes whether the device is readable or writable.
Bit mask
1>pollin Device Readable
2>pollrdnorm data can be read
3>pollout\ devices can be written
4>pollwrnorm data can be written
Device readable usually returns (pollin| Pollrdnorm)
Device writable usually returns (pollout| Pollwrnorm)
6. Example
static unsigned int mem_poll (struct file *filp,poll_table *wait)
{
struct Scull_pipe *dev =filp->private_data;
unsigned int mask = 0;
/* Add the wait queue to poll_table */
Poll_wait (filp,&dev->inq,wait);
/* Return mask */
if (with data readable)
Mask = Pollin | pollrdnorm;/* Device Readable */
return mask;
}
7. Working principle
The poll method simply does a registration, the real block occurs in the Do_select function of the select.c.

8. Example Analysis

1) Poll Type equipment drive Memdev.h source code


#ifndef _memdev_h_
#define _memdev_h_

#ifndef Memdev_major
#define MEMDEV_MAJOR 0/* Preset MEM main device number */
#endif

#ifndef Memdev_nr_devs
#define MEMDEV_NR_DEVS 2/* Number of devices */
#endif

#ifndef memdev_size
#define MEMDEV_SIZE 4096
#endif

/*MEM Device Description Structure Body */
struct MEM_DEV
{
Char *data;
unsigned long size;

wait_queue_head_t inq;

};

#endif/* _memdev_h_ */

2) Poll Type equipment drive MEMDEV.C source code

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#include <linux/poll.h>
#include "Memdev.h"

static mem_major = Memdev_major;
BOOL Have_data = false; /* Indicates that the device has enough data to read */

Module_param (mem_major, int, s_irugo);

struct Mem_dev *mem_devp; /* Device Structural body pointer */

struct Cdev Cdev;

/* File Open function */
int Mem_open (struct inode *inode, struct file *filp)
{
struct Mem_dev *dev;

/* Get the secondary device number */
int num = MINOR (Inode->i_rdev);

if (num >= memdev_nr_devs)
Return-enodev;
dev = &mem_devp[num];

/* Assign the device description structure pointer to the file private data pointer */
Filp->private_data = Dev;

return 0;
}

/* File deallocation function */
int mem_release (struct inode *inode, struct file *filp)
{
return 0;
}

/* Read function */
Static ssize_t mem_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct Mem_dev *dev = filp->private_data; /* Get the device structure pointer */

/* Determine if the read position is valid */
if (P >= memdev_size)
return 0;
if (Count > Memdev_size-p)
Count = memdev_size-p;

while (!have_data)/* has no data to read, consider why not use the IF, while */
{
if (Filp->f_flags & O_nonblock)
Return-eagain;

Wait_event_interruptible (Dev->inq,have_data);
}

/* Read data to User space */
if (Copy_to_user (buf, (void*) (Dev->data + P), count))
{
ret =-Efault;
}
Else
{
*ppos + = count;
ret = count;

PRINTK (kern_info "read%d bytes (s) from%d\n", Count, p);
}

Have_data = false; /* Indicates no more data to read */
/* Wake up the Write process */
return ret;
}

/* Write function */
Static ssize_t mem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct Mem_dev *dev = filp->private_data; /* Get the device structure pointer */

/* Parse and get a valid write length */
if (P >= memdev_size)
return 0;
if (Count > Memdev_size-p)
Count = memdev_size-p;

/* Write data from user space */
if (Copy_from_user (Dev->data + p, buf, Count))
ret =-Efault;
Else
{
*ppos + = count;
ret = count;

PRINTK (kern_info "written%d bytes (s) from%d\n", Count, p);
}

Have_data = true; /* There are new data to read */

/* Wake-up Read process */
Wake_up (& (DEV-&GT;INQ));

return ret;
}

/* Seek file Locator function */
Static loff_t mem_llseek (struct file *filp, loff_t offset, int whence)
{
loff_t Newpos;

Switch (whence) {
Case 0:/* seek_set */
Newpos = offset;
Break

Case 1:/* seek_cur */
Newpos = Filp->f_pos + offset;
Break

Case 2:/* seek_end */
Newpos = memdev_size-1 + offset;
Break

Default:/* can ' t happen */
Return-einval;
}
if ((newpos<0) | | | (newpos>memdev_size))
Return-einval;

Filp->f_pos = Newpos;
return newpos;

}
unsigned int mem_poll (struct file *filp, poll_table *wait)
{
struct Mem_dev *dev = filp->private_data;
unsigned int mask = 0;

/* Add the wait queue to the poll_table table */
Poll_wait (FILP, &dev->inq, wait);


if (Have_data)

Mask |= Pollin |  Pollrdnorm; /* readable */


return mask;
}


/* File operation structure */
static const struct File_operations Mem_fops =
{
. Owner = This_module,
. Llseek = Mem_llseek,
. Read = Mem_read,
. write = Mem_write,
. open = Mem_open,
. Release = Mem_release,
. Poll = Mem_poll,
};

/* Device driver module load function */
static int memdev_init (void)
{
int result;
int i;

dev_t Devno = MKDEV (mem_major, 0);

/* Static application device number */
if (mem_major)
result = Register_chrdev_region (Devno, 2, "Memdev");
else/* Dynamically assign device number */
{
result = Alloc_chrdev_region (&devno, 0, 2, "Memdev");
Mem_major = Major (Devno);
}

if (Result < 0)
return result;

/* Initialize the CDEV structure */
Cdev_init (&cdev, &mem_fops);
Cdev.owner = This_module;
Cdev.ops = &mem_fops;

/* Register character device */
Cdev_add (&cdev, MKDEV (mem_major, 0), Memdev_nr_devs);

/* Allocate memory for device description structure */
MEM_DEVP = Kmalloc (Memdev_nr_devs * sizeof (struct mem_dev), gfp_kernel);
if (!MEM_DEVP)/* Request failed */
{
result =-Enomem;
Goto Fail_malloc;
}
memset (MEM_DEVP, 0, sizeof (struct mem_dev));

/* Allocate memory for device */
for (i=0; i < Memdev_nr_devs; i++)
{
Mem_devp[i].size = memdev_size;
Mem_devp[i].data = Kmalloc (memdev_size, Gfp_kernel);
memset (mem_devp[i].data, 0, memdev_size);

/* Initialize the wait queue */
Init_waitqueue_head (& (MEM_DEVP[I].INQ));
Init_waitqueue_head (& (MEM_DEVP[I].OUTQ));
}

return 0;

Fail_malloc:
Unregister_chrdev_region (Devno, 1);

return result;
}

/* Module Unload function */
static void Memdev_exit (void)
{
Cdev_del (&cdev); /* Unregister the device */
Kfree (MEM_DEVP); /* release device structure in vivo */
Unregister_chrdev_region (MKDEV (mem_major, 0), 2); /* Release the device number */
}

Module_author ("David Xie");
Module_license ("GPL");

Module_init (Memdev_init);

Module_exit (Memdev_exit);

3) test procedure APP-READ.C Source code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>

int main ()
{
int FD;
Fd_set RDS; Declaration Descriptor Collection
int ret;
Char buf[128];

/* Initialize buf*/
strcpy (Buf, "Memdev is char dev!");
printf ("BUF:%s\n", BUF);

/* Open the device file */
FD = open ("/dev/memdev0", O_RDWR);

Fd_zero (&rds); Empty Descriptor Collection
Fd_set (FD, &rds); Set Descriptor Collection

/* Clear buf*/
strcpy (Buf, "Buf is null!");
printf ("Read BUF1:%s\n", Buf);

ret = SELECT (FD + 1, &rds, NULL, NULL, NULL);//Call the Select () Monitor function
if (Ret < 0)
{
printf ("Select error!\n");
Exit (1);
}
if (Fd_isset (FD, &rds))//test fd1 is readable
Read (FD, Buf, sizeof (BUF));

/* Test Results */
printf ("Read BUF2:%s\n", Buf);

Close (FD);

return 0;
}

Linux Advanced Character Device driver poll method (select multi-channel monitoring principle and implementation)

Related Article

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.