Chinaunix首页 | 论坛 | 博客
  • 博客访问: 521796
  • 博文数量: 56
  • 博客积分: 1136
  • 博客等级: 少尉
  • 技术积分: 1378
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-28 14:02
文章存档

2014年(1)

2013年(7)

2012年(45)

2011年(3)

分类: 嵌入式

2012-08-03 11:26:09

信号量

 

信号量定义代码如下:(include/linux/semaphore.h文件中定义了信号量及有关操作)

struct semaphore {

    spinlock_t    lock;

    unsigned int      count;

    struct list_head  wait_list;

};

 

#define __SEMAPHORE_INITIALIZER(name, n)             \

{                               \

    .lock      = __SPIN_LOCK_UNLOCKED((name).lock),       \

    .count     = n,                     \

    .wait_list = LIST_HEAD_INIT((name).wait_list),       \

}

 

#define   \

    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

 

static inline void sema_init(struct semaphore *sem, int val)

{

    static struct lock_class_key __key;

    *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);

    lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);

}

extern void down(struct semaphore *sem);//获得信号量/*不推荐使用,会建立不可杀进程*/

struct semaphore *sem);

extern int __must_check down_killable(struct semaphore *sem);

extern int __must_check down_trylock(struct semaphore *sem);

extern int __must_check down_timeout(struct semaphore *sem, long jiffies);

extern void up(struct semaphore *sem);//释放信号量

//老版本的内核还提供以下宏来操作信号,新版本(2.6.39.3)中这些宏已删掉了

#define init_MUTEX(sem)         sema_init(sem, 1)

#define init_MUTEX_LOCKED(sem)  sema_init(sem, 0)

 

#define DECLARE_MUTEX(name)     \

         struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

 

//驱动程序中可按如下方式使用信号量,当执行单无执行到Down(semname);函数处时,//会比较的值是否大于1,如果大于1就进行临界区,并把semname的值减1//如果此时,有另一个执行单元B执行此处,它也会比较semname的值是否大于1

//由于semname初值为1,已进行了一次down操作,所以此时semname0,则执行

//单元B不能进入临界区,需要等待上一个执行单元释放该信号量,才能进入临界区

 

#include.h>

DEFINE_SEMAPHORE();

Down(semname);

//临界区

Up(semname);

//使用示例如下:

#include

#include

#include

#include

#include

#include

#include

 

#define DEV_MAJOR 251

 

struct cheney_cdev{

    struct cdev cdev;

    int a;

    struct semaphore sema;

};

 

static struct cheney_cdev *dev;

static int cdev_major = DEV_MAJOR;

 

static int cheney_cdev_open(struct inode *inode,struct file *filp){

    struct cheney_cdev *dev;

    dev=container_of(inode->i_cdev,struct cheney_cdev,cdev);

    filp->private_data=dev;

    return 0;

}

   

 

static ssize_t cheney_cdev_read(struct file *filp,char __user *buf, size_t count ,loff_t *ppos)

{

    struct cheney_cdev *dev=filp->private_data;

    if(down_interruptible(&dev->sema))

        return -1;

    copy_to_user(buf,&dev->a,sizeof(int));

    up(&dev->sema);

    return count;

}

 

static ssize_t cheney_cdev_write(struct file *filp,const char __user *buf,size_t count ,loff_t *ppos )

{

    struct cheney_cdev *dev=filp->private_data;

    if(down_interruptible(&dev->sema))

        return -1;

    copy_from_user(&dev->a,buf,sizeof(int));

    up(&dev->sema);

    return 0;

}

 

static struct file_operations cdev_fops={

    .owner = THIS_MODULE,

    .open = cheney_cdev_open,

    .write = cheney_cdev_write,

    .read = cheney_cdev_read,

};

 

static cdev_setup(struct cheney_cdev *dev,int index)

{

    int result;

    dev_t devo=MKDEV(cdev_major,index);

    cdev_init(&dev->cdev,&cdev_fops);

    dev->cdev.owner= THIS_MODULE;

    result=cdev_add(&dev->cdev,devo,1);

    sema_init(&dev->sema,1);

 

    if(result <0)

        printk("cdev %d add error \n",index);

}

 

