OLD | NEW |
| (Empty) |
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
5 | |
6 #include "primpl.h" | |
7 #include <process.h> /* for _beginthreadex() */ | |
8 | |
9 #if defined(_MSC_VER) && _MSC_VER <= 1200 | |
10 /* | |
11 * VC++ 6.0 doesn't have DWORD_PTR. | |
12 */ | |
13 | |
14 typedef DWORD DWORD_PTR; | |
15 #endif /* _MSC_VER <= 1200 */ | |
16 | |
17 /* --- globals ------------------------------------------------ */ | |
18 #ifdef _PR_USE_STATIC_TLS | |
19 __declspec(thread) struct PRThread *_pr_thread_last_run; | |
20 __declspec(thread) struct PRThread *_pr_currentThread; | |
21 __declspec(thread) struct _PRCPU *_pr_currentCPU; | |
22 #else | |
23 DWORD _pr_currentThreadIndex; | |
24 DWORD _pr_lastThreadIndex; | |
25 DWORD _pr_currentCPUIndex; | |
26 #endif | |
27 int _pr_intsOff = 0; | |
28 _PRInterruptTable _pr_interruptTable[] = { { 0 } }; | |
29 | |
30 void | |
31 _PR_MD_EARLY_INIT() | |
32 { | |
33 #ifndef _PR_USE_STATIC_TLS | |
34 _pr_currentThreadIndex = TlsAlloc(); | |
35 _pr_lastThreadIndex = TlsAlloc(); | |
36 _pr_currentCPUIndex = TlsAlloc(); | |
37 #endif | |
38 } | |
39 | |
40 void _PR_MD_CLEANUP_BEFORE_EXIT(void) | |
41 { | |
42 _PR_NT_FreeSids(); | |
43 | |
44 _PR_MD_CleanupSockets(); | |
45 | |
46 WSACleanup(); | |
47 | |
48 #ifndef _PR_USE_STATIC_TLS | |
49 TlsFree(_pr_currentThreadIndex); | |
50 TlsFree(_pr_lastThreadIndex); | |
51 TlsFree(_pr_currentCPUIndex); | |
52 #endif | |
53 } | |
54 | |
55 PRStatus | |
56 _PR_MD_INIT_THREAD(PRThread *thread) | |
57 { | |
58 if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { | |
59 /* | |
60 ** Warning: | |
61 ** -------- | |
62 ** NSPR requires a real handle to every thread. | |
63 ** GetCurrentThread() returns a pseudo-handle which | |
64 ** is not suitable for some thread operations (e.g., | |
65 ** suspending). Therefore, get a real handle from | |
66 ** the pseudo handle via DuplicateHandle(...) | |
67 */ | |
68 BOOL ok = DuplicateHandle( | |
69 GetCurrentProcess(), /* Process of source handle */ | |
70 GetCurrentThread(), /* Pseudo Handle to dup */ | |
71 GetCurrentProcess(), /* Process of handle */ | |
72 &(thread->md.handle), /* resulting handle */ | |
73 0L, /* access flags */ | |
74 FALSE, /* Inheritable */ | |
75 DUPLICATE_SAME_ACCESS); /* Options */ | |
76 if (!ok) { | |
77 return PR_FAILURE; | |
78 } | |
79 thread->id = GetCurrentThreadId(); | |
80 thread->md.id = thread->id; | |
81 } | |
82 | |
83 /* Create the blocking IO semaphore */ | |
84 thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); | |
85 if (thread->md.blocked_sema == NULL) | |
86 return PR_FAILURE; | |
87 else | |
88 return PR_SUCCESS; | |
89 } | |
90 | |
91 static unsigned __stdcall | |
92 pr_root(void *arg) | |
93 { | |
94 PRThread *thread = (PRThread *)arg; | |
95 thread->md.start(thread); | |
96 return 0; | |
97 } | |
98 | |
99 PRStatus | |
100 _PR_MD_CREATE_THREAD(PRThread *thread, | |
101 void (*start)(void *), | |
102 PRThreadPriority priority, | |
103 PRThreadScope scope, | |
104 PRThreadState state, | |
105 PRUint32 stackSize) | |
106 { | |
107 | |
108 thread->md.start = start; | |
109 thread->md.handle = (HANDLE) _beginthreadex( | |
110 NULL, | |
111 thread->stack->stackSize, | |
112 pr_root, | |
113 (void *)thread, | |
114 CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, | |
115 &(thread->id)); | |
116 if(!thread->md.handle) { | |
117 return PR_FAILURE; | |
118 } | |
119 | |
120 thread->md.id = thread->id; | |
121 /* | |
122 * On windows, a thread is created with a thread priority of | |
123 * THREAD_PRIORITY_NORMAL. | |
124 */ | |
125 if (priority != PR_PRIORITY_NORMAL) { | |
126 _PR_MD_SET_PRIORITY(&(thread->md), priority); | |
127 } | |
128 | |
129 /* Activate the thread */ | |
130 if ( ResumeThread( thread->md.handle ) != -1) | |
131 return PR_SUCCESS; | |
132 | |
133 return PR_FAILURE; | |
134 } | |
135 | |
136 void | |
137 _PR_MD_YIELD(void) | |
138 { | |
139 /* Can NT really yield at all? */ | |
140 Sleep(0); | |
141 } | |
142 | |
143 void | |
144 _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) | |
145 { | |
146 int nativePri; | |
147 BOOL rv; | |
148 | |
149 if (newPri < PR_PRIORITY_FIRST) { | |
150 newPri = PR_PRIORITY_FIRST; | |
151 } else if (newPri > PR_PRIORITY_LAST) { | |
152 newPri = PR_PRIORITY_LAST; | |
153 } | |
154 switch (newPri) { | |
155 case PR_PRIORITY_LOW: | |
156 nativePri = THREAD_PRIORITY_BELOW_NORMAL; | |
157 break; | |
158 case PR_PRIORITY_NORMAL: | |
159 nativePri = THREAD_PRIORITY_NORMAL; | |
160 break; | |
161 case PR_PRIORITY_HIGH: | |
162 nativePri = THREAD_PRIORITY_ABOVE_NORMAL; | |
163 break; | |
164 case PR_PRIORITY_URGENT: | |
165 nativePri = THREAD_PRIORITY_HIGHEST; | |
166 } | |
167 rv = SetThreadPriority(thread->handle, nativePri); | |
168 PR_ASSERT(rv); | |
169 if (!rv) { | |
170 PR_LOG(_pr_thread_lm, PR_LOG_MIN, | |
171 ("PR_SetThreadPriority: can't set thread priority\n")); | |
172 } | |
173 return; | |
174 } | |
175 | |
176 const DWORD MS_VC_EXCEPTION = 0x406D1388; | |
177 | |
178 #pragma pack(push,8) | |
179 typedef struct tagTHREADNAME_INFO | |
180 { | |
181 DWORD dwType; // Must be 0x1000. | |
182 LPCSTR szName; // Pointer to name (in user addr space). | |
183 DWORD dwThreadID; // Thread ID (-1=caller thread). | |
184 DWORD dwFlags; // Reserved for future use, must be zero. | |
185 } THREADNAME_INFO; | |
186 #pragma pack(pop) | |
187 | |
188 void | |
189 _PR_MD_SET_CURRENT_THREAD_NAME(const char *name) | |
190 { | |
191 #ifdef _MSC_VER | |
192 THREADNAME_INFO info; | |
193 | |
194 if (!IsDebuggerPresent()) | |
195 return; | |
196 | |
197 info.dwType = 0x1000; | |
198 info.szName = (char*) name; | |
199 info.dwThreadID = -1; | |
200 info.dwFlags = 0; | |
201 | |
202 __try { | |
203 RaiseException(MS_VC_EXCEPTION, | |
204 0, | |
205 sizeof(info) / sizeof(ULONG_PTR), | |
206 (ULONG_PTR*)&info); | |
207 } __except(EXCEPTION_CONTINUE_EXECUTION) { | |
208 } | |
209 #endif | |
210 } | |
211 | |
212 void | |
213 _PR_MD_CLEAN_THREAD(PRThread *thread) | |
214 { | |
215 BOOL rv; | |
216 | |
217 if (thread->md.blocked_sema) { | |
218 rv = CloseHandle(thread->md.blocked_sema); | |
219 PR_ASSERT(rv); | |
220 thread->md.blocked_sema = 0; | |
221 } | |
222 | |
223 if (thread->md.handle) { | |
224 rv = CloseHandle(thread->md.handle); | |
225 PR_ASSERT(rv); | |
226 thread->md.handle = 0; | |
227 } | |
228 } | |
229 | |
230 void | |
231 _PR_MD_EXIT_THREAD(PRThread *thread) | |
232 { | |
233 _PR_MD_CLEAN_THREAD(thread); | |
234 _PR_MD_SET_CURRENT_THREAD(NULL); | |
235 } | |
236 | |
237 | |
238 void | |
239 _PR_MD_EXIT(PRIntn status) | |
240 { | |
241 _exit(status); | |
242 } | |
243 | |
244 PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) | |
245 { | |
246 #ifdef WINCE | |
247 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
248 return -1; | |
249 #else | |
250 DWORD_PTR rv; | |
251 | |
252 rv = SetThreadAffinityMask(thread->md.handle, mask); | |
253 | |
254 return rv?0:-1; | |
255 #endif | |
256 } | |
257 | |
258 PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) | |
259 { | |
260 #ifdef WINCE | |
261 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
262 return -1; | |
263 #else | |
264 BOOL rv; | |
265 DWORD_PTR process_mask; | |
266 DWORD_PTR system_mask; | |
267 | |
268 rv = GetProcessAffinityMask(GetCurrentProcess(), | |
269 &process_mask, &system_mask); | |
270 if (rv) | |
271 *mask = (PRUint32)process_mask; | |
272 | |
273 return rv?0:-1; | |
274 #endif | |
275 } | |
276 | |
277 void | |
278 _PR_MD_SUSPEND_CPU(_PRCPU *cpu) | |
279 { | |
280 _PR_MD_SUSPEND_THREAD(cpu->thread); | |
281 } | |
282 | |
283 void | |
284 _PR_MD_RESUME_CPU(_PRCPU *cpu) | |
285 { | |
286 _PR_MD_RESUME_THREAD(cpu->thread); | |
287 } | |
288 | |
289 void | |
290 _PR_MD_SUSPEND_THREAD(PRThread *thread) | |
291 { | |
292 if (_PR_IS_NATIVE_THREAD(thread)) { | |
293 DWORD previousSuspendCount; | |
294 /* XXXMB - SuspendThread() is not a blocking call; how do we | |
295 * know when the thread is *REALLY* suspended? | |
296 */ | |
297 previousSuspendCount = SuspendThread(thread->md.handle); | |
298 PR_ASSERT(previousSuspendCount == 0); | |
299 } | |
300 } | |
301 | |
302 void | |
303 _PR_MD_RESUME_THREAD(PRThread *thread) | |
304 { | |
305 if (_PR_IS_NATIVE_THREAD(thread)) { | |
306 DWORD previousSuspendCount; | |
307 previousSuspendCount = ResumeThread(thread->md.handle); | |
308 PR_ASSERT(previousSuspendCount == 1); | |
309 } | |
310 } | |
311 | |
312 PRThread* | |
313 _MD_CURRENT_THREAD(void) | |
314 { | |
315 PRThread *thread; | |
316 | |
317 thread = _MD_GET_ATTACHED_THREAD(); | |
318 | |
319 if (NULL == thread) { | |
320 thread = _PRI_AttachThread( | |
321 PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, NULL, 0); | |
322 } | |
323 PR_ASSERT(thread != NULL); | |
324 return thread; | |
325 } | |
326 | |
327 #ifdef NSPR_STATIC | |
328 | |
329 // The following code is from Chromium src/base/thread_local_storage_win.cc, | |
330 // r11329. | |
331 | |
332 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | |
333 // | |
334 // Redistribution and use in source and binary forms, with or without | |
335 // modification, are permitted provided that the following conditions are | |
336 // met: | |
337 // | |
338 // * Redistributions of source code must retain the above copyright | |
339 // notice, this list of conditions and the following disclaimer. | |
340 // * Redistributions in binary form must reproduce the above | |
341 // copyright notice, this list of conditions and the following disclaimer | |
342 // in the documentation and/or other materials provided with the | |
343 // distribution. | |
344 // * Neither the name of Google Inc. nor the names of its | |
345 // contributors may be used to endorse or promote products derived from | |
346 // this software without specific prior written permission. | |
347 // | |
348 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
349 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
350 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
351 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
352 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
353 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
354 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
355 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
356 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
357 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
358 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
359 | |
360 // Thread Termination Callbacks. | |
361 // Windows doesn't support a per-thread destructor with its | |
362 // TLS primitives. So, we build it manually by inserting a | |
363 // function to be called on each thread's exit. | |
364 // This magic is from http://www.codeproject.com/threads/tls.asp | |
365 // and it works for VC++ 7.0 and later. | |
366 | |
367 // Force a reference to _tls_used to make the linker create the TLS directory | |
368 // if it's not already there. (e.g. if __declspec(thread) is not used). | |
369 // Force a reference to p_thread_callback_nspr to prevent whole program | |
370 // optimization from discarding the variable. | |
371 #ifdef _WIN64 | |
372 | |
373 #pragma comment(linker, "/INCLUDE:_tls_used") | |
374 #pragma comment(linker, "/INCLUDE:p_thread_callback_nspr") | |
375 | |
376 #else // _WIN64 | |
377 | |
378 #pragma comment(linker, "/INCLUDE:__tls_used") | |
379 #pragma comment(linker, "/INCLUDE:_p_thread_callback_nspr") | |
380 | |
381 #endif // _WIN64 | |
382 | |
383 // Static callback function to call with each thread termination. | |
384 static void NTAPI PR_OnThreadExit(PVOID module, DWORD reason, PVOID reserved) | |
385 { | |
386 PRThread *me; | |
387 | |
388 switch (reason) { | |
389 case DLL_PROCESS_ATTACH: | |
390 break; | |
391 case DLL_THREAD_ATTACH: | |
392 break; | |
393 case DLL_THREAD_DETACH: | |
394 if (_pr_initialized) { | |
395 me = _MD_GET_ATTACHED_THREAD(); | |
396 if ((me != NULL) && (me->flags & _PR_ATTACHED)) | |
397 _PRI_DetachThread(); | |
398 } | |
399 break; | |
400 case DLL_PROCESS_DETACH: | |
401 break; | |
402 } | |
403 } | |
404 | |
405 // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are | |
406 // called automatically by the OS loader code (not the CRT) when the module is | |
407 // loaded and on thread creation. They are NOT called if the module has been | |
408 // loaded by a LoadLibrary() call. It must have implicitly been loaded at | |
409 // process startup. | |
410 // By implicitly loaded, I mean that it is directly referenced by the main EXE | |
411 // or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being | |
412 // implicitly loaded. | |
413 // | |
414 // See VC\crt\src\tlssup.c for reference. | |
415 | |
416 // The linker must not discard p_thread_callback_nspr. (We force a reference | |
417 // to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If | |
418 // this variable is discarded, the PR_OnThreadExit function will never be | |
419 // called. | |
420 #ifdef _WIN64 | |
421 | |
422 // .CRT section is merged with .rdata on x64 so it must be constant data. | |
423 #pragma const_seg(".CRT$XLB") | |
424 // When defining a const variable, it must have external linkage to be sure the | |
425 // linker doesn't discard it. | |
426 extern const PIMAGE_TLS_CALLBACK p_thread_callback_nspr; | |
427 const PIMAGE_TLS_CALLBACK p_thread_callback_nspr = PR_OnThreadExit; | |
428 | |
429 // Reset the default section. | |
430 #pragma const_seg() | |
431 | |
432 #else // _WIN64 | |
433 | |
434 #pragma data_seg(".CRT$XLB") | |
435 PIMAGE_TLS_CALLBACK p_thread_callback_nspr = PR_OnThreadExit; | |
436 | |
437 // Reset the default section. | |
438 #pragma data_seg() | |
439 | |
440 #endif // _WIN64 | |
441 | |
442 #endif // NSPR_STATIC | |
OLD | NEW |