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

#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

......

linux进程阻塞例子,linux阻塞与非阻塞驱动例子相关推荐

  1. 五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

    From: http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/ 五种I/O 模式: [1]        ...

  2. 同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO

    IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSock ...

  3. linux进程管理机制,linux进程管理,linux进程管理机制

    linux进程管理,linux进程管理机制 一.基本介绍 1.在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号 2.每一个进程,都会对应一个父进程,而这个父进程 ...

  4. 【linux】串口编程(二)——非阻塞接收

    项目中很少会使用阻塞接收,一般都是select+read监听模式来实现非阻塞接收. 使用selece时,需要处理一些异常情况的返回,比如:系统中断产生EINTR错误:超时错误ETIMEDOUT. 使用 ...

  5. linux socket 阻塞服务端 非阻塞客户端,linux下异步RPC的阶段性总结-非阻塞SOCKET客户端...

    尽可能使用非阻塞socket int flags, s; flags = fcntl (fd, F_GETFL, 0); if (flags == -1){ close(fd); return -1; ...

  6. Linux进程实践(1) --Linux进程编程概述

    进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...

  7. linux进程操作相关函数,Linux进程控制简介与要素及相关函数详解

    进程是操作系统中的一个重要概念,它是一个程序的一次执行过程,程序是进程的一种静态描述,系统中运行的每一个程序都是在它的进程中运行的. 进程4要素 要有一段程序供该进程运行 进程专用的系统堆栈空间 进程 ...

  8. Linux进程ID号--Linux进程的管理与调度(三)

    进程ID概述 进程ID类型 要想了解内核如何来组织和管理进程ID,先要知道进程ID的类型: 内核中进程ID的类型用pid_type来描述,它被定义在include/linux/pid.h中 enum ...

  9. linux 进程管理 ppt,Linux内核结构与进程管理.ppt

    Linux内核结构与进程管理.ppt Linux 内核结构与进程管理,Linux系统结构Linux kernel 开放源代码的linux操作系统内核,目前版本为2.6,Linux内核组成1. 进程调度 ...

  10. linux 进程的执行时间,Linux 获取进程执行时间

    Linux 获取进程执行时间 1 前言 测试一个程序的执行时间, 时间包括用户 CPU 时间系统 CPU 时间时钟时间之前获取之前时间都是在程序的 main 函数用 time 函数实现, 这个只能粗略 ...

最新文章

  1. vector机器人 HOW TO MEET VECTOR 如何满足向量
  2. 多边形的时针方向与法线方向
  3. 从CLR GC到CoreCLR GC看.NET Core对云原生的支持
  4. python timer 死掉_Python定时事件 Timer sched
  5. 使用GIT不小心merge后的回滚操作
  6. quartz定时器依赖_Spring Quartz定时器 配置文件详解
  7. opencv 的norm_OpenCV:norm-范数求解函数
  8. The Devil Wears Prada-16
  9. 如何选择DDoS防御服务器
  10. 通过ajax单独上传图片
  11. python3 collections模块 tree_python3上的ete3模块无法导入TreeStyle、faces、AttrFace、NodeSty...
  12. 全球首推语音定制产品,百度地图背后的语音技术到底有多强大?
  13. R语言plotly可视化:使用plotly可视化模型预测真阳性率(True positive)TPR和假阳性率(False positive)FPR在不同阈值(threshold)下的曲线
  14. #三、回测试验给我们的启示
  15. 【NOIP1999普及组】Cantor表
  16. autoconf使用环境
  17. 服务器centos 内网代理上网- tinyproxy
  18. 公众号文章中怎样添加音乐、音频
  19. J2EE 框架结构及核心技术基础面面观
  20. 使用gitee镜像加速oh-my-zsh下载与更新

热门文章

  1. python 面向对象全面详解
  2. 用md5值识别相似图片 python
  3. 计算机一级字幕设置,如何开启电脑哔哩哔哩中的CC字幕功能
  4. Office2010安装时,需要安装msxml6.msi解决办法
  5. 浅析汽车融资租赁业务模式
  6. python实现网页微信登陆_(转帖)网站微信登录-python 实现
  7. lpush rpush 区别_redis中lpush、rpush、lset、lrem是什么
  8. SPSS——描述性统计分析——比率分析
  9. [附源码]Java计算机毕业设计SSM房屋租赁管理系统设计
  10. Zotero批量下载知网文献