static int hello_init()

{

    int result;

    dev_t devno=MKDEV(cdev_major,0);

    if( (result=register_chrdev_region(devno,2,"cheney_cdev") )<0){

        printk("get cdev major erro\n");

        goto err1;

    }

    dev=kmalloc(2*sizeof(struct cheney_cdev),GFP_KERNEL);

    if(!dev)

        printk("kmalloc error \n");

    memset(dev,0,2*sizeof(struct cheney_cdev));

        

    cdev_setup(&dev[0],0);

    cdev_setup(&dev[1],1);

 

    printk("hello cheney module \n");

 

err1:    return 0;

}

 

static void hello_exit()

{

    cdev_del(&dev[0].cdev);

    cdev_del(&dev[1].cdev);

    kfree(dev);

    unregister_chrdev_region(MKDEV(cdev_major,0),2);

    printk("cheney module exit");

}

 

module_init(hello_init);

module_exit(hello_exit);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Cheney.Xu ");

MODULE_DESCRIPTION("a simple moule example");

 

测试cat /proc/devices显示系统中已占用的设备号

251 cheney_cdev

#insmod hello-cdev.ko

#mknod /dev/cheney_cdev c 251 0

#mknod /dev/cheney_cdev1 c 251 1

./test

12

The Num1 = 12

54

The Num1 = 54

#include

#include

#include

#define DEV_NAME "/dev/cheney_cdev"

#define DEV_NAME1 "/dev/cheney_cdev1"

int main()

{

    int fd,fd1,num,num1;

    fd = open(DEV_NAME,O_RDWR);

    if(fd<0)

        printf("open error \n");

    scanf("%d",&num);

    write(fd,&num,sizeof(int));

    read(fd,&num1,sizeof(int));

    printf("The Num1 = %d \n",num1);

    close(fd);

   

    fd1 = open(DEV_NAME1,O_RDWR);

    if(fd<0)

        printf("open error \n");

    scanf("%d",&num);

    write(fd1,&num,sizeof(int));

    read(fd1,&num1,sizeof(int));

    printf("The Num1 = %d \n",num1);

    close(fd1);

}

 

 

如果一个执行单元A,定义一个信号量,并将信号量初始化为0时,则意为着需要执行单元B执行一次UP操作时,执行单元A才能向下执行,这种方式通常用于同步操作,也就是一个执行单元继续执行需要等待另一个执行单元完成某事,这样可以保证执行的先后次序

extern int __must_check down_interruptible(struct semaphore *sem); /*推荐使用,使用down_interruptible需要格外小心,若操作被中断,该函数会返回非零值,而调用这不会拥有该信号量。对down_interruptible的正确使用需要始终检查返回值,并做出相应的响应。*/

extern int __must_check down_killable(struct semaphore *sem);

extern int __must_check _trylock(struct semaphore *sem); /*down _trylock”的永不休眠,若信号量在调用是不可获得,会返回非零值。*/

extern int __must_check down_timeout(struct semaphore *sem, long jiffies);

 

互斥体

Include/linux/mutex.h

struct mutex {

    /* 1: unlocked, 0: locked, negative: locked, possible waiters */

    atomic_t      count;

    spinlock_t    wait_lock;

    struct list_head  wait_list;

#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)

    struct thread_info   *owner;

#endif

#ifdef CONFIG_DEBUG_MUTEXES

    const char        *name;

    void          *magic;

#endif

#ifdef CONFIG_DEBUG_LOCK_ALLOC

    struct lockdep_map   dep_map;

#endif

};

 

#define __MUTEX_INITIALIZER(lockname) \

       { .count = ATOMIC_INIT(1) \

       , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \

       , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \

       __DEBUG_MUTEX_INITIALIZER(lockname) \

       __DEP_MAP_MUTEX_INITIALIZER(lockname) }

 

# define mutex_init(mutex) \

