今天把这两个锁的内核实现源码重新捋了一遍,基于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_SPINLOCK
unsigned 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