I have an application which needs to do the following:
I am limited in that I cannot use threads, only processes. I also cannot afford to wait for the result of reconnect() to return.
So far I have a design like this:
int main(int argc, char **argv)
{
/* do main loop work, if disconnected, call reconnect() & continue doing work */
}
void reconnect()
{
pid = fork();
if (pid >= 0) {
/*Successful fork*/
if (pid == 0) {
rv = attempt_reconnect;
if (rv == 0) {
/*Notify sig_child Success*/
exit(0);
} else {
/*Notify sig_child Fail*/
exit(1);
}
}
}
}
void sig_child(int signum)
{
if(fork returned success) {
set flag to continue network stuff
}
else {
alarm(20);
}
}
void sig_alarm(int signo)
{
/*Received alarm, trying to reconnect...*/
reconnect();
}
Any help would be greatly appreciated!
Edit
I think I have a solution working from an example here. It allows me to create timers with separate ID's, and then identify which one has has signalled the program
Using the following code I found here, I have achieved (I think) what I was trying to do.
It allows the creation and handling of multiple timer_t objects using the functions "makeTtimer" and "timerHandler" respectively:
timer_t reconnect_timer_id;
timer_t timeout_timer_id;
int main(int argc, char **argv)
{
/* do main loop work */
if(disconnected()) {
/*IF TIMEOUT SET, SKIP, IF OK, RESET*/
if(timeout_set != 1) {
"Schedule Alarm"
makeTimer("Timeout Timer", &timeout_timer_id, 600,0);
timeout_set = 1;
} else {
"Timeout alarm already set..";
}
reconnect();
}
}
void reconnect()
{
pid = fork();
if (pid >= 0) {
/*Successful fork*/
if (pid == 0) {
rv = attempt_reconnect;
if (rv == 0) {
/*Notify sig_child Success*/
exit(0);
} else {
/*Notify sig_child Fail*/
exit(1);
}
}
}
}
void sig_child(int signum)
{
if(fork returned success) {
set flag to continue network stuff
}
else {
"Reconnect fail, retrying in 20 seconds...";
makeTimer("Reconnect Timer", &reconnect_timer_id, 20,0);
}
}
static void
timerHandler( int sig, siginfo_t *si, void *uc )
{
timer_t *tidp;
tidp = si->si_value.sival_ptr;
if ( *tidp == timeout_timer_id ) {
if(state != STATE_CONNECTED) {
"Timeout alarm received, not connected to server, exiting..."
exit(0);
} else {
"Timeout alarm received, connected to server, continuing..."
timeout_set = 0;
}
} else if ( *tidp == reconnect_timer_id ) {
"Reconnect alarm received, retrying...";
reconnect();
}
}
static int
makeTimer( char *name, timer_t *timerID, int expireSeconds, int intervalSeconds )
{
struct sigevent te;
struct itimerspec its;
struct sigaction sa;
int sigNo = SIGRTMIN;
/* Set up signal handler. */
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timerHandler;
sigemptyset(&sa.sa_mask);
if (sigaction(sigNo, &sa, NULL) == -1) {
"Failed to setup signal handling for" *name;
return(-1);
}
/* Set and enable alarm */
te.sigev_notify = SIGEV_SIGNAL;
te.sigev_signo = sigNo;
te.sigev_value.sival_ptr = timerID;
timer_create(CLOCK_REALTIME, &te, timerID);
its.it_interval.tv_sec = intervalSeconds;
its.it_interval.tv_nsec =0;
its.it_value.tv_sec = expireSeconds;
its.it_value.tv_nsec = 0;
timer_settime(*timerID, 0, &its, NULL);
return(0);
}
One idea could be not to use alarm( ) but create timers as subprocesses that kill the main processes with two different signals after sleep():
void timer( int nsec, int signum )
{
pid_t pid = getpid();
if( fork() > 0 ) {
sleep( nsec );
kill( pid, signum );
exit( 0 );
}
}
By using two different signals, (e.g. SIGUSR1 for the short timer and SIGUSR2 for the long one) you can have a signal handler like that:
void sig_timer( int signum )
{
if( signum == SIGUSR1 ) {
// reconnect
} else if( signumm == SIGUSR2 ) {
if( !reconnected )
exit( 11 );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With