Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Sep 2010 19:43:09 -0400
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        John Baldwin <jhb@freebsd.org>
Cc:        Daniel Eischen <deischen@freebsd.org>, freebsd-threads@freebsd.org
Subject:   Re: threads/150889: PTHREAD_MUTEX_INITIALIZER +	pthread_mutex_destroy () == EINVAL
Message-ID:  <201009241943.10401.jkim@FreeBSD.org>
In-Reply-To: <201009241724.10223.jhb@freebsd.org>
References:  <201009232220.o8NMK3fX011639@freefall.freebsd.org> <201009241137.56764.jkim@FreeBSD.org> <201009241724.10223.jhb@freebsd.org>

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

--Boundary-00=_OeTnMm3Rs0n8fas
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Friday 24 September 2010 05:24 pm, John Baldwin wrote:
> On Friday, September 24, 2010 11:37:53 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? ;-)
>
> I actually find the (void *)1 more natural for a destroyed state
> FWIW. One thing I would advocate is that regardless of the values
> chosen, use constants for both the INITIALIZER and DESTROYED
> values.  That would make the code more obvious.  In general I think
> your patch in your followup is correct, but having explicitly
> DESTROYED constants that you check against instead of NULL would
> improve the code.

Here goes more complicated patch.  Not really tested, though.

Jung-uk Kim

--Boundary-00=_OeTnMm3Rs0n8fas
Content-Type: text/plain;
  charset="iso-8859-1";
  name="pthread2.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="pthread2.diff"

