代码改变世界

《LINUX设备驱动程序》学习之信号量实例

2012-10-31 17:34  Chung-shu  阅读(382)  评论(0)    收藏  举报

1. 在上一个globalvar模块的基础上,添加信号量机制,globalvar.c代码如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include <linux/random.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");

int globalvar_open(struct inode *, struct file *);
int globalvar_release(struct inode *, struct file *);
ssize_t globalvar_read(struct file *, char *, size_t, loff_t *);
ssize_t globalvar_write(struct file *, const char *, size_t, loff_t *);

int dev_major=0;
int dev_minor=0;

struct file_operations globalvar_fos=
{
    .owner=THIS_MODULE,
    .open=globalvar_open,
    .release=globalvar_release,
    .read=globalvar_read,
    .write=globalvar_write,
};

struct globalvar_dev
{
    int global_var;                    //代表要操作的设备
    struct cdev cdev;                  //内核中表示字符设备的结构
    struct semaphore sem;              //互斥信号量
};

struct globalvar_dev *my_dev;


static void __exit globalvar_exit(void)       //退出模块时的操作
{
    dev_t devno=MKDEV(dev_major, dev_minor);
    cdev_del(&my_dev->cdev);               //从系统中移除一个字符设备
    kfree(my_dev);                         //释放自定义的设备结构
    unregister_chrdev_region(devno, 1);    //注销已注册的驱动程序
    printk("globalvar unregister success!\n");    
}

static int __init globalvar_init(void)        //初始化模块的操作
{
    int ret, err;

    dev_t devno=MKDEV(dev_major, dev_minor);

    //注册设备号
    if(dev_major)
    {
        ret=register_chrdev_region(devno, 1, "globalvar");
    }
    else
    {
        ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar");
        dev_major=MAJOR(devno);
    }
    if(ret<0)
    {
        printk("globalvar register failure!\n");
        globalvar_exit();               //如果注册设备号失败就退出。这个有问题?
        return ret;
    }
    else
    {
        printk("globalvar register success!\n");
    }

    //为设备分配内核空间
    my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL);
    if(!my_dev)
    {
        ret=-ENOMEM;
        printk("create device failed!\n");
    }
    else       //初始化设备,添加设备
    {
        my_dev->global_var=0;            //设备变量初始化为0
        sema_init(&my_dev->sem, 1);      //初始化信号量
        cdev_init(&my_dev->cdev, &globalvar_fos);  //初始化设备中的cdev结构
        my_dev->cdev.owner=THIS_MODULE;     //初始化cdev中的所有者字段
        //向内核添加cdev结构,注意到此时用到了devno
        err=cdev_add(&my_dev->cdev, devno, 1);
        if(err<0)        //如果添加字符设备失败,打印错误信息
            printk("add charater device failure!\n");
        else
            printk("add charater device success!\n");
    }
    return ret;
}

//打开操作
int globalvar_open(struct inode *inode, struct file *filp)
{
    struct globalvar_dev *dev;
    //根据inode结构的cdev字段,获得整个设备结构的指针
    dev=container_of(inode->i_cdev, struct globalvar_dev, cdev);
    //分配并填写置于filp->private_data里的数据结构,private_data是跨系统调用时
    //保存状态信息的非常有用的资源    
    filp->private_data=dev;
    return 0;
}

//释放操作
int globalvar_release(struct inode *inode, struct file *filp)
{
    //为什么不释放filp->private_data???
    return 0;
}

//读操作
ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
    int random_int, random_int_msec;
    struct globalvar_dev *dev=filp->private_data;   //获取已指向分配数据的指针
    //获取信号量
    if(down_interruptible(&dev->sem))
        return -ERESTARTSYS;
    //将设备变量值复制到用户空间
    if(copy_to_user(buf, &dev->global_var, sizeof(int)))
        return -EFAULT;
    //获取一个随机整数
    get_random_bytes(&random_int, sizeof(int));
    random_int_msec=random_int%500+500;
    printk("random_int_msec is %d.\n",random_int_msec);
    //让进程忙等待随机时间,模拟设备忙
    mdelay(random_int_msec);
    //释放信号量
    up(&dev->sem);
    return sizeof(int);     //返回读取数据字节数
}