do {                        \

    static struct lock_class_key __key;       \

                         \

    __mutex_init((mutex), #mutex, &__key);    \

} while (0)

extern void __mutex_init(struct mutex *lock, const char *name,

            struct lock_class_key *key);

 

#define \

    struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)

 

extern void struct mutex *lock);

extern int __must_check mutex_lock_interruptible(struct mutex *lock);

extern int __must_check mutex_lock_killable(struct mutex *lock);

 

extern int mutex_trylock(struct mutex *lock);

extern void mutex_unlock(struct mutex *lock);

extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);

 

互斥体使用方法如下:

#include/mutex.h>

DEFINE_MUTEX();

mutex_lock(mutexname);

//临界区

mutex_unlock(mutexname);

//使用示例如下

#include

#include

#include

#include

#include

#include

#include

 

#define DEV_MAJOR 251

 

struct cheney_cdev{

    struct cdev cdev;

    int a;

    struct mutex my_mutex;

    int open_count;

};

 

static struct cheney_cdev *dev;

static int cdev_major = DEV_MAJOR;

 

static int cheney_cdev_open(struct inode *inode,struct file *filp){

    struct cheney_cdev *dev;

    dev=container_of(inode->i_cdev,struct cheney_cdev,cdev);

    filp->private_data=dev;

 

    mutex_lock(&dev->my_mutex);

    if(dev->open_count)

        return -1;

    ++dev->open_count;

    mutex_unlock(&dev->my_mutex);

 

    return 0;

}

 

static int cheney_cdev_release(struct inode *inode,struct file *filp){

    struct cheney_cdev *dev;

    dev=container_of(inode->i_cdev,struct cheney_cdev,cdev);

    mutex_lock(&dev->my_mutex);

    --(dev->open_count);

    mutex_unlock(&dev->my_mutex);

    return 0;

}

  

 

static ssize_t cheney_cdev_read(struct file *filp,char __user *buf, size_t count ,loff_t *ppos)

{

    struct cheney_cdev *dev=filp->private_data;

    copy_to_user(buf,&dev->a,sizeof(int));

    return count;

}

 

static ssize_t cheney_cdev_write(struct file *filp,const char __user *buf,size_t count ,loff_t *ppos )

{

    struct cheney_cdev *dev=filp->private_data;

    copy_from_user(&dev->a,buf,sizeof(int));

    return 0;

}

 

static struct file_operations cdev_fops={

    .owner = THIS_MODULE,

    .open = cheney_cdev_open,

    .write = cheney_cdev_write,

    .read = cheney_cdev_read,

};

 

static cdev_setup(struct cheney_cdev *dev,int index)

{

    int result;

    dev_t devo=MKDEV(cdev_major,index);

    cdev_init(&dev->cdev,&cdev_fops);

    dev->cdev.owner= THIS_MODULE;

    result=cdev_add(&dev->cdev,devo,1);

    mutex_init(&dev->my_mutex);

    dev->open_count =0;

    if(result <0)

        printk("cdev %d add error \n",index);

}

 

static int hello_init()

{

    int result;

    dev_t devno=MKDEV(cdev_major,0);

    if( (result=register_chrdev_region(devno,2,"cheney_cdev") )<0){

        printk("get cdev major erro\n");

        goto err1;

    }

    dev=kmalloc(2*sizeof(struct cheney_cdev),GFP_KERNEL);

    if(!dev)

        printk("kmalloc error \n");

    memset(dev,0,2*sizeof(struct cheney_cdev));

        

    cdev_setup(&dev[0],0);

    cdev_setup(&dev[1],1);

 

    printk("hello cheney module \n");

 

err1:    return 0;

}

 

static void hello_exit()

{

    cdev_del(&dev[0].cdev);

    cdev_del(&dev[1].cdev);

    kfree(dev);

    unregister_chrdev_region(MKDEV(cdev_major,0),2);

    printk("cheney module exit");

}

 

module_init(hello_init);

module_exit(hello_exit);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Cheney.Xu ");

MODULE_DESCRIPTION("a simple moule example");

 

#insmod hello-cdev.ko

# ./test

65

The Num1 = 65

21

The Num1 = 21

测试代码同上

 

 

阅读(2764) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~