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>
