[igt-dev] [PATCH i-g-t] igt/drm_read: Exercise waking up the next waiter
Chris Wilson
chris at chris-wilson.co.uk
Wed Feb 27 10:20:19 UTC 2019
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 <chris at chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
---
tests/drm_read.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/tests/drm_read.c b/tests/drm_read.c
index 309f389f6..923a9f750 100644
--- a/tests/drm_read.c
+++ b/tests/drm_read.c
@@ -43,6 +43,7 @@
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/poll.h>
+#include <pthread.h>
#include "drm.h"
IGT_TEST_DESCRIPTION("Call read(drm) and see if it behaves.");
@@ -166,6 +167,90 @@ 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[1024]; /* events are typically 32 bytes */
+
+ while (!w->done) {
+ /* Short read, does not consume the event. */
+ igt_assert_eq(read(w->fd, buffer, 4), 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, 40) > 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 +303,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);
}
--
2.20.1
More information about the igt-dev
mailing list