1 /* 2 * pthread_mutex_consistent.c 3 * 4 * Description: 5 * This translation unit implements mutual exclusion (mutex) primitives. 6 * 7 * -------------------------------------------------------------------------- 8 * 9 * Pthreads-win32 - POSIX Threads Library for Win32 10 * Copyright(C) 1998 John E. Bossom 11 * Copyright(C) 1999,2005 Pthreads-win32 contributors 12 * 13 * Contact Email: rpj (at) callisto.canberra.edu.au 14 * 15 * The current list of contributors is contained 16 * in the file CONTRIBUTORS included with the source 17 * code distribution. The list can also be seen at the 18 * following World Wide Web location: 19 * http://sources.redhat.com/pthreads-win32/contributors.html 20 * 21 * This library is free software; you can redistribute it and/or 22 * modify it under the terms of the GNU Lesser General Public 23 * License as published by the Free Software Foundation; either 24 * version 2 of the License, or (at your option) any later version. 25 * 26 * This library is distributed in the hope that it will be useful, 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 * Lesser General Public License for more details. 30 * 31 * You should have received a copy of the GNU Lesser General Public 32 * License along with this library in the file COPYING.LIB; 33 * if not, write to the Free Software Foundation, Inc., 34 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 35 */ 36 37 /* 38 * From the Sun Multi-threaded Programming Guide 39 * 40 * robustness defines the behavior when the owner of the mutex terminates without unlocking the 41 * mutex, usually because its process terminated abnormally. The value of robustness that is 42 * defined in pthread.h is PTHREAD_MUTEX_ROBUST or PTHREAD_MUTEX_STALLED. The 43 * default value is PTHREAD_MUTEX_STALLED . 44 * PTHREAD_MUTEX_STALLED 45 * When the owner of the mutex terminates without unlocking the mutex, all subsequent calls 46 * to pthread_mutex_lock() are blocked from progress in an unspecified manner. 47 * PTHREAD_MUTEX_ROBUST 48 * When the owner of the mutex terminates without unlocking the mutex, the mutex is 49 * unlocked. The next owner of this mutex acquires the mutex with an error return of 50 * EOWNERDEAD. 51 * Note Your application must always check the return code from pthread_mutex_lock() for 52 * a mutex initialized with the PTHREAD_MUTEX_ROBUST attribute. 53 * The new owner of this mutex should make the state protected by the mutex consistent. 54 * This state might have been left inconsistent when the previous owner terminated. 55 * If the new owner is able to make the state consistent, call 56 * pthread_mutex_consistent() for the mutex before unlocking the mutex. This 57 * marks the mutex as consistent and subsequent calls to pthread_mutex_lock() and 58 * pthread_mutex_unlock() will behave in the normal manner. 59 * If the new owner is not able to make the state consistent, do not call 60 * pthread_mutex_consistent() for the mutex, but unlock the mutex. 61 * All waiters are woken up and all subsequent calls to pthread_mutex_lock() fail to 62 * acquire the mutex. The return code is ENOTRECOVERABLE. The mutex can be made 63 * consistent by calling pthread_mutex_destroy() to uninitialize the mutex, and calling 64 * pthread_mutex_int() to reinitialize the mutex.However, the state that was protected 65 * by the mutex remains inconsistent and some form of application recovery is required. 66 * If the thread that acquires the lock with EOWNERDEAD terminates without unlocking the 67 * mutex, the next owner acquires the lock with an EOWNERDEAD return code. 68 */ 69 #if !defined(_UWIN) 70 /*# include <process.h> */ 71 #endif 72 #include "pthread.h" 73 #include "implement.h" 74 75 INLINE 76 int 77 ptw32_robust_mutex_inherit(pthread_mutex_t * mutex) 78 { 79 int result; 80 pthread_mutex_t mx = *mutex; 81 ptw32_robust_node_t* robust = mx->robustNode; 82 83 switch ((LONG)PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( 84 (PTW32_INTERLOCKED_LONGPTR)&robust->stateInconsistent, 85 (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT, 86 (PTW32_INTERLOCKED_LONG)-1 /* The terminating thread sets this */)) 87 { 88 case -1L: 89 result = EOWNERDEAD; 90 break; 91 case (LONG)PTW32_ROBUST_NOTRECOVERABLE: 92 result = ENOTRECOVERABLE; 93 break; 94 default: 95 result = 0; 96 break; 97 } 98 99 return result; 100 } 101 102 /* 103 * The next two internal support functions depend on only being 104 * called by the thread that owns the robust mutex. This enables 105 * us to avoid additional locks. 106 * Any mutex currently in the thread's robust mutex list is held 107 * by the thread, again eliminating the need for locks. 108 * The forward/backward links allow the thread to unlock mutexes 109 * in any order, not necessarily the reverse locking order. 110 * This is all possible because it is an error if a thread that 111 * does not own the [robust] mutex attempts to unlock it. 112 */ 113 114 INLINE 115 void 116 ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self) 117 { 118 ptw32_robust_node_t** list; 119 pthread_mutex_t mx = *mutex; 120 ptw32_thread_t* tp = (ptw32_thread_t*)self.p; 121 ptw32_robust_node_t* robust = mx->robustNode; 122 123 list = &tp->robustMxList; 124 mx->ownerThread = self; 125 if (NULL == *list) 126 { 127 robust->prev = NULL; 128 robust->next = NULL; 129 *list = robust; 130 } 131 else 132 { 133 robust->prev = NULL; 134 robust->next = *list; 135 (*list)->prev = robust; 136 *list = robust; 137 } 138 } 139 140 INLINE 141 void 142 ptw32_robust_mutex_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp) 143 { 144 ptw32_robust_node_t** list; 145 pthread_mutex_t mx = *mutex; 146 ptw32_robust_node_t* robust = mx->robustNode; 147 148 list = &(((ptw32_thread_t*)mx->ownerThread.p)->robustMxList); 149 mx->ownerThread.p = otp; 150 if (robust->next != NULL) 151 { 152 robust->next->prev = robust->prev; 153 } 154 if (robust->prev != NULL) 155 { 156 robust->prev->next = robust->next; 157 } 158 if (*list == robust) 159 { 160 *list = robust->next; 161 } 162 } 163 164 165 int 166 pthread_mutex_consistent (pthread_mutex_t* mutex) 167 { 168 pthread_mutex_t mx = *mutex; 169 int result = 0; 170 171 /* 172 * Let the system deal with invalid pointers. 173 */ 174 if (mx == NULL) 175 { 176 return EINVAL; 177 } 178 179 if (mx->kind >= 0 180 || (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT != PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( 181 (PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent, 182 (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_CONSISTENT, 183 (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT)) 184 { 185 result = EINVAL; 186 } 187 188 return (result); 189 } 190 191