src/debug.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- enableCoreDump
- debug_watch
- debugSelf
- watchCallGdb
- sigchld
- watch_main
- 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];
}