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