Why can't kernel code / thread executed in interrupt context sleep?

I read the following article by Robert Love

http://www.linuxjournal.com/article/6916

who says

"... Let's discuss the fact that work queues are executed in the context of the process. This contrasts with the other mechanisms of the lower half that all work in the context of the interrupt. Coding in the context of the interrupt cannot sleep or block because the interrupt context does not have a backup process copying to be rescheduled. Therefore, since interrupt handlers are not associated with the process, there is nothing that the scheduler could sleep and, more importantly, nothing that the scheduler wakes up ... "

I do not understand. AFAIK, the scheduler in the kernel is O (1), which is implemented through a bitmap. So, what makes scehduler put the interrupt context to sleep and accept the next scheduled process and give it control?

+43
linux-kernel
Jun 27 '09 at 20:41
source share
11 answers

I think this is a design idea.

Of course, you can create a system in which you can sleep in interruption, but besides making the system difficult to learn and complicate (many many situations you need to consider), this helps nothing. Thus, from a constructive view, declaring an interrupt handler because it cannot sleep is very clear and easy to implement.




From Robert Love (hacker-hacker): http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791

You cannot sleep in an interrupt handler because interrupts do not have the context of an auxiliary process, and therefore there is nothing that could be brought back to. In other words, interrupt handlers are not related to the task, so there is nothing to "sleep" and (more importantly) to "wake up nothing." They should work atomically.

This is not like other operating systems. On most operating systems, interrupts are not threaded. However, the lower halves are often.

The reason the page error handler can sleep is because it is only called by code that runs in the context of the process. Because kernel memory is not pagable, accessing memory only for user space can result in a page error. Thus, only a few specific places (for example, calls to copy_ {to, from} _user ()) can cause a page error in the kernel. Those places should be made using code that can sleep (that is, the context of the process, no locks, etc.).

+27
Jun 29 '09 at 5:37
source share

So, what prevents scehduler from putting the interrupt context into sleep mode and accepting the next scheduled process and passing control to it?

The problem is that the interrupt context is not a process and therefore cannot be strewn with.

When an interrupt occurs, the processor saves the registers onto the stack and proceeds to the start of the interrupt service routine. This means that when the interrupt handler is running, it starts in the context of the process that was executed when the interrupt occurred. An interrupt is executed in this process stack, and when the interrupt handler terminates, this process will resume execution.

If you tried to sleep or lock inside the interrupt handler, you would not only stop the interrupt handler, but also interrupt it. This can be dangerous because the interrupt handler does not know that it interrupted the process, or even if it is safe to pause the process.

A simple scenario where things could go wrong would be a dead end between the interrupt handler and the process that it interrupts.

  • Process1 goes into kernel mode.
  • Process1 receives LockA.
  • Interruption occurs.
  • ISR begins execution using the package Process1.
  • ISR is trying to acquire LockA.
  • ISR causes a dream, waiting for the release of LockA.

At this point you have a dead end. Process1 cannot resume execution until the ISR is executed with its stack. But the ISR is blocked, waiting for Process1 to release LockA.

+41
Jun 27 '09 at 21:10
source share

Because the flow switching infrastructure is not available at this point. When servicing an interrupt, only material with a higher priority can be executed — see the APIC documentation for interrupt priority . If you allowed another thread to execute (which you mean in your question that it will be easy to do), you won’t be able to let it do anything - if this caused a page error, you will have to use services in the kernel that are unsuitable for interrupting the interrupt ( see below why).

Typically, your only goal in the interrupt procedure is to make the device stop interrupting and stop something at a lower interrupt level (on unix it is usually not an intermittent level, but for Windows it sends, apc or passive level) so that make heavy lifting when you have access to additional kernel / os features. See Implementing a Handler .

EDIT: This is a feature of O / S, not something Linux has. The interrupt procedure can be performed at any point; therefore, the interrupt status is incompatible. If you interrupted the thread scheduling code, its status is incompatible, so you cannot be sure that you can "sleep" and switch threads. Even if you protect the thread-switching code from interruption, thread-switching is a very high function of the O / S level, and if you protect everything that it relies on, interruption becomes more of a sentence than an imperative implied by its name.

EDIT2: Removed the use of the word "shutdown", as this implies readers. This requires O / S. Added links to more authoritative links to justify my answer.

+5
Jun 27 '09 at 20:43
source share

So, what prevents scehduler from putting the interrupt context into sleep mode and accepting the next scheduled process and passing control to it?

Scheduling occurs on timer interrupts. The basic rule is that only one interrupt can be opened at a time, so if you go to sleep in the “received data from device X” interrupt, the timer interrupt cannot be executed to schedule it.

