最近在做一个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. Add Digits 解答

    Question Given a non-negative integer num, repeatedly add all its digits until the result has only o ...

  2. UVA10487(二分)

    Given is a set of integers and then a sequence of queries. A query gives you a number and asks to fin ...

  3. 关于set和map的用法

    1.set 定义:每个元素最多只出现一次,并且默认的是从小到大排序. set 遍历: 题目http://www.cnblogs.com/ZP-Better/p/4700218.html for(set ...

  4. 擅长排列的小明 II(找规律)

    擅长排列的小明 II 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 小明十分聪明,而且十分擅长排列计算. 有一天小明心血来潮想考考你,他给了你一个正整数n,序列1,2, ...

  5. C,C#,C++中&&和||,&和|的联系和区别

    本文来自:http://www.cnblogs.com/GT_Andy/archive/2010/03/30/1921805.html 两者计算结果相同(针对各自的运算对象),只是性能上有差别而已. ...

  6. [bzoj2301: [HAOI2011]Problem b] 乞讨

    </pre><pre code_snippet_id="507886" snippet_file_name="blog_20141104_2_53831 ...

  7. Multiscale Combinatorial Grouping 学习和理解源代码(一)

    目标探测由于所做的最新研究.因此,这一领域的一般阅读文章.发现这篇文章,效果是比较新的比较好.在如此仔细研究.贴纸和共享.下面已经发布若干个连续的,分别对论文和代码进行大致地介绍,最后依据自己的实验对 ...

  8. Linux三种关机/重启系统的命令

    Linux提供了三种关机/重启系统的命令:shutdown.halt和reboot.这三个命令在一般情况下只有 系统的超级用户(一般是指root)才可以执行.输入没有参数的shutdown命令,两分钟 ...

  9. 全分布式环境下,DataNode不启动的问题解决

    问题出现:机器重启之后,再次在master结点上面执行start-all.sh,发现有一个datanode没有启动,通过jps检查之后,发现slave1上面的datanode进程未启动 原因:每次na ...

  10. SQL Server服务启动失败,错误代码:10048

    今天打开电脑后遇到了一个奇葩的问题,启动Sql Server服务时,出现如下图所示错误: