Unix & Linux Stack Exchange
Q&A for users of Linux, FreeBSD and other Unix-like operating systems
Latest Questions
33
votes
12
answers
29787
views
Process descendants
I'm trying to build a process container. The container will trigger other programs. For example - a bash script that launches running background tasks with '&' usage. The important feature I'm after is this: when I kill the container, everything that has been spawned under it should be killed. Not j...
I'm trying to build a process container. The container will trigger other programs. For example - a bash script that launches running background tasks with '&' usage.
The important feature I'm after is this: when I kill the container, everything that has been spawned under it should be killed. Not just direct children, but their descendants too.
When I started this project, I mistakenly believed that when you killed a process its children were automatically killed too. I've sought advice from people who had the same incorrect idea. While it's possible to catch a signal and pass the kill on to children, that's not what I'm looking for here.
I believe what I want to be achievable, because when you close an xterm, anything that was running within it is killed unless it was nohup'd. This includes orphaned processes. That's what I'm looking to recreate.
I have an idea that what I'm loooking for involves unix sessions.
If there was a reliable way to identify all the descendants of a process, it would be useful to be able to send them arbitrary signals, too. e.g. SIGUSR1.
Craig Turner
(430 rep)
Jun 11, 2011, 10:59 AM
• Last activity: Jul 24, 2025, 05:07 PM
42
votes
6
answers
11887
views
Does pressing ctrl-c several times make the running program close more quickly?
I often start to read a huge file and then want to quit after a while, but there is a lag from pressing Ctrl + C to the program stops. Is there a chance of shortening the lag by pressing the Ctrl + C key several times? Or am I wasting my keypresses?
I often start to read a huge file and then want to quit after a while, but there is a lag from pressing
Ctrl+C to the program stops. Is there a chance of shortening the lag by pressing the Ctrl+C key several times? Or am I wasting my keypresses?
Ctrl+C to the program stops. Is there a chance of shortening the lag by pressing the Ctrl+C key several times? Or am I wasting my keypresses?
The Unfun Cat
(3451 rep)
Jan 15, 2014, 07:33 AM
• Last activity: Jul 8, 2025, 10:00 AM
30
votes
3
answers
3596
views
Why does 'ping' not output a summary when redirecting output?
I can ping *google.com* for several seconds and when I press Ctrl + C , a brief summary is displayed at the bottom: $ ping google.com PING google.com (74.125.131.113) 56(84) bytes of data. 64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=2 ttl=56 time=46.7 ms 64 bytes from lu-in-f113.1e...
I can ping *google.com* for several seconds and when I press Ctrl + C, a brief summary is displayed at the bottom:
$ ping google.com
PING google.com (74.125.131.113) 56(84) bytes of data.
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=2 ttl=56 time=46.7 ms
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=3 ttl=56 time=45.0 ms
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=4 ttl=56 time=54.5 ms
^C
--- google.com ping statistics ---
4 packets transmitted, 3 received, 25% packet loss, time 3009ms
rtt min/avg/max/mdev = 44.965/48.719/54.524/4.163 ms
However, when I do the same redirecting output to log file with
tee
, the summary is not displayed:
$ ping google.com | tee log
PING google.com (74.125.131.113) 56(84) bytes of data.
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=1 ttl=56 time=34.1 ms
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=2 ttl=56 time=57.0 ms
64 bytes from lu-in-f113.1e100.net (74.125.131.113): icmp_seq=3 ttl=57 time=50.9 ms
^C
Can I get the summary as well when redirecting output with tee
?
ks1322
(1670 rep)
Jan 22, 2022, 11:03 AM
• Last activity: Jun 29, 2025, 06:11 PM
23
votes
5
answers
22097
views
Ctrl-C with two simultaneous commands in bash
I want to run two commands simultaneously in bash on a Linux machine. Therefore in my `./execute.sh` bash script I put: command 1 & command 2 echo "done" However when I want to stop the bash script and hit Ctrl + C , only the second command is stopped. The first command keeps running. How do I make...
I want to run two commands simultaneously in bash on a Linux machine. Therefore in my
./execute.sh
bash script I put:
command 1 & command 2
echo "done"
However when I want to stop the bash script and hit Ctrl+C, only the second command is stopped. The first command keeps running.
How do I make sure that the complete bash script is stopped? Or in any case, how do I stop both commands? Because in this case no matter how often I press Ctrl+C the command keeps running and I am forced to close the terminal.
maero21
(333 rep)
Jan 1, 2014, 01:54 PM
• Last activity: Mar 21, 2025, 11:25 AM
1
votes
2
answers
38
views
Why a signal that is blocked not shown up in SigPnd of /proc/pid/status when it is sent
**Fact** 1. A signal may be blocked, which means that it will not be delivered until it is later unblocked. Between the time when it is generated and when it is delivered a signal is said to be pending. [Manpage](https://man7.org/linux/man-pages/man7/signal.7.html) 2. SigPnd (in /proc/pid/status): M...
**Fact**
1. A signal may be blocked, which means that it will not be delivered
until it is later unblocked. Between the time when it is
generated and when it is delivered a signal is said to be pending. [Manpage](https://man7.org/linux/man-pages/man7/signal.7.html)
2. SigPnd (in /proc/pid/status): Mask (expressed in hexadecimal) of signals pending
for thread and for process as a whole [Manpage](https://man7.org/linux/man-pages/man5/proc_pid_status.5.html)
==> So if a signal is being blocked by a process and I send the signal to that process, that signal is "pending" and should show up in SigPnd.
**Situation**
I blocked a signal, say SIGUSR2, with
sigprocmask
.
This is the result of /proc/pid/status
SigQ: 0/21148
SigPnd: 0000000000000000
SigBlk: 0000000000000aec
SigIgn: 0000000000000200
SigCgt: 0000000000000000
SigBlk shows that SIGUSR2 is being
Then I send SIGUSR2 with kill
**Expectation**
SigPnd: 0000000000000aec
because SIGUSR2 is being blocked so it is not delivered (aka pending)
**Reality**
SigPnd: 0000000000000000
**Question**
Why SigPnd does not show up as my expectation?
Tran Triet
(715 rep)
Mar 1, 2025, 10:23 AM
• Last activity: Mar 5, 2025, 05:01 PM
8
votes
2
answers
10916
views
Wait for signal
In a `bash` script, is there a simple way to wait for a signal, something like: wait -s SIGINT or whatever? Maybe just `trap`?
In a
bash
script, is there a simple way to wait for a signal, something like:
wait -s SIGINT
or whatever? Maybe just trap
?
Alexander Mills
(10734 rep)
Jun 19, 2018, 05:20 AM
• Last activity: Mar 2, 2025, 10:33 AM
2
votes
1
answers
74
views
Detectng missed SIGWINCH in Bash extension, when apparent terminal size has not changed
I maintain an extension for the Bash environment called [Basta](https://www.kylheku.com/cgit/basta/about). Basta provides a scroll-protected status line at the bottom of your ANSI/VT100 terminal. When Basta sets itself up, the effective number of lines, as known by the termios stuff in the kernel an...
I maintain an extension for the Bash environment called [Basta](https://www.kylheku.com/cgit/basta/about) . Basta provides a scroll-protected status line at the bottom of your ANSI/VT100 terminal.
When Basta sets itself up, the effective number of lines, as known by the termios stuff in the kernel and the shell
LINES
variable decreases by 1. Resizing the terminal is handled nicely. Almost. There is trap
for the SIGWINCH
signal to call the update routine, which is also called after every command, prior to returning to the prompt.
However, from time to time I see a situation in which the scrolling region is lost. The prompt is being painted over the bottom line, where the user is editing commands and where command output appears, resulting in a mess.
I have a hypothesis on one how it can occur, which has reliable repro steps.
1. We run a program that waits for input, while Bash is in the background, such as cat
.
2. While this program is running, we resize the window such that we shrink it by one line.
3. Terminate the cat
program.
If the terminal is resized while cat
is running, Bash does not get the SIGWINCH
(because, I think, SIGWINCH
is only sent to the processes in the terminal sessions foreground process group, and Bash is in the Background at that moment). Our trap
does not execute.
Basta's update function also relies on comparing the previous terminal size to the current to detect a size change.
**Here is the problem:** in this situation where a terminal with a scroll-protected status like has shrunk by one line, the **number of lines appears not to have changed**.
E.g. 40 line screen with 39 line scrolling region: LINES=39
. Resize terminal to be 39 lines long. Scrolling region is gone. LINES=39
again. To the software, it looks like the same size, so it concludes that there has not been a resize. The status line is now being painted over top of the bottom row, over top of the user's input, because Basta wants to put it on row 40, which doesn't exist any more, so the cursor clamps to 39.
If Basta knows what a window size change occurred, it will not do the size comparison; in that situation it takes the slow path whereby it queries the terminal itself to determine the size. (It would be undesirable to do that for each update, because sending queries to the terminal is dodgy. If the user is typing rapidly, the terminal response can get mixed up with their keystrokes, and there can be a noticeable delay in getting a response from the terminal over laggy remote connections.)
Is there any clever way to know that the terminal has changed (or at least suspect it with a reasonably low false positive rate), in the absence of having received the WINCH
trap, due to having been in the background, without talking to the terminal?
Kaz
(8867 rep)
Feb 7, 2025, 07:54 PM
• Last activity: Feb 11, 2025, 02:04 AM
17
votes
3
answers
2012
views
Why have SIGPIPE when EPIPE exists?
According to [`pipe(7)`](https://linux.die.net/man/7/pipe): > If all file descriptors referring to the read end of a pipe have been closed, then a `write(2)` will cause a `SIGPIPE` signal to be generated for the calling process. If the calling process is ignoring this signal, then `write(2)` fails w...
According to [
pipe(7)
](https://linux.die.net/man/7/pipe) :
> If all file descriptors referring to the read end of a pipe have been closed, then a write(2)
will cause a SIGPIPE
signal to be generated for the calling process. If the calling process is ignoring this signal, then write(2)
fails with the error EPIPE
.
Why does Unix need to have the SIGPIPE
signal when write()
can simply return EPIPE
directly? My understanding is that signals are intended for things that are inherently asynchronous (e.g. termination of a child, terminal interrupt). But SIGPIPE
is only ever generated as the immediate result of a call to write()
, in which case it could always just return EPIPE
to to caller to signify the error to the caller.
Why was it deemed necessary to have SIGPIPE
in addition to EPIPE
?
CarmenCarmen
(195 rep)
Aug 2, 2024, 01:49 AM
• Last activity: Feb 3, 2025, 12:37 PM
3
votes
2
answers
136
views
Why does the linux manual say nothing about generating a SIGCHLD signal when the child resumes execution?
I am using linux (ubuntu). When I type `man 7 signal` (manual 2020-12-21) in my terminal, I find the following for the SIGCHLD: SIGCHLD P1990 Ign Child stopped or terminated So, it states that the `SIGCHLD` signal is only generated in this two cases. It says nothing about when the child process cont...
I am using linux (ubuntu).
When I type
man 7 signal
(manual 2020-12-21) in my terminal, I find the following for the SIGCHLD:
SIGCHLD P1990 Ign Child stopped or terminated
So, it states that the SIGCHLD
signal is only generated in this two cases. It says nothing about when the child process continues.
However, in POSIX, it states the following:
SIGCHLD Child process terminated, stopped,
[XSI] or continued.
Thus, when OS supports XSI, this signal is also generated when the child continues. I also write some simple child/parent programs and can confirm it. **Since linux supports XSI, why does the manual not include "continue" scenario for the SIGCHLD as well? What is the purpose of manual when it's incomplete (or I am missing its purpose?)**
Also I found [the following answers](https://unix.stackexchange.com/questions/6332/what-causes-various-signals-to-be-sent) for SIGCHLD then incomplete.
---
Below is the code. It is a simple golang code. The parent starts the child via the classic fork/exec. It then registers a handler for the SIGCHLD signal and that's it. Both parent and child print a message every 10 seconds. After building both programs, I run them via ./parent
command. I control the behavior (T
R/S
state) of the child process via kill -SISTOP child_process_id
and kill -SIGCONT child_process_id
.
Parent:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
if err != nil {
fmt.Println("Error:", err)
return
}
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGCHLD)
go func() {
for {
select {
case <-ch:
fmt.Println("SIGNAL")
}
}
}()
for {
fmt.Println("Parent is live")
time.Sleep(10 * time.Second)
}
}
Child:
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("hi from child")
time.Sleep(time.Second * 10)
}
}
Yakog
(517 rep)
Jan 25, 2025, 02:39 PM
• Last activity: Feb 2, 2025, 01:30 PM
5
votes
3
answers
859
views
What documentation shows the associated numbers for linux signals like SIGTERM and SIGKILL?
I can look around the internet and find that the associated number for SIGKILL is 9, but is there linux documentation (such as, a man page) showing the complete list of signals and their numbers?
I can look around the internet and find that the associated number for SIGKILL is 9, but is there linux documentation (such as, a man page) showing the complete list of signals and their numbers?
Cory Klein
(19341 rep)
Feb 17, 2011, 06:16 PM
• Last activity: Jan 26, 2025, 12:58 PM
2
votes
1
answers
239
views
Why does the SIGCHLD generated by process continuation not activate the trap?
I am using linux (Ubuntu) and bash. I made a simple Go program. Literally infinite for-loop that prints text every 20 seconds. ```go package main import ( "fmt" "time" ) func main() { for { fmt.Println("Hi from program 1") time.Sleep(time.Second * 20) } } ``` First, I register a trap for the `SIGCHL...
I am using linux (Ubuntu) and bash.
I made a simple Go program. Literally infinite for-loop that prints text every 20 seconds.
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("Hi from program 1")
time.Sleep(time.Second * 20)
}
}
First, I register a trap for the SIGCHLD
signal using the command:
trap 'echo "hi you"' SIGCHLD
Next, I start a program asynchronously (in the background) with:
./program &
I started it as background job so bash can use terminal. When I execute the command:
kill -SIGSTOP process_id
the trap is triggered, and the message "hi you" is displayed as expected. However, when I run:
kill -SIGCONT process_id
to resume the process, the process continues running (printing "Hi from program 1"), but trap message ("hi you") is not displayed. I invoke these kill
commands from another terminal.
I found in [the bash documentation](https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html) the following:
> Any trap on SIGCHLD is executed for each child process that exits.
I could understand it as exclusive. In other words, that the SIGCHLD
trap is activated only when the child process exits. If so, it would be clear to me why my example does not work. However, the SIGCHLD
trap is also activated when the child process is suspended.
Why is this happening? Resuming the process also generates a SIGCHLD
signal, so why doesn’t the trap trigger in this case?
---
Related [question](https://unix.stackexchange.com/questions/790116/why-does-the-linux-manual-say-nothing-about-generating-a-sigchld-signal-when-the) .
Yakog
(517 rep)
Jan 25, 2025, 08:44 AM
• Last activity: Jan 25, 2025, 07:39 PM
2
votes
1
answers
61
views
Why does the termination of the parent terminate the child when it is in the suspend (T) state?
I am using Ubuntu (linux). I have the following two simple programs. Parent: ```go package main import ( "fmt" "syscall" "time" ) func main() { attr := &syscall.ProcAttr{ Files: []uintptr{0, 1, 2}, Sys: &syscall.SysProcAttr{ // child in its own group Setpgid: true, Pgid: 0, }, } _, err := syscall.Fo...
I am using Ubuntu (linux).
I have the following two simple programs.
Parent:
package main
import (
"fmt"
"syscall"
"time"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
Sys: &syscall.SysProcAttr{ // child in its own group
Setpgid: true,
Pgid: 0,
},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
if err != nil {
fmt.Println("Error:", err)
return
}
for {
fmt.Println("Parent is live")
time.Sleep(10 * time.Second)
}
}
Child (child in its own group):
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("hi from child")
time.Sleep(time.Second * 20)
}
}
After starting the parent program (./parent
), the result of calling the ps
(specifically, ps -t /dev/pts/0 -o pid,ppid,pgid,stat,comm
) command is as follows:
PID PPID PGID STAT COMMAND
466922 466896 466922 Ss bash
467049 466922 467049 Sl+ parent
467054 467049 467054 Sl child
After terminating the parent process (either with kill -SIGKILL 467049
, kill -SIGINT 467049
or CTRL-C
), child continues to work (S/R state). This is exactly what I expect.
PID PPID PGID STAT COMMAND
466922 466896 466922 Ss+ bash
467054 467049 467054 Sl child
What confuses me is the following scenario. Firstly, I start the parent process (./parent
). Result of the ps
command is the same as in the previous case. Then I suspend the child process with kill -SIGTSTP 467054
or kill -SIGSTOP 467054
. The result of ps
command is the following:
PID PPID PGID STAT COMMAND
466922 466896 466922 Ss bash
467049 466922 467049 Sl+ parent
467054 467049 467054 Tl child
Then, I terminate the parent process (either with kill -SIGKILL 467049
, kill -SIGINT 467049
or CTRL-C
). **For some reason, in this case child is terminated as well!** Result of the ps
command:
PID PPID PGID STAT COMMAND
466922 466896 466922 Ss+ bash
**How? Why?**
Yakog
(517 rep)
Jan 22, 2025, 11:03 AM
• Last activity: Jan 22, 2025, 01:38 PM
7
votes
2
answers
2424
views
Sending SIGINT to process groups sometimes gets ignored
I start a process group from bash. Then I send SIGINT to the entire process group. Sometimes the SIGINT kills the processes, sometimes does not. Why does SIGINT sometimes gets ignored ? I see different behavior depending on whether the process group is started in the background or not, on nestedness...
I start a process group from bash. Then I send SIGINT to the entire process
group. Sometimes the SIGINT kills the processes, sometimes does not. Why does
SIGINT sometimes gets ignored ?
I see different behavior depending on whether the process group is started in
the background or not, on nestedness of bash shells and on Mac/Linux operating
system. I would really appreciate if someone can shed some light on this.
In the following examples I use this python executable called
sleep_in_pgrp.py
#!/usr/bin/env python2.7
import os;
import subprocess
os.setpgrp();
subprocess.check_call(["sleep","10000"]);
It creates a process group and starts sleep. The observed phenomena should not
be related to python. I use python only because bash does not have a setpgrp
command or builtin. **Update**: Apparently one could also run an interactive
shell to create a [new process group](https://unix.stackexchange.com/a/18711/212862)
**1) Start the process group in the background and wait on the leader. SIGINT gets ignored.**
Execute the following command:
$ bash -c ' { sleep_in_pgrp.py; } & wait $! '
Bash starts python in the background and waits on it.
In another terminal:
$ ps -Heo pid,ppid,tpgid,pgid,sid,user,args
PID PPID TPGID PGID SID COMMAND
2507 1574 2963 2507 2507 -bash
2963 2507 2963 2963 2507 bash -c { sleep_in_pgrp.py; } & wait $!
2964 2963 2963 2963 2507 bash -c { sleep_in_pgrp.py; } & wait $!
2965 2964 2963 2965 2507 python2.7 ./sleep_in_pgrp.py
2966 2965 2963 2965 2507 sleep 10000
SIGINT’ing the proccess group of python **does not kill any processes**. What can be the reason ?
$ sudo kill -s SIGINT -- -2965
**2) Start the process group in the foreground. SIGINT works.**
If I remove the & wait $!
, SIGINT kills the process group as expected. I do not know why but I am not surprised SIGINT killed the processes in this case.
$ bash -c ' { sleep_in_pgrp.py; } '
In another terminal:
$ ps -Heo pid,ppid,tpgid,pgid,sid,user,args
PID PPID TPGID PGID SID COMMAND
2507 1574 3352 2507 2507 -bash
3352 2507 3352 3352 2507 bash -c { sleep_in_pgrp.py; }
3353 3352 3352 3353 2507 python2.7 ./sleep_in_pgrp.py
3354 3353 3352 3353 2507 sleep 10000
SIGINT kills the process group.
$ sudo kill -s SIGINT -- -3353
**3) Removing the subshell while running python in the background. SIGINT works.**
I was very surprised that the shell nestedness affects the behavior here. I cannot think of any explanation why.
I remove the bash -c
at the start:
$ { sleep_in_pgrp.py; } & wait $!
In another terminal:
$ ps -Heo pid,ppid,tpgid,pgid,sid,user,args
PID PPID TPGID PGID SID COMMAND
2507 1574 2507 2507 2507 -bash
3488 2507 2507 3488 2507 -bash
3489 3488 2507 3489 2507 python2.7 ./sleep_in_pgrp.py
3490 3489 2507 3489 2507 sleep 10000
SIGINT kills the process group.
$ sudo kill -s SIGINT -- -2507
**4) Running the first command in Mac: SIGINT works.**
The first 2 commands ran in a CentOs7 VM.
$ uname -a
Linux ip-10-229-193-124 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 13 10:46:25 EDT 2017 x86_64 x86_64 x86_64 GNU/Linux
I now execute the first command with backgrounded python in a subshell in mac.
$ uname -a
Darwin mbp-005063 15.6.0 Darwin Kernel Version 15.6.0: Sun Jun 4 21:43:07 PDT 2017; root:xnu-3248.70.3~1/RELEASE_X86_64 x86_64
In Mac:
$ bash -c ' { sleep_in_pgrp.py; } & wait $! '
In another terminal:
$ PID PPID TPGID PGID SESS COMMAND
18741 40096 18741 18741 0 bash -c { sleep_in_pgrp.py; } & wait $!
18742 18741 18741 18741 0 bash -c { sleep_in_pgrp.py; } & wait $!
18743 18742 18741 18743 0 /usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python ./sleep_in_pgrp.py
18744 18743 18741 18743 0 sleep 10000
40094 2423 18741 40094 0 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server /usr/bin/login -fpl hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
40095 40094 18741 40095 0 /usr/bin/login -fpl hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
40096 40095 18741 40096 0 -bash
-+= 00001 root /sbin/launchd
\-+= 02423 hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2
\-+= 40094 hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2 --server /usr/bin/login -fpl hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
\-+= 40095 root /usr/bin/login -fpl hbaba /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
\-+= 40096 hbaba -bash
\-+= 18741 hbaba bash -c { sleep_in_pgrp.py; } & wait $!
\-+- 18742 hbaba bash -c { sleep_in_pgrp.py; } & wait $!
\-+= 18743 hbaba /usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python ./sleep_in_pgrp.py
\--- 18744 hbaba sleep 10000
And in this case, SIGINT also kills the process group
$ sudo kill -s INT -18743
Bash version in CentOs7 is
$ echo $BASH_VERSION
4.2.46(2)-release
In Mac the bash version is
$ echo $BASH_VERSION
4.4.12(1)-release
----------------------------
This [answer](https://unix.stackexchange.com/a/149756/212862) explains how
Ctrl+C sends SIGINT to the process group. That is what I am trying to do here
sending SIGINT to a process group.
This [answer](https://unix.stackexchange.com/a/256318/212862) mentions that non
interactive jobs require a SIGINT handler. I am not sure it explains the
varying behavior I see. I am also wondering whether waiting on a background
process affects the SIGINT handling by that process.
Hakan Baba
(919 rep)
Oct 29, 2017, 08:03 AM
• Last activity: Jan 21, 2025, 06:00 AM
1
votes
2
answers
104
views
Why does the kill command not work for SIGTSTP, but works for some other signals (SIGSTOP/SIGINT etc.)?
I have the following two simple programs. Parent: ```go package main import ( "fmt" "syscall" ) func main() { attr := &syscall.ProcAttr{ Files: []uintptr{0, 1, 2}, Sys: &syscall.SysProcAttr{ // child in its own group Setpgid: true, Pgid: 0, }, } _, err := syscall.ForkExec("./child/child", []string{"...
I have the following two simple programs.
Parent:
package main
import (
"fmt"
"syscall"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
Sys: &syscall.SysProcAttr{ // child in its own group
Setpgid: true,
Pgid: 0,
},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
if err != nil {
fmt.Println("Error:", err)
return
}
}
Child:
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("hi from child")
time.Sleep(time.Second * 5)
}
}
Output of the ps
:
yakog@yakog-computer:~/goprojects/parent$ ps -o pid,ppid,pgid,uid,wchan,stat,tt,command -t /dev/pts/19
PID PPID PGID UID WCHAN STAT TT COMMAND
1867701 1867320 1867701 1000 do_sel Ss+ pts/19 bash
1870508 2118 1870508 1000 ep_pol Sl pts/19 child
When I press CTRL-Z
or CTRL-C
, it doesn't have any effect. That's exactly what I expect since the process 1870508 is not part of the foreground job and CTRL-Z
/CTRL-C
invokes kill -SIGTSTP -1867701
/kill -SIGINT -1867701
. Thus, 1870508 doesn't receive these signals.
Also, when I invoke kill -SIGINT 1870508
or kill -SIGSTOP 1870508
, the process is terminated/suspended. I still can understand it. Although 1870508 is not part of the foreground job, with kill
command **we "directly" send the signal to the process**.
However, why does kill -SIGTSTP 1870508
not work? After starting the ./parent
process and calling kill -SIGTSTP 1870508
command, literally nothing happens (the 1870508 still has status R
/S
and continues to print to the terminal). I can't understand why it didn't suspend the process (moved it to T
). It's should be same as with -SIGINT
and -SIGSTOP
(**we "directly" send -SIGTSTP to the process**), however, it has not effect in this case.
What is strange is that if we change parent code (code below) and make it continues the execution after the child is created, then kill -SIGTSTP 1870508
works as it should (child is suspended).
package main
import (
"fmt"
"os/signal"
"syscall"
"time"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
Sys: &syscall.SysProcAttr{ // child in its own group
Setpgid: true,
Pgid: 0,
},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
signal.Ignore(syscall.SIGTSTP)
if err != nil {
fmt.Println("Error:", err)
return
}
for {
fmt.Println("hi from parent")
time.Sleep(time.Second * 7)
}
}
----
Additionally, when I invoke kill -SIGSTOP 1870508
(move process to T
state) and then invoke kill -SIGINT 1870508
it doesn't terminate process... Why?
Yakog
(517 rep)
Jan 13, 2025, 09:48 PM
• Last activity: Jan 14, 2025, 10:21 AM
0
votes
1
answers
117
views
Why does a SIGTSTP signal not handled by the parent move the entire group to the background (contrary to written in TTY demystified)?
I started learning about linux tty(s) and signals and ran into some trouble. I am reading and using [The TTY demystified](https://www.linusakesson.net/programming/tty/) as a reference. I made two simple golang programs. Parent: ```go package main import ( "fmt" "syscall" "time" ) func main() { attr...
I started learning about linux tty(s) and signals and ran into some trouble.
I am reading and using [The TTY demystified](https://www.linusakesson.net/programming/tty/) as a reference.
I made two simple golang programs.
Parent:
package main
import (
"fmt"
"syscall"
"time"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
if err != nil {
fmt.Println("Error:", err)
return
}
for {
fmt.Println("hi from parent")
time.Sleep(time.Second * 10)
}
}
Child:
package main
import (
"fmt"
"os/signal"
"syscall"
"time"
)
func main() {
signal.Ignore(syscall.SIGTSTP) // golang's way to handle (ignore) signal
for {
fmt.Println("hi from child")
time.Sleep(time.Second * 5)
}
}
They are quite simple. Both just print a message to tty every 5/10 seconds. The only difference is that the child ignores the SIGTSTP (ctrl-z) signal. So when I press ctrl-z it suspends the parent but not the child. That's exactly what I expect. However, what I didn't expect is that the whole group is moved from the foreground to the background group. It contrasts with [The TTY demystified](https://www.linusakesson.net/programming/tty/) . Specifically:
> **When all processes in the foreground job have been suspended**, the
> session leader reads the current configuration from the TTY device,
> and stores it for later retrieval. The session leader goes on to
> install itself as the current foreground process group for the TTY
> using an ioctl call. Then, it prints something like "+ Stopped" to
> inform the user that a job was just suspended.
It says that only when **all processes in the foreground job have been suspended**, the session leader (shell/bash) moves the group to the background job...
Result of ps l -t /dev/pts/0
before and after ctrl-z:
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1747467 1747441 20 0 14288 5632 do_wai Ss pts/0 0:00 bash
0 1000 1747496 1747467 20 0 1225432 1792 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1747501 1747496 20 0 1225424 1664 ep_pol Sl+ pts/0 0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1747467 1747441 20 0 14288 5632 do_sel Ss+ pts/0 0:00 bash
0 1000 1747496 1747467 20 0 1225432 1792 do_sig Tl pts/0 0:00 ./parent
0 1000 1747501 1747496 20 0 1225680 1792 ep_pol Sl pts/0 0:00 child
If I move the ignore (signal.Ignore(syscall.SIGTSTP)
) from the child to the parent, then everything works as it should (from my point of view). The child suspends (T), the parent resumes normally (R/S), but the group is still the foreground job.
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1749437 1749410 20 0 14420 5632 do_wai Ss pts/0 0:00 bash
0 1000 1749957 1749437 20 0 1225448 1920 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1749962 1749957 20 0 1225412 1664 ep_pol Sl+ pts/0 0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1749437 1749410 20 0 14420 5632 do_wai Ss pts/0 0:00 bash
0 1000 1749957 1749437 20 0 1225448 1920 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1749962 1749957 20 0 1225668 1792 do_sig Tl+ pts/0 0:00 child
Why is this happening, what am I missing?
Yakog
(517 rep)
Jan 12, 2025, 01:36 AM
• Last activity: Jan 12, 2025, 09:17 AM
0
votes
0
answers
47
views
Why does sudo change process session id using setsid()?
I've been writing a script that spawns a child process as a different user via `sudo` then I realized that my script is not getting SIGINT as opposed to when I run it without `sudo`. As suspected strace shows that [sudo](https://man7.org/linux/man-pages/man8/sudo.8.html) calls [setsid](https://www.m...
I've been writing a script that spawns a child process as a different user via
sudo
then I realized that my script is not getting SIGINT as opposed to when I run it without sudo
.
As suspected strace shows that [sudo](https://man7.org/linux/man-pages/man8/sudo.8.html) calls [setsid](https://www.man7.org/linux/man-pages/man2/setsid.2.html) after [clone](https://man7.org/linux/man-pages/man2/clone.2.html) which means my (python) scripts are in a different process-group and don't receive the same signals as the sudo process.
What would be the reason sudo
calls setsid
? Is there security benefit? Why isn't there an equivalent of su --session-command
option to disable this behavior (which is also discouraged according to man page)?
Ahmet Sait
(101 rep)
Jan 3, 2025, 08:45 PM
1
votes
1
answers
69
views
Hit a strange signal settings of a kernel thread in Linux
I am working on an embedded Linux system (kernel-5.10.24), and using `busybox` as `init`. Now I hit a strange problem about `signal` settings of a kernel thread in system. The kernel thread is from a device driver, and by `cat /proc/pid/status`, I found its signal settings are as follows, ``` SigQ:...
I am working on an embedded Linux system (kernel-5.10.24), and using
busybox
as init
.
Now I hit a strange problem about signal
settings of a kernel thread in system.
The kernel thread is from a device driver, and by cat /proc/pid/status
, I found its signal settings are as follows,
SigQ: 0/31126
SigPnd: 0000000000000000
ShdPnd: 0000000000004000
SigBlk: 0000000000000000
SigIgn: ffffffffffffbfff
SigCgt: 0000000000004000
Other kernel threads have 0xffffffffffffffff
of SigIgn
.
The kernel thread is started with kthread_run()
as other threads do.
The setting of SigCgt
and ShdPnd
make the kernel thread unable to go into waiting
status, instead, the kernel thread now is in a busy-loop on down_interruptible
.
So I am wondering is it correct about the kernel thread's signal settings? Where are the signal settings configured for kernel thread, is it possible for me to customize this settings, if so, how to??
wangt13
(631 rep)
Dec 23, 2024, 11:40 AM
• Last activity: Dec 24, 2024, 03:16 AM
1
votes
2
answers
66
views
Failed to core dump with send_sig(task, SIGSEGV, 1) from Linux kernel
I am working in an embedded Linux system, and now I want to trigger a core dump from within kernel by using `send_sig(task, SIGSEGV, 1)`. There is a process A having 10 threads, occasionally, there is a kernel `oops` occurred and at that time, one thread of A is the `current` process reported by ker...
I am working in an embedded Linux system, and now I want to trigger a core dump from within kernel by using
send_sig(task, SIGSEGV, 1)
.
There is a process A having 10 threads, occasionally, there is a kernel oops
occurred and at that time, one thread of A is the current
process reported by kernel.
So I want to dump the core of the process A to find out what happened. So I did followings.
1. Enable core dump in kernel configuration.
2. Running ulimit -c unlimited
in init script.
3. echo '/mnt/core.%p.%e' > /proc/sys/kernel/core_pattern
.
4. Changed the kernel oops codes to call send_sig(task_A, SIGSEGV, 1)
to send SIGSEGV
to the process A.
Then I tried to reproduce the kernel oops
, and I found the log of Segmentation Fault
from process A, but I did NOT see any core dumped in /mnt/
.
If I changed the process A to access 0
of address, it can trigger a core dump correctly.
Why it failed to dump core from my kernel codes (the process A did is killed by SIGSEGV
)? And how can I trigger a core-dump to capture the user space context in the case of kernel oops
???
wangt13
(631 rep)
Dec 2, 2024, 11:38 AM
• Last activity: Dec 4, 2024, 03:08 AM
1
votes
1
answers
58
views
Prevent SIGINT propagation from subshell to parent shell in Zsh
I need to prevent SIGINT (Ctrl-C) from propagating from a subshell to its parent shell functions in Zsh. Here's a minimal example: ``` function sox-record { local output="${1:-$(mktemp).wav}" ( rec "${output}" trim 0 300 # Part of sox package ) echo "${output}" # Need this to continue executing afte...
I need to prevent SIGINT (Ctrl-C) from propagating from a subshell to its parent shell functions in Zsh.
Here's a minimal example:
function sox-record {
local output="${1:-$(mktemp).wav}"
(
rec "${output}" trim 0 300 # Part of sox package
)
echo "${output}" # Need this to continue executing after Ctrl-C
}
function audio-postprocess {
local audio="$(sox-record)"
# Process the audio file...
echo "${audio}"
}
function audio-transcribe {
local audio="$(audio-postprocess)"
# Send to transcription service...
transcribe_audio "${audio}" # Never reached if Ctrl-C during recording
}
The current workaround requires trapping SIGINT at every level, which leads to repetitive, error-prone code:
function sox-record {
local output="${1:-$(mktemp).wav}"
setopt localtraps
trap '' INT
(
rec "${output}" trim 0 300
)
trap - INT
echo "${output}"
}
function audio-postprocess {
setopt localtraps
trap '' INT
local audio="$(sox-record)"
trap - INT
# Process the audio file...
echo "${audio}"
}
function audio-transcribe {
setopt localtraps
trap '' INT
local audio="$(audio-postprocess)"
trap - INT
# Send to transcription service...
transcribe_audio "${audio}"
}
When the user presses Ctrl-C to stop the recording, I want: 1. The rec
subprocess to terminate (working) 2. The parent functions to continue executing (requires trapping SIGINT in every caller)
I know that:
- SIGINT is sent to all processes in the foreground process group
- Using setsid
creates a new process group but prevents signals from reaching the child
- Adding trap '' INT
in the parent requires all callers to also trap SIGINT to prevent propagationj
Is there a way to isolate SIGINT to just the subshell without requiring signal handling in all parent functions? Or is this fundamentally impossible due to how Unix process groups and signal propagation work?
---
I took a look at [this question](https://unix.stackexchange.com/questions/80975/preventing-propagation-of-sigint-to-parent-process) , and I tried this:
function sox-record {
local output="${1:-$(mktemp).wav}"
zsh -mfc "rec "${output}" trim 0 300" &2 || true
echo "${output}"
}
While this works when I just call sox-record
, when I call a parent function like audio-postprocess
, Ctrl-C doesn't do anything. (And I have to use pkill
to kill rec
.)
function audio-postprocess {
local audio="$(sox-record)"
# Process the audio file...
echo "${audio}"
}
HappyFace
(1694 rep)
Nov 3, 2024, 04:34 PM
• Last activity: Nov 3, 2024, 06:07 PM
3
votes
2
answers
432
views
How is PID 1 made special and unkillable?
Using docker, I recently found that PID 1 is by default unkillable by `SIGTERM`. Yet you can still catch `SIGTERM` in PID 1 if you setup a handler in the process. So this doesn't seem to be the case of the kernel just masking `SIGTERM` for PID 1. How is this implemented? How does the process as PID...
Using docker, I recently found that PID 1 is by default unkillable by
SIGTERM
. Yet you can still catch SIGTERM
in PID 1 if you setup a handler in the process. So this doesn't seem to be the case of the kernel just masking SIGTERM
for PID 1.
How is this implemented? How does the process as PID 1 have the default SIGTERM
handler be a noop?
rrauenza
(852 rep)
May 17, 2024, 10:18 PM
• Last activity: Oct 14, 2024, 02:36 AM
Showing page 1 of 20 total questions