瞎旋个啥,咋不去休眠、挂起呢?因为一些代码是大忙人,闲不得,更是停不得,就在门口自己玩死循环,急切的等待屋子里的人出来把锁给自己。
关于锁,最常使用的便是:自旋锁与信号量。先贴些实例,来点感性的认识。
-- include/linux/spinlock_types.h --
typedef
struct
{
raw_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned
int
break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned
int
magic, owner_cpu;
void
*owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct
lockdep_map dep_map;
#endif
} spinlock_t;
typedef
struct
{
volatile
unsigned
int
lock;
} raw_spinlock_t;
|
以上是2.6.32中的定义。raw_spinlock_t在2.6.39中的定义:
typedef
struct
spinlock {
union
{
struct
raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct
{
u8 __padding[LOCK_PADSIZE];
struct
lockdep_map dep_map;
};
#endif
};
} spinlock_t;
typedef
struct
raw_spinlock {
arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned
int
break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned
int
magic, owner_cpu;
void
*owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct
lockdep_map dep_map;
#endif
} raw_spinlock_t;
typedef
struct
{
volatile
unsigned
int
lock;
} arch_spinlock_t;
|
大体上就是将struct raw_spinlock变肥了而已,对于我们而言,该吃吃,该睡睡,平时如何写代码,现在依旧如何写。只要volatile unsigned int lock在就好。
关于lock变量,涉及到一个“排队自旋锁“的问题,将lock分为三部分:高16位(一般未用),第16位再一分为二(next域,owner域)。
简单的说,申请自旋锁,next++;释放自旋锁,owner++;
if (next<未增值前> == owner)
能申请自旋锁
else
不能申请自旋锁
spinlock_t lock = SPIN_LOCK_UNLOCKED;
int
__init my_init(
void
)
{
/*输出宏SPIN_LOCK_UNLOCKED的相关信息*/
printk(
"<0>SPIN_LOCK_UNLOCKED: %d\n"
,SPIN_LOCK_UNLOCKED.raw_lock.rlock);
spin_lock_init( &lock );
//初始化自旋锁
printk(
"<0>after init, lock: %d\n"
,lock.raw_lock.rlock);
printk(
"<0>\n"
);
spin_lock( &lock );
//第一次获取自旋锁
printk(
"<0>first spin_lock, lock: %d\n"
,lock.raw_lock.rlock);
spin_unlock( &lock );
//第一次释放自旋锁
printk(
"<0>first spin_unlock, lock: %d\n"
,lock.raw_lock.rlock);
printk(
"<0>\n"
);
spin_lock( &lock );
//第二次获取自旋锁
printk(
"<0>second spin_lock, lock: %d\n"
,lock.raw_lock.rlock);
spin_unlock( &lock );
//第二次释放自旋锁
printk(
"<0>second spin_unlock, lock: %d\n"
,lock.raw_lock.rlock);
return
0;
}
|
加载结果:
加锁是主菜,当然还会有一些附属功能(irq)一并执行,比如下面的三个实例:
(1)
int
__init spin_lock_bh_init(
void
)
{
spinlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init( &lock );
//初始化自旋锁
printk(
"<0>in_softirq():%ld\n"
, in_softirq());
//输出软中断计数
printk(
"<0>lock........\n"
);
spin_lock_bh( &lock);
//获取自旋锁同时禁止软中断
printk(
"<0>in_softirq():%ld\n"
, in_softirq());
printk(
"<0>unlock........\n"
);
spin_unlock_bh( &lock);
//释放自旋锁同时使能软中断
printk(
"<0>in_softirq():%ld\n"
, in_softirq());
return
0;
}
--------------------------------------
[ 5065.951735] in_softirq():0
[ 5065.951739] lock........
[ 5065.951741] in_softirq():256
[ 5065.951743] unlock........
[ 5065.951745] in_softirq():0
|
(2)
int
__init spin_lock_irq_init(
void
)
{
spinlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init( &lock );
//初始化自旋锁
printk(
"<0>lock........\n"
);
spin_lock_irq( &lock);
//获取自旋锁同时禁止本地中断
printk(
"<0>irqs_disabled():%d\n"
,irqs_disabled());
//查看中断是否被禁止
printk(
"<0>unlock........\n"
);
spin_unlock_irq( &lock);
//释放自旋锁同时使能本地中断
printk(
"<0>irqs_disabled():%d\n"
,irqs_disabled());
return
0;
}
---------------------------------------
[ 5747.407543] lock........
[ 5747.407548] irqs_disabled():1
[ 5747.407550] unlock........
[ 5747.407552] irqs_disabled():0
|
(3)
int
__init spin_lock_irqsave_init(
void
)
{
unsigned
long
flags = 0;
spinlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init( &lock );
//初始化自旋锁
printk(
"<0>lock........\n"
);
spin_lock_irqsave( &lock, flags );
//先禁止中断,后加锁,将加锁前的中断状态保存在flag
printk(
"<0>irqs_disabled():%d\n"
,irqs_disabled());
//查看中断是否被禁止
printk(
"<0>flags = 0x%lx\n"
,flags);
//输出标志寄存器的值
printk(
"<0>unlock........\n"
);
spin_unlock_irqrestore( &lock, flags );
printk(
"<0>irqs_disabled():%d\n"
,irqs_disabled());
return
0;
}
--------------------------------------
[ 6197.981793] lock........
[ 6197.981798] irqs_disabled():1
[ 6197.981800] flags = 0x200296
[ 6197.981802] unlock........
[ 6197.981804] irqs_disabled():0
|
再介绍一个try_lock:
-------trylock的特点在于会有返回值。
spinlock_t lock = SPIN_LOCK_UNLOCKED;
int
ret;
int
my_function(
void
* argc)
{
printk(
"<0>\nin child, the current pid is:%d\n"
,current->pid);
//显示子进程PID
ret = spin_trylock( &lock );
if
( ret == 1 )
{
spin_unlock( &lock );
}
else
{
printk(
"<0>spin_trylock could't get the lock!\n"
);
printk(
"<0>need the parent to unlock.\n\n"
);
}
return
0;
}
int
__init spin_trylock_init(
void
)
{
int
ret0;
printk(
"<0>in parent, the current pid is:%d\n"
,current->pid);
//显示父进程PID
spin_lock_init( &lock );
spin_lock( &lock );
//获取自旋锁
ret0 = kernel_thread(my_function,NULL,CLONE_KERNEL);
spin_unlock( &lock );
//释放自旋锁
printk(
"<0>parent unlock!\n"
);
return
0;
}
|
-----------
读写自旋锁
-----------
读写锁当然也有个lock,低24位为读者计数器(0~23)。
24位为“未锁“标志字段
其他未用。
未锁置1,表示此时锁没人拿。
未锁置0,其他也为0,表示写者掌控锁。
未锁置0,低24位有值,表示读者掌控锁,读者的个数表示有点特别,就是:
一个读者,则:0x00ffffff
两个读者,则:0x00fffffe
以此列推,大伙儿都看得出来。
最后来个实例,帮助理解:
rwlock_t rwlock = RW_LOCK_UNLOCKED;
int
__init write_trylock_init(
void
)
{
int
ret;
rwlock_init( &rwlock );
//读写自旋锁初始化
read_lock( &rwlock );
//读者申请得到读写锁rwlock
/* 输出读写自旋锁lock字段信息*/
printk(
"<0>after read_lock,lock: 0x%x\n"
,rwlock.raw_lock.lock);
printk(
"<0>\n"
);
ret = write_trylock( &rwlock );
//写者试图获得自旋锁
if
( ret == 1 )
{
printk(
"<0>after write_trylock, lock: 0x%x\n"
,rwlock.raw_lock.lock);
write_unlock( &rwlock );
printk(
"<0>after write_unlock, lock: 0x%x\n"
,rwlock.raw_lock.lock);
}
else
{
printk(
"<0>write_trylock could't get the lock!\n"
);
}
printk(
"<0>\n"
);
read_unlock( &rwlock );
//读者释放读写锁rwlock
printk(
"<0>after read_unlock,lock: 0x%x\n"
,rwlock.raw_lock.lock);
return
0;
}
|
加载结果:
当然,kernel里的锁还有许多,顺序锁啊,信号量啊什么。但基本都是那个样子。再说一个completioin,这个东西初次看到有点唬人,先来个实例:
struct
completion {
unsigned
int
done;
wait_queue_head_t wait;
};
--------------------------------
static
struct
completion comple;
int
my_function(
void
* argc)
{
wait_queue_head_t head;
wait_queue_t data;
printk(
"<0>in the kernel thread function!\n"
);
init_waitqueue_head(&head);
init_waitqueue_entry(&data,current);
add_wait_queue(&head,&data);
sleep_on_timeout(&head,10);
printk(
"<0>the current pid is:%d\n"
,current->pid);
printk(
"<0>the state of the parent is:%ld\n"
,current->real_parent->state);
complete(&comple);
//这里若不执行此函数,之前的wait_for_completioin便会一直堵死在那里
printk(
"<0>out the kernel thread function\n"
);
return
0;
}
static
int
__init wait_for_completion_init(
void
)
{
int
result;
wait_queue_t data;
printk(
"<0>into wait_for_completion_init.\n"
);
result=kernel_thread(my_function, NULL, CLONE_KERNEL);
struct
pid * kpid=find_get_pid(result);
struct
task_struct * task=pid_task(kpid,PIDTYPE_PID);
init_completion(&comple);
//初始化好变量,记得变量里还包含个:wait_queue_head_t
init_waitqueue_entry(&data, task);
__add_wait_queue_tail(&(comple.wait), &data);
//加入这个队列头
wait_for_completion(&comple);
//等待,起到同步作用
printk(
"<0>the result of the kernel_thread is :%d\n"
,result);
printk(
"<0>the current pid is:%d\n"
,current->pid);
printk(
"<0>out wait_for_completion_init.\n"
);
return
0;
}
|
completion是同步用的,和等待队列放在一起,自然就露出了她的本来面目~
好了,就先说这么些。。。