On a Linux system, the bash builtin command
disown can be used to remove jobs from the current session. How does bash implement this feature? Is
setsid() used here, and if so, how does bash trigger the child process to invoke
setsid()? Does it use signal?
disown does not remove a job from the current session , does not detach it from the terminal, and does not affect which signals the kernel will send it when the session leader exits or when the controlling terminal is torn down.
disown only works on bash's own job table, only changes bash's idea of which jobs it's in control of, and only affects bash's own behavior, namely which jobs it will resend a
SIGHUP received by the bash process. That
SIGHUP resending is an extra feature of
bash , not required by the standard and not related to the job control provided by the OS.
You can see it with a simple example, where I'm using
script(1) to create a pty and an interactive shell session running in it:
$ script /dev/null -qc bash $ sh -c 'sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666' &  3837 $ disown -a $ jobs # no jobs known to bash $ pgrep -as0 # show all processes from the current session 3836 bash 3837 sh -c sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666 3838 sleep 555 3841 sleep 666 $ kill -HUP $$ # seppuku the session leader Hangup hupped!
Here the kernel sends a
SIGHUP signal to the background process group (= job) because one of its processes is stopped, and disowning it will not prevent that from happening.
All processes from the
sh -c '...' are part of the same job, including the "background"
sleep &; shell scripts don't do job control by default.
If no members of the background process group are stopped, no
SIGHUP is sent:
$ script /dev/null -qc bash $ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' &  3270 $ disown -a $ kill -HUP $$ # sleep 555, 666 and sh -c are still running
Finally, bash will send a
SIGHUP to all the jobs from its table (only those started by itself and not disowned), no matter if bash is the session leader or not, or if the jobs are running, stopped, etc:
$ bash $ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' &  3413 $ kill -HUP $$ Hangup hupped! Hangup
 which would be impossible to do anyway;
setsid() is only able to make into a new session a process which is not a process group leader, there is no way to move a whole job into a new or existing session.
 which is documented in the bash's manpage:
The shell exits by default upon receipt of a
SIGHUP. Before exiting, an interactive shell resends the
SIGHUPto all jobs, running or stopped. Stopped jobs are sent
SIGCONTto ensure that they receive the
SIGHUP. To prevent the shell from sending the signal to a particular job, it should be removed from the jobs table with the
disownbuiltin (see SHELL BUILTIN COMMANDS below) or marked to not receive
There's is also
shopt -s huponexit which cause a login bash shell to send a
HUP to its jobs upon exiting (whether because of a signal or not), which again overlaps in confusing ways with the standard job control features of the OS.