Linux内核之内核锁

 

 1.内核定时器:
 未来的某个时间点执行提前设置的某个任务函数。

 涉及到的核心头文件:
 #include <linux/timer.h>

 涉及到的结构体:
 struct timer_list {
  /*
   * All fields that change during normal runtime grouped to the
   * same cacheline
   */
  struct list_head entry;
  unsigned long expires;    //未来的定时时间点,参考时间是jiffies
  struct tvec_base *base;
 
  void (*function)(unsigned long); //定时到达时要执行的处理函数
  unsigned long data;              //定时处理函数需要的参数
 
  int slack;
 
 #ifdef CONFIG_TIMER_STATS
  int start_pid;
  void *start_site;
  char start_comm[16];
 #endif
 #ifdef CONFIG_LOCKDEP
  struct lockdep_map lockdep_map;
 #endif
 };

 使用步骤:

 1. 实例化定时器对象
 方法1,
  struct timer_list timer;
  init_timer(&timer);

  timer.expires = jiffies + xxx;
  timer.function = service_timer;
  timer.data = (unsigned long)dev;
 
 方法2,
  struct timer_list timer;
  setup_timer(&timer, service_timer, (unsigned long)dev);
  timer.expires = jiffies + xxx;

 方法3,
  DEFINE_TIMER(timer, service_timer, jiffies + xxx, (unsigned long)dev);

 2. 向内核注册定时器并启动
  add_timer(&timer);
 3. 如果需要(周期性的来定时)
  mod_timer(&timer, jiffies + xx);
 4. 在驱动模块的出口移除定时器
  //在对称多处理器对应的系统中使用
  del_timer_sync(&timer);
  //单核使用
  del_timer(&timer); 

  2.杂项设备驱动(misc)的方法注册字符设备驱动

 本质上misc驱动也是一个字符设备驱动,可能相对特殊一点而已。在drivers/char/misc.c的misc驱动初始化函数
 misc_init()中实际上使用了MISC_MAJOR(主设备号为10)并调用register_chrdev()去注册了一个字符设备驱动。
 同时也创建了一个misc_class,使得最后可自动在/dev下自动生成一个主设备号为10的字符设备。总的来讲,如果
 使用misc驱动可以满足要求的话,那么这可以为开发人员剩下不少麻烦。

 使用杂项设备的优点:

 第一,节省主设备号:
 使用普通字符设备,不管该驱动的主设备号是静态还是动态分配,都会消耗一个主设备号.而且如果你的这个驱动最
 终会提交到内核主线版本上的话,需要申请一个专门主设备号。如用misc驱动的话就好多了。因为内核中已经为misc
 驱动分配了一个主设备号。当系统中拥有多个misc设备驱动时,那么它们的主设备号相同,而用子设备号来区分

 第二,使用简单:
 有时候需要一个功能较简单的字符设备驱动,导出接口让用户空间程序方便地控制硬件,只需要使用misc子系统提供
 的接口即可快速地创建一个misc设备驱动。当使用普通的字符设备驱动时,如果开发人员需要导出操作接口给用户空
 间的话,需要自己去注册字符驱动,并创建字符设备class以自动在/dev下生成设备节点,相对麻烦一点。而misc驱动
 则无需考虑这些,基本上只需要把一些基本信息通过struct miscdevice交给misc_register()去处理即可。

 涉及头文件:
 #include <linux/miscdevice.h>

 一个杂项设备对应的结构类型:
 struct miscdevice  {
  int minor;      //次设备号
  const char *name; //设备名称
  const struct file_operations *fops; //驱动函数集
  struct list_head list;
  struct device *parent;
  struct device *this_device;
  const char *nodename;
  umode_t mode;
 };

 注册步骤:
 1. 实现驱动函数集
 struct file_operations fops = {
  xxx;
  ...
 };   
 2. 实例化杂项设备对象 
 struct miscdevice misc = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "hehe",
  .fops = &fops;
 }; 
 3. 注册 
    misc_register(&misc); 

 current 是全局的一个宏,用其可以获得当前进程的信息.在内核,一个进程用一个struct task_struct
 的结构体对象描述。
 
 内核会为每个进程分配8K的栈,在8K栈的低地址出放有一个struct
 thread_info的一个对象, 而这个对象内部又有一个struct task_struct 的
 一个指针变量task,task指向当前的进程结构体对象。

=======================================================================================================
2015年11月16日

内容:

互斥量(线程锁):
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

pthread_mutex_lock(&mutex);
pthread_mutex_trylock(&mutex);

pthread_mutex_unlock(&mutex);

自旋锁:

pthread_spin_t spin;

pthread_spin_init(&spin, 0);

pthread_spin_lock(&spin);
pthread_spin_trylock(&spin);

pthread_spin_unlock(&spin);

加锁一定要避免死锁:
常见的死锁有:
 
 1. ABBA
 2. 进程自己递归加锁


加锁的力度:
 不能太大,太大有可能起不到保护作用;会降低程序的执行效率。
 加锁是一种工程师的自愿工作,如果要加锁,一开始就要考虑。

kernel:

解决竞争实现同步的机制:

1. 原子操作: 
 int i = 2; /*global*/

 A process     B process

 //i++;  i++;

 ldr r0,[r1]   ldr r0,[r1]
 add r0,#1     add r0,#1
 str r0,[r1]   str r0,[r1]

 i = 3;  i = 4; 
  
原子变量替换整形变量。

原子变量:
 //int i = 2;
 atomic_t v = ATOMIC_INIT(2);

原子操作函数接口:

 //i += 3;
 atomic_add(3, &v);

 atomic_add_return();
 atomic_add_negative();

 atomic_inc();
 atomic_inc_and_test();
 atomic_inc_return();

2. 信号量

 信号量属于睡眠锁,可以指定锁的持有者的个数。

 实例化:
 struct semaphore sema;

 初始化:
 sema_init(&sema, 1);

 加锁解锁:
 down()/up();

 如果当前进程获得信号量暂时拿不到,睡。
 
3. 互斥量

 睡眠锁
 struct mutex;
 使用互斥量锁的步骤:

 实例化:
 struct mutex mutex;

 初始化:
 mutex_init(&mutex); 

 加锁/解锁
 mutex_lock(&mutex);/mutex_unlock(&mutex);

4. 自旋锁

 非睡眠锁

 实例化:
 spinlock_t spin;

 初始化:
 spin_lock_init(&spin);

 加锁:
 //进程和进程
 spin_lock(&spin);
 spin_unlock(&spin);

 //进程和进程,进程和中断处理函数的竞争
 spin_lock_irqsave();
 spin_unlock_irqrestore();

 spin_lock_bh();
 spin_unlock_bh();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值