信号量机制:

struct sempahore是其结构,定义如下
  1. struct semaphore {
  2. atomic_t count;//资源数目
  3. int sleepers;//等待进程数目
  4. wait_queue_head_t wait;//等待队列
  5. #if WAITQUEUE_DEBUG
  6. long __magic;
  7. #endif
  8. };

down操作成功(减后结果非负数)那就在标号1处结束down操作,转到临界区.
如果减为负数,跳转到2标号,并且调用call_down_failed,进入睡眠,一直要到唤醒并拿到资源才返回跳转到1标号,结束down操作进入临界区
  1. /*
  2. * This is ugly, but we want the default case to fall through.
  3. * "__down_failed" is a special asm handler that calls the C
  4. * routine that actually waits. See arch/i386/kernel/semaphore.c
  5. */
  6. static inline void down(struct semaphore * sem)
  7. {
  8. #if WAITQUEUE_DEBUG
  9. CHECK_MAGIC(sem->__magic);
  10. #endif
  11. __asm__ __volatile__(
  12. "# atomic down operation\n\t"
  13. LOCK "decl %0\n\t" /* --sem->count lock字段把总线锁住,防止其他cpu干扰*/
  14. "js 2f\n" /*如果小于0,那就跳转到2号*/
  15. "1:\n" /*成功拿到,从此处进入临界区*/
  16. ".section .text.lock,\"ax\"\n"
  17. "2:\tcall __down_failed\n\t" /*count--后为负值,休眠*/
  18. "jmp 1b\n"/*失败睡眠,但经过一段时间被唤醒,并且进入临界区,就跳转到1*/
  19. ".previous"
  20. :"=m" (sem->count)
  21. :"c" (sem)
  22. :"memory");
  23. }

__down_failed源码,这里的目的只是为了调用__down函数
  1. asm(
  2. ".align 4\n"
  3. ".globl __down_failed\n"
  4. "__down_failed:\n\t"
  5. "pushl %eax\n\t"
  6. "pushl %edx\n\t"
  7. "pushl %ecx\n\t"
  8. "call __down\n\t"
  9. "popl %ecx\n\t"
  10. "popl %edx\n\t"
  11. "popl %eax\n\t"
  12. "ret"
  13. );

__down将判断资源是否存在,不存在睡眠,如果被唤醒那就从等待队列删除,并且唤醒其他等待队列进程
  1. void __down(struct semaphore * sem)
  2. {
  3. struct task_struct *tsk = current;
  4. DECLARE_WAITQUEUE(wait, tsk);//wait代表tsk
  5. tsk->state = TASK_UNINTERRUPTIBLE;//设置为睡眠状态
  6. add_wait_queue_exclusive(&sem->wait, &wait);//把当前进程的等待队列元素wait加入到sem->wait等待队列队尾
  7. spin_lock_irq(&semaphore_lock);
  8. sem->sleepers++;//等待进程数目+1
  9. for (;;) {
  10. int sleepers = sem->sleepers;//禁止本地中断并获取指定的锁
  11. /*返回非0,表示进程需要等待
  12. * 假设有2个进程,进程资源已经被占用,当前进程执行down失败,跳转到这里,等待调度
  13. 结郭前一个进程归还了资源,count变为0(之前down2次为-1),sleeper-1也为0,相加等于0,于是可以进入临界区
  14. */
  15. if (!atomic_add_negative(sleepers - 1, &sem->count)) {//返回0表示可以进入临界区
  16. sem->sleepers = 0;//睡眠的进程为0,因为要唤醒这进程了
  17. break;
  18. }
  19. sem->sleepers = 1; /* 没法到临界区,那就需要阻塞,执行到这,设置为1,那就只有us - see -1 above */
  20. spin_unlock_irq(&semaphore_lock);
  21. schedule();//调度
  22. tsk->state = TASK_UNINTERRUPTIBLE;//将当前进程设置为睡眠状态
  23. spin_lock_irq(&semaphore_lock);
  24. }
  25. spin_unlock_irq(&semaphore_lock);//解锁
  26. remove_wait_queue(&sem->wait, &wait);//当前进程可以进入临界区后,从wait队列移除
  27. tsk->state = TASK_RUNNING;//设置为可执行状态
  28. wake_up(&sem->wait);//唤醒等待队列(然而等待队列很多进程依旧无法进入临界区)
  29. }
缺陷:优先级倒转,优先级高进程在外等待,在临界区的进程优先级很低,一旦优先级低的进程在临界区受阻睡眠,也得不到及时调度,优先级高进程会被拖累,解决办法:把高优先级借给进入临界区的进程

