OSDN Git Service

Rework __try1/__except1 to resolve issue [#1328].
[mingw/mingw-org-wsl.git] / mingwrt / mthr.c
1 /*
2  * mthr.c
3  *
4  * Implement Mingw thread-support DLL .
5  *
6  * This file is used iff the following conditions are met:
7  *  - gcc uses -mthreads option
8  *  - user code uses C++ exceptions
9  *
10  * The sole job of the Mingw thread support DLL (MingwThr) is to catch
11  * all the dying threads and clean up the data allocated in the TLSs
12  * for exception contexts during C++ EH. Posix threads have key dtors,
13  * but win32 TLS keys do not, hence the magic. Without this, there's at
14  * least `6 * sizeof (void*)' bytes leaks for each catch/throw in each
15  * thread. The only public interface is __mingwthr_key_dtor().
16  *
17  * Created by Mumit Khan  <khan@nanotech.wisc.edu>
18  *
19  */
20
21 #define WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #undef WIN32_LEAN_AND_MEAN
24 #include <stdlib.h>
25
26 /* To protect the thread/key association data structure modifications. */
27 CRITICAL_SECTION __mingwthr_cs;
28
29 typedef struct __mingwthr_key __mingwthr_key_t;
30
31 /* The list of threads active with key/dtor pairs. */
32 struct __mingwthr_key {
33   DWORD key;
34   void (*dtor) (void *);
35   __mingwthr_key_t *next;
36 };
37
38
39 static __mingwthr_key_t *key_dtor_list;
40
41 /*
42  * __mingwthr_key_add:
43  *
44  * Add key/dtor association for this thread. If the thread entry does not
45  * exist, create a new one and add to the head of the threads list; add
46  * the new assoc at the head of the keys list.
47  *
48  */
49
50 static int
51 ___mingwthr_add_key_dtor ( DWORD key, void (*dtor) (void *))
52 {
53   __mingwthr_key_t *new_key;
54
55   new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t));
56   if (new_key == NULL)
57     return -1;
58
59   new_key->key = key;
60   new_key->dtor = dtor;
61
62   EnterCriticalSection (&__mingwthr_cs);
63
64   new_key->next = key_dtor_list;
65   key_dtor_list = new_key;
66
67   LeaveCriticalSection (&__mingwthr_cs);
68
69 #ifdef DEBUG
70   printf ("%s: allocating: (%ld, %x)\n",
71           __FUNCTION__, key, dtor);
72 #endif
73
74   return 0;
75 }
76
77 static int
78 ___mingwthr_remove_key_dtor ( DWORD key )
79 {
80   __mingwthr_key_t *prev_key;
81   __mingwthr_key_t *cur_key;
82
83   EnterCriticalSection (&__mingwthr_cs);
84
85   prev_key = NULL;
86   cur_key = key_dtor_list;
87
88   while( cur_key != NULL )
89   {
90      if( cur_key->key == key )
91      {
92 // take key/dtor out of list
93         if( prev_key == NULL )
94         {
95            key_dtor_list = cur_key->next;
96         }
97         else
98         {
99            prev_key->next = cur_key->next;
100         }
101
102 #ifdef DEBUG
103         printf ("%s: removing: (%ld)\n",
104                 __FUNCTION__, key );
105 #endif
106
107         free( cur_key );
108         break;
109      }
110
111      prev_key = cur_key;
112      cur_key = cur_key->next;
113   }
114
115   LeaveCriticalSection (&__mingwthr_cs);
116
117   return 0;
118 }
119
120 /*
121  * __mingwthr_run_key_dtors (void):
122  *
123  * Callback from DllMain when thread detaches to clean up the key
124  * storage.
125  *
126  * Note that this does not delete the key itself, but just runs
127  * the dtor if the current value are both non-NULL. Note that the
128  * keys with NULL dtors are not added by __mingwthr_key_dtor, the
129  * only public interface, so we don't need to check.
130  *
131  */
132
133 void
134 __mingwthr_run_key_dtors (void)
135 {
136   __mingwthr_key_t *keyp;
137
138 #ifdef DEBUG
139   printf ("%s: Entering Thread id %ld\n", __FUNCTION__, GetCurrentThreadId() );
140 #endif
141
142   EnterCriticalSection (&__mingwthr_cs);
143
144   for (keyp = key_dtor_list; keyp; )
145   {
146      LPVOID value = TlsGetValue (keyp->key);
147      if (GetLastError () == ERROR_SUCCESS)
148      {
149 #ifdef DEBUG
150         printf ("   (%ld, %x)\n", keyp->key, keyp->dtor);
151 #endif
152         if (value)
153            (*keyp->dtor) (value);
154      }
155 #ifdef DEBUG
156      else
157      {
158         printf ("   TlsGetValue FAILED  (%ld, %x)\n",
159                 keyp->key, keyp->dtor);
160      }
161 #endif
162      keyp = keyp->next;
163   }
164
165   LeaveCriticalSection (&__mingwthr_cs);
166
167 #ifdef DEBUG
168   printf ("%s: Exiting Thread id %ld\n", __FUNCTION__, GetCurrentThreadId() );
169 #endif
170 }
171
172 /*
173  * __mingwthr_register_key_dtor (DWORD key, void (*dtor) (void *))
174  *
175  * Public interface called by C++ exception handling mechanism in
176  * libgcc (cf: __gthread_key_create).
177  *
178  */
179
180 __declspec(dllexport)
181 int
182 __mingwthr_key_dtor (DWORD key, void (*dtor) (void *))
183 {
184   if (dtor)
185     {
186       return ___mingwthr_add_key_dtor (key, dtor);
187     }
188
189   return 0;
190 }
191
192 __declspec(dllexport)
193 int
194 __mingwthr_remove_key_dtor (DWORD key )
195 {
196    return ___mingwthr_remove_key_dtor ( key );
197 }