/* subprocs.c --- choosing, spawning, and killing screenhacks.
- * xscreensaver, Copyright (c) 1991-2012 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#endif /* VMS */
#include <signal.h> /* for the signal names */
+#include <time.h>
#if !defined(SIGCHLD) && defined(SIGCLD)
# define SIGCHLD SIGCLD
pid_t pid;
int screen;
enum job_status status;
+ time_t launched, killed;
struct screenhack_job *next;
};
struct screenhack_job *job;
fprintf(stderr, "%s: job list:\n", blurb());
for (job = jobs; job; job = job->next)
- fprintf (stderr, " %5ld: %2d: (%s) %s\n",
- (long) job->pid,
- job->screen,
- (job->status == job_running ? "running" :
- job->status == job_stopped ? "stopped" :
- job->status == job_killed ? " killed" :
- job->status == job_dead ? " dead" : " ???"),
- job->name);
+ {
+ char b[] = " ??:??:?? ";
+ char *t = (job->killed ? timestring (job->killed) :
+ job->launched ? timestring (job->launched) : b);
+ t += 11;
+ t[8] = 0;
+ fprintf (stderr, " %5ld: %2d: (%s) %s %s\n",
+ (long) job->pid,
+ job->screen,
+ (job->status == job_running ? "running" :
+ job->status == job_stopped ? "stopped" :
+ job->status == job_killed ? " killed" :
+ job->status == job_dead ? " dead" : " ???"),
+ t, job->name);
+ }
fprintf (stderr, "\n");
}
job->pid = pid;
job->screen = screen;
job->status = job_running;
+ job->launched = time ((time_t *) 0);
+ job->killed = 0;
job->next = jobs;
jobs = job;
clean_job_list (void)
{
struct screenhack_job *job, *prev, *next;
+ time_t now = time ((time_t *) 0);
+ static time_t last_warn = 0;
+ Bool warnedp = False;
+
for (prev = 0, job = jobs, next = (job ? job->next : 0);
job;
prev = job, job = next, next = (job ? job->next : 0))
free_job (job);
job = prev;
}
+ else if (job->status == job_killed &&
+ now - job->killed > 10 &&
+ now - last_warn > 10)
+ {
+ fprintf (stderr,
+ "%s: WARNING: pid %ld (%s) sent SIGTERM %ld seconds ago"
+ " and did not die!\n",
+ blurb(),
+ (long) job->pid,
+ job->name,
+ (long) (now - job->killed));
+ warnedp = True;
+ }
}
+ if (warnedp) last_warn = now;
}
void
unblock_sigchld (void)
{
+ if (block_sigchld_handler <= 0)
+ abort();
+
+ if (block_sigchld_handler <= 1) /* only unblock if count going to 0 */
+ {
#ifdef HAVE_SIGACTION
struct sigaction sa;
sigset_t child_set;
#else /* !HAVE_SIGACTION */
signal(SIGPIPE, SIG_DFL);
#endif /* !HAVE_SIGACTION */
+ }
block_sigchld_handler--;
}
clean_job_list();
- if (block_sigchld_handler)
+ if (in_signal_handler_p)
/* This function should not be called from the signal handler. */
abort();
}
switch (signal) {
- case SIGTERM: job->status = job_killed; break;
+ case SIGTERM:
+ job->status = job_killed;
+ job->killed = time ((time_t *) 0);
+ break;
#ifdef SIGSTOP
/* #### there must be a way to do this on VMS... */
case SIGSTOP: job->status = job_stopped; break;
if (def_path && *def_path)
{
const char *opath = getenv("PATH");
- char *npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
+ char *npath;
+ if (! opath) opath = "/bin:/usr/bin"; /* WTF */
+ npath = (char *) malloc(strlen(def_path) + strlen(opath) + 20);
strcpy (npath, "PATH=");
strcat (npath, def_path);
strcat (npath, ":");
{
int result = 0;
int wait_status = 0;
+ pid_t pid = -1;
FILE *f = fdopen (in, "r");
unsigned long v = 0;
close (errin);
}
- /* Wait for the child to die. */
- waitpid (-1, &wait_status, 0);
+ /* Wait for the child to die - wait for this pid only, not others. */
+ pid = waitpid (forked, &wait_status, 0);
+ if (si->prefs.debug_p)
+ {
+ write_string (STDERR_FILENO, blurb());
+ write_string (STDERR_FILENO, ": waitpid(");
+ write_long (STDERR_FILENO, (long) forked);
+ write_string (STDERR_FILENO, ") ==> ");
+ write_long (STDERR_FILENO, (long) pid);
+ write_string (STDERR_FILENO, "\n");
+ }
unblock_sigchld(); /* child is dead and waited, unblock now. */