分类: 嵌入式
2013-03-09 14:56:15
信号量
信号量定义代码如下:(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操作,所以此时semname为0,则执行 //单元B不能进入临界区,需要等待上一个执行单元释放该信号量,才能进入临界区
|
#include 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 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 |
测试代码同上 |