Linux内核-内核中断与进程之间的竞争与解决

key.c 利用内核中断实现按键

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>

struct tiny4412_key {
	int keynum;  //按键编号
	int irqnum; //记录内核的中断号
	int cnt;  //条件标记
}keys[4] = {
	{0, IRQ_EINT(26), 0},
	{1, IRQ_EINT(27), 0},
	{2, IRQ_EINT(28), 0},
	{3, IRQ_EINT(29), 0},
};

extern void print_info(char *str);//doem中的打印函数,实现临界资源访问的部分
extern spinlock_t spin;  //从doem申请的自旋锁

/*当按键中断发生后,内核自动调用到注册的这个处理函数,并将
  注册中断时的第五个参数传给此处理函数的第二形参*/
static irqreturn_t do_key(int irqnum, void *data) //中断处理函数
{
	struct tiny4412_key *k = data;	
	char kbuf[SZ_64];
	unsigned long flag;

	k->cnt ^= 1;
	sprintf(kbuf, "key %d is %s.", k->keynum, (k->cnt)?"down":"up");

	spin_lock_irqsave(&spin, flag);  //加锁 避免死锁 用_irqsave函数
	print_info(kbuf);
	spin_unlock_irqrestore(&spin, flag);//解锁

	return IRQ_HANDLED; //IRQ_NONE;
}

int register_key_irq(void)
{
	int i;
	int ret;

	for (i = 0; i < 4; i++) {
		ret = request_irq(keys[i].irqnum, do_key, 
					IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
						"keys", keys+i); //注册中断 通过内核中断的编号,设置双边沿触发
		if (ret < 0) {
			goto error0;
		}
	}

	return 0;
error0:
	while (i--) {
		free_irq(keys[i].irqnum, keys+i);
	}

	return ret;
}

void unregister_key_irq(void)   
{
	int i = 4;

	while (i--) {

		free_irq(keys[i].irqnum, keys+i);   //出口时,需要释放注册的中断
	}
}


demo.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/delay.h>

#define DEVNAME	"spin"

#define LOOPCNT 3

extern void unregister_key_irq(void);
extern int register_key_irq(void);

static int glb_cnt = 0;

spinlock_t spin;

void print_info(char *str)
{
	int i;

	for (i = 0; i < LOOPCNT; i++) {
		printk("%d -> : %s\n", glb_cnt, str);
		glb_cnt++;
		mdelay(50);
	}
}

static long 
demo_ioctl (struct file *filp, unsigned int request, unsigned long arg)
{
	unsigned long flag;
//	spin_lock(&spin);//使用 这个函数会导致只要进程逻辑不结束,永远不会进中断
	spin_lock_irqsave(&spin, flag); 
	print_info((char *)arg);
	spin_unlock_irqrestore(&spin, flag); 
//	spin_unlock(&spin);

	return 0;
}
/*
	为上层用户提供了ioctl的函数接口
*/
static struct file_operations fops = {
	.owner		=  	THIS_MODULE,
	.unlocked_ioctl	=	demo_ioctl,

};

static struct miscdevice misc = {    
	.minor	= 	MISC_DYNAMIC_MINOR,
	.name	=	DEVNAME,
	.fops	=	&fops,
};

static int demo_init(void)  //驱动模块的入口
{
	int ret;

	spin_lock_init(&spin);   //初始化自旋锁

	ret = misc_register(&misc);  //注册混杂设备驱动
	if (ret < 0) {
		return ret;
	}

	ret = register_key_irq(); .//调用key.c中实现的注册中断函数
	if (ret < 0) {
		goto error0;
	}

	return 0;

error0:
	misc_deregister(&misc);

	return ret;
}

module_init(demo_init);

static void demo_exit(void)  //驱动的出口
{
	misc_deregister(&misc);
	unregister_key_irq();    //需要释放注册的中断和混杂设备驱动

	printk("goodbye...\n");
}

module_exit(demo_exit);

MODULE_LICENSE("GPL");

MODULE_VERSION("2018-09-30");
MODULE_AUTHOR("Hebowen");
MODULE_DESCRIPTION("a simple demo for module");

app.c 开启512个进程,使之打印每3个一致,即使发生中断,不会发生资源
的抢占,然后进入中断

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>

#define N 98 

#define SZ 512

/*
 	./a.out /dev/semaphore  r/w
 */
int main(int argc, char **argv)
{
	int fd;
	int ret;
	int i;
	pid_t pid[N];
	char buf[SZ];

	if (argc != 2) {
		fprintf(stderr, "Usage: %s devicefile\n", argv[0]);
		exit(1);
	}

	fd = open(argv[1], O_RDWR | O_NDELAY);
	assert(fd > 0);

	for (i = 0; i < N; i++) { 
		if ((pid[i] = fork()) < 0) {
			perror("fork");
			exit(1);
		}

		if (pid[i] == 0) {
			sprintf(buf, "hello, %d.", getpid());
			ret = ioctl(fd, 0, buf);
			assert(ret == 0);
			return;
		}
	}

	for (i = 0; i < N; i++) {
		waitpid(pid[i], NULL, 0);
	}

	close(fd);

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值