Linux设备驱动编程之阻塞与非阻塞

sailorn88

sailorn88

2016-01-29 17:40

Linux设备驱动编程之阻塞与非阻塞,Linux设备驱动编程之阻塞与非阻塞
  阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作。非阻塞操作的进程在不能进行设备操作时,并不挂起。被挂起的进程进入sleep状态,被从调度器的运行队列移走,直到等待的条件被满足。

  在Linux驱动程序中,我们可以使用等待队列(wait queue)来实现阻塞操作。wait queue很早就作为一个基本的功能单位出现在Linux内核里了,它以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制。等待队列可以用来同步对系统资源的访问,上节中所讲述Linux信号量在内核中也是由等待队列来实现的。

  下面我们重新定义设备"globalvar",它可以被多个进程打开,但是每次只有当一个进程写入了一个数据之后本进程或其它进程才可以读取该数据,否则一直阻塞。

#include <linux/module.h
#include <linux/init.h
#include <linux/fs.h
#include <asm/uaccess.h
#include <linux/wait.h
#include <asm/semaphore.h
MODULE_LICENSE("GPL");

#define MAJOR_NUM 254

static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);

struct file_operations globalvar_fops =
{
 read: globalvar_read, write: globalvar_write,
};

static int global_var = 0;
static struct semaphore sem;
static wait_queue_head_t outq;
static int flag = 0;

static int __init globalvar_init(void)
{
 int ret;
 ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
 if (ret)
 {
  printk("globalvar register failure");
 }
 else
 {
  printk("globalvar register success");
  init_MUTEX(&sem);
  init_waitqueue_head(&outq);
 }
 return ret;
}

static void __exit globalvar_exit(void)
{
 int ret;
 ret = unregister_chrdev(MAJOR_NUM, "globalvar");
 if (ret)
 {
  printk("globalvar unregister failure");
 }
 else
 {
  printk("globalvar unregister success");
 }
}

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
 //等待数据可获得
 if (wait_event_interruptible(outq, flag != 0))
 {
  return - ERESTARTSYS;
 }

 if (down_interruptible(&sem))
 {
  return - ERESTARTSYS;
 }

 flag = 0;
 if (copy_to_user(buf, &global_var, sizeof(int)))
 {
  up(&sem);
  return - EFAULT;
 }
 up(&sem);
 return sizeof(int);
}

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,loff_t *off)
{
 if (down_interruptible(&sem))
 {
  return - ERESTARTSYS;
 }
 if (copy_from_user(&global_var, buf, sizeof(int)))
 {
  up(&sem);
  return - EFAULT;
 }
 up(&sem);
 flag = 1;
 //通知数据可获得
 wake_up_interruptible(&outq);
 return sizeof(int);
}

module_init(globalvar_init);
module_exit(globalvar_exit);


 

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/linux/)

[1] [2] [3] [4]   

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/linux/)
展开更多 50%)
分享

猜你喜欢

Linux设备驱动编程之阻塞与非阻塞

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
Linux设备驱动编程之阻塞与非阻塞

深入浅出Linux设备驱动编程之内核模块

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux设备驱动编程之内核模块

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

linux设备驱动笔记——字符设备驱动

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
linux设备驱动笔记——字符设备驱动

输卵管阻塞的症状与治疗

电脑网络
输卵管阻塞的症状与治疗

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

SQL Server阻塞详解

编程语言 网络编程
SQL Server阻塞详解

毛孔阻塞怎么办

电脑网络
毛孔阻塞怎么办

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

清除Word页眉横线且不影响页眉格式的方法

清除Word页眉横线且不影响页眉格式的方法

《NBA 2K16》MT模式球员卡获得方法解析攻略

《NBA 2K16》MT模式球员卡获得方法解析攻略
下拉加载更多内容 ↓