学习笔记八:linux驱动之内核信号量

信号量

信号量分为用户信号量和内核信号量,用户信号量又分为POSIX信号量和SYTEM V 信号量,POSIX信号量又细分为无名信号量与有名信号量。所以总共有四种信号量,即无名信号量、有名信号量、SYTEM V信号量、内核信号量。
该文章中主要讲内核信号量的使用方法:

初始化

在linux/semaphore.h中

#include <linux/semaphore.h>
struct semaphore sem;
sema_init(&sem,1);
// 第一个参数是要操作的信号量
// 第二个参数是信号量计数的初始值

PV操作:
P操作指的是一个任务想要获取已经被占用的信号量时,信号量会将其放入一个等待队列中然后让其睡眠。
V操作指的是当持有信号量的进程将信号释放,处于等待队列中的一个任务将被唤醒(因为等待队列中不止一个任务),并让其获得信号量。

P操作相关函数:

// 如果可以获得信号量计数-1,无法则获得挂入等待队列睡眠
void down(struct semaphore *sem);
// 如果可以获得信号量计数-1,无法则获得挂入等待队列睡眠,可被打断
int __must_check down_interruptible(struct semaphore *sem);
// 如果可以获得信号量计数-1,无法则获得挂入等待队列睡眠,可被杀死
int __must_check down_killable(struct semaphore *sem);
// 尝试获取信号量,成功获得计数-1,返回0,失败返回非零,不会导致睡眠
int __must_check down_trylock(struct semaphore *sem);
// 如果可以获得信号量计数-1,无法获得加入等待队列等待,达到超时时间返回非0
int __must_check down_timeout(struct semaphore *sem,long jiffies);

V操作相关函数:

// 释放信号量,并唤醒等待队列中的一个任务
void up(struct semaphore *sem);

示例代码:
模块源文件sema.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/semaphore.h>

#define DEV_NAME    "sema_test"
#define DEV_NUM     (1)


static struct my_st
{
    int major;
    int minor;
    dev_t dev_num;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct semaphore sema;
}*my;


static int sema_open(struct inode *inode,struct file *file)
{
    printk("oepn()\r\n");
    down(&my->sema);
    return 0;
}

static int sema_release(struct inode *inode,struct file *file)
{
    printk("release()\r\n");
    up(&my->sema);
    return 0;
}
static const struct file_operations fops =
{
    .owner = THIS_MODULE,
    .open = sema_open,
    .release = sema_release,
};

static int __init msema_init(void)
{
    int ret;
    my = kzalloc(sizeof(struct my_st),GFP_KERNEL);
    if(my == NULL)
        return -ENOMEM;


    sema_init(&my->sema,1);

    ret = alloc_chrdev_region(&my->dev_num,0,DEV_NUM,DEV_NAME);
    if(ret < 0)
        goto alloc_chrdev_failed;

    my->major = MAJOR(my->dev_num);
    my->minor = MINOR(my->dev_num);

    cdev_init(&my->cdev,&fops);
    my->cdev.owner = THIS_MODULE;
    ret = cdev_add(&my->cdev,my->dev_num,DEV_NUM);
    if(ret < 0)
        goto cdev_add_failed;

    my->class = class_create(THIS_MODULE,DEV_NAME);
    if(IS_ERR(my->class))
    {
        ret = PTR_ERR(my->class);
        goto class_create_failed;
    }
    my->device = device_create(my->class,NULL,my->dev_num,NULL,DEV_NAME);
    if(IS_ERR(my->device))
    {
        ret = PTR_ERR(my->device);
        goto device_create_failed;
    }


    printk("sema module was installed !!!\r\n");
    printk("major dev number is %d \r\n",my->major);

    return 0;


device_create_failed:
    class_destroy(my->class);
class_create_failed:
    cdev_del(&my->cdev);
cdev_add_failed:
    unregister_chrdev_region(my->dev_num,DEV_NUM);
alloc_chrdev_failed:
    kfree(my);
    return ret;
}

static void __exit msema_exit(void)
{
    device_destroy(my->class,my->dev_num);
    class_destroy(my->class);
    cdev_del(&my->cdev);
    unregister_chrdev_region(my->dev_num,DEV_NUM);
    kfree(my);

}

module_init(msema_init);
module_exit(msema_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chen");

Makefile 文件

ifneq ($(KERNELRELEASE),)
    obj-m:=sema.o
else
    CURRENT_DIR:=$(shell pwd)
    KERNEL_DIR:=/lib/modules/$(shell uname -r)/build
    ccflags-y:=-std=gnu99 -Wno-declaration-after-statement
all:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
clean:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
endif

测试文件

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd; 
    fd = open("/dev/sema_test",O_RDWR);
    if(fd < 0)
    {   
        perror("");
        exit(1);
    }   

    printf("1\r\n");
    sleep(15);
    printf("2\r\n");

    close(fd);


    exit(0);
}

编译程序,然后切换到root执行,再开启一个新的终端也执行,可以看到,只有在第一个app执行后第二个app才能获取信号量才能执行。并且在过程中无法使用ctrl+c结束,若有需要可以使用down的其他类型函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值