threads/150889: PTHREAD_MUTEX_INITIALIZER + pthread_mutex_destroy () == EINVAL

Jung-uk Kim jkim at FreeBSD.org
Fri Sep 24 21:11:31 UTC 2010


On Friday 24 September 2010 11:37 am, Jung-uk Kim wrote:
> On Friday 24 September 2010 09:26 am, John Baldwin wrote:
> > On Thursday, September 23, 2010 11:48:40 pm Jung-uk Kim wrote:
> > > On Thursday 23 September 2010 06:44 pm, Daniel Eischen wrote:
> > > > You shouldn't have to call pthread_mutex_init() on a mutex
> > > > initialized with PTHREAD_MUTEX_INITIALIZER.  Our
> > > > implementation should auto initialize the mutex when it is
> > > > first used; if it doesn't, I think that is a bug.
> > >
> > > Ah, I see.  I verified that libthr does it correctly.  However,
> > > that's a hack and it is far from real static allocation
> > > although it should work pretty well in reality, IMHO.  More
> > > over, it will have a side-effect, i.e., any destroyed mutex may
> > > be resurrected if it is used again.  POSIX seems to say it
> > > should return EINVAL when it happens. :-(
> >
> > I think the fix there is that we should put a different value
> > ((void *)1 for example) into "destroyed" mutex objects than 0 so
> > that destroyed mutexes can be differentiated from statically
> > initialized mutexes.  This would also allow us to properly return
> > EBUSY, etc.
>
> It would be nice if we had "uninitialized" as (void *)0 and "static
> initializer" as (void *)1.  IMHO, it looks more natural, i.e.,
> "uninitialized" or "destroyed" one gets zero, and "dynamically
> initialized" or "statically initialized" one gets non-zero.  Can we
> break the ABI for 9, maybe? ;-)

--------------------------------
WARNING!!! WARNING!!! WARNING!!!
--------------------------------
This patch is a proof of concept!
This patch massively breaks pthread ABI!
This patch may crash and burn your system!

I couldn't resist trying. ;-)

Jung-uk Kim
-------------- next part --------------
--- include/pthread.h	2009-03-14 16:10:14.000000000 -0400
+++ include/pthread.h	2010-09-24 16:34:45.000000000 -0400
@@ -97,10 +97,10 @@
 /*
  * Static initialization values. 
  */
-#define PTHREAD_MUTEX_INITIALIZER	NULL
-#define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP	NULL
-#define PTHREAD_COND_INITIALIZER	NULL
-#define PTHREAD_RWLOCK_INITIALIZER	NULL
+#define	PTHREAD_MUTEX_INITIALIZER	((void *)1)
+#define	PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP	((void *)1)
+#define	PTHREAD_COND_INITIALIZER	((void *)1)
+#define	PTHREAD_RWLOCK_INITIALIZER	((void *)1)
 
 /*
  * Default attribute arguments (draft 4, deprecated).
--- lib/libthr/thread/thr_cond.c	2010-09-01 12:13:31.000000000 -0400
+++ lib/libthr/thread/thr_cond.c	2010-09-24 15:36:56.000000000 -0400
@@ -94,7 +94,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_cond_static_lock);
 
-	if (*cond == NULL)
+	if (*cond == STATIC_INITIALIZER)
 		ret = cond_init(cond, NULL);
 	else
 		ret = 0;
@@ -121,6 +121,8 @@ _pthread_cond_destroy(pthread_cond_t *co
 
 	if (*cond == NULL)
 		rval = EINVAL;
+	else if (*cond == STATIC_INITIALIZER)
+		*cond = NULL;
 	else {
 		cv = *cond;
 		THR_UMUTEX_LOCK(curthread, &cv->c_lock);
@@ -184,7 +186,7 @@ cond_wait_common(pthread_cond_t *cond, p
 	 * If the condition variable is statically initialized,
 	 * perform the dynamic initialization:
 	 */