接下来分析up函数
  1. /*
  2. * Note! This is subtle. We jump to wake people up only if
  3. * the semaphore was negative (== somebody was waiting on it).
  4. * The default case (no contention) will result in NO
  5. * jumps for both down() and up().
  6. */
  7. static inline void up(struct semaphore * sem)
  8. {
  9. #if WAITQUEUE_DEBUG
  10. CHECK_MAGIC(sem->__magic);
  11. #endif
  12. __asm__ __volatile__(
  13. "# atomic up operation\n\t"
  14. LOCK "incl %0\n\t" /* ++sem->count */
  15. "jle 2f\n"//如果资源充足(也就是递增结果为正数,直接从1:跳出临界区,不用唤醒阻塞进程(应该说没有阻塞临界区的进程)
  16. "1:\n"
  17. ".section .text.lock,\"ax\"\n"
  18. "2:\tcall __up_wakeup\n\t" /*递增结果为负数或者非0值,就唤醒阻塞进程*/
  19. "jmp 1b\n"
  20. ".previous"
  21. :"=m" (sem->count)
  22. :"c" (sem)
  23. :"memory");
  24. }

__up_wakup的目的也是调用__up
  1. asm(
  2. ".align 4\n"
  3. ".globl __up_wakeup\n"
  4. "__up_wakeup:\n\t"
  5. "pushl %eax\n\t"
  6. "pushl %edx\n\t"
  7. "pushl %ecx\n\t"
  8. "call __up\n\t"
  9. "popl %ecx\n\t"
  10. "popl %edx\n\t"
  11. "popl %eax\n\t"
  12. "ret"
  13. );

  1. /*
  2. * Semaphores are implemented using a two-way counter:
  3. * The "count" variable is decremented for each process
  4. * that tries to acquire the semaphore, while the "sleeping"
  5. * variable is a count of such acquires.
  6. *
  7. * Notably, the inline "up()" and "down()" functions can
  8. * efficiently test if they need to do any extra work (up
  9. * needs to do something only if count was negative before
  10. * the increment operation.
  11. *
  12. * "sleeping" and the contention routine ordering is
  13. * protected by the semaphore spinlock.
  14. *
  15. * Note that these functions are only called when there is
  16. * contention on the lock, and as such all this is the
  17. * "non-critical" part of the whole semaphore business. The
  18. * critical part is the inline stuff in <asm/semaphore.h>
  19. * where we want to avoid any extra jumps and calls.
  20. */
  21. /*
  22. * Logic:
  23. * - only on a boundary condition do we need to care. When we go
  24. * from a negative count to a non-negative, we wake people up.
  25. * - when we go from a non-negative count to a negative do we
  26. * (a) synchronize with the "sleeper" count and (b) make sure
  27. * that we're on the wakeup list before we synchronize so that
  28. * we cannot lose wakeup events.
  29. */
  30. void __up(struct semaphore *sem)
  31. {
  32. wake_up(&sem->wait);//唤醒等待队列中的进程
  33. }
  1. #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)

  1. void __wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
  2. {
  3.     __wake_up_common(q, mode, wq_mode, 0);
  4. }

posix信号量与内核信号量概念基本一样,不过posix信号量可以用于位于内核外临界区的不同进程.而内核信号量只可以用于临界区位于内核
互斥锁(也就是mutex.一般用于线程互斥),不过可以通过设置线程锁属性用于不同进程通信,为了达到多进程共享的需要,互斥锁对象需要创建在共享内存中
文件锁用于2个进程访问一个文件
自旋锁,读写锁只可用于线程互斥
信号量分为匿名信号量与有名信号量,前一个用于线程互斥,后一个用于进程同步
大内核锁也是用来保护临界区资源,避免出现多个处理器上的进程同时访问同一区域的

