what code gets executed in kernel when cntrl+c or cntrl+z is invoked while executing a program in command line.
> what code gets executed in kernel when cntrl+c or cntrl+z
> is invoked while executing a program in command line.
I'm sure you can see that in sources. But i'll try to describe it generally, if you don't mind.
there is a notion of controlling terminal
so, if generating signals on "Certain input sequences" isn't switched off (man stty(1)), and terminal is controlling (e.g. not NO_CTTY, man open(2)), then kernel sends signals:
* ctrl+c (0x03)-- SIGINT (fixed)
* ctrl+z (0x1A)-- SIGSTOP
This is a pretty crazy path - hopefully I can give you enough to go on. I'll just deal with ^C.. ^Z is similar.
The controlling tty processes each new character through n_tty_receive_char() in drivers/char/n_tty.c. If that keypress is the termios interrupt character (tested with INTR_CHAR()) then it proceeds to send SIGINT to the process group (assuming there is one) with kill_pgrp(). The interrupt character is ^C by default, but the application can change that if it likes with an ioctl() on the tty or preferably with glibc's tcsetattr().
At this point, the tty code is left behind and it is pretty much the same as if some other process had sent kill(SIGINT) to the code.
kill_pgrp() is in kernel/signal.c.. first it finds each process in the process group, and then calls group_send_sig_info() for each one. Nested in here is send_signal() which sticks the sigint information in a queue of the task's called shared pending.. then it wakes the process up (makes it ready to run) with the signal in the pending state.
I told you it was a twisty path. but we're making progress.
eventually the signalled process starts to run again, and off in architecture specific code (e.g. arch/x86/kernel/signal_32.c) do_notify_resume() is called. This code basically checks to see if, generically speaking, any signal handlers should be invoked instead of wherever the task last left off.
If it finds something it calls do_signal(), which gets the specific signal structure using get_signal_to_deliver() [back in the generic signal.c code] - which checks for blocked signals and all that kind of jazz.. and then actually sets up the new stack frame to run the SIGINT code on and all the ephemera involved in handling the return.
The path is a little different if you don't have a signal handler installed for SIGINT - the default behavior for that signal is simply to terminate. get_signal_to_deliver() checks for that directly and takes care of it inline without ever running the task again (possibly dumping core along the way).
hope this is helpful. kernel/signal.c is interesting reading.
> This is a pretty crazy path - hopefully I can give you enough to go on. > I'll just deal with ^C.. ^Z is similar.
> The controlling tty processes each new character through
> n_tty_receive_char() in drivers/char/n_tty.c.
Before all this there are another crazy things in input (keyboard, usb alike or network), pseudo-TTY and console code. Terminal emulator is a byte checker and kernel signaling is a kind of, as you've said, kill()-like.
So, IMHO, describing all input parts will be more funny :) But it's kind of book chapter or something like that...