[Linux内核驱动]信号量
信号量
更多详细内容在我的github中
对应操作系统中的经典概念PV操作,信号量的值可以是0、1或n。
使用
#include <linux/semaphore.h>
// 定义
struct semaphore sem;
// 初始化信号量sem的值为val
sema_init(&sem, int val);
// 获得信号量
// 会导致当前进程睡眠,不能被信号打断
down(&sem);
// 会导致当前进程睡眠,可被信号打断
down_interruptible(&sem);
// 释放
up(&sem);
运行
make
insmod semaphore.ko
gcc test.c -o test
./test
// 另外开启一个终端
cat /dev/sem_dev
// 会发现只有当test结束后,才会输出内容
互斥锁
与信号量类似,但是互斥锁的值只能是0或1。
#include <linux/mutex.h>
// 声明
struct mutex lock;
// 初始化
mutex_init(&lock);
// 获取互斥锁
mutex_lock(&lock);
mutex_lock_interruptible(&lock);
// 尝试获取互斥锁,失败时不会引起睡眠
mutex_trylock(&lock);
// 释放
mutex_unlock(&lock);/*
* @Date: 2024-05-01 09:44:20
* @author: lidonghang-02 [email protected]
* @LastEditTime: 2024-05-19 19:55:47
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#define SEM_SIZE 0x1000
#define MEM_CLEAR 0x1
#define SEM_MAJOR 230
static int major = 230;
static int minor = 0;
struct semaphore ops_sem;
struct sem_dev
{
struct cdev cdev;
struct class* cls;
struct device* class_dev;
struct semaphore sem;
unsigned char mem[SEM_SIZE];
};
struct sem_dev* sem_devp;
static int sem_open_func(struct inode* inode, struct file* filp)
{
if (down_interruptible(&ops_sem) != 0)
return -ERESTARTSYS;
filp->private_data = sem_devp;
return 0;
}
static int sem_release_func(struct inode* inode, struct file* filp)
{
up(&ops_sem);
return 0;
}
static long sem_ioctl_func(struct file* filp, unsigned int cmd, unsigned long arg)
{
struct sem_dev* dev = filp->private_data;
switch (cmd)
{
case MEM_CLEAR:
memset(dev->mem, 0, SEM_SIZE);
printk(KERN_INFO "Memory cleared\n");
break;
default:
return -ENOTTY;
}
return 0;
}
static ssize_t sem_read_func(struct file* filp, char __user* buf, size_t size, loff_t* ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct sem_dev* dev = filp->private_data;
if (p >= SEM_SIZE)
return 0;
if (count > SEM_SIZE - p)
count = SEM_SIZE - p;
// 获取信号量,可以被信号打断,这时候返回非0
if (down_interruptible(&dev->sem) != 0)
return -ERESTARTSYS;
if (copy_to_user(buf, dev->mem + p, count))
ret = -EFAULT;
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %u bytes from %lu\n", count, p);
}
up(&dev->sem);
return ret;
}
static ssize_t sem_write_func(struct file* filp, const char __user* buf, size_t size, loff_t* ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct sem_dev* dev = filp->private_data;
if (p >= SEM_SIZE)
return -ENOMEM;
if (count > SEM_SIZE - p)
count = SEM_SIZE - p;
if (down_interruptible(&dev->sem) != 0)
return -ERESTARTSYS;
if (copy_from_user(dev->mem + p, buf, count))
ret = -EFAULT;
else
{
ret = count;
printk(KERN_INFO "wrote %u bytes to %lu\n", count, p);
}
up(&dev->sem);
return ret;
}
static struct file_operations sem_ops =
{
.owner = THIS_MODULE,
.open = sem_open_func,
.release = sem_release_func,
.unlocked_ioctl = sem_ioctl_func,
.read = sem_read_func,
.write = sem_write_func,
};
static int __init sem_init_module(void)
{
int ret = 0;
dev_t devno = MKDEV(major, minor);
printk(KERN_INFO "Semaphore init\n");
if (major)
ret = register_chrdev_region(devno, 1, "sem");
else
{
ret = alloc_chrdev_region(&devno, minor, 1, "sem");
major = MAJOR(devno);
}
if (ret < 0)
return ret;
sem_devp = kzalloc(sizeof(struct sem_dev), GFP_KERNEL);
if (!sem_devp)
{
ret = -ENOMEM;
goto out_err_1;
}
cdev_init(&sem_devp->cdev, &sem_ops);
sem_devp->cdev.owner = THIS_MODULE;
if (cdev_add(&sem_devp->cdev, devno, 1))
{
printk(KERN_ERR "cdev_add failed\n");
ret = -ENOMEM;
goto out_err_1;
}
sem_devp->cls = class_create(THIS_MODULE, "sem_cls");
if (IS_ERR(sem_devp->cls))
{
printk(KERN_ERR "class_create failed\n");
ret = PTR_ERR(sem_devp->cls);
goto out_err_1;
}
sem_devp->class_dev = device_create(sem_devp->cls, NULL, devno, NULL, "sem_dev");
if (IS_ERR(sem_devp->class_dev))
{
printk(KERN_ERR "device_create failed\n");
ret = PTR_ERR(sem_devp->class_dev);
goto out_err_2;
}
sema_init(&sem_devp->sem, 1);
sema_init(&ops_sem, 1);
return 0;
out_err_2:
class_destroy(sem_devp->cls);
out_err_1:
unregister_chrdev_region(devno, 1);
return ret;
}
static void __exit sem_exit_module(void)
{
printk(KERN_INFO "Semaphore exit\n");
device_destroy(sem_devp->cls, MKDEV(major, minor));
class_destroy(sem_devp->cls);
kfree(sem_devp);
unregister_chrdev_region(MKDEV(major, minor), 1);
}
module_param(major, int, S_IRUGO);
module_init(sem_init_module);
module_exit(sem_exit_module);
MODULE_AUTHOR("lidonghang-02");
MODULE_LICENSE("GPL");
代码