1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2009-2013 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <windows.h> 29bf215546Sopenharmony_ci#include <tlhelp32.h> 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "pipe/p_compiler.h" 32bf215546Sopenharmony_ci#include "util/u_debug.h" 33bf215546Sopenharmony_ci#include "stw_tls.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cistatic DWORD tlsIndex = TLS_OUT_OF_INDEXES; 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci/** 39bf215546Sopenharmony_ci * Static mutex to protect the access to g_pendingTlsData global and 40bf215546Sopenharmony_ci * stw_tls_data::next member. 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_cistatic CRITICAL_SECTION g_mutex = { 43bf215546Sopenharmony_ci (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0 44bf215546Sopenharmony_ci}; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci/** 47bf215546Sopenharmony_ci * There is no way to invoke TlsSetValue for a different thread, so we 48bf215546Sopenharmony_ci * temporarily put the thread data for non-current threads here. 49bf215546Sopenharmony_ci */ 50bf215546Sopenharmony_cistatic struct stw_tls_data *g_pendingTlsData = NULL; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_cistatic struct stw_tls_data * 54bf215546Sopenharmony_cistw_tls_data_create(DWORD dwThreadId); 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_cistatic struct stw_tls_data * 57bf215546Sopenharmony_cistw_tls_lookup_pending_data(DWORD dwThreadId); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ciboolean 61bf215546Sopenharmony_cistw_tls_init(void) 62bf215546Sopenharmony_ci{ 63bf215546Sopenharmony_ci tlsIndex = TlsAlloc(); 64bf215546Sopenharmony_ci if (tlsIndex == TLS_OUT_OF_INDEXES) { 65bf215546Sopenharmony_ci return FALSE; 66bf215546Sopenharmony_ci } 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci /* 69bf215546Sopenharmony_ci * DllMain is called with DLL_THREAD_ATTACH only for threads created after 70bf215546Sopenharmony_ci * the DLL is loaded by the process. So enumerate and add our hook to all 71bf215546Sopenharmony_ci * previously existing threads. 72bf215546Sopenharmony_ci * 73bf215546Sopenharmony_ci * XXX: Except for the current thread since it there is an explicit 74bf215546Sopenharmony_ci * stw_tls_init_thread() call for it later on. 75bf215546Sopenharmony_ci */ 76bf215546Sopenharmony_ci if (1) { 77bf215546Sopenharmony_ci DWORD dwCurrentProcessId = GetCurrentProcessId(); 78bf215546Sopenharmony_ci DWORD dwCurrentThreadId = GetCurrentThreadId(); 79bf215546Sopenharmony_ci HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwCurrentProcessId); 80bf215546Sopenharmony_ci if (hSnapshot != INVALID_HANDLE_VALUE) { 81bf215546Sopenharmony_ci THREADENTRY32 te; 82bf215546Sopenharmony_ci te.dwSize = sizeof te; 83bf215546Sopenharmony_ci if (Thread32First(hSnapshot, &te)) { 84bf215546Sopenharmony_ci do { 85bf215546Sopenharmony_ci if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + 86bf215546Sopenharmony_ci sizeof te.th32OwnerProcessID) { 87bf215546Sopenharmony_ci if (te.th32OwnerProcessID == dwCurrentProcessId) { 88bf215546Sopenharmony_ci if (te.th32ThreadID != dwCurrentThreadId) { 89bf215546Sopenharmony_ci struct stw_tls_data *data; 90bf215546Sopenharmony_ci data = stw_tls_data_create(te.th32ThreadID); 91bf215546Sopenharmony_ci if (data) { 92bf215546Sopenharmony_ci EnterCriticalSection(&g_mutex); 93bf215546Sopenharmony_ci data->next = g_pendingTlsData; 94bf215546Sopenharmony_ci g_pendingTlsData = data; 95bf215546Sopenharmony_ci LeaveCriticalSection(&g_mutex); 96bf215546Sopenharmony_ci } 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci te.dwSize = sizeof te; 101bf215546Sopenharmony_ci } while (Thread32Next(hSnapshot, &te)); 102bf215546Sopenharmony_ci } 103bf215546Sopenharmony_ci CloseHandle(hSnapshot); 104bf215546Sopenharmony_ci } 105bf215546Sopenharmony_ci } 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci return TRUE; 108bf215546Sopenharmony_ci} 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci/** 112bf215546Sopenharmony_ci * Install windows hook for a given thread (not necessarily the current one). 113bf215546Sopenharmony_ci */ 114bf215546Sopenharmony_cistatic struct stw_tls_data * 115bf215546Sopenharmony_cistw_tls_data_create(DWORD dwThreadId) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci struct stw_tls_data *data; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci if (0) { 120bf215546Sopenharmony_ci debug_printf("%s(0x%04lx)\n", __FUNCTION__, dwThreadId); 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci data = calloc(1, sizeof *data); 124bf215546Sopenharmony_ci if (!data) { 125bf215546Sopenharmony_ci goto no_data; 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci data->dwThreadId = dwThreadId; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, 131bf215546Sopenharmony_ci stw_call_window_proc, 132bf215546Sopenharmony_ci NULL, 133bf215546Sopenharmony_ci dwThreadId); 134bf215546Sopenharmony_ci if (data->hCallWndProcHook == NULL) { 135bf215546Sopenharmony_ci goto no_hook; 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci return data; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_cino_hook: 141bf215546Sopenharmony_ci free(data); 142bf215546Sopenharmony_cino_data: 143bf215546Sopenharmony_ci return NULL; 144bf215546Sopenharmony_ci} 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci/** 147bf215546Sopenharmony_ci * Destroy the per-thread data/hook. 148bf215546Sopenharmony_ci * 149bf215546Sopenharmony_ci * It is important to remove all hooks when unloading our DLL, otherwise our 150bf215546Sopenharmony_ci * hook function might be called after it is no longer there. 151bf215546Sopenharmony_ci */ 152bf215546Sopenharmony_cistatic void 153bf215546Sopenharmony_cistw_tls_data_destroy(struct stw_tls_data *data) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci assert(data); 156bf215546Sopenharmony_ci if (!data) { 157bf215546Sopenharmony_ci return; 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci if (0) { 161bf215546Sopenharmony_ci debug_printf("%s(0x%04lx)\n", __FUNCTION__, data->dwThreadId); 162bf215546Sopenharmony_ci } 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci if (data->hCallWndProcHook) { 165bf215546Sopenharmony_ci UnhookWindowsHookEx(data->hCallWndProcHook); 166bf215546Sopenharmony_ci data->hCallWndProcHook = NULL; 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci free(data); 170bf215546Sopenharmony_ci} 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ciboolean 173bf215546Sopenharmony_cistw_tls_init_thread(void) 174bf215546Sopenharmony_ci{ 175bf215546Sopenharmony_ci struct stw_tls_data *data; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci if (tlsIndex == TLS_OUT_OF_INDEXES) { 178bf215546Sopenharmony_ci return FALSE; 179bf215546Sopenharmony_ci } 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci data = stw_tls_data_create(GetCurrentThreadId()); 182bf215546Sopenharmony_ci if (!data) { 183bf215546Sopenharmony_ci return FALSE; 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci TlsSetValue(tlsIndex, data); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci return TRUE; 189bf215546Sopenharmony_ci} 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_civoid 192bf215546Sopenharmony_cistw_tls_cleanup_thread(void) 193bf215546Sopenharmony_ci{ 194bf215546Sopenharmony_ci struct stw_tls_data *data; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (tlsIndex == TLS_OUT_OF_INDEXES) { 197bf215546Sopenharmony_ci return; 198bf215546Sopenharmony_ci } 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci data = (struct stw_tls_data *) TlsGetValue(tlsIndex); 201bf215546Sopenharmony_ci if (data) { 202bf215546Sopenharmony_ci TlsSetValue(tlsIndex, NULL); 203bf215546Sopenharmony_ci } else { 204bf215546Sopenharmony_ci /* See if there this thread's data in on the pending list */ 205bf215546Sopenharmony_ci data = stw_tls_lookup_pending_data(GetCurrentThreadId()); 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci if (data) { 209bf215546Sopenharmony_ci stw_tls_data_destroy(data); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_civoid 214bf215546Sopenharmony_cistw_tls_cleanup(void) 215bf215546Sopenharmony_ci{ 216bf215546Sopenharmony_ci if (tlsIndex != TLS_OUT_OF_INDEXES) { 217bf215546Sopenharmony_ci /* 218bf215546Sopenharmony_ci * Destroy all items in g_pendingTlsData linked list. 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_ci EnterCriticalSection(&g_mutex); 221bf215546Sopenharmony_ci while (g_pendingTlsData) { 222bf215546Sopenharmony_ci struct stw_tls_data * data = g_pendingTlsData; 223bf215546Sopenharmony_ci g_pendingTlsData = data->next; 224bf215546Sopenharmony_ci stw_tls_data_destroy(data); 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci LeaveCriticalSection(&g_mutex); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci TlsFree(tlsIndex); 229bf215546Sopenharmony_ci tlsIndex = TLS_OUT_OF_INDEXES; 230bf215546Sopenharmony_ci } 231bf215546Sopenharmony_ci} 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci/* 234bf215546Sopenharmony_ci * Search for the current thread in the g_pendingTlsData linked list. 235bf215546Sopenharmony_ci * 236bf215546Sopenharmony_ci * It will remove and return the node on success, or return NULL on failure. 237bf215546Sopenharmony_ci */ 238bf215546Sopenharmony_cistatic struct stw_tls_data * 239bf215546Sopenharmony_cistw_tls_lookup_pending_data(DWORD dwThreadId) 240bf215546Sopenharmony_ci{ 241bf215546Sopenharmony_ci struct stw_tls_data ** p_data; 242bf215546Sopenharmony_ci struct stw_tls_data *data = NULL; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci EnterCriticalSection(&g_mutex); 245bf215546Sopenharmony_ci for (p_data = &g_pendingTlsData; *p_data; p_data = &(*p_data)->next) { 246bf215546Sopenharmony_ci if ((*p_data)->dwThreadId == dwThreadId) { 247bf215546Sopenharmony_ci data = *p_data; 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci /* 250bf215546Sopenharmony_ci * Unlink the node. 251bf215546Sopenharmony_ci */ 252bf215546Sopenharmony_ci *p_data = data->next; 253bf215546Sopenharmony_ci data->next = NULL; 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci break; 256bf215546Sopenharmony_ci } 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci LeaveCriticalSection(&g_mutex); 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci return data; 261bf215546Sopenharmony_ci} 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_cistruct stw_tls_data * 264bf215546Sopenharmony_cistw_tls_get_data(void) 265bf215546Sopenharmony_ci{ 266bf215546Sopenharmony_ci struct stw_tls_data *data; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci if (tlsIndex == TLS_OUT_OF_INDEXES) { 269bf215546Sopenharmony_ci return NULL; 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci data = (struct stw_tls_data *) TlsGetValue(tlsIndex); 273bf215546Sopenharmony_ci if (!data) { 274bf215546Sopenharmony_ci DWORD dwCurrentThreadId = GetCurrentThreadId(); 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci /* 277bf215546Sopenharmony_ci * Search for the current thread in the g_pendingTlsData linked list. 278bf215546Sopenharmony_ci */ 279bf215546Sopenharmony_ci data = stw_tls_lookup_pending_data(dwCurrentThreadId); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci if (!data) { 282bf215546Sopenharmony_ci /* 283bf215546Sopenharmony_ci * This should be impossible now. 284bf215546Sopenharmony_ci */ 285bf215546Sopenharmony_ci assert(!"Failed to find thread data for thread id"); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci /* 288bf215546Sopenharmony_ci * DllMain is called with DLL_THREAD_ATTACH only by threads created 289bf215546Sopenharmony_ci * after the DLL is loaded by the process 290bf215546Sopenharmony_ci */ 291bf215546Sopenharmony_ci data = stw_tls_data_create(dwCurrentThreadId); 292bf215546Sopenharmony_ci if (!data) { 293bf215546Sopenharmony_ci return NULL; 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci } 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci TlsSetValue(tlsIndex, data); 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci assert(data); 301bf215546Sopenharmony_ci assert(data->dwThreadId = GetCurrentThreadId()); 302bf215546Sopenharmony_ci assert(data->next == NULL); 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci return data; 305bf215546Sopenharmony_ci} 306