Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Oct 2004 17:30:43 +0200
From:      Hans Petter Selasky <hselasky@c2i.net>
To:        damien.bergamini@free.fr
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: msleep(9) and recursed mutex
Message-ID:  <20041011173042.B744@curly.tele2.no>
In-Reply-To: <1097500245.416a86556c692@imp1-q.free.fr>; from damien.bergamini@free.fr on Mon, Oct 11, 2004 at 03:10:45PM %2B0200
References:  <1097500245.416a86556c692@imp1-q.free.fr>

next in thread | previous in thread | raw e-mail | index | archive | help

--gBBFr7Ir9EOA20Yy
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Oct 11, 2004 at 03:10:45PM +0200, 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.
> 
> 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 the "Giant" mutex is released if it recurses. By the way there is
a bug in msleep:

mtx_lock(&Giant);
msleep(xxx, &Giant, 0, "foo", 0);
mtx_unlock(&Giant);

doesn't work. See attached patch.

> 
> Thanks,
> Damien Bergamini
> 
> ----
> 
> void foo_intr(void *arg)
> {
>     struct foo_softc *sc = arg;
> 
>     mtx_lock(&sc->mtx);
>     ...
>     wakeup(sc);
>     ...
>     mtx_unlock(&sc->mtx);
> }
> 
> void foo_f(struct foo_softc *sc)
> {
>     mtx_lock(&sc->mtx);
>     ...
>     foo_g(sc);
>     ...
>     mtx_unlock(&sc->mtx);
> }
> 
> void foo_g(struct foo_softc *sc)
> {
>     /* mtx will recurse if called from foo_f() */
>     mtx_lock(&sc->mtx);
>     ...
>     /* do something that will make hardware raise an interrupt */
>     ...
>     /* wait at most 2 second for the interrupt */
>     msleep(sc, &sc->mtx, 0, "foo", 2 * hz);
>     ...
>     mtx_unlock(&sc->mtx);
> }

-HPS

--gBBFr7Ir9EOA20Yy
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="kern_synch.c.diff"

*** src/sys/kern/kern_synch.c.ref	Wed Sep 29 14:21:09 2004
--- src/sys/kern/kern_synch.c	Wed Sep 29 14:22:25 2004
***************
*** 182,193 ****
  	CTR5(KTR_PROC, "msleep: thread %p (pid %ld, %s) on %s (%p)",
  	    (void *)td, (long)p->p_pid, p->p_comm, wmesg, ident);
  
- 	DROP_GIANT();
  	if (mtx != NULL) {
  		mtx_assert(mtx, MA_OWNED | MA_NOTRECURSED);
  		WITNESS_SAVE(&mtx->mtx_object, mtx);
  		mtx_unlock(mtx);
  	}
  
  	/*
  	 * We put ourselves on the sleep queue and start our timeout
--- 182,194 ----
  	CTR5(KTR_PROC, "msleep: thread %p (pid %ld, %s) on %s (%p)",
  	    (void *)td, (long)p->p_pid, p->p_comm, wmesg, ident);
  
  	if (mtx != NULL) {
  		mtx_assert(mtx, MA_OWNED | MA_NOTRECURSED);
  		WITNESS_SAVE(&mtx->mtx_object, mtx);
  		mtx_unlock(mtx);
  	}
+ 	/* drop Giant after mtx in case mtx == &Giant */
+ 	DROP_GIANT();
  
  	/*
  	 * We put ourselves on the sleep queue and start our timeout

--gBBFr7Ir9EOA20Yy--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20041011173042.B744>