diff --git a/config/cci.m4 b/config/cci.m4 index faadae3e..a5b1721c 100644 --- a/config/cci.m4 +++ b/config/cci.m4 @@ -100,6 +100,12 @@ AC_DEFUN([CCI_SETUP_CTP],[ [AC_MSG_WARN([-g has been added to CFLAGS (developer build)]) CFLAGS="$CFLAGS -g"]) + # Look for mutex-errorcheck + AC_ARG_ENABLE(mutex-errorcheck, + AC_HELP_STRING(--mutex-errorcheck, enable mutex error checking), + AC_DEFINE([MUTEX_ERRORCHECK], [1], + [Define to enable mutex error checking])) + # Look for valgrind AC_ARG_ENABLE(valgrind, AC_HELP_STRING(--enable-valgrind, enable Valgrind hooks), diff --git a/include/cci_lib_types.h b/include/cci_lib_types.h index 4a12c020..51c83251 100644 --- a/include/cci_lib_types.h +++ b/include/cci_lib_types.h @@ -267,5 +267,66 @@ extern int cci__debug; #define CCI_VALGRIND_CHECK_WRITABLE(p, s) /* nothing */ #endif /* !HAVE_DECL_VALGRIND_MAKE_MEM_NOACCESS */ +#ifdef MUTEX_ERRORCHECK && MUTEX_ERRORCHECK == 1 +#define CCI_LOCK_INIT(x) \ +do { \ + int ret = 0; \ + pthread_mutexattr_t attr; \ + ret = pthread_mutexattr_init(&attr); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutexattr_init() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutexattr_settype() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ + ret = pthread_mutex_init((x), &attr); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutex_init() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ +} while(0) +#define CCI_LOCK_DESTROY(x) \ +do { \ + int ret = 0; \ + ret = pthread_mutex_destroy((x)); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutex_destroy() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ +} while(0) +#define CCI_LOCK(x) \ +do { \ + int ret = 0; \ + ret = pthread_mutex_lock((x)); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutex_lock() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ +} while(0) +#define CCI_UNLOCK(x) \ +do { \ + int ret = 0; \ + ret = pthread_mutex_unlock((x)); \ + if (ret) { \ + debug(CCI_DB_ERR, "%s: pthread_mutex_unlock() failed with %s", \ + __func__, strerror(ret)); \ + abort(); \ + } \ +} while(0) +#else +#define CCI_LOCK_INIT(x) pthread_mutex_init((x), NULL) +#define CCI_LOCK_DESTROY(x) pthread_mutex_destroy((x)) +#define CCI_LOCK(x) pthread_mutex_lock((x)) +#define CCI_UNLOCK(x) pthread_mutex_unlock((x)) +#endif /* PTHREAD_MUTEX_RECURSIVE */ + END_C_DECLS #endif /* CCI_LIB_TYPES_H */ diff --git a/src/api/create_endpoint.c b/src/api/create_endpoint.c index 92a533f2..4f8da466 100644 --- a/src/api/create_endpoint.c +++ b/src/api/create_endpoint.c @@ -27,7 +27,7 @@ int cci_create_endpoint(cci_device_t * device, cci__ep_t *ep; cci__dev_t *dev; - pthread_mutex_lock(&globals->lock); + CCI_LOCK(&globals->lock); if (NULL == device) { /* walk list of devs to find default device */ @@ -62,7 +62,7 @@ int cci_create_endpoint(cci_device_t * device, } TAILQ_INIT(&ep->evts); - pthread_mutex_init(&ep->lock, NULL); + CCI_LOCK_INIT(&ep->lock); ep->dev = dev; ep->endpoint.device = &dev->device; *endpoint = &ep->endpoint; @@ -70,16 +70,16 @@ int cci_create_endpoint(cci_device_t * device, ret = dev->plugin->create_endpoint(device, flags, endpoint, fd); ep->plugin = dev->plugin; - pthread_mutex_unlock(&globals->lock); + CCI_UNLOCK(&globals->lock); - pthread_mutex_lock(&dev->lock); + CCI_LOCK(&dev->lock); /* TODO check dev's state */ TAILQ_INSERT_TAIL(&dev->eps, ep, entry); - pthread_mutex_unlock(&dev->lock); + CCI_UNLOCK(&dev->lock); return ret; out: - pthread_mutex_unlock(&globals->lock); + CCI_UNLOCK(&globals->lock); return ret; } diff --git a/src/api/destroy_endpoint.c b/src/api/destroy_endpoint.c index 8ed6c812..ec3e1a7b 100644 --- a/src/api/destroy_endpoint.c +++ b/src/api/destroy_endpoint.c @@ -29,10 +29,10 @@ int cci_destroy_endpoint(cci_endpoint_t * endpoint) ep = container_of(endpoint, cci__ep_t, endpoint); dev = ep->dev; - pthread_mutex_lock(&dev->lock); + CCI_LOCK(&dev->lock); ep->closing = 1; TAILQ_REMOVE(&dev->eps, ep, entry); - pthread_mutex_unlock(&dev->lock); + CCI_UNLOCK(&dev->lock); /* the transport is responsible for cleaning up ep->priv, * the evts list, and any cci__conn_t that it is maintaining. diff --git a/src/api/finalize.c b/src/api/finalize.c index e0618660..dc2c074b 100644 --- a/src/api/finalize.c +++ b/src/api/finalize.c @@ -26,7 +26,7 @@ int cci_finalize(void) cci__dev_t *dev = NULL; int i; - pthread_mutex_lock(&init_lock); + CCI_LOCK(&init_lock); if (!initialized) { /* not initialized */ @@ -41,7 +41,7 @@ int cci_finalize(void) } /* lock the device list while destroying devices and finalizing CTPs */ - pthread_mutex_lock(&globals->lock); + CCI_LOCK(&globals->lock); /* for each device * for each endpoint @@ -49,14 +49,14 @@ int cci_finalize(void) */ TAILQ_FOREACH(dev, &globals->devs, entry) { - pthread_mutex_lock(&dev->lock); + CCI_LOCK(&dev->lock); while (!TAILQ_EMPTY(&dev->eps)) { cci__ep_t *ep = TAILQ_FIRST(&dev->eps); - pthread_mutex_unlock(&dev->lock); + CCI_UNLOCK(&dev->lock); cci_destroy_endpoint(&ep->endpoint); - pthread_mutex_lock(&dev->lock); + CCI_LOCK(&dev->lock); } - pthread_mutex_unlock(&dev->lock); + CCI_UNLOCK(&dev->lock); } /* let the transport clean up the private device */ @@ -77,7 +77,7 @@ int cci_finalize(void) free(globals->devices); globals->devices = NULL; - pthread_mutex_unlock(&globals->lock); + CCI_UNLOCK(&globals->lock); /* free globals */ free(globals); @@ -86,6 +86,6 @@ int cci_finalize(void) cci_plugins_finalize(); out: - pthread_mutex_unlock(&init_lock); + CCI_UNLOCK(&init_lock); return ret; } diff --git a/src/api/init.c b/src/api/init.c index 70894090..cbf93c6e 100644 --- a/src/api/init.c +++ b/src/api/init.c @@ -168,7 +168,7 @@ void cci__init_dev(cci__dev_t *dev) dev->priority = -1; /* tell the transport it must initialize it if we didn't */ dev->is_default = 0; TAILQ_INIT(&dev->eps); - pthread_mutex_init(&dev->lock, NULL); + CCI_LOCK_INIT(&dev->lock); device->up = 0; device->rate = 0; /* unknown */ @@ -539,7 +539,7 @@ int cci__parse_config(const char *path) static void cci_lock_init(void) { - pthread_mutex_init(&init_lock, NULL); + CCI_LOCK_INIT(&init_lock); return; } @@ -560,7 +560,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) return CCI_EINVAL; pthread_once(&once, cci_lock_init); - pthread_mutex_lock(&init_lock); + CCI_LOCK(&init_lock); if (0 == initialized) { cci__dev_t *dev; @@ -579,12 +579,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) globals->configfile = 0; TAILQ_INIT(&globals->configfile_devs); - ret = pthread_mutex_init(&globals->lock, NULL); - if (ret) { - perror("pthread_mutex_init failed:"); - ret = errno; - goto out_with_globals; - } + CCI_LOCK_INIT(&globals->lock); if (CCI_SUCCESS != (ret = cci_plugins_init())) { goto out_with_globals; @@ -599,7 +594,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) } /* lock the device list while initializing CTPs and devices */ - pthread_mutex_lock(&globals->lock); + CCI_LOCK(&globals->lock); str = getenv("CCI_CONFIG"); if (str && str[0] != '\0') { @@ -653,7 +648,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) globals->devices[i++] = &dev->device; } - pthread_mutex_unlock(&globals->lock); + CCI_UNLOCK(&globals->lock); /* success */ initialized++; @@ -674,7 +669,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) } } - pthread_mutex_unlock(&init_lock); + CCI_UNLOCK(&init_lock); return CCI_SUCCESS; out_with_plugins: @@ -688,7 +683,7 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) out_with_config_file: /* FIXME? */ out_with_glock: - pthread_mutex_unlock(&globals->lock); + CCI_UNLOCK(&globals->lock); out_with_plugins_ctp_open: cci_plugins_ctp_close(); out_with_plugins_init: @@ -696,6 +691,6 @@ int cci_init(uint32_t abi_ver, uint32_t flags, uint32_t * caps) out_with_globals: free(globals); out: - pthread_mutex_unlock(&init_lock); + CCI_UNLOCK(&init_lock); return ret; }