-	if (__predict_false(*cond == NULL &&
+	if (__predict_false(*cond == STATIC_INITIALIZER &&
 	    (ret = init_static(curthread, cond)) != 0))
 		return (ret);
 
@@ -273,7 +275,7 @@ cond_signal_common(pthread_cond_t *cond,
 	 * If the condition variable is statically initialized, perform dynamic
 	 * initialization.
 	 */
-	if (__predict_false(*cond == NULL &&
+	if (__predict_false(*cond == STATIC_INITIALIZER &&
 	    (ret = init_static(curthread, cond)) != 0))
 		return (ret);
 
--- lib/libthr/thread/thr_mutex.c	2010-09-01 12:13:32.000000000 -0400
+++ lib/libthr/thread/thr_mutex.c	2010-09-24 16:32:07.000000000 -0400
@@ -184,7 +184,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
 
-	if (*mutex == NULL)
+	if (*mutex == STATIC_INITIALIZER)
 		ret = mutex_init(mutex, NULL, calloc);
 	else
 		ret = 0;
@@ -263,6 +263,8 @@ _pthread_mutex_destroy(pthread_mutex_t *
 
 	if (__predict_false(*mutex == NULL))
 		ret = EINVAL;
+	else if (*mutex == STATIC_INITIALIZER)
+		*mutex = NULL;
 	else {
 		id = TID(curthread);
 
@@ -346,7 +348,7 @@ __pthread_mutex_trylock(pthread_mutex_t 
 	 * If the mutex is statically initialized, perform the dynamic
 	 * initialization:
 	 */
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -454,7 +456,7 @@ __pthread_mutex_lock(pthread_mutex_t *mu
 	 * If the mutex is statically initialized, perform the dynamic
 	 * initialization:
 	 */
-	if (__predict_false((m = *mutex) == NULL)) {
+	if (__predict_false((m = *mutex) == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -479,7 +481,7 @@ __pthread_mutex_timedlock(pthread_mutex_
 	 * If the mutex is statically initialized, perform the dynamic
 	 * initialization:
 	 */
-	if (__predict_false((m = *mutex) == NULL)) {
+	if (__predict_false((m = *mutex) == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -614,6 +616,9 @@ mutex_unlock_common(pthread_mutex_t *mut
 	if (__predict_false((m = *mutex) == NULL))
 		return (EINVAL);
 
+	if (*mutex == STATIC_INITIALIZER)
+		return (EPERM);
+
 	/*
 	 * Check if the running thread is not the owner of the mutex.
 	 */
@@ -749,7 +754,7 @@ __pthread_mutex_setspinloops_np(pthread_
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -773,7 +778,7 @@ __pthread_mutex_setyieldloops_np(pthread
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -788,7 +793,7 @@ _pthread_mutex_isowned_np(pthread_mutex_
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
--- lib/libthr/thread/thr_private.h	2010-09-24 12:01:02.000000000 -0400
+++ lib/libthr/thread/thr_private.h	2010-09-24 14:43:35.000000000 -0400
@@ -125,6 +125,8 @@ TAILQ_HEAD(mutex_queue, pthread_mutex);
 		}						\
 	} while (0)
 
+#define	STATIC_INITIALIZER	((void *)1)
+
 struct pthread_mutex {
 	/*
 	 * Lock for accesses to this structure.
--- lib/libthr/thread/thr_rwlock.c	2009-07-06 05:31:04.000000000 -0400
+++ lib/libthr/thread/thr_rwlock.c	2010-09-24 16:45:37.000000000 -0400
@@ -64,10 +64,12 @@ rwlock_init(pthread_rwlock_t *rwlock, co
 int
 _pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
 {
-	int ret;
+	int ret = 0;
 
 	if (rwlock == NULL)
 		ret = EINVAL;
+	else if (*rwlock == STATIC_INITIALIZER)
+		*rwlock = NULL;
 	else {
 		pthread_rwlock_t prwlock;
 
@@ -75,7 +77,6 @@ _pthread_rwlock_destroy (pthread_rwlock_
 		*rwlock = NULL;
 
 		free(prwlock);
-		ret = 0;
 	}
 	return (ret);
 }
@@ -87,7 +88,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
 
-	if (*rwlock == NULL)
+	if (*rwlock == STATIC_INITIALIZER)
 		ret = rwlock_init(rwlock, NULL);
 	else
 		ret = 0;
@@ -119,7 +120,7 @@ rwlock_rdlock_common(pthread_rwlock_t *r
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -212,7 +213,7 @@ _pthread_rwlock_tryrdlock (pthread_rwloc
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -256,7 +257,7 @@ _pthread_rwlock_trywrlock (pthread_rwloc
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -283,7 +284,7 @@ rwlock_wrlock_common (pthread_rwlock_t *
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -364,6 +365,9 @@ _pthread_rwlock_unlock (pthread_rwlock_t
 	if (__predict_false(prwlock == NULL))
 		return (EINVAL);
 
+	if (prwlock == STATIC_INITIALIZER)
+		return (EPERM);
+
 	state = prwlock->lock.rw_state;
 	if (state & URWLOCK_WRITE_OWNER) {
 		if (__predict_false(prwlock->owner != curthread))


More information about the freebsd-threads mailing list