summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml1
-rw-r--r--lib/Makefile.sources2
-rw-r--r--lib/drmtest.c830
-rw-r--r--lib/drmtest.h269
-rw-r--r--lib/igt_core.c901
-rw-r--r--lib/igt_core.h305
6 files changed, 1213 insertions, 1095 deletions
diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index bf85685f..6723fe1f 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -17,6 +17,7 @@
<title>Intel GPU Tools</title>
<xi:include href="xml/debug.xml"/>
<xi:include href="xml/drmtest.xml"/>
+ <xi:include href="xml/igt_core.xml"/>
<xi:include href="xml/igt_debugfs.xml"/>
<xi:include href="xml/igt_display.xml"/>
<xi:include href="xml/igt_kms.xml"/>
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index ba4e8282..a3a679c1 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -41,5 +41,7 @@ libintel_tools_la_SOURCES = \
intel_iosf.c \
igt_kms.c \
igt_kms.h \
+ igt_core.c \
+ igt_core.h \
$(NULL)
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)
{
diff --git a/lib/drmtest.h b/lib/drmtest.h
index a0b6e9fc..f9f21d39 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -45,6 +45,7 @@
#include "intel_gpu_tools.h"
#include "ioctl_wrappers.h"
+#include "igt_core.h"
int drm_get_card(void);
int drm_open_any(void);
@@ -61,266 +62,7 @@ void igt_permute_array(void *array, unsigned size,
unsigned i,
unsigned j));
void igt_progress(const char *header, uint64_t i, uint64_t total);
-
-/**
- * igt_simple_init:
- *
- * Init for simple tests without subtests
- */
-void igt_simple_init(void);
-#define igt_simple_main \
- static void igt_tokencat(__real_main, __LINE__)(void); \
- int main(int argc, char **argv) { \
- igt_simple_init(); \
- igt_tokencat(__real_main, __LINE__)(); \
- exit(0); \
- } \
- static void igt_tokencat(__real_main, __LINE__)(void) \
-
-/* subtest infrastructure */
-jmp_buf igt_subtest_jmpbuf;
-void igt_subtest_init(int argc, char **argv);
-typedef int (*igt_opt_handler_t)(int opt, int opt_index);
-struct option;
-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 opt_handler);
-bool __igt_run_subtest(const char *subtest_name);
-/**
- * igt_subtest:
- *
- * Denote a subtest code block
- *
- * Magic control flow which denotes a subtest code block. Within that codeblock
- * igt_skip|success will only bail out of the subtest. The _f variant accepts a
- * printf format string, which is useful for constructing combinatorial tests.
- */
-#define igt_tokencat2(x, y) x ## y
-#define igt_tokencat(x, y) igt_tokencat2(x, y)
-#define __igt_subtest_f(tmp, format...) \
- for (char tmp [256]; \
- snprintf( tmp , sizeof( tmp ), \
- format), \
- __igt_run_subtest( tmp ) && \
- (setjmp(igt_subtest_jmpbuf) == 0); \
- igt_success())
-
-/**
- * igt_subtest_f:
- * @...: format string
- *
- * Denote a subtest code block
- *
- * Like #igt_subtest, but also accepts a printf format string
- */
-#define igt_subtest_f(f...) \
- __igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
-#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
- (setjmp(igt_subtest_jmpbuf) == 0); \
- igt_success())
-const char *igt_subtest_name(void);
-#define igt_main \
- static void igt_tokencat(__real_main, __LINE__)(void); \
- int main(int argc, char **argv) { \
- igt_subtest_init(argc, argv); \
- igt_tokencat(__real_main, __LINE__)(); \
- igt_exit(); \
- } \
- static void igt_tokencat(__real_main, __LINE__)(void) \
-
-
-/**
- * igt_skip:
- *
- * Subtest aware test skipping
- *
- * For tests with subtests this will either bail out of the current subtest or
- * mark all subsequent subtests as SKIP (in case some global setup code failed).
- *
- * For normal tests without subtest it will directly exit.
- */
-__attribute__((format(printf, 1, 2)))
-void igt_skip(const char *f, ...) __attribute__((noreturn));
-__attribute__((format(printf, 5, 6)))
-void __igt_skip_check(const char *file, const int line,
- const char *func, const char *check,
- const char *format, ...) __attribute__((noreturn));
-/**
- * igt_success:
- *
- * Complete a (subtest) as successfull
- *
- * This bails out of a subtests and marks it as successful. For global tests it
- * it won't bail out of anything.
- */
-void igt_success(void);
-
-/**
- * igt_fail:
- *
- * Fail a testcase
- *
- * For subtest it just bails out of the subtest, when run in global context it
- * will exit. Note that it won't attempt to keep on running further tests,
- * presuming that some mandatory setup failed.
- */
-void igt_fail(int exitcode) __attribute__((noreturn));
-__attribute__((format(printf, 6, 7)))
-void __igt_fail_assert(int exitcode, const char *file,
- const int line, const char *func, const char *assertion,
- const char *format, ...)
- __attribute__((noreturn));
-/**
- * igt_exit:
- *
- * exit() for igts
- *
- * This will exit the test with the right exit code when subtests have been
- * skipped. For normal tests it exits with a successful exit code, presuming
- * everything has worked out. For subtests it also checks that at least one
- * subtest has been run (save when only listing subtests.
- */
-void igt_exit(void) __attribute__((noreturn));
-/**
- * igt_assert:
- *
- * Fails (sub-)test if a condition is not met
- *
- * Should be used everywhere where a test checks results.
- */
-#define igt_assert(expr) \
- do { if (!(expr)) \
- __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
- } while (0)
-#define igt_assert_f(expr, f...) \
- do { if (!(expr)) \
- __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
- } while (0)
-/**
- * igt_assert_cmptint:
- *
- * Like #igt_assert, but displays the values being compared on failure.
- */
-#define igt_assert_cmpint(n1, cmp, n2) \
- do { \
- int __n1 = (n1), __n2 = (n2); \
- if (__n1 cmp __n2) ; else \
- __igt_fail_assert(99, __FILE__, __LINE__, __func__, \
- #n1 " " #cmp " " #n2, \
- "error: %d %s %d\n", __n1, #cmp, __n2); \
- } while (0)
-
-/**
- * igt_require:
- *
- * Skip a (sub-)test if a condition is not met
- *
- * This is useful to streamline the skip logic since it allows for a more flat
- * code control flow.
- */
-#define igt_require(expr) igt_skip_on(!(expr))
-#define igt_skip_on(expr) \
- do { if ((expr)) \
- __igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
- } while (0)
-#define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
-#define igt_skip_on_f(expr, f...) \
- do { if ((expr)) \
- __igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
- } while (0)
-
-bool __igt_fixture(void);
-void __igt_fixture_complete(void);
-void __igt_fixture_end(void) __attribute__((noreturn));
-/**
- * igt_fixture:
- *
- * Annotate global test fixture code
- *
- * Testcase with subtests often need to set up a bunch of global state as the
- * common test fixture. To avoid such code interferring with the subtest
- * enumeration (e.g. when enumerating on systemes without an intel gpu) such
- * blocks should be annotated with igt_fixture.
- */
-#define igt_fixture for (int igt_tokencat(__tmpint,__LINE__) = 0; \
- igt_tokencat(__tmpint,__LINE__) < 1 && \
- __igt_fixture() && \
- (setjmp(igt_subtest_jmpbuf) == 0); \
- igt_tokencat(__tmpint,__LINE__) ++, \
- __igt_fixture_complete())
-
-bool __igt_fork(void);
-/**
- * igt_fork:
- * @child: name of the int variable with the child number
- * @num_children: number of children to fork
- *
- * Fork parallel test threads with fork()
- *
- * Joining all test threads should be done with igt_waitchildren to ensure that
- * the exit codes of all children are properly reflected in the test status.
- */
-#define igt_fork(child, num_children) \
- for (int child = 0; child < (num_children); child++) \
- for (; __igt_fork(); exit(0))
-void igt_waitchildren(void);
-
-struct igt_helper_process {
- bool running;
- bool use_SIGKILL;
- pid_t pid;
- int id;
-};
-bool __igt_fork_helper(struct igt_helper_process *proc);
-void igt_stop_helper(struct igt_helper_process *proc);
-void igt_wait_helper(struct igt_helper_process *proc);
-#define igt_fork_helper(proc) \
- for (; __igt_fork_helper(proc); exit(0))
-
-/* logging support */
-enum igt_log_level {
- IGT_LOG_DEBUG,
- IGT_LOG_INFO,
- IGT_LOG_WARN,
- IGT_LOG_NONE,
-};
-__attribute__((format(printf, 2, 3)))
-void igt_log(enum igt_log_level level, const char *format, ...);
-#define igt_debug(f...) igt_log(IGT_LOG_DEBUG, f)
-#define igt_info(f...) igt_log(IGT_LOG_INFO, f)
-#define igt_warn(f...) igt_log(IGT_LOG_WARN, f)
-extern enum igt_log_level igt_log_level;
-
-#define igt_warn_on(condition) do {\
- if (condition) \
- igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
- #condition, __func__, __FILE__, __LINE__); \
- } while (0)
-#define igt_warn_on_f(condition, f...) do {\
- if (condition) {\
- igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
- #condition, __func__, __FILE__, __LINE__); \
- igt_warn(f); \
- } \
- } while (0)
-
-/* helpers to automatically reduce test runtime in simulation */
-bool igt_run_in_simulation(void);
-#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
-/**
- * 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);
+bool igt_env_set(const char *env_var, bool default_value);
bool drmtest_dump_aub(void);
@@ -332,13 +74,6 @@ void igt_cleanup_aperture_trashers(void);
#define do_or_die(x) igt_assert((x) == 0)
#define do_ioctl(fd, ptr, sz) igt_assert(drmIoctl((fd), (ptr), (sz)) == 0)
-typedef void (*igt_exit_handler_t)(int sig);
-
-/* reliable atexit helpers, also work when killed by a signal (if possible) */
-void igt_install_exit_handler(igt_exit_handler_t fn);
-void igt_enable_exit_handler(void);
-void igt_disable_exit_handler(void);
-
/* set vt into graphics mode, required to prevent fbcon from interfering */
void igt_set_vt_graphics_mode(void);
diff --git a/lib/igt_core.c b/lib/igt_core.c
new file mode 100644
index 00000000..27c159c6
--- /dev/null
+++ b/lib/igt_core.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+#include "igt_debugfs.h"
+#include "../version.h"
+#include "config.h"
+
+#include "igt_core.h"
+
+/**
+ * SECTION:igt_core
+ * @short_description: Core i-g-t testing support
+ * @title: i-g-t core
+ *
+ * This libary implements the core of the i-g-t test support infrastructure.
+ * Main features are the subtest enumeration, cmdline option parsing helpers for
+ * subtest handling and various helpers to structure testcases with subtests and
+ * handle subtest test results.
+ *
+ * Auxiliary code provides exit handlers, support for forked processes with test
+ * result propagation. Other generally useful functionality includes optional
+ * structure logging infrastructure and some support code for running reduced
+ * test set on in simulated hardware environments.
+ */
+
+static unsigned int exit_handler_count;
+
+/* 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);
+}
+
+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));
+}
+
+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();
+
+ oom_adjust_for_doom();
+
+ 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;
+}
+
+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);
+}
+
+/* fork support code */
+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;
+}
+
+/* exit handler code */
+#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;
+}
+
+/* simulation enviroment support */
+bool igt_run_in_simulation(void)
+{
+ static int simulation = -1;
+
+ if (simulation == -1)
+ simulation = igt_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());
+}
+
+/* structured logging */
+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);
+}
+
diff --git a/lib/igt_core.h b/lib/igt_core.h
new file mode 100644
index 00000000..1ec0bfcb
--- /dev/null
+++ b/lib/igt_core.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright © 2007,2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+
+#ifndef IGT_CORE_H
+#define IGT_CORE_H
+
+bool igt_only_list_subtests(void);
+
+bool __igt_fixture(void);
+void __igt_fixture_complete(void);
+void __igt_fixture_end(void) __attribute__((noreturn));
+/**
+ * igt_fixture:
+ *
+ * Annotate global test fixture code
+ *
+ * Testcase with subtests often need to set up a bunch of global state as the
+ * common test fixture. To avoid such code interferring with the subtest
+ * enumeration (e.g. when enumerating on systemes without an intel gpu) such
+ * blocks should be annotated with igt_fixture.
+ */
+#define igt_fixture for (int igt_tokencat(__tmpint,__LINE__) = 0; \
+ igt_tokencat(__tmpint,__LINE__) < 1 && \
+ __igt_fixture() && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_tokencat(__tmpint,__LINE__) ++, \
+ __igt_fixture_complete())
+
+/* subtest infrastructure */
+jmp_buf igt_subtest_jmpbuf;
+void igt_subtest_init(int argc, char **argv);
+typedef int (*igt_opt_handler_t)(int opt, int opt_index);
+struct option;
+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 opt_handler);
+
+bool __igt_run_subtest(const char *subtest_name);
+/**
+ * igt_subtest:
+ *
+ * Denote a subtest code block
+ *
+ * Magic control flow which denotes a subtest code block. Within that codeblock
+ * igt_skip|success will only bail out of the subtest. The _f variant accepts a
+ * printf format string, which is useful for constructing combinatorial tests.
+ */
+#define igt_tokencat2(x, y) x ## y
+#define igt_tokencat(x, y) igt_tokencat2(x, y)
+#define __igt_subtest_f(tmp, format...) \
+ for (char tmp [256]; \
+ snprintf( tmp , sizeof( tmp ), \
+ format), \
+ __igt_run_subtest( tmp ) && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_success())
+
+/**
+ * igt_subtest_f:
+ * @...: format string
+ *
+ * Denote a subtest code block
+ *
+ * Like #igt_subtest, but also accepts a printf format string
+ */
+#define igt_subtest_f(f...) \
+ __igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
+#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
+ (setjmp(igt_subtest_jmpbuf) == 0); \
+ igt_success())
+const char *igt_subtest_name(void);
+#define igt_main \
+ static void igt_tokencat(__real_main, __LINE__)(void); \
+ int main(int argc, char **argv) { \
+ igt_subtest_init(argc, argv); \
+ igt_tokencat(__real_main, __LINE__)(); \
+ igt_exit(); \
+ } \
+ static void igt_tokencat(__real_main, __LINE__)(void) \
+
+/**
+ * igt_simple_init:
+ *
+ * Init for simple tests without subtests
+ */
+void igt_simple_init(void);
+#define igt_simple_main \
+ static void igt_tokencat(__real_main, __LINE__)(void); \
+ int main(int argc, char **argv) { \
+ igt_simple_init(); \
+ igt_tokencat(__real_main, __LINE__)(); \
+ exit(0); \
+ } \
+ static void igt_tokencat(__real_main, __LINE__)(void) \
+
+/**
+ * igt_skip:
+ *
+ * Subtest aware test skipping
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as SKIP (in case some global setup code failed).
+ *
+ * For normal tests without subtest it will directly exit.
+ */
+__attribute__((format(printf, 1, 2)))
+void igt_skip(const char *f, ...) __attribute__((noreturn));
+__attribute__((format(printf, 5, 6)))
+void __igt_skip_check(const char *file, const int line,
+ const char *func, const char *check,
+ const char *format, ...) __attribute__((noreturn));
+/**
+ * igt_success:
+ *
+ * Complete a (subtest) as successfull
+ *
+ * This bails out of a subtests and marks it as successful. For global tests it
+ * it won't bail out of anything.
+ */
+void igt_success(void);
+
+/**
+ * igt_fail:
+ *
+ * Fail a testcase
+ *
+ * For subtest it just bails out of the subtest, when run in global context it
+ * will exit. Note that it won't attempt to keep on running further tests,
+ * presuming that some mandatory setup failed.
+ */
+void igt_fail(int exitcode) __attribute__((noreturn));
+__attribute__((format(printf, 6, 7)))
+void __igt_fail_assert(int exitcode, const char *file,
+ const int line, const char *func, const char *assertion,
+ const char *format, ...)
+ __attribute__((noreturn));
+/**
+ * igt_exit:
+ *
+ * exit() for igts
+ *
+ * This will exit the test with the right exit code when subtests have been
+ * skipped. For normal tests it exits with a successful exit code, presuming
+ * everything has worked out. For subtests it also checks that at least one
+ * subtest has been run (save when only listing subtests.
+ */
+void igt_exit(void) __attribute__((noreturn));
+/**
+ * igt_assert:
+ *
+ * Fails (sub-)test if a condition is not met
+ *
+ * Should be used everywhere where a test checks results.
+ */
+#define igt_assert(expr) \
+ do { if (!(expr)) \
+ __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
+ } while (0)
+#define igt_assert_f(expr, f...) \
+ do { if (!(expr)) \
+ __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
+ } while (0)
+/**
+ * igt_assert_cmptint:
+ *
+ * Like #igt_assert, but displays the values being compared on failure.
+ */
+#define igt_assert_cmpint(n1, cmp, n2) \
+ do { \
+ int __n1 = (n1), __n2 = (n2); \
+ if (__n1 cmp __n2) ; else \
+ __igt_fail_assert(99, __FILE__, __LINE__, __func__, \
+ #n1 " " #cmp " " #n2, \
+ "error: %d %s %d\n", __n1, #cmp, __n2); \
+ } while (0)
+
+/**
+ * igt_require:
+ *
+ * Skip a (sub-)test if a condition is not met
+ *
+ * This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow.
+ */
+#define igt_require(expr) igt_skip_on(!(expr))
+#define igt_skip_on(expr) \
+ do { if ((expr)) \
+ __igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
+ } while (0)
+#define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
+#define igt_skip_on_f(expr, f...) \
+ do { if ((expr)) \
+ __igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
+ } while (0)
+
+/* fork support code */
+bool __igt_fork(void);
+/**
+ * igt_fork:
+ * @child: name of the int variable with the child number
+ * @num_children: number of children to fork
+ *
+ * Fork parallel test threads with fork()
+ *
+ * Joining all test threads should be done with igt_waitchildren to ensure that
+ * the exit codes of all children are properly reflected in the test status.
+ */
+#define igt_fork(child, num_children) \
+ for (int child = 0; child < (num_children); child++) \
+ for (; __igt_fork(); exit(0))
+void igt_waitchildren(void);
+
+struct igt_helper_process {
+ bool running;
+ bool use_SIGKILL;
+ pid_t pid;
+ int id;
+};
+bool __igt_fork_helper(struct igt_helper_process *proc);
+void igt_stop_helper(struct igt_helper_process *proc);
+void igt_wait_helper(struct igt_helper_process *proc);
+#define igt_fork_helper(proc) \
+ for (; __igt_fork_helper(proc); exit(0))
+
+/* exit handler code */
+typedef void (*igt_exit_handler_t)(int sig);
+
+/* reliable atexit helpers, also work when killed by a signal (if possible) */
+void igt_install_exit_handler(igt_exit_handler_t fn);
+void igt_enable_exit_handler(void);
+void igt_disable_exit_handler(void);
+
+/* helpers to automatically reduce test runtime in simulation */
+bool igt_run_in_simulation(void);
+#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
+/**
+ * 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);
+
+/* structured logging */
+enum igt_log_level {
+ IGT_LOG_DEBUG,
+ IGT_LOG_INFO,
+ IGT_LOG_WARN,
+ IGT_LOG_NONE,
+};
+__attribute__((format(printf, 2, 3)))
+void igt_log(enum igt_log_level level, const char *format, ...);
+#define igt_debug(f...) igt_log(IGT_LOG_DEBUG, f)
+#define igt_info(f...) igt_log(IGT_LOG_INFO, f)
+#define igt_warn(f...) igt_log(IGT_LOG_WARN, f)
+extern enum igt_log_level igt_log_level;
+
+#define igt_warn_on(condition) do {\
+ if (condition) \
+ igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+ #condition, __func__, __FILE__, __LINE__); \
+ } while (0)
+#define igt_warn_on_f(condition, f...) do {\
+ if (condition) {\
+ igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+ #condition, __func__, __FILE__, __LINE__); \
+ igt_warn(f); \
+ } \
+ } while (0)
+
+
+#endif /* IGT_CORE_H */