diff --git a/tests/linux_kernel/helpers/test_wait.py b/tests/linux_kernel/helpers/test_wait.py new file mode 100644 index 000000000..191d1f073 --- /dev/null +++ b/tests/linux_kernel/helpers/test_wait.py @@ -0,0 +1,30 @@ +# Copyright (c) 2023, Oracle and/or its affiliates. +# SPDX-License-Identifier: LGPL-2.1-or-later + +from drgn.helpers.linux.wait import waitqueue_active, waitqueue_for_each_task +from tests.linux_kernel import LinuxKernelTestCase, skip_unless_have_test_kmod + + +def waiter_tasks(prog): + return [ + prog["drgn_test_waitq_kthread"], + ] + + +@skip_unless_have_test_kmod +class TestWaitqueue(LinuxKernelTestCase): + @classmethod + def setUpClass(cls): + cls.waitq = cls.prog["drgn_test_waitq"].address_of_() + cls.empty_waitq = cls.prog["drgn_test_empty_waitq"].address_of_() + + def test_waitqueue_active(self): + self.assertTrue(waitqueue_active(self.waitq)) + self.assertFalse(waitqueue_active(self.empty_waitq)) + + def test_waitqueue_for_each_task(self): + self.assertEqual(list(waitqueue_for_each_task(self.empty_waitq)), []) + self.assertEqual( + [task for task in waitqueue_for_each_task(self.waitq)], + waiter_tasks(self.prog), + ) diff --git a/tests/linux_kernel/kmod/drgn_test.c b/tests/linux_kernel/kmod/drgn_test.c index 81d9567b3..74c1bbd40 100644 --- a/tests/linux_kernel/kmod/drgn_test.c +++ b/tests/linux_kernel/kmod/drgn_test.c @@ -25,6 +25,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) #define HAVE_XARRAY 1 #include @@ -847,6 +848,41 @@ static void drgn_test_idr_exit(void) idr_destroy(&drgn_test_idr_sparse); } +// wait-queue +static struct task_struct *drgn_test_waitq_kthread; +static wait_queue_head_t drgn_test_waitq; +static wait_queue_head_t drgn_test_empty_waitq; +static bool exit_waitq_test; + +static int drgn_test_waitq_kthread_fn(void *arg) +{ + wait_event_interruptible(drgn_test_waitq, exit_waitq_test); + return 0; +} + +static int drgn_test_waitq_init(void) +{ + init_waitqueue_head(&drgn_test_waitq); + init_waitqueue_head(&drgn_test_empty_waitq); + + drgn_test_waitq_kthread = kthread_create(drgn_test_waitq_kthread_fn, NULL, + "drgn_test_waitq_kthread"); + if (!drgn_test_waitq_kthread) + return -1; + + wake_up_process(drgn_test_waitq_kthread); + return 0; +} + +static void drgn_test_waitq_exit(void) +{ + if (drgn_test_waitq_kthread) { + exit_waitq_test = true; + kthread_stop(drgn_test_waitq_kthread); + drgn_test_waitq_kthread = NULL; + } +} + // Dummy function symbol. int drgn_test_function(int x) { @@ -862,6 +898,7 @@ static void drgn_test_exit(void) drgn_test_stack_trace_exit(); drgn_test_radix_tree_exit(); drgn_test_xarray_exit(); + drgn_test_waitq_exit(); drgn_test_idr_exit(); } @@ -891,6 +928,10 @@ static int __init drgn_test_init(void) if (ret) goto out; ret = drgn_test_xarray_init(); + if (ret) + goto out; + + ret = drgn_test_waitq_init(); if (ret) goto out; ret = drgn_test_idr_init();