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