linux驱动学习(4)--阻塞和非阻塞

发布者:MusicLover123最新更新时间:2024-08-14 来源: cnblogs关键字:linux  驱动学习  阻塞  非阻塞 手机看文章 扫描二维码
随时随地手机看文章

以串口的应用程序为例:

阻塞地都取串口一个字符

非阻塞地都取串口一个字符

char buf; 
fd = open('/dev/ttys',O_RDWR);
.. .. 
res = read(fd,&buf,1); //当串口上有输入时才返回 
if(res == 1) 

     printf('%cn',buf); 
}
char buf;
fd = open('/dev/ttys',O_RDWR | O_NONBLOCK);
.. .. 
while( read(fd,&buf,1) !=1); //当串口上无输入也返回,所
                                                //以要循环尝试读取串口
printf('%cn',buf);

现在我们有了阻塞的方式读取,那么阻塞的进程因为没有获得资源会进入休眠状态,现在就要聊聊有关唤醒的事了。在Linux设备驱动中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒.等待队列能够用于实现内核中的异步事件通知机制。

 

Linux提供了有关等待队列的操作:

1)wait_queue_head_t my_queue; //定义等待队列头

2) init_waitqueue_head(&my_queue);   //初始化队列头

如果觉得上边两步来的麻烦,可以直接使用

DECLARE_WAIT_QUEUE_HEAD(name)   //定义并初始化

 

3) DECLARE_WAITQUEUE(name,tsk); //定义等待队列

4) void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

    void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

    用于将等待队列wait添加到等待队列头指向的等待队列链表中 。

5) wait_event(queue, conditon);

     wait_event_interruptible(queue, condition);  //可以被信号打断

     wait_event_timeout(queue, condition, timeout);

     wait_event_interruptible_timeout(queue, condition, timeout); //不能被信号打断

     queue:作为等待队列头的等待队列被唤醒

     conditon:必须满足,否则阻塞

     timeout和conditon相比,有更高优先级

6) void wake_up(wait_queue_head_t *queue);

     void wake_up_interruptible(wait_queue_head_t *queue);

     上述操作会唤醒以queue作为等待队列头的所有等待队列中所有属于该等待队列头的等待队列对应的进程。

7) sleep_on(wait_queue_head_t *q);

     interruptible_sleep_on(wait_queue_head_t *q);

     sleep_on作用是把目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列,之后把他附属到等待队列头q,直到资源可用,q引导的等待队列被唤醒。interruptible_sleep_on作用是一样的, 只不过它把进程状态置为TASK_INTERRUPTIBLE.

    这两个函数的流程是首先,定义并初始化等待队列,把进程的状态置成TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE,并将对待队列添加到等待队列头。

然后通过schedule(放弃CPU,调度其他进程执行。最后,当进程被其他地方唤醒,将等待队列移除等待队列头。

    在Linux内核中,使用set_current_state()和__add_wait_queue()函数来实现目前进程状态的改变,直接使用current->state = TASK_UNINTERRUPTIBLE

类似的语句也是可以的。

    因此我们有时也可能在许多驱动中看到,它并不调用sleep_on或interruptible_sleep_on(),而是亲自进行进程的状态改变和切换。

  

    废话少说,直接上代码,实际代码很简单。


#include

#include

#include

#include

 

/*for spinlock and semaphore*/

#include

#include

#include

 

/*for task management*/

#include

#include

 

/*

 * xiaoyang yi @HIT 2011-9-25

 * char device driver with blocked testing

 */

 

MODULE_LICENSE('GPL');

 

static int MAJOR_NUM=0;

static struct semaphore sem;

static int global_var = 0;

static int global_var_count = 0;

static spinlock_t spin;

/*waiting queue for kernel*/

static wait_queue_head_t wqueue;

static int flag = 0;

 

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*);

static int globalvar_open(struct inode*node, struct file* fp);

static int globalvar_release(struct inode*node, struct file* fp);

 

/*init the file_operation structure*/

static struct file_operations globalvar_fpos={

    .read = globalvar_read,

    .write = globalvar_write,

    .open = globalvar_open,

    .release = globalvar_release,

};

 

static int __init globalvar_init(void)

{

    int ret;

 

    printk('register globalvar:[blocked testing]');

    /*register device drivre*/

    ret = register_chrdev(MAJOR_NUM,'globalvar',&globalvar_fpos);

    if(ret < 0){

        printk('globalvar reg failed!n');

    }else{

        spin_lock_init(&spin);

    }

     

    if(MAJOR_NUM == 0){

        MAJOR_NUM = ret;

    }

 

    sema_init(&sem,1);

    init_waitqueue_head(&wqueue);

    return ret;

}

 

static void __exit globalvar_exit()

{

    unregister_chrdev(MAJOR_NUM,'globalvar');

}

 

static ssize_t globalvar_read(struct file* fp, char* buf, size_t len, loff_t* off)

