waiting once after sending kill signal to multiple processes? - c

So I'm working on a project for one of my programming classes, and part of this assignment is about being able to launch process in the background, and being able to kill them when the user types "endb".
In order to kill the background processes, I have an array (PIDpool) which holds the PIDs of all the processes, and whenever the user input "endb", I go through this array of PIDs and kill them one by one.
Though, in order for this to work, I had to add a single wait after I sent a kill signal to each process. If I didn't, there would be a single defunct process left, and if I put a wait for each kill signal (by putting the wait within the killing loop), the program would hang.
While I'm happy to know my program seems to be working, I'm wondering why that wait is necessary, cuz it would seem to me that I would need either to wait for each process after killing them or wait for none at all...
Thanks in advance ^^
static void backgroundExecution(char** cmd_tokens){
if(!strcmp(cmd_tokens[0], "endb")){
for(size_t i = 0; i < arraySize(PIDpool); i++){
intptr_t PID = (intptr_t) arrayGet(PIDpool, i);
kill(PID, SIGKILL);
}
wait(NULL); // <------------ THIS WAIT HERE
arrayEmpty(PIDpool);
}else{
pid_t PID = fork();
if(PID == 0){
execvp(cmd_tokens[0], cmd_tokens);
}else{
arrayPushBack(PIDpool, (void*) (unsigned long) PID);
}
}
}

Look deeper into wait() and waitpid(). Wait simply waits for any child process to terminate, thus it works in your case.
You actually don't check whether each process has indeed stopped, nor whether the kill function returned an error.
As pointed out in the comments, your cast to intptr_t is incorrect, not sure what the type of PIDpool is but it should look like pid_t PIDpool[POOL_SIZE];

Related

Allow a process to stop another process for a given time c

I want to know if there is a way to make a parent process stop his child for a given time using signal
for example:
pid_t pid = fork();
if(pid==0){
while(1){
//some code here
}
}else{
// some code to make child process stop for x seconds
}
You may use SIGSTOP and SIGCONT to stop and continue the process. In combination with some time delay function (e.g. sleep() ) you may get the desired effect.
You may check the example here: https://ostechnix.com/suspend-process-resume-later-linux/

Creating "background running" children with fork() and kill each of them with signals

I need to create n children from the same parent, and have them running while the parent asks infinitely for a signal to send to some child. I made the parent create those n children, but they finished executing, so I made them enter a while(1) loop. The problem is, when I try to kill any child, it becomes a zombie process instead of actually terminating its execution. I'm guessing that's because the parent is still waiting for the children to terminate execution and they don't send the exit status. So... First of all, do I really need to make the children enter an infinite while loop to make them be running while the parent is asking for the signals? If I do, how do I avoid this "never terminating execution" problem? I need to find a way for the children to exit that while loop and send the actual "finished execution" signal since I think I can't use wait() because the children never actually finish running, they are just terminated by the parent.
Thanks.
PS: Running in Linux. This is my code
int main(){
int i;
pid_t parent = getpid();
pid_t pid[4];
printf("parent with pid %d\n", parent);
for(i = 0; i < 5; i++){
pid[i] = fork();
if(pid[i] < 0){
perror("Error in fork.");
exit(1);
} else if(pid[i] == 0 && getppid() == padre) {
printf("Number: %d pid %d, parent: %d\n", i, getpid(), getppid());
while(1);
}
}
if(getpid() == padre){
while(1){
printf("Enter pid and signal:\n");
int x, y;
scanf("%d", &x); // pid
scanf("%d", &y); // signal
printf("you did: kill(%d, %d)\n", x, y);
kill(x, y);
}
}
return 0;
}
EDIT:
Final code with answer implemented: https://github.com/sebasura/sistope
The problem is, when I try to kill any child, it becomes a zombie process instead of actually terminating its execution.
Well, yes and no. Becoming a zombie is normally what happens when a process terminates, until that process is collected by its parent. A zombie takes up a bit of space in the process table, but it is not running, and therefore consumes no CPU.
I'm guessing that's because the parent is still waiting for the children to terminate execution and they don't send the exit status.
No, it's because kill() just sends a signal. You need to use one of the wait() functions -- perhaps waitpid() -- to actually collect the terminated child.
So... First of all, do I really need to make the children enter an infinite while loop to make them be running while the parent is asking for the signals?
No. The child can use sigwait() or one of its variants to wait for a signal from a designated set, or pause() to suspend execution pending receipt of any signal that terminates the process or triggers a signal handler function. Note, however, that there are some signals that by default do neither of those, so sigwait() is probably the better alternative.
If I do, how do I avoid this "never terminating execution" problem?
The child must terminate as a result of receiving the signal. That's already happening for you, because the children are becoming zombies. With your present code it may depend on which signal you send, however, for there are some whose default handling does not terminate the process.
Thank you everyone, I did it.
I used pause() instead of while(1).
And after the kill, I used this:
int state;
waitpid(pid, &state, 0);
This is part of a homework so I will upload the code after the due date so they don't penalize me for sharing it or something.
Thanks again.
EDIT:
Here is the final code https://github.com/sebasura/sistope