//写操作
ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
    struct globalvar_dev *dev=filp->private_data;   //获取已指向分配数据的指针
    //将用户空间值复制到设备变量
    if(copy_from_user(&dev->global_var, buf, sizeof(int)))
        return -EFAULT;
    return sizeof(int);
}

module_init(globalvar_init);
module_exit(globalvar_exit);

2. 编写测试程序,代码如下:

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

extern int errno;

int main(void)
{
    pid_t i, child;

    for(i=0;i<5;i++)
    {
        child=fork();
        if(child==0||child==-1)break;
    }

    //进程创建错误
    if(child==-1)
    {
        printf("Fork error:%s.\n",strerror(errno));
        return -1;
    }
    else if(child==0)  //子进程
    {
        int fd, j, num=3;

        //只读方式打开设备
        fd=open("/dev/globalvar", O_RDONLY, S_IRWXU|S_IRWXG);
        if(fd==-1)
        {
            printf("Device open failure!\n");
            return -1;
        }
        for(j=0;j<20;j++)
        {
            if(read(fd, &num, sizeof(int))==-1)        //读取设备变量
                printf("Child process NO.%d error:%s.\n", getpid(), strerror(errno));
            else
                printf("Child process NO.%d:The globalvar is %d.\n", getpid(), num);
        }
        close(fd);     //关闭设备文件
    }
    else     //父进程
    {
        int fd, j, num=3;

        //只读方式打开设备
        fd=open("/dev/globalvar", O_RDONLY, S_IRWXU|S_IRWXG);
        if(fd==-1)
        {
            printf("Device open failure!\n");
            return -1;
        }
        for(j=0;j<20;j++)
        {
            if(read(fd, &num, sizeof(int))==-1)        //读取设备变量
                printf("Parent process NO.%d error:%s.\n", getpid(), strerror(errno));
            else
                printf("Parent process NO.%d:The globalvar is %d.\n", getpid(), num);
        }
        close(fd);     //关闭设备文件
    }
    
    return 0;
}

