文章目录
- 前言
- 1、spinlock是什么?
- 2、自旋锁实验
-
- 2.1源码
- 2.2 结果图
- 总结
前言
本文记录在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控制应用程序只允许打开一个。
思路:
- 在驱动程序init初始化lock
- 每次open驱动设备,都会上锁解锁来限制state变量,防止其他线程修改state变量。state为1的时候表示有应用程序在占用设备。为0则表示设备空闲。
- 应用程序结束后,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;