VirtualBox

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

Last change on this file since 78451 was 78408, checked in by vboxsync, 6 years ago

Additions,GuestHost/OpenGL,HostServices/SharedOpenGL: Get rid of the individual SPU shared libraries and merge them into the VBoxSharedCrOpenGL shared libraries on the host and VBoxOGL{,-x86} shared libraries for the guest additions, bugref:9435

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 36.7 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 int rc = RTThreadWait(stub.hSyncThread, RT_INDEFINITE_WAIT, NULL);
472 if (RT_FAILURE(rc))
473 {
474 WARN(("RTThreadWait_join failed %i", rc));
475 }
476 }
477 }
478#endif
479 crLockMutex(mutex);
480#endif
481
482#ifndef WINDOWS
483 crNetTearDown();
484#endif
485
486 crUnlockMutex(mutex);
487 crFreeMutex(mutex);
488 crMemset(&stub, 0, sizeof(stub));
489}
490
491
492static void stubExitHandler(void)
493{
494 stubSPUSafeTearDown();
495 signal(SIGTERM, SIG_DFL);
496 signal(SIGINT, SIG_DFL);
497}
498
499/**
500 * Called when we receive a SIGTERM signal.
501 */
502static void stubSignalHandler(int signo)
503{
504 (void)signo;
505 stubSPUSafeTearDown();
506 exit(0); /* this causes stubExitHandler() to be called */
507}
508
509#ifndef RT_OS_WINDOWS
510static void stubThreadTlsDtor(void *pvValue)
511{
512 ContextInfo *pCtx = (ContextInfo*)pvValue;
513 VBoxTlsRefRelease(pCtx);
514}
515#endif
516
517
518/**
519 * Init variables in the stub structure, install signal handler.
520 */
521static void stubInitVars(void)
522{
523 WindowInfo *defaultWin;
524
525 crInitMutex(&stub.mutex);
526
527 /* At the very least we want CR_RGB_BIT. */
528 stub.haveNativeOpenGL = GL_FALSE;
529 stub.spu = NULL;
530 stub.appDrawCursor = 0;
531 stub.minChromiumWindowWidth = 0;
532 stub.minChromiumWindowHeight = 0;
533 stub.maxChromiumWindowWidth = 0;
534 stub.maxChromiumWindowHeight = 0;
535 stub.matchChromiumWindowCount = 0;
536 stub.matchChromiumWindowID = NULL;
537 stub.matchWindowTitle = NULL;
538 stub.ignoreFreeglutMenus = 0;
539 stub.threadSafe = GL_FALSE;
540 stub.trackWindowSize = 0;
541 stub.trackWindowPos = 0;
542 stub.trackWindowVisibility = 0;
543 stub.trackWindowVisibleRgn = 0;
544 stub.mothershipPID = 0;
545 stub.spu_dir = NULL;
546
547 stub.freeContextNumber = MAGIC_CONTEXT_BASE;
548 stub.contextTable = crAllocHashtable();
549#ifndef RT_OS_WINDOWS
550 if (!g_stubIsCurrentContextTSDInited)
551 {
552 crInitTSDF(&g_stubCurrentContextTSD, stubThreadTlsDtor);
553 g_stubIsCurrentContextTSDInited = true;
554 }
555#endif
556 stubSetCurrentContext(NULL);
557
558 stub.windowTable = crAllocHashtable();
559
560#ifdef CR_NEWWINTRACK
561 stub.bShutdownSyncThread = false;
562 stub.hSyncThread = NIL_RTTHREAD;
563#endif
564
565 defaultWin = (WindowInfo *) crCalloc(sizeof(WindowInfo));
566 defaultWin->type = CHROMIUM;
567 defaultWin->spuWindow = 0; /* window 0 always exists */
568#ifdef WINDOWS
569 defaultWin->hVisibleRegion = INVALID_HANDLE_VALUE;
570#elif defined(GLX)
571 defaultWin->pVisibleRegions = NULL;
572 defaultWin->cVisibleRegions = 0;
573#endif
574 crHashtableAdd(stub.windowTable, 0, defaultWin);
575
576#if 1
577 atexit(stubExitHandler);
578 signal(SIGTERM, stubSignalHandler);
579 signal(SIGINT, stubSignalHandler);
580#ifndef WINDOWS
581 signal(SIGPIPE, SIG_IGN); /* the networking code should catch this */
582#endif
583#else
584 (void) stubExitHandler;
585 (void) stubSignalHandler;
586#endif
587}
588
589
590static void stubSetDefaultConfigurationOptions(void)
591{
592 stub.appDrawCursor = 0;
593 stub.minChromiumWindowWidth = 0;
594 stub.minChromiumWindowHeight = 0;
595 stub.maxChromiumWindowWidth = 0;
596 stub.maxChromiumWindowHeight = 0;
597 stub.matchChromiumWindowID = NULL;
598 stub.numIgnoreWindowID = 0;
599 stub.matchWindowTitle = NULL;
600 stub.ignoreFreeglutMenus = 0;
601 stub.trackWindowSize = 1;
602 stub.trackWindowPos = 1;
603 stub.trackWindowVisibility = 1;
604 stub.trackWindowVisibleRgn = 1;
605 stub.matchChromiumWindowCount = 0;
606 stub.spu_dir = NULL;
607 stub.force_pbuffers = 0;
608
609#ifdef WINDOWS
610# ifdef VBOX_WITH_WDDM
611 stub.bRunningUnderWDDM = false;
612# endif
613#endif
614}
615
616#ifdef CR_NEWWINTRACK
617# ifdef VBOX_WITH_WDDM
618static void stubDispatchVisibleRegions(WindowInfo *pWindow)
619{
620 DWORD dwCount;
621 LPRGNDATA lpRgnData;
622
623 dwCount = GetRegionData(pWindow->hVisibleRegion, 0, NULL);
624 lpRgnData = crAlloc(dwCount);
625
626 if (lpRgnData)
627 {
628 GetRegionData(pWindow->hVisibleRegion, dwCount, lpRgnData);
629 crDebug("Dispatched WindowVisibleRegion (%i, cRects=%i)", pWindow->spuWindow, lpRgnData->rdh.nCount);
630 stub.spuDispatch.WindowVisibleRegion(pWindow->spuWindow, lpRgnData->rdh.nCount, (GLint*) lpRgnData->Buffer);
631 crFree(lpRgnData);
632 }
633 else crWarning("GetRegionData failed, VisibleRegions update failed");
634}
635
636# endif /* VBOX_WITH_WDDM */
637
638static void stubSyncTrCheckWindowsCB(unsigned long key, void *data1, void *data2)
639{
640 WindowInfo *pWindow = (WindowInfo *) data1;
641 (void)key; (void) data2;
642
643 if (pWindow->type!=CHROMIUM || pWindow->spuWindow==0)
644 {
645 return;
646 }
647
648 stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
649
650 if (!stubSystemWindowExist(pWindow))
651 {
652#ifdef WINDOWS
653 stubDestroyWindow(0, (GLint)pWindow->hWnd);
654#else
655 stubDestroyWindow(0, (GLint)pWindow->drawable);
656#endif
657 /*No need to flush here as crWindowDestroy does it*/
658 return;
659 }
660
661#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
662 if (stub.bRunningUnderWDDM)
663 return;
664#endif
665 stubCheckWindowState(pWindow, GL_TRUE);
666}
667
668static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
669{
670#ifdef WINDOWS
671 MSG msg;
672# ifdef VBOX_WITH_WDDM
673 HMODULE hVBoxD3D = NULL;
674 GLint spuConnection = 0;
675# endif
676#endif
677
678 (void) pvUser;
679
680 crDebug("Sync thread started");
681#ifdef WINDOWS
682 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
683# ifdef VBOX_WITH_WDDM
684 hVBoxD3D = NULL;
685 if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
686 {
687 crDebug("GetModuleHandleEx failed err %d", GetLastError());
688 hVBoxD3D = NULL;
689 }
690
691 if (hVBoxD3D)
692 {
693 crDebug("running with " VBOX_MODNAME_DISPD3D);
694 stub.trackWindowVisibleRgn = 0;
695 stub.bRunningUnderWDDM = true;
696 }
697# endif /* VBOX_WITH_WDDM */
698#endif /* WINDOWS */
699
700 crLockMutex(&stub.mutex);
701#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
702 spuConnection =
703#endif
704 stub.spu->dispatch_table.VBoxPackSetInjectThread(NULL);
705#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
706 if (stub.bRunningUnderWDDM && !spuConnection)
707 {
708 crError("VBoxPackSetInjectThread failed!");
709 }
710#endif
711 crUnlockMutex(&stub.mutex);
712
713 RTThreadUserSignal(ThreadSelf);
714
715 while(!stub.bShutdownSyncThread)
716 {
717#ifdef WINDOWS
718 if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
719 {
720# ifdef VBOX_WITH_WDDM
721 if (stub.bRunningUnderWDDM)
722 {
723
724 }
725 else
726# endif
727 {
728 crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
729 RTThreadSleep(50);
730 }
731 }
732 else
733 {
734 if (WM_QUIT==msg.message)
735 {
736 crDebug("Sync thread got WM_QUIT");
737 break;
738 }
739 else
740 {
741 TranslateMessage(&msg);
742 DispatchMessage(&msg);
743 }
744 }
745#else
746 /* Try to keep a consistent locking order. */
747 crHashtableLock(stub.windowTable);
748 crLockMutex(&stub.mutex);
749 crHashtableWalkUnlocked(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
750 crUnlockMutex(&stub.mutex);
751 crHashtableUnlock(stub.windowTable);
752 RTThreadSleep(50);
753#endif
754 }
755
756#ifdef VBOX_WITH_WDDM
757 if (spuConnection)
758 {
759 stub.spu->dispatch_table.VBoxConDestroy(spuConnection);
760 }
761 if (hVBoxD3D)
762 {
763 FreeLibrary(hVBoxD3D);
764 }
765#endif
766 crDebug("Sync thread stopped");
767 return 0;
768}
769#endif /* CR_NEWWINTRACK */
770
771/**
772 * Do one-time initializations for the faker.
773 * Returns TRUE on success, FALSE otherwise.
774 */
775static bool
776stubInitLocked(void)
777{
778 /* Here is where we contact the mothership to find out what we're supposed
779 * to be doing. Networking code in a DLL initializer. I sure hope this
780 * works :)
781 *
782 * HOW can I pass the mothership address to this if I already know it?
783 */
784
785 char response[1024];
786 int aSpuIds[] = {0, 1};
787 const char *apszSpuNames[] = {"feedback", "pack"};
788 PCSPUREG apSpuReg[] = { &g_ErrorSpuReg, &g_FeedbackSpuReg, &g_PassthroughSpuReg,&g_PackSpuReg};
789 const char *app_id;
790 int disable_sync = 0;
791#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
792 HMODULE hVBoxD3D = NULL;
793#endif
794
795 stubInitVars();
796
797 crGetProcName(response, 1024);
798 crDebug("Stub launched for %s", response);
799
800#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
801 /** @todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread
802 * as at the start compiz runs our code under XGrabServer.
803 */
804 if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real") || !crStrcmp(response, "compiz.real")
805 || !crStrcmp(response, "compiz-bin"))
806 {
807 disable_sync = 1;
808 }
809#endif
810
811 /** @todo check if it'd be of any use on other than guests, no use for windows */
812 app_id = RTEnvGet( "CR_APPLICATION_ID_NUMBER" );
813
814 crNetInit( NULL, NULL );
815
816#ifndef WINDOWS
817 {
818 CRNetServer ns;
819
820 ns.name = "vboxhgcm://host:0";
821 ns.buffer_size = 1024;
822 crNetServerConnect(&ns
823#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
824 , NULL
825#endif
826 );
827 if (!ns.conn)
828 {
829 crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
830# ifdef VBOXOGL_FAKEDRI
831 return false;
832# else
833 exit(1);
834# endif
835 }
836 else
837 {
838 crNetFreeConnection(ns.conn);
839 }
840 }
841#endif
842
843 stubSetDefaultConfigurationOptions();
844
845#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
846 hVBoxD3D = NULL;
847 if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
848 {
849 crDebug("GetModuleHandleEx failed err %d", GetLastError());
850 hVBoxD3D = NULL;
851 }
852
853 if (hVBoxD3D)
854 {
855 disable_sync = 1;
856 crDebug("running with %s", VBOX_MODNAME_DISPD3D);
857 stub.trackWindowVisibleRgn = 0;
858 /** @todo should we enable that? */
859 stub.trackWindowSize = 0;
860 stub.trackWindowPos = 0;
861 stub.trackWindowVisibility = 0;
862 stub.bRunningUnderWDDM = true;
863 }
864#endif
865
866 stub.spu = crSPUInitChainFromReg(RT_ELEMENTS(aSpuIds), &aSpuIds[0], &apszSpuNames[0], NULL, &apSpuReg[0]);
867
868 // spu chain load failed somewhere
869 if (!stub.spu) {
870 return false;
871 }
872
873 crSPUInitDispatchTable( &glim );
874
875 /* This is unlikely to change -- We still want to initialize our dispatch
876 * table with the functions of the first SPU in the chain. */
877 stubInitSPUDispatch( stub.spu );
878
879 /* we need to plug one special stub function into the dispatch table */
880 glim.GetChromiumParametervCR = stub_GetChromiumParametervCR;
881
882#if !defined(VBOX_NO_NATIVEGL)
883 /* Load pointers to native OpenGL functions into stub.nativeDispatch */
884 stubInitNativeDispatch();
885#endif
886
887/*crDebug("stub init");
888raise(SIGINT);*/
889
890#ifdef WINDOWS
891# ifndef CR_NEWWINTRACK
892 stubInstallWindowMessageHook();
893# endif
894#endif
895
896#ifdef CR_NEWWINTRACK
897 {
898 int rc;
899
900 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
901
902 if (!disable_sync)
903 {
904 crDebug("Starting sync thread");
905
906 rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync");
907 if (RT_FAILURE(rc))
908 {
909 crError("Failed to start sync thread! (%x)", rc);
910 }
911 RTThreadUserWait(stub.hSyncThread, 60 * 1000);
912 RTThreadUserReset(stub.hSyncThread);
913
914 crDebug("Going on");
915 }
916 }
917#endif
918
919#ifdef GLX
920 stub.xshmSI.shmid = -1;
921 stub.bShmInitFailed = GL_FALSE;
922 stub.pGLXPixmapsHash = crAllocHashtable();
923
924 stub.bXExtensionsChecked = GL_FALSE;
925 stub.bHaveXComposite = GL_FALSE;
926 stub.bHaveXFixes = GL_FALSE;
927#endif
928
929 return true;
930}
931
932/**
933 * Do one-time initializations for the faker.
934 * Returns TRUE on success, FALSE otherwise.
935 */
936bool
937stubInit(void)
938{
939 bool bRc = true;
940 /* we need to serialize the initialization, otherwise racing is possible
941 * for XPDM-based d3d when a d3d switcher is testing the gl lib in two or more threads
942 * NOTE: the STUB_INIT_LOCK/UNLOCK is a NOP for non-win currently */
943 STUB_INIT_LOCK();
944 if (!stub_initialized)
945 bRc = stub_initialized = stubInitLocked();
946 STUB_INIT_UNLOCK();
947 return bRc;
948}
949
950/* Sigh -- we can't do initialization at load time, since Windows forbids
951 * the loading of other libraries from DLLMain. */
952
953#ifdef WINDOWS
954#define WIN32_LEAN_AND_MEAN
955#include <windows.h>
956
957#if 1//def DEBUG_misha
958 /* debugging: this is to be able to catch first-chance notifications
959 * for exceptions other than EXCEPTION_BREAKPOINT in kernel debugger */
960# define VDBG_VEHANDLER
961#endif
962
963#ifdef VDBG_VEHANDLER
964# include <dbghelp.h>
965# include <cr_string.h>
966static PVOID g_VBoxVehHandler = NULL;
967static DWORD g_VBoxVehEnable = 0;
968
969/* generate a crash dump on exception */
970#define VBOXVEH_F_DUMP 0x00000001
971/* generate a debugger breakpoint exception */
972#define VBOXVEH_F_BREAK 0x00000002
973/* exit on exception */
974#define VBOXVEH_F_EXIT 0x00000004
975
976static DWORD g_VBoxVehFlags = 0;
977
978typedef BOOL WINAPI FNVBOXDBG_MINIDUMPWRITEDUMP(HANDLE hProcess,
979 DWORD ProcessId,
980 HANDLE hFile,
981 MINIDUMP_TYPE DumpType,
982 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
983 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
984 PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
985typedef FNVBOXDBG_MINIDUMPWRITEDUMP *PFNVBOXDBG_MINIDUMPWRITEDUMP;
986
987static HMODULE g_hVBoxMdDbgHelp = NULL;
988static PFNVBOXDBG_MINIDUMPWRITEDUMP g_pfnVBoxMdMiniDumpWriteDump = NULL;
989static size_t g_cVBoxMdFilePrefixLen = 0;
990static WCHAR g_aszwVBoxMdFilePrefix[MAX_PATH];
991static WCHAR g_aszwVBoxMdDumpCount = 0;
992static MINIDUMP_TYPE g_enmVBoxMdDumpType = MiniDumpNormal
993 | MiniDumpWithDataSegs
994 | MiniDumpWithFullMemory
995 | MiniDumpWithHandleData
996//// | MiniDumpFilterMemory
997//// | MiniDumpScanMemory
998// | MiniDumpWithUnloadedModules
999//// | MiniDumpWithIndirectlyReferencedMemory
1000//// | MiniDumpFilterModulePaths
1001// | MiniDumpWithProcessThreadData
1002// | MiniDumpWithPrivateReadWriteMemory
1003//// | MiniDumpWithoutOptionalData
1004// | MiniDumpWithFullMemoryInfo
1005// | MiniDumpWithThreadInfo
1006// | MiniDumpWithCodeSegs
1007// | MiniDumpWithFullAuxiliaryState
1008// | MiniDumpWithPrivateWriteCopyMemory
1009// | MiniDumpIgnoreInaccessibleMemory
1010// | MiniDumpWithTokenInformation
1011//// | MiniDumpWithModuleHeaders
1012//// | MiniDumpFilterTriage
1013 ;
1014
1015
1016
1017#define VBOXMD_DUMP_DIR_DEFAULT "C:\\dumps"
1018#define VBOXMD_DUMP_NAME_PREFIX_W L"VBoxDmp_"
1019
1020static HMODULE loadSystemDll(const char *pszName)
1021{
1022#ifndef DEBUG
1023 char szPath[MAX_PATH];
1024 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
1025 size_t cbName = strlen(pszName) + 1;
1026 if (cchPath + 1 + cbName > sizeof(szPath))
1027 {
1028 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1029 return NULL;
1030 }
1031 szPath[cchPath] = '\\';
1032 memcpy(&szPath[cchPath + 1], pszName, cbName);
1033 return LoadLibraryA(szPath);
1034#else
1035 return LoadLibraryA(pszName);
1036#endif
1037}
1038
1039static DWORD vboxMdMinidumpCreate(struct _EXCEPTION_POINTERS *pExceptionInfo)
1040{
1041 WCHAR aszwMdFileName[MAX_PATH];
1042 HANDLE hProcess = GetCurrentProcess();
1043 DWORD ProcessId = GetCurrentProcessId();
1044 MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
1045 HANDLE hFile;
1046 DWORD winErr = ERROR_SUCCESS;
1047
1048 if (!g_pfnVBoxMdMiniDumpWriteDump)
1049 {
1050 if (!g_hVBoxMdDbgHelp)
1051 {
1052 g_hVBoxMdDbgHelp = loadSystemDll("DbgHelp.dll");
1053 if (!g_hVBoxMdDbgHelp)
1054 return GetLastError();
1055 }
1056
1057 g_pfnVBoxMdMiniDumpWriteDump = (PFNVBOXDBG_MINIDUMPWRITEDUMP)GetProcAddress(g_hVBoxMdDbgHelp, "MiniDumpWriteDump");
1058 if (!g_pfnVBoxMdMiniDumpWriteDump)
1059 return GetLastError();
1060 }
1061
1062 ++g_aszwVBoxMdDumpCount;
1063
1064 memcpy(aszwMdFileName, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen * sizeof (g_aszwVBoxMdFilePrefix[0]));
1065 swprintf(aszwMdFileName + g_cVBoxMdFilePrefixLen, RT_ELEMENTS(aszwMdFileName) - g_cVBoxMdFilePrefixLen, L"%d_%d.dmp", ProcessId, g_aszwVBoxMdDumpCount);
1066
1067 hFile = CreateFileW(aszwMdFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1068 if (hFile == INVALID_HANDLE_VALUE)
1069 return GetLastError();
1070
1071 ExceptionInfo.ThreadId = GetCurrentThreadId();
1072 ExceptionInfo.ExceptionPointers = pExceptionInfo;
1073 ExceptionInfo.ClientPointers = FALSE;
1074
1075 if (!g_pfnVBoxMdMiniDumpWriteDump(hProcess, ProcessId, hFile, g_enmVBoxMdDumpType, &ExceptionInfo, NULL, NULL))
1076 winErr = GetLastError();
1077
1078 CloseHandle(hFile);
1079 return winErr;
1080}
1081
1082LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
1083{
1084 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
1085 PCONTEXT pContextRecord = pExceptionInfo->ContextRecord;
1086 switch (pExceptionRecord->ExceptionCode)
1087 {
1088 case EXCEPTION_BREAKPOINT:
1089 case EXCEPTION_ACCESS_VIOLATION:
1090 case EXCEPTION_STACK_OVERFLOW:
1091 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1092 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1093 case EXCEPTION_FLT_INVALID_OPERATION:
1094 case EXCEPTION_INT_DIVIDE_BY_ZERO:
1095 case EXCEPTION_ILLEGAL_INSTRUCTION:
1096 if (g_VBoxVehFlags & VBOXVEH_F_BREAK)
1097 {
1098 BOOL fBreak = TRUE;
1099#ifndef DEBUG_misha
1100 if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
1101 {
1102 HANDLE hProcess = GetCurrentProcess();
1103 BOOL fDebuggerPresent = FALSE;
1104 /* we do not want to generate breakpoint exceptions recursively, so do it only when running under debugger */
1105 if (CheckRemoteDebuggerPresent(hProcess, &fDebuggerPresent))
1106 fBreak = !!fDebuggerPresent;
1107 else
1108 fBreak = FALSE; /* <- the function has failed, don't break for sanity */
1109 }
1110#endif
1111
1112 if (fBreak)
1113 {
1114 RT_BREAKPOINT();
1115 }
1116 }
1117
1118 if (g_VBoxVehFlags & VBOXVEH_F_DUMP)
1119 vboxMdMinidumpCreate(pExceptionInfo);
1120
1121 if (g_VBoxVehFlags & VBOXVEH_F_EXIT)
1122 exit(1);
1123 break;
1124 default:
1125 break;
1126 }
1127 return EXCEPTION_CONTINUE_SEARCH;
1128}
1129
1130void vboxVDbgVEHandlerRegister()
1131{
1132 CRASSERT(!g_VBoxVehHandler);
1133 g_VBoxVehHandler = AddVectoredExceptionHandler(1,vboxVDbgVectoredHandler);
1134 CRASSERT(g_VBoxVehHandler);
1135}
1136
1137void vboxVDbgVEHandlerUnregister()
1138{
1139 ULONG uResult;
1140 if (g_VBoxVehHandler)
1141 {
1142 uResult = RemoveVectoredExceptionHandler(g_VBoxVehHandler);
1143 CRASSERT(uResult);
1144 g_VBoxVehHandler = NULL;
1145 }
1146}
1147#endif
1148
1149/* Windows crap */
1150BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
1151{
1152 (void) lpvReserved;
1153
1154 switch (fdwReason)
1155 {
1156 case DLL_PROCESS_ATTACH:
1157 {
1158 CRNetServer ns;
1159 const char * env;
1160#if defined(DEBUG_misha)
1161 HMODULE hCrUtil;
1162 char aName[MAX_PATH];
1163
1164 GetModuleFileNameA(hDLLInst, aName, RT_ELEMENTS(aName));
1165 crDbgCmdSymLoadPrint(aName, hDLLInst);
1166#endif
1167
1168 int rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); CRASSERT(rc==0);
1169 rc = VbglR3Init();
1170
1171 crInitTSD(&g_stubCurrentContextTSD);
1172 crInitMutex(&stub_init_mutex);
1173
1174#ifdef VDBG_VEHANDLER
1175 env = RTEnvGet("CR_DBG_VEH_ENABLE");
1176 g_VBoxVehEnable = crStrParseI32(env,
1177# ifdef DEBUG_misha
1178 1
1179# else
1180 0
1181# endif
1182 );
1183
1184 if (g_VBoxVehEnable)
1185 {
1186 char procName[1024];
1187 size_t cProcName;
1188 size_t cChars;
1189
1190 env = RTEnvGet("CR_DBG_VEH_FLAGS");
1191 g_VBoxVehFlags = crStrParseI32(env,
1192 0
1193# ifdef DEBUG_misha
1194 | VBOXVEH_F_BREAK
1195# else
1196 | VBOXVEH_F_DUMP
1197# endif
1198 );
1199
1200 env = RTEnvGet("CR_DBG_VEH_DUMP_DIR");
1201 if (!env)
1202 env = VBOXMD_DUMP_DIR_DEFAULT;
1203
1204 g_cVBoxMdFilePrefixLen = strlen(env);
1205
1206 if (RT_ELEMENTS(g_aszwVBoxMdFilePrefix) <= g_cVBoxMdFilePrefixLen + 26 + (sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR)) / sizeof (WCHAR))
1207 {
1208 g_cVBoxMdFilePrefixLen = 0;
1209 env = "";
1210 }
1211
1212 mbstowcs_s(&cChars, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen + 1, env, _TRUNCATE);
1213
1214 Assert(cChars == g_cVBoxMdFilePrefixLen + 1);
1215
1216 g_cVBoxMdFilePrefixLen = cChars - 1;
1217
1218 if (g_cVBoxMdFilePrefixLen && g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen - 1] != L'\\')
1219 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen++] = L'\\';
1220
1221 memcpy(g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, VBOXMD_DUMP_NAME_PREFIX_W, sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR));
1222 g_cVBoxMdFilePrefixLen += (sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR)) / sizeof (WCHAR);
1223
1224 crGetProcName(procName, RT_ELEMENTS(procName));
1225 cProcName = strlen(procName);
1226
1227 if (RT_ELEMENTS(g_aszwVBoxMdFilePrefix) > g_cVBoxMdFilePrefixLen + cProcName + 1 + 26)
1228 {
1229 mbstowcs_s(&cChars, g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, cProcName + 1, procName, _TRUNCATE);
1230 Assert(cChars == cProcName + 1);
1231 g_cVBoxMdFilePrefixLen += cChars - 1;
1232 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen++] = L'_';
1233 }
1234
1235 /* sanity */
1236 g_aszwVBoxMdFilePrefix[g_cVBoxMdFilePrefixLen] = L'\0';
1237
1238 env = RTEnvGet("CR_DBG_VEH_DUMP_TYPE");
1239
1240 g_enmVBoxMdDumpType = crStrParseI32(env,
1241 MiniDumpNormal
1242 | MiniDumpWithDataSegs
1243 | MiniDumpWithFullMemory
1244 | MiniDumpWithHandleData
1245 //// | MiniDumpFilterMemory
1246 //// | MiniDumpScanMemory
1247 // | MiniDumpWithUnloadedModules
1248 //// | MiniDumpWithIndirectlyReferencedMemory
1249 //// | MiniDumpFilterModulePaths
1250 // | MiniDumpWithProcessThreadData
1251 // | MiniDumpWithPrivateReadWriteMemory
1252 //// | MiniDumpWithoutOptionalData
1253 // | MiniDumpWithFullMemoryInfo
1254 // | MiniDumpWithThreadInfo
1255 // | MiniDumpWithCodeSegs
1256 // | MiniDumpWithFullAuxiliaryState
1257 // | MiniDumpWithPrivateWriteCopyMemory
1258 // | MiniDumpIgnoreInaccessibleMemory
1259 // | MiniDumpWithTokenInformation
1260 //// | MiniDumpWithModuleHeaders
1261 //// | MiniDumpFilterTriage
1262 );
1263
1264 vboxVDbgVEHandlerRegister();
1265 }
1266#endif
1267
1268 crNetInit(NULL, NULL);
1269 ns.name = "vboxhgcm://host:0";
1270 ns.buffer_size = 1024;
1271 crNetServerConnect(&ns
1272#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1273 , NULL
1274#endif
1275);
1276 if (!ns.conn)
1277 {
1278 crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
1279#ifdef VDBG_VEHANDLER
1280 if (g_VBoxVehEnable)
1281 vboxVDbgVEHandlerUnregister();
1282#endif
1283 return FALSE;
1284 }
1285 else
1286 {
1287 crNetFreeConnection(ns.conn);
1288 }
1289
1290#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1291 VBoxCrHgsmiInit();
1292#endif
1293 break;
1294 }
1295
1296 case DLL_PROCESS_DETACH:
1297 {
1298 /* do exactly the same thing as for DLL_THREAD_DETACH since
1299 * DLL_THREAD_DETACH is not called for the thread doing DLL_PROCESS_DETACH according to msdn docs */
1300 stubSetCurrentContext(NULL);
1301 if (stub_initialized)
1302 {
1303 CRASSERT(stub.spu);
1304 stub.spu->dispatch_table.VBoxDetachThread();
1305 }
1306
1307
1308#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1309 VBoxCrHgsmiTerm();
1310#endif
1311
1312 stubSPUSafeTearDown();
1313 crFreeTSD(&g_stubCurrentContextTSD);
1314
1315#ifdef VDBG_VEHANDLER
1316 if (g_VBoxVehEnable)
1317 vboxVDbgVEHandlerUnregister();
1318#endif
1319 VbglR3Term();
1320 break;
1321 }
1322
1323 case DLL_THREAD_ATTACH:
1324 {
1325 if (stub_initialized)
1326 {
1327 CRASSERT(stub.spu);
1328 stub.spu->dispatch_table.VBoxAttachThread();
1329 }
1330 break;
1331 }
1332
1333 case DLL_THREAD_DETACH:
1334 {
1335 stubSetCurrentContext(NULL);
1336 if (stub_initialized)
1337 {
1338 CRASSERT(stub.spu);
1339 stub.spu->dispatch_table.VBoxDetachThread();
1340 }
1341 break;
1342 }
1343
1344 default:
1345 break;
1346 }
1347
1348 return TRUE;
1349}
1350#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