VirtualBox

source: vbox/trunk/src/VBox/Additions/common/crOpenGL/load.c@ 79120

Last change on this file since 79120 was 78816, checked in by vboxsync, 6 years ago

Additions/crOpenGL/load.c: Don't hang on exit if stubSPUSafeTearDown() is called on the sync thread due to an X11 error for example

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 37.0 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_spu.h"
8#include "cr_net.h"
9#include "cr_error.h"
10#include "cr_mem.h"
11#include "cr_string.h"
12#include "cr_net.h"
13#include "cr_process.h"
14#include "cr_netserver.h"
15#include "stub.h"
16#include <stdlib.h>
17#include <string.h>
18#include <signal.h>
19#include <stdio.h> /*swprintf*/
20#include <iprt/initterm.h>
21#include <iprt/thread.h>
22#include <iprt/errcore.h>
23#include <iprt/asm.h>
24#include <iprt/env.h>
25#ifndef WINDOWS
26# include <sys/types.h>
27# include <unistd.h>
28#endif
29
30#include "VBox/VBoxGuestLib.h"
31
32#ifdef VBOX_WITH_WDDM
33#include <d3d9types.h>
34#include <D3dumddi.h>
35#endif
36
37#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
38# include <VBoxCrHgsmi.h>
39#endif
40
41/**
42 * If you change this, see the comments in tilesortspu_context.c
43 */
44#define MAGIC_CONTEXT_BASE 500
45
46#define CONFIG_LOOKUP_FILE ".crconfigs"
47
48#ifdef WINDOWS
49#define PYTHON_EXE "python.exe"
50#else
51#define PYTHON_EXE "python"
52#endif
53
54static bool stub_initialized = 0;
55#ifdef WINDOWS
56static CRmutex stub_init_mutex;
57#define STUB_INIT_LOCK() do { crLockMutex(&stub_init_mutex); } while (0)
58#define STUB_INIT_UNLOCK() do { crUnlockMutex(&stub_init_mutex); } while (0)
59#else
60#define STUB_INIT_LOCK() do { } while (0)
61#define STUB_INIT_UNLOCK() do { } while (0)
62#endif
63
64/* NOTE: 'SPUDispatchTable glim' is declared in NULLfuncs.py now */
65/* NOTE: 'SPUDispatchTable stubThreadsafeDispatch' is declared in tsfuncs.c */
66Stub stub;
67static bool g_stubIsCurrentContextTSDInited;
68CRtsd g_stubCurrentContextTSD;
69
70#ifndef VBOX_NO_NATIVEGL
71static void stubInitNativeDispatch( void )
72{
73# define MAX_FUNCS 1000
74 SPUNamedFunctionTable gl_funcs[MAX_FUNCS];
75 int numFuncs;
76
77 numFuncs = crLoadOpenGL( &stub.wsInterface, gl_funcs );
78
79 stub.haveNativeOpenGL = (numFuncs > 0);
80
81 /* XXX call this after context binding */
82 numFuncs += crLoadOpenGLExtensions( &stub.wsInterface, gl_funcs + numFuncs );
83
84 CRASSERT(numFuncs < MAX_FUNCS);
85
86 crSPUInitDispatchTable( &stub.nativeDispatch );
87 crSPUInitDispatch( &stub.nativeDispatch, gl_funcs );
88 crSPUInitDispatchNops( &stub.nativeDispatch );
89# undef MAX_FUNCS
90}
91#endif /* !VBOX_NO_NATIVEGL */
92
93
94/** Pointer to the SPU's real glClear and glViewport functions */
95static ClearFunc_t origClear;
96static ViewportFunc_t origViewport;
97static SwapBuffersFunc_t origSwapBuffers;
98static DrawBufferFunc_t origDrawBuffer;
99static ScissorFunc_t origScissor;
100
101static void stubCheckWindowState(WindowInfo *window, GLboolean bFlushOnChange)
102{
103 bool bForceUpdate = false;
104 bool bChanged = false;
105
106#ifdef WINDOWS
107 /** @todo install hook and track for WM_DISPLAYCHANGE */
108 {
109 DEVMODE devMode;
110
111 devMode.dmSize = sizeof(DEVMODE);
112 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
113
114 if (devMode.dmPelsWidth!=window->dmPelsWidth || devMode.dmPelsHeight!=window->dmPelsHeight)
115 {
116 crDebug("Resolution changed(%d,%d), forcing window Pos/Size update", devMode.dmPelsWidth, devMode.dmPelsHeight);
117 window->dmPelsWidth = devMode.dmPelsWidth;
118 window->dmPelsHeight = devMode.dmPelsHeight;
119 bForceUpdate = true;
120 }
121 }
122#endif
123
124 bChanged = stubUpdateWindowGeometry(window, bForceUpdate) || bForceUpdate;
125
126#if defined(GLX) || defined (WINDOWS)
127 if (stub.trackWindowVisibleRgn)
128 {
129 bChanged = stubUpdateWindowVisibileRegions(window) || bChanged;
130 }
131#endif
132
133 if (stub.trackWindowVisibility && window->type == CHROMIUM && window->drawable) {
134 const int mapped = stubIsWindowVisible(window);
135 if (mapped != window->mapped) {
136 crDebug("Dispatched: WindowShow(%i, %i)", window->spuWindow, mapped);
137 stub.spu->dispatch_table.WindowShow(window->spuWindow, mapped);
138 window->mapped = mapped;
139 bChanged = true;
140 }
141 }
142
143 if (bFlushOnChange && bChanged)
144 {
145 stub.spu->dispatch_table.Flush();
146 }
147}
148
149static bool stubSystemWindowExist(WindowInfo *pWindow)
150{
151#ifdef WINDOWS
152 if (pWindow->hWnd!=WindowFromDC(pWindow->drawable))
153 {
154 return false;
155 }
156#else
157 Window root;
158 int x, y;
159 unsigned int border, depth, w, h;
160 Display *dpy;
161
162 dpy = stubGetWindowDisplay(pWindow);
163
164 XLOCK(dpy);
165 if (!XGetGeometry(dpy, pWindow->drawable, &root, &x, &y, &w, &h, &border, &depth))
166 {
167 XUNLOCK(dpy);
168 return false;
169 }
170 XUNLOCK(dpy);
171#endif
172
173 return true;
174}
175
176static void stubCheckWindowsCB(unsigned long key, void *data1, void *data2)
177{
178 WindowInfo *pWindow = (WindowInfo *) data1;
179 ContextInfo *pCtx = (ContextInfo *) data2;
180 (void)key;
181
182 if (pWindow == pCtx->currentDrawable
183 || pWindow->type!=CHROMIUM
184 || pWindow->pOwner!=pCtx)
185 {
186 return;
187 }
188
189 if (!stubSystemWindowExist(pWindow))
190 {
191#ifdef WINDOWS
192 stubDestroyWindow(CR_CTX_CON(pCtx), (GLint)pWindow->hWnd);
193#else
194 stubDestroyWindow(CR_CTX_CON(pCtx), (GLint)pWindow->drawable);
195#endif
196 return;
197 }
198
199 stubCheckWindowState(pWindow, GL_FALSE);
200}
201
202static void stubCheckWindowsState(void)
203{
204 ContextInfo *context = stubGetCurrentContext();
205
206 CRASSERT(stub.trackWindowSize || stub.trackWindowPos);
207
208 if (!context)
209 return;
210
211#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
212 if (stub.bRunningUnderWDDM)
213 return;
214#endif
215
216 /* Try to keep a consistent locking order. */
217 crHashtableLock(stub.windowTable);
218#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
219 crLockMutex(&stub.mutex);
220#endif
221
222 stubCheckWindowState(context->currentDrawable, GL_TRUE);
223 crHashtableWalkUnlocked(stub.windowTable, stubCheckWindowsCB, context);
224
225#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
226 crUnlockMutex(&stub.mutex);
227#endif
228 crHashtableUnlock(stub.windowTable);
229}
230
231
232/**
233 * Override the head SPU's glClear function.
234 * We're basically trapping this function so that we can poll the
235 * application window size at a regular interval.
236 */
237static void SPU_APIENTRY trapClear(GLbitfield mask)
238{
239 stubCheckWindowsState();
240 /* call the original SPU glClear function */
241 origClear(mask);
242}
243
244/**
245 * As above, but for glViewport. Most apps call glViewport before
246 * glClear when a window is resized.
247 */
248static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
249{
250 stubCheckWindowsState();
251 /* call the original SPU glViewport function */
252 origViewport(x, y, w, h);
253}
254
255/*static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
256{
257 stubCheckWindowsState();
258 origSwapBuffers(window, flags);
259}
260
261static void SPU_APIENTRY trapDrawBuffer(GLenum buf)
262{
263 stubCheckWindowsState();
264 origDrawBuffer(buf);
265}*/
266
267#if 0 /* unused */
268static void SPU_APIENTRY trapScissor(GLint x, GLint y, GLsizei w, GLsizei h)
269{
270 int winX, winY;
271 unsigned int winW, winH;
272 WindowInfo *pWindow;
273 ContextInfo *context = stubGetCurrentContext();
274 (void)x; (void)y; (void)w; (void)h;
275
276 pWindow = context->currentDrawable;
277 stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
278 origScissor(0, 0, winW, winH);
279}
280#endif /* unused */
281
282/**
283 * Use the GL function pointers in \<spu\> to initialize the static glim
284 * dispatch table.
285 */
286static void stubInitSPUDispatch(SPU *spu)
287{
288 crSPUInitDispatchTable( &stub.spuDispatch );
289 crSPUCopyDispatchTable( &stub.spuDispatch, &(spu->dispatch_table) );
290
291 if (stub.trackWindowSize || stub.trackWindowPos || stub.trackWindowVisibleRgn) {
292 /* patch-in special glClear/Viewport function to track window sizing */
293 origClear = stub.spuDispatch.Clear;
294 origViewport = stub.spuDispatch.Viewport;
295 origSwapBuffers = stub.spuDispatch.SwapBuffers;
296 origDrawBuffer = stub.spuDispatch.DrawBuffer;
297 origScissor = stub.spuDispatch.Scissor;
298 stub.spuDispatch.Clear = trapClear;
299 stub.spuDispatch.Viewport = trapViewport;
300
301 /*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
302 stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
303 }
304
305 crSPUCopyDispatchTable( &glim, &stub.spuDispatch );
306}
307
308#if 0 /** @todo stubSPUTearDown & stubSPUTearDownLocked are not referenced */
309
310// Callback function, used to destroy all created contexts
311static void hsWalkStubDestroyContexts(unsigned long key, void *data1, void *data2)
312{
313 (void)data1; (void)data2;
314 stubDestroyContext(key);
315}
316
317/**
318 * This is called when we exit.
319 * We call all the SPU's cleanup functions.
320 */
321static void stubSPUTearDownLocked(void)
322{
323 crDebug("stubSPUTearDownLocked");
324
325#ifdef WINDOWS
326# ifndef CR_NEWWINTRACK
327 stubUninstallWindowMessageHook();
328# endif
329#endif
330
331#ifdef CR_NEWWINTRACK
332 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
333#endif
334
335 //delete all created contexts
336 stubMakeCurrent( NULL, NULL);
337
338 /* the lock order is windowTable->contextTable (see wglMakeCurrent_prox, glXMakeCurrent)
339 * this is why we need to take a windowTable lock since we will later do stub.windowTable access & locking */
340 crHashtableLock(stub.windowTable);
341 crHashtableWalk(stub.contextTable, hsWalkStubDestroyContexts, NULL);
342 crHashtableUnlock(stub.windowTable);
343
344 /* shutdown, now trap any calls to a NULL dispatcher */
345 crSPUCopyDispatchTable(&glim, &stubNULLDispatch);
346
347 crSPUUnloadChain(stub.spu);
348 stub.spu = NULL;
349
350#ifndef Linux
351 crUnloadOpenGL();
352#endif
353
354#ifndef WINDOWS
355 crNetTearDown();
356#endif
357
358#ifdef GLX
359 if (stub.xshmSI.shmid>=0)
360 {
361 shmctl(stub.xshmSI.shmid, IPC_RMID, 0);
362 shmdt(stub.xshmSI.shmaddr);
363 }
364 crFreeHashtable(stub.pGLXPixmapsHash, crFree);
365#endif
366
367 crFreeHashtable(stub.windowTable, crFree);
368 crFreeHashtable(stub.contextTable, NULL);
369
370 crMemset(&stub, 0, sizeof(stub));
371
372}
373
374/**
375 * This is called when we exit.
376 * We call all the SPU's cleanup functions.
377 */
378static void stubSPUTearDown(void)
379{
380 STUB_INIT_LOCK();
381 if (stub_initialized)
382 {
383 stubSPUTearDownLocked();
384 stub_initialized = 0;
385 }
386 STUB_INIT_UNLOCK();
387}
388
389#endif /** @todo stubSPUTearDown & stubSPUTearDownLocked are not referenced */
390
391static void stubSPUSafeTearDown(void)
392{
393 CRmutex *mutex;
394
395 if (!stub_initialized) return;
396 stub_initialized = 0;
397
398 mutex = &stub.mutex;
399 crLockMutex(mutex);
400 crDebug("stubSPUSafeTearDown");
401
402#ifdef WINDOWS
403# ifndef CR_NEWWINTRACK
404 stubUninstallWindowMessageHook();
405# endif
406#endif
407
408#if defined(CR_NEWWINTRACK)
409 crUnlockMutex(mutex);
410# if defined(WINDOWS)
411 if (stub.hSyncThread && RTThreadGetState(stub.hSyncThread)!=RTTHREADSTATE_TERMINATED)
412 {
413 HANDLE hNative;
414 DWORD ec=0;
415
416 hNative = OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION|THREAD_TERMINATE,
417 false, RTThreadGetNative(stub.hSyncThread));
418 if (!hNative)
419 {
420 crWarning("Failed to get handle for sync thread(%#x)", GetLastError());
421 }
422 else
423 {
424 crDebug("Got handle %p for thread %#x", hNative, RTThreadGetNative(stub.hSyncThread));
425 }
426
427 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
428
429 if (PostThreadMessage(RTThreadGetNative(stub.hSyncThread), WM_QUIT, 0, 0))
430 {
431 RTThreadWait(stub.hSyncThread, 1000, NULL);
432
433 /*Same issue as on linux, RTThreadWait exits before system thread is terminated, which leads
434 * to issues as our dll goes to be unloaded.
435 *@todo
436 *We usually call this function from DllMain which seems to be holding some lock and thus we have to
437 * kill thread via TerminateThread.
438 */
439 if (WaitForSingleObject(hNative, 100)==WAIT_TIMEOUT)
440 {
441 crDebug("Wait failed, terminating");
442 if (!TerminateThread(hNative, 1))
443 {
444 crDebug("TerminateThread failed");
445 }
446 }
447 if (GetExitCodeThread(hNative, &ec))
448 {
449 crDebug("Thread %p exited with ec=%i", hNative, ec);
450 }
451 else
452 {
453 crDebug("GetExitCodeThread failed(%#x)", GetLastError());
454 }
455 }
456 else
457 {
458 crDebug("Sync thread killed before DLL_PROCESS_DETACH");
459 }
460
461 if (hNative)
462 {
463 CloseHandle(hNative);
464 }
465 }
466#else
467 if (stub.hSyncThread!=NIL_RTTHREAD)
468 {
469 ASMAtomicWriteBool(&stub.bShutdownSyncThread, true);
470 {
471 /* stubSPUSafeTearDown() can be called from the sync thread in case
472 * of an X11 error:
473 * XGetGeometry() -> [...] -> _XError() -> exit() -> [...] -> stubExitHandler() -> stubSPUSafetearDown())
474 * Don't hang in that case.
475 */
476 RTTHREAD hSelf = RTThreadSelf();
477 if (hSelf != stub.hSyncThread)
478 {
479 int rc = RTThreadWait(stub.hSyncThread, RT_INDEFINITE_WAIT, NULL);
480 if (RT_FAILURE(rc))
481 WARN(("RTThreadWait_join failed %i", rc));
482 }
483 }
484 }
485#endif
486 crLockMutex(mutex);
487#endif
488
489#ifndef WINDOWS
490 crNetTearDown();
491#endif
492
493 crUnlockMutex(mutex);
494 crFreeMutex(mutex);
495 crMemset(&stub, 0, sizeof(stub));
496}
497
498
499static void stubExitHandler(void)
500{
501 stubSPUSafeTearDown();
502 signal(SIGTERM, SIG_DFL);
503 signal(SIGINT, SIG_DFL);
504}
505
506/**
507 * Called when we receive a SIGTERM signal.
508 */
509static void stubSignalHandler(int signo)
510{
511 (void)signo;
512 stubSPUSafeTearDown();
513 exit(0); /* this causes stubExitHandler() to be called */
514}
515
516#ifndef RT_OS_WINDOWS
517static void stubThreadTlsDtor(void *pvValue)
518{
519 ContextInfo *pCtx = (ContextInfo*)pvValue;
520 VBoxTlsRefRelease(pCtx);
521}
522#endif
523
524
525/**
526 * Init variables in the stub structure, install signal handler.
527 */
528static void stubInitVars(void)
529{
530 WindowInfo *defaultWin;
531
532 crInitMutex(&stub.mutex);
533
534 /* At the very least we want CR_RGB_BIT. */
535 stub.haveNativeOpenGL = GL_FALSE;
536 stub.spu = NULL;
537 stub.appDrawCursor = 0;
538 stub.minChromiumWindowWidth = 0;
539 stub.minChromiumWindowHeight = 0;
540 stub.maxChromiumWindowWidth = 0;
541 stub.maxChromiumWindowHeight = 0;
542 stub.matchChromiumWindowCount = 0;
543 stub.matchChromiumWindowID = NULL;
544 stub.matchWindowTitle = NULL;
545 stub.ignoreFreeglutMenus = 0;
546 stub.threadSafe = GL_FALSE;
547 stub.trackWindowSize = 0;
548 stub.trackWindowPos = 0;
549 stub.trackWindowVisibility = 0;
550 stub.trackWindowVisibleRgn = 0;
551 stub.mothershipPID = 0;
552 stub.spu_dir = NULL;
553
554 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
555 stub.contextTable = crAllocHashtable();
556#ifndef RT_OS_WINDOWS
557 if (!g_stubIsCurrentContextTSDInited)
558 {
559 crInitTSDF(&g_stubCurrentContextTSD, stubThreadTlsDtor);
560 g_stubIsCurrentContextTSDInited = true;
561 }
562#endif
563 stubSetCurrentContext(NULL);
564
565 stub.windowTable = crAllocHashtable();
566
567#ifdef CR_NEWWINTRACK
568 stub.bShutdownSyncThread = false;
569 stub.hSyncThread = NIL_RTTHREAD;
570#endif
571
572 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
573 defaultWin->type = CHROMIUM;
574 defaultWin->spuWindow = 0; /* window 0 always exists */
575#ifdef WINDOWS
576 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
577#elif defined(GLX)
578 defaultWin->pVisibleRegions = NULL;
579 defaultWin->cVisibleRegions = 0;
580#endif
581 crHashtableAdd(stub.windowTable, 0, defaultWin);
582
583#if 1
584 atexit(stubExitHandler);
585 signal(SIGTERM, stubSignalHandler);
586 signal(SIGINT, stubSignalHandler);
587#ifndef WINDOWS
588 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
589#endif
590#else
591 (void) stubExitHandler;
592 (void) stubSignalHandler;
593#endif
594}
595
596
597static void stubSetDefaultConfigurationOptions(void)
598{
599 stub.appDrawCursor = 0;
600 stub.minChromiumWindowWidth = 0;
601 stub.minChromiumWindowHeight = 0;
602 stub.maxChromiumWindowWidth = 0;
603 stub.maxChromiumWindowHeight = 0;
604 stub.matchChromiumWindowID = NULL;
605 stub.numIgnoreWindowID = 0;
606 stub.matchWindowTitle = NULL;
607 stub.ignoreFreeglutMenus = 0;
608 stub.trackWindowSize = 1;
609 stub.trackWindowPos = 1;
610 stub.trackWindowVisibility = 1;
611 stub.trackWindowVisibleRgn = 1;
612 stub.matchChromiumWindowCount = 0;
613 stub.spu_dir = NULL;
614 stub.force_pbuffers = 0;
615
616#ifdef WINDOWS
617# ifdef VBOX_WITH_WDDM
618 stub.bRunningUnderWDDM = false;
619# endif
620#endif
621}
622
623#ifdef CR_NEWWINTRACK
624# ifdef VBOX_WITH_WDDM
625static void stubDispatchVisibleRegions(WindowInfo *pWindow)
626{
627 DWORD dwCount;
628 LPRGNDATA lpRgnData;
629
630 dwCount = GetRegionData(pWindow->hVisibleRegion, 0, NULL);
631 lpRgnData = crAlloc(dwCount);
632
633 if (lpRgnData)
634 {
635 GetRegionData(pWindow->hVisibleRegion, dwCount, lpRgnData);
636 crDebug("Dispatched WindowVisibleRegion (%i, cRects=%i)", pWindow->spuWindow, lpRgnData->rdh.nCount);
637 stub.spuDispatch.WindowVisibleRegion(pWindow->spuWindow, lpRgnData->rdh.nCount, (GLint*) lpRgnData->Buffer);
638 crFree(lpRgnData);
639 }
640 else crWarning("GetRegionData failed, VisibleRegions update failed");
641}
642
643# endif /* VBOX_WITH_WDDM */
644
645static void stubSyncTrCheckWindowsCB(unsigned long key, void *data1, void *data2)
646{
647 WindowInfo *pWindow = (WindowInfo *) data1;
648 (void)key; (void) data2;
649
650 if (pWindow->type!=CHROMIUM || pWindow->spuWindow==0)
651 {
652 return;
653 }
654
655 stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
656
657 if (!stubSystemWindowExist(pWindow))
658 {
659#ifdef WINDOWS
660 stubDestroyWindow(0, (GLint)pWindow->hWnd);
661#else
662 stubDestroyWindow(0, (GLint)pWindow->drawable);
663#endif
664 /*No need to flush here as crWindowDestroy does it*/
665 return;
666 }
667
668#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
669 if (stub.bRunningUnderWDDM)
670 return;
671#endif
672 stubCheckWindowState(pWindow, GL_TRUE);
673}
674
675static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
676{
677#ifdef WINDOWS
678 MSG msg;
679# ifdef VBOX_WITH_WDDM
680 HMODULE hVBoxD3D = NULL;
681 GLint spuConnection = 0;
682# endif
683#endif
684
685 (void) pvUser;
686
687 crDebug("Sync thread started");
688#ifdef WINDOWS
689 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
690# ifdef VBOX_WITH_WDDM
691 hVBoxD3D = NULL;
692 if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
693 {
694 crDebug("GetModuleHandleEx failed err %d", GetLastError());
695 hVBoxD3D = NULL;
696 }
697
698 if (hVBoxD3D)
699 {
700 crDebug("running with " VBOX_MODNAME_DISPD3D);
701 stub.trackWindowVisibleRgn = 0;
702 stub.bRunningUnderWDDM = true;
703 }
704# endif /* VBOX_WITH_WDDM */
705#endif /* WINDOWS */
706
707 crLockMutex(&stub.mutex);
708#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
709 spuConnection =
710#endif
711 stub.spu->dispatch_table.VBoxPackSetInjectThread(NULL);
712#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
713 if (stub.bRunningUnderWDDM && !spuConnection)
714 {
715 crError("VBoxPackSetInjectThread failed!");
716 }
717#endif
718 crUnlockMutex(&stub.mutex);
719
720 RTThreadUserSignal(ThreadSelf);
721
722 while(!stub.bShutdownSyncThread)
723 {
724#ifdef WINDOWS
725 if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
726 {
727# ifdef VBOX_WITH_WDDM
728 if (stub.bRunningUnderWDDM)
729 {
730
731 }
732 else
733# endif
734 {
735 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
736 RTThreadSleep(50);
737 }
738 }
739 else
740 {
741 if (WM_QUIT==msg.message)
742 {
743 crDebug("Sync thread got WM_QUIT");
744 break;
745 }
746 else
747 {
748 TranslateMessage(&msg);
749 DispatchMessage(&msg);
750 }
751 }
752#else
753 /* Try to keep a consistent locking order. */
754 crHashtableLock(stub.windowTable);
755 crLockMutex(&stub.mutex);
756 crHashtableWalkUnlocked(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
757 crUnlockMutex(&stub.mutex);
758 crHashtableUnlock(stub.windowTable);
759 RTThreadSleep(50);
760#endif
761 }
762
763#ifdef VBOX_WITH_WDDM
764 if (spuConnection)
765 {
766 stub.spu->dispatch_table.VBoxConDestroy(spuConnection);
767 }
768 if (hVBoxD3D)
769 {
770 FreeLibrary(hVBoxD3D);
771 }
772#endif
773 crDebug("Sync thread stopped");
774 return 0;
775}
776#endif /* CR_NEWWINTRACK */
777
778/**
779 * Do one-time initializations for the faker.
780 * Returns TRUE on success, FALSE otherwise.
781 */
782static bool
783stubInitLocked(void)
784{
785 /* Here is where we contact the mothership to find out what we're supposed
786 * to be doing. Networking code in a DLL initializer. I sure hope this
787 * works :)
788 *
789 * HOW can I pass the mothership address to this if I already know it?
790 */
791
792 char response[1024];
793 int aSpuIds[] = {0, 1};
794 const char *apszSpuNames[] = {"feedback", "pack"};
795 PCSPUREG apSpuReg[] = { &g_ErrorSpuReg, &g_FeedbackSpuReg, &g_PassthroughSpuReg,&g_PackSpuReg};
796 const char *app_id;
797 int disable_sync = 0;
798#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
799 HMODULE hVBoxD3D = NULL;
800#endif
801
802 stubInitVars();
803
804 crGetProcName(response, 1024);
805 crDebug("Stub launched for %s", response);
806
807#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
808 /** @todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread
809 * as at the start compiz runs our code under XGrabServer.
810 */
811 if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real") || !crStrcmp(response, "compiz.real")
812 || !crStrcmp(response, "compiz-bin"))
813 {
814 disable_sync = 1;
815 }
816#endif
817
818 /** @todo check if it'd be of any use on other than guests, no use for windows */
819 app_id = RTEnvGet( "CR_APPLICATION_ID_NUMBER" );
820
821 crNetInit( NULL, NULL );
822
823#ifndef WINDOWS
824 {
825 CRNetServer ns;
826
827 ns.name = "vboxhgcm://host:0";
828 ns.buffer_size = 1024;
829 crNetServerConnect(&ns
830#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
831 , NULL
832#endif
833 );
834 if (!ns.conn)
835 {
836 crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
837# ifdef VBOXOGL_FAKEDRI
838 return false;
839# else
840 exit(1);
841# endif
842 }
843 else
844 {
845 crNetFreeConnection(ns.conn);
846 }
847 }
848#endif
849
850 stubSetDefaultConfigurationOptions();
851
852#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
853 hVBoxD3D = NULL;
854 if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
855 {
856 crDebug("GetModuleHandleEx failed err %d", GetLastError());
857 hVBoxD3D = NULL;
858 }
859
860 if (hVBoxD3D)
861 {
862 disable_sync = 1;
863 crDebug("running with %s", VBOX_MODNAME_DISPD3D);
864 stub.trackWindowVisibleRgn = 0;
865 /** @todo should we enable that? */
866 stub.trackWindowSize = 0;
867 stub.trackWindowPos = 0;
868 stub.trackWindowVisibility = 0;
869 stub.bRunningUnderWDDM = true;
870 }
871#endif
872
873 stub.spu = crSPUInitChainFromReg(RT_ELEMENTS(aSpuIds), &aSpuIds[0], &apszSpuNames[0], NULL, &apSpuReg[0]);
874
875 // spu chain load failed somewhere
876 if (!stub.spu) {
877 return false;
878 }
879
880 crSPUInitDispatchTable( &glim );
881
882 /* This is unlikely to change -- We still want to initialize our dispatch
883 * table with the functions of the first SPU in the chain. */
884 stubInitSPUDispatch( stub.spu );
885
886 /* we need to plug one special stub function into the dispatch table */
887 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
888
889#if !defined(VBOX_NO_NATIVEGL)
890 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
891 stubInitNativeDispatch();
892#endif
893
894/*crDebug("stub init");
895raise(SIGINT);*/
896
897#ifdef WINDOWS
898# ifndef CR_NEWWINTRACK
899 stubInstallWindowMessageHook();
900# endif
901#endif
902
903#ifdef CR_NEWWINTRACK
904 {
905 int rc;
906
907 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
908
909 if (!disable_sync)
910 {
911 crDebug("Starting sync thread");
912
913 rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync");
914 if (RT_FAILURE(rc))
915 {
916 crError("Failed to start sync thread! (%x)", rc);
917 }
918 RTThreadUserWait(stub.hSyncThread, 60 * 1000);
919 RTThreadUserReset(stub.hSyncThread);
920
921 crDebug("Going on");
922 }
923 }
924#endif
925
926#ifdef GLX
927 stub.xshmSI.shmid = -1;
928 stub.bShmInitFailed = GL_FALSE;
929 stub.pGLXPixmapsHash = crAllocHashtable();
930
931 stub.bXExtensionsChecked = GL_FALSE;
932 stub.bHaveXComposite = GL_FALSE;
933 stub.bHaveXFixes = GL_FALSE;
934#endif
935
936 return true;
937}
938
939/**
940 * Do one-time initializations for the faker.
941 * Returns TRUE on success, FALSE otherwise.
942 */
943bool
944stubInit(void)
945{
946 bool bRc = true;
947 /* we need to serialize the initialization, otherwise racing is possible
948 * for XPDM-based d3d when a d3d switcher is testing the gl lib in two or more threads
949 * NOTE: the STUB_INIT_LOCK/UNLOCK is a NOP for non-win currently */
950 STUB_INIT_LOCK();
951 if (!stub_initialized)
952 bRc = stub_initialized = stubInitLocked();
953 STUB_INIT_UNLOCK();
954 return bRc;
955}
956
957/* Sigh -- we can't do initialization at load time, since Windows forbids
958 * the loading of other libraries from DLLMain. */
959
960#ifdef WINDOWS
961#define WIN32_LEAN_AND_MEAN
962#include <windows.h>
963
964#if 1//def DEBUG_misha
965 /* debugging: this is to be able to catch first-chance notifications
966 * for exceptions other than EXCEPTION_BREAKPOINT in kernel debugger */
967# define VDBG_VEHANDLER
968#endif
969
970#ifdef VDBG_VEHANDLER
971# include <dbghelp.h>
972# include <cr_string.h>
973static PVOID g_VBoxVehHandler = NULL;
974static DWORD g_VBoxVehEnable = 0;
975
976/* generate a crash dump on exception */
977#define VBOXVEH_F_DUMP 0x00000001
978/* generate a debugger breakpoint exception */
979#define VBOXVEH_F_BREAK 0x00000002
980/* exit on exception */
981#define VBOXVEH_F_EXIT 0x00000004
982
983static DWORD g_VBoxVehFlags = 0;
984
985typedef BOOL WINAPI FNVBOXDBG_MINIDUMPWRITEDUMP(HANDLE hProcess,
986 DWORD ProcessId,
987 HANDLE hFile,
988 MINIDUMP_TYPE DumpType,
989 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
990 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
991 PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
992typedef FNVBOXDBG_MINIDUMPWRITEDUMP *PFNVBOXDBG_MINIDUMPWRITEDUMP;
993
994static HMODULE g_hVBoxMdDbgHelp = NULL;
995static PFNVBOXDBG_MINIDUMPWRITEDUMP g_pfnVBoxMdMiniDumpWriteDump = NULL;
996static size_t g_cVBoxMdFilePrefixLen = 0;
997static WCHAR g_aszwVBoxMdFilePrefix[MAX_PATH];
998static WCHAR g_aszwVBoxMdDumpCount = 0;
999static MINIDUMP_TYPE g_enmVBoxMdDumpType = MiniDumpNormal
1000 | MiniDumpWithDataSegs
1001 | MiniDumpWithFullMemory
1002 | MiniDumpWithHandleData
1003//// | MiniDumpFilterMemory
1004//// | MiniDumpScanMemory
1005// | MiniDumpWithUnloadedModules
1006//// | MiniDumpWithIndirectlyReferencedMemory
1007//// | MiniDumpFilterModulePaths
1008// | MiniDumpWithProcessThreadData
1009// | MiniDumpWithPrivateReadWriteMemory
1010//// | MiniDumpWithoutOptionalData
1011// | MiniDumpWithFullMemoryInfo
1012// | MiniDumpWithThreadInfo
1013// | MiniDumpWithCodeSegs
1014// | MiniDumpWithFullAuxiliaryState
1015// | MiniDumpWithPrivateWriteCopyMemory
1016// | MiniDumpIgnoreInaccessibleMemory
1017// | MiniDumpWithTokenInformation
1018//// | MiniDumpWithModuleHeaders
1019//// | MiniDumpFilterTriage
1020 ;
1021
1022
1023
1024#define VBOXMD_DUMP_DIR_DEFAULT "C:\\dumps"
1025#define VBOXMD_DUMP_NAME_PREFIX_W L"VBoxDmp_"
1026
1027static HMODULE loadSystemDll(const char *pszName)
1028{
1029#ifndef DEBUG
1030 char szPath[MAX_PATH];
1031 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
1032 size_t cbName = strlen(pszName) + 1;
1033 if (cchPath + 1 + cbName > sizeof(szPath))
1034 {
1035 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1036 return NULL;
1037 }
1038 szPath[cchPath] = '\\';
1039 memcpy(&szPath[cchPath + 1], pszName, cbName);
1040 return LoadLibraryA(szPath);
1041#else
1042 return LoadLibraryA(pszName);
1043#endif
1044}
1045
1046static DWORD vboxMdMinidumpCreate(struct _EXCEPTION_POINTERS *pExceptionInfo)
1047{
1048 WCHAR aszwMdFileName[MAX_PATH];
1049 HANDLE hProcess = GetCurrentProcess();
1050 DWORD ProcessId = GetCurrentProcessId();
1051 MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
1052 HANDLE hFile;
1053 DWORD winErr = ERROR_SUCCESS;
1054
1055 if (!g_pfnVBoxMdMiniDumpWriteDump)
1056 {
1057 if (!g_hVBoxMdDbgHelp)
1058 {
1059 g_hVBoxMdDbgHelp = loadSystemDll("DbgHelp.dll");
1060 if (!g_hVBoxMdDbgHelp)
1061 return GetLastError();
1062 }
1063
1064 g_pfnVBoxMdMiniDumpWriteDump = (PFNVBOXDBG_MINIDUMPWRITEDUMP)GetProcAddress(g_hVBoxMdDbgHelp, "MiniDumpWriteDump");
1065 if (!g_pfnVBoxMdMiniDumpWriteDump)
1066 return GetLastError();
1067 }
1068
1069 ++g_aszwVBoxMdDumpCount;
1070
1071 memcpy(aszwMdFileName, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen * sizeof (g_aszwVBoxMdFilePrefix[0]));
1072 swprintf(aszwMdFileName + g_cVBoxMdFilePrefixLen, RT_ELEMENTS(aszwMdFileName) - g_cVBoxMdFilePrefixLen, L"%d_%d.dmp", ProcessId, g_aszwVBoxMdDumpCount);
1073
1074 hFile = CreateFileW(aszwMdFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1075 if (hFile == INVALID_HANDLE_VALUE)
1076 return GetLastError();
1077
1078 ExceptionInfo.ThreadId = GetCurrentThreadId();
1079 ExceptionInfo.ExceptionPointers = pExceptionInfo;
1080 ExceptionInfo.ClientPointers = FALSE;
1081
1082 if (!g_pfnVBoxMdMiniDumpWriteDump(hProcess, ProcessId, hFile, g_enmVBoxMdDumpType, &ExceptionInfo, NULL, NULL))
1083 winErr = GetLastError();
1084
1085 CloseHandle(hFile);
1086 return winErr;
1087}
1088
1089LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
1090{
1091 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
1092 PCONTEXT pContextRecord = pExceptionInfo->ContextRecord;
1093 switch (pExceptionRecord->ExceptionCode)
1094 {
1095 case EXCEPTION_BREAKPOINT:
1096 case EXCEPTION_ACCESS_VIOLATION:
1097 case EXCEPTION_STACK_OVERFLOW:
1098 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1099 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1100 case EXCEPTION_FLT_INVALID_OPERATION:
1101 case EXCEPTION_INT_DIVIDE_BY_ZERO:
1102 case EXCEPTION_ILLEGAL_INSTRUCTION:
1103 if (g_VBoxVehFlags & VBOXVEH_F_BREAK)
1104 {
1105 BOOL fBreak = TRUE;
1106#ifndef DEBUG_misha
1107 if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
1108 {
1109 HANDLE hProcess = GetCurrentProcess();
1110 BOOL fDebuggerPresent = FALSE;
1111 /* we do not want to generate breakpoint exceptions recursively, so do it only when running under debugger */
1112 if (CheckRemoteDebuggerPresent(hProcess, &fDebuggerPresent))
1113 fBreak = !!fDebuggerPresent;
1114 else
1115 fBreak = FALSE; /* <- the function has failed, don't break for sanity */
1116 }
1117#endif
1118
1119 if (fBreak)
1120 {
1121 RT_BREAKPOINT();
1122 }
1123 }
1124
1125 if (g_VBoxVehFlags & VBOXVEH_F_DUMP)
1126 vboxMdMinidumpCreate(pExceptionInfo);
1127
1128 if (g_VBoxVehFlags & VBOXVEH_F_EXIT)
1129 exit(1);
1130 break;
1131 default:
1132 break;
1133 }
1134 return EXCEPTION_CONTINUE_SEARCH;
1135}
1136
1137void vboxVDbgVEHandlerRegister()
1138{
1139 CRASSERT(!g_VBoxVehHandler);
1140 g_VBoxVehHandler = AddVectoredExceptionHandler(1,vboxVDbgVectoredHandler);
1141 CRASSERT(g_VBoxVehHandler);
1142}
1143
1144void vboxVDbgVEHandlerUnregister()
1145{
1146 ULONG uResult;
1147 if (g_VBoxVehHandler)
1148 {
1149 uResult = RemoveVectoredExceptionHandler(g_VBoxVehHandler);
1150 CRASSERT(uResult);
1151 g_VBoxVehHandler = NULL;
1152 }
1153}
1154#endif
1155
1156/* Windows crap */
1157BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
1158{
1159 (void) lpvReserved;
1160
1161 switch (fdwReason)
1162 {
1163 case DLL_PROCESS_ATTACH:
1164 {
1165 CRNetServer ns;
1166 const char * env;
1167#if defined(DEBUG_misha)
1168 HMODULE hCrUtil;
1169 char aName[MAX_PATH];
1170
1171 GetModuleFileNameA(hDLLInst, aName, RT_ELEMENTS(aName));
1172 crDbgCmdSymLoadPrint(aName, hDLLInst);
1173#endif
1174
1175 int rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); CRASSERT(rc==0);
1176 rc = VbglR3Init();
1177
1178 crInitTSD(&g_stubCurrentContextTSD);
1179 crInitMutex(&stub_init_mutex);
1180
1181#ifdef VDBG_VEHANDLER
1182 env = RTEnvGet("CR_DBG_VEH_ENABLE");
1183 g_VBoxVehEnable = crStrParseI32(env,
1184# ifdef DEBUG_misha
1185 1
1186# else
1187 0
1188# endif
1189 );
1190
1191 if (g_VBoxVehEnable)
1192 {
1193 char procName[1024];
1194 size_t cProcName;
1195 size_t cChars;
1196
1197 env = RTEnvGet("CR_DBG_VEH_FLAGS");
1198 g_VBoxVehFlags = crStrParseI32(env,
1199 0
1200# ifdef DEBUG_misha
1201 | VBOXVEH_F_BREAK
1202# else
1203 | VBOXVEH_F_DUMP
1204# endif
1205 );
1206
1207 env = RTEnvGet("CR_DBG_VEH_DUMP_DIR");
1208 if (!env)
1209 env = VBOXMD_DUMP_DIR_DEFAULT;
1210
1211 g_cVBoxMdFilePrefixLen = strlen(env);
1212
1213 if (RT_ELEMENTS(g_aszwVBoxMdFilePrefix) <= g_cVBoxMdFilePrefixLen + 26 + (sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR)) / sizeof (WCHAR))
1214 {
1215 g_cVBoxMdFilePrefixLen = 0;
1216 env = "";
1217 }
1218
1219 mbstowcs_s(&cChars, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen + 1, env, _TRUNCATE);
1220
1221 Assert(cChars == g_cVBoxMdFilePrefixLen + 1);
1222
1223 g_cVBoxMdFilePrefixLen = cChars - 1;
1224
1225 if (g_cVBoxMdFilePrefixLen && g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen - 1] != L'\\')
1226 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen++] = L'\\';
1227
1228 memcpy(g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, VBOXMD_DUMP_NAME_PREFIX_W, sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR));
1229 g_cVBoxMdFilePrefixLen += (sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR)) / sizeof (WCHAR);
1230
1231 crGetProcName(procName, RT_ELEMENTS(procName));
1232 cProcName = strlen(procName);
1233
1234 if (RT_ELEMENTS(g_aszwVBoxMdFilePrefix) > g_cVBoxMdFilePrefixLen + cProcName + 1 + 26)
1235 {
1236 mbstowcs_s(&cChars, g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, cProcName + 1, procName, _TRUNCATE);
1237 Assert(cChars == cProcName + 1);
1238 g_cVBoxMdFilePrefixLen += cChars - 1;
1239 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen++] = L'_';
1240 }
1241
1242 /* sanity */
1243 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen] = L'\0';
1244
1245 env = RTEnvGet("CR_DBG_VEH_DUMP_TYPE");
1246
1247 g_enmVBoxMdDumpType = crStrParseI32(env,
1248 MiniDumpNormal
1249 | MiniDumpWithDataSegs
1250 | MiniDumpWithFullMemory
1251 | MiniDumpWithHandleData
1252 //// | MiniDumpFilterMemory
1253 //// | MiniDumpScanMemory
1254 // | MiniDumpWithUnloadedModules
1255 //// | MiniDumpWithIndirectlyReferencedMemory
1256 //// | MiniDumpFilterModulePaths
1257 // | MiniDumpWithProcessThreadData
1258 // | MiniDumpWithPrivateReadWriteMemory
1259 //// | MiniDumpWithoutOptionalData
1260 // | MiniDumpWithFullMemoryInfo
1261 // | MiniDumpWithThreadInfo
1262 // | MiniDumpWithCodeSegs
1263 // | MiniDumpWithFullAuxiliaryState
1264 // | MiniDumpWithPrivateWriteCopyMemory
1265 // | MiniDumpIgnoreInaccessibleMemory
1266 // | MiniDumpWithTokenInformation
1267 //// | MiniDumpWithModuleHeaders
1268 //// | MiniDumpFilterTriage
1269 );
1270
1271 vboxVDbgVEHandlerRegister();
1272 }
1273#endif
1274
1275 crNetInit(NULL, NULL);
1276 ns.name = "vboxhgcm://host:0";
1277 ns.buffer_size = 1024;
1278 crNetServerConnect(&ns
1279#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1280 , NULL
1281#endif
1282);
1283 if (!ns.conn)
1284 {
1285 crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
1286#ifdef VDBG_VEHANDLER
1287 if (g_VBoxVehEnable)
1288 vboxVDbgVEHandlerUnregister();
1289#endif
1290 return FALSE;
1291 }
1292 else
1293 {
1294 crNetFreeConnection(ns.conn);
1295 }
1296
1297#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1298 VBoxCrHgsmiInit();
1299#endif
1300 break;
1301 }
1302
1303 case DLL_PROCESS_DETACH:
1304 {
1305 /* do exactly the same thing as for DLL_THREAD_DETACH since
1306 * DLL_THREAD_DETACH is not called for the thread doing DLL_PROCESS_DETACH according to msdn docs */
1307 stubSetCurrentContext(NULL);
1308 if (stub_initialized)
1309 {
1310 CRASSERT(stub.spu);
1311 stub.spu->dispatch_table.VBoxDetachThread();
1312 }
1313
1314
1315#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1316 VBoxCrHgsmiTerm();
1317#endif
1318
1319 stubSPUSafeTearDown();
1320 crFreeTSD(&g_stubCurrentContextTSD);
1321
1322#ifdef VDBG_VEHANDLER
1323 if (g_VBoxVehEnable)
1324 vboxVDbgVEHandlerUnregister();
1325#endif
1326 VbglR3Term();
1327 break;
1328 }
1329
1330 case DLL_THREAD_ATTACH:
1331 {
1332 if (stub_initialized)
1333 {
1334 CRASSERT(stub.spu);
1335 stub.spu->dispatch_table.VBoxAttachThread();
1336 }
1337 break;
1338 }
1339
1340 case DLL_THREAD_DETACH:
1341 {
1342 stubSetCurrentContext(NULL);
1343 if (stub_initialized)
1344 {
1345 CRASSERT(stub.spu);
1346 stub.spu->dispatch_table.VBoxDetachThread();
1347 }
1348 break;
1349 }
1350
1351 default:
1352 break;
1353 }
1354
1355 return TRUE;
1356}
1357#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette