From: Paulo Zanoni <[email protected]>

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 <[email protected]>
---
 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
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to