Why are all processes killed when a terminal session ends? - c

Not long ago, I wondered about the question: why are all processes killed when you close a terminal on Linux, and not passed to the "init" process (with pid 1)?
Because, all child processes are adopted by "init" process after termination of the parent.
Please, help me understand difference and the errors in my reasoning.
And also:
If it's possible, then can we use a system call to stop this happening? I think, that for this the programs need use setsid(), but in practice it's not correct.

As explained by cnicutar, it's due to the SIGHUP sent to all processes in the process group associated with the controlling terminal. You may either install a handler for this signal or ignore it completely. For arbitrary programs, you can start them with the nohup utility designed for this purpose.
You can also place the process in a new process group without a controlling terminal.

why on close terminal on linux all his processes will terminated, but
not passed to "init" process (with pid 1)
The processes are losing their controlling terminal so the kernel sends them a SIGHUP. The default action of SIGHUP is to terminate the process.

i think this will help you to understand
http://www.digipedia.pl/usenet/thread/18802/10189/

Related

How to do something in C when a process terminates without hanging the program?

Currently, I'm learning about processes on the UNIX system.
My issue is, I need to do something every time a background process terminates. That means that I can't use the typical functionality of waitpid because then the process won't be running in the background and it'll hang the program.
I'm also aware of the SIGCHLD signal which is sent whenever a child of the parent process is terminated however I'm not aware of how to get the process id of the said process which I will need.
What is the proper way to go about this in C? I've tried things such as WNOHANG option on waitpid however that of course only gets called once so I don't see how I could make that apply to my current situation.
waitpid because then the process won't be running in the background and it'll hang the program.
If the process won't be running in the backrgound, waitpid with the pid argument will exit immediately (assuming there are no pid clashes). And still, that's not true - just use WNOHANG...
however I'm not aware of how to get the process id of the said process which I will need. What is the proper way to go about this in C?
Use sigaction to register the signal handler and use the field si_pid from the second signal handler argument of type siginfo_t. From man sigaction:
SIGCHLD fills in si_pid, si_uid, si_status, si_utime, and si_stime,
providing information about the child. The si_pid field is the
process ID of the child
A working example that uses it is in the man 3p wait page under section Waiting for a Child Process in a Signal Handler for SIGCHLD.
What is the proper way to go about this in C?
The C standard is not aware of child processes and SIGCHLD signals. These are part of your operating system. In this case the behavior is standardized by POSIX.

Default behavior of a Unix-based shell with respect to child processes on exit?

I am implementing a basic Unix-based shell. The shell maintains a list of child processes running in background and stopped processes.
If a shell is exited:
Does the shell kill all the child processes running/stopped in the background?
Or
Does the shell simply ignore the child processes existing in the background or in stopped state, only to be later adopted by init?
Note that I need to know the exact behavior of the Unix shells. I found an answer here but still it doesn't talk about the exact implementation of Unix shells.
Read more about the SIGHUP signal. This signal is typically sent to all processes in a process group whenever their controlling terminal exits. In the case of a shell, this usually happens when the terminal window is closed. The default behaviour of the signal is to terminate the process. That is why programs such as nohup exist.
In order to write a real shell, you really have to understand the whole TTY subsystem and how signals are related. A recommended article is "The TTY Demystified".
Actually SIGHUP (signal number is 1, (to verify kill -l)) is signal, which is used to close all the processes (we can say children) , which are running under the terminal, by sending this signal by that terminal to all processes.
The SIGHUP signal is sent to a process when its controlling terminal is closed. It was
originally designed to notify the process of a serial line drop (a hangup). In modern
systems, this signal usually means that the controlling pseudo or virtual terminal has
been closed.Many daemons will reload their configuration files and reopen their
logfiles instead of exiting when receiving this signal.nohup is a command to make a
command ignore the signal.

How to kill a process synchronously on Linux?