--- include/pthread.h	2010-09-24 16:49:50.000000000 -0400
+++ include/pthread.h	2010-09-24 17:42:00.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-24 16:49:50.000000000 -0400
+++ lib/libthr/thread/thr_cond.c	2010-09-24 19:32:34.000000000 -0400
@@ -64,27 +64,28 @@ static int
 cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
 {
 	pthread_cond_t	pcond;
-	int             rval = 0;
 
-	if ((pcond = (pthread_cond_t)
-	    calloc(1, sizeof(struct pthread_cond))) == NULL) {
-		rval = ENOMEM;
+	if (__predict_false(cond == NULL))
+		return (EINVAL);
+
+	pcond = (pthread_cond_t)calloc(1, sizeof(struct pthread_cond));
+	if (pcond == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Initialise the condition variable structure:
+	 */
+	if (cond_attr == NULL || *cond_attr == NULL) {
+		pcond->c_pshared = 0;
+		pcond->c_clockid = CLOCK_REALTIME;
 	} else {
-		/*
-		 * Initialise the condition variable structure:
-		 */
-		if (cond_attr == NULL || *cond_attr == NULL) {
-			pcond->c_pshared = 0;
-			pcond->c_clockid = CLOCK_REALTIME;
-		} else {
-			pcond->c_pshared = (*cond_attr)->c_pshared;
-			pcond->c_clockid = (*cond_attr)->c_clockid;
-		}
-		_thr_umutex_init(&pcond->c_lock);
-		*cond = pcond;
+		pcond->c_pshared = (*cond_attr)->c_pshared;
+		pcond->c_clockid = (*cond_attr)->c_clockid;
 	}
-	/* Return the completion status: */
-	return (rval);
+	_thr_umutex_init(&pcond->c_lock);
+	*cond = pcond;
+
+	return (0);
 }
 
 static int
@@ -94,7 +95,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_cond_static_lock);
 
-	if (*cond == NULL)
+	if (*cond == THR_STATIC_INITIALIZER)
 		ret = cond_init(cond, NULL);
 	else
 		ret = 0;
@@ -108,7 +109,6 @@ int
 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
 {
 
-	*cond = NULL;
 	return (cond_init(cond, cond_attr));
 }
 
@@ -117,10 +117,12 @@ _pthread_cond_destroy(pthread_cond_t *co
 {
 	struct pthread		*curthread = _get_curthread();
 	struct pthread_cond	*cv;
-	int			rval = 0;
 
-	if (*cond == NULL)
-		rval = EINVAL;
+	if (__predict_false(cond == NULL || *cond == THR_UNINITIALIZED))
+		return (EINVAL);
+
+	if (*cond == THR_STATIC_INITIALIZER)
+		*cond = THR_UNINITIALIZED;
 	else {
 		cv = *cond;
 		THR_UMUTEX_LOCK(curthread, &cv->c_lock);
@@ -128,7 +130,7 @@ _pthread_cond_destroy(pthread_cond_t *co
 		 * NULL the caller's pointer now that the condition
 		 * variable has been destroyed:
 		 */
-		*cond = NULL;
+		*cond = THR_UNINITIALIZED;
 		THR_UMUTEX_UNLOCK(curthread, &cv->c_lock);
 
 		/*
@@ -137,8 +139,8 @@ _pthread_cond_destroy(pthread_cond_t *co
 		 */
 		free(cv);
 	}
-	/* Return the completion status: */
-	return (rval);
+
+	return (0);
 }
 
 struct cond_cancel_info
@@ -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 == THR_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 == THR_STATIC_INITIALIZER &&
 	    (ret = init_static(curthread, cond)) != 0))
 		return (ret);
 
--- /usr/src/lib/libthr/thread/thr_mutex.c	2010-09-24 16:49:50.000000000 -0400
+++ lib/libthr/thread/thr_mutex.c	2010-09-24 19:25:30.000000000 -0400
@@ -130,9 +130,12 @@ mutex_init(pthread_mutex_t *mutex,
 	const struct pthread_mutex_attr *attr;
 	struct pthread_mutex *pmutex;
 
-	if (mutex_attr == NULL) {
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+
+	if (mutex_attr == NULL)
 		attr = &_pthread_mutexattr_default;
-	} else {
+	else {
 		attr = *mutex_attr;
 		if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
 		    attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
@@ -141,8 +144,8 @@ mutex_init(pthread_mutex_t *mutex,
 		    attr->m_protocol > PTHREAD_PRIO_PROTECT)
 			return (EINVAL);
 	}
-	if ((pmutex = (pthread_mutex_t)
-		calloc_cb(1, sizeof(struct pthread_mutex))) == NULL)
+	pmutex = (pthread_mutex_t)calloc_cb(1, sizeof(struct pthread_mutex));
+	if (pmutex == NULL)
 		return (ENOMEM);
 
 	pmutex->m_type = attr->m_type;
@@ -184,7 +187,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
 
-	if (*mutex == NULL)
+	if (*mutex == THR_STATIC_INITIALIZER)
 		ret = mutex_init(mutex, NULL, calloc);
 	else
 		ret = 0;
@@ -259,48 +262,53 @@ _pthread_mutex_destroy(pthread_mutex_t *
 	struct pthread *curthread = _get_curthread();
 	pthread_mutex_t m;
 	uint32_t id;
-	int ret = 0;
+	int ret;
 
-	if (__predict_false(*mutex == NULL))
-		ret = EINVAL;
-	else {
-		id = TID(curthread);
+	if (__predict_false(mutex == NULL || *mutex == THR_UNINITIALIZED))
+		return (EINVAL);
 
+	if (*mutex == THR_STATIC_INITIALIZER) {
+		*mutex = THR_UNINITIALIZED;
+		return (0);
+	}
+
+	id = TID(curthread);
+
+	/*
+	 * Try to lock the mutex structure, we only need to try once,
+	 * if failed, the mutex is in used.
+	 */
+	ret = _thr_umutex_trylock(&(*mutex)->m_lock, id);
+	if (ret)
+		return (ret);
+
+	/*
+	 * Check mutex other fields to see if this mutex is in use.
+	 * Mostly for prority mutex types, or there are condition
+	 * variables referencing it.
+	 */
+	m  = *mutex;
+	if (m->m_owner != NULL || m->m_refcount != 0) {
+		if (m->m_lock.m_flags & UMUTEX_PRIO_PROTECT)
+			set_inherited_priority(curthread, m);
+		_thr_umutex_unlock(&m->m_lock, id);
+		return (EBUSY);
+	} else {
 		/*
-		 * Try to lock the mutex structure, we only need to
-		 * try once, if failed, the mutex is in used.
-		 */
-		ret = _thr_umutex_trylock(&(*mutex)->m_lock, id);
-		if (ret)
-			return (ret);
-		m  = *mutex;
-		/*
-		 * Check mutex other fields to see if this mutex is
-		 * in use. Mostly for prority mutex types, or there
-		 * are condition variables referencing it.
+		 * Save a pointer to the mutex so it can be free'd
+		 * and set the caller's pointer to NULL.
 		 */
-		if (m->m_owner != NULL || m->m_refcount != 0) {
-			if (m->m_lock.m_flags & UMUTEX_PRIO_PROTECT)
-				set_inherited_priority(curthread, m);
-			_thr_umutex_unlock(&m->m_lock, id);
-			ret = EBUSY;
-		} else {
-			/*
-			 * Save a pointer to the mutex so it can be free'd
-			 * and set the caller's pointer to NULL.
-			 */
-			*mutex = NULL;
+		*mutex = THR_UNINITIALIZED;
 
-			if (m->m_lock.m_flags & UMUTEX_PRIO_PROTECT)
-				set_inherited_priority(curthread, m);
-			_thr_umutex_unlock(&m->m_lock, id);
+		if (m->m_lock.m_flags & UMUTEX_PRIO_PROTECT)
+			set_inherited_priority(curthread, m);
+		_thr_umutex_unlock(&m->m_lock, id);
 
-			MUTEX_ASSERT_NOT_OWNED(m);
-			free(m);
-		}
+		MUTEX_ASSERT_NOT_OWNED(m);
+		free(m);
 	}
 
-	return (ret);
+	return (0);
 }
 
 #define ENQUEUE_MUTEX(curthread, m)  					\
@@ -342,11 +350,14 @@ __pthread_mutex_trylock(pthread_mutex_t 
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+
 	/*
 	 * If the mutex is statically initialized, perform the dynamic
 	 * initialization:
 	 */
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -446,6 +457,9 @@ __pthread_mutex_lock(pthread_mutex_t *mu
 	struct pthread_mutex *m;
 	int	ret;
 
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+
 	_thr_check_init();
 
 	curthread = _get_curthread();
@@ -454,7 +468,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) == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -471,6 +485,9 @@ __pthread_mutex_timedlock(pthread_mutex_
 	struct pthread_mutex *m;
 	int	ret;
 
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+
 	_thr_check_init();
 
 	curthread = _get_curthread();
@@ -479,7 +496,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) == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -611,9 +628,12 @@ mutex_unlock_common(pthread_mutex_t *mut
 	struct pthread_mutex *m;
 	uint32_t id;
 
-	if (__predict_false((m = *mutex) == NULL))
+	if (__predict_false(mutex == NULL || (m = *mutex) == THR_UNINITIALIZED))
 		return (EINVAL);
 
+	if (*mutex == THR_STATIC_INITIALIZER)
+		return (EPERM);
+
 	/*
 	 * Check if the running thread is not the owner of the mutex.
 	 */
@@ -649,7 +669,7 @@ _mutex_cv_unlock(pthread_mutex_t *mutex,
 	struct pthread *curthread = _get_curthread();
 	struct pthread_mutex *m;
 
-	if (__predict_false((m = *mutex) == NULL))
+	if (__predict_false((m = *mutex) == THR_UNINITIALIZED))
 		return (EINVAL);
 
 	/*
@@ -685,18 +705,14 @@ int
 _pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
 			      int *prioceiling)
 {
-	int ret;
 
-	if (*mutex == NULL)
-		ret = EINVAL;
-	else if (((*mutex)->m_lock.m_flags & UMUTEX_PRIO_PROTECT) == 0)
-		ret = EINVAL;
-	else {
-		*prioceiling = (*mutex)->m_lock.m_ceilings[0];
-		ret = 0;
-	}
+	if (mutex == NULL || *mutex == THR_UNINITIALIZED ||
+	    ((*mutex)->m_lock.m_flags & UMUTEX_PRIO_PROTECT) == 0)
+		return (EINVAL);
+
+	*prioceiling = (*mutex)->m_lock.m_ceilings[0];
 
-	return(ret);
+	return (0);
 }
 
 int
@@ -707,10 +723,11 @@ _pthread_mutex_setprioceiling(pthread_mu
 	struct pthread_mutex *m, *m1, *m2;
 	int ret;
 
-	m = *mutex;
-	if (m == NULL || (m->m_lock.m_flags & UMUTEX_PRIO_PROTECT) == 0)
+	if (mutex == NULL || *mutex == THR_UNINITIALIZED ||
+	    ((*mutex)->m_lock.m_flags & UMUTEX_PRIO_PROTECT) == 0)
 		return (EINVAL);
 
+	m = *mutex;
 	ret = __thr_umutex_set_ceiling(&m->m_lock, ceiling, old_ceiling);
 	if (ret != 0)
 		return (ret);
@@ -737,7 +754,8 @@ _pthread_mutex_setprioceiling(pthread_mu
 int
 _pthread_mutex_getspinloops_np(pthread_mutex_t *mutex, int *count)
 {
-	if (*mutex == NULL)
+
+	if (mutex == NULL || *mutex == THR_UNINITIALIZED)
 		return (EINVAL);
 	*count = (*mutex)->m_spinloops;
 	return (0);
@@ -749,7 +767,7 @@ __pthread_mutex_setspinloops_np(pthread_
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(*mutex == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -761,7 +779,8 @@ __pthread_mutex_setspinloops_np(pthread_
 int
 _pthread_mutex_getyieldloops_np(pthread_mutex_t *mutex, int *count)
 {
-	if (*mutex == NULL)
+
+	if (mutex == NULL || *mutex == THR_UNINITIALIZED)
 		return (EINVAL);
 	*count = (*mutex)->m_yieldloops;
 	return (0);
@@ -773,7 +792,9 @@ __pthread_mutex_setyieldloops_np(pthread
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+	if (__predict_false(*mutex == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
@@ -788,7 +809,9 @@ _pthread_mutex_isowned_np(pthread_mutex_
 	struct pthread *curthread = _get_curthread();
 	int ret;
 
-	if (__predict_false(*mutex == NULL)) {
+	if (__predict_false(mutex == NULL))
+		return (EINVAL);
+	if (__predict_false(*mutex == THR_STATIC_INITIALIZER)) {
 		ret = init_static(curthread, mutex);
 		if (__predict_false(ret))
 			return (ret);
--- lib/libthr/thread/thr_private.h	2010-09-24 16:49:50.000000000 -0400
+++ lib/libthr/thread/thr_private.h	2010-09-24 17:45:12.000000000 -0400
@@ -125,6 +125,9 @@ TAILQ_HEAD(mutex_queue, pthread_mutex);
 		}						\
 	} while (0)
 
+#define	THR_UNINITIALIZED	((void *)0)
+#define	THR_STATIC_INITIALIZER	((void *)1)
+
 struct pthread_mutex {
 	/*
 	 * Lock for accesses to this structure.
--- lib/libthr/thread/thr_rwlock.c	2010-09-24 16:49:50.000000000 -0400
+++ lib/libthr/thread/thr_rwlock.c	2010-09-24 19:26:20.000000000 -0400
@@ -54,6 +54,9 @@ rwlock_init(pthread_rwlock_t *rwlock, co
 {
 	pthread_rwlock_t prwlock;
 
+	if (__predict_false(rwlock == NULL))
+		return (EINVAL);
+
 	prwlock = (pthread_rwlock_t)calloc(1, sizeof(struct pthread_rwlock));
 	if (prwlock == NULL)
 		return (ENOMEM);
@@ -64,20 +67,14 @@ rwlock_init(pthread_rwlock_t *rwlock, co
 int
 _pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
 {
-	int ret;
 
-	if (rwlock == NULL)
-		ret = EINVAL;
-	else {
-		pthread_rwlock_t prwlock;
-
-		prwlock = *rwlock;
-		*rwlock = NULL;
+	if (__predict_false(rwlock == NULL || *rwlock == THR_UNINITIALIZED))
+		return (EINVAL);
 
-		free(prwlock);
-		ret = 0;
-	}
-	return (ret);
+	if (*rwlock != THR_STATIC_INITIALIZER)
+		free(*rwlock);
+	*rwlock = THR_UNINITIALIZED;
+	return (0);
 }
 
 static int
@@ -87,7 +84,7 @@ init_static(struct pthread *thread, pthr
 
 	THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
 
-	if (*rwlock == NULL)
+	if (*rwlock == THR_STATIC_INITIALIZER)
 		ret = rwlock_init(rwlock, NULL);
 	else
 		ret = 0;
@@ -100,7 +97,7 @@ init_static(struct pthread *thread, pthr
 int
 _pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
 {
-	*rwlock = NULL;
+
 	return (rwlock_init(rwlock, attr));
 }
 
@@ -119,7 +116,7 @@ rwlock_rdlock_common(pthread_rwlock_t *r
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == THR_STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -212,7 +209,7 @@ _pthread_rwlock_tryrdlock (pthread_rwloc
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == THR_STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -256,7 +253,7 @@ _pthread_rwlock_trywrlock (pthread_rwloc
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == THR_STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -283,7 +280,7 @@ rwlock_wrlock_common (pthread_rwlock_t *
 	prwlock = *rwlock;
 
 	/* check for static initialization */
-	if (__predict_false(prwlock == NULL)) {
+	if (__predict_false(prwlock == THR_STATIC_INITIALIZER)) {
 		if ((ret = init_static(curthread, rwlock)) != 0)
 			return (ret);
 
@@ -361,9 +358,12 @@ _pthread_rwlock_unlock (pthread_rwlock_t
 
 	prwlock = *rwlock;
 
-	if (__predict_false(prwlock == NULL))
+	if (__predict_false(prwlock == THR_UNINITIALIZED))
 		return (EINVAL);
 
+	if (prwlock == THR_STATIC_INITIALIZER)
+		return (EPERM);
+
 	state = prwlock->lock.rw_state;
 	if (state & URWLOCK_WRITE_OWNER) {
 		if (__predict_false(prwlock->owner != curthread))

--Boundary-00=_OeTnMm3Rs0n8fas--



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