|
|
About ::
TODO ::
Blog ::
RSS ::
Old blog ::
Projects ::
GIT ::
Gallery ::
Notes
Tue, 23 Jan 2007
How do signals work in Linux?
Likely it is the same in all other Unix systems too,
but I only checked Linux kernel.
There are two types of signals - synchronous, which are
for example result of error operation,
they always happen synchronously after the wrong operation,
and asynchronous ones - they can be delivered at any time,
for example using kill() call.
No matter what type of signal we received, it was produced exactly the same way.
When signal is generated and it is not blocked, mask of pending signals is updated.
Later (when process is scheduled for execution) kernel will examine mask of pending signals
and if there are any, it will start to deliver them one-by-one.
If handler is set to SIG_DFL or SIG_IGN
either process will be killed (actually default action will take place),
or signal will be dropped. The most interesting case thus is when there is
our own handler.
In that case kernel will eventually call setup_frame() function,
which will setup new signal stack (or use existing if
SA_ONSTACK flag is set), save current context (copy registers,
error value, some thread info and other interesting information), setup
return call (function which will be called when signal handler is completed
to return back to kernel). Save context procedure includes filling
struct sigframe, which contains all info needed to continue to run
interrupted task and/or schedule it after some time.
After some GNU asm learning and googling, I've managed to run
function on top of its own stack. Code (for x86) is pretty simple:
asm volatile (
"mov %0,%%eax \n" /* Start address */
"mov %1,%%ebx \n" /* Arguments */
"mov %%esp,%%edx \n" /* save old sp to edx */
"mov %2,%%esp \n" /* change stack */
"push %%edx \n"
"push %%ebx \n" /* copy arguments to new stack */
"call *%%eax \n" /* call (*func)(arg); */
"mov 4(%%esp),%%edx \n"
"mov %%edx,%%esp\n" /* restore old stack */
:
: "g"(func), "g"(data), "g"(stack+stack_size)
: "eax", "ebx", "edx", "esp"
);
It was lurked in PTL threading library,
which is the only one which does support preemptive userspace scheduling. Provided
function is indeed called on its own stack. But when signal is delivered,
its $ebp does not contain that stack, but instead it contains address
somewhere in the middle of the new stack, which rised a suspicion, that glibc
installs own signal handler, and then calls my, but experiments with x86_64 test machine
showed, that kernel indeed jumps directly into my own signal handler. Unfortunately
I do not have fast x86 test machine, and do not want to spread power to two arches currently,
so I will setup my VIA C3 test machine and will run some signal tests on its modified
kernel to detect, where exactly stack pointer for interrupted context is stored.
When this issue will be resolved, correct preemptible scheduler for M-on-N threading
model implementation will be just a matter of hours.
/devel/threading :: Link / Comments ()
This year Linux Kernel Summit will be held in Cambridge, England.
According to Theodore Ts'o
this will happen September 5-6.
Up to that date I have some projects to complete, so I think I would participate,
if starts got into the straight line.
Main projects are kevent
of course and netchannels
(with grand network stack breakage and replacement of socket hash tibles).
Additionally I think threading
issues can form a good talk and of course new filesystem
(but only if there will be some results up to that point).
Although I believe that probability of my talks is quite low (and if you likely do not know,
but my english speech skills are somewhere between zero and void, although it is
not a problem for me), it is still possible to move there for a day and meet Abr
(although he is in London) and Mephody (although he is in Limerick, Ireland).
/devel/other :: Link / Comments ()
True context switching in userspace.
After some thinking, I've understood, that setcontext()
approach does not allow to have real context switching - when this function is called,
context is restored from the point where getcontext()/makecontext()
was called last time, so even if one have possibility to restore new context, context being removed
must save its state by itself - obviously no one will do it. So this approach will not be used
at all in my context switching implementation (although I will check getcontext()/makecontext()s
sources, since they contain needed bits).
Let's slightly move away from topic and concentrate on how signals work.
According to my knowledge, signal is just a call for some function in stack -
kernel saves needed context, setups small region on stack of currently executed thread,
saves current context
and calls a special function which ends up with registered handler invocation.
(Interesting note for investigation - how do signals work with non-executable stack -
likely special page is allocated for that purpose, but if it is so, then there is a way
to write explits which can run on stack even when system setups it to be non-executable).
Signal handler can not be reentered, when it is exiting, it restores previous context,
thus creating real context switching.
Returning back to our topic - scheduler's work thus become obvious -
system's signal helper will store current execution context on stack,
then new thread will be selected by registered handler
and its context will be restored when signal will exit instead of
old one, thus true context switching will be performed.
This looks simple in theory, but on practice there are couple of small problems:
- I do not know (even x86) asm enough to code like in C (but I always wanted to hack low-level stuff)
- I do not 100% sure that signals work like I described (but I surely want to know)
- I do not know how it will be easy or not to save/restore context (according to glibc sources,
getcontext()/makecontext() and friends are not too big though)
Actually context switch is a bit more complex - for example virtual mapping should be restored/saved too
for TLS (thread-local storage), on x86 MMU registers must be saved and more generally FPU state
must be saved too, but for initial implementation I think it is not too relevant.
So, enough for theories, it is about an 1 A.M. and I need to sleep - I'm sure this day will be very interesting.
/devel/threading :: Link / Comments ()
|