3. 运行结果

  1 Parent process NO.2492:The globalvar is 0.
  2 Child process NO.2496:The globalvar is 0.
  3 Child process NO.2497:The globalvar is 0.
  4 Child process NO.2494:The globalvar is 0.
  5 Child process NO.2495:The globalvar is 0.
  6 Child process NO.2493:The globalvar is 0.
  7 Parent process NO.2492:The globalvar is 0.
  8 Child process NO.2496:The globalvar is 0.
  9 Child process NO.2497:The globalvar is 0.
 10 Child process NO.2494:The globalvar is 0.
 11 Child process NO.2495:The globalvar is 0.
 12 Child process NO.2493:The globalvar is 0.
 13 Parent process NO.2492:The globalvar is 0.
 14 Child process NO.2496:The globalvar is 0.
 15 Child process NO.2497:The globalvar is 0.
 16 Child process NO.2494:The globalvar is 0.
 17 Child process NO.2495:The globalvar is 0.
 18 Child process NO.2493:The globalvar is 0.
 19 Parent process NO.2492:The globalvar is 0.
 20 Child process NO.2496:The globalvar is 0.
 21 Child process NO.2497:The globalvar is 0.
 22 Child process NO.2494:The globalvar is 0.
 23 Child process NO.2495:The globalvar is 0.
 24 Child process NO.2493:The globalvar is 0.
 25 Parent process NO.2492:The globalvar is 0.
 26 Child process NO.2496:The globalvar is 0.
 27 Child process NO.2497:The globalvar is 0.
 28 Child process NO.2494:The globalvar is 0.
 29 Child process NO.2495:The globalvar is 0.
 30 Child process NO.2493:The globalvar is 0.
 31 Parent process NO.2492:The globalvar is 0.
 32 Child process NO.2496:The globalvar is 0.
 33 Child process NO.2497:The globalvar is 0.
 34 Child process NO.2494:The globalvar is 0.
 35 Child process NO.2495:The globalvar is 0.
 36 Child process NO.2493:The globalvar is 0.
 37 Parent process NO.2492:The globalvar is 0.
 38 Child process NO.2496:The globalvar is 0.
 39 Child process NO.2497:The globalvar is 0.
 40 Child process NO.2494:The globalvar is 0.
 41 Child process NO.2495:The globalvar is 0.
 42 Child process NO.2493:The globalvar is 0.
 43 Parent process NO.2492:The globalvar is 0.
 44 Child process NO.2496:The globalvar is 0.
 45 Child process NO.2497:The globalvar is 0.
 46 Child process NO.2494:The globalvar is 0.
 47 Child process NO.2495:The globalvar is 0.
 48 Child process NO.2493:The globalvar is 0.
 49 Parent process NO.2492:The globalvar is 0.
 50 Child process NO.2496:The globalvar is 0.
 51 Child process NO.2497:The globalvar is 0.
 52 Child process NO.2494:The globalvar is 0.
 53 Child process NO.2495:The globalvar is 0.
 54 Child process NO.2493:The globalvar is 0.
 55 Parent process NO.2492:The globalvar is 0.
 56 Child process NO.2496:The globalvar is 0.
 57 Child process NO.2497:The globalvar is 0.
 58 Child process NO.2494:The globalvar is 0.
 59 Child process NO.2495:The globalvar is 0.
 60 Child process NO.2493:The globalvar is 0.
 61 Parent process NO.2492:The globalvar is 0.
 62 Child process NO.2496:The globalvar is 0.
 63 Child process NO.2497:The globalvar is 0.
 64 Child process NO.2494:The globalvar is 0.
 65 Child process NO.2495:The globalvar is 0.
 66 Child process NO.2493:The globalvar is 0.
 67 Parent process NO.2492:The globalvar is 0.
 68 Child process NO.2496:The globalvar is 0.
 69 Child process NO.2497:The globalvar is 0.
 70 Child process NO.2494:The globalvar is 0.
 71 Child process NO.2495:The globalvar is 0.
 72 Child process NO.2493:The globalvar is 0.
 73 Parent process NO.2492:The globalvar is 0.
 74 Child process NO.2496:The globalvar is 0.
 75 Child process NO.2497:The globalvar is 0.
 76 Child process NO.2494:The globalvar is 0.
 77 Child process NO.2495:The globalvar is 0.
 78 Child process NO.2493:The globalvar is 0.
 79 Parent process NO.2492:The globalvar is 0.
 80 Child process NO.2496:The globalvar is 0.
 81 Child process NO.2497:The globalvar is 0.
 82 Child process NO.2494:The globalvar is 0.
 83 Child process NO.2495:The globalvar is 0.
 84 Child process NO.2493:The globalvar is 0.
 85 Parent process NO.2492:The globalvar is 0.
 86 Child process NO.2496:The globalvar is 0.
 87 Child process NO.2497:The globalvar is 0.
 88 Child process NO.2494:The globalvar is 0.
 89 Child process NO.2495:The globalvar is 0.
 90 Child process NO.2493:The globalvar is 0.
 91 Parent process NO.2492:The globalvar is 0.
 92 Child process NO.2496:The globalvar is 0.
 93 Child process NO.2497:The globalvar is 0.
 94 Child process NO.2494:The globalvar is 0.
 95 Child process NO.2495:The globalvar is 0.
 96 Child process NO.2493:The globalvar is 0.
 97 Parent process NO.2492:The globalvar is 0.
 98 Child process NO.2496:The globalvar is 0.
 99 Child process NO.2497:The globalvar is 0.
100 Child process NO.2494:The globalvar is 0.
101 Child process NO.2495:The globalvar is 0.
102 Child process NO.2493:The globalvar is 0.
103 Parent process NO.2492:The globalvar is 0.
104 Child process NO.2496:The globalvar is 0.
105 Child process NO.2497:The globalvar is 0.
106 Child process NO.2494:The globalvar is 0.
107 Child process NO.2495:The globalvar is 0.
108 Child process NO.2493:The globalvar is 0.
109 Parent process NO.2492:The globalvar is 0.
110 Child process NO.2496:The globalvar is 0.
111 Child process NO.2497:The globalvar is 0.
112 Child process NO.2494:The globalvar is 0.
113 Child process NO.2495:The globalvar is 0.
114 Child process NO.2493:The globalvar is 0.
115 Parent process NO.2492:The globalvar is 0.
116 Child process NO.2496:The globalvar is 0.
117 Child process NO.2497:The globalvar is 0.
118 Child process NO.2494:The globalvar is 0.
119 Child process NO.2495:The globalvar is 0.
120 Child process NO.2493:The globalvar is 0.

这让我很困惑,为什么没有发生竞争现象?