src/debug.c

/* [<][>]
[^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. enableCoreDump
  2. debug_watch
  3. debugSelf
  4. watchCallGdb
  5. sigchld
  6. watch_main
  7. watchInit



/* $Id: debug.c,v 1.10 2002/04/04 11:07:45 proff Exp $
 * $Copyright$
 */

#include "nglobal.h"

#include "debug.h"

#define MIN_DEBUG_TIME (30*60)  /* time between debug attempts */

EXPORT bool enableCoreDump()
/* [<][>][^][v][top][bottom][index][help] */
{
        struct rlimit r;
        if (getrlimit(RLIMIT_CORE, &r) == 0)
        {
                r.rlim_cur = r.rlim_max = RLIM_INFINITY;
                if (setrlimit(RLIMIT_CORE, &r) != 0)
                        loge (("couldn't enable core dumps"));
                else
                        return TRUE;
        }
        {
                loge (("couldn't get RLIMIT_CORE"));
        }
        return FALSE;
}

static void
debug_watch()
/* [<][>][^][v][top][bottom][index][help] */
{
    char buf[512];
    sprintf(buf, "%d %s\n", getpid(), logPrintP);
    if (write(Watch_fd, buf, strlen(buf)) != strlen(buf))
    {
            loge (("couldn't inform watch"));
            return;
    }
}    

EXPORT void debugSelf()
/* [<][>][^][v][top][bottom][index][help] */
{
        if (Watch_fd >= 0)
        {
                debug_watch();
                return;
        }
        watchCallGdb(getpid(), logPrintP);
}


/*
 * watch_call_gdb can be called directly (i.e not from the "watch" task),
 * e.g if a crash occurs before watch has been created
 */
EXPORT void watchCallGdb(pid_t pid, char *msg)
/* [<][>][^][v][top][bottom][index][help] */
{
        bool self = (pid == getpid());
        pid_t child = fork();
        if (child == 0)
        {
                char pid_asc[80];
        
        char cwd[MAX_PATH]="";
                if (self) /* give parent time to core */
                        usleep(5 * 1000000);
                getcwd(cwd, MAX_PATH);
                sprintf(pid_asc, "%d", (int)pid);
                execl("/bin/sh", "sh", PATH_DEBUG_SH, cwd, Argv0, pid_asc, Version, msg, NULL);
                _exit(1);
        }
        if (child == -1)
        {
                loge (("fork()"));
                return;
        }
}
    
static RETSIGTYPE
sigchld(int sig)
/* [<][>][^][v][top][bottom][index][help] */
{
        waitpid(-1, NULL, WNOHANG);
        signal(SIGCHLD, sigchld);
}

static void
watch_main(int fd)
/* [<][>][^][v][top][bottom][index][help] */
{
        time_t last_debug = 0;
        settaskinfo("watch: ready");
        signal(SIGCHLD, sigchld);
        for (;;)
        {
                char buf[512];
                pid_t pid;
                int i;
                char *msg;
                time_t t;
                FILE *fh = fdopen(fd, "r");
                if (!fgets(buf, sizeof buf, fh))
                {
                        /* this usually harmless and means
                           our parent has exited */
                        retire_vm_proc(0);
                }
                waitpid(-1, NULL, WNOHANG);
                msg = strchr(buf, ' ');
                sscanf(buf, "%d", &i);
                if (!msg || i < 1)
                {
                        logen (("bad pid: %s", buf));
                        continue;
                }
                pid = i;
                msg++;
                t = time(NULL);
                if (t - last_debug < MIN_DEBUG_TIME)
                        continue;
                last_debug = t;

                watchCallGdb(pid, msg);
        }
}           

EXPORT void watchInit()
/* [<][>][^][v][top][bottom][index][help] */
{
        int p[2];
        if (pipe(p) != 0)
        {
                loge (("pipe()"));
                Exit(1);
        }
        if (make_vm_proc(nc_watch, -1, "watch") == 0) /* 0 == child */
        {
                close(p[1]);
                watch_main(p[0]);

                NOTREACHED;
        }
        close(p[0]);
        Watch_fd = p[1];
}

/* [<][>][^][v][top][bottom][index][help] */