From: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> These functions should help you checking for new Kernel error messages. One of the problems I had while writing the runtime PM test suite is that when you read the sysfs and debugfs files, the only way to detect errors is by checking dmesg, so I was always getting SUCCESS even if the test caught a bug. Also, we have so many debugfs/sysfs files that it was not easy to discover which file caused the error messages I was seeing. So this commit adds some infrastructure to allow us to automatically check for new errors on dmesg. Use it like this: int main(int argc, char *argv[]) { int fd, i; igt_fixture fd = kmsg_error_setup(); igt_subtest("t1") { kmsg_error_reset(fd); do_something(); kmsg_error_detect(""); } igt_subtest("t2") { for (i = 0; i < 10; i++) { char *file_name = get_file(i); kmsg_error_reset(fd); process_file(file_name); kmsg_error_detect(file_name): } } igt_fixture kmsg_error_teardown(fd); } Signed-off-by: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> --- lib/drmtest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/drmtest.h | 13 ++++++++++ 2 files changed, 92 insertions(+) diff --git a/lib/drmtest.c b/lib/drmtest.c index d8fc60f..ebabfd8 100644 --- a/lib/drmtest.c +++ b/lib/drmtest.c @@ -41,6 +41,7 @@ #include <linux/kd.h> #include <unistd.h> #include <sys/wait.h> +#include <poll.h> #include "drm_fourcc.h" #include "drmtest.h" @@ -2307,3 +2308,81 @@ void igt_system_suspend_autoresume(void) ret = system("rtcwake -s 30 -m mem"); igt_assert(ret == 0); } + +/* The kmsg error detecting functions allow you to catch new error messages from + * the Kernel. The idea is that you have to call kmsg_error_setup() only once at + * the beginning, and kmsg_error_teardown() at the end. And for every subtest, + * you run kmsg_error_reset() at the begin and kmsg_error_detect() at the end: + * this should make sure that kmsg_error_detect() will only catch the error + * messages that were introduced after the subtest started. */ +int kmsg_error_setup(void) +{ + int fd = open("/dev/kmsg", O_RDONLY); + + igt_assert_f(fd >= 0, "Can't open /dev/kmsg\n"); + return fd; +} + +void kmsg_error_teardown(int fd) +{ + close(fd); +} + +/* You have to call this before running your subtest, so that the next time you + * call kmsg_error_detect you'll only look at the new kmsg lines. */ +void kmsg_error_reset(int fd) +{ + lseek(fd, 0, SEEK_END); +} + +static void kmsg_error_line_parse(const char *line, const char *error_msg) +{ + igt_assert_f(strstr(line, "------------[ cut here ]------------") == 0, + "%s\n", error_msg); + igt_assert_f(strstr(line, "*ERROR*") == 0, "%s\n", error_msg); + igt_assert_f(strstr(line, "BUG: sleeping function called from invalid context at") == 0, + "%s\n", error_msg); +} + +/* Keep reading the Kernel ring buffer and checking for errors. Stop reading if + * there's nothing new on the buffer after the timeout. Notice that every time + * you call this function, the time it will take to return will always be >= the + * timeout. */ +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg) +{ + int i, rc; + int line_size = 128, line_used = 0, buf_size = 128; + char buf[buf_size]; + char *line; + struct pollfd pfd; + ssize_t readed; + + line = malloc(sizeof(char) * line_size); + igt_assert(line); + + pfd.fd = fd; + pfd.events = POLLIN | POLLPRI; + + while (1) { + pfd.revents = 0; + rc = poll(&pfd, 1, timeout_ms); + if (!rc) + break; + + readed = read(fd, &buf, buf_size - 1); + for (i = 0; i < readed; i++) { + if (line_used + 1 >= line_size) { + line = realloc(line, line_size * 2); + line_size *= 2; + igt_assert(line); + } + line[line_used++] = buf[i]; + if (buf[i] == '\n') { + line[line_used] = '\0'; + kmsg_error_line_parse(line, error_msg); + line_used = 0; + } + } + } + free(line); +} diff --git a/lib/drmtest.h b/lib/drmtest.h index a9fd0bc..05e3629 100644 --- a/lib/drmtest.h +++ b/lib/drmtest.h @@ -413,4 +413,17 @@ void igt_enable_prefault(void); /* suspend and auto-resume system */ void igt_system_suspend_autoresume(void); +/* Returns the fd for the other functions. */ +int kmsg_error_setup(void); +/* Closes the fd */ +void kmsg_error_teardown(int fd); +/* Skip to the end of the kmsg fd, so that the next time you call + * kmsg_error_detect() you will only parse the new messages. */ +void kmsg_error_reset(int fd); +/* Reads all the new Kernel messages since the last time you called + * kmsg_error_teardown, and also waits for new messages for timeout_ms. In case + * we find any error we'll also print error_msg. Uses igt_assert, so no need to + * check for return values. */ +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg); + #endif /* DRMTEST_H */ -- 1.8.3.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx