diff --git a/configure.ac b/configure.ac index 1b03135..38930b7 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,32 @@ AS_IF([test "$ac_cv_func_gettimeofday" = yes], [Define to 1 if you have a standard gettimeofday function]) ]) +dnl The --enable-proc-loadavg option will automatically test for the +dnl presence of a working /proc/loadavg file, but it can also be set +dnl manually in order to override the test result. +AC_CACHE_CHECK(for usable /proc/loadavg, ac_cv_proc_loadavg_test, + [AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +int main() { + int fd, i, n; char str[64]; + fd = open("/proc/loadavg", O_RDONLY | O_CLOEXEC); + if (fd < 0 || read(fd, str, 64) < 0 || lseek(fd, 0, SEEK_SET) < 0) return 1; + for (str[63] = i = n = 0; i < 3 && n < 64; ++n) if (str[n] == ' ') ++i; + return i < 3 || strtoul(&str[n], NULL, 10) < 1 || close(fd) < 0; } ]])], + ac_cv_proc_loadavg_test=yes, + ac_cv_proc_loadavg_test=no)]) + +AC_MSG_CHECKING(wether to use /proc/loadavg) +AC_ARG_ENABLE(proc-loadavg, + AS_HELP_STRING([--enable-proc-loadavg={yes|no}],[Allow to limit the processes started by make to not exceed the total number of active processes on a system based on /proc/loadavg [default=autodetect]]), + ac_cv_proc_loadavg=$enableval, + ac_cv_proc_loadavg=$ac_cv_proc_loadavg_test) +AS_IF(test x$ac_cv_proc_loadavg = xyes, + AC_DEFINE(USE_PROC_LOADAVG, 1, [Defined when load limiting shall be based on /proc/loadavg])) +AC_MSG_RESULT($ac_cv_proc_loadavg) + AC_CHECK_FUNCS([strdup strndup umask mkstemp mktemp fdopen \ dup dup2 getcwd realpath sigsetmask sigaction \ getgroups seteuid setegid setlinebuf setreuid setregid \ diff --git a/job.c b/job.c index 5f24597..b1ff68e 100644 --- a/job.c +++ b/job.c @@ -1963,6 +1963,59 @@ load_too_high (void) { #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) return 1; +#elif defined(USE_PROC_LOADAVG) + /* Read from /proc/loadavg and use the number of active running + tasks & threads to determine if we can start another process. */ +#define PROC_LOADAVG_SIZE 64 + static int fd = -2; + char proc_loadavg[PROC_LOADAVG_SIZE]; + int i, p; + unsigned long load; + + if (max_load_average < 0.0 || fd == -1) + return 0; + + if (fd == -2) + { + fd = open ("/proc/loadavg", O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + perror_with_name (_("cannot open /proc/loadavg: "), "open"); + fd = -1; + return 0; + } + } + p = read (fd, proc_loadavg, PROC_LOADAVG_SIZE); + if (p < 0) + { + perror_with_name (_("cannot read /proc/loadavg: "), "read"); + close(fd); + fd = -1; + return 0; + } + if (lseek (fd, 0, SEEK_SET) < 0) + { + perror_with_name (_("cannot seek on /proc/loadavg: "), "lseek"); + close(fd); + fd = -1; + return 0; + } + proc_loadavg[p < PROC_LOADAVG_SIZE ? p : PROC_LOADAVG_SIZE - 1] = '\0'; + for (i = p = 0; i < 3 && p < PROC_LOADAVG_SIZE; ++p) + { + if (proc_loadavg[p] == ' ') + ++i; + } + if (i < 3) + { + errno = ENOTSUP; + perror_with_name (_("unsupported format of /proc/loadavg: "), "load_too_high"); + close (fd); + fd = -1; + return 0; + } + load = strtoul(&proc_loadavg[p], NULL, 10); + return max_load_average < (double) load; #else static double last_sec; static time_t last_now;