{

    /*wait until condition become true*/

    if( wait_event_interruptible(wqueue,flag!=0) ){

        return -ERESTARTSYS;

    }

 

    /*get semaphore*/

    if(down_interruptible(&sem)){

        return -ERESTARTSYS;

    }

     

    /*copy from kernel to user space*/

    if(copy_to_user(buf,&global_var,sizeof(int)) != 0){

        /*release semaphore*/

        up(&sem);

        return -EFAULT;

    }

    /*data unaccessible flag*/

    flag = 0;

     

    /*release semaphore*/

    up(&sem);

    return sizeof(int);

}

 

static ssize_t globalvar_write(struct file* fs,const char* buf, size_t len, loff_t* off)

{

    /*get semaphore*/

    if(down_interruptible(&sem)){

        return -ERESTARTSYS;

    }

     

    printk('down_interruptible ok!n');

    if(copy_from_user(&global_var,buf,sizeof(int) != 0)){

        /*release semaphore*/

        up(&sem);

        return -EFAULT;

    }

 

    /*release semaphore*/

    up(&sem);

 

    /*data ready*/

    flag = 1;

    /*wake up the waiting task*/

    wake_up_interruptible(&wqueue);

    return sizeof(int);

}

 

/*

 * open device with checking busy.

 * if busy,count++;else return 0

 */

static int globalvar_open(struct inode*node, struct file* fp)

{

    /*get spinlock*/

    //spin_lock(&spin);

     

    /*reach criticle section*/

    //if(global_var_count){

        //spin_unlock(&spin);

        //printk('[debug]:globalvar open fialed!n');

        //return -EBUSY;

    //}

     

    /*release spinlock*/

    global_var_count++;

     

    //spin_unlock(&spin);

    return 0;

}

 

static int globalvar_release(struct inode*node, struct file* fp)

{

    //spin_lock(&spin);

    global_var_count--;

    //spin_unlock(&spin);

    return 0;

}

 

/*module setting*/

module_init(globalvar_init);

module_exit(globalvar_exit);

 

/*this is end of file*/

这里的信号量和wait_queue操作要注意顺序,否则可能形成死锁。


如:


//对于读

 

down(sem)

 

wait_queue(...)

 

up(sem)

 

//对于写:

 

down(sem)

 

up(sem)

 

wake_up_queue(..)

      这种情况下可能读进程永远在wait_queue里睡眠,而写进程由于无法得到sem永远不会执行wake_up...  


      ....


      下面是测试用的应用程序,包括了读写两个分支。


    


#include

#include

#include

#include

#include

 

/*

 * xiaoyang yi @HIT 2011.9.24

 * this is a test for char device 'globalvar'

 */

 

