最近在做一个arm+linux平台的视频驱动。本来这个驱动应该是做板子的第三方提供的,结果对方软件实力很差,自己做不了这个东西,外包给了一个暑期兼职的在读博士。学生嘛,只做过实验,没做过产品,给出的东西自然和产品的实际需要相去十万八千里。博士同学给我们的驱动甚至是从未编译过的,充满了"unsigned void "这样可笑的语法错误,不得已跑到北平追着那厮现场联调,最后所谓的“调通”,也仅仅是寄存器配置正确而已。

视频驱动的输出是连续的帧数据,必须要有完善的缓冲、跳帧和同步阻塞机制。而这些机制在博士同学给我的驱动程序中全部付之阙如。在这份驱动程序中,是没有阻塞机制的,在采集一帧图像期间连续两次调用采集API,得到的会是同一帧图像的buffer。如果你写一个线程循环采集,那么这个线程必定会耗尽CPU所有空闲的资源。诸如此类的问题还有一大堆,这样的驱动肯定是没法用到实际产品中的。

不得已只好自己操刀上阵改写这个驱动。我的思路是这样的:

驱动程序流程

1、在驱动中创建两个内核链表,一个用来缓冲新采集到的图像buffer,而另一个用来缓冲废弃的图像buffer。

2、从预先分配的buffer中取出三个buffer,第一个作为前帧buffer,第二个作为当前buffer设置为dma目的地址,第三个作为后备buffer。

3、当新图像到来时,将dma目的地址更新为后备buffer,然后将前帧buffer链入新图像链表尾端。

4、将当前buffer的值赋给前帧buffer,将后备buffer的值赋给当前buffer,再判断废弃图像链表中是否有buffer存在。

5、如果废弃链表不为空,则从废弃图像链表取出一个buffer赋给后备buffer;如果废弃图像链表中没有buffer可用,则从新图像链表中获取一个buffer赋给后备buffer,也就是发生了跳帧。

备注:链表中buffer的进出使用信号量进行增减计数

客户程序流程

1、判断新图像链表是否为空。

2、不为空则从新图像链表获取一个buffer,即采集到一帧图像;为空则由于计数信号量为0,导致线程挂起等到新buffer链入链表。

3、使用采集到的图像。

4、将使用过的图像buffer送入废弃链表。

由于使用信号量对链表进行了计数,当链表为空时,从链表获取buffer的线程可以挂起,也就达到了阻塞同步的目的。新图像被链表串联在一起,达到了缓冲的目的。当废弃链表中的buffer耗尽时,从新图像链表获取buffer进行采集,达到了跳帧的目的。这样的流程设计似乎是没有问题,但是实现起来就遇到了些麻烦。这个机制中,链表的更新是在中断和线程并发执行的,有很大的几率发生访问冲突,这就要求引入互斥机制。然而中断是不可阻塞或挂起的,互斥量不能在中断中使用。基于循环等待的自旋锁,在这种场合又会引起死锁(当用户线程获得自旋锁之后,如果有中断发生,线程会被中断抢占;此时中断试图获取自旋锁,必然由于获取不到而循环等待;此时线程被中断抢占,无法释放手中的自旋锁,就会造成死锁)。这就要求引入一种机制,既要能够被阻塞,又要能在中断isr返回之后立即执行。将链表的更新操作全部安排到这种机制中,就能够实现与用户线程的互斥。

linux提供了一种称为“底半部(bottom half)”的机制。ISR是软件代码,由硬件设备触发。底半部机制类似中断,却是由软件代码触发的。常用的底半部机制有软中断、基于软中断的tasklet(小任务)和基于内核线程的工作队列等。软中断类似于中断,也是不可阻塞的,显然软中断和基于软中断的tasklet等机制无法满足我的需求。而工作队列是可以阻塞的,又可以在中断中触发执行,看起来这是一个不错的选择。

于是我将原先规划给中断的链表操作全部移到了工作队列绑定的函数中,每次中断触发时,isr将后备buffer的值置为dma目的地址,然后触发工作队列。工作队列绑定的函数根据链表当前的情况更新当前buffer和后备buffer的地址,供isr下一次执行时使用。当然这个过程是加了互斥机制的,在用户线程调用的驱动api中也加了同样的互斥机制,这样二者就不会发生冲突。

在我看来,所谓“底半部”机制这种说法很有故弄玄虚的味道。在任何处理器或操作系统中,中断都是一种不可阻塞且必须快速返回的机制,遇到长时间的运算或必须阻塞的情形,都会采用由中断触发某种线程或任务的方法。例如在DSP/BIOS或ucOS-II中,一般会为类似的工作预留一个高优先级的线程,平时被信号或邮箱阻塞,在中断isr中发送信号或消息来触发这个线程。虽然采用了类似的处理方法,但是并没有什么“底半部”之类的术语。可能是linux内核太过庞杂了吧,还严格区分了内核态和用户态,不能像准操作系统内核那样使用普通线程实现这种机制,而内核线程等机制调用又太过复杂,必须进行专门的封装才能得到易于使用的API。按照我的理解,所谓的“底半部”,其实就是这种“封装”而已。

