笔记整理—linux驱动开发部分(11)中断上下文

        触摸屏分为两种,一种为电阻式触摸屏,另一种为电容式触摸屏。电阻式触摸屏(x+、x-、y+、y-、+AD)有两种接口,一种为SOC自带的接口(misc+input或platform),第二种为外部IC,通过IIC与SOC进行通信。电容触摸屏类似外部IC方式也是通过IIC通信。

        再次提一下解决竞态的方式:①原子操作automic_t(不可打断,不可拆分的操作);

typedef struct {
	int counter;
} atomic_t;

        ②信号量(互斥锁是一种特别的信号量);③自旋锁。

        竞态:由并发引起的竞争状态。

        同步:并行运行(多核、多任务、中断)会引发同步相关问题。

        临界段:可能造成并发的一段代码,因在上下加入互斥锁或对资源上锁,由此解除竞态。

        死锁:两个锁相互锁死(A锁B,B锁A,钥匙相互在二者手中),

        休眠:代码可以休眠(交出CPU)自己挂起,并保护资源,自己无法满足条件时,保证CPU效率。

        自旋锁:代码运行不了时,拉着CPU死等资源,在原地打转。

        信号量支持休眠交出CPU,因为一般资源等待时间长,而自旋锁不支持休眠,因为一般资源等待时间短。

        自旋锁不可递归,获取自旋锁失败不会返回,会自选等待别人释放锁。自旋锁可用在中断上下文(中断处理程序),但信号量不行,因为会休眠交出CPU,也因为中断上下文的过程不参与进程调度。在中断上下文中获取自旋锁之前要先禁用本地中断,因为可能存在中断嵌套。

        自旋锁的核心要求,拥有锁的代码不能休眠,否则就是思索,直到释放持有的CPU。

        读写信号量,是信号量的升级版plus,读信号量,只管读,不能写;写信号量只能写,不能读,为了解决多写冲突,只能在进行上下文使用。

        总结一下

        自旋锁:中断上下文,短期保留。

        信号量:进程上下文,长期保留。

        二者使用时都要考虑调度成本。自旋锁保持期间是抢占失效的(运行等级高等级抢不到已经锁住的资源与锁)。信号量在保持期间可以被抢占,因为可以被调度。自旋锁只有在抢占式内核+SMPC(多核CPU)中才能真正需要,单核非抢占内核为空操作。

        中断的上下半部:①中断上下文不能与用户空间数据交互,因为会造成休眠;②不能交出cpul交出(休眠、调度);③ISR运行时间尽可能短,越长对系统的影响越大,性能越差。

        进程上下文可以被切分成多个子块分开执行,然而中断上下文不可打断、切分,必须一次性执行完成。中断上半部与下半部用于解决中断处理程序的运行时间问题将一个中断处理程序人为的切分为Top half和Botton half。

        为了兼顾系统特性,上半部一般为:登记中断、标记中断、调度下半部(时间短,但事件很着急);下半部:干活(不太急,时间长)。

        上下半部处理策略:①task let小任务;②work queue工作队列。这与下半部怎么被调度有关。

        tasklet小任务:

#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

void func(unsigned long data)
{
	......

	s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0));		// input模式
	flag = gpio_get_value(S5PV210_GPH0(2));
	s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f));		// eint2模式

	input_report_key(button_dev, KEY_LEFT, !flag);
	input_sync(button_dev);
}

static irqreturn_t button_interrupt(int irq, void *dummy) 
{ 
	......
	
	tasklet_schedule(&mytasklet);
	
	return IRQ_HANDLED; 
}

request_irq(BUTTON_IRQ, button_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "button-x210", NULL);按键上下沿触发

        workqueue方法:中断下半部交给workqueue,可被调度、休眠。workqueue是处理进程上下文的。

#define DECLARE_WORK(n, f)					\
	struct work_struct n = __WORK_INITIALIZER(n, f)


DECLARE_WORK(mywork, func);

void func(struct work_struct *work)//中断下文
{
	......
	s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0));		// input模式
	flag = gpio_get_value(S5PV210_GPH0(2));
	s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f));		// eint2模式

	input_report_key(button_dev, KEY_LEFT, !flag);
	input_sync(button_dev);
}


static irqreturn_t button_interrupt(int irq, void *dummy) //中断上文
{ 
	......
	schedule_work(&mywork);
	return IRQ_HANDLED; 
}

        中断上下半部处理原则:①必须立刻处理,极少的任务要放在上半部,此时屏蔽同类型的中断,可以迅速不被打扰完成紧急任务。②中等数量的任务,中等急迫放在tasklet中,不屏蔽任何中断(包括与自己顶半部同类的中断),不会影响顶半部对紧急任务的处理(以不在量评判调用tasklet)同时又不会进行用户进程调度,保证急迫任务完成。③需求事件较多,且不急迫的大量任务放在workqueue中,此时操作系统会尽量快的处理这个任务,但量大,期间系统也会有机会调度别的用户程序运行,从而保证不会因为这个任务需要运行时其他用户进行无法运行。④可能引起休眠的任务放在workqueue中(休眠、大量内存、阻塞I/O、信号量)用workqueue十分合适。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值