/* A busy mutex can't be destroyed */ static __attribute__((noinline)) int mutex_ref(pthread_mutex_t *m ) { int r = 0; _spin_lite_lock(&mutex_global); if (!m || !*m) { _spin_lite_unlock(&mutex_global); return EINVAL; } if (STATIC_INITIALIZER(*m)) { _spin_lite_unlock(&mutex_global); r = mutex_static_init(m); _spin_lite_lock(&mutex_global); if (r != 0 && r != EBUSY) { _spin_lite_unlock(&mutex_global); return r; } } r = 0; if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) r = EINVAL; else { ((mutex_t *)*m)->busy ++; } _spin_lite_unlock(&mutex_global); return r; }
static __attribute__((noinline)) int mutex_static_init(pthread_mutex_t *m) { static pthread_mutexattr_t mxattr_recursive = PTHREAD_MUTEX_RECURSIVE; static pthread_mutexattr_t mxattr_errorcheck = PTHREAD_MUTEX_ERRORCHECK; int r; _spin_lite_lock(&mutex_global_static); if (!STATIC_INITIALIZER(*m)) { /* Assume someone crept in between: */ r = 0; } else { if (*m == PTHREAD_MUTEX_INITIALIZER) r = pthread_mutex_init (m, NULL); else if (*m == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) r = pthread_mutex_init (m, &mxattr_recursive); else if (*m == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) r = pthread_mutex_init (m, &mxattr_errorcheck); else if (*m == NULL) r = EINVAL; else r = pthread_mutex_init(m, NULL); } _spin_lite_unlock(&mutex_global_static); return r; }
/* A busy mutex can't be destroyed -> EBUSY */ static WINPTHREADS_ATTRIBUTE((noinline)) int mutex_ref_destroy (pthread_mutex_t *m, pthread_mutex_t *mDestroy ) { int r = 0; *mDestroy = NULL; /* also considered as busy, any concurrent access prevents destruction: $$$$ */ if (_spin_lite_trylock (&mutex_global) != 0) return EBUSY; if (!m || !*m) r = EINVAL; else { mutex_t *m_ = (mutex_t *)*m; if (STATIC_INITIALIZER(*m)) *m = NULL; else if (m_->valid != LIFE_MUTEX) r = EINVAL; else if (m_->busy || COND_LOCKED(m_)) r = EBUSY; else { *mDestroy = *m; *m = NULL; } } _spin_lite_unlock (&mutex_global); return r; }
/* A busy mutex can't be destroyed -> EBUSY */ static WINPTHREADS_ATTRIBUTE((noinline)) int mutex_ref_destroy (pthread_mutex_t *m, pthread_mutex_t *mDestroy) { pthread_mutex_t mx; mutex_t *m_; int r = 0; if (!m || !*m) return EINVAL; *mDestroy = NULL; /* also considered as busy, any concurrent access prevents destruction: */ mx = *m; r = pthread_mutex_trylock (&mx); if (r) return r; pthread_spin_lock (&mutex_global); if (!*m) r = EINVAL; else { m_ = (mutex_t *)*m; if (STATIC_INITIALIZER(*m)) *m = NULL; else if (m_->valid != LIFE_MUTEX) r = EINVAL; else if (m_->busy) r = 0xbeef; else { *mDestroy = *m; *m = NULL; } } if (r) { pthread_spin_unlock (&mutex_global); pthread_mutex_unlock (&mx); } return r; }
/* An unlock can simply fail with EPERM instead of auto-init (can't be owned) */ static WINPTHREADS_ATTRIBUTE((noinline)) int mutex_ref_unlock (pthread_mutex_t *m) { int r = 0; mutex_t *m_ = (mutex_t *)*m; _spin_lite_lock (&mutex_global); if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) r = EINVAL; else if (STATIC_INITIALIZER(*m) || !COND_LOCKED(m_)) r = EPERM; else ((mutex_t *)*m)->busy ++; _spin_lite_unlock (&mutex_global); return r; }
/* An unlock can simply fail with EPERM instead of auto-init (can't be owned) */ static __attribute__((noinline)) int mutex_ref_unlock(pthread_mutex_t *m) { int r = 0; mutex_t *m_ = (mutex_t *)*m; _spin_lite_lock(&mutex_global); if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) r = EINVAL; else if (STATIC_INITIALIZER(*m) || !COND_LOCKED(m_)) { r= EPERM; } else { ((mutex_t *)*m)->busy ++; } _spin_lite_unlock(&mutex_global); return r; }
/* A busy mutex can't be destroyed */ static WINPTHREADS_ATTRIBUTE((noinline)) int mutex_ref (pthread_mutex_t *m) { int r = 0; pthread_spin_lock (&mutex_global); if (!m || !*m) { pthread_spin_unlock (&mutex_global); return EINVAL; } if (STATIC_INITIALIZER(*m)) { pthread_spin_unlock (&mutex_global); r = mutex_static_init (m); pthread_spin_lock (&mutex_global); if (r != 0 && r != EBUSY) { pthread_spin_unlock (&mutex_global); return r; } } r = 0; if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) r = EINVAL; else ((mutex_t *)*m)->busy += 1; pthread_spin_unlock (&mutex_global); return r; }