- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / third_party / pthreads-win32 / ptw32_callUserDestroyRoutines.c
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  *      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 */