linux底半部机制在视频采集驱动中的应用的更多相关文章

  1. Linux中断底半部机制

    参考: Linux下半部处理之软中断 linux中断底半部机制 <深入理解Linux内核>软中断/tasklet/工作队列 软中断和tasklet介绍 详解操作系统中断 Linux内核:中 ...

  2. linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】

    转自:http://blog.chinaunix.net/uid-20768928-id-5077401.html 在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方 ...

  3. Linux内核中断顶半部和底半部的理解

    文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...

  4. 嵌入式LINUX环境下视频采集知识

    V4L2是Linux环境下开发视频采集设备驱动程序的一套规范(API),它为驱动程序的编写提供统一的接口,并将所有的视频采集设备的驱动程序都纳入其的管理之中.V4L2不仅给驱动程序编写者带来极大的方便 ...

  5. Linux 驱动框架---驱动中的中断

    在单片机开发中中断就是执行过程中发生了一些事件需要及时处理,所以需要停止当前正在运行的处理的事情转而去执行中断服务函数,已完成必要的事件的处理.在Linux中断一样是如此使用但是基于常见的中断控制器的 ...

  6. V4L2视频采集原理

    一.简介 Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版.V4L2是linux操作系统下用于采集图片.视频和音频数据的API接口,配合适当的视频采集设备 ...

  7. 基于PCIe的多路视频采集与显示子系统

    基于PCIe的多路视频采集与显示子系统 1        概述 视频采集与显示子系统可以实时采集多路视频信号,并存储到视频采集队列中,借助高效的硬实时视频帧出入队列管理和PCIe C2H DMA引擎, ...

  8. Linux kernel workqueue机制分析

    Linux kernel workqueue机制分析 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.10.108的workqueue文档分析其基 ...

  9. Linux内核同步机制之completion【转】

    Linux内核同步机制之completion 内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束.这个活动可能是,创建一个新的内核线程或者新的用户空间进程.对一个已有进程的 ...

随机推荐

  1. relative与absolute相结合

    relative会把别人挤下去, absolute会跑偏. 两者结合就会很好的解决问题. <span class='pic_selected' style='position:relative; ...

  2. VC使用#定义方便控制版本号的宏

    一个 VC Project 中,可能有很多地方需要用到版本号,比如 About 对话框.版本资源等.如果每次版本更改都一一去改变这些值,不但非常麻烦,而且有悖唯一原则. 巧妙地使用宏定义,可以很好地解 ...

  3. (转载)HDU4565

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4565 这个博客讲的比较好:http://blog.csdn.net/ljd4305/article/d ...

  4. [Leetcode][Python]56: Merge Intervals

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 56: Merge Intervalshttps://oj.leetcode. ...

  5. Linux系统下定时上传文件至FTP服务器脚本

    环境:Red Hat Enterprise Linux Server release 6.4 需求:需要将Oracle数据库的定时备份上传至FTP服务器 1.干货,用户名:oracle,数据库名称:X ...

  6. Struts2(三)——数据在框架中的数据流转问题

    一款软件,无在乎对数据的处理.而B/S软件,一般都是用户通过浏览器客户端输入数据,传递到服务器,服务器进行相关处理,然后返回到指定的页面,进行相关显示,完成相关功能.这篇博客重点简述一下Struts2 ...

  7. WIN7 64位系统安装JDK并配置环境变量

    本文来自:http://jingyan.baidu.com/article/3c343ff70bc6ea0d377963df.html 工具/原料 JDK 方法/步骤   首先,下载JDK安装包,到官 ...

  8. PCI、PCIE配置空间的訪问(MCFG,Bus,Device,Funtion)

    一般来说,在x86平台上,有两大类方式能够訪问这一区间的寄存器,   1,配置机制1#或者配置机制2#   訪问时借助in/out指令.请注意,这样的方式有别于一般的in/out指令訪问PCI的IO空 ...

  9. vim中对文本的选择

    本文主要解说vim中对文本的选择,vim中选择文本分为: (1)选择字符  ----  命令行模式下输入小写v (2)选择行     ----  命令行模式下输入大写V (3)选择块     ---- ...

  10. cacti出现snmp error

    一.在被监控机器中确认snmp是否启动 service snmpd status [root@test2 ~]# service snmpd status snmpd (pid  1247) 正在运行 ...