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>