linux进程阻塞例子,linux阻塞与非阻塞驱动例子

这里主要是例子,分析在另一篇博文,下面是支持阻塞操作的设备驱动代码

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define GLOBALMEM_SIZE 0x1000

#define MEM_CLEAR 0x1

#define GLOBALMEM_MAJOR 250

static struct class *firstdrv_class;//自动建立设备节点时要用到

static int globalmem_major = GLOBALMEM_MAJOR;

//设备结构体

struct globalmem_dev{

struct cdev cdev;

unsigned int current_len;//fifo有效长度

unsigned char mem[GLOBALMEM_SIZE];

struct semaphore sem;//并发控制用到的信号量

wait_queue_head_t r_wait;//阻塞读用到的等待队列头

wait_queue_head_t w_wait;;//阻塞写用到的等待队列头

};

struct globalmem_dev *globalmem_devp;

int globalmem_open(struct inode *inode,struct file *filp)

{

filp->private_data =

globalmem_devp;//将设备结构体指针赋给文件私有数据指针

return 0;

}

int globalmem_release(struct inode *inode,struct file *filp)

{

return 0;

}

static int globalmem_ioctl(struct inode *inodeep,struct file

*filp,unsigned int cmd,unsigned long arg)

{

struct globalmem_dev *dev =

filp->private_data;

switch (cmd) {

case MEM_CLEAR :

if

(down_interruptible(&dev->sem))//获得信号量

return -ERESTARTSYS;//如果返回非0说明进程在等待时被信号打断

memset(dev->mem,0,GLOBALMEM_SIZE);//清除全局内存

up(&dev->sem);//释放信号量

printk(KERN_INFO "globalmem is

set to zero\n");

break;

default :

return -EINVAL;

}

return 0;

}

static ssize_t globalmem_read(struct file *filp,char __user

*buf,size_t count,loff_t *ppos)

{

int ret;

struct globalmem_dev *dev =

filp->private_data;//获得设备结构体指针

DECLARE_WAITQUEUE(wait,current);//定义等待队列并初始化

down(&dev->sem);//获得信号

add_wait_queue(&dev->r_wait,&wait);//把队列加到wait队列头去

while(dev->current_len == 0){//如果数据缓冲区为空,表示不可读

if(filp->f_flags

&O_NONBLOCK){//如果以非阻塞打开

ret = -EAGAIN;

goto out;//释放信号

}

__set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为TASK_INTERRUPTIBLE,进程进入休眠

up(&dev->sem);释放信号

schedule();//调用其它进程

if(signal_pending(current)){//如果是信号打断进程

ret = -ERESTARTSYS;

goto

out2;//主要是把队列(进程)从队列头中拉出,并改变进程状态

}

// down(&dev->sem);

}

if(count > dev->current_len)

count = dev->current_len;

if(copy_to_user(buf,dev->mem,count)){

return -EFAULT;

goto out;

}else {

memcpy(dev->mem,dev->mem +

count,dev->current_len - count);//fifo数据前移

dev->current_len -= count;//有效长度减少

printk(KERN_INFO "read %d bytes(s)

courrent_len:%d\n",count,dev->current_len);

printk(KERN_INFO "mydyy TQ2440\n");

wake_up_interruptible(&dev->w_wait);//唤醒写等待队列

ret = count;

}

out: up(&dev->sem);

out2:remove_wait_queue(&dev->r_wait,&wait);//移除等待队列

set_current_state(TASK_RUNNING);//改变进程状态为TASK_RUNNING

return ret;

}

static ssize_t globalmem_write(struct file *filp,const char

__user *buf,size_t count,loff_t *ppos)

{

int ret;

struct globalmem_dev *dev =

filp->private_data;//获得设备结构体指针

DECLARE_WAITQUEUE(wait,current);//定义并初始化写等待队列

down(&dev->sem);//获得信号

add_wait_queue(&dev->w_wait,&wait);//把写等待队列加到队列头

while(dev->current_len ==

GLOBALMEM_SIZE){//如果fifo已满

if(filp->f_flags &

O_NONBLOCK){//以非阻塞方式打开

ret = -EAGAIN;

goto out;//释放信号

}

__set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为TASK_INTERRUPTIBLE

up(&dev->sem);//释放信号

schedule();//调度其它进程

if(signal_pending(current)){//如果是信号打断

ret = -ERESTARTSYS;

goto

out2;//主要是把队列从队列头中拉出,并改变进程状态

}

// down(&dev->sem);

}

if(count > GLOBALMEM_SIZE -

dev->current_len)

count = GLOBALMEM_SIZE - dev->current_len;

if(copy_from_user(dev->mem +

dev->current_len,buf,count)){

return -EFAULT;

goto out;

}else {

dev->current_len += count;//有效长度变长

printk(KERN_INFO "write %d bytes(s) current_len

%d\n",count,dev->current_len);

printk(KERN_INFO "mycgy TQ2440\n");

wake_up_interruptible(&dev->r_wait);//唤醒读等待队列

ret = count;

}

out: up(&dev->sem);//释放信号

out2:remove_wait_queue(&dev->w_wait,&wait);//把写等待队列从队列头中移除

set_current_state(TASK_RUNNING);//改变进程状态为TASK_RUNNING

return ret;

}

static loff_t globalmem_llseek(struct file *filp,loff_t

offset,int orig)

{

loff_t ret = 0;

switch(orig){

case 0 :

if(offset <

0){

ret =

-EINVAL;

break;

}

if((unsigned int)offset > GLOBALMEM_SIZE){

ret =

-EINVAL;

break;

}

filp->f_pos = (unsigned int)offset;

ret = filp->f_pos;

break;

case 1 :

if((filp->f_pos + offset)

> GLOBALMEM_SIZE){

ret = -EINVAL;

break;

}

if((filp->f_pos + offset)

< 0){

ret = -EINVAL;

break;

}

filp->f_pos += offset;

break;

default :

ret = -EINVAL;

break;

}

return ret;

}

static const struct file_operations globalmem_fops = {

.owner = THIS_MODULE,

.llseek = globalmem_llseek,

.read = globalmem_read,

.write = globalmem_write,

.ioctl = globalmem_ioctl,

.open = globalmem_open,

.release = globalmem_release,

};

static void globalmem_setup_cdev(struct globalmem_dev *dev,int

index)

{

int err,devno = MKDEV(globalmem_major,index);

cdev_init(&dev->cdev,&globalmem_fops);

dev->cdev.owner = THIS_MODULE;

err =

cdev_add(&dev->cdev,devno,1);

if(err)

printk(KERN_NOTICE "Error %d adding globalmem

%d",err,index);

}

int globalmem_init(void)

{

int result;

dev_t devno = MKDEV(globalmem_major,0);

if(globalmem_major)

result = register_chrdev_region(devno, 1,

"globalmem");

else{

result =

alloc_chrdev_region(&devno,0,1,"globalmem");

globalmem_major = MAJOR(devno);

}

if (result < 0)

return result;

firstdrv_class = class_create(THIS_MODULE,

"firstdrv");//建立firstdrv这个类

device_create(firstdrv_class,NULL,devno,NULL,"globalmem");//自动创建设备节点/dev/LED

globalmem_devp = kmalloc(sizeof(struct

globalmem_dev),GFP_KERNEL);

if(!globalmem_devp){

result = -ENOMEM;

goto fail_malloc;

}

memset(globalmem_devp,0,sizeof(struct globalmem_dev));

globalmem_setup_cdev(globalmem_devp,0);

init_MUTEX(&globalmem_devp->sem);//定义并初始化一个互斥信号

init_waitqueue_head(&globalmem_devp->r_wait);//初始化读队列头

init_waitqueue_head(&globalmem_devp->w_wait);//初始化写队列头

//globalmem_devp->current_len = 0x800;

return 0;

fail_malloc:

unregister_chrdev_region(devno,1);

return result;

}

void globalmem_exit(void)

{

cdev_del(&globalmem_devp->cdev);

kfree(globalmem_devp);

device_destroy(firstdrv_class,MKDEV(globalmem_major,0));

class_destroy(firstdrv_class);//释放这个类,干掉它

unregister_chrdev_region(MKDEV(globalmem_major,0),1);

}

MODULE_LICENSE("Dual BSD/GPL");

module_init(globalmem_init);

module_exit(globalmem_exit);

上面是驱动程序,下面给出运行时现象(用的是TQ2440开发板和linux-2.6.30.4内核)

[root@cgyl2010 ~]#

[root@cgyl2010 ~]#insmod yueyi.ko

[root@cgyl2010 ~]#cat /dev/globalmem &

[root@cgyl2010 ~]#echo "yygy" > /dev/globalmem

write 5 bytes(s) current_len 5

mycgy TQ2440

read 5 bytes(s) courrent_len:0

mydyy TQ2440

yygy

[root@cgyl2010 ~]#

顺便给出Makefile文件

obj-m += yueyi.o

KERDIR = /work/linux-2.6.30.4

#KERDIR = /usr/src/linux-headers-2.6.32-33-generic

modules:

make -C $(KERDIR) M=`pwd` modules

clean:

make -C $(KERDIR) M=`pwd` clean

##################################################################################################

下面是支持轮询的驱动,和上面的差不多

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define GLOBALMEM_SIZE 0x1000

#define MEM_CLEAR 0x1

#define GLOBALMEM_MAJOR 250

static struct class *firstdrv_class;

static int globalmem_major = GLOBALMEM_MAJOR;

struct globalmem_dev{

struct cdev cdev;

unsigned int current_len;

unsigned char mem[GLOBALMEM_SIZE];

struct semaphore sem;

wait_queue_head_t r_wait;

wait_queue_head_t w_wait;

};

struct globalmem_dev *globalmem_devp;

int globalmem_open(struct inode *inode,struct file *filp)

{

filp->private_data = globalmem_devp;

return 0;

}

int globalmem_release(struct inode *inode,struct file *filp)

{

return 0;

}

static int globalmem_ioctl(struct inode *inodeep,struct file

*filp,unsigned int cmd,unsigned long arg)

{

struct globalmem_dev *dev =

filp->private_data;

switch (cmd) {

case MEM_CLEAR :

if

(down_interruptible(&dev->sem))

return -ERESTARTSYS;

memset(dev->mem,0,GLOBALMEM_SIZE);

up(&dev->sem);

printk(KERN_INFO "globalmem is

set to zero\n");

break;

default :

return -EINVAL;

}

return 0;

}

static ssize_t globalmem_read(struct file *filp,char __user

*buf,size_t count,loff_t *ppos)

{

int ret;

struct globalmem_dev *dev =

filp->private_data;

DECLARE_WAITQUEUE(wait,current);

down(&dev->sem);

add_wait_queue(&dev->r_wait,&wait);

while(dev->current_len == 0){

if(filp->f_flags

&O_NONBLOCK){

ret = -EAGAIN;

goto out;

}

__set_current_state(TASK_INTERRUPTIBLE);

up(&dev->sem);

schedule();

if(signal_pending(current)){

ret = -ERESTARTSYS;

goto out2;

}

//down(&dev->sem);

}

if(count > dev->current_len)

count = dev->current_len;

if(copy_to_user(buf,dev->mem,count)){

return -EFAULT;

goto out;

}else {

memcpy(dev->mem,dev->mem +

count,dev->current_len - count);

dev->current_len -= count;

printk(KERN_INFO "read %d bytes(s)

courrent_len:%d\n",count,dev->current_len);

printk(KERN_INFO "mydyy TQ2440\n");

wake_up_interruptible(&dev->w_wait);

ret = count;

}

out: up(&dev->sem);

out2:remove_wait_queue(&dev->r_wait,&wait);

set_current_state(TASK_RUNNING);

return ret;

}

static ssize_t globalmem_write(struct file *filp,const char

__user *buf,size_t count,loff_t *ppos)

{

int ret;

struct globalmem_dev *dev =

filp->private_data;

DECLARE_WAITQUEUE(wait,current);

down(&dev->sem);

add_wait_queue(&dev->w_wait,&wait);

while(dev->current_len == GLOBALMEM_SIZE){

if(filp->f_flags &

O_NONBLOCK){

ret = -EAGAIN;

goto out;

}

__set_current_state(TASK_INTERRUPTIBLE);

up(&dev->sem);

schedule();

if(signal_pending(current)){

ret = -ERESTARTSYS;

goto out2;

}

//down(&dev->sem);

}

if(count > GLOBALMEM_SIZE -

dev->current_len)

count = GLOBALMEM_SIZE - dev->current_len;

if(copy_from_user(dev->mem +

dev->current_len,buf,count)){

return -EFAULT;

goto out;

}else {

dev->current_len += count;

printk(KERN_INFO "write %d bytes(s) current_len

%d\n",count,dev->current_len);

printk(KERN_INFO "mycgy TQ2440\n");

wake_up_interruptible(&dev->r_wait);

ret = count;

}

out: up(&dev->sem);

out2:remove_wait_queue(&dev->w_wait,&wait);

set_current_state(TASK_RUNNING);

return ret;

}

static loff_t globalmem_llseek(struct file *filp,loff_t

offset,int orig)

{

loff_t ret = 0;

switch(orig){

case 0 :

if(offset <

0){

ret =

-EINVAL;

break;

}

if((unsigned int)offset > GLOBALMEM_SIZE){

ret =

-EINVAL;

break;

}

filp->f_pos = (unsigned int)offset;

ret = filp->f_pos;

break;

case 1 :

if((filp->f_pos + offset)

> GLOBALMEM_SIZE){

ret = -EINVAL;

break;

}

if((filp->f_pos + offset)

< 0){

ret = -EINVAL;

break;

}

filp->f_pos += offset;

break;

default :

ret = -EINVAL;

break;

}

return ret;

}

static unsigned int globalfifo_poll(struct file *filp, poll_table

*wait)

{

unsigned int mask = 0;

struct globalmem_dev *dev =

filp->private_data;//获得设备结构体指针

down(&dev->sem);//获取信号

poll_wait(filp,&dev->r_wait,wait);//把读队列头加到poll_table结构所指的链表中去

poll_wait(filp,&dev->w_wait,wait);//把写队列头加到poll_table结构所指的链表中去

if(dev->current_len != 0)//fifo非空

mask |= POLLIN | POLLRDNORM;//标志数据可获得

if(dev->current_len != GLOBALMEM_SIZE)//fifo非满

mask |= POLLOUT | POLLWRNORM;//标志数据可写入

up(&dev->sem);//释放信号

return mask;//返回标志mask

}

static const struct file_operations globalmem_fops = {

.owner = THIS_MODULE,

.llseek = globalmem_llseek,

.read = globalmem_read,

.write = globalmem_write,

.ioctl = globalmem_ioctl,

.poll = globalfifo_poll,

.open = globalmem_open,

.release = globalmem_release,

};

static void globalmem_setup_cdev(struct globalmem_dev *dev,int

index)

{

int err,devno = MKDEV(globalmem_major,index);

cdev_init(&dev->cdev,&globalmem_fops);

dev->cdev.owner = THIS_MODULE;

err =

cdev_add(&dev->cdev,devno,1);

if(err)

printk(KERN_NOTICE "Error %d adding globalmem

%d",err,index);

}

int globalmem_init(void)

{

int result;

dev_t devno = MKDEV(globalmem_major,0);

if(globalmem_major)

result = register_chrdev_region(devno, 1,

"globalmem");

else{

result =

alloc_chrdev_region(&devno,0,1,"globalmem");

globalmem_major = MAJOR(devno);

}

if (result < 0)

return result;

firstdrv_class = class_create(THIS_MODULE,

"firstdrv");//建立firstdrv这个类

device_create(firstdrv_class,NULL,devno,NULL,"globalmem");//自动创建设备节点/dev/LED

globalmem_devp = kmalloc(sizeof(struct

globalmem_dev),GFP_KERNEL);

if(!globalmem_devp){

result = -ENOMEM;

goto fail_malloc;

}

memset(globalmem_devp,0,sizeof(struct globalmem_dev));

globalmem_setup_cdev(globalmem_devp,0);

init_MUTEX(&globalmem_devp->sem);

init_waitqueue_head(&globalmem_devp->r_wait);

init_waitqueue_head(&globalmem_devp->w_wait);

return 0;

fail_malloc:

unregister_chrdev_region(devno,1);

return result;

}

void globalmem_exit(void)

{

cdev_del(&globalmem_devp->cdev);

kfree(globalmem_devp);

device_destroy(firstdrv_class,MKDEV(globalmem_major,0));

class_destroy(firstdrv_class);//释放这个类,干掉它

unregister_chrdev_region(MKDEV(globalmem_major,0),1);

}

MODULE_LICENSE("Dual BSD/GPL");

module_init(globalmem_init);

module_exit(globalmem_exit);

下面给出应用程序(用到poll)

#include

#include

#include

#include

#include

#define FIFO_CLEAR 0x1

#define BUFFER_LEN 20//用于清除内存

main()

{

int fd,num;

char rd_ch[BUFFER_LEN];

fd_set rfds,wfds;//读/写文件描述符集

fd = open("/dev/globalmem",O_RDWR |

O_NONBLOCK);以非阻塞可读写方式打开

if(fd != -1){

if(ioctl(fd,FIFO_CLEAR,0) <

0)//先清空整个fifo

printf("ioctl command

failed\n");

while (1) {

FD_ZERO(&rfds);//清除读文件描述符集

FD_ZERO(&wfds);//清除写文件描述符集

FD_SET(fd,&rfds);//把fd文件描述符加到读文件描述符集中去

FD_SET(fd,&wfds);//把fd文件描述符加到写文件描述符集中去

select(fd +

1,&rfds,&wfds,NULL,NULL);//系统调用最终会调用到驱动里的poll()函数

if(FD_ISSET(fd,&rfds))//判断读文件描述符是否置为,也判断就是说是否可读

printf("poll

monitor:cat be read\n");

sleep(1);//延时1秒

if(FD_ISSET(fd,&wfds))//判断写文件描述符是否置为,也判断就是说是否可写

printf("poll

monitor:cat be writen\n");

sleep(1);

}

}else{

printf("Device open

failure\n");

}

}

下面是运行时现象(开发板TQ2440,内核linux-2.6.30.4)

[root@cgyl2010 ~]#

[root@cgyl2010 ~]#insmod yg.ko

[root@cgyl2010 ~]#./cs &

globalmem is set to zero

[root@cgyl2010 ~]#poll monitor:cat be writen

poll monitor:cat be writen

[root@cgyl2010 ~]#poll monitor:cat be writen

poll monitor:cat be writen

ecpoll monitor:cat be writen

ho poll monitor:cat be writen

dpoll monitor:cat be writen

yycgypoll monitor:cat be writen

> /depoll monitor:cat be

writen

[root@cgyl2010 ~]#echo dyycgy > /dev/globalmem poll

monitor:cat be writen

write 7 bytes(s) current_len 7

mycgy TQ2440

[root@cgyl2010 ~]#poll monitor:cat be read

poll monitor:cat be writen

poll monitor:cat be read

poll monitor:cat be writen

poll monitor:cat be read

poll monitor:cat be writen

......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值