load.c revision 72b97769a3c9b22b4fb60fc0f30a1a82f5bbb6f5
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "cr_spu.h"
#include "cr_net.h"
#include "cr_error.h"
#include "cr_mem.h"
#include "cr_string.h"
#include "cr_net.h"
#include "cr_environment.h"
#include "cr_process.h"
#include "cr_rand.h"
#include "cr_netserver.h"
#include "stub.h"
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <iprt/initterm.h>
#ifndef WINDOWS
# include <unistd.h>
#endif
#ifdef VBOX_WITH_WDDM
#include <d3d9types.h>
#include <D3dumddi.h>
#endif
/**
* If you change this, see the comments in tilesortspu_context.c
*/
#define MAGIC_CONTEXT_BASE 500
#define CONFIG_LOOKUP_FILE ".crconfigs"
#ifdef WINDOWS
#define PYTHON_EXE "python.exe"
#else
#define PYTHON_EXE "python"
#endif
static bool stub_initialized = 0;
#ifdef WINDOWS
static CRmutex stub_init_mutex;
#else
#define STUB_INIT_LOCK() do { } while (0)
#define STUB_INIT_UNLOCK() do { } while (0)
#endif
/* NOTE: 'SPUDispatchTable glim' is declared in NULLfuncs.py now */
/* NOTE: 'SPUDispatchTable stubThreadsafeDispatch' is declared in tsfuncs.c */
#ifdef CHROMIUM_THREADSAFE
static bool g_stubIsCurrentContextTSDInited;
#endif
static void stubInitNativeDispatch( void )
{
#define MAX_FUNCS 1000
int numFuncs;
/* XXX call this after context binding */
}
/** Pointer to the SPU's real glClear and glViewport functions */
static ClearFunc_t origClear;
static ViewportFunc_t origViewport;
static SwapBuffersFunc_t origSwapBuffers;
static DrawBufferFunc_t origDrawBuffer;
static ScissorFunc_t origScissor;
{
bool bForceUpdate = false;
bool bChanged = false;
#ifdef WINDOWS
/* @todo install hook and track for WM_DISPLAYCHANGE */
{
{
crDebug("Resolution changed(%d,%d), forcing window Pos/Size update", devMode.dmPelsWidth, devMode.dmPelsHeight);
bForceUpdate = true;
}
}
#endif
{
}
#endif
bChanged = true;
}
}
if (bFlushOnChange && bChanged)
{
}
}
{
#ifdef WINDOWS
{
return false;
}
#else
int x, y;
{
return false;
}
#endif
return true;
}
{
{
return;
}
if (!stubSystemWindowExist(pWindow))
{
#ifdef WINDOWS
#else
#endif
return;
}
}
static void stubCheckWindowsState(void)
{
if (!context)
return;
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
if (stub.bRunningUnderWDDM)
return;
#endif
/* Try to keep a consistent locking order. */
#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
#endif
#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
#endif
}
/**
* Override the head SPU's glClear function.
* We're basically trapping this function so that we can poll the
* application window size at a regular interval.
*/
{
/* call the original SPU glClear function */
}
/**
* As above, but for glViewport. Most apps call glViewport before
* glClear when a window is resized.
*/
{
/* call the original SPU glViewport function */
origViewport(x, y, w, h);
}
{
}
{
}
{
}
/**
* Use the GL function pointers in <spu> to initialize the static glim
* dispatch table.
*/
{
/*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
}
}
// Callback function, used to destroy all created contexts
{
}
/**
* This is called when we exit.
* We call all the SPU's cleanup functions.
*/
static void stubSPUTearDownLocked(void)
{
crDebug("stubSPUTearDownLocked");
#ifdef WINDOWS
# ifndef CR_NEWWINTRACK
# endif
#endif
#ifdef CR_NEWWINTRACK
#endif
//delete all created contexts
/* the lock order is windowTable->contextTable (see wglMakeCurrent_prox, glXMakeCurrent)
* this is why we need to take a windowTable lock since we will later do stub.windowTable access & locking */
/* shutdown, now trap any calls to a NULL dispatcher */
#ifndef Linux
#endif
#ifndef WINDOWS
#endif
#ifdef GLX
{
}
#endif
}
/**
* This is called when we exit.
* We call all the SPU's cleanup functions.
*/
static void stubSPUTearDown(void)
{
if (stub_initialized)
{
stub_initialized = 0;
}
}
static void stubSPUSafeTearDown(void)
{
#ifdef CHROMIUM_THREADSAFE
#endif
if (!stub_initialized) return;
stub_initialized = 0;
#ifdef CHROMIUM_THREADSAFE
#endif
crDebug("stubSPUSafeTearDown");
#ifdef WINDOWS
# ifndef CR_NEWWINTRACK
# endif
#endif
#if defined(CR_NEWWINTRACK)
# if defined(WINDOWS)
{
if (!hNative)
{
}
else
{
}
{
/*Same issue as on linux, RTThreadWait exits before system thread is terminated, which leads
* to issues as our dll goes to be unloaded.
*@todo
*We usually call this function from DllMain which seems to be holding some lock and thus we have to
* kill thread via TerminateThread.
*/
{
crDebug("Wait failed, terminating");
{
crDebug("TerminateThread failed");
}
}
{
}
else
{
}
}
else
{
crDebug("Sync thread killed before DLL_PROCESS_DETACH");
}
if (hNative)
{
}
}
#else
{
{
if (RT_FAILURE(rc))
{
}
}
}
#endif
#endif
#ifndef WINDOWS
#endif
#ifdef CHROMIUM_THREADSAFE
#endif
}
static void stubExitHandler(void)
{
}
/**
* Called when we receive a SIGTERM signal.
*/
static void stubSignalHandler(int signo)
{
exit(0); /* this causes stubExitHandler() to be called */
}
#ifndef RT_OS_WINDOWS
# ifdef CHROMIUM_THREADSAFE
{
}
# endif
#endif
/**
* Init variables in the stub structure, install signal handler.
*/
static void stubInitVars(void)
{
#ifdef CHROMIUM_THREADSAFE
#endif
/* At the very least we want CR_RGB_BIT. */
stub.appDrawCursor = 0;
stub.ignoreFreeglutMenus = 0;
stub.trackWindowSize = 0;
stub.trackWindowPos = 0;
stub.mothershipPID = 0;
#ifndef RT_OS_WINDOWS
# ifdef CHROMIUM_THREADSAFE
{
g_stubIsCurrentContextTSDInited = true;
}
# endif
#endif
#ifdef CR_NEWWINTRACK
stub.bShutdownSyncThread = false;
#endif
#ifdef WINDOWS
defaultWin->cVisibleRegions = 0;
#endif
#if 1
#ifndef WINDOWS
#endif
#else
(void) stubExitHandler;
(void) stubSignalHandler;
#endif
}
/**
* Return a free port number for the mothership to use, or -1 if we
* can't find one.
*/
static int
GenerateMothershipPort(void)
{
const int MAX_PORT = 10100;
unsigned short port;
/* generate initial port number randomly */
#ifdef WINDOWS
/* XXX should implement a free port check here */
return port;
#else
/*
* See if this port number really is free, try another if needed.
*/
{
struct sockaddr_in servaddr;
int so_reuseaddr = 1;
int sock, k;
/* create socket */
(char *) &so_reuseaddr, sizeof(so_reuseaddr));
CRASSERT(k == 0);
/* initialize the servaddr struct */
/* Bind to the given port number, return -1 if we fail */
if (k) {
/* failed to create port. try next one. */
port++;
}
else {
return port;
}
}
}
#endif /* WINDOWS */
return -1;
}
/**
* Try to determine which mothership configuration to use for this program.
*/
static char **
LookupMothershipConfig(const char *procName)
{
FILE *f;
const char *home;
char configPath[1000];
/* first, check if the CR_CONFIG env var is set */
{
}
/* second, look up config name from config file */
if (home)
else
/* Check if the CR_CONFIG_PATH env var is set. */
{
if (conf)
}
if (!f) {
return NULL;
}
while (!feof(f)) {
char line[1000];
char **args;
{
crWarning("Using Chromium configuration for %s from %s",
return args;
}
}
fclose(f);
return NULL;
}
static int Mothership_Awake = 0;
/**
* Signal handler to determine when mothership is ready.
*/
static void
MothershipPhoneHome(int signo)
{
Mothership_Awake = 1;
}
void stubSetDefaultConfigurationOptions(void)
{
unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
stub.appDrawCursor = 0;
stub.numIgnoreWindowID = 0;
stub.ignoreFreeglutMenus = 0;
crNetSetRank(0);
stub.force_pbuffers = 0;
#ifdef WINDOWS
# ifdef VBOX_WITH_WDDM
stub.bRunningUnderWDDM = false;
# endif
#endif
}
#ifdef CR_NEWWINTRACK
# ifdef VBOX_WITH_WDDM
{
if (lpRgnData)
{
crDebug("Dispatched WindowVisibleRegion (%i, cRects=%i)", pWindow->spuWindow, lpRgnData->rdh.nCount);
stub.spuDispatch.WindowVisibleRegion(pWindow->spuWindow, lpRgnData->rdh.nCount, (GLint*) lpRgnData->Buffer);
}
else crWarning("GetRegionData failed, VisibleRegions update failed");
}
{
uint32_t i;
{
return INVALID_HANDLE_VALUE;
}
hRgn = CreateRectRgn(0, 0, 0, 0);
{
}
return hRgn;
}
# endif /* VBOX_WITH_WDDM */
{
(void) data2;
{
return;
}
if (!stubSystemWindowExist(pWindow))
{
#ifdef WINDOWS
#else
#endif
/*No need to flush here as crWindowDestroy does it*/
return;
}
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
if (stub.bRunningUnderWDDM)
return;
#endif
}
{
#ifdef WINDOWS
# ifdef VBOX_WITH_WDDM
GLint spuConnection = 0;
# endif
#endif
(void) pvUser;
crDebug("Sync thread started");
#ifdef WINDOWS
# ifdef VBOX_WITH_WDDM
{
}
if (hVBoxD3D)
{
stub.bRunningUnderWDDM = true;
}
# endif /* VBOX_WITH_WDDM */
#endif /* WINDOWS */
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
#endif
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
{
crError("VBoxPackSetInjectThread failed!");
}
#endif
while(!stub.bShutdownSyncThread)
{
#ifdef WINDOWS
{
# ifdef VBOX_WITH_WDDM
if (stub.bRunningUnderWDDM)
{
}
else
# endif
{
RTThreadSleep(50);
}
}
else
{
{
crDebug("Sync thread got WM_QUIT");
break;
}
else
{
}
}
#else
/* Try to keep a consistent locking order. */
RTThreadSleep(50);
#endif
}
#ifdef VBOX_WITH_WDDM
if (spuConnection)
{
}
if (hVBoxD3D)
{
}
#endif
crDebug("Sync thread stopped");
return 0;
}
#endif /* CR_NEWWINTRACK */
/**
* Do one-time initializations for the faker.
* Returns TRUE on success, FALSE otherwise.
*/
static bool
stubInitLocked(void)
{
/* Here is where we contact the mothership to find out what we're supposed
* to be doing. Networking code in a DLL initializer. I sure hope this
* works :)
*
* HOW can I pass the mothership address to this if I already know it?
*/
char response[1024];
char **spuchain;
int num_spus;
int *spu_ids;
char **spu_names;
const char *app_id;
int i;
int disable_sync = 0;
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
#endif
stubInitVars();
#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
/*@todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread
* as at the start compiz runs our code under XGrabServer.
*/
if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real") || !crStrcmp(response, "compiz.real")
{
disable_sync = 1;
}
#endif
/* @todo check if it'd be of any use on other than guests, no use for windows */
#ifndef WINDOWS
{
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
, NULL
#endif
);
{
crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM.");
return false;
}
else
{
}
}
#endif
for (i = 0 ; i < num_spus ; i++)
{
}
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
{
}
if (hVBoxD3D)
{
disable_sync = 1;
/* @todo: should we enable that? */
stub.trackWindowSize = 0;
stub.trackWindowPos = 0;
stub.bRunningUnderWDDM = true;
}
#endif
for (i = 0; i < num_spus; ++i)
// spu chain load failed somewhere
return false;
}
/* This is unlikely to change -- We still want to initialize our dispatch
* table with the functions of the first SPU in the chain. */
/* we need to plug one special stub function into the dispatch table */
#if !defined(VBOX_NO_NATIVEGL)
/* Load pointers to native OpenGL functions into stub.nativeDispatch */
#endif
/*crDebug("stub init");
raise(SIGINT);*/
#ifdef WINDOWS
# ifndef CR_NEWWINTRACK
# endif
#endif
#ifdef CR_NEWWINTRACK
{
int rc;
if (!disable_sync)
{
crDebug("Starting sync thread");
rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync");
if (RT_FAILURE(rc))
{
}
crDebug("Going on");
}
}
#endif
#ifdef GLX
#endif
return true;
}
/**
* Do one-time initializations for the faker.
* Returns TRUE on success, FALSE otherwise.
*/
bool
stubInit(void)
{
bool bRc = true;
/* we need to serialize the initialization, otherwise racing is possible
* for XPDM-based d3d when a d3d switcher is testing the gl lib in two or more threads
* NOTE: the STUB_INIT_LOCK/UNLOCK is a NOP for non-win currently */
if (!stub_initialized)
return bRc;
}
/* Sigh -- we can't do initialization at load time, since Windows forbids
* the loading of other libraries from DLLMain. */
#ifdef LINUX
/* GCC crap
*void (*stub_init_ptr)(void) __attribute__((section(".ctors"))) = __stubInit; */
#endif
#ifdef WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if 1//def DEBUG_misha
/* debugging: this is to be able to catch first-chance notifications
* for exceptions other than EXCEPTION_BREAKPOINT in kernel debugger */
# define VDBG_VEHANDLER
#endif
#ifdef VDBG_VEHANDLER
# include <dbghelp.h>
# include <cr_string.h>
static DWORD g_VBoxVehEnable = 0;
/* generate a crash dump on exception */
#define VBOXVEH_F_DUMP 0x00000001
/* generate a debugger breakpoint exception */
#define VBOXVEH_F_BREAK 0x00000002
/* exit on exception */
#define VBOXVEH_F_EXIT 0x00000004
static DWORD g_VBoxVehFlags = 0;
static size_t g_cVBoxMdFilePrefixLen = 0;
static WCHAR g_aszwVBoxMdDumpCount = 0;
//// | MiniDumpFilterMemory
//// | MiniDumpScanMemory
// | MiniDumpWithUnloadedModules
//// | MiniDumpWithIndirectlyReferencedMemory
//// | MiniDumpFilterModulePaths
// | MiniDumpWithProcessThreadData
// | MiniDumpWithPrivateReadWriteMemory
//// | MiniDumpWithoutOptionalData
// | MiniDumpWithFullMemoryInfo
// | MiniDumpWithThreadInfo
// | MiniDumpWithCodeSegs
// | MiniDumpWithFullAuxiliaryState
// | MiniDumpWithPrivateWriteCopyMemory
// | MiniDumpIgnoreInaccessibleMemory
// | MiniDumpWithTokenInformation
//// | MiniDumpWithModuleHeaders
//// | MiniDumpFilterTriage
;
#define VBOXMD_DUMP_DIR_DEFAULT "C:\\dumps"
#define VBOXMD_DUMP_NAME_PREFIX_W L"VBoxDmp_"
{
{
return NULL;
}
return LoadLibraryA(szPath);
}
{
{
if (!g_hVBoxMdDbgHelp)
{
if (!g_hVBoxMdDbgHelp)
return GetLastError();
}
g_pfnVBoxMdMiniDumpWriteDump = (PFNVBOXDBG_MINIDUMPWRITEDUMP)GetProcAddress(g_hVBoxMdDbgHelp, "MiniDumpWriteDump");
return GetLastError();
}
memcpy(aszwMdFileName, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen * sizeof (g_aszwVBoxMdFilePrefix[0]));
swprintf(aszwMdFileName + g_cVBoxMdFilePrefixLen, RT_ELEMENTS(aszwMdFileName) - g_cVBoxMdFilePrefixLen, L"%d_%d.dmp", ProcessId, g_aszwVBoxMdDumpCount);
hFile = CreateFileW(aszwMdFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
if (!g_pfnVBoxMdMiniDumpWriteDump(hProcess, ProcessId, hFile, g_enmVBoxMdDumpType, &ExceptionInfo, NULL, NULL))
winErr = GetLastError();
return winErr;
}
{
switch (pExceptionRecord->ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
case EXCEPTION_STACK_OVERFLOW:
if (g_VBoxVehFlags & VBOXVEH_F_BREAK)
{
#ifndef DEBUG_misha
{
/* we do not want to generate breakpoint exceptions recursively, so do it only when running under debugger */
fBreak = !!fDebuggerPresent;
else
}
#endif
if (fBreak)
{
}
}
if (g_VBoxVehFlags & VBOXVEH_F_DUMP)
if (g_VBoxVehFlags & VBOXVEH_F_EXIT)
exit(1);
break;
default:
break;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void vboxVDbgVEHandlerRegister()
{
}
void vboxVDbgVEHandlerUnregister()
{
if (g_VBoxVehHandler)
{
}
}
#endif
/* Windows crap */
{
(void) lpvReserved;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
const char * env;
#if defined(DEBUG_misha)
#endif
#ifdef CHROMIUM_THREADSAFE
#endif
#ifdef VDBG_VEHANDLER
# ifdef DEBUG_misha
1
# else
0
# endif
);
if (g_VBoxVehEnable)
{
char procName[1024];
0
# ifdef DEBUG_misha
# else
# endif
);
if (!env)
if (RT_ELEMENTS(g_aszwVBoxMdFilePrefix) <= g_cVBoxMdFilePrefixLen + 26 + (sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR)) / sizeof (WCHAR))
{
env = "";
}
memcpy(g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, VBOXMD_DUMP_NAME_PREFIX_W, sizeof (VBOXMD_DUMP_NAME_PREFIX_W) - sizeof (WCHAR));
{
mbstowcs_s(&cChars, g_aszwVBoxMdFilePrefix + g_cVBoxMdFilePrefixLen, cProcName + 1, procName, _TRUNCATE);
}
/* sanity */
//// | MiniDumpFilterMemory
//// | MiniDumpScanMemory
// | MiniDumpWithUnloadedModules
//// | MiniDumpWithIndirectlyReferencedMemory
//// | MiniDumpFilterModulePaths
// | MiniDumpWithProcessThreadData
// | MiniDumpWithPrivateReadWriteMemory
//// | MiniDumpWithoutOptionalData
// | MiniDumpWithFullMemoryInfo
// | MiniDumpWithThreadInfo
// | MiniDumpWithCodeSegs
// | MiniDumpWithFullAuxiliaryState
// | MiniDumpWithPrivateWriteCopyMemory
// | MiniDumpIgnoreInaccessibleMemory
// | MiniDumpWithTokenInformation
//// | MiniDumpWithModuleHeaders
//// | MiniDumpFilterTriage
);
}
#endif
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
, NULL
#endif
);
{
crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
#ifdef VDBG_VEHANDLER
if (g_VBoxVehEnable)
#endif
return FALSE;
}
else
{
}
break;
}
case DLL_PROCESS_DETACH:
{
/* do exactly the same thing as for DLL_THREAD_DETACH since
* DLL_THREAD_DETACH is not called for the thread doing DLL_PROCESS_DETACH according to msdn docs */
if (stub_initialized)
{
}
#ifdef CHROMIUM_THREADSAFE
#endif
#ifdef VDBG_VEHANDLER
if (g_VBoxVehEnable)
#endif
break;
}
case DLL_THREAD_ATTACH:
{
if (stub_initialized)
{
}
break;
}
case DLL_THREAD_DETACH:
{
if (stub_initialized)
{
}
break;
}
default:
break;
}
return TRUE;
}
#endif