kthreads and sched_relinquish

Andrew Brampton brampton+freebsd-hackers at gmail.com
Fri May 8 17:24:04 UTC 2009


Hi,
I'm writing a FreeBSD kernel module and I think I really misunderstand
something. My module spawns a thread, which should be running while
the module is loaded. The thread does some work and then should yield
for other threads. However, if there are no other threads waiting,
then I would like to continue to do more work. The problem is that I
am getting weird deadlocks so I wrote a simple test app to ask why
this doesn't work:

------------------------
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/cdefs.h>
#include <sys/proc.h>
#include <sys/pcpu.h>
#include <sys/kthread.h>
#include <sys/sched.h>
#include <sys/systm.h>

static void test_thread(void *blah) {
        unsigned int i = 100000000; /* Limit the number of iterations */

        printf("Test Thread Started\n");

        while (i > 0) {
                sched_relinquish(curthread);
                i--;
        }

        printf("Test Thread Exited\n");
        kthread_exit(0);
}

/* The function called at load/unload. */
static int event_handler(struct module *module, int event, void *arg) {
        int e = 0; /* Error, 0 for normal return status */
        switch (event) {
                case MOD_LOAD:
                        printf("Test Module Loaded\n");
                        kthread_create(test_thread, NULL, NULL, 0, 0, "test");
                        break;
                case MOD_UNLOAD:
                        printf("Test Module Unloaded\n");
                        break;
                default:
                        e = EOPNOTSUPP; /* Error, Operation Not Supported */
        }

        return e;
}

/* The second argument of DECLARE_MODULE. */
static moduledata_t test_conf = {
        "test_mod",     /* module name */
        event_handler,  /* event handler */
        NULL            /* extra data */
};

DECLARE_MODULE(test_mod, test_conf, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
----------------------------


While my thread is running the rest of the system is unresponsive. The
thread should sched_relinquish() every time round the loop, and from
my understanding that should yield to allow other threads to run, for
example the thread which executes my shell (bash). I suspect my thread
is yielding and getting instantly rescheduled.  I noticed that
poll_idle() in sys/kern_poll.c does something similar to me, but they
first lower their priority. This however has not worked for me, since
my more complex module interacts with higher priority threads and ends
up deadlocking.

So I just want to ask, Why does this example code lock the system? Am
I using sched_relinquish correctly? Or should I be doing something
else? I did try using tsleep(...,1), but I don't want my thread
sleeping if there are no other threads waiting.

I would also be grateful if people could point me at other examples in
the kernel where something like this is done. I have looked in quite a
few places, but I can't see why my simple app is wrong.

thanks
Andrew


More information about the freebsd-hackers mailing list