Can a process background itself?
What would be a Perl and/or C implementation of this?
Can a process background itself?
What would be a Perl and/or C implementation of this?
I just want to answer the literal question here: can a process background itself, as opposed to fork itself, continue execution in the child and exit so that the process waiting for it can resume execution already covered by others here.
A note on terminology first here.
Backgrounding is usually referring to job control in interactive shells.
Like when you run a command with &
appended. Or press Ctrl+Z and run bg
afterwards.
Jobs there are not processes they are process groups. When you run:
$ ps -ej | grep -w "$$" & echo "$!"
35131
19152 19152 19152 pts/0 00:00:00 zsh
35130 35130 19152 pts/0 00:00:00 ps
35131 35130 19152 pts/0 00:00:00 grep
It's the ps | grep
job (here implemented via that 35130 process group whose leader is the process running ps
but also contains the process running grep
) that is put in background.
Backgrounding here means:
^C
/^Z
/^\
, etc.Now the backgrounding wording is sometimes used outside of terminal job control.
When you do:
cmd1 | cmd2 & pid=$!
somecommand
wait
in a script, there is no job control. If that script is started in a terminal by an interactive shell, it will be itself put in either foreground or background depending on how the script was started like any other command.
but that cmd1 | cmd2
in the script will not be put in background by the shell interpreting the script as it's not an interactive shell.
If you press ^C, cmd1
and cmd2
will be killed just the same alongside the shell running the script, and suspended when you press ^Z. Instead of saying that cmd1 | cmd2
is started in background, it's more correct to say that they are being run asynchronously.
Compared to a job started in background in an interactive shell, only 1 is done. No process group is created to run that pipeline.
Now, with that clarified, can a process put itself in background?
As it's jobs and not processes that are put in background, the questions for that process would be:
If we can answer yes to all those, that is if we're being called as a simple command (not as part of pipeline or compound command) from an interactive shell in a terminal, then we would need to (1) tell the waiting shell to stop waiting for us, (2) tell the terminal that its process group is no longer the foreground one and (3) tell the shell to update its job table to record the fact that we're now in background.
You can't really tell another process to stop waiting for you other than by terminating or being suspended in which case that process will receive a SIGCHLD
signal or the wait*()
call it's currently doing will return.
However, you can suspend yourself by sending yourself the SIGTSTP signal (same sent when you press ^Z
) or SIGSTOP (which cannot be intercepted), in which case, all of (1), (2) and (3) will happen automatically, except that the job state will be suspended instead of running in background.
Now, since you're suspended, you're no longer running and cannot resume yourself.
You could however fork a child process that will resume yourself (by sending SIGCONT to your pid) in a little while prior to suspending yourself.
When you resume execution, your shell will receive a SIGCHLD again, and (3) where the shell realises that you're now running in background will happen when it gets to process that signal.
As an example, implementing that in sh
:
$ sh -c 'echo running in foreground; sleep 1
(sleep 1; echo resuming my parent; kill -s CONT "$$") &
echo stopping; kill -s STOP "$$"
echo resumed
sleep 30
echo finished'; echo "$?"
running in foreground
stopping
147
zsh: suspended (signal) sh -c
$ resuming my parent
resumed
$ jobs
[1] + running sh -c
$ finished
[1] + done sh -c
It's also possible to suspend your whole job with kill(0, SIGSTOP)
(kill -s STOP 0
in sh
), but is it right for a process to do that, to affect the run flow of processes it hasn't started and it doesn't know about?
sh -c 'echo running in foreground
perl -MPOSIX -le "setpgid 0,0; # leave the process group before it is suspended
sleep 2;
print q(resuming the process group of my parent);
kill q(CONT), - shift@ARGV
" "$(ps -o pgid= -p "$$")" &
sleep 1
echo stopping my process group; kill -s STOP 0
echo process group resumed
sleep 30
echo finished' | cat
Only sometimes.
The advice in Ángel's answer is outdated and bad.
"daemonization", as it is called, does not really work from login sessions.
There are far too many one-way trapdoors that systems pass through in order to set up login sessions; and not only does Ángel's answer ignore things like OpenBSD's setlogin()
, AIX's protected environment (see setsenv
), and Linux's security contexts and control groups, so too does the old daemon()
library function in pretty much all C libraries.
It hasn't worked since the 1980s; because the 1990s saw the introduction of many of these one-way trapdoors. "daemonization" is a fallacy, unfortunately still promoted all of these years later by received wisdom and folklore.
It's not even what dæmons should do. Service management subsystems from the late 1980s (e.g. the AT&T Unix Service Access Facility) and 1990s (e.g. IBM's System Resource Controller) onwards invoke dæmons already in dæmon context. They are not started in login session context in the first place.
Moreover, doing fork-and-exit-parent conflicts with the control semantics that service management subsystems have been using for dæmons for over 3 decades; and closing file descriptors conflicts with the logging mechanisms that service management subsystems set up for dæmons.
/etc/rc
or /etc/rc.local
shell script, or even interactively from a superuser login session, and defeats the fact that service management subsystems use the process ID that it got from fork()
ing the service process to both track and control the service.
(As you can see from the further reading, IBM has been advising against doing this for almost as long as its System Resource Controller has existed.)
Service management subsystems invoke dæmons in sessions that already have no controlling terminal.Furthermore, "daemonization" isn't what one does to get in the background in a login session.
A "job-control" shell puts things into the foreground and background in login sessions by calling the tcsetpgrp()
function to alter the controlling terminal's current foreground process group ID value.
This has actually nothing whatsoever to do with fork()
, chdir()
, closing file descriptors, or (kernel) sessions.
A child process of the shell can call tcsetpgrp()
, but note that (a) it will be sent a SIGTTOU
signal if it is already in the background, and (b) it's non-trivial to find another process group ID to switch to, as the shell might not be the immediate parent process in all circumstances.
&
mechanism for doing so.tcsetpgrp
. System Interfaces. Single UNIX Specification. IEEE 1003.1. 2018. The Open Group.service
command. nosh pages. JdeBP's Softwares.Yes. The basic way of working o the background would be to fork()
itself and fnish the parent, while continuing the work in the child. This often also includes changing the working directory to /
(so that the detached process doesn't block unmounting filesystems), closing file descriptors (to avoid TTY signals) and creating a new process session (see setsid(2))
There are library functions like daemon that may simplify doing all of these:
#define _DEFAULT_SOURCE // glibc >= 2.19
#define _BSD_SOURCE // glibc <= 2.19
#include <unistd.h>
int main() {
daemon(0, 0);
....
}