LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   memory leak: Parent killing child process (https://www.linuxquestions.org/questions/programming-9/memory-leak-parent-killing-child-process-645917/)

wkhoo 05-30-2008 03:23 PM

memory leak: Parent killing child process
 
How can I cleanly terminate Child Process without memory leak on a Ctrl-C?

Parent program monitor SIGINT signal, Child program monitor on a SIGTERM.
I start the child program with exec.

on a Ctrl-C the process handler sends a kill(child's pid, SIGTERM), to the child process.
what I am observe is the child process does not handle this signal and terminates.

what I noticed is when the parent program terminate, it will terminate the child program too. Does it automatically sends a SIGKILL to the child process? how does it work?

pinniped 05-30-2008 06:59 PM

See the man pages for 'prctl'.

According to the documentation of 'fork()', the child should not be killed when the parent terminates (it becomes an 'orphan' and will be adopted by another process - 'init' if no one else wants it).

You can use 'prctl' to check that the settings are as expected.

paulsm4 05-30-2008 08:16 PM

You might want to look at setsid () and friends:

http://www.enderunix.org/documents/eng/daemon.php
http://linux.die.net/man/2/setsid

osor 05-30-2008 08:23 PM

Indeed a parent can die and leave children behind, in which case they will be inherited by a process higher up in the hierarchy (one which is wait()ing for children or has a suitable handler for the SIGCHLD signal).

When you have a process created on a terminal it is in the session of the shell which created it (so its SID will match that of the shell). The shell will give it a PGID matching its PID and make that PGID the foreground process of the terminal. If the process fork()s both the parent and child will retain the PGID.

So when you type Ctrl-C at the terminal, a SIGINT is generated and sent to all processes in the foreground process group (i.e., all processes whose PGID matches the PID of command started by the shell). This is why a Ctrl-C will kill both child and parent.

If you want to kill the parent without killing the child, you can do one of a few things:
  • kill by PID of the parent.
  • When creating the child, use setpgid(), setsid() or some other measures to ensure that the child is no longer part of the same process group as the parent (and thus will not recieve a SIGINT on Ctrl-C).

wkhoo 06-02-2008 09:07 AM

Thank for the tip, will read into the man pages and try it out.

I can assume doing a exec() is the same as a fork()? and setpgid(), setsid() applies the same way as fork().

wkhoo 06-02-2008 03:45 PM

I forget to mention I am running valgrind on the child process.

in the parent I called the below to track memory leaks in the child process.

execlp("libtool",
"",
"--mode=execute",
"valgrind --tool=memcheck --leak-check=full",
program_name,
sock_addr,
user_args,
NULL);


using getpid and getpgrp in the parent program the PID and GPID are the same.
The child has a unique PID whereas the GPID is same with the Parent's GPID.
using ps -ef

UID PID PPID C STIME TTY TIME CMD
wkhoo 2350 5750 0 15:08 pts/8 00:00:00 ./puiface
wkhoo 2353 2350 19 15:08 ? 00:00:07 /usr/bin/valgrind.bin --tool=memcheck --leak-check=full ./gen_router /tmp/puiface14_1 p
wkhoo 2386 1591 0 15:09 pts/3 00:00:00 ps -ef

From my limited understanding shouldn't the parent terminates and leave behind a zombie process as the GPID of the parent and child are different?

On a Ctrl-C in the terminal, the parent receives the SIGINT signal and
calls its terminate handler routine to clean up. The parent sent a socket msg to the child asking it to clean up. The child process receives the msgs and before it can execute the clean up route it terminates abruptly. causing memory leaks in pthread_create.


What did I do wrong here? Is there any example that show me how to use the setpgid() correctly to elimiate this behaviour?

osor 06-02-2008 04:10 PM

Quote:

Originally Posted by wkhoo (Post 3172088)
I can assume doing a exec() is the same as a fork()?

No, they are completely different. A call to fork() will create a two processes from one process. A call to one of the exec() functions will replace the current process image with that of a completely different process. Often, a call to exec() follows a call to fork() so you can call an arbitrary program without disrupting the currently-running one.
Quote:

Originally Posted by wkhoo (Post 3172088)
setpgid(), setsid() applies the same way as fork().

I don’t understand what you mean by this statement. setpgid() sets the PGID, and setsid() allows you to create a new session.
Quote:

Originally Posted by wkhoo (Post 3172450)
using getpid and getpgrp in the parent program the PID and GPID are the same.
The child has a unique PID whereas the GPID is same with the Parent's GPID.

Quote:

Originally Posted by wkhoo (Post 3172450)
From my limited understanding shouldn't the parent terminates and leave behind a zombie process as the GPID of the parent and child are different?

As you just said in the quote above this one, the child’s PGID is the same as the parent’s.
Quote:

Originally Posted by wkhoo (Post 3172450)
On a Ctrl-C in the terminal, the parent receives the SIGINT signal and
calls its terminate handler routine to clean up. The parent sent a socket msg to the child asking it to clean up. The child process receives the msgs and before it can execute the clean up route it terminates abruptly. causing memory leaks in pthread_create.

When you Ctrl-C on the terminal, both parent and child receive the SIGINT signal. The child presumably does not have a SIGINT handler and terminates immediately, before the parent’s SIGINT handler gets a chance to send any messages.
Quote:

Originally Posted by wkhoo (Post 3172450)
What did I do wrong here? Is there any example that show me how to use the setpgid() correctly to elimiate this behaviour?

Consider the following program:
Code:

#include <stdio.h>
#include <unistd.h>

int main()
{
        if(fork()) {
                while(1) {
                        printf("Parent printing\n");
                        sleep(2);
                }
        } else {
#ifdef IMMUNE
                setpgrp();
#endif
                sleep(1);
                while(1) {
                        printf("Child printing\n");
                        sleep(2);
                }
        }
        return 0;
}

Compile the above program both with and without the flag ‘-DIMMUNE’. First, run the non-immune one. When you are ready, press Ctrl-C at the terminal. As you notice, both processes are killed (this is because both receive SIGINT).

Now, run the immune one. This time, when you press Ctrl-C at the terminal, only the parent receives the SIGINT, and the child lives on.

wkhoo 06-03-2008 01:13 PM

I am grateful for your detail explaination and example.

I am able to start my child process with setpgrp() on a different GPID.
Termination of the parent now will not terminate the child.

My goal of cleaning up the child is still unfulfilled.
on a SIGINT, the parent sends a message to the child to clean up itself.
The code below is whats in my child program, when it gets the message it calls the pthread_cancel to close the thread. The issue when the call to pthread_cancel is called the program just hangs there. There is no return on pthread_cancel. By me introducing setpgrp in the parent did I just changed how thread is close in the child process?

What is the hidden effects of changing GroupId and Threads?

osor 06-03-2008 05:21 PM

A few things which will help your problem get more attention:
  1. Use [code] and [/code] tags to enclose sections of code and enhance readability.
  2. This is not a debugging service.
  3. If you are having a bug, reduce your code to the smallest sample of code which exhibits the problem. Post that small sample.

wkhoo 06-04-2008 07:57 AM

Thank you mod, I understand fully its not a debugging service.
Not expecting that. wasn't think thru, thought that with code will help ppl understand the problem.

I have taken your advice and remove the code, as it was not my intend.
tried googling with different keys like "pthread_cancel Hang and setpgrp" but did not yield good results. Wanted to know what could have gone wrong by changing setgprg on threads. as when I remove the code, thru a different use case the child process is able to perform pthread_cancel without problems.

osor 06-04-2008 02:30 PM

First, I am not a mod. Second, my advice was not for you to remove the code, my advice was for you to produce the smallest portion of code which demonstrates the problem, so we may more easily asses a solution.

osor 06-04-2008 02:35 PM

Btw, as I said in my first post, you can completely avoid the issue by not using Ctrl-C at all.

If you do not wish to use setpgrp() or setsid(), you may instead just issue a manual kill on the parent process:
Code:

kill -SIGINT pid

chrism01 06-04-2008 05:39 PM

Can I just clarify if you are using fork() or threading? As a general rule, you shouldn't mix the two in the same 'program'.


All times are GMT -5. The time now is 07:01 AM.