信号量
// include/asm-i386/semaphore.h/line: 44
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
};
// wait_queue_head_t 的介绍,在第三章进程的解析文档里介绍过。
// include/linux/wait.h/line: 51
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
// 现在再看到自旋锁,就没有那么陌生和不安了。
// 用一个双向链表来组织
// Linux 中的双向链表可以组织各种数据结构
信号量的获取
可以想象,信号量往往是和资源绑定的,理论上应该是内核的全局变量。
而 down() 是在某个进程里被调用的,并且这个进程应该知道这个信号量。
// include/asm-i386/semaphore.h/line: 105
static inline void down(struct semaphore * sem)
{
...
"call __down_failed\n\t"
...
}
// arch/i386/kernel/semaphore.c/line: 190
asm(
...
".globl __down_failed\n"
"__down_failed:\n\t"
...
"call __down\n\t"
...
);
// arch/i386/kernel/semaphore.c/line: 57
fastcall void __sched __down(struct semaphore * sem)
{
struct task_struct *tsk = current; // 获取当前进程
DECLARE_WAITQUEUE(wait, tsk); // 创建一个名为 wait 的 wait_queue_t,并和当前进程绑定
// 这一定是在内核态吗?使用的是进程的内核态的栈吗?
unsigned long flags;
tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irqsave(&sem->wait.lock, flags);
// 《第三版》P102,互斥睡眠进程;把 wait_queue 放到 wait_queue_head 里
add_wait_queue_exclusive_locked(&sem->wait, &wait);
sem->sleepers++; // 先预定自己睡眠在这个信号量上
for (;;) {
int sleepers = sem->sleepers;
// atomic_add_negative() 是把第一个参数加到第二个参数上,如果是负数则返回1
if (!atomic_add_negative(sleepers - 1, &sem->count)) {
sem->sleepers = 0; // 猜测这个是自旋锁的主要保护对象
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irqrestore(&sem->wait.lock, flags);
schedule();
spin_lock_irqsave(&sem->wait.lock, flags);
tsk->state = TASK_UNINTERRUPTIBLE;
}
// 把 wati_queue 从 wait_queue_head 中移除
remove_wait_queue_locked(&sem->wait, &wait);
wake_up_locked(&sem->wait);
spin_unlock_irqrestore(&sem->wait.lock, flags);
tsk->state = TASK_RUNNING;
}
// include/linux/wait.h/line: 156
#define wake_up_locked(x) \
__wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
// kernel/sched.c/line: 2975
void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
{
__wake_up_common(q, mode, 1, 0, NULL);
}
// kernel/sched.c/line: 2937
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int sync, void *key)
{
struct list_head *tmp, *next;
// for (tmp = (&q->task_list)->next, next = tmp->next;
// tmp != (&q->task_list);
// tmp = next, next = tmp->next)
list_for_each_safe(tmp, next, &q->task_list) {
wait_queue_t *curr;
unsigned flags;
curr = list_entry(tmp, wait_queue_t, task_list);
flags = curr->flags;
if (curr->func(curr, mode, sync, key) &&
(flags & WQ_FLAG_EXCLUSIVE) &&
!--nr_exclusive)
break;
}
}
// 此处的参数传入
__wake_up_common(&sem->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, 0, NULL)
// 现在没有追踪到 curr->func() 的指向,所以暂时不细究这个语句了。
信号量的释放
通过调用 up() 实现信号量的释放。
// include/asm-i386/semaphore.h/line: 180
static inline void up(struct semaphore * sem)
{
...
"call __up_wakeup\n\t"
...
}
// arch/i386/kernel/semaphore.c/line: 253
asm(
".section .sched.text\n"
".align 4\n"
".globl __up_wakeup\n"
"__up_wakeup:\n\t"
...
"call __up\n\t"
...
);
// arch/i386/kernel/semaphore.c/line: 52
fastcall void __up(struct semaphore *sem)
{
wake_up(&sem->wait);
}
// include/linux/wait.h/line: 150
#define wake_up(x) \
__wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
// kernel/sched.c/line: 2960
void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, void *key)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, 0, key);
spin_unlock_irqrestore(&q->lock, flags);
}
// spin_lock_irqsave() 和 spin_lock 类似,但是会中断;暂时存疑吧
读写信号量
// include/asm-i386/rwsem.h/line: 54
struct rw_semaphore {
signed long count;
#define RWSEM_UNLOCKED_VALUE 0x00000000
#define RWSEM_ACTIVE_BIAS 0x00000001
#define RWSEM_ACTIVE_MASK 0x0000ffff
#define RWSEM_WAITING_BIAS (-0x00010000)
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
spinlock_t wait_lock;
struct list_head wait_list;
#if RWSEM_DEBUG
int debug;
#endif
};
// lib/rwsem.c/line: 11
struct rwsem_waiter { // 读写信号量的实体,挂到上面的那个 list_head 上
struct list_head list;
struct task_struct *task;
unsigned int flags;
#define RWSEM_WAITING_FOR_READ 0x00000001
#define RWSEM_WAITING_FOR_WRITE 0x00000002
};
// include/asm-i386/rwsem.h/line: 85
static inline void init_rwsem(struct rw_semaphore *sem)
// 以下这几个函数都在这个文件中
// include/linux/rwsem.h
static inline void down_read(struct rw_semaphore *sem)
static inline int down_read_trylock(struct rw_semaphore *sem)
static inline void down_write(struct rw_semaphore *sem)
static inline int down_write_trylock(struct rw_semaphore *sem)
static inline void up_read(struct rw_semaphore *sem)
static inline void up_write(struct rw_semaphore *sem)
// downgrade write lock to read lock
static inline void downgrade_write(struct rw_semaphore *sem)
// include/linux/rwsem.h/line: 64
static inline void down_write(struct rw_semaphore *sem)
{
might_sleep();
rwsemtrace(sem,"Entering down_write");
__down_write(sem);
rwsemtrace(sem,"Leaving down_write");
}
// include/asm-i386/rwsem.h/line: 146
static inline void __down_write(struct rw_semaphore *sem)
{
...
" call rwsem_down_write_failed\n\t"
...
}
// lib/rwsem.c/line: 202
struct rw_semaphore fastcall __sched *
rwsem_down_write_failed(struct rw_semaphore *sem)
{
struct rwsem_waiter waiter;
rwsemtrace(sem, "Entering rwsem_down_write_failed");
waiter.flags = RWSEM_WAITING_FOR_WRITE;
rwsem_down_failed_common(sem, &waiter, -RWSEM_ACTIVE_BIAS);
rwsemtrace(sem, "Leaving rwsem_down_write_failed");
return sem;
}
// lib/rwsem.c/line: 143
static inline struct rw_semaphore *
rwsem_down_failed_common(struct rw_semaphore *sem,
struct rwsem_waiter *waiter, signed long adjustment)
// 没看太明白,赶进度,先不细看了
版权声明:本文为weixin_42346852原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。