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@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  *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
ptw32_callUserDestroyRoutines(pthread_t thread)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