/* * pthread_mutex_consistent.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * From the Sun Multi-threaded Programming Guide * * robustness defines the behavior when the owner of the mutex terminates without unlocking the * mutex, usually because its process terminated abnormally. The value of robustness that is * defined in pthread.h is PTHREAD_MUTEX_ROBUST or PTHREAD_MUTEX_STALLED. The * default value is PTHREAD_MUTEX_STALLED . * ■ PTHREAD_MUTEX_STALLED * When the owner of the mutex terminates without unlocking the mutex, all subsequent calls * to pthread_mutex_lock() are blocked from progress in an unspecified manner. * ■ PTHREAD_MUTEX_ROBUST * When the owner of the mutex terminates without unlocking the mutex, the mutex is * unlocked. The next owner of this mutex acquires the mutex with an error return of * EOWNERDEAD. * Note – Your application must always check the return code from pthread_mutex_lock() for * a mutex initialized with the PTHREAD_MUTEX_ROBUST attribute. * ■ The new owner of this mutex should make the state protected by the mutex consistent. * This state might have been left inconsistent when the previous owner terminated. * ■ If the new owner is able to make the state consistent, call * pthread_mutex_consistent() for the mutex before unlocking the mutex. This * marks the mutex as consistent and subsequent calls to pthread_mutex_lock() and * pthread_mutex_unlock() will behave in the normal manner. * ■ If the new owner is not able to make the state consistent, do not call * pthread_mutex_consistent() for the mutex, but unlock the mutex. * All waiters are woken up and all subsequent calls to pthread_mutex_lock() fail to * acquire the mutex. The return code is ENOTRECOVERABLE. The mutex can be made * consistent by calling pthread_mutex_destroy() to uninitialize the mutex, and calling * pthread_mutex_int() to reinitialize the mutex.However, the state that was protected * by the mutex remains inconsistent and some form of application recovery is required. * ■ If the thread that acquires the lock with EOWNERDEAD terminates without unlocking the * mutex, the next owner acquires the lock with an EOWNERDEAD return code. */ #ifndef _UWIN /*# include */ #endif #include "pthread.h" #include "implement.h" INLINE int ptw32_robust_mutex_inherit(pthread_mutex_t * mutex) { int result; pthread_mutex_t mx = *mutex; ptw32_robust_node_t* robust = mx->robustNode; switch (PTW32_INTERLOCKED_COMPARE_EXCHANGE( (LPLONG)&robust->stateInconsistent, (LONG)PTW32_ROBUST_INCONSISTENT, -1L /* Terminating thread sets this */)) { case -1L: result = EOWNERDEAD; break; case (LONG)PTW32_ROBUST_NOTRECOVERABLE: result = ENOTRECOVERABLE; break; default: result = 0; break; } return result; } #if 1 INLINE void ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self) { ptw32_mcs_local_node_t listLock; ptw32_mcs_local_node_t mx1Lock; ptw32_mcs_local_node_t mx2Lock; ptw32_robust_node_t** list; pthread_mutex_t mx = *mutex; ptw32_thread_t* tp = self.p; ptw32_robust_node_t* robust = mx->robustNode; ptw32_mcs_lock_acquire(&tp->robustMxListLock, &listLock); list = &tp->robustMxList; ptw32_mcs_lock_acquire(&mx->robustNode->lock, &mx1Lock); mx->ownerThread = self; if (NULL == *list) { robust->prev = NULL; robust->next = NULL; *list = robust; } else { robust->prev = NULL; robust->next = *list; ptw32_mcs_lock_acquire(&(*list)->lock, &mx2Lock); (*list)->prev = robust; ptw32_mcs_lock_release(&mx2Lock); *list = robust; } ptw32_mcs_lock_release(&mx1Lock); ptw32_mcs_lock_release(&listLock); } #else INLINE void ptw32_robust_mutex_add(pthread_mutex_t* mutex) { ptw32_mcs_local_node_t listLock; ptw32_mcs_local_node_t mx1Lock; ptw32_mcs_local_node_t mx2Lock; ptw32_robust_node_t** list; pthread_mutex_t mx = *mutex; ptw32_robust_node_t* robust = mx->robustNode; ptw32_thread_t* tp = mx->ownerThread.p; if (NULL != tp) { ptw32_mcs_lock_acquire(&tp->robustMxListLock, &listLock); if (0 == robust->inList) { list = &tp->robustMxList; ptw32_mcs_lock_acquire(&mx->robustNode->lock, &mx1Lock); if (NULL == *list) { robust->prev = NULL; robust->next = NULL; *list = robust; } else { robust->prev = NULL; robust->next = *list; ptw32_mcs_lock_acquire(&(*list)->lock, &mx2Lock); (*list)->prev = robust; ptw32_mcs_lock_release(&mx2Lock); *list = robust; } ptw32_mcs_lock_release(&mx1Lock); robust->inList = 1; } ptw32_mcs_lock_release(&listLock); } } #endif #if 1 INLINE void ptw32_robust_mutex_quick_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp) { ptw32_mcs_local_node_t mx1Lock; ptw32_mcs_local_node_t mx2Lock; ptw32_robust_node_t** list; pthread_mutex_t mx = *mutex; ptw32_thread_t* tp = mx->ownerThread.p; if (NULL != tp) { ptw32_robust_node_t* robust = mx->robustNode; list = &tp->robustMxList; if (list != NULL) { ptw32_mcs_lock_acquire(&robust->lock, &mx1Lock); mx->ownerThread.p = otp; if (NULL != robust->next) { ptw32_mcs_lock_acquire(&robust->next->lock, &mx2Lock); robust->next->prev = robust->prev; ptw32_mcs_lock_release(&mx2Lock); } if (NULL != robust->prev) { ptw32_mcs_lock_acquire(&robust->prev->lock, &mx2Lock); robust->prev->next = robust->next; ptw32_mcs_lock_release(&mx2Lock); } if (*list == robust) { *list = robust->next; } ptw32_mcs_lock_release(&mx1Lock); } } } INLINE void ptw32_robust_mutex_remove(pthread_mutex_t* mutex) { ptw32_mcs_local_node_t listLock; ptw32_thread_t* tp = (*mutex)->ownerThread.p; if (NULL != tp) { ptw32_mcs_lock_acquire(&tp->robustMxListLock, &listLock); ptw32_robust_mutex_quick_remove(mutex, NULL); ptw32_mcs_lock_release(&listLock); } } #else INLINE void ptw32_robust_mutex_quick_remove(pthread_mutex_t* mutex, ptw32_thread_t* tp) { ptw32_mcs_local_node_t mx1Lock; ptw32_mcs_local_node_t mx2Lock; ptw32_robust_node_t** list; pthread_mutex_t mx = *mutex; ptw32_robust_node_t* robust = mx->robustNode; list = &tp->robustMxList; if (list != NULL) { ptw32_mcs_lock_acquire(&robust->lock, &mx1Lock); if (NULL != robust->next) { ptw32_mcs_lock_acquire(&robust->next->lock, &mx2Lock); robust->next->prev = robust->prev; ptw32_mcs_lock_release(&mx2Lock); } if (NULL != robust->prev) { ptw32_mcs_lock_acquire(&robust->prev->lock, &mx2Lock); robust->prev->next = robust->next; ptw32_mcs_lock_release(&mx2Lock); } if (*list == robust) { *list = robust->next; } ptw32_mcs_lock_release(&mx1Lock); } robust->inList = 0; } INLINE void ptw32_robust_mutex_remove(pthread_mutex_t* mutex, pthread_t self) { ptw32_mcs_local_node_t listLock; ptw32_thread_t* tp = self.p; ptw32_mcs_lock_acquire(&tp->robustMxListLock, &listLock); if (1 == (*mutex)->robustNode->inList) { ptw32_robust_mutex_quick_remove(mutex, tp); } ptw32_mcs_lock_release(&listLock); } #endif int pthread_mutex_consistent (pthread_mutex_t* mutex) { pthread_mutex_t mx = *mutex; int result = 0; /* * Let the system deal with invalid pointers. */ if (mx == NULL) { return EINVAL; } if (mx->kind >= 0 || (LONG)PTW32_ROBUST_INCONSISTENT != PTW32_INTERLOCKED_COMPARE_EXCHANGE( (LPLONG)&mx->robustNode->stateInconsistent, (LONG)PTW32_ROBUST_CONSISTENT, (LONG)PTW32_ROBUST_INCONSISTENT)) { result = EINVAL; } return (result); }