I would like to build a kernel module, which will run a tasklet when there is a keystroke of f5 key.
I understand how to init a tasklet, but how do I get the event in my module? How do I use request_irq to figure out if f5 was pressed?
-
Hi, 0x90,
I guess you know, to handle a interrupt, there are two parts.
First part, top half, that is interrupt handler,
Second part, bottom half, may be softirq, tasklet, work queue.
So, even if you want to implement all you want in a tasklet, you must make sure the top half, the interrupt handler, has chance to run first.
IIRC, the tasklet is just a variant of softirqs, and they are handled in irq_exit(), which is called in do_IRQ(). But, this flow may depend on the specific archtecture.
For your question, I guess it may be on x86 platform.
Whatever key is pressed, there will always be a keyboard interrupt passed to CPU.
And whether the key pressed is f5, will be checked in your tasklet, your interrupt handler may just need to pass the code to tasklet.
So, you should attach your interrupt handler, which is handled before the tasklet, to the keyboard interrupt by calling request_irq().
Update:
As Probie said, you may want to check notifier.txt and notifiers.txt in Documentation/ directory.
Thanks.
Related
In <<understanding Linux kernel>>, it mentions that while interrupt handler is running, the corresponding IRQ line are temporarily ignored. So I want to know why IRQ line need to be ignored, what to be protected? Thanks.
in other words, why "there should be no occurrence of an interrupt until the corresponding interrupt handler has terminated".
If it's a level triggered interrupt, it got to be ignored at least until its source has been cleared by the handler, otherwise the interrupt would occur repeatedly until the stack overflows. And regardless of level or edge triggering, it usually does no good to re-enter a specific interrupt handler while it still processes the interrupt; the actual interrupt routine (top half) should be quite short anyway. See also Top halves and bottom halves concept clarification.
In Linux, the handling of interrupt handler is divided into two components : top half, and bottom half.
From my understanding, the bottom-half of an interrupt handler can be handled in many ways : softirq, tasklet, work-queue, and timer-list.
I want to know which function(s) in the Linux kernel handle the schedule function of these bottom-halves.
Edit : I looked into the halndling of softirq's and tasklet's, and it seems that both of them are handled through the __do_softirq (http://lxr.linux.no/linux+v2.6.32.58/kernel/softirq.c#L207) function. However, I still see many paths inside the handler execution which pass through the schedule() function of the Linux kernel, and then show divergence. I am not able to explain these paths properly.
Some intuition for guiding you towards this function :
The scheduling of pending task (bottom-half) should be triggered by some event. Kernel events can either be a system call, or an interrupt.I think that the event which triggers a bottom half is an interrupt and not a system call.
As per my knowledge, this are the steps followed on arrival of an interrupt :
1. Interrupt arrives at core
2. Top half of the interrupt handler is run
3. Check the pending queue to see if there is a task which needs attention.
4. If there is any pending task, then execute it
I was going through the function list of all the OS handlers, and observed that the execution of many handlers passed through the schedule() function of the Linux kernel. Since this function is called so often from many interrupt handlers, I suppose that the bottom half of the interrupt handlers should be called from within this function only.
The schedule() function calls the post_schedule() function at the end. I tracked all the functions between this two function calls. There are many different function lists between them, raising suspicion that the bottom half functions must lie on the path from schedule() to post_schedule(). However, the sheer number of different MACROS and functions in the kernel is making it really difficult to pinpoint the function from where the scheduler jumps into the bottom half.
The top half of interrupt handler of the device driver must return IRQ_HANDLED, IRQ_WAKE_THREAD or IRQ_NONE to indicate to the interrupt sub-system that irq is handled or not. If IRQ_WAKE_THREAD is returned then the threaded bottom-half part of the interrupt handler is scheduled for execution. Normally bottom halves have higher priority over other normal kernel tasks. See https://lwn.net/Articles/302043/ for more details
I would like to ask if there is a way to register the interrupt handler so that only one cpu will handle this interrupt line.
The problem is that we have a function that can be called in both normal context and interrupt context. In this function we use irqs_disabled() to check the caller context. If the caller context is interrupt, we switch the processing to polling mode (continuously check the interrupt status register). Although the irqs_disabled() tells that the local interrupt of current CPU is disabled, the interrupt handler is still called by other CPUs and hence the interrupt status register are cleared in the interrupt handler. The polling code now checks the wrong value of the interrupt status register and do wrong processing.
You're doing it wrong. Don't limit your interrupt to be handled by a single CPU - instead use a spin_lock_irqsave to protect the code path. This will work both on the same CPU and across CPUs.
See http://www.mjmwired.net/kernel/Documentation/spinlocks.txt for the relevant API and here is a nice article from Linux Journal that explain the usage: http://www.linuxjournal.com/article/5833
I've got no experience with ARM, but on x86 you can arrange for a particular interrupt to be called on only one processor via /proc/irq/<number>/smp_affinity - set from user space - replacing the number with irq you care about - and this looks as if it's essentially generic. Note that the value you set it to is a bit mask, expressed in hex, without a leading 0x. I.e. if you want cpu 0, set it to 1, for cpu 1, set it to 2, etc. Beware of a process called irqbalance, which uses this mechanism, and might well override whatever you have done.
But why are you doing this? If you want to know whether you are called from an interrupt, there's an interface available named something like in_interrupt(). I've used it to avoid trying to call blocking functions from code that might be called from interrupt context.
I would like to be confirmed that kernel's panic() function and the others like kernel_halt() and machine_halt(), once triggered, guarantee complete freezing of the machine.
So, are all the kernel and user processes frozen? Is panic() interruptible by the scheduler? The interrupt handlers could still be executed?
Use case: in case of serious error, I need to be sure that the hardware watchdog resets the machine. To this end, I need to make sure that no other thread/process is keeping the watchdog alive. I need to trigger a complete halt of the system. Currently, inside my kernel module, I simply call panic() to freeze everything.
Also, the user-space halt command is guaranteed to freeze the system?
Thanks.
edit: According to: http://linux.die.net/man/2/reboot, I think the best way is to use reboot(LINUX_REBOOT_CMD_HALT): "Control is given to the ROM monitor, if there is one"
Thank you for the comments above. After some research, I am ready to give myself a more complete answer, below:
At least for the x86 architecture, the reboot(LINUX_REBOOT_CMD_HALT) is the way to go. This, in turn, calls the syscall reboot() (see: http://lxr.linux.no/linux+v3.6.6/kernel/sys.c#L433). Then, for the LINUX_REBOOT_CMD_HALT flag (see: http://lxr.linux.no/linux+v3.6.6/kernel/sys.c#L480), the syscall calls kernel_halt() (defined here: http://lxr.linux.no/linux+v3.6.6/kernel/sys.c#L394). That function calls syscore_shutdown() to execute all the registered system core shutdown callbacks, displays the "System halted" message, then it dumps the kernel, AND, finally, it calls machine_halt(), that is a wrapper for native_machine_halt() (see: http://lxr.linux.no/linux+v3.6.6/arch/x86/kernel/reboot.c#L680). It is this function that stops the other CPUs (through machine_shutdown()), then calls stop_this_cpu() to disable the last remaining working processor. The first thing that this function does is to disable interrupts on the current processor, that is the scheduler is no more able to take control.
I am not sure why the syscall reboot() still calls do_exit(0), after calling kernel_halt(). I interpret it like that: now, with all processors marked as disabled, the syscall reboot() calls do_exit(0) and ends itself. Even if the scheduler is awoken, there are no more enabled processors on which it could schedule some task, nor interrupt: the system is halted. I am not sure about this explanation, as the stop_this_cpu() seems to not return (it enters an infinite loop). Maybe is just a safeguard, for the case when the stop_this_cpu() fails (and returns): in this case, do_exit() will end cleanly the current task, then the panic() function is called.
As for the panic() code (defined here: http://lxr.linux.no/linux+v3.6.6/kernel/panic.c#L69), the function first disables the local interrupts, then it disables all the other processors, except the current one by calling smp_send_stop(). Finally, as the sole task executing on the current processor (which is the only processor still alive), with all local interrupts disabled (that is, the preemptible scheduler -- a timer interrupt, after all -- has no chance...), then the panic() function loops some time or it calls emergency_restart(), that is supposed to restart the processor.
If you have better insight, please contribute.
Why can't a context switch happen when an interrupt handler is executing ? More specifically, in the linux kernel, interrupt handlers run in the context of the process that was interrupted. Why is it not possible to do a context switch in the interrupt handler to schedule another process ?
On a multiprocessor, a context switch can certainly happen while an interrupt handler is executing. In fact, it would be difficult to prevent.
On a single-CPU machine, by definition it can only be running one thread of control at a time. It only has one register set, one ALU, etc. So if the interrupt handler is running there simply are no resources with which to execute a context switch.
Now, if you mean, can the interrupt handler actually call the context switch code and make one happen, well, I suppose on some systems that could be made to work. But for most, this wouldn't have much value and would be difficult to arrange. The CPU is running at elevated priority, and this priority cannot be lowered or synchronization between interrupt levels is lost. Critical sections in the OS are already synchronizing against interrupt execution and this would introduce complexities. Furthermore, a context switch happens by changing stacks, much like in a threaded user mode program, so it's hard to imagine how this might happen when the interrupt stack is needed for a return from the interrupt.
A couple of reasons, I guess, depending on the meaning of your question:
Q: Why would context switching during an interrupt be bad?
A: Interrupts are generally for interacting with hardware. Hardware is typically time-sensitive so the OS can't just stop dealing with it in the middle of something and come back when it feels like it.
Q: What stops a context switch from happening during an interrupt?
A: An interrupt happens in a special interrupt context, not a regular process context. Since it's not in a process, it's not subject to context switching as a normal process would be.
There's probably a better, deeper explanation to be made, but that's the extent of my own understanding of the matter.