Path: blob/21.2-virgl/src/gallium/frontends/wgl/stw_tls.c
4561 views
/**************************************************************************1*2* Copyright 2009-2013 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include <windows.h>28#include <tlhelp32.h>2930#include "pipe/p_compiler.h"31#include "util/u_debug.h"32#include "stw_tls.h"3334static DWORD tlsIndex = TLS_OUT_OF_INDEXES;353637/**38* Static mutex to protect the access to g_pendingTlsData global and39* stw_tls_data::next member.40*/41static CRITICAL_SECTION g_mutex = {42(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 043};4445/**46* There is no way to invoke TlsSetValue for a different thread, so we47* temporarily put the thread data for non-current threads here.48*/49static struct stw_tls_data *g_pendingTlsData = NULL;505152static struct stw_tls_data *53stw_tls_data_create(DWORD dwThreadId);5455static struct stw_tls_data *56stw_tls_lookup_pending_data(DWORD dwThreadId);575859boolean60stw_tls_init(void)61{62tlsIndex = TlsAlloc();63if (tlsIndex == TLS_OUT_OF_INDEXES) {64return FALSE;65}6667/*68* DllMain is called with DLL_THREAD_ATTACH only for threads created after69* the DLL is loaded by the process. So enumerate and add our hook to all70* previously existing threads.71*72* XXX: Except for the current thread since it there is an explicit73* stw_tls_init_thread() call for it later on.74*/75if (1) {76DWORD dwCurrentProcessId = GetCurrentProcessId();77DWORD dwCurrentThreadId = GetCurrentThreadId();78HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwCurrentProcessId);79if (hSnapshot != INVALID_HANDLE_VALUE) {80THREADENTRY32 te;81te.dwSize = sizeof te;82if (Thread32First(hSnapshot, &te)) {83do {84if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) +85sizeof te.th32OwnerProcessID) {86if (te.th32OwnerProcessID == dwCurrentProcessId) {87if (te.th32ThreadID != dwCurrentThreadId) {88struct stw_tls_data *data;89data = stw_tls_data_create(te.th32ThreadID);90if (data) {91EnterCriticalSection(&g_mutex);92data->next = g_pendingTlsData;93g_pendingTlsData = data;94LeaveCriticalSection(&g_mutex);95}96}97}98}99te.dwSize = sizeof te;100} while (Thread32Next(hSnapshot, &te));101}102CloseHandle(hSnapshot);103}104}105106return TRUE;107}108109110/**111* Install windows hook for a given thread (not necessarily the current one).112*/113static struct stw_tls_data *114stw_tls_data_create(DWORD dwThreadId)115{116struct stw_tls_data *data;117118if (0) {119debug_printf("%s(0x%04lx)\n", __FUNCTION__, dwThreadId);120}121122data = calloc(1, sizeof *data);123if (!data) {124goto no_data;125}126127data->dwThreadId = dwThreadId;128129data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,130stw_call_window_proc,131NULL,132dwThreadId);133if (data->hCallWndProcHook == NULL) {134goto no_hook;135}136137return data;138139no_hook:140free(data);141no_data:142return NULL;143}144145/**146* Destroy the per-thread data/hook.147*148* It is important to remove all hooks when unloading our DLL, otherwise our149* hook function might be called after it is no longer there.150*/151static void152stw_tls_data_destroy(struct stw_tls_data *data)153{154assert(data);155if (!data) {156return;157}158159if (0) {160debug_printf("%s(0x%04lx)\n", __FUNCTION__, data->dwThreadId);161}162163if (data->hCallWndProcHook) {164UnhookWindowsHookEx(data->hCallWndProcHook);165data->hCallWndProcHook = NULL;166}167168free(data);169}170171boolean172stw_tls_init_thread(void)173{174struct stw_tls_data *data;175176if (tlsIndex == TLS_OUT_OF_INDEXES) {177return FALSE;178}179180data = stw_tls_data_create(GetCurrentThreadId());181if (!data) {182return FALSE;183}184185TlsSetValue(tlsIndex, data);186187return TRUE;188}189190void191stw_tls_cleanup_thread(void)192{193struct stw_tls_data *data;194195if (tlsIndex == TLS_OUT_OF_INDEXES) {196return;197}198199data = (struct stw_tls_data *) TlsGetValue(tlsIndex);200if (data) {201TlsSetValue(tlsIndex, NULL);202} else {203/* See if there this thread's data in on the pending list */204data = stw_tls_lookup_pending_data(GetCurrentThreadId());205}206207if (data) {208stw_tls_data_destroy(data);209}210}211212void213stw_tls_cleanup(void)214{215if (tlsIndex != TLS_OUT_OF_INDEXES) {216/*217* Destroy all items in g_pendingTlsData linked list.218*/219EnterCriticalSection(&g_mutex);220while (g_pendingTlsData) {221struct stw_tls_data * data = g_pendingTlsData;222g_pendingTlsData = data->next;223stw_tls_data_destroy(data);224}225LeaveCriticalSection(&g_mutex);226227TlsFree(tlsIndex);228tlsIndex = TLS_OUT_OF_INDEXES;229}230}231232/*233* Search for the current thread in the g_pendingTlsData linked list.234*235* It will remove and return the node on success, or return NULL on failure.236*/237static struct stw_tls_data *238stw_tls_lookup_pending_data(DWORD dwThreadId)239{240struct stw_tls_data ** p_data;241struct stw_tls_data *data = NULL;242243EnterCriticalSection(&g_mutex);244for (p_data = &g_pendingTlsData; *p_data; p_data = &(*p_data)->next) {245if ((*p_data)->dwThreadId == dwThreadId) {246data = *p_data;247248/*249* Unlink the node.250*/251*p_data = data->next;252data->next = NULL;253254break;255}256}257LeaveCriticalSection(&g_mutex);258259return data;260}261262struct stw_tls_data *263stw_tls_get_data(void)264{265struct stw_tls_data *data;266267if (tlsIndex == TLS_OUT_OF_INDEXES) {268return NULL;269}270271data = (struct stw_tls_data *) TlsGetValue(tlsIndex);272if (!data) {273DWORD dwCurrentThreadId = GetCurrentThreadId();274275/*276* Search for the current thread in the g_pendingTlsData linked list.277*/278data = stw_tls_lookup_pending_data(dwCurrentThreadId);279280if (!data) {281/*282* This should be impossible now.283*/284assert(!"Failed to find thread data for thread id");285286/*287* DllMain is called with DLL_THREAD_ATTACH only by threads created288* after the DLL is loaded by the process289*/290data = stw_tls_data_create(dwCurrentThreadId);291if (!data) {292return NULL;293}294}295296TlsSetValue(tlsIndex, data);297}298299assert(data);300assert(data->dwThreadId = GetCurrentThreadId());301assert(data->next == NULL);302303return data;304}305306307