| 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 |