X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fsubprocs.c;h=0ccf7d2367bdb2d680221d4e628411b9b4a83694;hb=d6b0217f2417bd19187f0ebc389d6c5c2233b11c;hp=009bb6dc529905286b79573e90a469c959d81194;hpb=488f2fa8fbdbc77e91a70da2962d73af49e6cace;p=xscreensaver diff --git a/driver/subprocs.c b/driver/subprocs.c index 009bb6dc..0ccf7d23 100644 --- a/driver/subprocs.c +++ b/driver/subprocs.c @@ -1,5 +1,5 @@ /* subprocs.c --- choosing, spawning, and killing screenhacks. - * xscreensaver, Copyright (c) 1991-2007 Jamie Zawinski + * xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -44,6 +44,7 @@ #endif /* VMS */ #include /* for the signal names */ +#include #if !defined(SIGCHLD) && defined(SIGCLD) # define SIGCHLD SIGCLD @@ -213,6 +214,7 @@ struct screenhack_job { pid_t pid; int screen; enum job_status status; + time_t launched, killed; struct screenhack_job *next; }; @@ -228,14 +230,21 @@ show_job_list (void) 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"); } @@ -277,6 +286,8 @@ make_job (pid_t pid, int screen, const char *cmd) job->pid = pid; job->screen = screen; job->status = job_running; + job->launched = time ((time_t *) 0); + job->killed = 0; job->next = jobs; jobs = job; @@ -315,6 +326,10 @@ static void 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)) @@ -326,7 +341,21 @@ clean_job_list (void) 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; } @@ -387,6 +416,11 @@ block_sigchld (void) 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; @@ -402,6 +436,7 @@ unblock_sigchld (void) #else /* !HAVE_SIGACTION */ signal(SIGPIPE, SIG_DFL); #endif /* !HAVE_SIGACTION */ + } block_sigchld_handler--; } @@ -415,7 +450,7 @@ kill_job (saver_info *si, pid_t pid, int signal) clean_job_list(); - if (block_sigchld_handler) + if (in_signal_handler_p) /* This function should not be called from the signal handler. */ abort(); @@ -433,7 +468,10 @@ kill_job (saver_info *si, pid_t pid, int signal) } 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; @@ -484,6 +522,7 @@ static RETSIGTYPE sigchld_handler (int sig) { saver_info *si = global_si_kludge; /* I hate C so much... */ + in_signal_handler_p++; if (si->prefs.debug_p) { @@ -510,6 +549,7 @@ sigchld_handler (int sig) } init_sigchld(); + in_signal_handler_p--; } #endif /* SIGCHLD */ @@ -851,7 +891,7 @@ fork_and_exec (saver_screen_info *ssi, const char *command) case 0: close (ConnectionNumber (si->dpy)); /* close display fd */ limit_subproc_memory (p->inferior_memory_limit, p->verbose_p); - hack_subproc_environment (ssi); /* set $DISPLAY */ + hack_subproc_environment (ssi->screen, ssi->screensaver_window); if (p->verbose_p) fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n", @@ -878,14 +918,22 @@ fork_and_exec (saver_screen_info *ssi, const char *command) } -static void -spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p) +void +spawn_screenhack (saver_screen_info *ssi) { saver_info *si = ssi->global; saver_preferences *p = &si->prefs; - raise_window (si, first_time_p, True, False); XFlush (si->dpy); + if (!monitor_powered_on_p (si)) + { + if (si->prefs.verbose_p) + fprintf (stderr, + "%s: %d: X says monitor has powered down; " + "not launching a hack.\n", blurb(), ssi->number); + return; + } + if (p->screenhacks_count) { screenhack *hack; @@ -1017,55 +1065,28 @@ spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p) break; } } -} - -void -spawn_screenhack (saver_info *si, Bool first_time_p) -{ - if (monitor_powered_on_p (si)) - { - int i; - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - spawn_screenhack_1 (ssi, first_time_p); - } - } - else if (si->prefs.verbose_p) - fprintf (stderr, - "%s: X says monitor has powered down; " - "not launching a hack.\n", blurb()); - - store_saver_status (si); /* store current hack numbers */ + store_saver_status (si); /* store current hack number */ } void -kill_screenhack (saver_info *si) +kill_screenhack (saver_screen_info *ssi) { - int i; - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - if (ssi->pid) - kill_job (si, ssi->pid, SIGTERM); - ssi->pid = 0; - } + saver_info *si = ssi->global; + if (ssi->pid) + kill_job (si, ssi->pid, SIGTERM); + ssi->pid = 0; } void -suspend_screenhack (saver_info *si, Bool suspend_p) +suspend_screenhack (saver_screen_info *ssi, Bool suspend_p) { #ifdef SIGSTOP /* older VMS doesn't have it... */ - int i; - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - if (ssi->pid) - kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT)); - } + saver_info *si = ssi->global; + if (ssi->pid) + kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT)); #endif /* SIGSTOP */ } @@ -1118,7 +1139,9 @@ hack_environment (saver_info *si) 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, ":"); @@ -1137,7 +1160,7 @@ hack_environment (saver_info *si) void -hack_subproc_environment (saver_screen_info *ssi) +hack_subproc_environment (Screen *screen, Window saver_window) { /* Store $DISPLAY into the environment, so that the $DISPLAY variable that the spawned processes inherit is correct. First, it must be on the same @@ -1152,8 +1175,8 @@ hack_subproc_environment (saver_screen_info *ssi) us to (eventually) run multiple hacks in Xinerama mode, where each hack has the same $DISPLAY but a different piece of glass. */ - saver_info *si = ssi->global; - const char *odpy = DisplayString (si->dpy); + Display *dpy = DisplayOfScreen (screen); + const char *odpy = DisplayString (dpy); char *ndpy = (char *) malloc (strlen(odpy) + 20); char *nssw = (char *) malloc (40); char *s, *c; @@ -1170,10 +1193,9 @@ hack_subproc_environment (saver_screen_info *ssi) while (isdigit(*s)) s++; /* skip over dpy number */ while (*s == '.') s++; /* skip over dot */ if (s[-1] != '.') *s++ = '.'; /* put on a dot */ - sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */ + sprintf(s, "%d", screen_number (screen)); /* put on screen number */ - sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", - (unsigned long) ssi->screensaver_window); + sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window); /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems any more, right? It's not Posix, but everyone seems to have it. */ @@ -1194,12 +1216,13 @@ hack_subproc_environment (saver_screen_info *ssi) /* GL crap */ Visual * -get_best_gl_visual (saver_screen_info *ssi) +get_best_gl_visual (saver_info *si, Screen *screen) { - saver_info *si = ssi->global; pid_t forked; int fds [2]; int in, out; + int errfds[2]; + int errin = -1, errout = -1; char buf[1024]; char *av[10]; @@ -1217,6 +1240,23 @@ get_best_gl_visual (saver_screen_info *ssi) in = fds [0]; out = fds [1]; + if (!si->prefs.verbose_p) + { + if (pipe (errfds)) + { + perror ("error creating pipe:"); + return 0; + } + + errin = errfds [0]; + errout = errfds [1]; + } + + block_sigchld(); /* This blocks it in the parent and child, to avoid + racing. It is never unblocked in the child before + the child exits, but that doesn't matter. + */ + switch ((int) (forked = fork ())) { case -1: @@ -1227,23 +1267,32 @@ get_best_gl_visual (saver_screen_info *ssi) } case 0: { - int stdout_fd = 1; - close (in); /* don't need this one */ close (ConnectionNumber (si->dpy)); /* close display fd */ - if (dup2 (out, stdout_fd) < 0) /* pipe stdout */ + if (dup2 (out, STDOUT_FILENO) < 0) /* pipe stdout */ { perror ("could not dup() a new stdout:"); return 0; } - hack_subproc_environment (ssi); /* set $DISPLAY */ + + if (! si->prefs.verbose_p) + { + close(errin); + if (dup2 (errout, STDERR_FILENO) < 0) + { + perror ("could not dup() a new stderr:"); + return 0; + } + } + + hack_subproc_environment (screen, 0); /* set $DISPLAY */ execvp (av[0], av); /* shouldn't return. */ - if (errno != ENOENT || si->prefs.verbose_p) + if (errno != ENOENT /* || si->prefs.verbose_p */ ) { - /* Ignore "no such file or directory" errors, unless verbose. + /* Ignore "no such file or directory" errors. Issue all other exec errors, though. */ sprintf (buf, "%s: running %s", blurb(), av[0]); perror (buf); @@ -1255,6 +1304,7 @@ get_best_gl_visual (saver_screen_info *ssi) { int result = 0; int wait_status = 0; + pid_t pid = -1; FILE *f = fdopen (in, "r"); unsigned long v = 0; @@ -1267,8 +1317,25 @@ get_best_gl_visual (saver_screen_info *ssi) *buf = 0; fclose (f); - /* Wait for the child to die. */ - waitpid (-1, &wait_status, 0); + if (! si->prefs.verbose_p) + { + close (errout); + close (errin); + } + + /* 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. */ if (1 == sscanf (buf, "0x%lx %c", &v, &c)) result = (int) v; @@ -1291,12 +1358,13 @@ get_best_gl_visual (saver_screen_info *ssi) } else { - Visual *v = id_to_visual (ssi->screen, result); + Visual *v = id_to_visual (screen, result); if (si->prefs.verbose_p) fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n", - blurb(), ssi->number, + blurb(), screen_number (screen), av[0], result, - (v == ssi->default_visual ? " (default)" : "")); + (v == DefaultVisualOfScreen (screen) + ? " (default)" : "")); return v; } }