How do you kill zombie process using wait()

I have this code that requires a parent to fork 3 children.
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
What is the command to view zombie processes if you have Linux
virtual box?
main(){
pid_t child;
printf("-----------------------------------\n");
about("Parent");
printf("Now .. Forking !!\n");
child = fork();
int i=0;
for (i=0; i<3; i++){
if (child < 0) {
perror ("Unable to fork");
break;
}
else if (child == 0){
printf ("creating child #%d\n", (i+1));
about ("Child");
break;
}
else{
child = fork();
}
}
}
void about(char * msg){
pid_t me;
pid_t oldone;
me = getpid();
oldone = getppid();
printf("***[%s] PID = %d PPID = %d.\n", msg, me, oldone);
}
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
If your parent spawns only a small, fixed number of children; does not care when or whether they stop, resume, or finish; and itself exits quickly, then you do not need to use wait() or waitpid() to clean up the child processes. The init process (pid 1) takes responsibility for orphaned child processes, and will clean them up when they finish.
Under any other circumstances, however, you must wait() for child processes. Doing so frees up resources, ensures that the child has finished, and allows you to obtain the child's exit status. Via waitpid() you can also be notified when a child is stopped or resumed by a signal, if you so wish.
As for where to perform the wait,
You must ensure that only the parent wait()s.
You should wait at or before the earliest point where you need the child to have finished (but not before forking), OR
if you don't care when or whether the child finishes, but you need to clean up resources, then you can periodically call waitpid(-1, NULL, WNOHANG) to collect a zombie child if there is one, without blocking if there isn't any.
In particular, you must not wait() (unconditionally) immediately after fork()ing because parent and child run the same code. You must use the return value of fork() to determine whether you are in the child (return value == 0), or in the parent (any other return value). Furthermore, the parent must wait() only if forking was successful, in which case fork() returns the child's pid, which is always greater than zero. A return value less than zero indicates failure to fork.
Your program doesn't really need to wait() because it spawns exactly four (not three) children, then exits. However, if you wanted the parent to have at most one live child at any time, then you could write it like this:
int main() {
pid_t child;
int i;
printf("-----------------------------------\n");
about("Parent");
for (i = 0; i < 3; i++) {
printf("Now .. Forking !!\n");
child = fork();
if (child < 0) {
perror ("Unable to fork");
break;
} else if (child == 0) {
printf ("In child #%d\n", (i+1));
about ("Child");
break;
} else {
/* in parent */
if (waitpid(child, NULL, 0) < 0) {
perror("Failed to collect child process");
break;
}
}
}
return 0;
}
If the parent exits before one or more of its children, which can happen if it does not wait, then the child will thereafter see its parent process being pid 1.
Others have already answered how to get a zombie process list via th ps command. You may also be able to see zombies via top. With your original code you are unlikely to catch a glimpse of zombies, however, because the parent process exits very quickly, and init will then clean up the zombies it leaves behind.
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
You can use wait() anywhere in the parent process, and when the child process terminates it'll be removed from the system. Where to put it is up to you, in your specific case you probably want to put it immediately after the child = fork(); line so that the parent process won't resume its execution until its child has exited.
What is the command to view zombie processes if you have Linux virtual box?
You can use the ps aux command to view all processes in the system (including zombie processes), and the STAT column will be equal to Z if the process is a zombie. An example output would be:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
daniel 1000 0.0 0.0 0 0 ?? Z 17:15 0:00 command
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
You can register a signal handler for SIGCHLD that sets a global volatile sig_atomic_t flag = 0 variable to 1. Then, at some convenient place in your program, test whether flag is set to 1, and, if so, set it back to 0 and afterwards (for otherwise you might miss a signal) call waitpid(-1, NULL, WNOHANG) in a loop until it tells you that no more processes are to be waited for. Note that the signal will interrupt system calls with EINTR, which is a good condition to check for the value of flag. If you use an indefinitely blocking system call like select(), you might want to specify a timeout after which you check for flag, since otherwise you might miss a signal that was raised after your last waitpid() call but before entering the indefinitely blocking system call. An alternative to this kludge is to use pselect().
Use:
ps -e -opid,ppid,pgid,stat,etime,cmd | grep defunct
to see your zombies, also the ppid and pgid to see the parent ID and process group ID. The etime to see the elapsed (cpu) time your zombie has been alive. The parent ID is useful to send custom signals to the parent process.
If the parent process is right coded to catch and handle the SIGCHLD signal, and to what expected (i.e., wait/reap the zombies), then you can submit:
kill -CHLD <parent_pid>
to tell the parent to reap all their zombies.