int main(int argc, char** args) {

    int fd, num;

 

    if (argc >= 2) {

        if (strcmp(args[1], '0') == 0) {

            printf('mode read!n');

            /*opemn device*/

            fd = open('/dev/globalvar', O_RDWR, S_IRUSR | S_IWUSR);

            if (fd != -1) {

                while (1) {

                    read(fd, &num, sizeof(int));

                    printf('globalvar=%dn',num);

                    if (num == 0) {

                        close(fd);

                        break;

                    }

                }//while

            } else {

                printf('error:device open error!n');

            }

        } else if (strcmp(args[1], '1') == 0) {

            printf('mode write!n');

 

            /*opemn device*/

            fd = open('/dev/globalvar', O_RDWR, S_IRUSR | S_IWUSR);

            if (fd != -1) {

                while (1) {

                    /*writing test*/

                    printf('print number to write: ');

                    scanf('%d', &num);

                    write(fd, &num, sizeof(int));

                    if (num == 0) {

                        close(fd);

[1] [2]
关键字:linux  驱动学习  阻塞  非阻塞 引用地址:linux驱动学习(4)--阻塞和非阻塞

上一篇:LRF020 DRIVER FOR LINUX(BASED ON TQ2440/ARM9)
下一篇:linux驱动学习(3)--同步、信号量和自旋锁

推荐阅读最新更新时间:2024-11-02 12:37

Tiny 6410的Linux学习总结!
1、Tiny6410的Linux系统修改IP地址: vi /etc/eth0-setting 2、Ubuntu14.04自动以root身份登录系统: /etc/lightdm/lightdm.conf 更改为以下内容:重启后自动以Root身份登录 autologin-guest=false autologin-user=root autologin-user-timeout=0 autologin-session=lightdm-autologin
[单片机]
S3C2410的linux 下DMA驱动程序开发
网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的驱动程序,有感于刚接手时无资料借鉴的茫然,故写点介绍,期待能给有DMA开发任务的网友们一点帮助。 本文将包括如下内容: DMA驱动主要函数功能 驱动中关键技术分析 具体的DMA实例分析 申明:本DMA驱动开发介绍仅适合S3C2410处理器类型,分析源码为韩国MIZI研究中心维护的dma驱动代码: linux/arch/arm/mach-s3c2410/dma.h,linux/arch/arm/mach-s3c2410/dma.c,
[单片机]
基于Linux操作系统的ARM/DSP多机I2C通信设计方案
  引言   在很多嵌入式控制系统中,系统既要完成大量的信息采集和复杂的算法,又要实现精确的控制功能。采用运行有嵌入式Linux操作系统的ARM9微控制器完成信号采集及实现上层控制算法,并向DSP芯片发送上层算法得到控制参数,DSP芯片根据获得的参数和下层控制算法实现精确、可靠的闭环控制。   1 多机系统组成   该多机控制系统以ARM9微控制器s3c2440为核心,采用I2C总线挂载多个DSP芯片TMS320F28015作为协控制器,构成整个控制系统的核心。   1.1 S3C2440及TMS320F28015简介   Samsung公司的处理器S3C2440是内部集成了ARM公司ARM920T处理器内核的32位微控
[单片机]
基于<font color='red'>Linux</font>操作系统的ARM/DSP多机I2C通信设计方案
Linux实时化解决方案Xenomai的原理及应用
引 言 随着嵌入式设备的快速发展,嵌入式设备的功能和灵活性要求越来越高,很多嵌入式设备中都开始使用操作系统。由于工作的特殊性,很多嵌入式设备要求系统对外部事件的中断响应必须在事先设定的时限范围内完成,使系统具有可预测性,而通用的桌面操作系统大都是非实时或者是软实时的,无法满足需求,因此就必须使用实时操作系统(Real-TIme OperATIng System,RTOS)。 实时操作系统(RTOS)是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的操作系统。因而,提供及时响应和高可靠性是其主要特点。实时操作系统有硬
[单片机]
<font color='red'>Linux</font>实时化解决方案Xenomai的原理及应用
Linux On iPhone将面世 支持iOS双启动
据 FOSSBRTES 报道称,用户很快将可以通过双启动功能,像在 Android 设备上那样在 iPhone 上运行 Linux。目前,越狱者、开发人员 Raffaele 以及 mcg29 已在其 Github 页面上发布了详细说明,详细介绍了如何双启动 64 位 iOS 设备。 这些说明内容包括有:用于对根文件系统进行分区和还原、创建自定义ramdisk、修改文件系统分区以及引导至设备的详细步骤。 A 64bit dual boot tutorial, brought to you by @Ralph0045 and @mcg29_https://t.co/PqumNzNcBz — mcg29 (@mcg29
[手机便携]
verilog中阻塞赋值和阻塞复制的理解
阻塞和非阻塞语句作为verilog HDL语言的最大难点之一,一直困扰着FPGA设计者,即使是一个颇富经验的设计工程师,也很容易在这个点上犯下一些不必要的错误。阻塞和非阻塞可以说是血脉相连,但是又有着本质的差别。理解不清或运用不当,都往往会导致设计工程达不到预期的效果,而其中的错误又很隐晦。下面我给大家谈谈阻塞和非阻塞语句的本质区别和在FPGA设计中的不同运用。 阻塞语句 顾名思义,即本条语句具有影响下一条语句的作用,在同一个进程always中,一条阻塞赋值语句的执行是立刻影响着下条语句的执行情况和结果。如果该条语句没有执行完,那么下条语句不可能进入执行状态的,因此,从字面层上理解,该条语句阻塞了下面语句的执行。阻塞语句
[嵌入式]
verilog中<font color='red'>阻塞</font>赋值和<font color='red'>非</font><font color='red'>阻塞</font>复制的理解
linux 2.6.24.4在S3C2410上的移植(根文件系统cramfs,ramdisk,jffs2)(基于GEC2410)
内核可以跑起来,接下来就是移植根文件系统了. 我们使用BusyBox-1.10.1来创建根文件系统.下载地址为:http://www.busybox.net/downloads/ 1.设置BusyBox (1)解压 #tar -xvjf BusyBox-1.10.1.tar.bz2 #cd BusyBox-1.10.1 (2)修改Makefile,设置CROSS_COMPILE ARCH ?= arm CROSS_COMPILE ?= /home/GEC2410/toolchain/arm-softfloat-linux-gnu/bin/arm-softfloat-linux-gnu- (根据自己的交叉编译环境路径) (3)配置B
[单片机]
CAN总线在嵌入式Linux驱动程序的实现
1   引言     基于嵌入式系统设计的工业控制装置,在工业控制现场受到各种干扰,如电磁、粉尘、天气等对系统的正常运行造成很大的影响。在工业控制现场各个设备之间要经常交换、传输数据,需要一种抗干扰性强、稳定、传输速率快的现场总线进行通信。文章采用CAN总线,基于嵌入式系统32位的S3C44B0X微处理器,通过其SPI接口,MCP2510 CAN控制器扩展CAN总线;将嵌入式操作系统嵌入到S3C44B0X微处理器中,能实现多任务、友好图形用户界面;针对S3C44B0X微处理器没有内存管理单元MMU,采用uClinux嵌入式操作系统。这样在嵌入式系统中扩展CAN设备关键技术就是CAN设备在嵌入式操作系统下驱动程序的实现。文章重点
[嵌入式]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved