Chinaunix首页 | 论坛 | 博客
  • 博客访问: 316098
  • 博文数量: 101
  • 博客积分: 2428
  • 博客等级: 大尉
  • 技术积分: 1050
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-24 13:16
文章分类

全部博文(101)

文章存档

2012年(3)

2011年(90)

2010年(8)

分类: LINUX

2011-04-27 14:25:13

7.1并发引起竞态;多个中断也可能引发并发而导致竞态;解决竞争的途径是对共享资源的互斥访问;
7.2中断屏蔽
中断屏蔽使得中断与进程之间并发不在发生,内核抢占进程之间的并发也可以避免。
Local_irq_disable()
。。。。
。。。
。。。。
Local_irq_enable()
只能禁止本cpu的中断。不能解决SMP引发的竞态。。
单独使用中断屏蔽不是一个好方法,它适合和自旋锁使用。
Local_irq_save()
Local_irq_restore()
Local_bh_disable()
Local_bh_enable();
7.3原子操作
声明原子变量,然后利用它来控制进程的执行。
Static atomic_t  xxx_available=ATOMIC_INIT ();//定义原子变量
Static int xxx_open(struct inode *inode,struct file *filp)
{
….
If(!atomic_dec_and_test(&xxx_available)
{atomic_inc(&xxx-available);
Return -EBUSY;
}
….
Return 0;
}
Static int xxx_release(struct inode *inode,struct file *filp)
{
Atomic_inc(&xxx_available);
Return 0;
}
7.4自旋锁
为了获得自旋锁,在某cpu上运行的代码先执行一个原子操作。
把他当做变量看待。
自旋锁的使用范例:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);//获取自旋锁
..../
spin_unlock(&lock);//释放自旋

还有一些自旋锁的衍生的函数。。可以使用。。。。。
使用自旋锁会降低系统的性能。
自旋锁可能导致系统死锁。原因:递归调用一个自旋锁。自旋锁占用期间不要调用会引起阻塞的函数。。
7.4.2读写自旋锁
可以同时有多个读,但只能有一个写进程;同时读和写不能同时进行。
例子:
rwlock_t lock;//define a rwlock
rwlock_init(&lock);//初始化rwlock
//读取获取锁
read_lock(&lock);
..../
read_unlock(&lock);
//写获取锁
write_lock_irqsave(&lock,flags);
...
...
write_unlock_irqrestore(&lock,flags);

7.5信号量
信号量与自旋锁相识,但信号量获取不到时不会原地打转,而是进入休眠状态。。。。
1定义信号量
struct semaphore sem;
2初始化信号量
void sema_init(struct semaphore *sem,int val);
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);
声明与定义:
DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);
3获取信号量
void down(struct semaphore *sem)
int down_interruptible(struct semaphore *sem)
int_trylock(struct semaphore *sem)
4释放信号量
void up(struc semaphore *sem)
例子:
DECLARE_MUTEX(mutex_sem)
down(&mutex_sem);
...
critical section
...
up(&mutex_sem);

7.5.2 信号量被初始化为0,它可以用于同步操作
7.5.3完成量用于同步
struct completion my_completion;
init_completion(&my_completion);//DECLARE_COMPLETION(my_completion);
void wait_for_completion(struct completion *c);
唤醒完成量:
void complete(struct completion *c);
void complete_all(struct completion *c);
7.5.4自旋锁VS信号量
选择的依据是临界区的性质和系统的特点:
在多cpu中需要自旋锁来互斥。
信号量是进初级的,进程休眠带来上下文切换,只有当进程占用的时间比较长的时候,用信号量才是一个比较好的选择。
当要保护的临界区访问时间比较短的时候,用自旋锁是非常方便的。因为自旋锁一直占用cpu,所以等待的时间越短越好。
信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁要绝对要避免用来保护包含这样代码的临界区。
信号量运行于进程上下文。
7.5.5读写信号量
例子:
rw_semaphore rw_sem;
init_rwsem(&rw_sem);
down_read(&rw_sem);
...
...
up_read(&rw_sem);
down_write(&rw_sem);
...
...
up_write(&rw_sem);
7.6互斥体
例子:
struct mutex my_mutex;
mutex_init(&my_mutex);
mutex_lock(&my_mutex);
.../
mutex_unlock(&my_lock);