Waiting for child process to terminate, or not - C

I'm trying to do an assignment for one of my classes and no professors/fellow classmates are getting back to me. So before you answer, please don't give me any exact answers! Only explanations!
What I have to do is write a c program (timeout.c) that takes in two command line arguments, W and T, where W is the amount of time in seconds the child process should take before exiting, and T is the amount of time the parent process should wait for the child process, before killing the child process and printing out a "Time Out" message. Basically, if W > T, there should be a timeout. Otherwise, the child should finish its work and then no timeout message is printed.
What I wanted to do was just have the parent process sleep for T seconds, and then kill the child process and print out the timeout, however printing out the timeout message would happen no in both cases. How do I check to see that the child process is terminated? I was told to use alarm() for this, however I have no idea of what use that function would serve.
Here's my code in case anyone wants to take a look:
void handler (int sig) {
return;
}
int main(int argc, char* argv[]){
if (argc != 3) {
printf ("Please enter values W and T, where W\n");
printf ("is the number of seconds the child\n");
printf ("should do work for, and T is the number\n");
printf ("of seconds the parent process should wait.\n");
printf ("-------------------------------------------\n");
printf ("./executable <W> <T>\n");
}
pid_t pid;
unsigned int work_seconds = (unsigned int) atoi(argv[1]);
unsigned int wait_seconds = (unsigned int) atoi(argv[2]);
if ((pid = fork()) == 0) {
/* child code */
sleep(work_seconds);
printf("Child done.\n");
exit(0);
}
sleep(wait_seconds);
kill(pid, SIGKILL);
printf("Time out.");
exit(0);
}
Although waitpid would get you the return status of the child, its default usage would force parent to wait until the child terminates.
But your requirement (if i understood correctly) only wants parent to wait for a certain time, alarm() can be used to do that.
Then, you should use waitpid() with a specific option that returns immediately if the child has not exited yet (study the api's parameters). So if the child didn't exit, you could kill it, else you already receive its return status.
You want the timeout program to stop more or less as soon as the command finishes, so if you say timeout -t 1000 sleep 1 the protecting program stops after about 1 second, not after 1000 seconds.
The way to do that is to set an alarm of some sort — classically, with the alarm() system call and a signal handler for SIGALRM — and then have the main process execute wait() or waitpid() so that when the child dies, it wakes up and collects the corpse. If the parent process gets the alarm signal, it can print its message and send death threats of some sort to its child. It might be sensible to try SIGTERM and/or SIGHUP before resorting to SIGKILL; the SIGTERM and SIGHUP signals give the errant child a chance to clean up whereas SIGKILL does not.
If you know how to manage signals, you could catch SIGALRM and SIGCHLD in your parent process. SIGCHLD will be raised when the client terminates, and SIGALRM when the timer expires. If the first raised signal is SIGALRM, the timeout expired, otherwise, if the first SIGNAL that the parent catches is SIGCHLD, the child has stopped before the expiration of the timeout.
wait() or waitpid() would still be necessary to collect the terminated child.

does linux never end child process until the parent ends?

Please consider this code in c:
int main()
{
pid_t cpid;
cpid = fork();
if (cpid == -1)
{
perror("fork");
return 0;
}
if (cpid == 0)
{
printf("I'm child\n");
_exit(0);
}
else
{
while(1)
{
printf("I'm parent\n");
sleep(1);
}
}
return 0;
}
After running the code, I expect it to run child and exits it once it's done.
But when I run
pgrep executable_name
or
ps fax
it shows the child process id and I don't know if its just a history crap of working process or it really does not end/terminate the child process?
thanks in advance
The child will remain until its parent dies or the parent cleans it up with the wait system calls. (In the time between the child terminating and it being cleaned up, it is referred to as a zombie process.)
The reason is that the parent might be interested in the child's return value or final output, so the process entry stays active until that information is queried.
edit:
Example code for using the sigchld handler to immediately clean up processes when they die without blocking:
http://arsdnet.net/child.c
Be mindful of the fact that system calls (like sleep, select, or file read/writes) can be interrupted by signals. This is a normal thing you should handle anyway in unix - they fail and set errno to EINTR. When this happens, you can just try again to finish the operation. This is why my example code calls sleep twice in the parent - the first long sleep is interrupted by the child dying, then the second, shorter sleep lets us confirm the process is actually cleaned up before the parent dies.
BTW signal handlers usually shouldn't do much, they should return as soon as possible and avoid things that aren't thread safe; printfing in them is usually discouraged. I did it here just so you can watch everything as it happens.
You need to call wait() in the parent, otherwise the child process will never be reaped (it becomes a zombie).*
* Unless the parent itself also exits.

Resources