The tty driver (specifically the line discipline) will send the signal directly to the foreground process group. Here's the code from Linux, where you can see that it simply gets the foreground group and signals it:
/**
* [...]
* Called when a signal is being sent due to terminal input.
* [...]
*/
static void __isig(int sig, struct tty_struct *tty)
{
struct pid *tty_pgrp = tty_get_pgrp(tty);
if (tty_pgrp) {
kill_pgrp(tty_pgrp, sig, 1);
put_pid(tty_pgrp);
}
}
This is invoked from the input processing function in the same file, where n_tty_receive_signal_char
is just a few short hops from invoking __isig
:
/**
* [...]
* Process an individual character of input received from the driver.
* This is serialized with respect to itself by the rules for the
* driver above.
* [...]
*/
static int
n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
/* [...] */
if (L_ISIG(tty)) {
if (c == INTR_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGINT, c);
return 0;
} else if (c == QUIT_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGQUIT, c);
return 0;
} else if (c == SUSP_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGTSTP, c);
return 0;
}
}