📄 4.html
字号:
1:<br>.section .text.lock,"ax"<br>2: call __up_wakeup<br> jmp 1b<br>.previous<br> ...<br>__down_failed:<br> pushl % eax<br> pushl % edx<br> pushl % ecx ; eax,edx,ecx是3个可用于函数参数的寄存器<br> call __down<br> popl % ecx<br> popl % edx<br> popl % eax<br> ret<br>__up_wakeup:<br> pushl % eax<br> pushl % edx<br> pushl % ecx<br> call __up<br> popl % ecx<br> popl % edx<br> popl % eax<br> ret<br>; semaphore.c<br>void __down(struct semaphore * sem)<br>{<br> struct task_struct *tsk = current;<br> DECLARE_WAITQUEUE(wait, tsk);<br> tsk->state = TASK_UNINTERRUPTIBLE;<br> add_wait_queue_exclusive(&sem->wait, &wait);<br> // 将当前进程加入到该semaphore的等待队列中<p> spin_lock_irq(&semaphore_lock);<br> sem->sleepers++;<br> for (;;) {<br> int sleepers = sem->sleepers;<p> /*<br> * Add "everybody else" into it. They aren't<br> * playing, because we own the spinlock.<br> */<p> // atomic_add_negative(int i,atomic_t *v)将i + v->counter相加,<br> // 结果为负返回1,否则返回0<br> if (!atomic_add_negative(sleepers - 1, &sem->count)) {<br> // 如果(sleepers - 1 + sem->count.counter)非负,则说明<br> // semaphore已经被释放,可以返回<br> sem->sleepers = 0;<br> break;<br> }<br> sem->sleepers = 1; /* us - see -1 above */<p> spin_unlock_irq(&semaphore_lock);<br> // 当semaphore被up()唤醒时,schedule()返回<br> schedule();<br> // 虽然已线程被up恢复,但为防止碰巧又有一个线程获得了semaphore,<br> // 因此将它们放在循环体中<br> tsk->state = TASK_UNINTERRUPTIBLE;<br> spin_lock_irq(&semaphore_lock);<br> }<br> spin_unlock_irq(&semaphore_lock);<br> // 该进程获得了semaphore,将它从等待队列中删除<br> remove_wait_queue(&sem->wait, &wait);<br> tsk->state = TASK_RUNNING;<br> // 为什么这里要调用wake_up,是因为调用它没有副作用从而防止潜在的死锁吗?<br> wake_up(&sem->wait);<br>}<br>void __up(struct semaphore *sem)<br>{<br> 扩展为<br>__wake_up_common(&sem->wait,TASK_UNINTERRUPTIBLE|TASK_INTERRUPTIBLE,1,0);<br> 唤醒队列中第1个进程,即将第1个进程放入运行队列<br> wake_up(&sem->wait);<br>}<br>; sched.c<br>static inline void __wake_up_common (wait_queue_head_t *q, unsigned int<br>mode,<br> int nr_exclusive, const int sync)<br>{<br> struct list_head *tmp, *head;<br> struct task_struct *p;<br> unsigned long flags;<p> if (!q)<br> goto out;<p> wq_write_lock_irqsave(&q->lock, flags);<p>#if WAITQUEUE_DEBUG<br> CHECK_MAGIC_WQHEAD(q);<br>#endif<p> head = &q->task_list;<br>#if WAITQUEUE_DEBUG<br> if (!head->next || !head->prev)<br> WQ_BUG();<br>#endif<br> tmp = head->next;<br> while (tmp != head) {<br> unsigned int state;<br> wait_queue_t *curr = list_entry(tmp, wait_queue_t,<br>task_list);<br> tmp = tmp->next;<p>#if WAITQUEUE_DEBUG<br> CHECK_MAGIC(curr->__magic);<br>#endif<br> p = curr->task;<br> state = p->state;<br> if (state & mode) {<br>#if WAITQUEUE_DEBUG<br> curr->__waker = (long)__builtin_return_address(0);<br>#endif<br> if (sync)<br> wake_up_process_synchronous(p);<br> else<br> wake_up_process(p);<br> if ((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)<br> break;<br> }<br> }<br> wq_write_unlock_irqrestore(&q->lock, flags);<br>out:<br> return;<br>}<br>; sched.c<br>inline void wake_up_process(struct task_struct * p)<br>{<br> unsigned long flags;<p> /*<br> * We want the common case fall through straight, thus the goto.<br> */<br> spin_lock_irqsave(&runqueue_lock, flags);<br> p->state = TASK_RUNNING;<br> if (task_on_runqueue(p))<br> goto out;<br> add_to_runqueue(p);<br> reschedule_idle(p);<br>out:<br> spin_unlock_irqrestore(&runqueue_lock, flags);<br>}<br>; sched.c<br>static inline void wake_up_process_synchronous(struct task_struct * p)<br>{<br> unsigned long flags;<p> /*<br> * We want the common case fall through straight, thus the goto.<br> */<br> spin_lock_irqsave(&runqueue_lock, flags);<br> p->state = TASK_RUNNING;<br> if (task_on_runqueue(p))<br> goto out;<br> add_to_runqueue(p);<br>out:<br> spin_unlock_irqrestore(&runqueue_lock, flags);<br>}<br>; sched.h<br>static inline int task_on_runqueue(struct task_struct *p)<br>{<br> return (p->run_list.next != NULL);<br>}<br>; sched.c<br>static inline void add_to_runqueue(struct task_struct * p)<br>{<br> list_add(&p->run_list, &runqueue_head);<br> nr_running++;<br>}<br>static LIST_HEAD(runqueue_head);<p>; fork.c<br>void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *<br>wait)<br>{<br> unsigned long flags;<p> wq_write_lock_irqsave(&q->lock, flags);<br> wait->flags = WQ_FLAG_EXCLUSIVE;<br> __add_wait_queue_tail(q, wait);<br> wq_write_unlock_irqrestore(&q->lock, flags);<br>}<br>; wait.h<br>static inline void __add_wait_queue_tail(wait_queue_head_t *head,<br> wait_queue_t *new)<br>{<br>#if WAITQUEUE_DEBUG<br> if (!head || !new)<br> WQ_BUG();<br> CHECK_MAGIC_WQHEAD(head);<br> CHECK_MAGIC(new->__magic);<br> if (!head->task_list.next || !head->task_list.prev)<br> WQ_BUG();<br>#endif<br> list_add_tail(&new->task_list, &head->task_list);<br>}<br>正执行调度的函数是schedule(void),它选择一个最合适的进程执行,并且真正进行上下文切换,<br>使得选中的进程得以执行。而reschedule_idle(struct task_struct *p)的作用是为进程选择<br>一个合适的CPU来执行,如果它选中了某个CPU,则将该CPU上当前运行进程的need_resched标志<br>置为1,然后向它发出一个重新调度的处理机间中断,使得选中的CPU能够在中断处理返回时执行<br>schedule函数,真正调度进程p在CPU上执行。在schedule()和reschedule_idle()中调用了goodness()<br>函数。goodness()函数用来衡量一个处于可运行状态的进程值得运行的程度。此外,在schedule()<br>函数中还调用了schedule_tail()函数;在reschedule_idle()函数中还调用了reschedule_idle_slow()。<p><p><br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -