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