Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Sep 2010 14:14:50 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-threads@freebsd.org
Cc:        freebsd-gnats-submit@freebsd.org, Christopher Faylor <cgf@netapp.com>
Subject:   Re: threads/150889: PTHREAD_MUTEX_INITIALIZER + pthread_mutex_destroy() == EINVAL
Message-ID:  <201009231414.50271.jhb@freebsd.org>
In-Reply-To: <201009231733.o8NHXuao082524@www.freebsd.org>
References:  <201009231733.o8NHXuao082524@www.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thursday, September 23, 2010 1:33:56 pm Christopher Faylor wrote:
> 
> >Number:         150889
> >Category:       threads
> >Synopsis:       PTHREAD_MUTEX_INITIALIZER + pthread_mutex_destroy() == EINVAL
> >Confidential:   no
> >Severity:       non-critical
> >Priority:       low
> >Responsible:    freebsd-threads
> >State:          open
> >Quarter:        
> >Keywords:       
> >Date-Required:
> >Class:          sw-bug
> >Submitter-Id:   current-users
> >Arrival-Date:   Thu Sep 23 17:40:01 UTC 2010
> >Closed-Date:
> >Last-Modified:
> >Originator:     Christopher Faylor
> >Release:        6.x - head
> >Organization:
> NetApp
> >Environment:
> FreeBSD osg-cycf64a.nane.netapp.com 7.2-RELEASE FreeBSD 7.2-RELEASE #0: Fri May  1 07:18:07 UTC 2009     
root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
> >Description:
> Consider the following code snippet:
> 
>  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>  int ret = pthread_mutex_destroy(&mutex);
>  assert(ret == 0);
> 
> This code snippet will currently always hit the assertion.
> 
> This appears to be in contradiction to 
> 
> http://www.opengroup.org/onlinepubs/9699919799/toc.htm
> 
> which states:
> 
>   In cases where default mutex attributes are appropriate, the macro
>   PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes that are statically 
>   allocated. The effect shall be equivalent to dynamic initialization by a call to
>   pthread_mutex_init() with parameter attr specified as NULL, except that no error
>   checks are performed.

I suppose that is true, but I think this is also probably buggy code if you
are doing this.  The use case for PTHREAD_MUTEX_INITALIZER is static
initialization of static objects to ease adding locking to C libraries where
constructors are not easy.  Specifically, to avoid prefixing every
pthread_mutex_lock() with a pthread_once() call to initialize the mutex.
(See the example given in the RATIONALE section in the pthread_mutex_init()
page at the link above where it talks about static initialization.)  Such
mutexes are generally never destroyed (their lifetime is the same as the
containing executable or shared library (since presumably they could vanish
as part of a dlclose())).  I think it is not provided so that you can
initialize dynamically allocated mutexes at runtime via:

	struct foo {
		...
		pthread_mutex_t m;
	}

	f = malloc(sizeof(foo);
	f->m = PTHREAD_MUTEX_INITIALIZER;

Those sorts of locks should be initialized via pthread_mutex_init() instead.

All that said, we do use a rather gross hack that is similar in stdio.  We
create a template FILE object like this:

	static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };

and use structure assignment to initialize new FILE objects that are
allocated dynamically:

	g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE));
	p = (FILE *)ALIGN(g + 1);
	while (--n >= 0)
		*p++ = empty;

Of course, this is internal to the implementation of stdio and isn't
necessarily portable.  In this case stdio is probably doing it this way to
avoid the dance of invoking pthread_mutex_init() in the non-threaded case to
avoid "poisoning" the pthread_mutex_init() weak symbol.  That problem is
unique to libc's implementation, however.  I would not do this in portable
code. :)

The one possibly valid reason I can see for pthread_mutex_destroy() to
operate on a statically initialized mutex is to let a library destroy a
mutex due to dlclose() unloading the library.  However, to pull that off the
library would need to install an atexit() hook or similar to actually invoke
pthread_mutex_destroy().  That requires some sort of initialization code to
invoke atexit() at which point you might as well call pthread_mutex_init()
to initialize the mutex at the same time as calling atexit().

-- 
John Baldwin



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