[comp.unix.questions] Killing a background process from a C program

marwood@ncs.dnd.ca (Gordon Marwood) (07/19/90)

I am in the process of converting a Bourne shell script to C, and I am
having trouble finding out how to identify and kill background
processes.  With the Bourne Shell approach this was simple, using $!.

What I would like to do is start a background process at one point in the
C program, and at a later time kill it.  Currently I am invoking the
background process with system("background_process &");, but none of the
texts that I have available help me to proceed any further.

Any assistance would be appreciated.

Gordon Marwood
Internet: marwood@ncs.dnd.ca

dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (07/20/90)

In article <1990Jul19.151728.17448@ncs.dnd.ca> marwood@ncs.dnd.ca (Gordon Marwood) writes:
>
>What I would like to do is start a background process at one point in the
>C program, and at a later time kill it.  Currently I am invoking the
>background process with system("background_process &");, but none of the
>texts that I have available help me to proceed any further.
>

System is not a powerful enough tool for this, it is designed for only
the simplest of process control situations. You'll have to fork and
exec the new process yourself. Fork will create a new process and return
the pid of that process, at some later point use kill (pid, signal_number)
to kill it. For more details, drop me a note or (better still) pick up
a copy of Marc Rochkind's Advanced Unix Programming. (BTW -- even though
it is a UNIX book and not a C book, I think it should be mentioned
in the Frequently Asked Questions posting as an excellent reference for
C programming under UNIX.)

Followups redirected to comp.unix.questions.



--
Dave Eisen                      	    Home: (415) 323-9757
dkeisen@Gang-of-Four.Stanford.EDU           Office: (415) 967-5644
1447 N. Shoreline Blvd.
Mountain View, CA 94043

larrym@pi19.pnfi.forestry.ca (Larry Marshall) (07/20/90)

marwood@ncs.dnd.ca (Gordon Marwood) writes:

>What I would like to do is start a background process at one point in the
>C program, and at a later time kill it.  Currently I am invoking the
>background process with system("background_process &");, but none of the
>texts that I have available help me to proceed any further.

The latest Computer Language (July) has an article on manipulating Unix
processes in C.  It discusses the monitoring of PIDs and includes code for 
terminating those processes.

Larry Marshall
Petawawa National Forestry Institute

truong@wk35..nas.nasa.gov (Tuong C. Truong) (07/24/90)

In article <1990Jul19.201116.13696@Neon.Stanford.EDU> dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes:
>In article <1990Jul19.151728.17448@ncs.dnd.ca> marwood@ncs.dnd.ca (Gordon Marwood) writes:
>>
>>What I would like to do is start a background process at one point in the
>>C program, and at a later time kill it.  Currently I am invoking the
>>background process with system("background_process &");, but none of the
>>texts that I have available help me to proceed any further.
>>
>

Just off the top of my head, but you may want to try something like :

set PID = `background_process&`

at this point PID will keep track of the process ID of the background process.
later when you want to kill it, you may use something like:

kill -9 $PID

I have not tried this, but hope it works.

------------------------
Signature Under Construction.

martin@mwtech.UUCP (Martin Weitzel) (07/25/90)

In article <1990Jul19.201116.13696@Neon.Stanford.EDU> dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes:
>In article <1990Jul19.151728.17448@ncs.dnd.ca> marwood@ncs.dnd.ca (Gordon Marwood) writes:
>>
>>What I would like to do is start a background process at one point in the
>>C program, and at a later time kill it.  Currently I am invoking the
>>background process with system("background_process &");, but none of the
>>texts that I have available help me to proceed any further.
>>
>
>System is not a powerful enough tool for this, it is designed for only
>the simplest of process control situations. You'll have to fork and
>exec the new process yourself. [...]

Though the solution sketched thereafter by Dave Eisen is surely correct,
it's not the only way to go. In fact, it often goes unnoticed (because
it's not obvious) that you can start background-processes without
fork/exec and still wait for them at any time later by using `popen'.

At first glance the purpose of `popen' seems different (communicate thru
a pipeline to stdin or stdout of a program), but if the background
process doesn't use stdin/stdout - or you redirect them to files -
`popen' can safely be used to invoke background processes. If you
want to wait for such a process later, just use the appropriate `pclose'.
If you need to kill one and must have its PID, you can either go the
non-portable way and try to figure out how and where `popen' stores
the relevant information - or use this:

	FILE *bpd; int t, pid;
	bpd = popen("echo $$; exec backgroundprocess" , "r"); /* %% */
	... check for errors /* assert(bpd != (FILE *)0) */ ...
	t = fscanf(bpd, "%d", &pid);
	... again check for errors /* assert(t == 1) */ ...
	... let background process run and do its work ...
	... later you may stop it gracefully ...
	kill(pid, SIGTERM);
	... or with brute force ...
	kill(pid, SIGKILL);
	... and don't forget to cleanup zombies from process table ...
	pclose(bpd);

>For more details [...] pick up
>a copy of Marc Rochkind's Advanced Unix Programming. (BTW -- even though
>it is a UNIX book and not a C book, I think it should be mentioned
>in the Frequently Asked Questions posting as an excellent reference for
>C programming under UNIX.)

My opinion too.

%%: If these lines shall go into a later SETUID-ed program, you must pay
    special attention to assure that the "right" program is started here.
    But as this is generally true for `system', `popen', and partially for
    `execv' too, I'll not go into the security details here.
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

george@hls0.hls.oz (George Turczynski) (07/25/90)

In article <7459@amelia.nas.nasa.gov>, truong@wk35..nas.nasa.gov (Tuong C. Truong) writes:

> Just off the top of my head, but you may want to try something like :
> 
> set PID = `background_process&`
> 
> at this point PID will keep track of the process ID of the background process.
> later when you want to kill it, you may use something like:
> 
> kill -9 $PID
> 
> I have not tried this, but hope it works.

I have not tried this either, but I know it won't work.  That simply
isn't `C'.  The initial poster was writing in `C', and might get
very confused trying to use your solution :-)

