Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Sep 2010 18:20:03 GMT
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-threads@FreeBSD.org
Subject:   Re: threads/150889: PTHREAD_MUTEX_INITIALIZER + pthread_mutex_destroy() == EINVAL
Message-ID:  <201009231820.o8NIK3fA063459@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR threads/150889; it has been noted by GNATS.

From: John Baldwin <jhb@freebsd.org>
To: freebsd-threads@freebsd.org
Cc: Christopher Faylor <cgf@netapp.com>,
 freebsd-gnats-submit@freebsd.org
Subject: Re: threads/150889: PTHREAD_MUTEX_INITIALIZER + pthread_mutex_destroy() == EINVAL
Date: Thu, 23 Sep 2010 14:14:50 -0400

 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?201009231820.o8NIK3fA063459>