linux轮询脚本,linux驱动的等待队列(阻塞操作)和轮询(poll),缓冲区笔记
覺得還是貼代碼最直接,以后要用的時候也方便參考。
先是相應驅動的詳細代碼:
/* linux/drivers/char/sep4020_char/sep4020_fifo.c
*
* Copyright (c) 2009 leeming
*
* sep4020 fifo driver.
*
* Changelog:
*?12-Aug-2009 leeming?Initial version
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include #include #include #include #include #include #include #include #include #include #include #include #include
#include #include #include #include #include
#define FIFO_MAJOR 252????????? //主設備號
#define MAX_FIFO_BUF 16???????? //按鍵緩沖區(qū)的大小
struct fifodev
{
unsigned char buf[MAX_FIFO_BUF];?? //按鍵緩沖區(qū)
unsigned int current_len;
wait_queue_head_t r_wait;??????????? //讀等待隊列
wait_queue_head_t w_wait;??????????? //寫等待隊列
struct cdev cdev;
} ;
struct fifodev *fifo_dev;???? //鍵盤結構體
//返回讀到的字節(jié)數
static ssize_t sep4020_fifo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
int ret;
// 第二個參數condition必須滿足,否則阻塞
wait_event_interruptible(fifo_dev->r_wait, fifo_dev->current_len != 0);
if(size > fifo_dev->current_len)
size = fifo_dev->current_len;
if(copy_to_user(buf, fifo_dev->buf, size))
{
ret = -EFAULT;
goto out;
}
else
{
memcpy(fifo_dev->buf, fifo_dev->buf+size, fifo_dev->current_len-size);
fifo_dev->current_len = fifo_dev->current_len - size;
wake_up_interruptible(&fifo_dev->w_wait);
ret = size;
}
out:
return ret;
}
//返回寫入的字節(jié)數
static ssize_t sep4020_fifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int ret;
wait_event_interruptible(fifo_dev->r_wait, fifo_dev->current_len != MAX_FIFO_BUF);
if(size > (MAX_FIFO_BUF-fifo_dev->current_len))
{
size = MAX_FIFO_BUF-fifo_dev->current_len;
}
if(copy_from_user(fifo_dev->buf+fifo_dev->current_len, buf, size))
{
ret = -EFAULT;
goto out;
}
else
{
fifo_dev->current_len += size;
ret = size;
}
wake_up_interruptible(&fifo_dev->r_wait);
out:
return ret;
}
//在使用echo或者cat的時候都會調用open函數
static int sep4020_fifo_open(struct inode *inode, struct file *filp)
{
//memset(fifo_dev->buf, 0, MAX_FIFO_BUF);
//fifo_dev->current_len = 0;
return 0;
}
static int sep4020_fifo_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*
#define POLLIN???0x0001 ?//有數據可以讀入,read不會阻塞,注意:select的請情況下,即使到EOF也是ready的.
#define POLLPRI??0x0002?//緊急數據,比如TCP,或者packet模式的peseudo-terminal發(fā)現slave的狀態(tài)有變化.
#define POLLOUT??0x0004?//寫入不會阻塞.
#define POLLERR??0x0008?//輸出出錯
#define POLLHUP??0x0010?//Hang up (output only).
#define POLLNVAL??0x0020?//Invalid request: fd not open (output only).
The rest seem to be more-or-less nonstandard. Check them!
#define POLLRDNORM?0x0040?//POLLIN.
#define POLLRDBAND?0x0080?//高優(yōu)先級的數據read for read (generally unused on Linux).
#define POLLWRNORM?0x0100?//Equivalent to POLLOUT.
#define POLLWRBAND?0x0200?//Priority data may be written.
#define POLLMSG??0x0400
#define POLLREMOVE?0x1000
*/
static unsigned int sep4020_fifo_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
//加入這兩句話是為了在讀寫狀態(tài)發(fā)生變化的時候,通知核心層,讓核心層重新調用poll函數查詢信息。也就是說這兩句只會在select阻塞的時候用到
//當利用select函數發(fā)現既不能讀又不能寫時,select函數會阻塞,但是此時的阻塞并不是輪詢,而是睡眠,通過下面兩個隊列發(fā)生變化時通知select
poll_wait(filp, &fifo_dev->r_wait, wait);
poll_wait(filp, &fifo_dev->w_wait, wait);
if(fifo_dev->current_len != 0)
{
mask |= POLLIN | POLLRDNORM;//可讀,同時寫上POLLRDNORM
}
if(fifo_dev->current_len != MAX_FIFO_BUF)
{
mask |= POLLOUT | POLLWRNORM;//可寫,同時寫上POLLWRNORM
}
return mask;
}
static struct file_operations sep4020_fifo_fops =
{
.owner = THIS_MODULE,
.read? = sep4020_fifo_read,
.write = sep4020_fifo_write,
.poll? = sep4020_fifo_poll,
.open? = sep4020_fifo_open,
.release = sep4020_fifo_release,
};
static int __init sep4020_fifo_init(void)
{
int err,result;
dev_t devno;
devno = MKDEV(FIFO_MAJOR, 0);
result = register_chrdev_region(devno, 1, "sep4020_fifo");?? //向系統(tǒng)靜態(tài)申請設備號
if (result < 0)
{
return result;
}
fifo_dev = kmalloc(sizeof(struct fifodev), GFP_KERNEL);
if (fifo_dev == NULL)
{
result = -ENOMEM;
unregister_chrdev_region(devno, 1);
return result;
}
memset(fifo_dev,0,sizeof(struct fifodev));? //初始化
cdev_init(&fifo_dev->cdev, &sep4020_fifo_fops);
fifo_dev->cdev.owner = THIS_MODULE;
//初始化等待對列
init_waitqueue_head(&fifo_dev->r_wait);
init_waitqueue_head(&fifo_dev->w_wait);
//向系統(tǒng)注冊該字符設備
err = cdev_add(&fifo_dev->cdev, devno, 1);
if (err)
{
printk("fifo adding err\r\n");
unregister_chrdev_region(devno,1);
kfree(fifo_dev);
return err;
}
return 0;
}
static void __exit sep4020_fifo_exit(void)
{
cdev_del(&fifo_dev->cdev);
kfree(fifo_dev);
unregister_chrdev_region(MKDEV(FIFO_MAJOR, 0), 1);
}
module_init(sep4020_fifo_init);
module_exit(sep4020_fifo_exit);
MODULE_AUTHOR("Leeming Zhang");
MODULE_LICENSE("GPL");
/*****************************************************************************************************************/
接下來是相應的應用程序:
#include #include #include #include
int main(int argc, char **argv)
{
int fd;
char buf[16];
fd_set rfds,wfds;?//讀寫描述符集合
unsigned char w_buf[7] = {'a','b','c','d','e','f','g'};
//open的標志位有:O_RDONLY O_WRONLY O_RDWR O_NONBLOCK O_NDELAY O_SYNC O_NOCTY
fd = open("/dev/fifo",O_RDWR);
if(fd == -1)
{
printf("wrong\r\n");
exit(-1);
}
while(1)
{
//初始化文件描述符集合
//清零
FD_ZERO(&rfds);
FD_ZERO(&wfds);
//將文件描述符加入文件描述符集合中,利用函數FD_CLR(int fd,fd_set *set)將一個文件描述符從文件描述符集中清除
FD_SET(fd, &rfds);
FD_SET(fd, &wfds);
//函數原型:int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
//readfds writefds exceptfds分別是被select監(jiān)視的讀,寫和異常處理的文件描述符集合,numfds是需要檢查的文件描述符加1。
select(fd+1, &rfds, &wfds, NULL, NULL);
//判斷是否被置位,通過select函數調用驅動poll函數的返回值,來判斷是否可讀,還是可寫,還是又能讀又能寫;當然如果驅動又不能讀又不能寫,在select那兒會阻塞,直到能讀或者能寫為止
if(FD_ISSET(fd, &rfds))
{
printf("Poll monitor: can be read\n");
}
if(FD_ISSET(fd, &wfds))
{
printf("Poll monitor: can be written\n");
}
}
return 0;
}
總結
以上是生活随笔為你收集整理的linux轮询脚本,linux驱动的等待队列(阻塞操作)和轮询(poll),缓冲区笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux虚拟用户创建目录权限不足,ce
- 下一篇: linux交换分区的文件格式为,LINU