kthread_exit(9) unexpectedness

Julian Elischer julian at elischer.org
Sun Nov 23 22:39:56 PST 2008


Lawrence Stewart wrote:
> John Baldwin wrote:
>> On Thursday 20 November 2008 05:22:03 pm Lawrence Stewart wrote:
>>> John Baldwin wrote:
>>>> On Wednesday 19 November 2008 08:21:44 am Lawrence Stewart wrote:
>>>>> Hi all,
>>>>>
>>>>> I tracked down a deadlock in some of my code today to some weird 
>>>>> behaviour in the kthread(9) KPI. The executive summary is that 
>>>>> kthread_exit() thread termination notification using wakeup() 
>>>>> behaves as expected intuitively in 8.x, but not in 7.x.
>>>> In 5.x/6.x/7.x kthreads are still processes and it has always been a 
>> wakeup on
>>>> the proc pointer.  kthread_create() in 7.x returns a proc pointer, 
>>>> not a thread pointer for example.  In 8.x kthreads are actual 
>>>> threads and 
>>> Yep, but the processes have a *thread in them right? The API naming 
>>> is obviously slightly misleading, but it essentially creates a new 
>>> single threaded process prior to 8.x.
>>
>> Yes, but you have to go explicitly use FIRST_THREAD_IN_PROC().  Most 
>> of the kernel modules I've written that use kthread's in < 8 do this:
>>
>> static struct proc *foo_thread;
>>
>> /* Called for MOD_LOAD. */
>> static void
>> load(...)
>> {
>>
>>     error = kthread_create(..., &foo_thread);
>> }
>>
>> static void
>> unload(...)
>> {
>>
>>     /* set flag */
>>     msleep(foo_thread, ...);
>> }
>>
>> And never actually use the thread at all.  However, if you write the 
>> code for 8.x, now you _do_ get a kthread and sleep on the thread so it 
>> becomes:
>>
>> static struct thread *foo_thread;
>>
>> static void
>> load(...)
>> {
>>
>>     error = kproc_kthread_add(..., proc0, &foo_thread);
>> }
>>
>> static void
>> unload(...)
>> {
>>
>>     /* set flag */
>>     msleep(foo_thread, ...);
>> }
>>
> 
> 
> Sure, but to write the code in this way means you are exercising 
> undocumented knowledge of the KPI. I suspect the average developer 
> completely unfamiliar with the KPI would (and should!) use the man page 
> to learn about the functionality it provides.
> 
> With that basis in mind, it seems unreasonable to expect the developer 
> to come to the conclusion that "...will initiate a call to wakeup(9) on 
> the thread handle." refers to sleeping on the *proc passed in to 
> kthread_create. Perhaps I'm not as switched on as the average developer, 
> but when I read it I certainly did not understand that the KPI created 
> processes and that the man page used the term thread to really mean a 
> single threaded process. I also did no equate "thread handle" with the 
> *proc returned by kthread_create.
> 
> It seems to me that the kthread(9) man page is somewhat unclear with 
> respect to what the KPI actually achieves, making references to thread 
> related activities all over the place when in reality it's manipulating 
> single threaded processes (which for all intensive purposes can be used 
> like threads but are structurally different). I guess this is the cause 
> for the underlying confusion.
> 
> While we're on the topic, I'm also having trouble understanding the 
> reasoning for renaming kthread_create to kthread_add, when in reality 
> 8.x kthread_add is doing a *real* kthread creation and the originally 
> named kthread_create seems to have been a bit of a misnomer (corrected 
> in 8.x by moving the functionality into the kproc_* KPI).

kthread_add was named tha tway to indicate that it is adding a
thread to an existing process in addition to the thread already 
running the code..  I wanted anyone  linking in a binary module
to get a link failure, even if they manageed to sneak past the
other safeguards.

> 
> The changing of the **proc to a **thread argument is enough to ensure 
> code from 7.x won't compile without a tweak on 8.x, so why the rename to 
> add further confusion? With the same line of reasoning, 
> kproc_kthread_add should probably be kproc_kthread_create?

kproc_kthread_add will add a thread to the process if it already
exists, but if it doesn't it will make a new process.

Hey, it's just how I think I guess.

> 
>>>> kthread_add() and kproc_kthread_add() both return thread pointers.  
>>>> Hence 
>> in
>>> Yup.
>>>
>>>> 8.x kthread_exit() is used for exiting kernel threads and wakes up the 
>> thread
>>>> pointer, but in 7.x kthread_exit() is used for exiting kernel processes 
>> and
>>>> wakes up the proc pointer.  I think what is probably needed is to 
>>>> simply 
>>> In the code, yes. Our documented behaviour as far as I can tell is 
>>> different though, unless we equate a "thread handle" to "proc handle" 
>>> prior to 8.x, which I don't think is the case -  they are still 
>>> different.
>>
>> It has always been the case in < 8 that you sleep on the proc handle 
>> (what kthread_create() actually returns in < 8).  And in fact, you 
>> even have to dig around in the proc you get from kthread_create() to 
>> even find the thread pointer as opposed to having the API hand it to you.
>>
>>>> document that arrangement as such.  Note that the sleeping on proc 
>>>> pointer 
>>> I agree that the arrangement needs to be better documented. The 
>>> change in 8.x is subtle enough that reading the kthread man page in 
>>> 7.x and 8.x doesn't immediately make it obvious what's going on.
>>>
>>>> has been the documented way to synchronize with kthread_exit() since 
>>>> 5.0.
>>>>
>>> Could you please point me at this documentation? I've missed it in my 
>>> poking around thus far.
>>
>> It is probably only documented in numerous threads in the mail 
>> archives sadly, but there have been several of them and there have 
>> been several fixes to get this right (the randomdev thread and fdc(4) 
>> thread come to mind).
> 
> If we had no man page, mail archives would be the next best thing. In 
> this instance, we have a misleading man page and I think it would be 
> more beneficial to align the documentation/implementation rather than 
> leaving people confused.
> 
> Apart from the discussion thus far, you haven't actually commented yet 
> on my proposed single line change to kthread_exit() in 7.x to call 
> wakeup on the *thread as well as the *proc. Do you have any specific 
> thoughts on or objection to that idea?

I really haven't got this stuff in my head at the moment so I can't 
comment.

> 
> Cheers,
> Lawrence
> _______________________________________________
> freebsd-arch at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-arch
> To unsubscribe, send any mail to "freebsd-arch-unsubscribe at freebsd.org"



More information about the freebsd-arch mailing list