diff options
Diffstat (limited to 'config')
-rw-r--r-- | config/os/gnu-linux/Makefile.am | 2 | ||||
-rw-r--r-- | config/os/gnu-linux/sanitycheck.c | 73 | ||||
-rw-r--r-- | config/os/gnu-linux/systemtest.c | 313 | ||||
-rw-r--r-- | config/sysdeps/sanitycheck.c | 12 | ||||
-rw-r--r-- | config/sysdeps/systemtest.c | 12 |
5 files changed, 411 insertions, 1 deletions
diff --git a/config/os/gnu-linux/Makefile.am b/config/os/gnu-linux/Makefile.am index 56c5dca..eb4c557 100644 --- a/config/os/gnu-linux/Makefile.am +++ b/config/os/gnu-linux/Makefile.am @@ -1,3 +1,3 @@ MAINTAINERCLEANFILES = Makefile.in -noinst_HEADERS = time.c time.h +noinst_HEADERS = systemtest.c sanitycheck.c time.c time.h diff --git a/config/os/gnu-linux/sanitycheck.c b/config/os/gnu-linux/sanitycheck.c new file mode 100644 index 0000000..523fbbc --- /dev/null +++ b/config/os/gnu-linux/sanitycheck.c @@ -0,0 +1,73 @@ +/** + * GPL etc. + * + * @author Florian Faber + * + * @version 0.1 (2009-01-17) [FF] + * - initial version + **/ + +#include <stdio.h> +#include <jack/systemtest.h> +#include <jack/sanitycheck.h> + +int sanitycheck() { + int errors = 0; + int relogin = 0; + + if (!system_user_can_rtprio()) { + errors++; + relogin++; + fprintf(stderr, "\nYou are not allowed to set realtime priority.\n"); + + if (!system_has_rtprio_limits_conf()) { + errors++; + relogin++; + fprintf (stderr, "Please check your /etc/security/limits.conf for the following lines\n"); + fprintf (stderr, "and correct/add them:\n\n"); + fprintf(stderr, " @audio - rtprio 100\n"); + fprintf(stderr, " @audio - nice -10\n"); + } else if (!system_has_audiogroup()) { + errors++; + relogin++; + fprintf(stderr, "\nYour system has no audio group. Please add it by executing (as root):\n"); + fprintf(stderr, " groupadd -r audio\n"); + fprintf(stderr, " usermod -a -G audio %s\n", system_get_username()); + } else if (!system_user_in_audiogroup()) { + errors++; + relogin++; + fprintf(stderr, "\nYour system has an audio group, but you are not a member of it.\n"); + fprintf(stderr, "Please add yourself to the audio group by executing (as root):\n"); + fprintf(stderr, " usermod -a -G audio %s\n", system_get_username()); + } + } + if (system_has_frequencyscaling() && system_uses_frequencyscaling()) { + errors++; + fprintf(stderr, "\nYour system seems to use frequency scaling. This can have a serious impact\n"); + fprintf(stderr, "on the audio latency. Please turn it off, e.g. by chosing the 'performance'\n"); + fprintf(stderr, "governor.\n"); + } + if (system_memlock_is_unlimited()) { + fprintf(stderr, "\nMemory locking is unlimited - this is dangerous. Please alter the line"); + fprintf(stderr, " @audio - memlock unlimited"); + fprintf(stderr, "in your /etc/limits.conf to"); + fprintf(stderr, " @audio - memlock %llu\n", (system_available_physical_mem()*3)/4096); + } else if (0==system_memlock_amount()) { + errors++; + relogin++; + fprintf(stderr, "\nYou are not allowed to lock memory. Please add a line\n"); + fprintf(stderr, " @audio - memlock %llu\n", (system_available_physical_mem()*3)/4096); + fprintf(stderr, "in your /etc/limits.conf.\n"); + } + + if (0<relogin) { + fprintf(stderr, "\nAfter applying these changes, please re-login in order for them to take effect.\n"); + } + + if (0<errors) { + fprintf(stderr, "\nYou don't appear to have a sane system configuration. It is very likely that you\n"); + fprintf(stderr, "encounter xruns. Please apply all the above mentioned changes and start jack again!\n"); + } + + return errors; +} diff --git a/config/os/gnu-linux/systemtest.c b/config/os/gnu-linux/systemtest.c new file mode 100644 index 0000000..2daf86b --- /dev/null +++ b/config/os/gnu-linux/systemtest.c @@ -0,0 +1,313 @@ +/** + * GPL, yabbadabba + * + * Set of functions to gather system information for the jack setup wizard. + * + * TODO: Test for rt prio availability + * + * @author Florian Faber, faber@faberman.de + * + * @version 0.1 (2009-01-15) [FF] + * - initial version + * + **/ + +/** maximum number of groups a user can be a member of **/ +#define MAX_GROUPS 100 + +#include <fcntl.h> + +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> + +#include <sched.h> +#include <string.h> + +#include <sys/time.h> +#include <sys/resource.h> + +#include <stdio.h> +#include <errno.h> + +#include <jack/systemtest.h> + +/** + * This function checks for the existence of known frequency scaling mechanisms + * in this system by testing for the availability of scaling governors/ + * + * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise. + **/ +int system_has_frequencyscaling() { + int fd; + + fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY); + + if (-1==fd) { + return 0; + } + + (void) close(fd); + + return 1; +} + + +static int read_string(char* filename, char* buf, size_t buflen) { + int fd; + ssize_t r=-1; + + memset(buf, 0, buflen); + + fd = open(filename, O_RDONLY); + if (-1<fd) { + r = read(fd, buf, buflen); + (void) close(fd); + + if (-1==r) { + fprintf(stderr, "Error while reading \"%s\": %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + } + + return (int) r; +} + + +static int read_int(char* filename, int* value) { + char buf[20]; + + if (0<read_string(filename, buf, 20)) { + return (1==sscanf(buf, "%d", value)); + } + + return 0; +} + + +/** + * This function determines wether any CPU core uses a variable clock speed if frequency + * scaling is available. If the governor for all cores is either "powersave" or + * "performance", the CPU frequency can be assumed to be static. This is also the case + * if scaling_min_freq and scaling_max_freq are set to the same value. + * + * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise + **/ +int system_uses_frequencyscaling() { + int cpu=0, done=0, min, max; + char filename[256], buf[256]; + + while (!done) { + (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu); + if (0<read_string(filename, buf, 256)) { + if ((0!=strcmp("performance", buf)) && + (0!=strcmp("powersafe", buf))) { + // So it's neither the "performance" nor the "powersafe" governor + (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); + if (read_int(filename, &min)) { + (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + if (read_int(filename, &max)) { + if (min!=max) { + // wrong governor AND different frequency limits -> scaling + return 1; + } + } + } + } + } else { + // couldn't open file -> no more cores + done = 1; + } + cpu++; + } + + // couldn't find anything that points to scaling + return 0; +} + + +static gid_t get_group_by_name(const char* name) { + struct group* grp; + gid_t res = 0; + + while ((0==res) && (NULL != (grp = getgrent()))) { + if (0==strcmp(name, grp->gr_name)) { + res = grp->gr_gid; + } + } + + endgrent(); + + return res; +} + +/*** + * Checks for a definition in /etc/security/limits.conf that looks + * as if it allows RT scheduling priority. + * + * @returns 1 if there appears to be such a line + **/ +int system_has_rtprio_limits_conf () +{ + const char* limits = "/etc/security/limits.conf"; + char cmd[100]; + + snprintf (cmd, sizeof (cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits); + if (system (cmd) == 0) { + return 1; + } + return 0; +} + + +/** + * Checks for the existence of the 'audio' group on this system + * + * @returns 0 is there is no 'audio' group, the group id otherwise + **/ +int system_has_audiogroup() { + return get_group_by_name("audio") || get_group_by_name ("jackuser"); +} + + +/** + * Tests wether the owner of this process is in the 'audio' group. + * + * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise + **/ +int system_user_in_audiogroup() { + gid_t* list = (gid_t*) malloc(MAX_GROUPS * sizeof(gid_t)); + int num_groups, i=0, found=0; + unsigned int gid; + + if (NULL==list) { + perror("Cannot allocate group list structure"); + exit(EXIT_FAILURE); + } + + gid = get_group_by_name("audio"); + if (0==gid) { + fprintf(stderr, "No audio group found\n"); + exit(EXIT_FAILURE); + } + + num_groups = getgroups(MAX_GROUPS, list); + + while (i<num_groups) { + if (list[i]==gid) { + found = 1; + i = num_groups; + } + + i++; + } + + free(list); + + return found; +} + + +/** + * Determines wether the owner of this process can enable rt priority. + * + * @returns 0 if this process can not be switched to rt prio, non-0 otherwise + **/ +int system_user_can_rtprio() { + int min_prio; + struct sched_param schparam; + + memset(&schparam, 0, sizeof(struct sched_param)); + + if (-1 == (min_prio = sched_get_priority_min(SCHED_RR))) { + perror("sched_get_priority"); + exit(EXIT_FAILURE); + } + schparam.sched_priority = min_prio; + + if (0 == sched_setscheduler(0, SCHED_RR, &schparam)) { + // TODO: restore previous state + schparam.sched_priority = 0; + if (0 != sched_setscheduler(0, SCHED_OTHER, &schparam)) { + perror("sched_setscheduler"); + exit(EXIT_FAILURE); + } + return 1; + } + + return 0; +} + + +long long unsigned int system_memlock_amount() { + struct rlimit limits; + + if (-1==getrlimit(RLIMIT_MEMLOCK, &limits)) { + perror("getrlimit on RLIMIT_MEMLOCK"); + exit(EXIT_FAILURE); + } + + return limits.rlim_max; +} + + +/** + * Checks wether the memlock limit is unlimited + * + * @returns - 0 if the memlock limit is limited, non-0 otherwise + **/ +int system_memlock_is_unlimited() { + return ((RLIM_INFINITY==system_memlock_amount())?1:0); +} + + +long long unsigned int system_available_physical_mem() { + int fd, i; + char buf[256]; + long long unsigned int res = 0; + + fd = open("/proc/meminfo", O_RDONLY); + + if (0<fd) { + if (0<read(fd, buf, 256)) { + if (strcmp("MemTotal:", buf)) { + i=10; + while (buf[i]==' ') i++; + (void) sscanf(&buf[i], "%llu", &res); + } + } else { + perror("read from /proc/meminfo"); + } + + (void) close(fd); + } else { + perror("open /proc/meminfo"); + } + + return res*1024; +} + + +/** + * Gets the version of the currently running kernel. The string + * returned has to be freed by the caller. + * + * @returns String with the full version of the kernel + **/ +char* system_kernel_version() { + return NULL; +} + + + +char* system_get_username() { + char* res = NULL; + char* name = NULL; + + if ((name = getlogin())) { + res = strdup(name); + } + + return res; +} diff --git a/config/sysdeps/sanitycheck.c b/config/sysdeps/sanitycheck.c new file mode 100644 index 0000000..fb8359e --- /dev/null +++ b/config/sysdeps/sanitycheck.c @@ -0,0 +1,12 @@ +#ifndef _jack_sysdep_sanitycheck_c_ +#define _jack_sysdep_sanitycheck_c_ + +#if defined(__gnu_linux__) +#include <config/os/gnu-linux/sanitycheck.c> +#elif defined(__MACH__) && defined(__APPLE__) +/* relax */ +#else +/* relax */ +#endif + +#endif /* _jack_sysdep_sanitycheck_c_ */ diff --git a/config/sysdeps/systemtest.c b/config/sysdeps/systemtest.c new file mode 100644 index 0000000..7afa3ec --- /dev/null +++ b/config/sysdeps/systemtest.c @@ -0,0 +1,12 @@ +#ifndef _jack_sysdep_systemtest_c_ +#define _jack_sysdep_systemtest_c_ + +#if defined(__gnu_linux__) +#include <config/os/gnu-linux/systemtest.c> +#elif defined(__MACH__) && defined(__APPLE__) +/* relax */ +#else +/* relax */ +#endif + +#endif /* _jack_sysdep_systemtest_c_ */ |