自旋锁(spinlock)
更多内容可以查看我的github
概念
Spinlock是linux内核中常用的一种互斥锁机制,和mutex不同,当无法持锁进入临界区的时候,当前执行线索不会阻塞,而是不断的自旋等待该锁释放。 正因为如此,自旋锁也是可以用在中断上下文的。 也正是因为自旋,临界区的代码要求尽量的精简,否则在高竞争场景下会浪费宝贵的CPU资源。
使用
#include <linux/spinlock.h>
// 定义自选锁
spinlock_t lock;
// 初始化自旋锁
spin_lock_init(&lock);
// 获取自旋锁
spin_lock(&lock);
// 释放自旋锁
spin_unlock(&lock);
尽管使用自旋锁可以保证临界区不受别的CPU和本CPU内的抢占进程打扰。但是得到锁的代码路径在执行临界区的时候,可能受到 中断 的影响。因此,需要使用自旋锁的衍生函数。
// 锁 + 开/关中断
spin_lock_irq();
spin_unlock_irq();// 锁 + 关中断并保存中断状态/开中断并恢复中断状态
spin_lock_irqsave();
spin_unlock_irqrestore();
测试
make
dmesg -C
insmod spinlock.ko
mknod /dev/spinlock c 232 0cat /dev/spinlock
dmesg
echo "1" > /dev/spinlock
dmesg
cat /dev/spinlock
dmesg
代码
/** @Date: 2024-04-30 15:35:19* @author: lidonghang-02 2426971102@qq.com* @LastEditTime: 2024-05-19 20:02:50*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/device.h>#define DEVICE_NAME "spinlock_dev"#define SPINLOCK_MAJOR 0
static int spinlock_major = SPINLOCK_MAJOR;struct spinlock_dev
{struct cdev cdev;int shared_resource;struct device *class_dev;
};struct spinlock_dev *spinlock_devp;
struct class *my_class = NULL;
static dev_t dev_no;// 自旋锁
spinlock_t my_lock;static int spinlock_open_func(struct inode *inode, struct file *file)
{file->private_data = spinlock_devp;printk(KERN_INFO "Spinlock Device Opened\n");return 0;
}
static int spinlock_release_func(struct inode *inode, struct file *file)
{printk(KERN_INFO "Spinlock Device Closed\n");return 0;
}
static ssize_t spinlock_read_func(struct file *filp, char __user *buf, size_t size,loff_t *ppos)
{struct spinlock_dev *dev = filp->private_data;// 从用户空间读取数据if (copy_to_user(buf, &dev->shared_resource, sizeof(int))){printk(KERN_ERR "Failed to copy data to user space\n");return -EFAULT;}elseprintk(KERN_INFO "shared_resource: %d\n", dev->shared_resource);ppos += sizeof(int);return 0;
}
static ssize_t spinlock_write_func(struct file *filp, const char __user *buf, size_t size,loff_t *ppos)
{unsigned long flags;unsigned int count = size;struct spinlock_dev *dev = filp->private_data;// 加锁spin_lock_irqsave(&my_lock, flags);// 假设的共享资源操作dev->shared_resource += 1;// 解锁spin_unlock_irqrestore(&my_lock, flags);printk(KERN_INFO "shared_resource: %d\n", dev->shared_resource);return count;
}// 设备操作结构体
static const struct file_operations fops = {.open = spinlock_open_func,.release = spinlock_release_func,.read = spinlock_read_func,.write = spinlock_write_func,
};// 驱动初始化函数
static int __init my_driver_init_module(void)
{int ret;dev_no = MKDEV(spinlock_major, 0);spin_lock_init(&my_lock);// 分配设备号if (spinlock_major)ret = register_chrdev_region(dev_no, 1, DEVICE_NAME);else{ret = alloc_chrdev_region(&dev_no, 0, 1, DEVICE_NAME);spinlock_major = MAJOR(dev_no);}if (ret < 0){printk(KERN_ERR "Failed to allocate device number\n");return ret;}spinlock_devp = kzalloc(sizeof(struct spinlock_dev), GFP_KERNEL);if (!spinlock_devp){ret = -ENOMEM;goto free_chrdev_region;}my_class = class_create(THIS_MODULE, "spinlock");if (IS_ERR(my_class)){ret = PTR_ERR(my_class);goto free_chrdev_region;}// 初始化字符设备cdev_init(&spinlock_devp->cdev, &fops);spinlock_devp->cdev.owner = THIS_MODULE;ret = cdev_add(&spinlock_devp->cdev, dev_no, 1);if (ret < 0){printk(KERN_ERR "Failed to add cdev\n");goto free_chrdev_class;}spinlock_devp->class_dev = device_create(my_class, NULL, dev_no, NULL, DEVICE_NAME);if (IS_ERR(spinlock_devp->class_dev)){ret = PTR_ERR(spinlock_devp->class_dev);goto free_chrdev_class;}printk(KERN_INFO "My Spinlock Driver Init\n");return 0;free_chrdev_class:class_destroy(my_class);free_chrdev_region:unregister_chrdev_region(dev_no, 1);return ret;
}// 驱动退出函数
static void __exit my_driver_exit_module(void)
{cdev_del(&spinlock_devp->cdev);unregister_chrdev_region(dev_no, 1);kfree(spinlock_devp);printk(KERN_INFO "My Spinlock Driver Exited\n");
}module_init(my_driver_init_module);
module_exit(my_driver_exit_module);MODULE_AUTHOR("lidonghang-02");
MODULE_LICENSE("GPL");