X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fsubprocs.c;h=e34f896859dca33fd4e385f27ea935817f62cccf;hb=a1d41b2aa6e18bf9a49b914a99dda8232c5d7762;hp=c693d5b68a6cb6b0180d15dbd848bd3c469569b3;hpb=72c1f4c1dc6ab07fe121a327ff1c30bf51ef74c1;p=xscreensaver diff --git a/driver/subprocs.c b/driver/subprocs.c index c693d5b6..e34f8968 100644 --- a/driver/subprocs.c +++ b/driver/subprocs.c @@ -1,6 +1,5 @@ /* subprocs.c --- choosing, spawning, and killing screenhacks. - * xscreensaver, Copyright (c) 1991, 1992, 1993, 1995, 1997, 1998 - * Jamie Zawinski + * xscreensaver, Copyright (c) 1991-2001 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 @@ -31,8 +30,10 @@ # include /* for waitpid() and associated macros */ #endif -#if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) +#if (defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)) || \ + defined(HAVE_SETRLIMIT) # include /* for setpriority() and PRIO_PROCESS */ + /* and also setrlimit() and RLIMIT_AS */ #endif #ifdef VMS @@ -67,7 +68,7 @@ extern int kill (pid_t, int); /* signal() is in sys/signal.h... */ #include "xscreensaver.h" #include "yarandom.h" - +#include "visual.h" /* for id_to_visual() */ extern saver_info *global_si_kludge; /* I hate C so much... */ @@ -106,6 +107,64 @@ nice_subproc (int nice_level) } +/* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size + of a process's address space, i.e., the maximal brk(2) and mmap(2) values. + Setting this lets you put a cap on how much memory a process can allocate. + */ +#if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS) +# define RLIMIT_AS RLIMIT_VMEM +#endif + +static void +limit_subproc_memory (int address_space_limit, Bool verbose_p) +{ +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS) + struct rlimit r; + + if (address_space_limit < 10 * 1024) /* let's not be crazy */ + return; + + if (getrlimit (RLIMIT_AS, &r) != 0) + { + char buf [512]; + sprintf (buf, "%s: getrlimit(RLIMIT_AS) failed", blurb()); + perror (buf); + return; + } + + r.rlim_cur = address_space_limit; + + if (setrlimit (RLIMIT_AS, &r) != 0) + { + char buf [512]; + sprintf (buf, "%s: setrlimit(RLIMIT_AS, {%lu, %lu}) failed", + blurb(), r.rlim_cur, r.rlim_max); + perror (buf); + return; + } + + if (verbose_p) + { + int i = address_space_limit; + char buf[100]; + if (i >= (1<<30) && i == ((i >> 30) << 30)) + sprintf(buf, "%dG", i >> 30); + else if (i >= (1<<20) && i == ((i >> 20) << 20)) + sprintf(buf, "%dM", i >> 20); + else if (i >= (1<<10) && i == ((i >> 10) << 10)) + sprintf(buf, "%dK", i >> 10); + else + sprintf(buf, "%d bytes", i); + + fprintf (stderr, "%s: limited pid %lu address space to %s.\n", + blurb(), (unsigned long) getpid (), buf); + } + +#endif /* HAVE_SETRLIMIT && RLIMIT_AS */ +} + + + #ifndef VMS static void @@ -395,12 +454,6 @@ make_job (pid_t pid, const char *cmd) } while (isspace(*in)) in++; /* skip whitespace */ - if (first && *in == ':') /* token was a visual name; skip it. */ - { - out = name; - first = 0; - goto AGAIN; - } *out = 0; job->name = strdup(name); @@ -481,7 +534,7 @@ static void describe_dead_child (saver_info *, pid_t, int wait_status); static int block_sigchld_handler = 0; -static void +void block_sigchld (void) { #ifdef HAVE_SIGACTION @@ -494,7 +547,7 @@ block_sigchld (void) block_sigchld_handler++; } -static void +void unblock_sigchld (void) { #ifdef HAVE_SIGACTION @@ -771,7 +824,7 @@ select_visual_of_hack (saver_screen_info *ssi, screenhack *hack) saver_preferences *p = &si->prefs; Bool selected; - if (hack->visual && *hack->visual == ':') + if (hack->visual && *hack->visual) selected = select_visual(ssi, hack->visual); else selected = select_visual(ssi, 0); @@ -884,6 +937,7 @@ spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p) case 0: close (ConnectionNumber (si->dpy)); /* close display fd */ nice_subproc (p->nice_inferior); /* change process priority */ + limit_subproc_memory (p->inferior_memory_limit, p->verbose_p); hack_subproc_environment (ssi); /* set $DISPLAY */ exec_screenhack (si, hack->command); /* this does not return */ abort(); @@ -912,8 +966,8 @@ spawn_screenhack (saver_info *si, Bool first_time_p) } else if (si->prefs.verbose_p) fprintf (stderr, - "%s: server reports that monitor has powered down; " - "not launching a new hack.\n", blurb()); + "%s: X says monitor has powered down; " + "not launching a hack.\n", blurb()); store_saver_status (si); /* store current hack numbers */ } @@ -971,15 +1025,14 @@ emergency_kill_subproc (saver_info *si) Bool screenhack_running_p (saver_info *si) { - Bool result = True; + Bool any_running_p = False; int i; for (i = 0; i < si->nscreens; i++) { saver_screen_info *ssi = &si->screens[i]; - if (!ssi->pid) - result = False; + if (ssi->pid) any_running_p = True; } - return result; + return any_running_p; } @@ -1051,6 +1104,111 @@ hack_subproc_environment (saver_screen_info *ssi) #endif /* HAVE_PUTENV */ } + +/* GL crap */ + +Visual * +get_best_gl_visual (saver_screen_info *ssi) +{ + saver_info *si = ssi->global; + pid_t forked; + int fds [2]; + int in, out; + char buf[1024]; + + char *av[10]; + int ac = 0; + + av[ac++] = "xscreensaver-gl-helper"; + av[ac] = 0; + + if (pipe (fds)) + { + perror ("error creating pipe:"); + return 0; + } + + in = fds [0]; + out = fds [1]; + + switch ((int) (forked = fork ())) + { + case -1: + { + sprintf (buf, "%s: couldn't fork", blurb()); + perror (buf); + saver_exit (si, 1, 0); + } + 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 */ + { + perror ("could not dup() a new stdout:"); + return 0; + } + hack_subproc_environment (ssi); /* set $DISPLAY */ + + execvp (av[0], av); /* shouldn't return. */ + + if (errno != ENOENT || si->prefs.verbose_p) + { + /* Ignore "no such file or directory" errors, unless verbose. + Issue all other exec errors, though. */ + sprintf (buf, "%s: running %s", blurb(), av[0]); + perror (buf); + } + exit (1); /* exits fork */ + break; + } + default: + { + int result = 0; + int wait_status = 0; + + FILE *f = fdopen (in, "r"); + unsigned long v = 0; + char c; + + close (out); /* don't need this one */ + + *buf = 0; + fgets (buf, sizeof(buf)-1, f); + fclose (f); + + /* Wait for the child to die. */ + waitpid (-1, &wait_status, 0); + + if (1 == sscanf (buf, "0x%x %c", &v, &c)) + result = (int) v; + + if (result == 0) + { + if (si->prefs.verbose_p) + fprintf (stderr, "%s: %s did not report a GL visual!\n", + blurb(), av[0]); + return 0; + } + else + { + Visual *v = id_to_visual (ssi->screen, result); + if (si->prefs.verbose_p) + fprintf (stderr, "%s: %s says the GL visual is 0x%X%s.\n", + blurb(), av[0], result, + (v == ssi->default_visual ? " (the default)" : "")); + return v; + } + } + } + + abort(); +} + + /* Restarting the xscreensaver process from scratch. */