is signal handler code in a process paged? - linux

I have a question about linux signal handling mechanism. When a signal is to be delivered to a process, the kernel setups up the process stack(to do a successfull syscall back into the kernel using sys_sigreturn) and then does a sysexit/sysret to jump to the registered signal handler of the process. I am wondering what happens if the page in which the signal handler code is present, is paged out when the kernel does sysret ? The kernel does not expect page faults when executing ring 0 code right ?
Does the kernel keep process signal handling code pinned in memory always ?

Related

x86 how does Linux signal interrupt instruction stream

How does a Linux signal lead to the instruction stream of the X86 processor getting interrupted? So what CPU facility is used?
You have synchronous and asynchronous interrupts.
Synchronous interrupts are for issues like page faults, exceptions etc. Problems that are caused by the instructions that are executing on the CPU.
Asynchronous interrupts are from an IPI from the LAPIC, timer interrupt or for an interrupt picked up by the I/O-APIC and routed to the right LAPIC which then interrupts the processor. So these are external events.
But which X86 mechanism does the Signal use to interrupt the instruction stream and start processing the signal handler.
It isn't an asynchronous interrupt AFAIK because interrupts are handled within the kernel and signals in user-space. But its behavior is very similar to that of an asynchronous interrupt.
The kernel has to deliver a signal to user-space. You're right that that doesn't just happen on its own in hardware. That's why signal handling can respect the user-space red-zone, sigaltstack, and default actions if there's no handler registered.
As soon as the kernel has control, it can deliver the signal to user-space (or do the default action of ignoring it or killing the process).
If the signal was sent by a process running on another core, to a process running on this core, then probably it's delivered to user-space from an IPI handler, or else just at the next timer interrupt or system call that gives the kernel a chance to check for a pending signal.
When the IPI interrupt handler is preparing to return to user-space, it notices that there's a pending interrupt for the process that it's about to return to. (Either with a special case for one type of IPI, or by running the scheduler since we're in the kernel anyway). Instead of using iret to return to the interrupt frame pushed by hardware for the async interrupt, the kernel instead can iret to the address of the user-space signal handler.
The whole point of using an IPI (if that's what Linux even does) is to transfer control to the kernel sooner, instead of just waiting for it to notice the pending signal the next time it calls schedule().
If the process the signal is sent to isn't currently running on any core, then it either wakes the process up if there's a free CPU, or the signal just sits there for that task until the scheduler on some core decides to run it on this core. At that point it will notice and deliver the pending signal.

What is "process context" exactly, and how does it relates to "interrupt context"?

What does the following phrase mean: "the kernel executes in the process context"?
Does it mean that if CPU is executing some process and then some interrupt occurs (system call, key press, etc.), the CPU will keep the page table for the currently running process loaded and then it will execute the interrupt handler which resides in the process's kernel space?
If this is what it means, then it seems like the interrupt handler is executed in the process context, so what does interrupt context means?
Process context is its current state.
We need to save the context of the current running process so it can be resumed after the interrupt is handled.
Process context is basically its current state (what is in its registers).
esp
ss
eip
cs
and more.
We need to save the instruction pointer (EIP) and the CS (Code Segment) so that after the interrupt is handled we can continue running from where we were stopped.
The interrupt handler code resides in Kernel memory. Once an interrupt occur, we immediately switch from user mode to kernel mode. The state of the current running process is saved, part of it on user-stack and the other part on kernel-stack (depending on architecture). Assuming it's x86 then the interrupt handler is run by loading the appropriate ss, cs, esp and eip from TSS and Interrupt descriptor table.

Linux Signals and Interrupt handler

Reading about interrupts in linux, I understand that their handlers will run till completion (lets not consider the bottom halves here). So, assume that my code has SIGINT handler registered (using the signal()/sigaction() call) with a while(1)-loop in it (i.e the handler never returns).
If I quit my program abruptly while running, then shouldn't this scenario freeze my machine entirely? Won't my machine with only one CPU core go into an infinite loop?
What I mean is; since my interrupt handler is not returning, won't the CPU be stuck in executing the while(1) code only? (i.e no other process will get the chance of running, because there won't be any context-switch/preemption inside the handler or can the interrupt handler get preempted in between running the while(1) loop?)
You definitely mix signal handlers and interrupt handlers, despite they have similar handling. Unlike you are writing kernel code you won't meet interrupt handlers directly.
But, game rules for signal handlers are very similar. You should either exit from a signal handler or finish the program (and, the latter is analog for stopping the whole system, for the kernel land). This includes exotic ways for exiting signal handlers as longjmp().
From kernel POV, a process in forever loop in an interrupt handler doesn't differ from a process with the same loop in a usual code piece like main(). Entering a signal handler modifies signal mask but doesn't change things radically. Such process can be stopped, traced, killed in the same manner as outside of signal.
(All this doesn't concern some special process classes with advanced credentials. E.g. X Window server can be special because it disables some kernel activity during its video adapter handling. But you likely should know the needed safety rules when writing such software.)

how are signals implemented?

If a single thread process is currently running and a signal is detected by kernel, does the kernel simply halt the current execution, save the current address space of the instruction pointer and run the signal handler. In other words, it uses the same thread, that was being used by the program to execute the signal handler?
What happens if a process is multi-threaded? If a program have 3 threads and one thread registers the signal handler for say SIGUSR1, will the kernel interrupt the thread that had registered the signal handler and remainder two threads will continue to run?

Implementation of Signals under Linux and Windows?

I am not new to the use of signals in programming. I mostly work in C/C++ and Python.
But I am interested in knowing how signals are actually implemented in Linux (or Windows).
Does the OS check after each CPU instruction in a signal descriptor table if there are any registered signals left to process? Or is the process manager/scheduler responsible for this?
As signal are asynchronous, is it true that a CPU instruction interrupts before it complete?
The OS definitely does not process each and every instruction. No way. Too slow.
When the CPU encounters a problem (like division by 0, access to a restricted resource or a memory location that's not backed up by physical memory), it generates a special kind of interrupt, called an exception (not to be confused with C++/Java/etc high level language exception abstract).
The OS handles these exceptions. If it's so desired and if it's possible, it can reflect an exception back into the process from which it originated. The so-called Structured Exception Handling (SEH) in Windows is this kind of reflection. C signals should be implemented using the same mechanism.
On the systems I'm familiar with (although I can't see why it should be much different elsewhere), signal delivery is done when the process returns from the kernel to user mode.
Let's consider the one cpu case first. There are three sources of signals:
the process sends a signal to itself
another process sends the signal
an interrupt handler (network, disk, usb, etc) causes a signal to be sent
In all those cases the target process is not running in userland, but in kernel mode. Either through a system call, or through a context switch (since the other process couldn't send a signal unless our target process isn't running), or through an interrupt handler. So signal delivery is a simple matter of checking if there are any signals to be delivered just before returning to userland from kernel mode.
In the multi cpu case if the target process is running on another cpu it's just a matter of sending an interrupt to the cpu it's running on. The interrupt does nothing other than force the other cpu to go into kernel mode and back so that signal processing can be done on the way back.
A process can send signal to another process. process can register its own signal handler to handle the signal. SIGKILL and SIGSTOP are two signals which can not be captured.
When process executes signal handler, it blocks the same signal, That means, when signal handler is in execution, if another same signal arrives, it will not invoke the signal handler [ called blocking the signal], but it makes the note that the signal has arrived [ ie: pending signal]. once the already running signal handler is executed, then the pending signal is handled. If you do not want to run the pending signal, then you can IGNORE the signal.
The problem in the above concept is:
Assume the following:
process A has registered signal handler for SIGUSR1.
1) process A gets signal SIGUSR1, and executes signalhandler()
2) process A gets SIGUSR1,
3) process A gets SIGUSR1,
4) process A gets SIGUSR1,
When step (2) occurs, is it made as 'pending signal'. Ie; it needs to be served.
And when the step (3) occors, it is just ignored as, there is only one bit
available to indicate the pending signal for each available signals.
To avoid such problem, ie: if we dont want to loose the signals, then we can use
real time signals.
2) Signals are executed synchronously,
Eg.,
1) process is executing in the middle of signal handler for SIGUSR1,
2) Now, it gets another signal SIGUSR2,
3) It stops the SIGUSR1, and continues with SIGUSR2,
and once it is done with SIGUSR2, then it continues with SIGUSR1.
3) IMHO, what i remember about checking if there are any signal has arrived to the process is:
1) When context switch happens.
Hope this helps to some extend.

Resources