Anyway, try something like this:


#include<stdio.h>
#include<signal.h>

#define	FOO_OK			0
#define	FOO_BAD_EXEC	1
#define FOO_BAD_FORK	2
#define FOO_BAD_KILL	3

int
foo(myname)
char *myname;	/* Perhaps equal to *argv[0]. */
{
    int pid;

    /* ... code ... */

    switch( pid= fork() )
    {
        case 0: /* execve() or execl etc. your child here. */
                /*
                 *	eg.
                 *
                 *	execl("/bin/cat","cat","/etc/passwd",(char *)0);
                 *
                 */

                 /* Should only get to here if exec?() fails. */

                 return FOO_BAD_EXEC;
		
        case -1: /* fork() failed. */

                 return FOO_BAD_FORK;
	
    }

    /* ... Parent code ... */

    if( kill(pid,SIGTERM) < 0 )
        return FOO_BAD_KILL;

    /* ... rest of code ... */

    return FOO_OK;

}

I humbly apologise for any typos in the above.  If anyone wants to
flame this, do it in aus.flame >please<.

Note:   kill() _will_ fail if the child has exited before kill() is
        called.

Note:   the use of "kill -9" is in VERY POOR TASTE with respect to
		unix.  "SIGTERM" (#15) is the software termination signal,
        so use it.

I hope this is of some benefit to the original poster, and to anyone
else watching.

Have a nice day...

George P. J. Turczynski           | ACSnet: george@highland.oz
System Administrator              | Phone: 61 48 683490
System Programmer                 | Fax:   61 48 683474
Logic Designer.                   |----------------------
Highland Logic Pty. Ltd.          | I can't speak for the
Suite 1, 348-354 Argyle Street    | company, I can barely
Moss Vale. NSW. 2577 Australia    | speak for myself...

venkat@matrix.UUCP (D Venkatrangan) (07/27/90)

In article <1990Jul19.151728.17448@ncs.dnd.ca> marwood@ncs.dnd.ca (Gordon Marwood) writes:
>I am in the process of converting a Bourne shell script to C, and I am
>having trouble finding out how to identify and kill background
>processes.  With the Bourne Shell approach this was simple, using $!.
>
>What I would like to do is start a background process at one point in the
>C program, and at a later time kill it.  Currently I am invoking the
>background process with system("background_process &");, but none of the
>texts that I have available help me to proceed any further.
>
>Any assistance would be appreciated.
>

Instead of system(), try using vfork() followed by execlp().

In foreground program, do something like:

	if ((child_pid = vfork()) == -1)
		perror("vfork failed");

	if (child_pid == 0) {
		execlp(execfile, execfile, arg1, arg2, ..., (char *)0);
		/* should not return */
		perror("exec failed");
	}

	/* parent */

	/* if we get killed... */
	(void)signal(SIGINT, kill_child);

/* call kill_child() to send a user defined signal to child. */
/* or just call kill(child_pid, SIGUSR1); */

void
kill_child(sigval)
int sigval;
{
	if (sigval == SIGINT)
		kill(child_pid, SIGUSR1);
}

In child, during initialization do:

	(void)signal(SIGUSR1, childsighandler);


and define:

void
childsighandler(sigval)
int sigval;
{
	if (sigval == SIGUSR1) {	/* the parent is sending something */
		cleanup();
		exit();
	}
}


	

mcdonald@aries.scs.uiuc.edu (Doug McDonald) (07/27/90)

In article <159@matrix.UUCP> you write:
>In article <1990Jul19.151728.17448@ncs.dnd.ca> marwood@ncs.dnd.ca (Gordon Marwood) writes:
>>I am in the process of converting a Bourne shell script to C, and I am
>>having trouble finding out how to identify and kill background
>>processes.  With the Bourne Shell approach this was simple, using $!.
>>

PPPPP        L        EEEEEEE            A           SSSS         EEEEEEE
P    P       L        E                 A A         S    S        E
P     P      L        E                A   A       S      S       E
P    P       L        E               A     A       S             E
PPPPP        L        EEEE           AAAAAAAAA       SSSS         EEEE
P            L        E             A         A          S        E
P            L        E             A         A    S      S       E
P            L        E             A         A     S    S        E
P            LLLLLLL  EEEEEEE       A         A      SSSS         EEEEEEE

Please, keep discussion relating  to operating systems OUT of comp.lang.c!!
Send them to the correct OS-specific getto!!! In this case, comp.unix.questions.


Doug McDonald