Interrupts also occur many times and overlap. If you put the “received data” interrupt to sleep and then get more data, what happens? This is confusing (and fragile) enough that the catch-all rule: no sleep in interrupts. You will do it wrong.

+3
Jun 27 '09 at 22:52
source share

Even if you can put an ISR for sleep, you don’t want to. You want your ISRs to be as fast as possible to reduce the risk of no subsequent interruptions.

+2
Jul 30 '09 at 17:56
source share

High-level interrupt handlers mask the operations of all interrupts with a lower priority, including interrupting the system timer. Therefore, the interrupt handler should avoid engaging itself in an activity that could cause it to sleep. If the handler is asleep, the system may hang because the timer is masked and is not able to schedule the sleep thread. It makes sense?

0
Jul 30 '09 at 17:50
source share

If a higher-level interrupt procedure approaches the point where the next thing that it needs to do should happen after a certain period of time, then it needs to send a request to the timer queue, asking it to start another interrupt procedure (at a lower priority level) after a while .

When this interrupt routine is executed, it will then raise the priority level to the level of the original interrupt routine and continue. This has the same effect as a dream.

0
Jul 30 '09 at 17:57
source share

The Linux kernel has two methods for distributing the interrupt stack. One is on the kernel stack of the interrupted process, the other is a dedicated interrupt package for each processor. If the interrupt context is stored in a dedicated interrupt stack for each processor, then indeed the interrupt context is not completely associated with any process. The "current" macro will cause an invalid pointer to the current current process, since the "current" macro with some architecture is evaluated by the stack pointer. The stack pointer in the context of an interrupt can point to the allocated interrupt stack, and not to the kernel stack of any process.

0
Aug 03 '10 at 19:25
source share

Disabling an interrupt handler for locking is a design choice. When some data is on the device, the interrupt handler intercepts the current process, prepares the data transfer and enables the interrupt; Before the handler activates the current interrupt, the device must hang. We want our I / O operations to be busy and our system to respond, then we better not block the interrupt handler.

I do not think that “volatile states” are an important reason. Processes, regardless of whether they are in user mode or kernel mode, should be aware that they can be interrupted by interrupts. If any data structure in kernel mode will be available to both the interrupt handler and the current process, as well as the race condition, then the current process should disable local interrupts, and, in addition, for multiprocessor architectures, spindle blocks should be used during critical sections .

I also do not think that if the interrupt handler was blocked, it cannot be woken up. When we say "block", this basically means that the blocked process is waiting for some event / resource, so it binds itself to some waiting queue for this event / resource. Whenever a resource is released, the release process is responsible for awakening the waiting process.

However, it is really annoying that a blocked process cannot do anything during a lock; he did nothing wrong with this punishment, which is unfair. And no one could accurately predict the time of blocking, so an innocent process should wait for an incomprehensible reason for an unlimited time.

0
Jan 16 '11 at 23:26
source share

This is just a design / implementation choice on Linux. The advantage of this design is simple, but it may not be very good for real-time OS requirements.

Other OSs have different designs / implementations.

For example, in Solaris, interrupts can have different priorities, which allows most device interrupts to be called in interrupt flows. Interrupt streams enable sleep mode because each interrupt stream has a separate stack in the context of the stream. The design of interrupt streams is good for real-time streams, which should have higher priorities than interrupts.

0
Jan 31 '13 at 3:47 on
source share

Essentially, the question is whether the interrupt handler can get a valid "current" (address for the current task_structure process), if so, can the content be changed accordingly so that it falls into a "sleep" state, which can be returned by the scheduler later if the state somehow changes. The answer may be hardware dependent.

But in ARM this is impossible, since the "current" is not related to the process in the interrupt mode. See code below:

#linux/arch/arm/include/asm/thread_info.h 94 static inline struct thread_info *current_thread_info(void) 95 { 96 register unsigned long sp asm ("sp"); 97 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 98 } 

sp is in USER mode, and SVC mode is “the same” (“same” here does not mean that they are equal, instead user mode sp points to the user space stack, while svc sp r13_svc mode points to the kernel stack, where user the task_structure process was updated the previous time the task was switched in. When a system call occurs, the process re-enters the kernel space, when sp (sp_svc) still does not change, these 2 sp are connected to each other, in this sense they are 're' same '), therefore in SVC mode, the kernel code can get a valid “current.” But in others, vilegirovannyh modes, for example, interrupt mode, sp is the "other" refers to a dedicated address defined in cpu_init (). " The current "calculated in this mode will not be related to the interrupted process, access to it will lead to unexpected behavior. That's why he always said that the system call can sleep, but the interrupt handler cannot, the system call works in the context of the process, but interrupts him.

0
Sep 27 '13 at 10:38 on
source share



All Articles