~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/frontends/wgl/stw_tls.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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