Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Oct 2004 09:47:52 -0400 (EDT)
From:      Daniel Eischen <deischen@freebsd.org>
To:        damien.bergamini@free.fr
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: msleep(9) and recursed mutex
Message-ID:  <Pine.GSO.4.43.0410110932350.21570-100000@sea.ntplx.net>
In-Reply-To: <1097500245.416a86556c692@imp1-q.free.fr>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 11 Oct 2004 damien.bergamini@free.fr wrote:

> msleep(9) behaves strangely with recursed mutexes.
> In the attached code, calling foo_f() will make the kernel hang for
> two seconds.
> It seems like msleep does not release the mtx mutex completely but
> simply decrement its reference count by one. When calling msleep, the
> mtx mutex is still held which prevent the interrupt from happening.
> msleep will then return error code EWOULDBLOCK after two seconds.
> If I remove calls to mtx_lock/unlock from function foo_g(), it works
> without problem but this is not a solution since foo_g() can be
> called outside of function foo_f().
> Of course, the mtx mutex was created with the MTX_RECURSE flag set.

First, don't use recursive mutexes -- they are (for now) a necessary
evil.

> Is it an expected behaviour? In msleep(9) it is said:
> "The msleep() function is a variation on tsleep.  The parameter mtx
> is a mutex which will be released before sleeping and reacquired
> before msleep() returns."
>
> Seems like the mutex is not *really* released if it recurses.

Only one thread can take and own a recursive mutex, not multiple
threads.  An interrupt occurs in a different thread, so it cannot
lock a mutex that it doesn't own.  As you suggest, the only way
this could work is if msleep() set the recurse count to zero and
restored it back to its original value once it was awoken.

I think it's great (a feature) that the use of recursive mutexes
breaks when used with interrupts!

Really, you want to be using condition variables.  Use a mutex
to protect your data and use cv_{timed}wait{_sig}() to sleep.
When the interrupt occurs, you use cv_signal() or cv_broadcast()
to wake up any waiters.

-- 
DE



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.GSO.4.43.0410110932350.21570-100000>