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
......
linux进程阻塞例子,linux阻塞与非阻塞驱动例子相关推荐
- 五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O
From: http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/ 五种I/O 模式: [1] ...
- 同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO
IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSock ...
- linux进程管理机制,linux进程管理,linux进程管理机制
linux进程管理,linux进程管理机制 一.基本介绍 1.在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号 2.每一个进程,都会对应一个父进程,而这个父进程 ...
- 【linux】串口编程(二)——非阻塞接收
项目中很少会使用阻塞接收,一般都是select+read监听模式来实现非阻塞接收. 使用selece时,需要处理一些异常情况的返回,比如:系统中断产生EINTR错误:超时错误ETIMEDOUT. 使用 ...
- linux socket 阻塞服务端 非阻塞客户端,linux下异步RPC的阶段性总结-非阻塞SOCKET客户端...
尽可能使用非阻塞socket int flags, s; flags = fcntl (fd, F_GETFL, 0); if (flags == -1){ close(fd); return -1; ...
- Linux进程实践(1) --Linux进程编程概述
进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...
- linux进程操作相关函数,Linux进程控制简介与要素及相关函数详解
进程是操作系统中的一个重要概念,它是一个程序的一次执行过程,程序是进程的一种静态描述,系统中运行的每一个程序都是在它的进程中运行的. 进程4要素 要有一段程序供该进程运行 进程专用的系统堆栈空间 进程 ...
- Linux进程ID号--Linux进程的管理与调度(三)
进程ID概述 进程ID类型 要想了解内核如何来组织和管理进程ID,先要知道进程ID的类型: 内核中进程ID的类型用pid_type来描述,它被定义在include/linux/pid.h中 enum ...
- linux 进程管理 ppt,Linux内核结构与进程管理.ppt
Linux内核结构与进程管理.ppt Linux 内核结构与进程管理,Linux系统结构Linux kernel 开放源代码的linux操作系统内核,目前版本为2.6,Linux内核组成1. 进程调度 ...
- linux 进程的执行时间,Linux 获取进程执行时间
Linux 获取进程执行时间 1 前言 测试一个程序的执行时间, 时间包括用户 CPU 时间系统 CPU 时间时钟时间之前获取之前时间都是在程序的 main 函数用 time 函数实现, 这个只能粗略 ...
最新文章
- vector机器人 HOW TO MEET VECTOR 如何满足向量
- 多边形的时针方向与法线方向
- 从CLR GC到CoreCLR GC看.NET Core对云原生的支持
- python timer 死掉_Python定时事件 Timer sched
- 使用GIT不小心merge后的回滚操作
- quartz定时器依赖_Spring Quartz定时器 配置文件详解
- opencv 的norm_OpenCV:norm-范数求解函数
- The Devil Wears Prada-16
- 如何选择DDoS防御服务器
- 通过ajax单独上传图片
- python3 collections模块 tree_python3上的ete3模块无法导入TreeStyle、faces、AttrFace、NodeSty...
- 全球首推语音定制产品,百度地图背后的语音技术到底有多强大?
- R语言plotly可视化:使用plotly可视化模型预测真阳性率(True positive)TPR和假阳性率(False positive)FPR在不同阈值(threshold)下的曲线
- #三、回测试验给我们的启示
- 【NOIP1999普及组】Cantor表
- autoconf使用环境
- 服务器centos 内网代理上网- tinyproxy
- 公众号文章中怎样添加音乐、音频
- J2EE 框架结构及核心技术基础面面观
- 使用gitee镜像加速oh-my-zsh下载与更新