Domanda

If you know the pid of a process is there a way to destroy the hole process tree created from that process and free all the memory allocated by those processes ? I need to find a way to do that in a C program without having to go to each process of the tree.

so here is the code I made after reading Basile Starynkevitch very useful answer .

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>

void proctreecreator(int count);

int main()
{
    int status,count;
    count = 0;
    pid_t pid,procapid;
    pid = fork();
    if (pid < 0) {
        perror("main: fork");
        exit(1);
    }
    if (pid == 0)
    {
        if( setpgid(0,0) <0 ) perror( "main: setpgid" );
        proctreecreator(count);
        exit(1);
    }
    procapid=pid;
    pid = fork();
    if (pid < 0) {
        perror("main: fork");
        exit(1);
    }
    if (pid == 0)
    {
        sleep(1);
        printf("I will now destroy the process tree \n");
        kill(-procapid, SIGTERM);
        exit(0);
    }
    procapid = waitpid(procapid, &status, 0);
    if (procapid < 0) perror( "main: waitpid" );
    else printf("Process A and its tree are killed\n");
    pid = waitpid(pid, &status, 0); 
    if (pid < 0) perror("main: waitpid");
    else printf("process B exited \n");
    return 0;
}

void proctreecreator(int count)
{
    pid_t pid;
    int status,i;
    int *k = (int*)malloc(sizeof(int));
    *k=count;
    pid_t mypid=getpid();
    printf("process with pid : %d created in depth %d \n",mypid,count);
    if (count > 3) 
    {
        sleep(5);
        free(k);
        exit(0);
    } 
    else 
    {
        count++;
        pid = fork();
        if (pid < 0) {
            perror("proctreecreator: fork");
            exit(1);
        }
        if (pid == 0)
        {
            proctreecreator(count);
            exit(1);
        }
        pid = fork();
        if (pid < 0) {
            perror("proctreecreator: fork");
            exit(1);
        }
        if (pid == 0)
        {
            proctreecreator(count);
            exit(1);
        }
        for (i=0; i<2; i++) 
        {
            pid = wait(&status);
            if (pid < 0) perror("proctreecreator: wait");
            else printf("process %d is now terminated",pid);            
        }
        free(k);
        exit(0);
    }
}

I have some questions about how the programm works! When using kill(-procapid, SIGTERM); does it take constant time to destroy the process tree or does it depend on the size of the tree ? Is all memory allocated with malloc free after kill(-procapid, SIGTERM); ?

È stato utile?

Soluzione

When a process is terminated, all the virtual memory that it has used -including heap often managed by malloc & free, generally thru mmap(2) etc...- is released (except for shared memory).

The system call for (forcibly) terminating some other process is kill(2), which exactly sends a signal to a process (or a process group). Read signal(7). If all the processes in your process tree belongs to the same process group (see credentials(7) ...) you just need to kill that process group. See also killpg(2).

You should first kill with SIGTERM. This gives the opportunity for well behaved programs (like many RDBMS servers) to handle that signal appropriately (e.g. releasing resources, cleaning up, etc...). A second later, you could kill with SIGQUIT. At last, you could send the SIGKILL signal which cannot be caught and will always terminate processes.

Read also about sessions and setsid(2) (and setpgid(2) for process groups) and controlling terminal. See also the tty demystified page and the job control wikipage.

Notice that some processing could still continue. Imagine that some of your processes is execve(2) batch(1) i.e. /usr/bin/batch (or ssh)

So your first program forks some A; make it call setpgid(0,0) (see setpgid(2) for details). Of course, your first program needs to keep the pid of A (returned by fork(2)), let us suppose it is in pid_t pid_of_A; then you'll need to later kill(-pid_of_A, SIGTERM) and at last waitpid(pid_of_A, &status_of_A, 0) (see waitpid(2)...).

Read Advanced Linux Programming


You have edited your question by adding:

have some questions about how the program works! When using kill(-procapid, SIGTERM); does it take constant time to destroy the process tree or does it depend on the size of the tree ?

This really should have been another question. The theoretical complexity of kill when killing a process group should not bother you in practice. The reason is that in practice you don't have a lot of (running) processes; you only want -unless you are running on a multi-million dollar supercomputer- to have a few dozen of running processes (otherwise your entire system and machine would be overloaded and begin thrashing). So the actual complexity of killing a process tree does not matter much, since in practice your process tree would have only a few dozen running processes (and a few hundred processes in total, most of them being idle).

You also ask

Is all memory allocated with malloc free after kill(-procapid, SIGTERM); ?

Read more about processes, the fork system call, fork bombs. Please understand that each process uses virtual memory and has its own address space, and malloc uses e.g. mmap(2) to change the address space of the running process (only).

When a process terminates, its entire address space is deleted by the kernel. This is not immediately related to kill(... SIGTERM) because some processes will catch SIGTERM to do useful cleanup. (In other words, sending SIGTERM to some process won't always immmediately terminate it).

Advanced Linux Programming is explaining that in details, much better than I have to do.

And yes, creating a process (with fork(2)), terminating a process (because of some terminating signal(7) or because it has gently _exit(2)-ed), replacing the running program with another one in a process (with execve(2) ...), and changing the address space of a running process (with mmap(2) often used by malloc...) are complex and expensive operations, but the Linux kernel is doing them quite well.

Processes are quite expansive resources, so you should not have a big lot of them. Hence asymptotic complexity is not the right concept to reason about them. You want to have "few" of them (and what "few" means depend upon your particular system and hardware). Right now my i3770K Linux/Debian desktop (with 16Gbytes RAM) has 238 processes, most of them being idle (run ps auxw in a terminal to find out), only a few are running. Recent Linux kernels have an efficient scheduler, often an O(1) scheduler.

Linux is rumored to be quite good at managing processes, and creating a process on Linux is believed to be faster than on Windows.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top