How does threads sleep with interrupt disabled?

本小妞迷上赌 提交于 2019-12-04 17:18:54

The CPU knows nothing about threads, they are just a logical/abstract concept implemented in software. But the CPU does know about interrupts, they are real, and whenever one comes in from some device, the CPU stops executing whatever it has been executing and starts executing the routine dedicated to handling this particular interrupt. Once done, the routine signals completion of interrupt handling and the CPU resumes execution of whatever was preempted by the interrupt handling routine.

If the preempted code belonged to a thread, so be it. If it was another interrupt handling routine, fine too.

Just before the interrupt handling routine starts, the CPU saves some of the execution context (a few general-purpose and maybe a few control/system registers) either on the stack or somewhere else, so the routine can use them for its own purposes, and then at the end of the routine the CPU restores those registers from wherever they were stored, as if nothing ever happened from the point of view of the interrupted code. If the routine alters those registers, the CPU will resume execution somewhere else, not where it was executing the last time before the interrupt.

So, there, you can use interrupts to switch execution between the various pieces of code, threads or what have you. In fact, this is exactly how many schedulers work. They receive periodic interrupts from a timer and in the interrupt handler they save the context of the preempted code (e.g. thread A) in memory and load the context of another preempted code (e.g. thread B) from memory and return thereby continuing execution in another thread.

If you disable those timer interrupts, periodic thread scheduling/switching will be disabled as well. Interrupts affect the entire CPU and the currently executing thread (or whatever it is) and by induction they affect all threads.

Got it?

Now, if there are threads in the system, there's always at least one thread that can execute. That's because the CPU needs to execute something, it can't just stop and wait for a thread to arrive from nowhere (after all, it's the CPU who creates threads and makes them runnable and runs them). For this purpose there's a dummy (or not so dummy) thread in the system that has a low priority and does pretty much nothing, looping forever and perhaps telling the CPU that it may switch to a lower power state or halt until an interrupt comes in. An interrupt would end the low-power mode and cause the code to continue execution.

So, when a thread blocks on a semaphore or some other synchronization primitive, the scheduler simply picks another thread to execute. If all threads are blocked, the dummy thread is selected.

In your code, interrupts get disabled for a short period of time, while the kernel code is manipulating the various global variables (e.g. the lists of blocked/sleeping and ready threads). That's normal. You don't want race conditions here. Interrupts are re-enabled when the scheduler picks another thread to execute and proceeds to execute it.

Observe that when an at-some-point-current thread finishes sleeping (e.g. when some other thread wakes it up), it always enables interrupts:

spl = splhigh(); // disable interrupts
while (sem->count==0) {
  thread_sleep(sem); // context switch (to another thread and then back) occurs here
}
sem->count--;
splx(spl); // <-- re-enable interrupts here

Every thread blocked in this manner will cause interrupts to be enabled again when it's woken up and chosen by the scheduler to run.

Just think about it. You have 2 (or more) instances of the above or similar code in 2 (or more) threads. When one enters thread_sleep() or a similar function, some other thread comes out of its thread_sleep() or a similar function and re-enables interrupts.

Follow the code and comments along this path:

P()
  thread_sleep()
    mi_switch()
      md_switch()
        mips_switch()

As for the semaphore count, I'm not willing to do more code analysis now. You should try to figure it out yourself, unless someone else chimes in and covers it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!