Re: Starting an external process from C++
- From: jt@xxxxxxxxxxx (Jens Thoms Toerring)
- Date: 29 Oct 2006 11:57:51 GMT
Henrik Goldman <henrik_goldman@xxxxxxxxxxxx> wrote:
However I noticed that on solaris 8 on sparc it might backfire a SIG_ALRM
and on Solaris 10 x86 it might kick a SIG_PIPE.
Who's receiving a signal? And there's nowhere a SIGALRM could come from
unless you send it yourself (perhaps indirectly by setting a timer),
For now I am catching those in my daemon since the parent process (the
process which started the daemon) might display the error on console which I
do not want.
Your "daemon" of course still can write to standard error, and that's
where it sends error messages to. If you want to keep it from messing
up your console have it close its standard error or redirect standard
error to e.g. /dev/null.
Then you can't use popen(). If you want finer-grained control or
additional information than what popen() gives you, you need to
use the fork()/exec() combination and do the pipe creation and
redirections yourself. There's no standard way you can make popen()
divulge the PID of the proceess it created.
But there might be a way to safe the day if you're willing to modify
your external application. If A' gets killed the standard output of
B suddenly vanishes and, as I already pointed out, B's next attempt
to write() to it will result in a SIGPIPE signal. Catch that signal,
do your cleanup in the signal handler and then have it exit.
Yeah thats what I did. So far I only saw SIG_PIPE and SIG_ALRM on Solaris
but I don't know which other platforms works like this too. I'm compiling
for linux, solaris, hp-ux, macosx and aix but only solaris behaved like you
described. So far I'm just catching the signals on solaris only for this
particular reason.
Sorry, but then there must be something going wrong in your program.
You definitely should get a SIGPIPE on all platforms, I tested the
following under Linux and IRIX (that's the two platforms I have easy
access to at the moment, but others should behave in exactly the same
way). There are two programs I cobbled together for testing, named A
(the program that forks and have its child A' starts the "daemon")
and B (the "daemon"):
--------- A.c ----------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
pid_t child_stuff( void )
{
char buf[ 80 ];
FILE *fp;
pid_t ch = fork( );
if ( ch == -1 )
{
perror( "Fork failed" );
exit( EXIT_FAILURE );
}
else if ( ch > 0 )
{
sleep( 3 );
return ch;
}
if ( ( fp = popen( "./B", "r" ) ) == NULL )
{
perror( "popen() failed" );
exit( EXIT_FAILURE );
}
while ( fgets( buf, sizeof buf, fp ) != NULL )
fprintf( stdout, "A': B sent message: %s", buf );
pclose( fp );
exit( EXIT_SUCCESS );
}
int main( void )
{
pid_t ch = child_stuff( );
kill( ch, SIGTERM );
return EXIT_SUCCESS;
}
--------- B.c ----------------------------------------------------
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sig_handler( int signo )
{
fprintf( stderr, "B: Got SIGPIPE\n" );
exit( EXIT_SUCCESS );
}
int main( void )
{
struct sigaction sact;
sact.sa_handler = sig_handler;
sigemptyset( &sact.sa_mask );
sact.sa_flags = 0;
if ( sigaction( SIGPIPE, &sact, NULL ) == -1 )
{
fprintf( stderr, "sigaction failed\n" );
exit( EXIT_FAILURE );
}
setbuf( stdout, NULL );
while ( 1 )
{
fprintf( stderr, "B: Sending message to A'\n" );
fprintf( stdout, "Message for A' from B\n" );
sleep( 1 );
}
return EXIT_SUCCESS;
}
------------------------------------------------------------------
And here's a typical invocation (no difference between Linux or
IRIX and no other signals like SIGALRM):
jens@john:~/TESTS> ./A
B: Sending message to A'
A': B sent message: Message for A' from B
B: Sending message to A'
A': B sent message: Message for A' from B
B: Sending message to A'
A': B sent message: Message for A' from B
jens@john:~/TESTS> B: Sending message to A'
B: Got SIGPIPE
As you can see, A' receives 3 messages from A' (I have B send one
message per second and A kills A' after 3 seconds), and then B
tries to send another one (by that time A already has quit, so
I got back to the command prompt), and it receives a SIGPIPE signal
since it can't write to the pipe to A' anymore. If you use standard
C functions like fprintf() it's of course important to "unbuffer"
them (that's what the setbuf() call is needed for, but setlinebuf()
will also do in this case since all lines end with a '\n), otherwise
the output would only get written to the internal buffers of these
functions until they are full (you are not writing to a terminal but
something that looks to them like a file), and the other side won't
get the messages immediately and the "daemon" would only detect that
there's no standard output anymore when those internal buffers are
full and need to be flushed.
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@xxxxxxxxxxx
\__________________________ http://toerring.de
.
- Follow-Ups:
- Re: Starting an external process from C++
- From: Henrik Goldman
- Re: Starting an external process from C++
- References:
- Starting an external process from C++
- From: Henrik Goldman
- Re: Starting an external process from C++
- From: Jens Thoms Toerring
- Re: Starting an external process from C++
- From: Henrik Goldman
- Re: Starting an external process from C++
- From: Jens Thoms Toerring
- Re: Starting an external process from C++
- From: Henrik Goldman
- Starting an external process from C++
- Prev by Date: Re: Starting an external process from C++
- Next by Date: A simple program for Xlib....can anyone tell me what's wrong ?
- Previous by thread: Re: Starting an external process from C++
- Next by thread: Re: Starting an external process from C++
- Index(es):
Relevant Pages
|