zombie process created in code, and killed in another part - c

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.

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.

Can a child process wait for the parent process to terminate in Linux programming in C?

In C programming for Linux, I know the wait() function is used to wait for the child process to terminate, but are there some ways (or functions) for child processes to wait for parent process to terminate?
Linux has an extension (as in, non-POSIX functions) for this. Look up prctl ("process-related control").
With prctl, you can arrange for the child to get a signal when the parent dies. Look for the PR_SET_PDEATHSIG operation code used with prctl.
For instance, if you set it to the SIGKILL signal, it effectively gives us a way to have the children die when a parent dies. But of course, the signal can be something that the child can catch.
prctl can do all kinds of other things. It's like an ioctl whose target is the process itself: a "process ioctl".
Short answer: no.
A parent process can control the terminal or process group of its children, which is why we have the wait() and waitpid() functions. A child doesn't have that kind of control over its parent, so there's nothing built in for that.
If you really need a child to know when its parent exits, you can have the parent send a signal to the child in an atexit() handler, and have the child catch that signal.
In Linux, you can use prctl with the value PR_SET_PDEATHSIG to establish a signal that will be sent to your process when the thread that created it dies. Maybe you find it useful.
When a parent process ends, child process is adopted by init, so it is enough to check in child proces if ppid()==1 or ppid()!= than oryginal PPID
That means the parent process was finished.

Using waitpid or sigaction?

I have understood that:
1) waitpid is used to wait for a child's death and then collect the SIGCHLD and the exit status of the child etc.
2) When we have a signal handler for SIGCHLD, we do some more things related to cleanup of child or other stuff (upto the programmer) and then do a waitpid so that the child will not go zombie and then return.
Now, do we need to have both 1 and 2 in our programs when we do a fork/exec and the child returns ?
If we have both, the SIGCHLD is obtained first, so the signal handler is called first and thus its waitpid is called successfully and not the waitpid in the parent process code as follows:
my_signal_handler_for_sigchld
{
do something
tmp = waitpid(-1,NULL,0);
print tmp (which is the correct value of the child pid)
}
int main ()
{
sigaction(SIGCHLD, my_signal_handler_for_sigchld)
fork()
if (child) //do something, return
if parent // waitpid(child_pid, NULL,0); print value returned from this waitpid - it is -1
}
Appreciate if someone helps me understand this.
You really don't need to handle SIGCHLD if your intent is to run a child process, do some stuff, then wait for it to finish. In that case, you just call waitpid when you're ready to synchronize. The only thing SIGCHLD is useful for is asynchronous notification of child termination, for example if you've got an interactive (or long-running daemon) application that's spawning various children and needs to know when they finish. However, SIGCHLD is really bad/ugly for this purpose too, since if you're using library code that creates child processes, you might catch the events for the library's children terminating and interfere with its handling of them. Signal handlers are inherently process-global and deal with global state, which is usually A Bad Thing(tm).
Here are two better approaches for when you have child processes that will be terminating asynchronously:
Approach 1 (select/poll event-based): Make sure you have a pipe to/from each child process you create. It can be either their stdin/stdout/stderr or just an extra dummy fd. When the child process terminates, its end of the pipe will be closed, and your main event loop will detect the activity on that file descriptor. From the fact that it closed, you recognize that the child process died, and call waitpid to reap the zombie.
Approach 2 (thread based): For each child process you create, also create a thread that will immediately call waitpid on the child process's pid. When waitpid returns successfully, use your favorite thread synchronization primitives to let the rest of the program know that the child terminated, or simply take care of everything you need to do in this waiter thread before it terminates.
Both of these approaches are modular and library-friendly (they avoid interfering with any other parts of your code or library code which might be making use of child processes).
You need to call the waiting syscalls like waitpid or friends -eg wait4 etc- othewise you could have zombie processes.
You could handle SIGCHLD to be notified that some child ended (or stopped, etc...) but you'll need to wait for it later.
Signal handlers are restricted to call a small set of async-signal-safe-functions (see signal(7) for more). Good advice is to just set a volatile sig_atomic_t flag inside, and test it at later and safer places.

How to kill the parent process and its children on ctrl+C or ctrl+Z

I have the main process in my program that fork() some children processes and then goes into endless loop (Also, the children processes are endless). Now, I want to kill all processes, close a socket, de-attach shared memory, and clean all similar stuff on terminating the program with Ctrl+C or Ctrl+Z. I search the internet and I found that I could do that by sending some signals like SIGSTOP and SIGINT, but I don't know how to do it.So, how can I accomplish this in my program?
From outside the program, you can send any process a signal using the kill command.
By default, kill will send the SIGTERM signal, which will terminate a process, and free its allocated resources. You can use the ps command to find the process ids of your program's processes. Using CTRL-C will only terminate the parent process. It will not kill the child processes. If you just forked, and didn't exec a new program, then all of your child processes will have the same name as the parent, which means you can use the killall command to terminate them all in one go. If you are logged in remotely, then logging out will cause a SIGHUP signal to be sent to all of the processes you spawned during the session, which will terminate them by default.
From inside the program, there is a kill() function that operates similar to the command. You will need the process ids still, so it's important that your parent code remembers the child process id returned by fork.
When your process exits brutally, all resources are certainly freed.
However, if you want to control the behaviour (what order, etc, I don't know what) then you should install a signal handler. See sigaction(2).

How can I send a signal to a popen'ed process in Perl?

I wrote a simple Perl script which will run in while loop and exit whenever any signal is send to this Perl script. I wrote a c program which creates a thread using the pthread_create() and in its start routine, it's using popen to execute that Perl script:
popen("/usr/bin/perl myprog.pl");
I am using the sigtrap in the Perl script to catch any signal it receives. Now I want to send signal (TERM) from my C program to this Perl process executed by the thread. How can I do that? Is there any way to send a signal to popen'ed processes. Please let me know if need more details.
Sending signals usually works using kill. In order to be able to kill you normally need the process id, PID, of the process you want to signal.
popen doesn't give you that. However, there's a couple of alternatives:
You could use a PID of 0, which would send your signal to every process in the process group. If you only have one parent process spawning one child process using popen, then using kill(0, your_signal) would be one way to go.
Another way to go would be to have the child process communicate its PID back to the parent process by, for example, just outputing that on a single line as the first thing after starting up.
In perl, that'd look like
print $$, "\n";
the process that did popen could then read that line from the filehandle it got, and extract a useful pid from that using strtol or atoi, and keep that around to use with kill later on, after having read the actual output of its child process.
If, for whatever reason, none of these approaches is viable for your problem, you probably want to stop using popen alltogether, and do most of what it does manually, most importantly the forking, as that's what'll give you the PID to use to later send signals.
popen() doesn't give you any way to access the PID of the child process, which you need in order to signal it.
You will need to do the gory work of popen() yourself (set up pipes, fork, exec, wait).

Resources