git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3434 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.117.0
| @@ -19,7 +19,7 @@ DIST_SUBDIRS = config jack libjack jackd drivers example-clients tools doc man | |||||
| pkgconfigdir = $(libdir)/pkgconfig | pkgconfigdir = $(libdir)/pkgconfig | ||||
| pkgconfig_DATA = jack.pc | pkgconfig_DATA = jack.pc | ||||
| EXTRA_DIST = COPYING COPYING.GPL COPYING.LGPL libjack/simd.c jack.spec | |||||
| EXTRA_DIST = COPYING COPYING.GPL COPYING.LGPL libjack/simd.c jack.spec testing | |||||
| AUTOMAKE_OPTIONS = foreign | AUTOMAKE_OPTIONS = foreign | ||||
| @@ -1,3 +1,3 @@ | |||||
| MAINTAINERCLEANFILES = Makefile.in | MAINTAINERCLEANFILES = Makefile.in | ||||
| noinst_HEADERS = time.c time.h | |||||
| noinst_HEADERS = systemtest.c sanitycheck.c time.c time.h | |||||
| @@ -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; | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| @@ -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_ */ | |||||
| @@ -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_ */ | |||||
| @@ -0,0 +1,21 @@ | |||||
| #ifndef __jack_sanitycheck_h__ | |||||
| #define __jack_sanitycheck_h__ | |||||
| /** | |||||
| * GPL etc. | |||||
| * | |||||
| * @author Florian Faber | |||||
| * | |||||
| * @version 0.1 (2009-01-17) [FF] | |||||
| * - initial version | |||||
| **/ | |||||
| /** | |||||
| * Performs a range of sanity checks on the system. The number of | |||||
| * found problems is returned. | |||||
| * | |||||
| **/ | |||||
| int sanitycheck(); | |||||
| #endif /* __jack_sanitycheck_h__ */ | |||||
| @@ -0,0 +1,97 @@ | |||||
| #ifndef __jack_systemtest_h__ | |||||
| #define __jack_systemtest_h__ | |||||
| /** | |||||
| * GPL, yabbadabba | |||||
| * | |||||
| * Set of functions to gather system information for the jack setup wizard. | |||||
| * | |||||
| * @author Florian Faber, faber@faberman.de | |||||
| * | |||||
| * @version 0.1 (2009-01-15) [FF] | |||||
| * - initial version | |||||
| * | |||||
| **/ | |||||
| /** | |||||
| * This function checks for the existence of known frequency scaling mechanisms | |||||
| * in this system. | |||||
| * | |||||
| * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise. | |||||
| **/ | |||||
| int system_has_frequencyscaling(); | |||||
| /** | |||||
| * This function determines wether the CPU has a variable clock speed if frequency | |||||
| * scaling is available. | |||||
| * | |||||
| * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise | |||||
| **/ | |||||
| int system_uses_frequencyscaling(); | |||||
| /*** | |||||
| * 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 (); | |||||
| /** | |||||
| * Checks for the existence of the 'audio' group on this system | |||||
| * | |||||
| * @returns 0 is there is no 'audio' group, non-0 otherwise | |||||
| **/ | |||||
| int system_has_audiogroup(); | |||||
| /** | |||||
| * 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(); | |||||
| /** | |||||
| * 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(); | |||||
| long long unsigned int system_memlock_amount(); | |||||
| /** | |||||
| * Checks wether the memlock limit is unlimited | |||||
| * | |||||
| * @returns 0 if the memlock limit is limited, non-0 otherwise | |||||
| **/ | |||||
| int system_memlock_is_unlimited(); | |||||
| long long unsigned int system_available_physical_mem(); | |||||
| /** | |||||
| * Gets the version of the currently running kernel | |||||
| * | |||||
| * @returns String with the full version of the kernel | |||||
| **/ | |||||
| char* system_kernel_version(); | |||||
| /** | |||||
| * Returns the username. The caller is in charge of disposal of | |||||
| * the returned name. | |||||
| * | |||||
| * @returns Pointer to a username or NULL | |||||
| **/ | |||||
| char* system_get_username(); | |||||
| #endif /* __jack_systemtest_h__ */ | |||||
| @@ -44,9 +44,13 @@ lib_LTLIBRARIES = libjackserver.la | |||||
| libjackserver_la_CFLAGS = $(AM_CFLAGS) | libjackserver_la_CFLAGS = $(AM_CFLAGS) | ||||
| libjackserver_la_SOURCES = engine.c clientengine.c transengine.c ../libjack/client.c ../libjack/driver.c ../libjack/intclient.c \ | |||||
| ../libjack/messagebuffer.c ../libjack/pool.c ../libjack/port.c ../libjack/midiport.c ../libjack/ringbuffer.c ../libjack/shm.c \ | |||||
| ../libjack/thread.c ../libjack/time.c ../libjack/transclient.c ../libjack/unlock.c | |||||
| libjackserver_la_SOURCES = engine.c clientengine.c transengine.c \ | |||||
| ../libjack/systemtest.c ../libjack/sanitycheck.c \ | |||||
| ../libjack/client.c ../libjack/driver.c ../libjack/intclient.c \ | |||||
| ../libjack/messagebuffer.c ../libjack/pool.c ../libjack/port.c \ | |||||
| ../libjack/midiport.c ../libjack/ringbuffer.c ../libjack/shm.c \ | |||||
| ../libjack/thread.c ../libjack/time.c ../libjack/transclient.c \ | |||||
| ../libjack/unlock.c | |||||
| libjackserver_la_LIBADD = simd.lo @OS_LDFLAGS@ | libjackserver_la_LIBADD = simd.lo @OS_LDFLAGS@ | ||||
| libjackserver_la_LDFLAGS = -export-dynamic -version-info @JACK_SO_VERSION@ | libjackserver_la_LDFLAGS = -export-dynamic -version-info @JACK_SO_VERSION@ | ||||
| @@ -369,6 +369,7 @@ static void usage (FILE *file) | |||||
| " [ --timeout OR -t client-timeout-in-msecs ]\n" | " [ --timeout OR -t client-timeout-in-msecs ]\n" | ||||
| " [ --port-max OR -p maximum-number-of-ports]\n" | " [ --port-max OR -p maximum-number-of-ports]\n" | ||||
| " [ --debug-timer OR -D ]\n" | " [ --debug-timer OR -D ]\n" | ||||
| " [ --no-sanity-checks OR -N ]\n" | |||||
| " [ --verbose OR -v ]\n" | " [ --verbose OR -v ]\n" | ||||
| " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" | " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" | ||||
| " [ --replace-registry OR -r ]\n" | " [ --replace-registry OR -r ]\n" | ||||
| @@ -519,6 +520,7 @@ main (int argc, char *argv[]) | |||||
| { "port-max", 1, 0, 'p' }, | { "port-max", 1, 0, 'p' }, | ||||
| { "no-mlock", 0, 0, 'm' }, | { "no-mlock", 0, 0, 'm' }, | ||||
| { "name", 1, 0, 'n' }, | { "name", 1, 0, 'n' }, | ||||
| { "no-sanity-checks", 1, 0, 'N' }, | |||||
| { "unlock", 0, 0, 'u' }, | { "unlock", 0, 0, 'u' }, | ||||
| { "realtime", 0, 0, 'R' }, | { "realtime", 0, 0, 'R' }, | ||||
| { "replace-registry", 0, 0, 'r' }, | { "replace-registry", 0, 0, 'r' }, | ||||
| @@ -540,6 +542,7 @@ main (int argc, char *argv[]) | |||||
| int driver_nargs = 1; | int driver_nargs = 1; | ||||
| int show_version = 0; | int show_version = 0; | ||||
| int replace_registry = 0; | int replace_registry = 0; | ||||
| int do_sanity_checks = 1; | |||||
| int i; | int i; | ||||
| int rc; | int rc; | ||||
| @@ -588,6 +591,10 @@ main (int argc, char *argv[]) | |||||
| server_name = optarg; | server_name = optarg; | ||||
| break; | break; | ||||
| case 'N': | |||||
| do_sanity_checks = 0; | |||||
| break; | |||||
| case 'p': | case 'p': | ||||
| port_max = (unsigned int) atol (optarg); | port_max = (unsigned int) atol (optarg); | ||||
| break; | break; | ||||
| @@ -642,6 +649,10 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| } | } | ||||
| if (do_sanity_checks && (0 < sanitycheck())) { | |||||
| return -1; | |||||
| } | |||||
| if (show_version) { | if (show_version) { | ||||
| printf ( "jackd version " VERSION | printf ( "jackd version " VERSION | ||||
| " tmpdir " DEFAULT_TMP_DIR | " tmpdir " DEFAULT_TMP_DIR | ||||
| @@ -0,0 +1 @@ | |||||
| #include <sysdeps/sanitycheck.c> | |||||
| @@ -0,0 +1 @@ | |||||
| #include <sysdeps/systemtest.c> | |||||