From 21e45c99dc2e0439bb48703a559814de002f4ff2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Feb 2019 09:10:14 +0000 Subject: igt/drm_read: Exercise waking up the next waiter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to hit a bug in the kernel whereby a short reader does not wakeup the next waiter (on the same fd) leading to forever blocking. Signed-off-by: Chris Wilson Cc: Daniel Vetter Reviewed-by: Ville Syrjälä --- tests/drm_read.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'tests/drm_read.c') diff --git a/tests/drm_read.c b/tests/drm_read.c index 309f389f..cfb1c04d 100644 --- a/tests/drm_read.c +++ b/tests/drm_read.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "drm.h" IGT_TEST_DESCRIPTION("Call read(drm) and see if it behaves."); @@ -166,6 +167,89 @@ static void test_short_buffer(int in, int nonblock, enum pipe pipe) teardown(fd); } +struct short_buffer_wakeup { + pthread_mutex_t mutex; + pthread_cond_t send, recv; + int counter; + int done; + int fd; +}; + +static void *thread_short_buffer_wakeup(void *arg) +{ + struct short_buffer_wakeup *w = arg; + char buffer; /* events are typically 32 bytes */ + + while (!w->done) { + /* Short read, does not consume the event. */ + igt_assert_eq(read(w->fd, &buffer, sizeof(buffer)), 0); + + pthread_mutex_lock(&w->mutex); + if (!--w->counter) + pthread_cond_signal(&w->send); + pthread_cond_wait(&w->recv, &w->mutex); + pthread_mutex_unlock(&w->mutex); + } + + return NULL; +} + +static void test_short_buffer_wakeup(int in, enum pipe pipe) +{ + const int nt = sysconf(_SC_NPROCESSORS_ONLN) + 1; + struct short_buffer_wakeup w = { + .fd = setup(in, 0), + }; + pthread_t t[nt]; + char buffer[1024]; /* events are typically 32 bytes */ + + pthread_mutex_init(&w.mutex, NULL); + pthread_cond_init(&w.send, NULL); + pthread_cond_init(&w.recv, NULL); + + for (int n = 0; n < nt; n++) + pthread_create(&t[n], NULL, thread_short_buffer_wakeup, &w); + + igt_until_timeout(30) { + struct timespec tv; + int err = 0; + + pthread_mutex_lock(&w.mutex); + w.counter = nt; + pthread_cond_broadcast(&w.recv); + pthread_mutex_unlock(&w.mutex); + + /* Give each thread a chance to sleep in drm_read() */ + pthread_yield(); + + /* One event should wake all threads as none consume */ + generate_event(w.fd, pipe); + + clock_gettime(CLOCK_REALTIME, &tv); + tv.tv_sec += 5; /* Let's be very generous to the scheduler */ + + pthread_mutex_lock(&w.mutex); + while (w.counter && !err) + err = pthread_cond_timedwait(&w.send, &w.mutex, &tv); + pthread_mutex_unlock(&w.mutex); + + igt_assert_f(err == 0, + "Timed out waiting for drm_read() to wakeup on an event\n"); + + /* No thread should consume the event */ + igt_assert(read(w.fd, buffer, sizeof(buffer)) > 0); + } + pthread_mutex_lock(&w.mutex); + w.done = true; + pthread_cond_broadcast(&w.recv); + pthread_mutex_unlock(&w.mutex); + + for (int n = 0; n < nt; n++) + pthread_join(t[n], NULL); + + close(w.fd); +} + igt_main { int fd; @@ -218,4 +302,7 @@ igt_main igt_subtest("short-buffer-nonblock") test_short_buffer(fd, 1, pipe); + + igt_subtest("short-buffer-wakeup") + test_short_buffer_wakeup(fd, pipe); } -- cgit v1.2.3