When I call kill() on a process, it returns immediately, because it just send a signal. I have a code where I am checking some (foreign, not written nor modifiable by me) processes in a loop infinitely and if they exceed some limits (too much ram eaten etc) it kills them (and write to a syslog etc).
Problem is that when processes are heavily swapped, it takes many seconds to kill them, and because of that, my process executes the same check against same processes multiple times and attempts to send the signal many times to same process, and write this to syslog as well. (this is not done on purpose, it's just a side effect which I am trying to fix)
I don't care how many times it send a signal to process, but I do care how many times it writes to syslog. I could keep a list of PID's that were already sent the kill signal, but in theory, even if there is low probability, there could be another process spawned with same pid as previously killed one had, which might also be supposed to be killed and in this case, the log would be missing.
I don't know if there is unique identifier for any process, but I doubt so. How could I kill a process either synchronously, or keep track of processes that got signal and don't need to be logged again?
Even if you could do a "synchronous kill", you still have the race condition where you could kill the wrong process. It can happen whenever the process you want to kill exits by its own volition, or by third-party action, after you see it but before you kill it. During this interval, the PID could be assigned to a new process. There is basically no solution to this problem. PIDs are inherently a local resource that belongs to the parent of the identified process; use of the PID by any other process is a race condition.
If you have more control over the system (for example, controlling the parent of the processes you want to kill) then there may be special-case solutions. There might also be (Linux-specific) solutions based on using some mechanisms in /proc to avoid the race, though I'm not aware of any.
One other workaround may be to use ptrace on the target process as if you're going to debug it. This allows you to partially "steal" the parent role, avoiding invalidation of the PID while you're still using it and allowing you to get notification when the process terminates. You'd do something like:
Check the process info (e.g. from /proc) to determine that you want to kill it.
ptrace it, temporarily stopping it.
Re-check the process info to make sure you got the process you wanted to kill.
Resume the traced process.
kill it.
Wait (via waitpid) for notification that the process exited.
This will make the script wait for process termination.
kill $PID
while [ kill -0 $PID 2>/dev/null ]
do
sleep 1
done
kill -0 [pid] tests the existence of a process
The following solution works for most processes that aren't debuggers or processes being debugged in a debugger.
Use ptrace with argument PTRACE_ATTACH to attach to the process. This stops the process you want to kill. At this point, you should probably verify that you've attached to the right process.
Kill the target with SIGKILL. It's now gone.
I can't remember whether the process is now a zombie that you need to reap or whether you need to PTRACE_CONT it first. In either case, you'll eventually have to call waitpid to reap it, at which point you know it's dead.
If you are writing this in C you are sending the signal with the kill system call. Rather than repeatedly sending the terminating signal just send it once and then loop (or somehow periodically check) with kill(pid, 0); The zero value of signal will just tell you if the process is still alive and you can act appropriately. When it dies kill will return ESRCH.
when you spawn these processes, the classical waitpid(2) family can be used
when not used anywhere else, you can move the processes going to be killed into an own cgroup; there can be notifiers on these cgroups which get triggered when process is exiting.
to find out, whether process has been killed, you can chdir(2) into /proc/<pid> or open(2) this directory. After process termination, the status files there can not be accessed anymore. This method is racy (between your check and the action, the process can terminate and a new one with the same pid be spawned).

zombie process created in code, and killed in another part

I want to write a 'zombie creator' and 'zombie terminator'. Main point is that I want to create zombies in one part and terminate them in other part of code. I'm using C.
Example:
create_zombie(); //let's say it's a spawn, using fork etc.
/* a houndred lines below */
kill_zombie(PID); // PID is determinated by user, I want to leave him the choice
I know how to do this using fork(), if .. else, but that's not the point. I'm looking for some kind of remote control. Is that possible? Sleeping him for a long time could be a solution?
I'm assuming Linux, but the process should be similar on other operating systems. You want to look into the kill() function declared typically declared in the signal.h header file. This will allow you to send a signal to a specific PID from your zombie killer. The easiest approach would be to send your zombie process a kill signal (SIGKILL). SIGKILL cannot be caught or ignored, and immediately kill a process dead.
If you need to do some cleanup in your zombie process, you can create a signal handler with the signal() function. This will allow you to specify a function to call when a process receives a signal. This function would implement your cleanup code and then exit().
On linux, your shell should have a kill command that mimics the functionality of kill(). The syntax is typically kill -s 9 PID. This will send a SIGKILL (signal number 9) to the process PID.
I hope this answer nudges you in the proper direction.
When you fork a process, fork returns 0 in the child process and the child's process id in the parent. You can save them in an array, write them to a file, or write them to a pipe and don't "uncap" the other end until you need it.

Fork, Parent and child process

In C, is it possible to have the forked() process alive indefinitely even after the parent exits?
The idea of what I am trying to do is, Parent process forks a child, then exits, child keeps running in background until another process sends it a kill signal.
Yes, it is definitely possible to keep the child alive. The other responders are also correct; this is how a "daemon" or background process runs in a Linux environment.
Some call this the "fork off and die" approach. Here's a link describing how to do it:
http://wiki.linuxquestions.org/wiki/Fork_off_and_die
Note that more than just fork()-ing is done. File descriptors are closed to keep the background process from tying up system resources, etc.
Kerrek is right, this exactly the way how every daemon is implemented. So, your idea is perfect.
There is a daemon library function which is very easy to use for that.
The daemon() function call is not without limitations if you want to
write a well-behaved daemon. See On Starting Daemons
for an explanation.
Briefly: A good daemon should only background when it is ready to field requests, but do its setup under its own PID and print startup errors

Resources