1 /*
2 * pthread_win32_attach_detach_np.c
3 *
4 * Description:
5 * This translation unit implements non-portable thread functions.
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@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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
35 */
36
37 #include "pthread.h"
38 #include "implement.h"
39
40 #include <tchar.h>
41
42 /*
43 * Handle to quserex.dll
44 */
45 static HINSTANCE ptw32_h_quserex;
46
47 BOOL
pthread_win32_process_attach_np()48 pthread_win32_process_attach_np ()
49 {
50 TCHAR QuserExDLLPathBuf[1024];
51 BOOL result = TRUE;
52
53 result = ptw32_processInitialize ();
54
55 #if defined(_UWIN)
56 pthread_count++;
57 #endif
58
59 #if defined(__GNUC__)
60 ptw32_features = 0;
61 #else
62 /*
63 * This is obsolete now.
64 */
65 ptw32_features = PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE;
66 #endif
67
68 /*
69 * Load QUSEREX.DLL and try to get address of QueueUserAPCEx.
70 * Because QUSEREX.DLL requires a driver to be installed we will
71 * assume the DLL is in the system directory.
72 *
73 * This should take care of any security issues.
74 */
75 #if defined(__GNUC__) || _MSC_VER < 1400
76 if(GetSystemDirectory(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf)))
77 {
78 (void) strncat(QuserExDLLPathBuf,
79 "\\QUSEREX.DLL",
80 sizeof(QuserExDLLPathBuf) - strlen(QuserExDLLPathBuf) - 1);
81 ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf);
82 }
83 #else
84 /* strncat is secure - this is just to avoid a warning */
85 if(GetSystemDirectory(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf) / sizeof(TCHAR)) &&
86 0 == _tcsncat_s(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf) / sizeof(TCHAR), TEXT("\\QUSEREX.DLL"), 12))
87 {
88 ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf);
89 }
90 #endif
91
92 if (ptw32_h_quserex != NULL)
93 {
94 ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD))
95 #if defined(NEED_UNICODE_CONSTS)
96 GetProcAddress (ptw32_h_quserex,
97 (const TCHAR *) TEXT ("QueueUserAPCEx"));
98 #else
99 GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx");
100 #endif
101 }
102
103 if (NULL == ptw32_register_cancelation)
104 {
105 ptw32_register_cancelation = ptw32_RegisterCancelation;
106
107 if (ptw32_h_quserex != NULL)
108 {
109 (void) FreeLibrary (ptw32_h_quserex);
110 }
111 ptw32_h_quserex = 0;
112 }
113 else
114 {
115 /* Initialise QueueUserAPCEx */
116 BOOL (*queue_user_apc_ex_init) (VOID);
117
118 queue_user_apc_ex_init = (BOOL (*)(VOID))
119 #if defined(NEED_UNICODE_CONSTS)
120 GetProcAddress (ptw32_h_quserex,
121 (const TCHAR *) TEXT ("QueueUserAPCEx_Init"));
122 #else
123 GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init");
124 #endif
125
126 if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ())
127 {
128 ptw32_register_cancelation = ptw32_RegisterCancelation;
129
130 (void) FreeLibrary (ptw32_h_quserex);
131 ptw32_h_quserex = 0;
132 }
133 }
134
135 if (ptw32_h_quserex)
136 {
137 ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL;
138 }
139
140 return result;
141 }
142
143
144 BOOL
pthread_win32_process_detach_np()145 pthread_win32_process_detach_np ()
146 {
147 if (ptw32_processInitialized)
148 {
149 ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);
150
151 if (sp != NULL)
152 {
153 /*
154 * Detached threads have their resources automatically
155 * cleaned up upon exit (others must be 'joined').
156 */
157 if (sp->detachState == PTHREAD_CREATE_DETACHED)
158 {
159 ptw32_threadDestroy (sp->ptHandle);
160 TlsSetValue (ptw32_selfThreadKey->key, NULL);
161 }
162 }
163
164 /*
165 * The DLL is being unmapped from the process's address space
166 */
167 ptw32_processTerminate ();
168
169 if (ptw32_h_quserex)
170 {
171 /* Close QueueUserAPCEx */
172 BOOL (*queue_user_apc_ex_fini) (VOID);
173
174 queue_user_apc_ex_fini = (BOOL (*)(VOID))
175 #if defined(NEED_UNICODE_CONSTS)
176 GetProcAddress (ptw32_h_quserex,
177 (const TCHAR *) TEXT ("QueueUserAPCEx_Fini"));
178 #else
179 GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Fini");
180 #endif
181
182 if (queue_user_apc_ex_fini != NULL)
183 {
184 (void) queue_user_apc_ex_fini ();
185 }
186 (void) FreeLibrary (ptw32_h_quserex);
187 }
188 }
189
190 return TRUE;
191 }
192
193 BOOL
pthread_win32_thread_attach_np()194 pthread_win32_thread_attach_np ()
195 {
196 return TRUE;
197 }
198
199 BOOL
pthread_win32_thread_detach_np()200 pthread_win32_thread_detach_np ()
201 {
202 if (ptw32_processInitialized)
203 {
204 /*
205 * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle
206 * unnecessarily.
207 */
208 ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);
209
210 if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle.
211 {
212 ptw32_mcs_local_node_t stateLock;
213 ptw32_callUserDestroyRoutines (sp->ptHandle);
214
215 ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
216 sp->state = PThreadStateLast;
217 /*
218 * If the thread is joinable at this point then it MUST be joined
219 * or detached explicitly by the application.
220 */
221 ptw32_mcs_lock_release (&stateLock);
222
223 /*
224 * Robust Mutexes
225 */
226 while (sp->robustMxList != NULL)
227 {
228 pthread_mutex_t mx = sp->robustMxList->mx;
229 ptw32_robust_mutex_remove(&mx, sp);
230 (void) PTW32_INTERLOCKED_EXCHANGE_LONG(
231 (PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent,
232 (PTW32_INTERLOCKED_LONG)-1);
233 /*
234 * If there are no waiters then the next thread to block will
235 * sleep, wakeup immediately and then go back to sleep.
236 * See pthread_mutex_lock.c.
237 */
238 SetEvent(mx->event);
239 }
240
241
242 if (sp->detachState == PTHREAD_CREATE_DETACHED)
243 {
244 ptw32_threadDestroy (sp->ptHandle);
245
246 TlsSetValue (ptw32_selfThreadKey->key, NULL);
247 }
248 }
249 }
250
251 return TRUE;
252 }
253
254 BOOL
pthread_win32_test_features_np(int feature_mask)255 pthread_win32_test_features_np (int feature_mask)
256 {
257 return ((ptw32_features & feature_mask) == feature_mask);
258 }
259