views:

537

answers:

5

I'm building some FastCGI apps and it sort of bugs me that lighttpd doesn't kill them off after they've been idle, so I'm trying to have them close on their own.

I tried using

signal(SIGALRM, close);
alarm(300);

and having the close function execute exit(0), and that works almost well.

The problem is the close function is being called every time the main program loop runs though (I call alarm(300) each loop to reset it). I've read the man page for alarm() and it doesn't seem as though calling it multiple times with the same value should trip SIGALRM so I'm assuming Lighttpd is sending an alarm signal.

The big question! Is there a way to run a method after a specific interval, and have that interval be resettable without SIGALRM? I'd be nice if I could have multiple alarms as well.

Here's the whole app thus far:

#include <stdlib.h>
#include <stdarg.h>
#include <signal.h>
#include "fcgiapp.h"

FCGX_Stream     *in, *out, *err;
FCGX_ParamArray envp;
int calls = 0;

void print(char*, ...);
void close();

int main(void)
{
        // If I'm not used for five minutes, leave
        signal(SIGALRM, close);

        int reqCount = 0;

        while (FCGX_Accept(&in, &out, &err, &envp) >= 0)
        {
                print("Content-type: text/plain\r\n\r\n");

                int i = 0;
                char **elements = envp;
                print("Environment:\n");
                while (elements[i])
                        print("\t%s\n", elements[i++]);

                print("\n\nDone. Have served %d requests", ++reqCount);
                print("\nFor some reason, close was called %d times", calls);

                alarm(300);
        }

        return 0;
}

void print(char *strFormat, ...)
{
        va_list args;
        va_start(args, strFormat);
        FCGX_VFPrintF(out, strFormat, args);
        va_end(args);
}

void close()
{
        calls++;
//      exit(0);
}
A: 

Maybe you can wrap the close function by another function which will first call sleep()?

Igor Oks
But will that pause the whole application? I'll give it a shot
RandomInsano
It does sort of hang when I try sleeping the interrupt as I believe it doesn't run in a thread. Thanks for the tip though
RandomInsano
sleep implementation is based on SIGALRM so they are practically the same
eyalm
A: 

The argument to the alarm call is seconds, not minutes. So you're asking to be woken up in 5 seconds after each time through the main loop.

caf
Yes, sorry, it was set to seconds for debugging and I forgot to change it.
RandomInsano
A: 
  • Try to close all the file descriptors (including stdin and stdout). This should close the CGI instance if its idle.
  • You can use select() with timeout to schedule instead of SIGALRM
eyalm
stdin and stdout are a tad different in FastCGI. Also, stopping the app isn't the problem, killing it after it's been idle for five minutes is.
RandomInsano
A: 

Here's a solution that sort of avoids the point of the question, but it works. It will respond to only my application's signal events:

void close(int intSignal, siginfo_t *info, void *context)
{
        // For some stupid reason MY signal doesn't populate siginfo_t
        if (!info)
        {
                count++;
        }
}

If the siginfo struct is empty, that's because alarm() tripped it. If an outside process does it, siginfo_t.si_pid is populated with zero.

I still don't like this solution, but it works. Odd problem now is that doing an exit(0) doesn't close the application, though lighttpd thinks it's gone and spawns another. This means that now I've got rouge processes. raise(SIGUSR1) which is what is supposed to stop FastCGI scripts doesn't seem to do the trick either... hmmm...

Question still remains: How does one call asynchronous functions on an interval timer without the use of signals?

RandomInsano
A: 

the best way is: add a thread so that you can remove signal and alarm, and sync the thread and your main code (main thread).

EffoStaff Effo
That sir, is an excellent plan
RandomInsano