今天把这两个锁的内核实现源码重新捋了一遍,基于liunx2,6.0,直接粘注释版:
核心文件,x86下实现的spinlock

#ifndef __ASM_SPINLOCK_H
#define __ASM_SPINLOCK_H#include <asm/atomic.h>
#include <asm/rwlock.h>
#include <asm/page.h>
#include <linux/config.h>extern int printk(const char * fmt, ...)__attribute__ ((format (printf, 1, 2)));/** Your basic SMP spinlocks, allowing only a single CPU anywhere*/typedef struct {//自旋锁为无符号的整型变量 volatile保证变量都从内存中获取,不要缓存在寄存器里volatile unsigned int lock;
#ifdef CONFIG_DEBUG_SPINLOCKunsigned magic;
#endif
} spinlock_t;
//定义一个spinlock的魔数,用来调试用
#define SPINLOCK_MAGIC  0xdead4ead#ifdef CONFIG_DEBUG_SPINLOCK
#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC
#else
#define SPINLOCK_MAGIC_INIT /*如果没有开启调试状态将什么也没有 */
#endif
//创建一个值为1的自旋锁
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
//初始化自旋锁 x是一根指针 所以解引用
#define spin_lock_init(x)   do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)/** Simple spin lock operations.  There are two variants, one clears IRQ's* on the local processor, one does not.* 简单的自旋锁操作。有两种变体,一种清除本地处理器上的IRQ,另一种不清除。** We make no fairness assumptions. They have a cost.* 我们没有做出公平的假设(非公平)。它们是有代价的*/
//判断自旋锁是否被锁定 先通过取地址拿到spinlock里的lock 再转为字符,再解引用判断是否小于0
#define spin_is_locked(x)   (*(volatile signed char *)(&(x)->lock) <= 0)
//等待自旋锁释放,barrier()保证禁止编译器任意排序
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
//获取自旋锁内联汇编代码,这里只是code部分,剩下在用的时候肯定是有输出数和输入数的
#define spin_lock_string \"1:" \ //1位置"lock ; decb %0" \ //对lock变量的值进行自减,如果lock变量是0或者小于0,再减岂不是直接就小于0了吗,所以底下js判断是否符号位为1,也就是小于0"js 2f" \  //f是forward,往后跳,因为2:确实在后面,如果小于0,跳转到前面的2处 js判断的是符号位是否为1,为1当然就小于0啦LOCK_SECTION_START("") \ //涉及到ELF的知识"2:" \"rep;nop" \ //repeat空操作"cmpb $0,%0" \ //比较lock的值是否为0,%0可以从后面的代码看出,是输出参数,是lock变量 cmpb的b代表比一个字节,l代表4字节"jle 2b" \ //b是backward,往前跳,jle代表小于或等于0,继续2处"jmp 1b" \//jmp:无条件转移到指定内存地址,否则跳回到1处去进行减一操作,这也不一定还能拿到哦,还得判断,如果成功就拿到了锁!!!!!LOCK_SECTION_END //".previous\n\t"/** This works. Despite all the confusion.* 这很有效。尽管如此混乱。* (except on PPro SMP or if we are using OOSTORE)* (PPro errata 66, 92)*/#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)#define spin_unlock_string \ //这里和lock_string是不一样的,直接就把输入输出和clobber都填好了"movb $1,%0" \ //把1设置为lock的值:"=m" (lock->lock) : : "memory" //static spinlock_t lock;这里的lock是一个spinlock_t,所以指针再指向spinlock里的lockstatic inline void _raw_spin_unlock(spinlock_t *lock)
{#ifdef CONFIG_DEBUG_SPINLOCKif (lock->magic != SPINLOCK_MAGIC)BUG();if (!spin_is_locked(lock))BUG();
#endif__asm__ __volatile__(spin_unlock_string);
}#else#define spin_unlock_string \"xchgb %b0, %1" \:"=q" (oldval), "=m" (lock->lock) \:"0" (oldval) : "memory"static inline void _raw_spin_unlock(spinlock_t *lock)
{char oldval = 1;
#ifdef CONFIG_DEBUG_SPINLOCKif (lock->magic != SPINLOCK_MAGIC)BUG();if (!spin_is_locked(lock))BUG();
#endif__asm__ __volatile__(spin_unlock_string);
}#endifstatic inline int _raw_spin_trylock(spinlock_t *lock)
{char oldval;__asm__ __volatile__("xchgb %b0,%1" //交换lock的值(%1)和oldval:"=q" (oldval), "=m" (lock->lock) //q:将输入变量放入eax,ebx,ecx,edx中的一个 :"0" (0) : "memory"); //0:表示用它限制的操作数与某个指定的操作数(这里就是0)匹配return oldval > 0; //大于0说明lock变量为1,那说明就没有人拿到这个锁,那么久尝试获得到了锁
}static inline void _raw_spin_lock(spinlock_t *lock)
{#ifdef CONFIG_DEBUG_SPINLOCK__label__ here;
here:if (lock->magic != SPINLOCK_MAGIC) {printk("eip: %p\n", &&here);BUG();}
#endif__asm__ __volatile__(spin_lock_string:"=m" (lock->lock)//输出操作数列表为lock : : "memory");
}/** Read-write spinlocks, allowing multiple readers* but only one writer.** NOTE! it is quite common to have readers in interrupts* but no interrupt writers. For those circumstances we* can "mix" irq-safe locks - any writer needs to get a* irq-safe write-lock, but readers can get non-irqsafe* read-locks.*/
typedef struct {volatile unsigned int lock;
#ifdef CONFIG_DEBUG_SPINLOCKunsigned magic;
#endif
} rwlock_t;//多个读者共享,写者互斥,和互斥自旋锁机构一模一样#define RWLOCK_MAGIC 0xdeaf1eed#ifdef CONFIG_DEBUG_SPINLOCK
#define RWLOCK_MAGIC_INIT   , RWLOCK_MAGIC
#else
#define RWLOCK_MAGIC_INIT   /* */
#endif#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }//RW_LOCK_BIAS->0x0100 0000第七位//初始化读写自旋锁
#define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)#define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS)//RW_LOCK_BIAS代表没上锁(既没有读锁也没有写锁)/** On x86, we implement read-write locks as a 32-bit counter* with the high bit (sign) being the "contended" bit.* 在x86上,我们将读写锁实现为32位计数器,高位(符号)为“争用”位。** The inline assembly is non-obvious. Think about it.** Changed to use the same technique as rw semaphores.  See* semaphore.h for details.  -ben*/
#endif
/* the spinlock helpers are in arch/i386/kernel/semaphore.c */
//helper__write_lock_failed和的实现去这个地方(arch/i386/kernel/semaphore.c)找,否则找不到
//获取读锁或者写锁失败后的helper实现
static inline void _raw_read_lock(rwlock_t *rw)
{#ifdef CONFIG_DEBUG_SPINLOCKif (rw->magic != RWLOCK_MAGIC)BUG();
#endif__build_read_lock(rw, "__read_lock_failed");//在读写锁文件rwlock.h里有相应实现
}static inline void _raw_write_lock(rwlock_t *rw)
{#ifdef CONFIG_DEBUG_SPINLOCKif (rw->magic != RWLOCK_MAGIC)BUG();
#endif__build_write_lock(rw, "__write_lock_failed");
}//读锁和写锁的释放也很简单,原子加1或者原子加0x0100 0000
#define _raw_read_unlock(rw)        asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
#define _raw_write_unlock(rw)   asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")static inline int _raw_write_trylock(rwlock_t *lock)
{atomic_t *count = (atomic_t *)lock;if (atomic_sub_and_test(RW_LOCK_BIAS, count))return 1;atomic_add(RW_LOCK_BIAS, count);return 0;
}#endif /* __ASM_SPINLOCK_H */

rwlock.h核心文件,x86实现:

/* include/asm-x86_64/rwlock.h** Helpers used by both rw spinlocks and rw semaphores.**  Based in part on code from semaphore.h and* spinlock.h Copyright 1996 Linus Torvalds.** Copyright 1999 Red Hat, Inc.*   Copyright 2001,2002 SuSE labs **    Written by Benjamin LaHaise.**  This program is free software; you can redistribute it and/or*  modify it under the terms of the GNU General Public License*    as published by the Free Software Foundation; either version*   2 of the License, or (at your option) any later version.*/
#ifndef _ASM_X86_64_RWLOCK_H
#define _ASM_X86_64_RWLOCK_H#include <linux/stringify.h>#define RW_LOCK_BIAS       0x01000000
#define RW_LOCK_BIAS_STR    "0x01000000"#define __build_read_lock_ptr(rw, helper)   \asm volatile(LOCK "subl $1,(%0)" \ //获取读锁就是尝试在lock上减1,因为RW_LOCK_BIAS是非常大的一个数// 只有有写锁的时候会直接减去0x01000000变为0,其他时候是不可能小于0的,所以没有写锁的情况下,去抢占这个读锁是没有问题的"js 2f" \ //判断符号位是否为1,也即是否为负数,如果是负数,那么说明已经有写锁啦,那你只能去2位置了"1:" \LOCK_SECTION_START("") \"2: call " helper "" \ //调用helper方法,helper即为__read_lock_failed,下面把这段实现摘抄出来了,我没有获取到锁,只好调用这个方法"jmp 1b" \LOCK_SECTION_END \::"a" (rw) : "memory") //a:将输入变量放入eax//这段代码是从i386的semaphore下摘出来的asm("__read_lock_failed:"LOCK "incl   (%eax)"//原子性增加eax寄存器中的值(也就是lock变量的值)"1: rep; nop" //进行空操作,耗掉一点点时间"cmpl $1,(%eax)"// cmp影响符号位,lock变量和1相减如果是负数,符号位为1"js 1b" //如果是负数那么就去1重新比较,直到可以获得读锁LOCK "decl (%eax)"//说明eax也就是lock大于等于1,进行相减再次判断是否为负数,因为可能两个线程同时走这一步,严谨!!!!!"js __read_lock_failed"//负数说明又没抢到,继续循环吧"ret"//抢到了,返回);#define __build_read_lock_const(rw, helper)   \asm volatile(LOCK "subl $1,%0\n\t" \"js 2f\n" \"1:\n" \LOCK_SECTION_START("") \"2:\tpushq %%rax\n\t" \"leaq %0,%%rax\n\t" \"call " helper "\n\t" \"popq %%rax\n\t" \"jmp 1b\n" \LOCK_SECTION_END \:"=m" (*((volatile int *)rw))::"memory")#define __build_read_lock(rw, helper) do { \if (__builtin_constant_p(rw)) \__build_read_lock_const(rw, helper); \else \__build_read_lock_ptr(rw, helper); \//走这里} while (0)#define __build_write_lock_ptr(rw, helper) \asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)" \ //核心,写锁只能有一个,上来直接把那个大数减完了"jnz 2f" \ //看是否为0,不为0说明绝对有读锁在占着,直接失败去2处forward"1:" \LOCK_SECTION_START("") \"2: call " helper "" \同读锁逻辑,截取helper如下"jmp 1b" \LOCK_SECTION_END \::"a" (rw) : "memory")//这段代码是从i386的semaphore下摘出来的asm("__write_lock_failed:"LOCK "addl  $" RW_LOCK_BIAS_STR ",(%eax)" //大同小异,先加后减"1: rep; nop\n\t""cmpl    $" RW_LOCK_BIAS_STR ",(%eax)""jne   1b"LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)""jnz   __write_lock_failed""ret");#define __build_write_lock_const(rw, helper) \asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \"jnz 2f\n" \"1:\n" \LOCK_SECTION_START("") \"2:\tpushq %%rax\n\t" \"leaq %0,%%rax\n\t" \"call " helper "\n\t" \"popq %%rax\n\t" \"jmp 1b\n" \LOCK_SECTION_END \:"=m" (*((volatile long *)rw))::"memory")#define __build_write_lock(rw, helper)  do { \if (__builtin_constant_p(rw)) \__build_write_lock_const(rw, helper); \else \__build_write_lock_ptr(rw, helper); \ //上读锁走这里} while (0)#endif

看注释可以很容易理解。

liunx内核中的互斥自旋锁和读写自旋锁的实现详解相关推荐

  1. 分布式锁(基于redis和zookeeper)详解

    分布式锁(基于redis和zookeeper)详解 https://blog.csdn.net/a15835774652/article/details/81775044 为什么写这篇文章? 目前网上 ...

  2. php self this static,PHP 中 self、static、$this 的区别和后期静态绑定详解

    本篇文章给大家分享的内容是关于PHP 中 self.static.$this 的区别和后期静态绑定详解,有着一定的参考价值,有需要的朋友可以参考一下 self.static 和 $this 的区别 为 ...

  3. java构造块_java中的静态代码块、构造代码块、构造方法详解

    运行下面这段代码,观察其结果: package com.test; public class HelloB extends HelloA { public HelloB() { } { System. ...

  4. (转)web.xml 中的listener、 filter、servlet 加载顺序及其详解

    转: https://www.cnblogs.com/Jeely/p/10762152.html web.xml 中的listener. filter.servlet 加载顺序及其详解 一.概述 1. ...

  5. nmmqq.php?/lspc.html,html中的图片直接使用base64编码后的字符串代替详解

    网页中的图片是使用base64编码后的字符串代替了,这个叫做Data URI scheme,下面有个不错的示例,大家可以参考下 最近来了一个网页,里面有图片,但是却没有引用外部的图片资源,很好奇.查看 ...

  6. Java中常见RuntimeException与其他异常表及Exception逻辑关系详解

    Java中常见RuntimeException与其他异常表及Exception逻辑关系详解 前言 常见`RuntimeException` 其他错误类型 `Error`类 `Exception`类 E ...

  7. python使用视频_Python中操作各种多媒体,视频、音频到图片的代码详解

    我们经常会遇到一些对于多媒体文件修改的操作,像是对视频文件的操作:视频剪辑.字幕编辑.分离音频.视频音频混流等.又比如对音频文件的操作:音频剪辑,音频格式转换.再比如我们最常用的图片文件,格式转换.各 ...

  8. java ant解压缩_java ant包中的org.apache.tools.zip实现压缩和解压缩实例详解

    java ant包中的org.apache.tools.zip实现压缩和解压缩实例详解 发布于 2020-4-7| 复制链接 摘记: java ant包中的org.apache.tools.zip实现 ...

  9. 多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解

    多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解 1. 概览 在开始具体讨论卡尔曼滤波和匈牙利算法之前,首先我们来看一下基于检测的目标跟踪算法的大 ...

最新文章

  1. PNAS | 根际植保素合成调控细菌对植物的促生长作用
  2. bs程序在linux下部署,在windows10 Linux (centos7)中安装go golang (够浪) 并测试运行
  3. opencv3.2.0 Cmake 3.8.0 + tdm-gcc-5.1.0-3 编译问题 highgui _Win32_IE
  4. 每天进步一点点:(11)进程优先级学习 nice
  5. [改善Java代码]自由选择字符串拼接方法
  6. 译]bootstrap-select (selectpicker)方法
  7. 成外集训小记(更新到7.31)
  8. 史上最全C/C++思维导图,B站疯传,快收藏!!(附配套学习视频)
  9. Nikto v2.1.0-手册
  10. idv和vdi的优劣势_IDV和VDI区别
  11. 初学博科YIGO2.0学习心得--下推
  12. 股票入门浅学20210721
  13. java安装 2203_win7系统无法安装java程序提示“内部错误2203”的解决方法
  14. CF869E The Untended Antiquity 解题报告
  15. python计算圆柱体积_如何用PYTHON计算体积公式
  16. 计算机技术非全日制调剂2020,2020年硕士研究生部分非全日制专业接收调剂的公告...
  17. 诺基亚 android,诺基亚当年为什么走向没落也没用安卓系统?
  18. java之简单的增删改查功能
  19. 录屏功能怎么打开?检查一下你的电脑这些设置
  20. PHP将图片验证码转换成base64格式

热门文章

  1. Java黑皮书课后题第2章:2.18(打印表格)编写程序,显示下面的表格,将浮点数值类型转化为整数
  2. Winform控件拖动
  3. Spring Boot下的lombok安装以及使用简介
  4. UVa11729 - Commando War(贪心)
  5. ie 9 渐变背景色兼容问题
  6. 2015.7.17( NOI2015 day1 )
  7. nodejs在服务器上运行
  8. Oracle数据库无法向listener注册的解决一例
  9. ASP.NET MVC3 Razor视图引擎-基础语法
  10. 2017\National _C_C++_C\1.哥德巴赫分解