Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Jan 2001 16:12:53 -0800 (PST)
From:      nuspl@polyserve.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   misc/24261: pthread_mutex_lock/pthread_mutex_unlock does not honor PTHREAD_MUTEX_ERRORCHECK
Message-ID:  <200101120012.f0C0Crs19290@freefall.freebsd.org>

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

>Number:         24261
>Category:       misc
>Synopsis:       pthread_mutex_lock/pthread_mutex_unlock does not honor PTHREAD_MUTEX_ERRORCHECK
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 11 16:20:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Joe Nuspl
>Release:        4.2
>Organization:
PolyServe Inc.
>Environment:
FreeBSD tm16.pdx.polyserve.com 4.2-RELEASE FreeBSD 4.2-RELEASE #0: Mon Nov 20 13:02:55 GMT 2000     jkh@bento.FreeBSD.org:/usr/src/sys/compile/GENERIC  i386

>Description:
The pthread_mutex_lock() and pthread_mutex_unlock() routines do not
honor the PTHREAD_MUTEX_ERRORCHECK type.

>How-To-Repeat:
#include <sys/types.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>

int
main(int argc, char **argv)
{
	int failed = -1;
	int rv;
	pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutexattr_t attr;

	rv = pthread_mutexattr_init(&attr);
	if (rv != 0) {
		(void)perror("pthread_mutexattr_init");
		return failed;
	}
	
	rv = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
	if (rv != 0) {
		perror("pthread_mutexattr_settype");
		goto unwind_attr;
	}

	rv = pthread_mutex_init(&mutex, &attr);
	if (rv != 0) {
		perror("pthread_mutex_init");
		goto unwind_attr;
	}

	rv = pthread_mutex_unlock(&mutex);
	if (rv != EPERM) {
		perror("pthread_mutex_unlock");
	}
	
	rv = pthread_mutex_lock(&mutex);
	if (rv != 0) {
		perror("pthread_mutex_lock");
		goto unwind_mutex;
	}

	rv = pthread_mutex_lock(&mutex);
	if (rv == EDEADLK) {
		failed = 0;
	} else {
		(void)fprintf(stderr, "rv=%d\n", rv);
		failed = 1;
	}
	
	(void)fprintf(stderr,
		      "PTHREAD_MUTEX_ERRORCHECK %s\n",
		      (failed ? "failed" : "passed"));

 unwind_mutex:
	(void)pthread_mutex_destroy(&mutex);
 unwind_attr:
	(void)pthread_mutexattr_destroy(&attr);

	return (failed);
}
>Fix:
Applying the attached patch to 
/usr/src/lib/libc_r/uthread/uthread_mutex.c
adds the needed error checks to the routines.

The patch for mutex_unlock_common() is a quick and dirty fix.  It could
be improved.

--- uthread_mutex.c.orig	Thu Jan 11 16:44:56 2001
+++ uthread_mutex.c	Thu Jan 11 17:02:19 2001
@@ -420,6 +420,22 @@
 	_thread_run->interrupted = 0;
 
 	/*
+	 * According to:
+	 * http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_mutex_lock.html
+	 *      If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error
+	 *      checking is provided. If a thread attempts to relock a mutex
+	 *      that it has already locked, an error will be returned.
+	 *
+	 *      The pthread_mutex_lock() function may fail if: 
+	 *      [EDEADLK]
+	 *             The current thread already owns the mutex. 
+	 */
+	if (((*mutex)->m_owner == _thread_run) &&
+	    ((*mutex)->m_type  == PTHREAD_MUTEX_ERRORCHECK)) {
+		return (EDEADLK);
+	}
+
+	/*
 	 * Enter a loop waiting to become the mutex owner.  We need a
 	 * loop in case the waiting thread is interrupted by a signal
 	 * to execute a signal handler.  It is not (currently) possible
@@ -739,6 +755,7 @@
 mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
 {
 	int	ret = 0;
+	int	proto;
 
 	if (mutex == NULL || *mutex == NULL) {
 		ret = EINVAL;
@@ -752,8 +769,33 @@
 		/* Lock the mutex structure: */
 		_SPINLOCK(&(*mutex)->lock);
 
+		proto =  (*mutex)->m_protocol;
+
+		/*
+		 * According to:
+		 * http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_mutex_lock.html
+		 *
+		 * If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then
+		 * error checking is provided.  If a thread attempts to
+		 * unlock a mutex that it has not locked or a mutex which
+		 * is unlocked, an error will be returned. 
+		 *
+		 * The pthread_mutex_unlock() function may fail if: 
+		 *	[EPERM]
+		 *	The current thread does not own the mutex. 
+		 */
+		if (((*mutex)->m_owner != _thread_run) &&
+		    ((*mutex)->m_type  == PTHREAD_MUTEX_ERRORCHECK)) {
+			proto = -1;
+			ret = EPERM;
+		}
+	
 		/* Process according to mutex type: */
-		switch ((*mutex)->m_protocol) {
+		switch (proto) {
+		case -1:
+			/* we've already caught an error, do nothing */
+			break;
+
 		/* Default POSIX mutex: */
 		case PTHREAD_PRIO_NONE:
 			/*


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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