w95thred.c (8708B)
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 typedef HRESULT(WINAPI* SETTHREADDESCRIPTION)(HANDLE, PCWSTR); 31 static SETTHREADDESCRIPTION sSetThreadDescription = NULL; 32 33 void _PR_MD_EARLY_INIT() { 34 HMODULE hModule; 35 36 #ifndef _PR_USE_STATIC_TLS 37 _pr_currentThreadIndex = TlsAlloc(); 38 _pr_lastThreadIndex = TlsAlloc(); 39 _pr_currentCPUIndex = TlsAlloc(); 40 #endif 41 42 #if defined(_WIN64) && defined(WIN95) 43 _fd_waiting_for_overlapped_done_lock = PR_NewLock(); 44 #endif 45 46 // SetThreadDescription is Windows 10 build 1607+ 47 hModule = GetModuleHandleW(L"kernel32.dll"); 48 if (hModule) { 49 sSetThreadDescription = 50 (SETTHREADDESCRIPTION)GetProcAddress(hModule, "SetThreadDescription"); 51 } 52 } 53 54 void _PR_MD_CLEANUP_BEFORE_EXIT(void) { 55 _PR_NT_FreeSids(); 56 57 _PR_MD_CleanupSockets(); 58 59 WSACleanup(); 60 61 #ifndef _PR_USE_STATIC_TLS 62 TlsFree(_pr_currentThreadIndex); 63 TlsFree(_pr_lastThreadIndex); 64 TlsFree(_pr_currentCPUIndex); 65 #endif 66 67 #if defined(_WIN64) && defined(WIN95) 68 // For each iteration check if TFO overlapped IOs are down. 69 if (_fd_waiting_for_overlapped_done_lock) { 70 PRIntervalTime delay = PR_MillisecondsToInterval(1000); 71 PRFileDescList* cur; 72 do { 73 CheckOverlappedPendingSocketsAreDone(); 74 75 PR_Lock(_fd_waiting_for_overlapped_done_lock); 76 cur = _fd_waiting_for_overlapped_done; 77 PR_Unlock(_fd_waiting_for_overlapped_done_lock); 78 # if defined(DO_NOT_WAIT_FOR_CONNECT_OVERLAPPED_OPERATIONS) 79 cur = NULL; 80 # endif 81 if (cur) { 82 PR_Sleep(delay); // wait another 1s. 83 } 84 } while (cur); 85 86 PR_DestroyLock(_fd_waiting_for_overlapped_done_lock); 87 } 88 #endif 89 } 90 91 PRStatus _PR_MD_INIT_THREAD(PRThread* thread) { 92 if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { 93 /* 94 ** Warning: 95 ** -------- 96 ** NSPR requires a real handle to every thread. 97 ** GetCurrentThread() returns a pseudo-handle which 98 ** is not suitable for some thread operations (e.g., 99 ** suspending). Therefore, get a real handle from 100 ** the pseudo handle via DuplicateHandle(...) 101 */ 102 BOOL ok = 103 DuplicateHandle(GetCurrentProcess(), /* Process of source handle */ 104 GetCurrentThread(), /* Pseudo Handle to dup */ 105 GetCurrentProcess(), /* Process of handle */ 106 &(thread->md.handle), /* resulting handle */ 107 0L, /* access flags */ 108 FALSE, /* Inheritable */ 109 DUPLICATE_SAME_ACCESS); /* Options */ 110 if (!ok) { 111 return PR_FAILURE; 112 } 113 thread->id = GetCurrentThreadId(); 114 thread->md.id = thread->id; 115 } 116 117 /* Create the blocking IO semaphore */ 118 thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); 119 if (thread->md.blocked_sema == NULL) { 120 return PR_FAILURE; 121 } else { 122 return PR_SUCCESS; 123 } 124 } 125 126 static unsigned __stdcall pr_root(void* arg) { 127 PRThread* thread = (PRThread*)arg; 128 thread->md.start(thread); 129 return 0; 130 } 131 132 PRStatus _PR_MD_CREATE_THREAD(PRThread* thread, void (*start)(void*), 133 PRThreadPriority priority, PRThreadScope scope, 134 PRThreadState state, PRUint32 stackSize) { 135 thread->md.start = start; 136 thread->md.handle = (HANDLE)_beginthreadex( 137 NULL, thread->stack->stackSize, pr_root, (void*)thread, 138 CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &(thread->id)); 139 if (!thread->md.handle) { 140 return PR_FAILURE; 141 } 142 143 thread->md.id = thread->id; 144 /* 145 * On windows, a thread is created with a thread priority of 146 * THREAD_PRIORITY_NORMAL. 147 */ 148 if (priority != PR_PRIORITY_NORMAL) { 149 _PR_MD_SET_PRIORITY(&(thread->md), priority); 150 } 151 152 /* Activate the thread */ 153 if (ResumeThread(thread->md.handle) != -1) { 154 return PR_SUCCESS; 155 } 156 157 return PR_FAILURE; 158 } 159 160 void _PR_MD_YIELD(void) { 161 /* Can NT really yield at all? */ 162 Sleep(0); 163 } 164 165 void _PR_MD_SET_PRIORITY(_MDThread* thread, PRThreadPriority newPri) { 166 int nativePri; 167 BOOL rv; 168 169 if (newPri < PR_PRIORITY_FIRST) { 170 newPri = PR_PRIORITY_FIRST; 171 } else if (newPri > PR_PRIORITY_LAST) { 172 newPri = PR_PRIORITY_LAST; 173 } 174 switch (newPri) { 175 case PR_PRIORITY_LOW: 176 nativePri = THREAD_PRIORITY_BELOW_NORMAL; 177 break; 178 case PR_PRIORITY_NORMAL: 179 nativePri = THREAD_PRIORITY_NORMAL; 180 break; 181 case PR_PRIORITY_HIGH: 182 nativePri = THREAD_PRIORITY_ABOVE_NORMAL; 183 break; 184 case PR_PRIORITY_URGENT: 185 nativePri = THREAD_PRIORITY_HIGHEST; 186 } 187 rv = SetThreadPriority(thread->handle, nativePri); 188 PR_ASSERT(rv); 189 if (!rv) { 190 PR_LOG(_pr_thread_lm, PR_LOG_MIN, 191 ("PR_SetThreadPriority: can't set thread priority\n")); 192 } 193 return; 194 } 195 196 const DWORD MS_VC_EXCEPTION = 0x406D1388; 197 198 #pragma pack(push, 8) 199 typedef struct tagTHREADNAME_INFO { 200 DWORD dwType; // Must be 0x1000. 201 LPCSTR szName; // Pointer to name (in user addr space). 202 DWORD dwThreadID; // Thread ID (-1=caller thread). 203 DWORD dwFlags; // Reserved for future use, must be zero. 204 } THREADNAME_INFO; 205 #pragma pack(pop) 206 207 void _PR_MD_SET_CURRENT_THREAD_NAME(const char* name) { 208 #ifdef _MSC_VER 209 THREADNAME_INFO info; 210 #endif 211 212 if (sSetThreadDescription) { 213 WCHAR wideName[MAX_PATH]; 214 if (MultiByteToWideChar(CP_ACP, 0, name, -1, wideName, MAX_PATH)) { 215 sSetThreadDescription(GetCurrentThread(), wideName); 216 } 217 } 218 219 #ifdef _MSC_VER 220 if (!IsDebuggerPresent()) { 221 return; 222 } 223 224 info.dwType = 0x1000; 225 info.szName = (char*)name; 226 info.dwThreadID = -1; 227 info.dwFlags = 0; 228 229 __try { 230 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), 231 (ULONG_PTR*)&info); 232 } __except (EXCEPTION_CONTINUE_EXECUTION) { 233 } 234 #endif 235 } 236 237 void _PR_MD_CLEAN_THREAD(PRThread* thread) { 238 BOOL rv; 239 240 if (thread->md.blocked_sema) { 241 rv = CloseHandle(thread->md.blocked_sema); 242 PR_ASSERT(rv); 243 thread->md.blocked_sema = 0; 244 } 245 246 if (thread->md.handle) { 247 rv = CloseHandle(thread->md.handle); 248 PR_ASSERT(rv); 249 thread->md.handle = 0; 250 } 251 } 252 253 void _PR_MD_EXIT_THREAD(PRThread* thread) { 254 _PR_MD_CLEAN_THREAD(thread); 255 _PR_MD_SET_CURRENT_THREAD(NULL); 256 } 257 258 void _PR_MD_EXIT(PRIntn status) { _exit(status); } 259 260 PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread* thread, PRUint32 mask) { 261 #ifdef WINCE 262 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 263 return -1; 264 #else 265 DWORD_PTR rv; 266 267 rv = SetThreadAffinityMask(thread->md.handle, mask); 268 269 return rv ? 0 : -1; 270 #endif 271 } 272 273 PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread* thread, PRUint32* mask) { 274 #ifdef WINCE 275 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 276 return -1; 277 #else 278 BOOL rv; 279 DWORD_PTR process_mask; 280 DWORD_PTR system_mask; 281 282 rv = GetProcessAffinityMask(GetCurrentProcess(), &process_mask, &system_mask); 283 if (rv) { 284 *mask = (PRUint32)process_mask; 285 } 286 287 return rv ? 0 : -1; 288 #endif 289 } 290 291 void _PR_MD_SUSPEND_CPU(_PRCPU* cpu) { _PR_MD_SUSPEND_THREAD(cpu->thread); } 292 293 void _PR_MD_RESUME_CPU(_PRCPU* cpu) { _PR_MD_RESUME_THREAD(cpu->thread); } 294 295 void _PR_MD_SUSPEND_THREAD(PRThread* thread) { 296 if (_PR_IS_NATIVE_THREAD(thread)) { 297 DWORD previousSuspendCount; 298 /* XXXMB - SuspendThread() is not a blocking call; how do we 299 * know when the thread is *REALLY* suspended? 300 */ 301 previousSuspendCount = SuspendThread(thread->md.handle); 302 PR_ASSERT(previousSuspendCount == 0); 303 } 304 } 305 306 void _PR_MD_RESUME_THREAD(PRThread* thread) { 307 if (_PR_IS_NATIVE_THREAD(thread)) { 308 DWORD previousSuspendCount; 309 previousSuspendCount = ResumeThread(thread->md.handle); 310 PR_ASSERT(previousSuspendCount == 1); 311 } 312 } 313 314 PRThread* _MD_CURRENT_THREAD(void) { 315 PRThread* thread; 316 317 thread = _MD_GET_ATTACHED_THREAD(); 318 319 if (NULL == thread) { 320 thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); 321 } 322 PR_ASSERT(thread != NULL); 323 return thread; 324 }