所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!
关于 LINUX驱动 的其它文章请点击这里: LINUX驱动
本文为 Linux内核的竞态与并发(中断屏蔽、原子操作、自旋锁、信号量、互斥体的互斥机制) 中原子操作的实例
其它部分:
● Linux内核的竞态与并发——原子操作实例
● Linux内核的竞态与并发——信号量实例
自旋锁使用步骤
// 1)定义一个自旋锁变量:
spinlock_t btn_lock;
// 2) 初始化自旋锁 :
spin_lock_init(&btn_lock)
// 3) 获取自旋锁 (获取权利)
spin_lock(&btn_lock); //获取自旋锁不成功,原地自旋等待,直到锁被释放,获取成功才返回
//或:
int spin_trylock(&btn_lock);//不成功,直接返回一个错误信息,调试的时候可用,可以避免死锁
// 4) 访问共享资源
// 5) 释放自旋锁
spin_unlock(&btn_lock);
自旋锁还有很多衍生自旋锁:读锁 写锁 顺序锁 内核的大锁:
// 1)定义一个自旋锁变量:
spinlock_t btn_lock;
// 2) 初始化自旋锁 :
spin_lock_init(&btn_lock)
// 3) 获取自旋锁 (获取权利)
unsigned long flags;
spin_lock_irq(&lock); // = spin_lock() + local_irq_disable()
//或
spin_lock_irqsave(&lock, flags); // = spin_lock() local_irq_save()
// 4) 访问共享资源
// 5) 释放自旋锁
spin_unlock_irq(&lock); // = spin_unlock()+ local_irq_enable()
//或
spin_unlock_irqrestore(&lock, flags); // = spin_unlock() + local_irq_restore()
实例
btn_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
dev_t dev;
struct cdev btn_cdev;
struct class *cls = NULL;
int count = 1; //共享资源
spinlock_t btn_lock; //[1]. 定义一个自旋锁变量
int btn_open(struct inode *inode, struct file *filp)
{
spin_lock(&btn_lock); /*[3].获取自旋锁*/
count--; /*[4] 访问共享资源*/
if(count !=0 )
{
count++;
spin_unlock(&btn_lock); /*[5]. 释放自旋锁*/
return -EBUSY;
}
spin_unlock(&btn_lock); /*[5].释放自旋锁*/
return 0;
}
int btn_close(struct inode *inode, struct file *filp)
{
spin_lock(&btn_lock);
count++;
spin_unlock(&btn_lock);
return 0;
}
struct file_operations btn_fops =
{
.owner = THIS_MODULE,
.open = btn_open,
.release = btn_close,
};
int __init btn_drv_init(void)
{
alloc_chrdev_region(&dev, 100, 1, "mybuttons"); /*设备号的动态申请注册*/
cdev_init(&btn_cdev, &btn_fops); /*初始化cdev*/
cdev_add(&btn_cdev, dev, 1); /*注册cdev*/
cls = class_create(THIS_MODULE, "buttons"); /*设备文件的自动创建*/
device_create(cls, NULL, dev, NULL,"mybuttons");
spin_lock_init(&btn_lock); /*2.初始化自旋锁*/
return 0;
}
void __exit btn_drv_exit(void)
{
/*销毁设备文件*/
device_destroy(cls, dev);
class_destroy(cls);
/*注销cdev*/
cdev_del(&btn_cdev);
/*注销设备号*/
unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
Makefile
obj-m += btn_drv.o
all:
make -C /home/chuckchee/driver/kernel M=$(PWD) modules
cp *.ko ../../rootfs
arm-cortex_a9-linux-gnueabi-gcc test.c -o test
cp test ../../rootfs
clean:
make -C /home/chuckchee/driver/kernel M=$(PWD) clean
test.c应用测试代码
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd = open("/dev/mybuttons", O_RDWR);
if(fd < 0)
{
perror("open failed:");
return -1;
}
printf("open successed: using device 20s...\n");
sleep(20);
printf("close device\n");
close(fd);
return 0;
}
实验步骤:
① insmod btn_drv.ko //设备文件自动形成
② ./test
③ 远程登录:telnet 192.168.1.6
④ ./test
⑤ 结果一般是登录失败
关于 LINUX驱动 的其它文章请点击这里: LINUX驱动