1 /* 2 * pthread_mutex_lock.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 #if !defined(_UWIN) 38 /*# include <process.h> */ 39 #endif 40 #include "pthread.h" 41 #include "implement.h" 42 43 int 44 pthread_mutex_lock (pthread_mutex_t * mutex) 45 { 46 int kind; 47 pthread_mutex_t mx; 48 int result = 0; 49 50 /* 51 * Let the system deal with invalid pointers. 52 */ 53 if (*mutex == NULL) 54 { 55 return EINVAL; 56 } 57 58 /* 59 * We do a quick check to see if we need to do more work 60 * to initialise a static mutex. We check 61 * again inside the guarded section of ptw32_mutex_check_need_init() 62 * to avoid race conditions. 63 */ 64 if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) 65 { 66 if ((result = ptw32_mutex_check_need_init (mutex)) != 0) 67 { 68 return (result); 69 } 70 } 71 72 mx = *mutex; 73 kind = mx->kind; 74 75 if (kind >= 0) 76 { 77 /* Non-robust */ 78 if (PTHREAD_MUTEX_NORMAL == kind) 79 { 80 if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 81 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 82 (PTW32_INTERLOCKED_LONG) 1) != 0) 83 { 84 while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 85 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 86 (PTW32_INTERLOCKED_LONG) -1) != 0) 87 { 88 if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) 89 { 90 result = EINVAL; 91 break; 92 } 93 } 94 } 95 } 96 else 97 { 98 pthread_t self = pthread_self(); 99 100 if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( 101 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 102 (PTW32_INTERLOCKED_LONG) 1, 103 (PTW32_INTERLOCKED_LONG) 0) == 0) 104 { 105 mx->recursive_count = 1; 106 mx->ownerThread = self; 107 } 108 else 109 { 110 if (pthread_equal (mx->ownerThread, self)) 111 { 112 if (kind == PTHREAD_MUTEX_RECURSIVE) 113 { 114 mx->recursive_count++; 115 } 116 else 117 { 118 result = EDEADLK; 119 } 120 } 121 else 122 { 123 while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 124 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 125 (PTW32_INTERLOCKED_LONG) -1) != 0) 126 { 127 if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) 128 { 129 result = EINVAL; 130 break; 131 } 132 } 133 134 if (0 == result) 135 { 136 mx->recursive_count = 1; 137 mx->ownerThread = self; 138 } 139 } 140 } 141 } 142 } 143 else 144 { 145 /* 146 * Robust types 147 * All types record the current owner thread. 148 * The mutex is added to a per thread list when ownership is acquired. 149 */ 150 ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; 151 152 if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( 153 (PTW32_INTERLOCKED_LONGPTR)statePtr, 154 (PTW32_INTERLOCKED_LONG)0)) 155 { 156 result = ENOTRECOVERABLE; 157 } 158 else 159 { 160 pthread_t self = pthread_self(); 161 162 kind = -kind - 1; /* Convert to non-robust range */ 163 164 if (PTHREAD_MUTEX_NORMAL == kind) 165 { 166 if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 167 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 168 (PTW32_INTERLOCKED_LONG) 1) != 0) 169 { 170 while (0 == (result = ptw32_robust_mutex_inherit(mutex)) 171 && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 172 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 173 (PTW32_INTERLOCKED_LONG) -1) != 0) 174 { 175 if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) 176 { 177 result = EINVAL; 178 break; 179 } 180 if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == 181 PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( 182 (PTW32_INTERLOCKED_LONGPTR)statePtr, 183 (PTW32_INTERLOCKED_LONG)0)) 184 { 185 /* Unblock the next thread */ 186 SetEvent(mx->event); 187 result = ENOTRECOVERABLE; 188 break; 189 } 190 } 191 } 192 if (0 == result || EOWNERDEAD == result) 193 { 194 /* 195 * Add mutex to the per-thread robust mutex currently-held list. 196 * If the thread terminates, all mutexes in this list will be unlocked. 197 */ 198 ptw32_robust_mutex_add(mutex, self); 199 } 200 } 201 else 202 { 203 if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( 204 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 205 (PTW32_INTERLOCKED_LONG) 1, 206 (PTW32_INTERLOCKED_LONG) 0) == 0) 207 { 208 mx->recursive_count = 1; 209 /* 210 * Add mutex to the per-thread robust mutex currently-held list. 211 * If the thread terminates, all mutexes in this list will be unlocked. 212 */ 213 ptw32_robust_mutex_add(mutex, self); 214 } 215 else 216 { 217 if (pthread_equal (mx->ownerThread, self)) 218 { 219 if (PTHREAD_MUTEX_RECURSIVE == kind) 220 { 221 mx->recursive_count++; 222 } 223 else 224 { 225 result = EDEADLK; 226 } 227 } 228 else 229 { 230 while (0 == (result = ptw32_robust_mutex_inherit(mutex)) 231 && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( 232 (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, 233 (PTW32_INTERLOCKED_LONG) -1) != 0) 234 { 235 if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) 236 { 237 result = EINVAL; 238 break; 239 } 240 if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == 241 PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( 242 (PTW32_INTERLOCKED_LONGPTR)statePtr, 243 (PTW32_INTERLOCKED_LONG)0)) 244 { 245 /* Unblock the next thread */ 246 SetEvent(mx->event); 247 result = ENOTRECOVERABLE; 248 break; 249 } 250 } 251 252 if (0 == result || EOWNERDEAD == result) 253 { 254 mx->recursive_count = 1; 255 /* 256 * Add mutex to the per-thread robust mutex currently-held list. 257 * If the thread terminates, all mutexes in this list will be unlocked. 258 */ 259 ptw32_robust_mutex_add(mutex, self); 260 } 261 } 262 } 263 } 264 } 265 } 266 267 return (result); 268 } 269 270