增加并发控制的globalmem驱动:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GLOBALMEM_SIZE 0x1000 /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define GLOBALMEM_MAJOR 254    /*预设的globalmem的主设备号*/
static globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
struct globalmem_dev                                    
{                                                       
  struct cdev cdev; /*cdev结构体*/                      
  unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/    
  struct semaphore sem; /*并发控制用的信号量*/   
};
struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
/*文件打开函数*/
int globalmem_open(struct inode *inode, struct file *filp)
{
  /*将设备结构体指针赋值给文件私有数据指针*/
  filp->private_data = globalmem_devp;
  return 0;
}
/*文件释放函数*/
int globalmem_release(struct inode *inode, struct file *filp)
{
  return 0;
}
/* ioctl设备控制函数 */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
  int cmd, unsigned long arg)
{
  struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  switch (cmd)
  {
    case MEM_CLEAR:
      if (down_interruptible(&dev->sem))
      {
        return  - ERESTARTSYS;
      }
      memset(dev->mem, 0, GLOBALMEM_SIZE);
      up(&dev->sem); //释放信号量
      printk(KERN_INFO "globalmem is set to zero\n");
      break;
    default:
      return  - EINVAL;
  }
  return 0;
}
/*读函数*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
  loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  /*分析和获取有效的写长度*/
  if (p >= GLOBALMEM_SIZE)
    return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;
  if (down_interruptible(&dev->sem))
  {
    return  - ERESTARTSYS;
  }
  /*内核空间->用户空间*/
  if (copy_to_user(buf, (void*)(dev->mem + p), count))
  {
    ret =  - EFAULT;
  }
  else
  {
    *ppos += count;
    ret = count;
    printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  }
  up(&dev->sem); //释放信号量
  return ret;
}
/*写函数*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
  size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  /*分析和获取有效的写长度*/
  if (p >= GLOBALMEM_SIZE)
    return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;
  if (down_interruptible(&dev->sem))//获得信号量
  {
    return  - ERESTARTSYS;
  }
  /*用户空间->内核空间*/
  if (copy_from_user(dev->mem + p, buf, count))
    ret =  - EFAULT;
  else
  {
    *ppos += count;
    ret = count;
    printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  }
  up(&dev->sem); //释放信号量
  return ret;
}
/* seek文件定位函数 */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
  loff_t ret = 0;
  switch (orig)
  {
    case 0:   /*相对文件开始位置偏移*/
      if (offset < 0)
      {
        ret =  - EINVAL;
        break;
      }
      if ((unsigned int)offset > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos = (unsigned int)offset;
      ret = filp->f_pos;
      break;
    case 1:   /*相对文件当前位置偏移*/
      if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      if ((filp->f_pos + offset) < 0)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos += offset;
      ret = filp->f_pos;
      break;
    default:
      ret =  - EINVAL;
      break;
  }
  return ret;
}
/*文件操作结构体*/
static const struct file_operations globalmem_fops =
{
  .owner = THIS_MODULE,
  .llseek = globalmem_llseek,
  .read = globalmem_read,
  .write = globalmem_write,
  .ioctl = globalmem_ioctl,
  .open = globalmem_open,
  .release = globalmem_release,
};
/*初始化并注册cdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
  int err, devno = MKDEV(globalmem_major, index);
  cdev_init(&dev->cdev, &globalmem_fops);
  dev->cdev.owner = THIS_MODULE;
  dev->cdev.ops = &globalmem_fops;
  err = cdev_add(&dev->cdev, devno, 1);
  if (err)
    printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}
/*设备驱动模块加载函数*/
int globalmem_init(void)
{
  int result;
  dev_t devno = MKDEV(globalmem_major, 0);
  /* 申请设备号*/
  if (globalmem_major)
    result = register_chrdev_region(devno, 1, "globalmem");
  else  /* 动态申请设备号 */
  {
    result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
    globalmem_major = MAJOR(devno);
  } 
  if (result < 0)
    return result;
   
  /* 动态申请设备结构体的内存*/
  globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
  if (!globalmem_devp)    /*申请失败*/
  {
    result =  - ENOMEM;
    goto fail_malloc;
  }
  memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
 
  globalmem_setup_cdev(globalmem_devp, 0);
  init_MUTEX(&globalfifo_devp->sem);   /*初始化信号量*/ 
  return 0;
  fail_malloc: unregister_chrdev_region(devno, 1);
  return result;
}
/*模块卸载函数*/
void globalmem_exit(void)
{
  cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
  kfree(globalmem_devp);     /*释放设备结构体内存*/
  unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
}
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);
 

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