diff options
Diffstat (limited to 'lib/drmtest.c')
-rw-r--r-- | lib/drmtest.c | 830 |
1 files changed, 2 insertions, 828 deletions
diff --git a/lib/drmtest.c b/lib/drmtest.c index b518b811..a5aac4dc 100644 --- a/lib/drmtest.c +++ b/lib/drmtest.c @@ -167,16 +167,6 @@ int drm_get_card(void) return -1; } -static void oom_adjust_for_doom(void) -{ - int fd; - const char always_kill[] = "1000"; - - fd = open("/proc/self/oom_score_adj", O_WRONLY); - igt_assert(fd != -1); - igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill)); -} - /** Open the first DRM device we can find, searching up to 16 device nodes */ static int __drm_open_any(void) { @@ -195,8 +185,6 @@ static int __drm_open_any(void) fd = -1; } - oom_adjust_for_doom(); - return fd; } @@ -226,8 +214,6 @@ static int __drm_open_any_render(void) return fd; } - oom_adjust_for_doom(); - return fd; } @@ -291,10 +277,6 @@ int drm_open_any_render(void) } /* signal interrupt helpers */ -static bool igt_only_list_subtests(void); - -static unsigned int exit_handler_count; - static struct igt_helper_process signal_helper; long long int sig_stat; static void __attribute__((noreturn)) signal_helper_process(pid_t pid) @@ -334,609 +316,7 @@ void igt_stop_signal_helper(void) sig_stat = 0; } -/* subtests helpers */ -static bool list_subtests = false; -static char *run_single_subtest = NULL; -static const char *in_subtest = NULL; -static bool in_fixture = false; -static bool test_with_subtests = false; -static enum { - CONT = 0, SKIP, FAIL -} skip_subtests_henceforth = CONT; - -/* fork support state */ -pid_t *test_children; -int num_test_children; -int test_children_sz; -bool test_child; - -bool __igt_fixture(void) -{ - assert(!in_fixture); - - if (igt_only_list_subtests()) - return false; - - if (skip_subtests_henceforth) - return false; - - in_fixture = true; - return true; -} - -void __igt_fixture_complete(void) -{ - assert(in_fixture); - - in_fixture = false; -} - -void __igt_fixture_end(void) -{ - assert(in_fixture); - - in_fixture = false; - longjmp(igt_subtest_jmpbuf, 1); -} - -bool igt_exit_called; -static void check_igt_exit(int sig) -{ - /* When not killed by a signal check that igt_exit() has been properly - * called. */ - assert(sig != 0 || igt_exit_called); -} - - -static void print_version(void) -{ - struct utsname uts; - - if (list_subtests) - return; - - uname(&uts); - - fprintf(stdout, "IGT-Version: %s-%s (%s) (%s: %s %s)\n", PACKAGE_VERSION, - IGT_GIT_SHA1, TARGET_CPU_PLATFORM, - uts.sysname, uts.release, uts.machine); -} - -static void print_usage(const char *command_str, const char *help_str, - bool output_on_stderr) -{ - FILE *f = output_on_stderr ? stderr : stdout; - - fprintf(f, "Usage: %s [OPTIONS]\n" - " --list-subtests\n" - " --run-subtest <pattern>\n", command_str); - if (help_str) - fprintf(f, "%s\n", help_str); -} - -int igt_subtest_init_parse_opts(int argc, char **argv, - const char *extra_short_opts, - struct option *extra_long_opts, - const char *help_str, - igt_opt_handler_t extra_opt_handler) -{ - int c, option_index = 0; - static struct option long_options[] = { - {"list-subtests", 0, 0, 'l'}, - {"run-subtest", 1, 0, 'r'}, - {"help", 0, 0, 'h'}, - }; - const char *command_str; - char *short_opts; - struct option *combined_opts; - int extra_opt_count; - int all_opt_count; - int ret = 0; - - test_with_subtests = true; - - command_str = argv[0]; - if (strrchr(command_str, '/')) - command_str = strrchr(command_str, '/') + 1; - - /* First calculate space for all passed-in extra long options */ - all_opt_count = 0; - while (extra_long_opts && extra_long_opts[all_opt_count].name) - all_opt_count++; - extra_opt_count = all_opt_count; - - all_opt_count += ARRAY_SIZE(long_options); - - combined_opts = malloc(all_opt_count * sizeof(*combined_opts)); - memcpy(combined_opts, extra_long_opts, - extra_opt_count * sizeof(*combined_opts)); - - /* Copy the subtest long options (and the final NULL entry) */ - memcpy(&combined_opts[extra_opt_count], long_options, - ARRAY_SIZE(long_options) * sizeof(*combined_opts)); - - ret = asprintf(&short_opts, "%sh", - extra_short_opts ? extra_short_opts : ""); - assert(ret >= 0); - - while ((c = getopt_long(argc, argv, short_opts, combined_opts, - &option_index)) != -1) { - switch(c) { - case 'l': - if (!run_single_subtest) - list_subtests = true; - break; - case 'r': - if (!list_subtests) - run_single_subtest = strdup(optarg); - break; - case 'h': - print_usage(command_str, help_str, false); - ret = -1; - goto out; - case '?': - if (opterr) { - print_usage(command_str, help_str, true); - ret = -2; - goto out; - } - /* - * Just ignore the error, since the unknown argument - * can be something the caller understands and will - * parse by doing a second getopt scanning. - */ - break; - default: - ret = extra_opt_handler(c, option_index); - if (ret) - goto out; - } - } - - igt_install_exit_handler(check_igt_exit); - oom_adjust_for_doom(); - -out: - free(short_opts); - free(combined_opts); - print_version(); - - return ret; -} - -enum igt_log_level igt_log_level = IGT_LOG_INFO; - -static void common_init(void) -{ - char *env = getenv("IGT_LOG_LEVEL"); - - if (!env) - return; - - if (strcmp(env, "debug") == 0) - igt_log_level = IGT_LOG_DEBUG; - else if (strcmp(env, "info") == 0) - igt_log_level = IGT_LOG_INFO; - else if (strcmp(env, "warn") == 0) - igt_log_level = IGT_LOG_WARN; - else if (strcmp(env, "none") == 0) - igt_log_level = IGT_LOG_NONE; -} - -void igt_subtest_init(int argc, char **argv) -{ - int ret; - - /* supress getopt errors about unknown options */ - opterr = 0; - - ret = igt_subtest_init_parse_opts(argc, argv, NULL, NULL, NULL, NULL); - if (ret < 0) - /* exit with no error for -h/--help */ - exit(ret == -1 ? 0 : ret); - - /* reset opt parsing */ - optind = 1; - - common_init(); -} - -void igt_simple_init(void) -{ - print_version(); - - common_init(); -} - -/* - * Note: Testcases which use these helpers MUST NOT output anything to stdout - * outside of places protected by igt_run_subtest checks - the piglit - * runner adds every line to the subtest list. - */ -bool __igt_run_subtest(const char *subtest_name) -{ - assert(!in_subtest); - assert(!in_fixture); - - if (list_subtests) { - printf("%s\n", subtest_name); - return false; - } - - if (run_single_subtest && - strcmp(subtest_name, run_single_subtest) != 0) - return false; - - if (skip_subtests_henceforth) { - printf("Subtest %s: %s\n", subtest_name, - skip_subtests_henceforth == SKIP ? - "SKIP" : "FAIL"); - return false; - } - - return (in_subtest = subtest_name); -} - -const char *igt_subtest_name(void) -{ - return in_subtest; -} - -static bool igt_only_list_subtests(void) -{ - return list_subtests; -} - -static bool skipped_one = false; -static bool succeeded_one = false; -static bool failed_one = false; -static int igt_exitcode; - -static void exit_subtest(const char *) __attribute__((noreturn)); -static void exit_subtest(const char *result) -{ - printf("Subtest %s: %s\n", in_subtest, result); - in_subtest = NULL; - longjmp(igt_subtest_jmpbuf, 1); -} - -void igt_skip(const char *f, ...) -{ - va_list args; - skipped_one = true; - - assert(!test_child); - - if (!igt_only_list_subtests()) { - va_start(args, f); - vprintf(f, args); - va_end(args); - } - - if (in_subtest) { - exit_subtest("SKIP"); - } else if (test_with_subtests) { - skip_subtests_henceforth = SKIP; - assert(in_fixture); - __igt_fixture_end(); - } else { - exit(77); - } -} - -void __igt_skip_check(const char *file, const int line, - const char *func, const char *check, - const char *f, ...) -{ - va_list args; - int err = errno; - - if (f) { - static char *buf; - - /* igt_skip never returns, so try to not leak too badly. */ - if (buf) - free(buf); - - va_start(args, f); - vasprintf(&buf, f, args); - va_end(args); - - igt_skip("Test requirement not met in function %s, file %s:%i:\n" - "Last errno: %i, %s\n" - "Test requirement: (%s)\n%s", - func, file, line, err, strerror(err), check, buf); - } else { - igt_skip("Test requirement not met in function %s, file %s:%i:\n" - "Last errno: %i, %s\n" - "Test requirement: (%s)\n", - func, file, line, err, strerror(err), check); - } -} - -void igt_success(void) -{ - succeeded_one = true; - if (in_subtest) - exit_subtest("SUCCESS"); -} - -void igt_fail(int exitcode) -{ - assert(exitcode != 0 && exitcode != 77); - - if (!failed_one) - igt_exitcode = exitcode; - - failed_one = true; - - /* Silent exit, parent will do the yelling. */ - if (test_child) - exit(exitcode); - - if (in_subtest) - exit_subtest("FAIL"); - else { - assert(!test_with_subtests || in_fixture); - - if (in_fixture) { - skip_subtests_henceforth = FAIL; - __igt_fixture_end(); - } - - exit(exitcode); - } -} - -static bool run_under_gdb(void) -{ - char buf[1024]; - - sprintf(buf, "/proc/%d/exe", getppid()); - return (readlink (buf, buf, sizeof (buf)) != -1 && - strncmp(basename(buf), "gdb", 3) == 0); -} - -void __igt_fail_assert(int exitcode, const char *file, - const int line, const char *func, const char *assertion, - const char *f, ...) -{ - va_list args; - int err = errno; - - printf("Test assertion failure function %s, file %s:%i:\n" - "Last errno: %i, %s\n" - "Failed assertion: %s\n", - func, file, line, err, strerror(err), assertion); - - if (f) { - va_start(args, f); - vprintf(f, args); - va_end(args); - } - - if (run_under_gdb()) - abort(); - igt_fail(exitcode); -} - -void igt_exit(void) -{ - igt_exit_called = true; - - if (igt_only_list_subtests()) - exit(0); - - if (!test_with_subtests) - exit(0); - - /* Calling this without calling one of the above is a failure */ - assert(skipped_one || succeeded_one || failed_one); - - if (failed_one) - exit(igt_exitcode); - else if (succeeded_one) - exit(0); - else - exit(77); -} - -static int helper_process_count; -static pid_t helper_process_pids[] = -{ -1, -1, -1, -1}; - -static void reset_helper_process_list(void) -{ - for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++) - helper_process_pids[i] = -1; - helper_process_count = 0; -} - -static void fork_helper_exit_handler(int sig) -{ - for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++) { - pid_t pid = helper_process_pids[i]; - int status, ret; - - if (pid != -1) { - /* Someone forgot to fill up the array? */ - assert(pid != 0); - - ret = kill(pid, SIGQUIT); - assert(ret == 0); - while (waitpid(pid, &status, 0) == -1 && - errno == EINTR) - ; - helper_process_count--; - } - } - - assert(helper_process_count == 0); -} - -bool __igt_fork_helper(struct igt_helper_process *proc) -{ - pid_t pid; - int id; - - assert(!proc->running); - assert(helper_process_count < ARRAY_SIZE(helper_process_pids)); - - for (id = 0; helper_process_pids[id] != -1; id++) - ; - - igt_install_exit_handler(fork_helper_exit_handler); - - switch (pid = fork()) { - case -1: - igt_assert(0); - case 0: - exit_handler_count = 0; - reset_helper_process_list(); - oom_adjust_for_doom(); - - return true; - default: - proc->running = true; - proc->pid = pid; - proc->id = id; - helper_process_pids[id] = pid; - helper_process_count++; - - return false; - } - -} - -void igt_stop_helper(struct igt_helper_process *proc) -{ - int status, ret; - - assert(proc->running); - - ret = kill(proc->pid, - proc->use_SIGKILL ? SIGKILL : SIGQUIT); - assert(ret == 0); - while (waitpid(proc->pid, &status, 0) == -1 && - errno == EINTR) - ; - igt_assert(WIFSIGNALED(status) && - WTERMSIG(status) == (proc->use_SIGKILL ? SIGKILL : SIGQUIT)); - - proc->running = false; - - helper_process_pids[proc->id] = -1; - helper_process_count--; -} - -void igt_wait_helper(struct igt_helper_process *proc) -{ - int status; - - assert(proc->running); - - while (waitpid(proc->pid, &status, 0) == -1 && - errno == EINTR) - ; - igt_assert(WIFEXITED(status) && WEXITSTATUS(status) == 0); - - proc->running = false; - - helper_process_pids[proc->id] = -1; - helper_process_count--; -} - -static void children_exit_handler(int sig) -{ - int ret; - - assert(!test_child); - - for (int nc = 0; nc < num_test_children; nc++) { - int status = -1; - ret = kill(test_children[nc], SIGQUIT); - assert(ret == 0); - - while (waitpid(test_children[nc], &status, 0) == -1 && - errno == EINTR) - ; - } - - num_test_children = 0; -} - -bool __igt_fork(void) -{ - assert(!test_with_subtests || in_subtest); - assert(!test_child); - - igt_install_exit_handler(children_exit_handler); - - if (num_test_children >= test_children_sz) { - if (!test_children_sz) - test_children_sz = 4; - else - test_children_sz *= 2; - - test_children = realloc(test_children, - sizeof(pid_t)*test_children_sz); - igt_assert(test_children); - } - - switch (test_children[num_test_children++] = fork()) { - case -1: - igt_assert(0); - case 0: - test_child = true; - exit_handler_count = 0; - reset_helper_process_list(); - oom_adjust_for_doom(); - - return true; - default: - return false; - } - -} - -/** - * igt_waitchildren: - * - * Wait for all children forked with igt_fork - * - * The magic here is that exit codes from children will be correctly propagated - */ -void igt_waitchildren(void) -{ - assert(!test_child); - - for (int nc = 0; nc < num_test_children; nc++) { - int status = -1; - while (waitpid(test_children[nc], &status, 0) == -1 && - errno == EINTR) - ; - - if (status != 0) { - if (WIFEXITED(status)) { - printf("child %i failed with exit status %i\n", - nc, WEXITSTATUS(status)); - igt_fail(WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - printf("child %i died with signal %i, %s\n", - nc, WTERMSIG(status), - strsignal(WTERMSIG(status))); - igt_fail(99); - } else { - printf("Unhandled failure in child %i\n", nc); - abort(); - } - } - } - - num_test_children = 0; -} - -static bool env_set(const char *env_var, bool default_value) +bool igt_env_set(const char *env_var, bool default_value) { char *val; @@ -947,59 +327,12 @@ static bool env_set(const char *env_var, bool default_value) return atoi(val) != 0; } -bool igt_run_in_simulation(void) -{ - static int simulation = -1; - - if (simulation == -1) - simulation = env_set("INTEL_SIMULATION", false); - - return simulation; -} - -/** - * igt_skip_on_simulation: - * - * Skip tests when INTEL_SIMULATION env war is set - * - * Skip the test when running on simulation (and that's relevant only when - * we're not in the mode where we list the subtests). - * - * This function is subtest aware (since it uses igt_skip) and so can be used to - * skip specific subtests or all subsequent subtests. - */ -void igt_skip_on_simulation(void) -{ - if (igt_only_list_subtests()) - return; - - igt_require(!igt_run_in_simulation()); -} - -void igt_log(enum igt_log_level level, const char *format, ...) -{ - va_list args; - - assert(format); - - if (igt_log_level > level) - return; - - va_start(args, format); - if (level == IGT_LOG_WARN) { - fflush(stdout); - vfprintf(stderr, format, args); - } else - vprintf(format, args); - va_end(args); -} - bool drmtest_dump_aub(void) { static int dump_aub = -1; if (dump_aub == -1) - dump_aub = env_set("IGT_DUMP_AUB", false); + dump_aub = igt_env_set("IGT_DUMP_AUB", false); return dump_aub; } @@ -1092,165 +425,6 @@ void igt_cleanup_aperture_trashers(void) free(trash_bos); } -#define MAX_SIGNALS 32 -#define MAX_EXIT_HANDLERS 5 - -static struct { - sighandler_t handler; - bool installed; -} orig_sig[MAX_SIGNALS]; - -static igt_exit_handler_t exit_handler_fn[MAX_EXIT_HANDLERS]; -static bool exit_handler_disabled; -static sigset_t saved_sig_mask; -static const int handled_signals[] = - { SIGINT, SIGHUP, SIGTERM, SIGQUIT, SIGPIPE, SIGABRT, SIGSEGV, SIGBUS }; - -static int install_sig_handler(int sig_num, sighandler_t handler) -{ - orig_sig[sig_num].handler = signal(sig_num, handler); - - if (orig_sig[sig_num].handler == SIG_ERR) - return -1; - - orig_sig[sig_num].installed = true; - - return 0; -} - -static void restore_sig_handler(int sig_num) -{ - /* Just restore the default so that we properly fall over. */ - signal(sig_num, SIG_DFL); -} - -static void restore_all_sig_handler(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(orig_sig); i++) - restore_sig_handler(i); -} - -static void call_exit_handlers(int sig) -{ - int i; - - if (!exit_handler_count) { - return; - } - - for (i = exit_handler_count - 1; i >= 0; i--) - exit_handler_fn[i](sig); - - /* ensure we don't get called twice */ - exit_handler_count = 0; -} - -static void igt_atexit_handler(void) -{ - restore_all_sig_handler(); - - if (!exit_handler_disabled) - call_exit_handlers(0); -} - -static void fatal_sig_handler(int sig) -{ - pid_t pid, tid; - - restore_all_sig_handler(); - - /* - * exit_handler_disabled is always false here, since when we set it - * we also block signals. - */ - call_exit_handlers(sig); - - /* Workaround cached PID and TID races on glibc and Bionic libc. */ - pid = syscall(SYS_getpid); - tid = syscall(SYS_gettid); - - syscall(SYS_tgkill, pid, tid, sig); -} - -/* - * Set a handler that will be called either when the process calls exit() or - * returns from the main function, or one of the signals in 'handled_signals' - * is raised. MAX_EXIT_HANDLERS handlers can be installed, each of which will - * be called only once, even if a subsequent signal is raised. If the exit - * handlers are called due to a signal, the signal will be re-raised with the - * original signal disposition after all handlers returned. - * - * The handler will be passed the signal number if called due to a signal, or - * 0 otherwise. - */ -void igt_install_exit_handler(igt_exit_handler_t fn) -{ - int i; - - for (i = 0; i < exit_handler_count; i++) - if (exit_handler_fn[i] == fn) - return; - - igt_assert(exit_handler_count < MAX_EXIT_HANDLERS); - - exit_handler_fn[exit_handler_count] = fn; - exit_handler_count++; - - if (exit_handler_count > 1) - return; - - for (i = 0; i < ARRAY_SIZE(handled_signals); i++) { - if (install_sig_handler(handled_signals[i], - fatal_sig_handler)) - goto err; - } - - if (atexit(igt_atexit_handler)) - goto err; - - return; -err: - restore_all_sig_handler(); - exit_handler_count--; - - igt_assert_f(0, "failed to install the signal handler\n"); -} - -void igt_disable_exit_handler(void) -{ - sigset_t set; - int i; - - if (exit_handler_disabled) - return; - - sigemptyset(&set); - for (i = 0; i < ARRAY_SIZE(handled_signals); i++) - sigaddset(&set, handled_signals[i]); - - if (sigprocmask(SIG_BLOCK, &set, &saved_sig_mask)) { - perror("sigprocmask"); - return; - } - - exit_handler_disabled = true; -} - -void igt_enable_exit_handler(void) -{ - if (!exit_handler_disabled) - return; - - if (sigprocmask(SIG_SETMASK, &saved_sig_mask, NULL)) { - perror("sigprocmask"); - return; - } - - exit_handler_disabled = false; -} - #define PREFAULT_DEBUGFS "/sys/module/i915/parameters/prefault_disable" static void igt_prefault_control(bool enable) { |