linux内核情景分析之内核中的互斥操作的更多相关文章

  1. 几个常用内核函数(《Windows内核情景分析》)

    参考:<Windows内核情景分析> 0x01  ObReferenceObjectByHandle 这个函数从句柄得到对应的内核对象,并递增其引用计数. NTSTATUS ObRefer ...

  2. [1]windows 内核情景分析---说明

    本文说明:这一系列文章(笔记)是在看雪里面下载word文档,现转帖出来,希望更多的人能看到并分享,感谢原作者的分享精神. 说明 本文结合<Windows内核情景分析>(毛德操著).< ...

  3. windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数

    windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数 1.KeRaiseIrql函数 这个 KeRaiseIrql() 只是简单地调用 hal 模块的 KfRa ...

  4. [2]windows内核情景分析--系统调用

    Windows的地址空间分用户模式与内核模式,低2GB的部分叫用户模式,高2G的部分叫内核模式,位于用户空间的代码不能访问内核空间,位于内核空间的代码却可以访问用户空间 一个线程的运行状态分内核态与用 ...

  5. [7] Windows内核情景分析---线程同步

    基于同步对象的等待.唤醒机制: 一个线程可以等待一个对象或多个对象而进入等待状态(也叫睡眠状态),另一个线程可以触发那个等待对象,唤醒在那个对象上等待的所有线程. 一个线程可以等待一个对象或多个对象, ...

  6. [4]Windows内核情景分析---内核对象

    写过Windows应用程序的朋友都常常听说"内核对象"."句柄"等术语却无从得知他们的内核实现到底是怎样的, 本篇文章就揭开这些技术的神秘面纱. 常见的内核对象 ...

  7. [12]Windows内核情景分析 --- MDI

    Mdl意为'内存映射描述符'.'缓冲描述符',一个mdl就代表一个缓冲.(任意一块物理内存,可以同时映射到用户地址空间和系统地址空间的) 设备IO方式分为三种:缓冲方式.直接IO方式.直接方式 缓冲方 ...

  8. [3]windows内核情景分析--内存管理

    32位系统中有4GB的虚拟地址空间 每个进程有一个地址空间,共4GB,(具体分为低2GB的用户地址空间+高2GB的内核地址空间) 各个进程的用户地址空间不同,属于各进程专有,内核地址空间部分则几乎完全 ...

  9. c# 分析SQL语句中的表操作

    最近写了很多方向的总结和demo.基本包含了工作中的很多方面,毕竟c#已经高度封装并且提供了很多类库.前面已经总结了博文.最近2天突然感觉前面的SQL分析阻组件的确麻烦,也注意看了下.为了方便大家学习 ...

随机推荐

  1. thinkcmf5 学习笔记

    1.api里如何传递页码和每页记录数   data     :{category_id: '{$category.id}',page:++count+',10'}, page参数传递页码+数量,例如 ...

  2. as API一些容易忘记的属性和方法

    1.在flash动画里的一些动态文本会随着动画的执行,有抖动,解决问题的方法: tt为动画里的动态文本,tt.transform.matrix=null;

  3. Centos7 使用 Supervisor 守护进程 Celery

    一.Supervisor 安装(centos7 还有另一个进程守护命令 Systemd ) Centos 7 安装 Supervisord 二.Supervisor 守护进程 Centos7 使用 S ...

  4. Django admin模块使用search时报错:django.core.exceptions.FieldError: Related Field got invalid lookup: contains

    日志如下: <class 'django.core.handlers.wsgi.WSGIRequest'> ------------registered_admins: {'spaceCl ...

  5. Python+Selenium练习篇之5-利用partial link text定位元素

    本文介绍如何通过partial link text来定位页面元素.看到这个,有点和前一篇文字link text有点类似.字面意思,确实和link text相类似,partial link text就是 ...

  6. 最少的硬币数量组合出1到m之间的任意面值(贪心算法)

    题目描述: 你有n种不同面值的硬币,每种面值的硬币都有无限多个,为了方便购物,你希望带尽量少的硬币,并且要能组合出 1 到 m 之间(包含1和m)的所有面值. 输入描述: 第一行包含两个整数:m ,n ...

  7. Java学习3之成员方法及函数重载

    方法的定义:方法名称,返回值,参数列表,修饰符(权限修饰符,final,static),实现体. 参考自:<Java 程序设计与工程实践> 方法的签名: 唯一区别其他方法的元素:(1)方法 ...

  8. Spring MVC请求参数绑定

    所谓请求参数绑定,就是在控制器方法中,将请求参数绑定到方法参数上 @RequestParam 绑定单个请求参数到方法参数上 @RequestParam("id") Integer ...

  9. linux服务器上设置多主机头,设置多web站点

    假设VPS的IP是58.130.17.168,有两个域名指向该IP,分别是domain1.com, domain2.com, 修改/etc/httpd/conf/httpd.conf,在文件的最后加入 ...

  10. hihoCoder [Offer收割]编程练习赛83 D 生成树问题

    题目 从 Kruskal 算法的角度来思考这个问题. 考虑 $n$ 个点的"空图"(即没有边的图). 先将 $m_2$ 条无权值的边加到图中,得到一个森林. 按边权从小到大的顺序枚 ...