【问题标题】:Correct way to initialize semaphore in linux driver在linux驱动程序中初始化信号量的正确方法
【发布时间】:2017-03-25 20:19:25
【问题描述】:

我写这个linux char驱动只是为了控制open call,

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>

MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem; 

static int myopen(struct inode *inod, struct file *fp)
{
    down(sem);
    printk(KERN_INFO "critical section\n");
    return 0;
}

static int myclose(struct inode *inod, struct file *fp )
{
    up(sem);
    printk(KERN_INFO "critical section freed\n");
    return 0;
}

static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
    return 0;
}

static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
    return 0;
}

static struct file_operations fops = 
{
    .open = myopen,
    .release = myclose,
    .read = myread,
    .write = mywrite,
};

static int __init myinit(void)
{
    int ret;

    ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
    if(ret<0)
    {
        printk(KERN_INFO "chardev can't be allocated\n");
    //  goto label;//todo
    }

    mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
    if(mycdev == NULL)
    {
        printk(KERN_INFO"cdev_alloc failed\n");
    //  goto label;//todo
    }
    mycdev->ops = &fops;

    ret = cdev_add(mycdev, mycdevt, 1);
    if(ret < 0)
    {
        printk(KERN_INFO"cdev_add failed\n");
    //  goto label;//todo
    }

    myclass = class_create(THIS_MODULE, CLASS_NAME);
    if(myclass == NULL)
    {
        printk(KERN_INFO"class create failed\n");
    //  goto label;//todo
    }


    mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
    if(mydevice == NULL)
    {
        printk(KERN_INFO"device create failed\n");
    //  goto label;//todo
    }

    sema_init(sem, 1);//here is the problem
    printk(KERN_INFO"myinit done\n");
    return 0;
}

static void __exit myexit(void)
{
    device_destroy(myclass, mycdevt);
    class_unregister(myclass);
    class_destroy(myclass);
    cdev_del(mycdev);
    unregister_chrdev(MAJOR(mycdevt), "mycdevt");
    printk(KERN_INFO "exited\n");
}   

module_init(myinit);
module_exit(myexit);

我正在关注 ldd3 书,并尝试使用简单的 API 将信号量用于应用程序。 发生的事情是我的内核在调用 sema_init 函数时崩溃了。我读到信号量在互斥模式下使用 http://www.makelinux.net/ldd3/chp-5-sect-3

我还读到信号量不是互斥体,因为没有所有权。我还没有探索“所有权”的东西,但现在我无法制作一个简单的信号量。

我在这里做错了什么?

【问题讨论】:

  • 需要注意的是,使用struct semaphore 作为互斥锁有点过时了。除非您需要支持 2.6.16 之前的旧内核,否则您可能应该使用较新的 struct mutex
  • 有时人们会说,互斥量与信号量有很大不同,并且书籍说它只是一个二进制信号量。关注什么
  • 有不同类型的互斥锁,包括可重入互斥锁,其中互斥锁可以由同一所有者递归锁定。内核中的struct mutex 只是一个简单的、不可重入的互斥体。
  • 只看linux专业架构书。它提到了两种类型的互斥锁,一种互斥锁用作二进制信号量,称为经典互斥锁,另一种用于解决优先级反转问题。
  • 那么既然重入互斥体需要记录所有者,那么当前所有者的优先级可以被操作系统提升,而更高优先级的任务正在等待互斥体?实现重入和克服优先级倒置都需要记录互斥体的当前所有者,但它们不是一回事。

标签: c linux-kernel linux-device-driver semaphore


【解决方案1】:

没有实际的信号量。

这一行:

static struct semaphore *sem; 

创建一个指向信号量的指针,而不是信号量本身。几乎可以肯定初始化为NULL

你可能想要类似的东西

static struct semaphore sem;

因此

sema_init( &sem, 1);

随着

up( &sem );

down( &sem );

请注意,这些调用使用的是实际信号量的地址。

【讨论】:

  • 信号量初始化是否使用自旋锁?我在 sema_init 内部看到它使用 __RAW_SPIN_LOCK_UNLOCKED。
  • 是的,信号量的自旋锁字段是用那个值初始化的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多