Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/nathanw_sa]: src/lib/libpthread Implement recursive and errorcheck mutexes.
details: https://anonhg.NetBSD.org/src/rev/ab6e3c8874eb
branches: nathanw_sa
changeset: 506735:ab6e3c8874eb
user: thorpej <thorpej%NetBSD.org@localhost>
date: Mon Jan 13 22:50:09 2003 +0000
description:
Implement recursive and errorcheck mutexes.
diffstat:
lib/libpthread/TODO | 2 -
lib/libpthread/pthread.h | 12 +-
lib/libpthread/pthread_mutex.c | 228 +++++++++++++++++++++++++++++++++++++---
3 files changed, 220 insertions(+), 22 deletions(-)
diffs (truncated from 417 to 300 lines):
diff -r f3824c64ff5f -r ab6e3c8874eb lib/libpthread/TODO
--- a/lib/libpthread/TODO Mon Jan 13 20:26:25 2003 +0000
+++ b/lib/libpthread/TODO Mon Jan 13 22:50:09 2003 +0000
@@ -51,8 +51,6 @@
- Get rid of thread structures when too many accumulate (is this
actually a good idea?)
- Adaptive spin/sleep locks for mutexes.
-- Supporting different mutex types would be nice (normal, debugging,
- recursive, etc).
- Currently, each thread uses two real pages of memory: one at the top
of the stack for actual stack data, and one at the bottom for the
pthread_st. If we can get suitable space above the initial stack for
diff -r f3824c64ff5f -r ab6e3c8874eb lib/libpthread/pthread.h
--- a/lib/libpthread/pthread.h Mon Jan 13 20:26:25 2003 +0000
+++ b/lib/libpthread/pthread.h Mon Jan 13 22:50:09 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread.h,v 1.1.2.19 2003/01/08 19:34:22 thorpej Exp $ */
+/* $NetBSD: pthread.h,v 1.1.2.20 2003/01/13 22:50:09 thorpej Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -80,6 +80,8 @@
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr);
@@ -180,4 +182,12 @@
#define PTHREAD_STACK_MIN 4096 /* XXX Pulled out of my butt */
#define PTHREAD_THREADS_MAX 64 /* Min. required */
+/*
+ * Mutex attributes.
+ */
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+
#endif /* _LIB_PTHREAD_H */
diff -r f3824c64ff5f -r ab6e3c8874eb lib/libpthread/pthread_mutex.c
--- a/lib/libpthread/pthread_mutex.c Mon Jan 13 20:26:25 2003 +0000
+++ b/lib/libpthread/pthread_mutex.c Mon Jan 13 22:50:09 2003 +0000
@@ -1,11 +1,11 @@
-/* $NetBSD: pthread_mutex.c,v 1.1.2.18 2003/01/09 19:27:52 thorpej Exp $ */
+/* $NetBSD: pthread_mutex.c,v 1.1.2.19 2003/01/13 22:50:10 thorpej Exp $ */
/*-
- * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Nathan J. Williams.
+ * by Nathan J. Williams, and by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,14 +36,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
-#include <sys/cdefs.h>
+#include <limits.h>
+#include <stdlib.h>
#include "pthread.h"
#include "pthread_int.h"
-static void pthread_mutex_lock_slow(pthread_mutex_t *);
+static int pthread_mutex_lock_slow(pthread_mutex_t *);
__strong_alias(__libc_mutex_init,pthread_mutex_init)
__strong_alias(__libc_mutex_lock,pthread_mutex_lock)
@@ -53,9 +55,42 @@
__strong_alias(__libc_thr_once,pthread_once)
+struct mutex_private {
+ int type;
+ int recursecount;
+};
+
+static const struct mutex_private mutex_private_default = {
+ PTHREAD_MUTEX_DEFAULT,
+ 0,
+};
+
+struct mutexattr_private {
+ int type;
+};
+
+static const struct mutexattr_private mutexattr_private_default = {
+ PTHREAD_MUTEX_DEFAULT,
+};
+
+/*
+ * If the mutex does not already have private data (i.e. was statically
+ * initialized), then give it the default.
+ */
+#define GET_MUTEX_PRIVATE(mutex, mp) \
+do { \
+ if (__predict_false((mp = (mutex)->ptm_private) == NULL)) { \
+ /* LINTED cast away const */ \
+ mp = ((mutex)->ptm_private = \
+ (void *)&mutex_private_default); \
+ } \
+} while (/*CONSTCOND*/0)
+
int
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
+ struct mutexattr_private *map;
+ struct mutex_private *mp;
#ifdef ERRORCHECK
if ((mutex == NULL) ||
@@ -63,11 +98,25 @@
return EINVAL;
#endif
+ if (attr != NULL && (map = attr->ptma_private) != NULL &&
+ memcmp(map, &mutexattr_private_default, sizeof(*map)) != 0) {
+ mp = malloc(sizeof(*mp));
+ if (mp == NULL)
+ return ENOMEM;
+
+ mp->type = map->type;
+ mp->recursecount = 0;
+ } else {
+ /* LINTED cast away const */
+ mp = (struct mutex_private *) &mutex_private_default;
+ }
+
mutex->ptm_magic = _PT_MUTEX_MAGIC;
mutex->ptm_owner = NULL;
pthread_lockinit(&mutex->ptm_lock);
pthread_lockinit(&mutex->ptm_interlock);
PTQ_INIT(&mutex->ptm_blocked);
+ mutex->ptm_private = mp;
return 0;
}
@@ -85,6 +134,9 @@
#endif
mutex->ptm_magic = _PT_MUTEX_DEAD;
+ if (mutex->ptm_private != NULL &&
+ mutex->ptm_private != (void *)&mutex_private_default)
+ free(mutex->ptm_private);
return 0;
}
@@ -105,23 +157,31 @@
int
pthread_mutex_lock(pthread_mutex_t *mutex)
{
+ int error;
#ifdef ERRORCHECK
if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
return EINVAL;
#endif
- if (__predict_false(pthread__simple_lock_try(&mutex->ptm_lock) == 0))
- pthread_mutex_lock_slow(mutex);
+ /*
+ * Note that if we get the lock, we don't have to deal with any
+ * non-default lock type handling.
+ */
+ if (__predict_false(pthread__simple_lock_try(&mutex->ptm_lock) == 0)) {
+ error = pthread_mutex_lock_slow(mutex);
+ if (error)
+ return error;
+ }
/* We have the lock! */
-#ifdef ERRORCHECK
- mutex->ptm_owner = (pthread_t)pthread__sp();
-#endif
+ mutex->ptm_owner = pthread__self();
+
return 0;
}
-static void
+
+static int
pthread_mutex_lock_slow(pthread_mutex_t *mutex)
{
pthread_t self;
@@ -130,7 +190,7 @@
while (/*CONSTCOND*/1) {
if (pthread__simple_lock_try(&mutex->ptm_lock))
- break; /* got it! */
+ break; /* got it! */
/* Okay, didn't look free. Get the interlock... */
pthread_spinlock(self, &mutex->ptm_interlock);
@@ -142,6 +202,32 @@
* again.
*/
if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) {
+ struct mutex_private *mp;
+
+ GET_MUTEX_PRIVATE(mutex, mp);
+
+ if (mutex->ptm_owner == self) {
+ /*
+ * It's safe to do this without holding the
+ * interlock, because we only modify it if
+ * we know we own the mutex.
+ */
+ switch (mp->type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ pthread_spinunlock(self,
+ &mutex->ptm_interlock);
+ return EDEADLK;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ pthread_spinunlock(self,
+ &mutex->ptm_interlock);
+ if (mp->recursecount == INT_MAX)
+ return EAGAIN;
+ mp->recursecount++;
+ return 0;
+ }
+ }
+
PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep);
/*
* Locking a mutex is not a cancellation
@@ -165,24 +251,49 @@
}
/* Go around for another try. */
}
+
+ return 0;
}
int
pthread_mutex_trylock(pthread_mutex_t *mutex)
{
+ pthread_t self = pthread__self();
#ifdef ERRORCHECK
if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
return EINVAL;
#endif
- if (pthread__simple_lock_try(&mutex->ptm_lock) == 0)
- return EBUSY;
+ if (pthread__simple_lock_try(&mutex->ptm_lock) == 0) {
+ struct mutex_private *mp;
+
+ GET_MUTEX_PRIVATE(mutex, mp);
-#ifdef ERRORCHECK
- mutex->ptm_owner = (pthread_t)pthread__sp();
-#endif
+ /*
+ * These tests can be performed without holding the
+ * interlock because these fields are only modified
+ * if we know we own the mutex.
+ */
+ if (mutex->ptm_owner == self) {
+ switch (mp->type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ return EDEADLK;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ if (mp->recursecount == INT_MAX)
+ return EAGAIN;
+ mp->recursecount++;
+ return 0;
+ }
+ }
+
+ return EBUSY;
+ }
+
+ mutex->ptm_owner = self;
+
return 0;
}
@@ -190,6 +301,7 @@
int
pthread_mutex_unlock(pthread_mutex_t *mutex)
{
+ struct mutex_private *mp;
pthread_t self, blocked;
Home |
Main Index |
Thread Index |
Old Index