rk3568_spinlock

本文详述了在rk3568开发板上进行的自旋锁实验,介绍了自旋锁的概念及其在Linux内核中的实现。通过示例代码展示了如何在驱动程序中使用spin_lock_irqsave和spin_unlock_irqrestore来控制state变量,确保只有一个应用程序能打开设备。文章还探讨了自旋锁的优缺点及适用场景,并提醒避免在临界区调用可能导致睡眠或阻塞的函数以防止死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

本文记录在rk3568开发板做的自旋锁实验。通过自旋锁控制state变量来限制只有一个应用程序来打开驱动设备。


1、spinlock是什么?

spinlock称为自旋锁,如果获取不到资源,就只能一直傻傻地等待资源被释放——“原地打转”,所以称为自旋锁。

Linux内核使用结构体spinlock_t表示自旋锁。

typedef struct spinlock {
   
union {
   
struct raw_spinlock rlock;

 #ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
   
 u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;

在使用自旋锁之前,肯定要先定义一个自旋锁变量,定义方法如下所示:
spinlock_t lock; //定义自旋锁

自旋锁API函数
在这里插入图片描述
注意:
若线程A执行自旋锁的过程中,被中断打断了,中断也有执行自旋锁的操作,那么为了防止死锁的出现,最好的解决办法是获取锁之前,关闭本地中断。
在这里插入图片描述线程与中断并发访问处理 API 函数
在这里插入图片描述
建议使用 spin_lock_irqsave/ spin_unlock_irqrestore,因为这一组函
数会保存中断状态,在释放锁的时候会恢复中断状态。一般在线程中使用 spin_lock_irqsave/
spin_unlock_irqrestore,在中断中使用 spin_lock/spin_unlock,示例代码如下所示:

 DEFINE_SPINLOCK(lock) /* 定义并初始化一个锁 */

/* 线程 A */
void functionA (){
   
    unsigned long flags; /* 中断状态 */
    spin_lock_irqsave(&lock, flags) /* 获取锁 */
    /* 临界区 */
    spin_unlock_irqrestore(&lock, flags) /* 释放锁 */
}

/* 中断服务函数 */
void irq() {
   
    spin_lock(&lock) /* 获取锁 */
    /* 临界区 */
    spin_unlock(&lock) /* 释放锁 */
}

下半部(BH)也会竞争共享资源,有些资料也会将下半部叫做底半部。关于下半部后面的
章节会讲解,如果要在下半部里面使用自旋锁
在这里插入图片描述

2、自旋锁实验

本实验目的:用spinlock的lock变量控制state变量加减,state控制应用程序只允许打开一个。

思路:

  1. 在驱动程序init初始化lock
  2. 每次open驱动设备,都会上锁解锁来限制state变量,防止其他线程修改state变量。state为1的时候表示有应用程序在占用设备。为0则表示设备空闲。
  3. 应用程序结束后,state变量减1,表示释放设备资源。(realse也要用自旋锁控制state)

2.1源码

驱动程序:spinlock.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define GPIOLED_CNT      		1           	/* 设备号个数 */
#define GPIOLED_NAME        	"gpioled" 	    /* 名字 */
#define LEDOFF              	0               /* 关灯 */
#define LEDON               	1               /* 开灯 */

struct led_dev
{
   
    dev_t devid;          		/* 设备号 */
    struct cdev cdev;    		/* cdev */
    struct class *class;  	    /* 类 */
    struct device *device;  	/* 设备 */
    int major;              	/* 主设备号 */
    int minor;              	/* 次设备号 */
    struct device_node  *nd;    /*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

free(me)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值