1 /* 2 * ptw32_callUserDestroyRoutines.c 3 * 4 * Description: 5 * This translation unit implements routines which are private to 6 * the implementation and may be used throughout it. 7 * 8 * -------------------------------------------------------------------------- 9 * 10 * Pthreads-win32 - POSIX Threads Library for Win32 11 * Copyright(C) 1998 John E. Bossom 12 * Copyright(C) 1999,2005 Pthreads-win32 contributors 13 * 14 * Contact Email: rpj (at) callisto.canberra.edu.au 15 * 16 * The current list of contributors is contained 17 * in the file CONTRIBUTORS included with the source 18 * code distribution. The list can also be seen at the 19 * following World Wide Web location: 20 * http://sources.redhat.com/pthreads-win32/contributors.html 21 * 22 * This library is free software; you can redistribute it and/or 23 * modify it under the terms of the GNU Lesser General Public 24 * License as published by the Free Software Foundation; either 25 * version 2 of the License, or (at your option) any later version. 26 * 27 * This library is distributed in the hope that it will be useful, 28 * but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 * Lesser General Public License for more details. 31 * 32 * You should have received a copy of the GNU Lesser General Public 33 * License along with this library in the file COPYING.LIB; 34 * if not, write to the Free Software Foundation, Inc., 35 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 36 */ 37 38 #include "pthread.h" 39 #include "implement.h" 40 41 #if defined(__CLEANUP_CXX) 42 # if defined(_MSC_VER) 43 # include <eh.h> 44 # elif defined(__WATCOMC__) 45 # include <eh.h> 46 # include <exceptio.h> 47 # else 48 # if defined(__GNUC__) && __GNUC__ < 3 49 # include <new.h> 50 # else 51 # include <new> 52 using 53 std::terminate; 54 # endif 55 # endif 56 #endif 57 58 void 59 ptw32_callUserDestroyRoutines (pthread_t thread) 60 /* 61 * ------------------------------------------------------------------- 62 * DOCPRIVATE 63 * 64 * This the routine runs through all thread keys and calls 65 * the destroy routines on the user's data for the current thread. 66 * It simulates the behaviour of POSIX Threads. 67 * 68 * PARAMETERS 69 * thread 70 * an instance of pthread_t 71 * 72 * RETURNS 73 * N/A 74 * ------------------------------------------------------------------- 75 */ 76 { 77 ThreadKeyAssoc * assoc; 78 79 if (thread.p != NULL) 80 { 81 ptw32_mcs_local_node_t threadLock; 82 ptw32_mcs_local_node_t keyLock; 83 int assocsRemaining; 84 int iterations = 0; 85 ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; 86 87 /* 88 * Run through all Thread<-->Key associations 89 * for the current thread. 90 * 91 * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. 92 */ 93 do 94 { 95 assocsRemaining = 0; 96 iterations++; 97 98 ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); 99 /* 100 * The pointer to the next assoc is stored in the thread struct so that 101 * the assoc destructor in pthread_key_delete can adjust it 102 * if it deletes this assoc. This can happen if we fail to acquire 103 * both locks below, and are forced to release all of our locks, 104 * leaving open the opportunity for pthread_key_delete to get in 105 * before us. 106 */ 107 sp->nextAssoc = sp->keys; 108 ptw32_mcs_lock_release(&threadLock); 109 110 for (;;) 111 { 112 void * value; 113 pthread_key_t k; 114 void (*destructor) (void *); 115 116 /* 117 * First we need to serialise with pthread_key_delete by locking 118 * both assoc guards, but in the reverse order to our convention, 119 * so we must be careful to avoid deadlock. 120 */ 121 ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); 122 123 if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) 124 { 125 /* Finished */ 126 ptw32_mcs_lock_release(&threadLock); 127 break; 128 } 129 else 130 { 131 /* 132 * assoc->key must be valid because assoc can't change or be 133 * removed from our chain while we hold at least one lock. If 134 * the assoc was on our key chain then the key has not been 135 * deleted yet. 136 * 137 * Now try to acquire the second lock without deadlocking. 138 * If we fail, we need to relinquish the first lock and the 139 * processor and then try to acquire them all again. 140 */ 141 if (ptw32_mcs_lock_try_acquire(&(assoc->key->keyLock), &keyLock) == EBUSY) 142 { 143 ptw32_mcs_lock_release(&threadLock); 144 Sleep(0); 145 /* 146 * Go around again. 147 * If pthread_key_delete has removed this assoc in the meantime, 148 * sp->nextAssoc will point to a new assoc. 149 */ 150 continue; 151 } 152 } 153 154 /* We now hold both locks */ 155 156 sp->nextAssoc = assoc->nextKey; 157 158 /* 159 * Key still active; pthread_key_delete 160 * will block on these same mutexes before 161 * it can release actual key; therefore, 162 * key is valid and we can call the destroy 163 * routine; 164 */ 165 k = assoc->key; 166 destructor = k->destructor; 167 value = TlsGetValue(k->key); 168 TlsSetValue (k->key, NULL); 169 170 // Every assoc->key exists and has a destructor 171 if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) 172 { 173 /* 174 * Unlock both locks before the destructor runs. 175 * POSIX says pthread_key_delete can be run from destructors, 176 * and that probably includes with this key as target. 177 * pthread_setspecific can also be run from destructors and 178 * also needs to be able to access the assocs. 179 */ 180 ptw32_mcs_lock_release(&threadLock); 181 ptw32_mcs_lock_release(&keyLock); 182 183 assocsRemaining++; 184 185 #if defined(__cplusplus) 186 187 try 188 { 189 /* 190 * Run the caller's cleanup routine. 191 */ 192 destructor (value); 193 } 194 catch (...) 195 { 196 /* 197 * A system unexpected exception has occurred 198 * running the user's destructor. 199 * We get control back within this block in case 200 * the application has set up it's own terminate 201 * handler. Since we are leaving the thread we 202 * should not get any internal pthreads 203 * exceptions. 204 */ 205 terminate (); 206 } 207 208 #else /* __cplusplus */ 209 210 /* 211 * Run the caller's cleanup routine. 212 */ 213 destructor (value); 214 215 #endif /* __cplusplus */ 216 217 } 218 else 219 { 220 /* 221 * Remove association from both the key and thread chains 222 * and reclaim it's memory resources. 223 */ 224 ptw32_tkAssocDestroy (assoc); 225 ptw32_mcs_lock_release(&threadLock); 226 ptw32_mcs_lock_release(&keyLock); 227 } 228 } 229 } 230 while (assocsRemaining); 231 } 232 } /* ptw32_callUserDestroyRoutines */ 233