mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-31 00:15:55 -04:00
again, re-add some windows stuff Revert "possibly controversial commit: remove all windows sources, keeping only the windows cmake so that we can generate an sln to edit the code"
This reverts commit 48ba7961eb.
This commit is contained in:
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#ifndef BASE_WIN32_ARCHIVE_H
|
||||
#define BASE_WIN32_ARCHIVE_H
|
||||
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
namespace NAMESPACE
|
||||
{
|
||||
|
||||
#endif
|
||||
namespace Base
|
||||
{
|
||||
|
||||
|
||||
#ifdef PACK_BIG_ENDIAN
|
||||
|
||||
inline double byteSwap(double value) { byteReverse64(&value); return value; }
|
||||
inline float byteSwap(float value) { byteReverse32(&value); return value; }
|
||||
inline uint64 byteSwap(uint64 value) { byteReverse64(&value); return value; }
|
||||
inline int64 byteSwap(int64 value) { byteReverse64(&value); return value; }
|
||||
inline uint32 byteSwap(uint32 value) { byteReverse32(&value); return value; }
|
||||
inline int32 byteSwap(int32 value) { byteReverse32(&value); return value; }
|
||||
inline uint16 byteSwap(uint16 value) { byteReverse16(&value); return value; }
|
||||
inline int16 byteSwap(int16 value) { byteReverse16(&value); return value; }
|
||||
|
||||
#else
|
||||
|
||||
inline double byteSwap(double value) { return value; }
|
||||
inline float byteSwap(float value) { return value; }
|
||||
inline uint64 byteSwap(uint64 value) { return value; }
|
||||
inline int64 byteSwap(int64 value) { return value; }
|
||||
inline uint32 byteSwap(uint32 value) { return value; }
|
||||
inline int32 byteSwap(int32 value) { return value; }
|
||||
inline uint16 byteSwap(uint16 value) { return value; }
|
||||
inline int16 byteSwap(int16 value) { return value; }
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
////////////////////////////////////////
|
||||
// Platform.cpp
|
||||
//
|
||||
// Purpose:
|
||||
// 1. Implementation of the global functionality declaired in Platform.h.
|
||||
//
|
||||
// Revisions:
|
||||
// 07/10/2001 Created
|
||||
//
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
namespace NAMESPACE
|
||||
{
|
||||
|
||||
#endif
|
||||
namespace Base
|
||||
{
|
||||
|
||||
|
||||
CTimer::CTimer() :
|
||||
mTimer(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
};
|
||||
#endif
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
////////////////////////////////////////
|
||||
// Platform.h
|
||||
//
|
||||
// Purpose:
|
||||
// 1. Include relevent system headers that are platform specific.
|
||||
// 2. Declair global platform specific functionality.
|
||||
// 3. Include primative type definitions
|
||||
//
|
||||
// Global Functions:
|
||||
// getTimer() : Return the current high resolution clock count.
|
||||
// getTimerFrequency() : Return the frequency of the high resolution clock.
|
||||
// sleep() : Voluntarily relinquish timeslice of the calling thread for a
|
||||
// specified number of milliseconds.
|
||||
//
|
||||
// Revisions:
|
||||
// 07/10/2001 Created
|
||||
//
|
||||
|
||||
#ifndef BASE_WIN32_PLATFORM_H
|
||||
#define BASE_WIN32_PLATFORM_H
|
||||
|
||||
#include <memory.h>
|
||||
#include <winsock2.h>
|
||||
#include <time.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
namespace NAMESPACE
|
||||
{
|
||||
|
||||
#endif
|
||||
namespace Base
|
||||
{
|
||||
|
||||
uint64 getTimer(void);
|
||||
uint64 getTimerFrequency(void);
|
||||
|
||||
inline uint64 getTimer(void)
|
||||
{
|
||||
uint64 result;
|
||||
if (!QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&result)))
|
||||
result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint64 getTimerFrequency(void)
|
||||
{
|
||||
uint64 result;
|
||||
if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&result)))
|
||||
result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void sleep(uint32 ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
|
||||
class CTimer
|
||||
{
|
||||
public:
|
||||
CTimer();
|
||||
|
||||
void Set(uint32 seconds);
|
||||
void Signal();
|
||||
bool Expired();
|
||||
|
||||
private:
|
||||
uint32 mTimer;
|
||||
};
|
||||
|
||||
inline void CTimer::Set(uint32 interval)
|
||||
{
|
||||
mTimer = (uint32)time(0) + interval;
|
||||
}
|
||||
|
||||
inline void CTimer::Signal()
|
||||
{
|
||||
mTimer = 0;
|
||||
}
|
||||
|
||||
inline bool CTimer::Expired()
|
||||
{
|
||||
return (mTimer <= (uint32)time(0));
|
||||
}
|
||||
};
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#endif BASE_WIN32_PLATFORM_H
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
////////////////////////////////////////
|
||||
// Types.h
|
||||
//
|
||||
// Purpose:
|
||||
// 1. Define integer types that are unambiguous with respect to size
|
||||
//
|
||||
// Revisions:
|
||||
// 07/10/2001 Created
|
||||
//
|
||||
|
||||
#ifndef BASE_WIN32_TYPES_H
|
||||
#define BASE_WIN32_TYPES_H
|
||||
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
namespace NAMESPACE
|
||||
{
|
||||
|
||||
#endif
|
||||
namespace Base
|
||||
{
|
||||
|
||||
#define INT32_MAX 0x7FFFFFFF
|
||||
#define INT32_MIN 0x80000000
|
||||
#define UINT32_MAX 0xFFFFFFFF
|
||||
|
||||
typedef signed char int8;
|
||||
typedef unsigned char uint8;
|
||||
typedef short int16;
|
||||
typedef unsigned short uint16;
|
||||
|
||||
typedef int int32;
|
||||
typedef unsigned uint32;
|
||||
typedef __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
|
||||
};
|
||||
#ifdef EXTERNAL_DISTRO
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // BASE_WIN32_TYPES_H
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "FirstCommodityServer.h"
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedCompression/SetupSharedCompression.h"
|
||||
#include "sharedDebug/SetupSharedDebug.h"
|
||||
#include "sharedFile/TreeFile.h"
|
||||
#include "sharedFile/SetupSharedFile.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedFoundation/SetupSharedFoundation.h"
|
||||
#include "sharedGame/CommoditiesAdvancedSearchAttribute.h"
|
||||
#include "sharedGame/ConfigSharedGame.h"
|
||||
#include "sharedNetwork/SetupSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include "sharedNetworkMessages/SetupSharedNetworkMessages.h"
|
||||
#include "sharedThread/SetupSharedThread.h"
|
||||
#include "sharedUtility/DataTableManager.h"
|
||||
#include "CommodityServer.h"
|
||||
#include "ConfigCommodityServer.h"
|
||||
#include "LocalizationManager.h"
|
||||
#include "UnicodeUtils.h"
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
SetupSharedThread::install();
|
||||
SetupSharedDebug::install(1024);
|
||||
|
||||
//-- setup foundation
|
||||
SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game);
|
||||
|
||||
setupFoundationData.argc = argc;
|
||||
setupFoundationData.argv = argv;
|
||||
setupFoundationData.createWindow = false;
|
||||
setupFoundationData.clockUsesSleep = true;
|
||||
SetupSharedFoundation::install (setupFoundationData);
|
||||
|
||||
ConfigSharedGame::install();
|
||||
SetupSharedCompression::install();
|
||||
SetupSharedFile::install(false);
|
||||
SetupSharedNetworkMessages::install();
|
||||
|
||||
SetupSharedNetwork::SetupData networkSetupData;
|
||||
SetupSharedNetwork::getDefaultServerSetupData(networkSetupData);
|
||||
SetupSharedNetwork::install(networkSetupData);
|
||||
NetworkHandler::install();
|
||||
|
||||
ConfigCommodityServer::install();
|
||||
|
||||
const bool displayBadStringIds = ConfigSharedGame::getDisplayBadStringIds ();
|
||||
const bool debugStringIds = ConfigSharedGame::getDebugStringIds ();
|
||||
Unicode::NarrowString defaultLocale(ConfigSharedGame::getDefaultLocale ());
|
||||
Unicode::UnicodeNarrowStringVector localeVector;
|
||||
localeVector.push_back(defaultLocale);
|
||||
|
||||
LocalizationManager::install (new TreeFile::TreeFileFactory, localeVector, debugStringIds, NULL, displayBadStringIds);
|
||||
ExitChain::add(LocalizationManager::remove, "LocalizationManager::remove");
|
||||
|
||||
DataTableManager::install();
|
||||
CommoditiesAdvancedSearchAttribute::install();
|
||||
|
||||
//-- run server
|
||||
SetupSharedFoundation::callbackWithExceptionHandling(CommodityServer::run);
|
||||
|
||||
SetupSharedFoundation::remove();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -0,0 +1,60 @@
|
||||
// main.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "FirstTransferServer.h"
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedCompression/SetupSharedCompression.h"
|
||||
#include "sharedDebug/SetupSharedDebug.h"
|
||||
#include "sharedFile/SetupSharedFile.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedFoundation/SetupSharedFoundation.h"
|
||||
#include "sharedNetwork/SetupSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include "sharedNetworkMessages/SetupSharedNetworkMessages.h"
|
||||
#include "sharedThread/SetupSharedThread.h"
|
||||
#include "TransferServer.h"
|
||||
#include "ConfigTransferServer.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
SetupSharedThread::install();
|
||||
SetupSharedDebug::install(1024);
|
||||
|
||||
//-- setup foundation
|
||||
SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game);
|
||||
|
||||
setupFoundationData.argc = argc;
|
||||
setupFoundationData.argv = argv;
|
||||
setupFoundationData.createWindow = true;
|
||||
SetupSharedFoundation::install (setupFoundationData);
|
||||
|
||||
SetupSharedCompression::install();
|
||||
SetupSharedFile::install(false);
|
||||
SetupSharedNetworkMessages::install();
|
||||
|
||||
SetupSharedNetwork::SetupData networkSetupData;
|
||||
SetupSharedNetwork::getDefaultServerSetupData(networkSetupData);
|
||||
SetupSharedNetwork::install(networkSetupData);
|
||||
NetworkHandler::install();
|
||||
|
||||
//Os::setProgramName("TransferServer");
|
||||
ConfigTransferServer::install();
|
||||
|
||||
//-- run server
|
||||
SetupSharedFoundation::callbackWithExceptionHandling(TransferServer::run);
|
||||
|
||||
NetworkHandler::remove();
|
||||
SetupSharedFoundation::remove();
|
||||
SetupSharedThread::remove();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstServerDatabase.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "serverDatabase/FirstServerDatabase.h"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstServerGame.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "serverGame/FirstServerGame.h"
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstServerKeyShare.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "serverKeyShare/FirstServerKeyShare.h"
|
||||
@@ -0,0 +1,9 @@
|
||||
// FirstServerMetrics.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "serverMetrics/FirstServerMetrics.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
#include "serverNetworkMessages/FirstServerNetworkMessages.h"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstServerPathfinding.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "serverPathfinding/FirstServerPathfinding.h"
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "serverScript/FirstServerScript.h"
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "serverUtility/FirstServerUtility.h"
|
||||
+1
@@ -0,0 +1 @@
|
||||
#include "FirstTemplateCompiler.h"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#include "sharedFoundationTypes/FoundationTypes.h"
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
#include "FirstTemplateDefinitionCompiler.h"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#include "sharedFoundationTypes/FoundationTypes.h"
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstSharedCollision.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedCollision/FirstSharedCollision.h"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstCommandParser.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedCommandParser/FirstSharedCommandParser.h"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstCompression.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedCompression/FirstSharedCompression.h"
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstServerDatabaseInterface.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDatabaseInterface/FirstSharedDatabaseInterface.h"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SQLC_Defs.h
|
||||
*
|
||||
* This file includes common definitions needed by the other SQLClasses header files.
|
||||
* (Don't include this file directly -- files that require it will include it.)
|
||||
*
|
||||
* Note that this file is specific to each OS, because what header files are
|
||||
* needed varies in each OS. In particular, Unix versions don't want windows.h.
|
||||
*
|
||||
* ODBC versions: includes definitions of ODBC datatypes needed by the various
|
||||
* SQLClasses
|
||||
*/
|
||||
|
||||
#ifndef _SQLC_DEFS_H
|
||||
#define _SQLC_DEFS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <sqltypes.h>
|
||||
|
||||
#endif
|
||||
+670
@@ -0,0 +1,670 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugHelp.cpp
|
||||
// copyright 2000 Verant Interactive
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/DebugHelp.h"
|
||||
|
||||
#include "sharedFoundation/WindowsWrapper.h"
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
|
||||
// ======================================================================
|
||||
// This was done to keep the header file from having to include <windows.h> or <dbghelp.h>
|
||||
|
||||
namespace DebugHelpNamespace
|
||||
{
|
||||
static HINSTANCE library;
|
||||
static HANDLE process;
|
||||
|
||||
struct CallbackData
|
||||
{
|
||||
const char *name;
|
||||
bool loaded;
|
||||
};
|
||||
|
||||
typedef DWORD (__stdcall *SymSetOptionsFP)(IN DWORD SymOptions);
|
||||
typedef BOOL (__stdcall *SymInitializeFP)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
|
||||
typedef BOOL (__stdcall *SymCleanupFP)(IN HANDLE hProcess);
|
||||
|
||||
typedef BOOL (__stdcall *StackWalk64FP)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
||||
typedef BOOL (__stdcall *SymGetModuleInfo64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PIMAGEHLP_MODULE64 ModuleInfo);
|
||||
typedef DWORD64 (__stdcall *SymLoadModule64FP)(IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
|
||||
typedef BOOL (__stdcall *SymGetSymFromAddr64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol);
|
||||
typedef BOOL (__stdcall *SymGetLineFromAddr64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line);
|
||||
typedef PVOID (__stdcall *SymFunctionTableAccess64FP)(HANDLE hProcess, DWORD64 AddrBase);
|
||||
typedef DWORD64 (__stdcall *SymGetModuleBase64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr);
|
||||
typedef BOOL (__stdcall *SymEnumerateModules64FP)(HANDLE hProcess, PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback, PVOID UserContext);
|
||||
typedef BOOL (__stdcall *EnumerateLoadedModules64FP)(IN HANDLE hProcess, IN PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, IN PVOID UserContext);
|
||||
typedef BOOL (__stdcall *MiniDumpWriteDumpFP)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
static SymSetOptionsFP symSetOptions;
|
||||
static SymInitializeFP symInitialize;
|
||||
static SymCleanupFP symCleanup;
|
||||
static StackWalk64FP stackWalk64;
|
||||
static SymGetModuleInfo64FP symGetModuleInfo64;
|
||||
static SymLoadModule64FP symLoadModule64;
|
||||
static SymGetSymFromAddr64FP symGetSymFromAddr64;
|
||||
static SymGetLineFromAddr64FP symGetLineFromAddr64;
|
||||
static SymFunctionTableAccess64FP symFunctionTableAccess64;
|
||||
static SymGetModuleBase64FP symGetModuleBase64;
|
||||
static SymEnumerateModules64FP symEnumerateModules64;
|
||||
static EnumerateLoadedModules64FP enumerateLoadedModules64;
|
||||
static MiniDumpWriteDumpFP miniDumpWriteDump;
|
||||
static CRITICAL_SECTION criticalSection;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//BOOL CALLBACK loadSymbolsForDllCallback(PTSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
|
||||
typedef unsigned char ub1; /* unsigned 1-byte quantities */
|
||||
|
||||
#define hashsize(n) ((ub4)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
For every delta with one or two bits set, and the deltas of all three
|
||||
high bits or all three low bits, whether the original value of a,b,c
|
||||
is almost all zero or is uniformly distributed,
|
||||
* If mix() is run forward or backward, at least 32 bits in a,b,c
|
||||
have at least 1/4 probability of changing.
|
||||
* If mix() is run forward, every bit of c will change between 1/3 and
|
||||
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
|
||||
mix() was built out of 36 single-cycle latency instructions in a
|
||||
structure that could supported 2x parallelism, like so:
|
||||
a -= b;
|
||||
a -= c; x = (c>>13);
|
||||
b -= c; a ^= x;
|
||||
b -= a; x = (a<<8);
|
||||
c -= a; b ^= x;
|
||||
c -= b; x = (b>>13);
|
||||
...
|
||||
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
|
||||
of that parallelism. They've also turned some of those single-cycle
|
||||
latency instructions into multi-cycle latency instructions. Still,
|
||||
this is the fastest good hash I could find. There were about 2^^68
|
||||
to choose from. I only looked at a billion or so.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
hash() -- hash a variable-length key into a 32-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
len : the length of the key, counting by bytes
|
||||
initval : can be any 4-byte value
|
||||
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||
the return value. Every 1-bit and 2-bit delta achieves avalanche.
|
||||
About 6*len+35 instructions.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (ub1 **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, 1996. [email protected]. You may use this
|
||||
code any way you wish, private, educational, or commercial. It's free.
|
||||
|
||||
See http://burtleburtle.net/bob/hash/evahash.html
|
||||
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||
acceptable. Do NOT use for cryptographic purposes.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// k; /* the key */
|
||||
// length; /* the length of the key */
|
||||
// initval; /* the previous hash, or an arbitrary value */
|
||||
#if 0
|
||||
static ub4 hash(ub1 *k, const ub4 length, const ub4 initval)
|
||||
{
|
||||
ub4 a, b, c, len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = initval; /* the previous hash value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 12)
|
||||
{
|
||||
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
|
||||
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
|
||||
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
|
||||
mix(a,b,c);
|
||||
k += 12; len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += length;
|
||||
switch(len) /* all the case statements fall through */
|
||||
{
|
||||
case 11: c+=((ub4)k[10]<<24);
|
||||
case 10: c+=((ub4)k[9]<<16);
|
||||
case 9 : c+=((ub4)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((ub4)k[7]<<24);
|
||||
case 7 : b+=((ub4)k[6]<<16);
|
||||
case 6 : b+=((ub4)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((ub4)k[3]<<24);
|
||||
case 3 : a+=((ub4)k[2]<<16);
|
||||
case 2 : a+=((ub4)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
// version optimized for 4 byte input.
|
||||
static ub4 hash_DWORD(const DWORD in, const ub4 initval)
|
||||
{
|
||||
ub1 *const k = (ub1 *)∈
|
||||
ub4 a, b, c, len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = 4;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = initval; /* the previous hash value */
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += 4;
|
||||
a+=((ub4)k[3]<<24);
|
||||
a+=((ub4)k[2]<<16);
|
||||
a+=((ub4)k[1]<<8);
|
||||
a+=k[0];
|
||||
|
||||
mix(a,b,c);
|
||||
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
struct BaseAddressLookup
|
||||
{
|
||||
DWORD64 keyAddress; // key
|
||||
DWORD64 baseAddress; // value
|
||||
};
|
||||
|
||||
static BaseAddressLookup * s_baseAddressCache;
|
||||
static inline unsigned _baseAddressCachePageBits() { return 8; }
|
||||
static inline unsigned _baseAddressCacheBits() { return _baseAddressCachePageBits() + 12; }
|
||||
static inline unsigned _baseAddressCacheSize() { return 1 << (_baseAddressCacheBits()); }
|
||||
static inline unsigned _baseAddressCacheElements() { return _baseAddressCacheSize() / sizeof(*s_baseAddressCache); }
|
||||
static inline unsigned _baseAddressCacheMask() { return _baseAddressCacheElements() - 1; }
|
||||
|
||||
static int s_baseAddressCacheMisses;
|
||||
static int s_baseAddressCacheHits;
|
||||
|
||||
static int s_baseAddressElements;
|
||||
static int s_baseAddressUsed;
|
||||
|
||||
/*
|
||||
static void _baseAddressCacheAnalyze()
|
||||
{
|
||||
s_baseAddressElements=0;
|
||||
s_baseAddressUsed=0;
|
||||
|
||||
unsigned i;
|
||||
const unsigned count = _baseAddressCacheElements();
|
||||
for (i=0;i<count;i++)
|
||||
{
|
||||
const BaseAddressLookup *lookup = s_baseAddressCache + i;
|
||||
s_baseAddressElements++;
|
||||
if (lookup->baseAddress)
|
||||
{
|
||||
s_baseAddressUsed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static DWORD64 _baseAddressLookup(DWORD64 addr)
|
||||
{
|
||||
BaseAddressLookup *lookup;
|
||||
|
||||
unsigned long bits = _baseAddressCacheBits();
|
||||
|
||||
DWORD *addr32 = (DWORD *)&addr;
|
||||
unsigned long hash32 = hash_DWORD(addr32[0], addr32[1]);
|
||||
unsigned long hash = (hash32>>(32-bits)) ^ hash32;
|
||||
|
||||
unsigned long mask = _baseAddressCacheMask();
|
||||
|
||||
unsigned long index = hash & mask;
|
||||
lookup = s_baseAddressCache + index;
|
||||
if (lookup->keyAddress==addr)
|
||||
{
|
||||
s_baseAddressCacheHits++;
|
||||
//DEBUG_FATAL(symGetModuleBase64(process, addr) != lookup->baseAddress, ("Cache failure.\n"));
|
||||
return lookup->baseAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_baseAddressCacheMisses++;
|
||||
|
||||
DWORD64 baseAddress = symGetModuleBase64(process, addr);
|
||||
|
||||
lookup->keyAddress=addr;
|
||||
lookup->baseAddress=baseAddress;
|
||||
|
||||
return baseAddress;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD64 __stdcall getModuleBase(HANDLE hProcess, DWORD64 dwAddr)
|
||||
{
|
||||
UNREF(hProcess);
|
||||
DEBUG_FATAL(hProcess!=process, ("Wrong process handle for module base lookup.\n"));
|
||||
return _baseAddressLookup(dwAddr);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
struct FunctionTableLookup
|
||||
{
|
||||
DWORD64 keyAddress; // key
|
||||
PVOID functionTable; // value
|
||||
};
|
||||
|
||||
static FunctionTableLookup * s_functionTableCache;
|
||||
static inline unsigned _functionTableCachePageBits() { return 4; }
|
||||
static inline unsigned _functionTableCacheBits() { return _functionTableCachePageBits() + 12; }
|
||||
static inline unsigned _functionTableCacheSize() { return 1 << (_functionTableCacheBits()); }
|
||||
static inline unsigned _functionTableCacheElements() { return _functionTableCacheSize() / sizeof(*s_functionTableCache); }
|
||||
static inline unsigned _functionTableCacheMask() { return _functionTableCacheElements() - 1; }
|
||||
|
||||
static int s_functionTableCacheMisses;
|
||||
static int s_functionTableCacheHits;
|
||||
|
||||
|
||||
static PVOID _functionTableLookup(DWORD64 addr)
|
||||
{
|
||||
FunctionTableLookup *lookup;
|
||||
|
||||
unsigned long bits = _functionTableCacheBits();
|
||||
|
||||
DWORD *addr32 = (DWORD *)&addr;
|
||||
unsigned long hash32 = hash_DWORD(addr32[0], addr32[1]);
|
||||
unsigned long hash = (hash32>>(32-bits)) ^ hash32;
|
||||
|
||||
unsigned long mask = _functionTableCacheMask();
|
||||
|
||||
unsigned long index = hash & mask;
|
||||
lookup = s_functionTableCache + index;
|
||||
if (lookup->keyAddress==addr)
|
||||
{
|
||||
s_functionTableCacheHits++;
|
||||
//DEBUG_FATAL(symFunctionTableAccess64(process, addr) != lookup->functionTable, ("Cache failure.\n"));
|
||||
return lookup->functionTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_functionTableCacheMisses++;
|
||||
PVOID functionTable = symFunctionTableAccess64(process, addr);
|
||||
lookup->keyAddress=addr;
|
||||
lookup->functionTable=functionTable;
|
||||
|
||||
return functionTable;
|
||||
}
|
||||
}
|
||||
|
||||
static PVOID __stdcall functionTableAccess(HANDLE hProcess, DWORD64 dwAddr)
|
||||
{
|
||||
UNREF(hProcess);
|
||||
DEBUG_FATAL(hProcess!=process, ("Wrong process handle for module base lookup.\n"));
|
||||
return _functionTableLookup(DWORD(dwAddr));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
}
|
||||
using namespace DebugHelpNamespace;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
BOOL CALLBACK loadSymbolsForDllCallback(PSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
|
||||
{
|
||||
if (!library)
|
||||
return false;
|
||||
|
||||
CallbackData *callbackData = reinterpret_cast<CallbackData *>(UserContext);
|
||||
|
||||
// see if this is the right file module and if we can load its symbol information
|
||||
if (_stricmp(ModuleName, callbackData->name) == 0 && symLoadModule64(process, NULL, ModuleName, 0, ModuleBase, ModuleSize) != 0)
|
||||
{
|
||||
callbackData->loaded = true;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void DebugHelp::install()
|
||||
{
|
||||
DEBUG_FATAL(library, ("DebugHelp already installed"));
|
||||
|
||||
library = LoadLibrary("dbghelp_6.3.17.0.dll");
|
||||
if (library)
|
||||
{
|
||||
process = GetCurrentProcess();
|
||||
|
||||
#define GPA(a, b) a = reinterpret_cast<b##FP>(GetProcAddress(library, #b)); DEBUG_FATAL(!a, ("GetProcAddress failed for " #b))
|
||||
GPA(symSetOptions, SymSetOptions);
|
||||
GPA(symInitialize, SymInitialize);
|
||||
GPA(symCleanup, SymCleanup);
|
||||
GPA(stackWalk64, StackWalk64);
|
||||
GPA(symGetModuleInfo64, SymGetModuleInfo64);
|
||||
GPA(symLoadModule64, SymLoadModule64);
|
||||
GPA(symGetSymFromAddr64, SymGetSymFromAddr64);
|
||||
GPA(symGetLineFromAddr64, SymGetLineFromAddr64);
|
||||
GPA(symFunctionTableAccess64, SymFunctionTableAccess64);
|
||||
GPA(symGetModuleBase64, SymGetModuleBase64);
|
||||
GPA(symEnumerateModules64, SymEnumerateModules64);
|
||||
GPA(enumerateLoadedModules64, EnumerateLoadedModules64);
|
||||
GPA(miniDumpWriteDump, MiniDumpWriteDump);
|
||||
#undef GPA
|
||||
|
||||
IGNORE_RETURN(symSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES));
|
||||
|
||||
// get the path to the executable
|
||||
char executableDirectory[MAX_PATH * 2];
|
||||
const DWORD result = GetModuleFileName(NULL, executableDirectory, sizeof(executableDirectory));
|
||||
FATAL(result == 0, ("GetModuleFileName failed"));
|
||||
char * const slash = strrchr(executableDirectory, '\\');
|
||||
DEBUG_FATAL(!slash, ("Executable path does not contain a slash"));
|
||||
*slash = '\0';
|
||||
|
||||
const BOOL result1 = symInitialize(process, executableDirectory, TRUE);
|
||||
UNREF(result1);
|
||||
DEBUG_FATAL(!result1, ("SymInitialize failed"));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
s_baseAddressCache = (BaseAddressLookup *)VirtualAlloc(0, _baseAddressCacheSize(), MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
s_functionTableCache = (FunctionTableLookup *)VirtualAlloc(0, _functionTableCacheSize(), MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// Initialize the critical section one time only.
|
||||
InitializeCriticalSection(&criticalSection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugHelp::remove()
|
||||
{
|
||||
if (s_baseAddressCache)
|
||||
{
|
||||
VirtualFree(s_baseAddressCache, 0, MEM_RELEASE);
|
||||
s_baseAddressCache=0;
|
||||
}
|
||||
|
||||
if (s_functionTableCache)
|
||||
{
|
||||
VirtualFree(s_functionTableCache, 0, MEM_RELEASE);
|
||||
s_functionTableCache=0;
|
||||
}
|
||||
|
||||
if (library)
|
||||
{
|
||||
IGNORE_RETURN(symCleanup(process));
|
||||
IGNORE_RETURN(FreeLibrary(library));
|
||||
library = NULL;
|
||||
process = NULL;
|
||||
symSetOptions = NULL;
|
||||
symInitialize = NULL;
|
||||
symCleanup = NULL;
|
||||
stackWalk64 = NULL;
|
||||
symGetModuleInfo64 = NULL;
|
||||
symLoadModule64 = NULL;
|
||||
symGetSymFromAddr64 = NULL;
|
||||
symGetLineFromAddr64 = NULL;
|
||||
symFunctionTableAccess64 = NULL;
|
||||
symGetModuleBase64 = NULL;
|
||||
symEnumerateModules64 = NULL;
|
||||
enumerateLoadedModules64 = NULL;
|
||||
}
|
||||
|
||||
// Release resources used by the critical section object.
|
||||
DeleteCriticalSection(&criticalSection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool DebugHelp::loadSymbolsForDll(const char *name)
|
||||
{
|
||||
if (!library)
|
||||
return false;
|
||||
|
||||
CallbackData callbackData = { name, false };
|
||||
enumerateLoadedModules64(process, (PENUMLOADED_MODULES_CALLBACK64)loadSymbolsForDllCallback, reinterpret_cast<void *>(&callbackData));
|
||||
return callbackData.loaded;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
#pragma warning (disable: 4740 4748)
|
||||
void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack)
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < sizeOfCallStack; ++i)
|
||||
callStack[i] = 0;
|
||||
}
|
||||
|
||||
if (!library)
|
||||
return;
|
||||
|
||||
CONTEXT context;
|
||||
Zero(context);
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
|
||||
// GetThreadContext returns invalid data when called from within the same thread
|
||||
//if (!GetThreadContext(GetCurrentThread(), &context))
|
||||
// return;
|
||||
|
||||
EnterCriticalSection(&criticalSection);
|
||||
__asm
|
||||
{
|
||||
call GetEIP
|
||||
GetEIP:
|
||||
pop eax
|
||||
mov context.Eip, eax
|
||||
mov context.Esp, esp
|
||||
mov context.Ebp, ebp
|
||||
}
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
|
||||
STACKFRAME64 stackFrame;
|
||||
Zero(stackFrame);
|
||||
stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
stackFrame.AddrPC.Offset = context.Eip;
|
||||
stackFrame.AddrStack.Offset = context.Esp;
|
||||
stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
stackFrame.AddrFrame.Offset = context.Ebp;
|
||||
stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
for (int i = 0; i < sizeOfCallStack; ++i, ++callStack)
|
||||
{
|
||||
if (stackWalk64(IMAGE_FILE_MACHINE_I386, process, process, &stackFrame, &context, NULL, functionTableAccess, getModuleBase, NULL))
|
||||
{
|
||||
const DWORD64 Offset = stackFrame.AddrPC.Offset;
|
||||
*callStack = DWORD(Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugHelp::reportCallStack(int const maxStackDepth)
|
||||
{
|
||||
// look up the call stack information
|
||||
int const callStackOffset = 2;
|
||||
int const callStackSize = callStackOffset + maxStackDepth;
|
||||
uint32 * callStack = static_cast<uint32 *>(_alloca((callStackOffset + maxStackDepth) * sizeof(uint32)));
|
||||
getCallStack(callStack, callStackOffset + maxStackDepth);
|
||||
|
||||
// look up the caller's file and line
|
||||
if (callStack[callStackOffset])
|
||||
{
|
||||
char lib[4 * 1024] = { '\0' };
|
||||
char file[4 * 1024] = { '\0' };
|
||||
int line = 0;
|
||||
for (int i = callStackOffset; i < callStackSize; ++i)
|
||||
{
|
||||
if (callStack[i])
|
||||
{
|
||||
if (lookupAddress(callStack[i], lib, file, sizeof(file), line))
|
||||
REPORT_LOG(true, ("\t%s(%d) : caller %d\n", file, line, i-callStackOffset));
|
||||
else
|
||||
REPORT_LOG(true, ("\tunknown(0x%08X) : caller %d\n", static_cast<int>(callStack[i]), i-callStackOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool DebugHelp::lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line)
|
||||
{
|
||||
UNREF(libName);
|
||||
|
||||
if (!library)
|
||||
return false;
|
||||
|
||||
// make sure the image is loaded
|
||||
IMAGEHLP_MODULE64 imageHelpModule;
|
||||
Zero(imageHelpModule);
|
||||
imageHelpModule.SizeOfStruct = sizeof(imageHelpModule);
|
||||
if (!symGetModuleInfo64(process, address, &imageHelpModule))
|
||||
return false;
|
||||
|
||||
// look up the symbol
|
||||
const int MaxNameLength = 256;
|
||||
char buffer[sizeof(IMAGEHLP_SYMBOL64) + MaxNameLength];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
IMAGEHLP_SYMBOL64 *imageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
|
||||
imageHelpSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
imageHelpSymbol->Address = address;
|
||||
imageHelpSymbol->MaxNameLength = MaxNameLength;
|
||||
{
|
||||
DWORD64 displacement = 0;
|
||||
if (!symGetSymFromAddr64(process, address, &displacement, imageHelpSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// look up the source file name and line number
|
||||
IMAGEHLP_LINE64 imageHelpLine;
|
||||
Zero(imageHelpLine);
|
||||
imageHelpLine.SizeOfStruct = sizeof(imageHelpLine);
|
||||
{
|
||||
DWORD displacement = 0;
|
||||
if (!symGetLineFromAddr64(process, address, &displacement, &imageHelpLine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// return the results
|
||||
strncpy(fileName, imageHelpLine.FileName, static_cast<uint>(fileNameLength));
|
||||
line = static_cast<int>(imageHelpLine.LineNumber);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool DebugHelp::writeMiniDump(char const *miniDumpFileName, PEXCEPTION_POINTERS exceptionPointers)
|
||||
{
|
||||
if (!miniDumpWriteDump)
|
||||
return false;
|
||||
|
||||
char buffer[256];
|
||||
if (!miniDumpFileName)
|
||||
{
|
||||
// get the program name
|
||||
char programName[512];
|
||||
DWORD result = GetModuleFileName(NULL, programName, sizeof(programName));
|
||||
if (result == 0)
|
||||
return false;
|
||||
|
||||
// get the file name without the path
|
||||
const char *shortProgramName = strrchr(programName, '\\');
|
||||
if (shortProgramName)
|
||||
++shortProgramName;
|
||||
else
|
||||
shortProgramName = programName;
|
||||
|
||||
// lop off the extension
|
||||
char *dot = const_cast<char *>(strchr(shortProgramName, '.'));
|
||||
if (dot)
|
||||
*dot = '\0';
|
||||
|
||||
// create a reasonable minidump filename
|
||||
snprintf(buffer, sizeof(buffer), "%s_%d.mdmp", shortProgramName, static_cast<int>(GetCurrentProcessId()));
|
||||
miniDumpFileName = buffer;
|
||||
}
|
||||
|
||||
// create the file
|
||||
HANDLE const file = CreateFile(miniDumpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
// create the exception information
|
||||
MINIDUMP_EXCEPTION_INFORMATION exceptionInformationData;
|
||||
MINIDUMP_EXCEPTION_INFORMATION *exceptionInformation = 0;
|
||||
if (exceptionPointers)
|
||||
{
|
||||
exceptionInformationData.ThreadId = GetCurrentThreadId();
|
||||
exceptionInformationData.ExceptionPointers = exceptionPointers;
|
||||
exceptionInformationData.ClientPointers = true;
|
||||
exceptionInformation = &exceptionInformationData;
|
||||
}
|
||||
|
||||
// @todo make the minidump style modifiable
|
||||
BOOL const result = miniDumpWriteDump(process, GetCurrentProcessId(), file, MiniDumpNormal, exceptionInformation, NULL, NULL);
|
||||
|
||||
// close the file
|
||||
CloseHandle(file);
|
||||
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugHelp.h
|
||||
// copyright 2000 Verant Interactive
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef DEBUG_HELP_H
|
||||
#define DEBUG_HELP_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
typedef unsigned long uint32;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class DebugHelp
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static bool loadSymbolsForDll(const char *name);
|
||||
|
||||
static void getCallStack(uint32 *callStack, int sizeOfCallStack);
|
||||
static void reportCallStack(int const maxStackDepth = 4);
|
||||
static bool lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line);
|
||||
|
||||
static bool writeMiniDump(char const *miniDumpFileName=0, PEXCEPTION_POINTERS exceptionPointers=0);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,321 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugMonitor.cpp
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001-2004 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/DebugMonitor.h"
|
||||
|
||||
#if PRODUCTION == 0
|
||||
|
||||
#include "sharedDebug/DebugFlags.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace DebugMonitorNamespace
|
||||
{
|
||||
typedef void (*ChangedWindowCallback)(int x, int y, int width, int height);
|
||||
|
||||
typedef bool (*InstallFunction)(int x, int y, int width, int height);
|
||||
typedef void (*RemoveFunction)();
|
||||
typedef void (*ShowFunction)();
|
||||
typedef void (*HideFunction)();
|
||||
typedef void (*SetChangedWindowCallback)(ChangedWindowCallback);
|
||||
typedef void (*SetBehindWindowFunction)(HWND window);
|
||||
typedef void (*ClearScreenFunction)();
|
||||
typedef void (*ClearToCursorFunction)();
|
||||
typedef void (*GotoXYFunction)(int x, int y);
|
||||
typedef void (*PrintFunction)(const char *string);
|
||||
|
||||
void changedWindowCallback(int x, int y, int width, int height);
|
||||
|
||||
HINSTANCE dll;
|
||||
HKEY registryKey = HKEY_CLASSES_ROOT;
|
||||
RemoveFunction removeFunction;
|
||||
ShowFunction showFunction;
|
||||
HideFunction hideFunction;
|
||||
SetBehindWindowFunction setBehindWindowFunction;
|
||||
ClearScreenFunction clearScreenFunction;
|
||||
ClearToCursorFunction clearToCursorFunction;
|
||||
GotoXYFunction gotoXYFunction;
|
||||
PrintFunction printFunction;
|
||||
|
||||
bool noClear;
|
||||
|
||||
int GetRegistryValue(char const * name, int defaultValue)
|
||||
{
|
||||
int value;
|
||||
DWORD type = 0;
|
||||
DWORD size = sizeof(DWORD);
|
||||
LONG result = RegQueryValueEx(registryKey, name, NULL, &type, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
if ((result != ERROR_SUCCESS || type != REG_DWORD) && (size != sizeof(int)))
|
||||
value = defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
void SetRegistryValue(char const * name, int value)
|
||||
{
|
||||
RegSetValueEx(registryKey, name, NULL, REG_DWORD, reinterpret_cast<const LPBYTE>(&value), sizeof(int));
|
||||
}
|
||||
}
|
||||
using namespace DebugMonitorNamespace;
|
||||
|
||||
// ======================================================================
|
||||
// Install the debug monitor subsystem
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine will first attempt to install the selected debug monitor.
|
||||
|
||||
void DebugMonitor::install()
|
||||
{
|
||||
dll = LoadLibrary("debugWindow.dll");
|
||||
if (dll)
|
||||
{
|
||||
InstallFunction installFunction = reinterpret_cast<InstallFunction>(GetProcAddress(dll, "install"));
|
||||
|
||||
RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Sony Online Entertainment\\DebugWindow", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, ®istryKey, NULL);
|
||||
|
||||
int const x = ConfigFile::getKeyInt("SharedDebug", "debugWindowX", GetRegistryValue("x", 0));
|
||||
int const y = ConfigFile::getKeyInt("SharedDebug", "debugWindowY", GetRegistryValue("y", 0));
|
||||
int const width = ConfigFile::getKeyInt("SharedDebug", "debugWindowWidth", GetRegistryValue("width", 80));
|
||||
int const height = ConfigFile::getKeyInt("SharedDebug", "debugWindowHeight", GetRegistryValue("height", 50));
|
||||
|
||||
if (installFunction && installFunction(x, y, width, height))
|
||||
{
|
||||
showFunction = reinterpret_cast<ShowFunction>(GetProcAddress(dll, "showWindow"));
|
||||
hideFunction = reinterpret_cast<ShowFunction>(GetProcAddress(dll, "hideWindow"));
|
||||
removeFunction = reinterpret_cast<RemoveFunction>(GetProcAddress(dll, "remove"));
|
||||
setBehindWindowFunction = reinterpret_cast<SetBehindWindowFunction>(GetProcAddress(dll, "setBehindWindow"));
|
||||
clearScreenFunction = reinterpret_cast<ClearScreenFunction>(GetProcAddress(dll, "clearScreen"));
|
||||
clearToCursorFunction = reinterpret_cast<ClearToCursorFunction>(GetProcAddress(dll, "clearToCursor"));
|
||||
gotoXYFunction = reinterpret_cast<GotoXYFunction>(GetProcAddress(dll, "gotoXY"));
|
||||
printFunction = reinterpret_cast<PrintFunction>(GetProcAddress(dll, "print"));
|
||||
|
||||
SetChangedWindowCallback setChangedWindowCallback = reinterpret_cast<SetChangedWindowCallback>(GetProcAddress(dll, "setChangedWindowCallback"));
|
||||
if (setChangedWindowCallback)
|
||||
(*setChangedWindowCallback)(changedWindowCallback);
|
||||
|
||||
DebugFlags::registerFlag(noClear, "SharedDebug", "noDebugMonitorClear");
|
||||
|
||||
if (ConfigFile::getKeyBool("SharedDebug", "debugWindow", false))
|
||||
show();
|
||||
}
|
||||
else
|
||||
{
|
||||
installFunction = NULL;
|
||||
const BOOL result = FreeLibrary(dll);
|
||||
dll = NULL;
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(!result, ("FreeLibrary failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Remove the debug monitor subsystem.
|
||||
*/
|
||||
|
||||
void DebugMonitor::remove()
|
||||
{
|
||||
if (removeFunction)
|
||||
removeFunction();
|
||||
|
||||
removeFunction = NULL;
|
||||
setBehindWindowFunction = NULL;
|
||||
clearScreenFunction = NULL;
|
||||
clearToCursorFunction = NULL;
|
||||
gotoXYFunction = NULL;
|
||||
printFunction = NULL;
|
||||
|
||||
if (dll)
|
||||
{
|
||||
const BOOL result = FreeLibrary(dll);
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(!result, ("FreeLibrary failed"));
|
||||
dll = NULL;
|
||||
|
||||
if (registryKey != HKEY_CLASSES_ROOT)
|
||||
{
|
||||
RegCloseKey(registryKey);
|
||||
registryKey = HKEY_CLASSES_ROOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugMonitorNamespace::changedWindowCallback(int const x, int const y, int const width, int const height)
|
||||
{
|
||||
SetRegistryValue("x", x);
|
||||
SetRegistryValue("y", y);
|
||||
SetRegistryValue("width", width);
|
||||
SetRegistryValue("height", height);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugMonitor::show()
|
||||
{
|
||||
if (showFunction)
|
||||
(*showFunction)();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugMonitor::hide()
|
||||
{
|
||||
if (hideFunction)
|
||||
(*hideFunction)();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the debug window's z-order.
|
||||
*/
|
||||
|
||||
void DebugMonitor::setBehindWindow(HWND window)
|
||||
{
|
||||
if (setBehindWindowFunction)
|
||||
setBehindWindowFunction(window);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Clear the debug monitor and home the cursor.
|
||||
*
|
||||
* If the mono monitor is not installed, this routine does nothing.
|
||||
*
|
||||
* This routine will clear the contents of the debug monitor, reset the screen
|
||||
* offset to 0, and move the cursor to the upper left corner of the screen.
|
||||
*
|
||||
* @see DebugMonitor::home(), DebugMonitor::clearToCursor()
|
||||
*/
|
||||
|
||||
void DebugMonitor::clearScreen()
|
||||
{
|
||||
if (noClear)
|
||||
return;
|
||||
|
||||
if (clearScreenFunction)
|
||||
clearScreenFunction();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Clear the debug monitor to the current cursor position and home the cursor.
|
||||
*
|
||||
* If the debug monitor is not installed, this routine does nothing.
|
||||
*
|
||||
* This routine will clear the contents of the debug monitor only up to the
|
||||
* cursor position. If the cursor is not very far down on the screen,
|
||||
* this routine may be significantly more efficient clearing the screen.
|
||||
*
|
||||
* It will also move the cursor to the upper left corner of the screen.
|
||||
*
|
||||
* @see DebugMonitor::clearScreen(), DebugMonitor::home()
|
||||
*/
|
||||
|
||||
void DebugMonitor::clearToCursor()
|
||||
{
|
||||
if (clearToCursorFunction)
|
||||
clearToCursorFunction();
|
||||
else
|
||||
clearScreen();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Move the cursor to the upper left hand corner of the mono monitor screen
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// If the debug monitor is not installed, this routine does nothing.
|
||||
//
|
||||
// All printing happens at the cursor position.
|
||||
//
|
||||
// This routine is identical to calling gotoXY(0,0);
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// DebugMonitor::gotoXY()
|
||||
|
||||
void DebugMonitor::home()
|
||||
{
|
||||
gotoXY(0,0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Position the cursor on the debug monitor screen.
|
||||
*
|
||||
* If the debug monitor is not installed, this routine does nothing.
|
||||
*
|
||||
* All printing happens at the cursor position.
|
||||
*
|
||||
* @param x New X position for the cursor
|
||||
* @param y New Y position for the cursor
|
||||
*/
|
||||
|
||||
void DebugMonitor::gotoXY(int x, int y)
|
||||
{
|
||||
if (gotoXYFunction)
|
||||
gotoXYFunction(x, y);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Display a string on the debug monitor.
|
||||
*
|
||||
* If the debug monitor is not installed, this routine does nothing.
|
||||
*
|
||||
* Printing occurs from the cursor position.
|
||||
*
|
||||
* Newline characters '\n' will cause the cursor position to advance to the
|
||||
* beginning of the next line. If the cursor is already on the last line of
|
||||
* the screen, the screen will scroll up one line and the cursor will move to
|
||||
* the beginning of the last line.
|
||||
*
|
||||
* The backspace character '\b' will cause the cursor to move one character
|
||||
* backwards. If at the beginning of the line, the cursor will move to the
|
||||
* end of the previous line. If already on the first line of the screen, the
|
||||
* cursor position and screen contents will be unchanged.
|
||||
*
|
||||
* All other characters are placed directly into the text frame buffer.
|
||||
* After each character, the cursor will be logically advanced one
|
||||
* character forward. If the cursor was on the last column, it will advance
|
||||
* to the next line. If the cursor was already on the last line, the screen
|
||||
* will be scrolled up one line and the cursor will move to the beginning of
|
||||
* the last line.
|
||||
*
|
||||
* @param string String to display on the debug monitor
|
||||
*/
|
||||
|
||||
void DebugMonitor::print(const char *string)
|
||||
{
|
||||
if (printFunction)
|
||||
printFunction(string);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Ensure all changes to the DebugMonitor have taken effect by the time
|
||||
* this function returns.
|
||||
*
|
||||
* Note: some platforms may do nothing here. The Win32 platform does not
|
||||
* require flushing. The Linux platform does. Call it assuming
|
||||
* that it is needed. It will be a no-op when not required.
|
||||
*/
|
||||
|
||||
void DebugMonitor::flushOutput()
|
||||
{
|
||||
// Win32 debug monitors don't need to do anything here.
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugMonitor.h
|
||||
//
|
||||
// Portions copyright 1998 Bootprint Entertainment
|
||||
// Portions copyright 2002-2004 Sony Online Entertainment
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_DebugMonitor_H
|
||||
#define INCLUDED_DebugMonitor_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/Production.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#if PRODUCTION == 0
|
||||
|
||||
class DebugMonitor
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static void setBehindWindow(HWND window);
|
||||
|
||||
static void show();
|
||||
static void hide();
|
||||
|
||||
static void clearScreen();
|
||||
static void clearToCursor();
|
||||
|
||||
static void home();
|
||||
static void gotoXY(int x, int y);
|
||||
static void print(const char *string);
|
||||
|
||||
static void flushOutput();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstDebug.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "shareddebug/FirstSharedDebug.h"
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// PerformanceTimer.cpp
|
||||
// Copyright 2000-2004 Sony Online Entertainment
|
||||
//
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include "shareddebug/FirstSharedDebug.h"
|
||||
#include "shareddebug/PerformanceTimer.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
__int64 PerformanceTimer::ms_frequency;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::install()
|
||||
{
|
||||
BOOL result = QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&ms_frequency));
|
||||
FATAL(!result, ("PerformanceTimer::install QPF failed"));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
PerformanceTimer::PerformanceTimer() :
|
||||
m_startTime (0),
|
||||
m_stopTime (0)
|
||||
{
|
||||
DEBUG_FATAL (ms_frequency == 0.f, ("PerformanceTimer not installed"));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
PerformanceTimer::~PerformanceTimer()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::start()
|
||||
{
|
||||
//-- get the current time
|
||||
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&m_startTime));
|
||||
DEBUG_FATAL(!result, ("PerformanceTimer::start QPC failed"));
|
||||
UNREF (result);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::resume()
|
||||
{
|
||||
__int64 delta = m_stopTime - m_startTime;
|
||||
start();
|
||||
m_startTime -= delta;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::stop ()
|
||||
{
|
||||
//-- get the current time
|
||||
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&m_stopTime));
|
||||
DEBUG_FATAL(!result, ("PerformanceTimer::stop QPC failed"));
|
||||
UNREF (result);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
float PerformanceTimer::getElapsedTime() const
|
||||
{
|
||||
return static_cast<float> (m_stopTime - m_startTime) / static_cast<float> (ms_frequency);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float PerformanceTimer::getSplitTime() const
|
||||
{
|
||||
__int64 currentTime;
|
||||
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(¤tTime));
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(!result, ("PerformanceTimer::getSplitTime QPC failed"));
|
||||
|
||||
return static_cast<float> (currentTime - m_startTime) / static_cast<float> (ms_frequency);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::logElapsedTime(const char* string) const
|
||||
{
|
||||
UNREF (string);
|
||||
|
||||
#ifdef _DEBUG
|
||||
static char buffer [1000];
|
||||
sprintf (buffer, "%s : %1.5f seconds\n", string ? string : "null", getElapsedTime());
|
||||
DEBUG_REPORT_LOG_PRINT (true, ("%s", buffer));
|
||||
DEBUG_OUTPUT_CHANNEL("Foundation\\PerformanceTimer", ("%s", buffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// PerformanceTimer.h
|
||||
// Copyright 2000-2004 Sony Online Entertainment
|
||||
//
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_PerformanceTimer_H
|
||||
#define INCLUDED_PerformanceTimer_H
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class PerformanceTimer
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
public:
|
||||
|
||||
DLLEXPORT PerformanceTimer();
|
||||
DLLEXPORT ~PerformanceTimer();
|
||||
|
||||
void DLLEXPORT start();
|
||||
void DLLEXPORT resume();
|
||||
void DLLEXPORT stop();
|
||||
|
||||
float DLLEXPORT getElapsedTime() const;
|
||||
float getSplitTime() const; // Get the time since the timer was started without stopping the timer.
|
||||
void logElapsedTime(const char* string) const;
|
||||
|
||||
private:
|
||||
|
||||
PerformanceTimer(PerformanceTimer const &);
|
||||
PerformanceTimer & operator=(PerformanceTimer const &);
|
||||
|
||||
private:
|
||||
|
||||
static __int64 ms_frequency;
|
||||
|
||||
private:
|
||||
|
||||
__int64 m_startTime;
|
||||
__int64 m_stopTime;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ProfilerTimer.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "shareddebug/FirstSharedDebug.h"
|
||||
#include "shareddebug/ProfilerTimer.h"
|
||||
|
||||
#include "shareddebug/DebugFlags.h"
|
||||
#include "sharedFoundation/WindowsWrapper.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace ProfilerTimerNamespace
|
||||
{
|
||||
ProfilerTimer::Type ms_qpcFrequency;
|
||||
float ms_floatQpcFrequency;
|
||||
__int64 ms_rdtsc;
|
||||
__int64 ms_qpc;
|
||||
bool ms_useRdtsc;
|
||||
|
||||
}
|
||||
using namespace ProfilerTimerNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static __int64 __declspec(naked) __stdcall readTimeStampCounter()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
rdtsc;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void ProfilerTimer::install()
|
||||
{
|
||||
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&ms_qpc)));
|
||||
ms_rdtsc = readTimeStampCounter();
|
||||
|
||||
IGNORE_RETURN(QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&ms_qpcFrequency)));
|
||||
ms_floatQpcFrequency = static_cast<float>(ms_qpcFrequency);
|
||||
|
||||
DebugFlags::registerFlag(ms_useRdtsc, "SharedDebug/Profiler", "useRdtsc");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ProfilerTimer::getTime(Type &time)
|
||||
{
|
||||
if (ms_useRdtsc)
|
||||
time = readTimeStampCounter();
|
||||
else
|
||||
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&time)));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ProfilerTimer::getCalibratedTime(Type &time, Type &frequency)
|
||||
{
|
||||
if (ms_useRdtsc)
|
||||
{
|
||||
__int64 qpc;
|
||||
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&qpc)));
|
||||
__int64 rdtsc = readTimeStampCounter();
|
||||
|
||||
float const t = static_cast<float>(qpc - ms_qpc) / ms_floatQpcFrequency;
|
||||
frequency = static_cast<__int64>(static_cast<float>(rdtsc - ms_rdtsc) / t);
|
||||
|
||||
time = rdtsc;
|
||||
ms_qpc = qpc;
|
||||
ms_rdtsc = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&time)));
|
||||
frequency = ms_qpcFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
void ProfilerTimer::getFrequency(Type &frequency)
|
||||
{
|
||||
frequency = ms_qpcFrequency;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,29 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ProfilerTimer.h
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ProfilerTimer_H
|
||||
#define INCLUDED_ProfilerTimer_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ProfilerTimer
|
||||
{
|
||||
public:
|
||||
|
||||
typedef __int64 Type;
|
||||
|
||||
public:
|
||||
|
||||
static void install();
|
||||
static void getTime(Type &time);
|
||||
static void getCalibratedTime(Type &time, Type &frequency);
|
||||
static void getFrequency(Type &frequency);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// VTune.cpp
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/VTune.h"
|
||||
|
||||
#if PRODUCTION == 0
|
||||
|
||||
#include "sharedDebug/DebugFlags.h"
|
||||
|
||||
#include <vtune/vtuneapi.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
HMODULE VTune::ms_module;
|
||||
VTune::PauseFunction VTune::ms_pauseFunction;
|
||||
VTune::ResumeFunction VTune::ms_resumeFunction;
|
||||
VTune::State VTune::ms_state;
|
||||
bool VTune::ms_resumeNextFrame;
|
||||
bool VTune::ms_pauseNextFrame;
|
||||
bool VTune::ms_debugReport;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void VTune::install()
|
||||
{
|
||||
DEBUG_FATAL(ms_module, ("vtune already installed"));
|
||||
|
||||
ms_module = LoadLibrary("VTuneAPI");
|
||||
if (!ms_module)
|
||||
return;
|
||||
|
||||
ms_pauseFunction = reinterpret_cast<PauseFunction>(GetProcAddress(ms_module, "VTPause"));
|
||||
ms_resumeFunction = reinterpret_cast<PauseFunction>(GetProcAddress(ms_module, "VTResume"));
|
||||
ms_state = S_default;
|
||||
|
||||
#if PRODUCTION == 0
|
||||
DebugFlags::registerFlag(ms_debugReport, "SharedDebug", "vtuneState", debugReport);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::remove()
|
||||
{
|
||||
if (ms_module)
|
||||
{
|
||||
FreeLibrary(ms_module);
|
||||
ms_pauseFunction = 0;
|
||||
ms_resumeFunction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::debugReport()
|
||||
{
|
||||
switch (ms_state)
|
||||
{
|
||||
case S_default:
|
||||
REPORT_PRINT(true, ("Vtune state unknown\n"));
|
||||
break;
|
||||
|
||||
case S_sampling:
|
||||
REPORT_PRINT(true, ("Vtune is sampling\n"));
|
||||
break;
|
||||
|
||||
case S_paused:
|
||||
REPORT_PRINT(true, ("Vtune is NOT sampling\n"));
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_FATAL(true, ("bad case"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::resume()
|
||||
{
|
||||
if (ms_module && ms_resumeFunction)
|
||||
{
|
||||
MessageBeep(MB_OK);
|
||||
(*ms_resumeFunction)();
|
||||
ms_state = S_sampling;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::pause()
|
||||
{
|
||||
if (ms_module && ms_pauseFunction)
|
||||
{
|
||||
(*ms_pauseFunction)();
|
||||
MessageBeep(MB_ICONEXCLAMATION);
|
||||
ms_state = S_paused;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::pauseNextFrame()
|
||||
{
|
||||
ms_pauseNextFrame = true;
|
||||
ms_resumeNextFrame = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::resumeNextFrame()
|
||||
{
|
||||
ms_pauseNextFrame = false;
|
||||
ms_resumeNextFrame = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void VTune::beginFrame()
|
||||
{
|
||||
if (ms_pauseNextFrame)
|
||||
{
|
||||
pause();
|
||||
ms_pauseNextFrame = false;
|
||||
}
|
||||
|
||||
if (ms_resumeNextFrame)
|
||||
{
|
||||
resume();
|
||||
ms_resumeNextFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // PRODUCTION == 0
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// VTune.h
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_VTune_H
|
||||
#define INCLUDED_VTune_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/Production.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#if PRODUCTION == 0
|
||||
|
||||
class VTune
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
static void resume();
|
||||
static void pause();
|
||||
|
||||
static void resumeNextFrame();
|
||||
static void pauseNextFrame();
|
||||
static void beginFrame();
|
||||
|
||||
private:
|
||||
|
||||
static void remove();
|
||||
static void debugReport();
|
||||
|
||||
private:
|
||||
|
||||
enum State
|
||||
{
|
||||
S_default,
|
||||
S_sampling,
|
||||
S_paused
|
||||
};
|
||||
|
||||
typedef void (__cdecl *PauseFunction)(void);
|
||||
typedef void (__cdecl *ResumeFunction)(void);
|
||||
|
||||
private:
|
||||
|
||||
static HMODULE ms_module;
|
||||
static PauseFunction ms_pauseFunction;
|
||||
static ResumeFunction ms_resumeFunction;
|
||||
static State ms_state;
|
||||
static bool ms_resumeNextFrame;
|
||||
static bool ms_pauseNextFrame;
|
||||
static bool ms_debugReport;
|
||||
};
|
||||
|
||||
#endif // PRODUCTION == 0
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstFile.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFile/FirstSharedFile.h"
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsFile.cpp
|
||||
// Copyright 2002, Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFile/FirstSharedFile.h"
|
||||
#include "sharedFile/OsFile.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "sharedDebug/PerformanceTimer.h"
|
||||
#endif
|
||||
|
||||
namespace OsFileNamespace
|
||||
{
|
||||
float ms_time;
|
||||
}
|
||||
using namespace OsFileNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void OsFile::install()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float OsFile::getSpentTime()
|
||||
{
|
||||
float const result = ms_time;
|
||||
ms_time = 0.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool OsFile::exists(const char *fileName)
|
||||
{
|
||||
NOT_NULL(fileName);
|
||||
DWORD attributes = GetFileAttributes(fileName);
|
||||
|
||||
#if _MSC_VER < 1300
|
||||
const DWORD INVALID_FILE_ATTRIBUTES = 0xffffffff;
|
||||
#endif
|
||||
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::getFileSize(const char *fileName)
|
||||
{
|
||||
NOT_NULL(fileName);
|
||||
|
||||
#ifdef _DEBUG
|
||||
PerformanceTimer t;
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
HANDLE handle = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
int const size = GetFileSize(handle, NULL);
|
||||
CloseHandle(handle);
|
||||
|
||||
#ifdef _DEBUG
|
||||
t.stop();
|
||||
ms_time += t.getElapsedTime();
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile *OsFile::open(const char *fileName, bool randomAccess)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
PerformanceTimer t;
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
// attempt to open the file
|
||||
HANDLE handle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | (randomAccess ? FILE_FLAG_RANDOM_ACCESS : 0), NULL);
|
||||
|
||||
// check to make sure the file opened sucessfully
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
t.stop();
|
||||
ms_time += t.getElapsedTime();
|
||||
#endif
|
||||
|
||||
return new OsFile(handle);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile::OsFile(HANDLE handle)
|
||||
: m_handle(handle),
|
||||
m_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile::~OsFile()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
PerformanceTimer t;
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
CloseHandle(m_handle);
|
||||
|
||||
#ifdef _DEBUG
|
||||
t.stop();
|
||||
ms_time+= t.getElapsedTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::length() const
|
||||
{
|
||||
return GetFileSize(m_handle, NULL);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void OsFile::seek(int newFilePosition)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
PerformanceTimer t;
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
if (m_offset != newFilePosition)
|
||||
{
|
||||
const DWORD result = SetFilePointer(m_handle, newFilePosition, NULL, FILE_BEGIN);
|
||||
DEBUG_FATAL(static_cast<int>(result) != newFilePosition, ("SetFilePointer failed"));
|
||||
UNREF(result);
|
||||
m_offset = newFilePosition;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
t.stop();
|
||||
ms_time += t.getElapsedTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::read(void *destinationBuffer, int numberOfBytes)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
PerformanceTimer t;
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
DWORD amountReadDword;
|
||||
BOOL result = ReadFile(m_handle, destinationBuffer, static_cast<uint>(numberOfBytes), &amountReadDword, NULL);
|
||||
|
||||
// miles crasher hack
|
||||
#if 0
|
||||
FATAL(!result, ("FileStreamerThread::processRead ReadFile failed to read '%d' bytes with error '%d'", static_cast<uint>(numberOfBytes), GetLastError()));
|
||||
#else
|
||||
if(!result)
|
||||
{
|
||||
if(GetLastError() == 998) // access violation - buffer coming from miles hosed
|
||||
{
|
||||
WARNING(true,("FileStreamerThread::processRead ReadFile failed to read '%d' bytes with error '%d'", static_cast<uint>(numberOfBytes), GetLastError()));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL(true, ("FileStreamerThread::processRead ReadFile failed to read '%d' bytes with error '%d'", static_cast<uint>(numberOfBytes), GetLastError()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// end miles crasher hack
|
||||
|
||||
#ifdef _DEBUG
|
||||
t.stop();
|
||||
ms_time += t.getElapsedTime();
|
||||
#endif
|
||||
|
||||
m_offset += static_cast<int>(amountReadDword);
|
||||
return static_cast<int>(amountReadDword);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsFile.h
|
||||
// Copyright 2002, Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_OsFile_H
|
||||
#define INCLUDED_OsFile_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class OsFile
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
static float getSpentTime();
|
||||
|
||||
static bool exists(const char *fileName);
|
||||
static int getFileSize(const char *fileName);
|
||||
static OsFile *open(const char *fileName, bool randomAccess=false);
|
||||
|
||||
public:
|
||||
|
||||
~OsFile();
|
||||
|
||||
int length() const;
|
||||
int tell() const;
|
||||
void seek(int newFilePosition);
|
||||
int read(void *destinationBuffer, int numberOfBytes);
|
||||
|
||||
private:
|
||||
|
||||
OsFile(HANDLE handle);
|
||||
OsFile(const char *fileName);
|
||||
|
||||
private:
|
||||
|
||||
HANDLE m_handle;
|
||||
int m_offset;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ByteOrder.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/ByteOrder.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// I'm using the arguments, but the compiler can't tell that
|
||||
#pragma warning(disable: 4100)
|
||||
|
||||
__declspec(naked) ulong ntohl(ulong netLong)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, [esp+4]
|
||||
bswap eax
|
||||
ret
|
||||
}
|
||||
} //lint !e533 !e715 // function should return a value, argument not referenced
|
||||
|
||||
__declspec(naked) ulong htonl(ulong hostLong)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, [esp+4]
|
||||
bswap eax
|
||||
ret
|
||||
}
|
||||
} //lint !e533 !e715 // function should return a value, argument not referenced
|
||||
|
||||
__declspec(naked) ushort ntohs(ushort netShort)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, [esp+4]
|
||||
bswap eax
|
||||
shr eax, 16
|
||||
ret
|
||||
}
|
||||
} //lint !e533 !e715 // function should return a value, argument not referenced
|
||||
|
||||
__declspec(naked) ushort htons(ushort hostShort)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, [esp+4]
|
||||
bswap eax
|
||||
shr eax, 16
|
||||
ret
|
||||
}
|
||||
} //lint !e533 !e715 // function should return a value, argument not referenced
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,22 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ByteOrder.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef BYTE_ORDER_H
|
||||
#define BYTE_ORDER_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
ulong __cdecl ntohl(ulong netLong);
|
||||
ushort __cdecl ntohs(ushort netShort);
|
||||
|
||||
ulong __cdecl htonl(ulong hostLong);
|
||||
ushort __cdecl htons(ushort hostShort);
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedFoundation.cpp
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/Production.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedFoundation", #a, b))
|
||||
#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedFoundation", #a, b))
|
||||
#define KEY_FLOAT(a,b) (ms_ ## a = ConfigFile::getKeyFloat("SharedFoundation", #a, b))
|
||||
#define KEY_STRING(a,b) (ms_ ## a = ConfigFile::getKeyString("SharedFoundation", #a, b))
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const int c_defaultFatalCallStackDepth = 32;
|
||||
const int c_defaultWarningCallStackDepth = PRODUCTION ? -1 : 8;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace ConfigSharedFoundationNamespace
|
||||
{
|
||||
bool ms_noExceptionHandling;
|
||||
|
||||
bool ms_fpuExceptionPrecision;
|
||||
bool ms_fpuExceptionUnderflow;
|
||||
bool ms_fpuExceptionOverflow;
|
||||
bool ms_fpuExceptionZeroDivide;
|
||||
bool ms_fpuExceptionDenormal;
|
||||
bool ms_fpuExceptionInvalid;
|
||||
|
||||
bool ms_demoMode;
|
||||
|
||||
real ms_frameRateLimit;
|
||||
real ms_minFrameRate;
|
||||
|
||||
bool ms_useRemoteDebug;
|
||||
int ms_defaultRemoteDebugPort;
|
||||
|
||||
bool ms_profilerExpandAllBranches;
|
||||
|
||||
bool ms_memoryManagerReportAllocations;
|
||||
bool ms_memoryManagerReportOnOutOfMemory;
|
||||
|
||||
bool ms_useMemoryBlockManager;
|
||||
bool ms_memoryBlockManagerDebugDumpOnRemove;
|
||||
|
||||
int ms_fatalCallStackDepth;
|
||||
int ms_warningCallStackDepth;
|
||||
bool ms_lookUpCallStackNames;
|
||||
|
||||
int ms_processPriority;
|
||||
|
||||
bool ms_verboseHardwareLogging;
|
||||
bool ms_verboseWarnings;
|
||||
|
||||
bool ms_causeAccessViolation;
|
||||
|
||||
float ms_debugReportLongFrameTime;
|
||||
}
|
||||
|
||||
using namespace ConfigSharedFoundationNamespace;
|
||||
|
||||
// ======================================================================
|
||||
// Determine the Platform-specific configuration information
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine inspects the ConfigFile class to set some variables for rapid access
|
||||
// by the rest of the engine.
|
||||
|
||||
void ConfigSharedFoundation::install (const Defaults &defaults)
|
||||
{
|
||||
KEY_BOOL(noExceptionHandling, false);
|
||||
|
||||
KEY_BOOL(fpuExceptionPrecision, false);
|
||||
KEY_BOOL(fpuExceptionUnderflow, false);
|
||||
KEY_BOOL(fpuExceptionOverflow, false);
|
||||
KEY_BOOL(fpuExceptionZeroDivide, false);
|
||||
KEY_BOOL(fpuExceptionDenormal, false);
|
||||
KEY_BOOL(fpuExceptionInvalid, false);
|
||||
|
||||
KEY_BOOL(demoMode, defaults.demoMode);
|
||||
|
||||
#if defined (WIN32) && PRODUCTION == 1
|
||||
// In production builds, force our frame rate limit to be the application defined limit
|
||||
ms_frameRateLimit = defaults.frameRateLimit;
|
||||
#else
|
||||
KEY_FLOAT(frameRateLimit, defaults.frameRateLimit);
|
||||
#endif
|
||||
|
||||
KEY_FLOAT(minFrameRate, 1.0f);
|
||||
|
||||
KEY_BOOL(useRemoteDebug, false);
|
||||
KEY_INT(defaultRemoteDebugPort, 4445);
|
||||
|
||||
KEY_BOOL(profilerExpandAllBranches, false);
|
||||
KEY_BOOL(memoryManagerReportAllocations, true);
|
||||
KEY_BOOL(memoryManagerReportOnOutOfMemory, true);
|
||||
KEY_BOOL(useMemoryBlockManager, true);
|
||||
KEY_BOOL(memoryBlockManagerDebugDumpOnRemove, false);
|
||||
|
||||
KEY_INT(fatalCallStackDepth, c_defaultFatalCallStackDepth);
|
||||
KEY_INT(warningCallStackDepth, PRODUCTION ? -1 : c_defaultWarningCallStackDepth);
|
||||
KEY_BOOL(lookUpCallStackNames, true);
|
||||
|
||||
KEY_INT(processPriority, 0);
|
||||
|
||||
KEY_BOOL(verboseHardwareLogging, false);
|
||||
KEY_BOOL(verboseWarnings, defaults.verboseWarnings);
|
||||
|
||||
KEY_BOOL(causeAccessViolation, false);
|
||||
|
||||
KEY_FLOAT(debugReportLongFrameTime, 0.25f);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return whether to run with exception handling enabled.
|
||||
*
|
||||
* @return True to run without exception handling
|
||||
*/
|
||||
|
||||
bool ConfigSharedFoundation::getNoExceptionHandling()
|
||||
{
|
||||
return ms_noExceptionHandling;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionPrecision()
|
||||
{
|
||||
return ms_fpuExceptionPrecision;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionUnderflow()
|
||||
{
|
||||
return ms_fpuExceptionUnderflow;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionOverflow()
|
||||
{
|
||||
return ms_fpuExceptionOverflow;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionZeroDivide()
|
||||
{
|
||||
return ms_fpuExceptionZeroDivide;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionDenormal()
|
||||
{
|
||||
return ms_fpuExceptionDenormal;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionInvalid()
|
||||
{
|
||||
return ms_fpuExceptionInvalid;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getDemoMode()
|
||||
{
|
||||
return ms_demoMode;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the frame rate limit value for the game.
|
||||
*
|
||||
* @return The initial frame rate limiter value
|
||||
*/
|
||||
|
||||
real ConfigSharedFoundation::getFrameRateLimit()
|
||||
{
|
||||
return ms_frameRateLimit;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the minimum frame rate value for the game. Frames that take longer
|
||||
* will log a warning and be hard set to the given value.
|
||||
*
|
||||
* @return The initial min frame rate value
|
||||
*/
|
||||
|
||||
real ConfigSharedFoundation::getMinFrameRate()
|
||||
{
|
||||
return ms_minFrameRate;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getDefaultRemoteDebugPort()
|
||||
{
|
||||
return ms_defaultRemoteDebugPort;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getUseRemoteDebug()
|
||||
{
|
||||
return ms_useRemoteDebug;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getProfilerExpandAllBranches()
|
||||
{
|
||||
return ms_profilerExpandAllBranches;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryManagerReportAllocations()
|
||||
{
|
||||
return ms_memoryManagerReportAllocations;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory()
|
||||
{
|
||||
return ms_memoryManagerReportOnOutOfMemory;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getUseMemoryBlockManager()
|
||||
{
|
||||
return ms_useMemoryBlockManager;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove ()
|
||||
{
|
||||
return ms_memoryBlockManagerDebugDumpOnRemove;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getFatalCallStackDepth()
|
||||
{
|
||||
return ms_fatalCallStackDepth;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getWarningCallStackDepth()
|
||||
{
|
||||
return ms_warningCallStackDepth;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getLookUpCallStackNames()
|
||||
{
|
||||
return ms_lookUpCallStackNames;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getProcessPriority()
|
||||
{
|
||||
return ms_processPriority;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getVerboseHardwareLogging()
|
||||
{
|
||||
return ms_verboseHardwareLogging;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getVerboseWarnings()
|
||||
{
|
||||
return ms_verboseWarnings;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ConfigSharedFoundation::setVerboseWarnings(bool const verboseWarnings)
|
||||
{
|
||||
ms_verboseWarnings = verboseWarnings;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getCauseAccessViolation()
|
||||
{
|
||||
return ms_causeAccessViolation;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float ConfigSharedFoundation::getDebugReportLongFrameTime()
|
||||
{
|
||||
return ms_debugReportLongFrameTime;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,74 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedFoundation.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ConfigSharedFoundation_H
|
||||
#define INCLUDED_ConfigSharedFoundation_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ConfigSharedFoundation
|
||||
{
|
||||
public:
|
||||
|
||||
struct Defaults
|
||||
{
|
||||
int screenHeight;
|
||||
int screenWidth;
|
||||
bool windowed;
|
||||
real frameRateLimit;
|
||||
bool demoMode;
|
||||
bool verboseWarnings;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void install(const Defaults &defaults);
|
||||
|
||||
static bool getNoExceptionHandling();
|
||||
|
||||
static bool getFpuExceptionPrecision();
|
||||
static bool getFpuExceptionUnderflow();
|
||||
static bool getFpuExceptionOverflow();
|
||||
static bool getFpuExceptionZeroDivide();
|
||||
static bool getFpuExceptionDenormal();
|
||||
static bool getFpuExceptionInvalid();
|
||||
|
||||
static bool getDemoMode();
|
||||
|
||||
static real getFrameRateLimit();
|
||||
static real getMinFrameRate();
|
||||
|
||||
static bool getUseRemoteDebug();
|
||||
static int getDefaultRemoteDebugPort();
|
||||
|
||||
static bool getProfilerExpandAllBranches();
|
||||
|
||||
static bool getMemoryManagerReportAllocations();
|
||||
static bool getMemoryManagerReportOnOutOfMemory();
|
||||
|
||||
static bool getUseMemoryBlockManager();
|
||||
static bool getMemoryBlockManagerDebugDumpOnRemove();
|
||||
|
||||
static int getFatalCallStackDepth();
|
||||
static int getWarningCallStackDepth();
|
||||
static bool getLookUpCallStackNames();
|
||||
|
||||
static int getProcessPriority();
|
||||
|
||||
static DLLEXPORT bool getVerboseHardwareLogging();
|
||||
static bool getVerboseWarnings();
|
||||
static void setVerboseWarnings(bool verboseWarnings);
|
||||
|
||||
static bool getCauseAccessViolation();
|
||||
|
||||
static float getDebugReportLongFrameTime();
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstPlatform.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_FirstPlatform_H
|
||||
#define INCLUDED_FirstPlatform_H
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include <WinNT.h>
|
||||
#include <WinDef.h>
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// C4127 conditional expression is constant
|
||||
// C4291 no matching operator delete found; memory will not be freed if initialization throws an exception
|
||||
// C4503 decorated name length exceeded, name was truncated
|
||||
// C4514 unreferenced inline function has been removed
|
||||
// C4702 unreachable code
|
||||
// C4710 inline function not expanded
|
||||
// C4786 identifier was truncated to 'number' characters in the debug
|
||||
|
||||
#pragma warning(disable: 4127 4291 4503 4514 4702 4710 4786)
|
||||
|
||||
// ======================================================================
|
||||
// If we haven't defined this yet, then we're not compiling a DLL
|
||||
|
||||
#ifndef COMPILE_DLL
|
||||
#define COMPILE_DLL 0
|
||||
#endif
|
||||
|
||||
#if COMPILE_DLL
|
||||
#define DLLEXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
template <class T>
|
||||
inline int ComGetReferenceCount(T *t)
|
||||
{
|
||||
t->AddRef();
|
||||
return t->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// forward declare some windows stuff to avoid having to include <windows.h> here
|
||||
|
||||
struct HCURSOR__;
|
||||
struct HICON__;
|
||||
struct HINSTANCE__;
|
||||
struct HWND__;
|
||||
|
||||
typedef void *HANDLE;
|
||||
typedef HICON__ *HCURSOR;
|
||||
typedef HICON__ *HICON;
|
||||
typedef HINSTANCE__ *HINSTANCE;
|
||||
typedef HWND__ *HWND;
|
||||
|
||||
// @todo codereorg still working on this
|
||||
#include "sharedFoundation/WindowsWrapper.h"
|
||||
|
||||
// ======================================================================
|
||||
// convienent fatal macros that check windows HRESULT codes
|
||||
|
||||
#define FATAL_HR(a,b) FATAL(FAILED(b), (a, HRESULT_CODE(b)))
|
||||
#define DEBUG_FATAL_HR(a,b) DEBUG_FATAL(FAILED(b), (a, HRESULT_CODE(b)))
|
||||
|
||||
// ======================================================================
|
||||
// include anything we need to replace missing functionality that other platforms provide
|
||||
|
||||
#include "sharedFoundation/PlatformGlue.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstFoundation.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
@@ -0,0 +1,257 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FloatingPointUnit.cpp
|
||||
// copyright 1999 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/FloatingPointUnit.h"
|
||||
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
int FloatingPointUnit::updateNumber;
|
||||
ushort FloatingPointUnit::status;
|
||||
FloatingPointUnit::Precision FloatingPointUnit::precision;
|
||||
FloatingPointUnit::Rounding FloatingPointUnit::rounding;
|
||||
bool FloatingPointUnit::exceptionEnabled[E_max];
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const WORD PRECISION_MASK = BINARY4(0000,0011,0000,0000);
|
||||
const WORD PRECISION_24 = BINARY4(0000,0000,0000,0000);
|
||||
const WORD PRECISION_53 = BINARY4(0000,0010,0000,0000);
|
||||
const WORD PRECISION_64 = BINARY4(0000,0011,0000,0000);
|
||||
|
||||
const WORD ROUND_MASK = BINARY4(0000,1100,0000,0000);
|
||||
const WORD ROUND_NEAREST = BINARY4(0000,0000,0000,0000);
|
||||
const WORD ROUND_CHOP = BINARY4(0000,1100,0000,0000);
|
||||
const WORD ROUND_DOWN = BINARY4(0000,0100,0000,0000);
|
||||
const WORD ROUND_UP = BINARY4(0000,1000,0000,0000);
|
||||
|
||||
const WORD EXCEPTION_PRECISION = BINARY4(0000,0000,0010,0000);
|
||||
const WORD EXCEPTION_UNDERFLOW = BINARY4(0000,0000,0001,0000);
|
||||
const WORD EXCEPTION_OVERFLOW = BINARY4(0000,0000,0000,1000);
|
||||
const WORD EXCEPTION_ZERO_DIVIDE = BINARY4(0000,0000,0000,0100);
|
||||
const WORD EXCEPTION_DENORMAL = BINARY4(0000,0000,0000,0010);
|
||||
const WORD EXCEPTION_INVALID = BINARY4(0000,0000,0000,0001);
|
||||
const WORD EXCEPTION_ALL = BINARY4(0000,0000,0011,1111);
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void FloatingPointUnit::install(void)
|
||||
{
|
||||
precision = P_24;
|
||||
rounding = R_roundToNearestOrEven;
|
||||
memset(exceptionEnabled, 0, sizeof(exceptionEnabled));
|
||||
|
||||
// preserve all other bits
|
||||
status = getControlWord();
|
||||
status &= ~(PRECISION_MASK | ROUND_MASK | EXCEPTION_ALL);
|
||||
|
||||
// set to single precision, rounding, and all exceptions masked
|
||||
status |= PRECISION_24 | ROUND_NEAREST | EXCEPTION_ALL;
|
||||
|
||||
// check the config platform flags to see if we should enable some exceptions
|
||||
if (ConfigSharedFoundation::getFpuExceptionPrecision())
|
||||
{
|
||||
exceptionEnabled[E_precision] = true;
|
||||
status &= ~EXCEPTION_PRECISION;
|
||||
}
|
||||
|
||||
if (ConfigSharedFoundation::getFpuExceptionUnderflow())
|
||||
{
|
||||
exceptionEnabled[E_underflow] = true;
|
||||
status &= ~EXCEPTION_UNDERFLOW;
|
||||
}
|
||||
|
||||
if (ConfigSharedFoundation::getFpuExceptionOverflow())
|
||||
{
|
||||
exceptionEnabled[E_overflow] = true;
|
||||
status &= ~EXCEPTION_OVERFLOW;
|
||||
}
|
||||
|
||||
if (ConfigSharedFoundation::getFpuExceptionZeroDivide())
|
||||
{
|
||||
exceptionEnabled[E_zeroDivide] = true;
|
||||
status &= ~EXCEPTION_ZERO_DIVIDE;
|
||||
}
|
||||
|
||||
if (ConfigSharedFoundation::getFpuExceptionDenormal())
|
||||
{
|
||||
exceptionEnabled[E_denormal] = true;
|
||||
status &= ~EXCEPTION_DENORMAL;
|
||||
}
|
||||
|
||||
if (ConfigSharedFoundation::getFpuExceptionInvalid())
|
||||
{
|
||||
exceptionEnabled[E_invalid] = true;
|
||||
status &= ~EXCEPTION_INVALID;
|
||||
}
|
||||
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::update(void)
|
||||
{
|
||||
WORD currentStatus = getControlWord();
|
||||
|
||||
if (currentStatus != status)
|
||||
{
|
||||
// DEBUG_REPORT_LOG_PRINT(true, ("FPU: update=%d, in mode=%04x, should be in mode=%04x\n", updateNumber, static_cast<int>(currentStatus), static_cast<int>(status)));
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
++updateNumber;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
WORD FloatingPointUnit::getControlWord(void)
|
||||
{
|
||||
WORD controlWord = 0;
|
||||
|
||||
__asm fnstcw controlWord;
|
||||
return controlWord;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::setControlWord(WORD controlWord)
|
||||
{
|
||||
UNREF(controlWord);
|
||||
__asm fldcw controlWord;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::setPrecision(Precision newPrecision)
|
||||
{
|
||||
WORD bits = 0;
|
||||
|
||||
switch (precision)
|
||||
{
|
||||
case P_24:
|
||||
bits = PRECISION_24;
|
||||
break;
|
||||
|
||||
case P_53:
|
||||
bits = PRECISION_53;
|
||||
break;
|
||||
|
||||
case P_64:
|
||||
bits = PRECISION_64;
|
||||
break;
|
||||
|
||||
case P_max:
|
||||
default:
|
||||
DEBUG_FATAL(true, ("bad case"));
|
||||
}
|
||||
|
||||
// record the current state
|
||||
precision = newPrecision;
|
||||
|
||||
// set the proper bit pattern
|
||||
status &= ~PRECISION_MASK;
|
||||
status |= bits;
|
||||
|
||||
// slam it into the FPU
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::setRounding(Rounding newRounding)
|
||||
{
|
||||
WORD bits = 0;
|
||||
|
||||
switch (newRounding)
|
||||
{
|
||||
case R_roundToNearestOrEven:
|
||||
bits = ROUND_NEAREST;
|
||||
break;
|
||||
|
||||
case R_chop:
|
||||
bits = ROUND_CHOP;
|
||||
break;
|
||||
|
||||
case R_roundDown:
|
||||
bits = ROUND_DOWN;
|
||||
break;
|
||||
|
||||
case R_roundUp:
|
||||
bits = ROUND_UP;
|
||||
break;
|
||||
|
||||
case R_max:
|
||||
default:
|
||||
DEBUG_FATAL(true, ("bad case"));
|
||||
}
|
||||
|
||||
// record the current state
|
||||
rounding = newRounding;
|
||||
|
||||
// set the proper bit pattern
|
||||
status &= ~ROUND_MASK;
|
||||
status |= bits;
|
||||
|
||||
// slam it into the FPU
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::setExceptionEnabled(Exception exception, bool enabled)
|
||||
{
|
||||
WORD bits = 0;
|
||||
|
||||
switch (exception)
|
||||
{
|
||||
case E_precision:
|
||||
bits = EXCEPTION_PRECISION;
|
||||
break;
|
||||
|
||||
case E_underflow:
|
||||
bits = EXCEPTION_UNDERFLOW;
|
||||
break;
|
||||
|
||||
case E_overflow:
|
||||
bits = EXCEPTION_OVERFLOW;
|
||||
break;
|
||||
|
||||
case E_zeroDivide:
|
||||
bits = EXCEPTION_ZERO_DIVIDE;
|
||||
break;
|
||||
|
||||
case E_denormal:
|
||||
bits = EXCEPTION_DENORMAL;
|
||||
break;
|
||||
|
||||
case E_invalid:
|
||||
bits = EXCEPTION_INVALID;
|
||||
break;
|
||||
|
||||
case E_max:
|
||||
default:
|
||||
DEBUG_FATAL(true, ("bad case"));
|
||||
}
|
||||
|
||||
// record the current state
|
||||
exceptionEnabled[exception] = enabled;
|
||||
|
||||
// twiddle the bit appropriately. these bits masks, so set the bit to disable the exception, clear the bit to enable it.
|
||||
if (enabled)
|
||||
status &= ~bits;
|
||||
else
|
||||
status |= bits;
|
||||
|
||||
// slam it into the FPU
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,104 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FloatingPointUnit.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1999 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef FLOATING_POINT_UNIT_H
|
||||
#define FLOATING_POINT_UNIT_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class FloatingPointUnit
|
||||
{
|
||||
public:
|
||||
|
||||
typedef unsigned short WORD;
|
||||
|
||||
enum Precision
|
||||
{
|
||||
P_24,
|
||||
P_53,
|
||||
P_64,
|
||||
|
||||
P_max
|
||||
};
|
||||
|
||||
enum Rounding
|
||||
{
|
||||
R_roundToNearestOrEven,
|
||||
R_chop,
|
||||
R_roundDown,
|
||||
R_roundUp,
|
||||
|
||||
R_max
|
||||
};
|
||||
|
||||
enum Exception
|
||||
{
|
||||
E_precision,
|
||||
E_underflow,
|
||||
E_overflow,
|
||||
E_zeroDivide,
|
||||
E_denormal,
|
||||
E_invalid,
|
||||
|
||||
E_max
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static int updateNumber;
|
||||
static WORD status;
|
||||
static Precision precision;
|
||||
static Rounding rounding;
|
||||
static bool exceptionEnabled[E_max];
|
||||
|
||||
public:
|
||||
|
||||
static WORD getControlWord(void);
|
||||
static void setControlWord(WORD controlWord);
|
||||
|
||||
public:
|
||||
|
||||
static void install(void);
|
||||
|
||||
static void update(void);
|
||||
|
||||
static void setPrecision(Precision newPrecision);
|
||||
static void setRounding(Rounding newRounding);
|
||||
static void setExceptionEnabled(Exception exception, bool enabled);
|
||||
|
||||
static Precision getPrecision(void);
|
||||
static Rounding getRounding(void);
|
||||
static bool getExceptionEnabled(Exception exception);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
inline FloatingPointUnit::Precision FloatingPointUnit::getPrecision(void)
|
||||
{
|
||||
return precision;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline FloatingPointUnit::Rounding FloatingPointUnit::getRounding(void)
|
||||
{
|
||||
return rounding;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool FloatingPointUnit::getExceptionEnabled(Exception theException)
|
||||
{
|
||||
DEBUG_FATAL(static_cast<int>(theException) < 0 || static_cast<int>(theException) >= static_cast<int>(E_max), ("exception out of range")); //lint !e568 // non-negative quantity is never less than 0
|
||||
return exceptionEnabled[theException];
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+1633
File diff suppressed because it is too large
Load Diff
+152
@@ -0,0 +1,152 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Os.h
|
||||
//
|
||||
// Portions copyright 1998 Bootprint Entertainment
|
||||
// Portions copyright 2000-2002 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Os_H
|
||||
#define INCLUDED_Os_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include <ctime>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Os
|
||||
{
|
||||
public:
|
||||
|
||||
typedef bool (*IsGdiVisibleHookFunction)();
|
||||
typedef void (*LostFocusHookFunction)();
|
||||
typedef void (*AcquiredFocusHookFunction)();
|
||||
typedef void (*QueueCharacterHookFunction)(int keyboard, int character);
|
||||
typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y);
|
||||
typedef bool (*GetHardwareMouseCursorEnabled)();
|
||||
typedef void (*GetOtherAdapterRectsHookFunction)(stdvector<RECT>::fwd &);
|
||||
typedef void (*WindowPositionChangedHookFunction)();
|
||||
typedef void (*DisplayModeChangedHookFunction)();
|
||||
typedef void (*InputLanguageChangedHookFunction)();
|
||||
typedef int (*IMEHookFunction)(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
typedef void (*QueueKeyDownHookFunction)(int keyboard, int character);
|
||||
|
||||
typedef uint ThreadId;
|
||||
typedef DWORD OsPID_t;
|
||||
|
||||
enum Priority
|
||||
{
|
||||
P_high,
|
||||
P_normal,
|
||||
P_low
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_PATH_LENGTH = 512
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void install(HINSTANCE newInstance, const char *windowName, HICON normalIcon, HICON smallIcon);
|
||||
static void install(HWND newWindow, bool processMessagePump);
|
||||
static void install();
|
||||
|
||||
static bool isGameOver();
|
||||
static DLLEXPORT bool isMainThread();
|
||||
static bool wasFocusLost();
|
||||
static void checkChildThreads();
|
||||
|
||||
static void setProcessPriority(Priority priority);
|
||||
|
||||
static bool update();
|
||||
|
||||
static void returnFromAbort();
|
||||
static void abort();
|
||||
|
||||
static void enablePopupDebugMenu();
|
||||
static void requestPopupDebugMenu();
|
||||
|
||||
static bool createDirectories (const char *dirname);
|
||||
|
||||
static bool writeFile(const char *fileName, const void *data, int length);
|
||||
|
||||
static HWND getWindow();
|
||||
static bool engineOwnsWindow();
|
||||
|
||||
static int getNumberOfUpdates();
|
||||
|
||||
static char *getLastError();
|
||||
|
||||
static const char *getProgramName();
|
||||
static const char *getShortProgramName();
|
||||
static const char *getProgramStartupDirectory();
|
||||
|
||||
static void setIsGdiVisibleHookFunction(IsGdiVisibleHookFunction newGlIsGdiVisible);
|
||||
static void setLostFocusHookFunction(LostFocusHookFunction lostFocusHookFunction);
|
||||
static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction);
|
||||
static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction);
|
||||
static void setSetSystemMouseCursorPositionHookFunction2(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction);
|
||||
static void setAcquiredFocusHookFunction(AcquiredFocusHookFunction acquiredFocusHookFunction);
|
||||
static void setAcquiredFocusHookFunction2(AcquiredFocusHookFunction acquiredFocusHookFunction);
|
||||
static void setGetHardwareMouseCursorEnabled(GetHardwareMouseCursorEnabled getHardwareMouseCursorEnabled);
|
||||
static void setGetOtherAdapterRectsHookFunction(GetOtherAdapterRectsHookFunction getOtherAdapterRectsHookFunction);
|
||||
static void setWindowPositionChangedHookFunction(WindowPositionChangedHookFunction windowPositionChangedHookFunction);
|
||||
static void setDisplayModeChangedHookFunction(DisplayModeChangedHookFunction displayModeChangedHookFunction);
|
||||
static void setInputLanguageChangedHookFunction(InputLanguageChangedHookFunction inputLanguageChangedHookFunction);
|
||||
static void setIMEHookFunction(IMEHookFunction imeHookFunction);
|
||||
static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction);
|
||||
|
||||
static DLLEXPORT ThreadId getThreadId();
|
||||
static void setThreadName(ThreadId threadID, const char* name);
|
||||
|
||||
static void sleep(int ms);
|
||||
|
||||
static time_t getRealSystemTime();
|
||||
static void convertTimeToGMT(const time_t &time, tm &zulu);
|
||||
static time_t convertGMTToTime(const tm &zulu);
|
||||
|
||||
static bool isMultiprocessor();
|
||||
static int getProcessorCount();
|
||||
|
||||
static void buildRelativePath(const char *baseDirectory, const char *targetPathname, std::string &relativePath);
|
||||
static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize);
|
||||
|
||||
static bool copyTextToClipboard(const char *text);
|
||||
|
||||
static bool getUserName(char *buffer, int &bufferSize);
|
||||
|
||||
static OsPID_t getProcessId();
|
||||
|
||||
static bool isFocused();
|
||||
|
||||
static bool launchBrowser(std::string const & website);
|
||||
static bool isNumPadValue(unsigned char asciiChar);
|
||||
static bool isNumPadChar(unsigned char asciiChar);
|
||||
|
||||
private:
|
||||
|
||||
Os();
|
||||
Os(const Os &);
|
||||
Os &operator =(const Os &);
|
||||
|
||||
private:
|
||||
|
||||
static void remove();
|
||||
static void installCommon();
|
||||
|
||||
static LRESULT CALLBACK Os::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
static bool handleDebugMenu();
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,465 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PerThreadData.cpp
|
||||
//
|
||||
// Portions copyright 1998 Bootprint Entertainment
|
||||
// Portions Copyright 2002 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/PerThreadData.h"
|
||||
|
||||
#include "sharedSynchronization/RecursiveMutex.h"
|
||||
#include "sharedSynchronization/Gate.h"
|
||||
|
||||
#include "sharedFoundation/Os.h"
|
||||
|
||||
#include <winbase.h>
|
||||
#include <vector>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// ======================================================================
|
||||
namespace PerThreadDataNamespace
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
bool exitChainRunning;
|
||||
bool exitChainFataling;
|
||||
ExitChain::Entry *exitChainFirstEntry;
|
||||
|
||||
int debugPrintFlags;
|
||||
|
||||
Gate *fileStreamerReadGate;
|
||||
|
||||
HANDLE watchHandle;
|
||||
};
|
||||
|
||||
typedef std::vector<Data *> DataAllocations;
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
static char buffer1[sizeof(RecursiveMutex)];
|
||||
static char buffer2[sizeof(DataAllocations)];
|
||||
|
||||
static const DWORD BadSlot = 0xffffffff;
|
||||
|
||||
static DWORD slot = BadSlot;
|
||||
static RecursiveMutex *criticalSection;
|
||||
static DataAllocations *dataAllocations;
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
static void _threadRemove(Data *data);
|
||||
static void _removeFromList(Data *data);
|
||||
static void _watchThreads();
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Get access to the per-thread-data.
|
||||
*
|
||||
* This routine will verify the per-thread-data subsystem has been installed and the
|
||||
* threadInstall() function has been called for the current thread.
|
||||
*
|
||||
* @return A pointer to the per-thread-data.
|
||||
*/
|
||||
inline static Data *_getData(bool allowReturnNull=false)
|
||||
{
|
||||
UNREF(allowReturnNull);
|
||||
|
||||
if (slot == BadSlot)
|
||||
{
|
||||
DEBUG_FATAL(true && !allowReturnNull, ("not installed"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Data * const data = reinterpret_cast<Data *>(TlsGetValue(slot));
|
||||
DEBUG_FATAL(!data && !allowReturnNull, ("not installed for this thread"));
|
||||
return data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
inline static void _closeData(Data *data)
|
||||
{
|
||||
if (data->fileStreamerReadGate)
|
||||
{
|
||||
delete data->fileStreamerReadGate;
|
||||
data->fileStreamerReadGate=0;
|
||||
}
|
||||
if (data->watchHandle)
|
||||
{
|
||||
CloseHandle(data->watchHandle);
|
||||
data->watchHandle=0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
inline static void _freeData(Data *data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
}
|
||||
using namespace PerThreadDataNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// ======================================================================
|
||||
// Install the per-thread-data subsystem
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine will install the per-thread-data subsystem that is required for several
|
||||
// other subsystems in the engine. It should be called from the primary thread before
|
||||
// any other threads have been created. It will also call threadInstall() for the
|
||||
// primary thread.
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// PerThreadData::remove()
|
||||
|
||||
void PerThreadData::install()
|
||||
{
|
||||
slot = TlsAlloc();
|
||||
FATAL(slot == BadSlot, ("TlsAlloc failed"));
|
||||
|
||||
criticalSection = new(buffer1) RecursiveMutex;
|
||||
dataAllocations = new(buffer2) DataAllocations;
|
||||
dataAllocations->reserve(8);
|
||||
threadInstall();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Remove the per-thread-subsystem.
|
||||
*
|
||||
* This routine should be called by the primary thread after all other threads have
|
||||
* terminated, and no other uses of per-thread-data will occur.
|
||||
*
|
||||
* @see PerThreadData::install()
|
||||
*/
|
||||
void PerThreadData::remove()
|
||||
{
|
||||
criticalSection->enter();
|
||||
{
|
||||
// remove this thread.
|
||||
threadRemove();
|
||||
|
||||
// clean up after any threads which didn't clean up after themselves (like the miles sound system)
|
||||
const DataAllocations::iterator iEnd = dataAllocations->end();
|
||||
for (DataAllocations::iterator i = dataAllocations->begin(); i != iEnd; ++i)
|
||||
{
|
||||
_closeData(*i);
|
||||
_freeData(*i);
|
||||
}
|
||||
|
||||
dataAllocations->clear();
|
||||
}
|
||||
criticalSection->leave();
|
||||
|
||||
criticalSection->~RecursiveMutex();
|
||||
dataAllocations->~vector();
|
||||
|
||||
memset(buffer1, 0, sizeof(buffer1));
|
||||
memset(buffer2, 0, sizeof(buffer2));
|
||||
|
||||
const BOOL result = TlsFree(slot);
|
||||
FATAL(!result, ("TlsFree failed"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Create the per-thread-data for a new thread.
|
||||
*
|
||||
* This routine should be called in a thread before the first usage of per-thread-data.
|
||||
*
|
||||
* If the client is calling this function on a thread that existed before the engine was
|
||||
* installed, the client should set isNewThread to false. Setting isNewThread to false
|
||||
* prevents the function from validating that the thread's TLS is NULL. For threads existing
|
||||
* before the engine is installed, the TLS data for the thread is undefined.
|
||||
*
|
||||
* @param isNewThread [IN] true if the thread was created after the engine was installed, false otherwise
|
||||
* @see PerThreadData::threadRemove()
|
||||
*/
|
||||
|
||||
void PerThreadData::threadInstall(bool isNewThread)
|
||||
{
|
||||
UNREF(isNewThread);
|
||||
|
||||
DEBUG_FATAL(slot == BadSlot, ("not installed"));
|
||||
|
||||
// only check for already-set data if this is supposed to be a new thread
|
||||
DEBUG_FATAL(isNewThread && TlsGetValue(slot), ("already installed for this thread"));
|
||||
|
||||
// create the data
|
||||
Data * const data = new Data;
|
||||
|
||||
// initialize the data
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
//create the event for file streaming reads
|
||||
data->fileStreamerReadGate = new Gate(false);
|
||||
|
||||
// set the data into the thread slot
|
||||
const BOOL result = TlsSetValue(slot, data);
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(!result, ("TlsSetValue failed"));
|
||||
|
||||
criticalSection->enter();
|
||||
{
|
||||
_watchThreads();
|
||||
|
||||
dataAllocations->push_back(data);
|
||||
|
||||
// This is most likely a thread created by a 3rd party library such as Miles or Bink.
|
||||
// Add a watch handle to it so we can clean it up.
|
||||
if (!isNewThread)
|
||||
{
|
||||
const HANDLE processHandle = GetCurrentProcess();
|
||||
DuplicateHandle(processHandle, GetCurrentThread(), processHandle, &data->watchHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
}
|
||||
}
|
||||
criticalSection->leave();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void PerThreadDataNamespace::_removeFromList(Data *data)
|
||||
{
|
||||
const DataAllocations::iterator iEnd = dataAllocations->end();
|
||||
const DataAllocations::iterator i = std::find(dataAllocations->begin(), iEnd, data);
|
||||
if (i!=iEnd)
|
||||
{
|
||||
dataAllocations->erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Synchronization is left up to the user
|
||||
// Unless this is called during shutdown, the critical section
|
||||
// needs to be entered.
|
||||
void PerThreadDataNamespace::_watchThreads()
|
||||
{
|
||||
DataAllocations::iterator tiDest = dataAllocations->begin();
|
||||
DataAllocations::iterator tiSrc = tiDest;
|
||||
DataAllocations::iterator tiEnd = dataAllocations->end();
|
||||
|
||||
while (tiSrc!=tiEnd)
|
||||
{
|
||||
Data *const data = *tiSrc;
|
||||
const HANDLE h = data->watchHandle;
|
||||
|
||||
if (h!=0 && WaitForSingleObject(h, 0)==WAIT_OBJECT_0)
|
||||
{
|
||||
_closeData(data);
|
||||
_freeData(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
*tiDest++=data;
|
||||
}
|
||||
++tiSrc;
|
||||
}
|
||||
|
||||
if (tiSrc!=tiDest)
|
||||
{
|
||||
const int newSize = tiDest - dataAllocations->begin();
|
||||
dataAllocations->resize(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void PerThreadDataNamespace::_threadRemove(Data *data)
|
||||
{
|
||||
//close the event used for file streaming reads
|
||||
_closeData(data);
|
||||
|
||||
_removeFromList(data);
|
||||
|
||||
// free the memory
|
||||
_freeData(data);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Destroy the per-thread-data for a terminating thread.
|
||||
*
|
||||
* This routine should be called in a thread after the last usage of per-thread-data.
|
||||
*
|
||||
* @see PerThreadData::threadInstall()
|
||||
*/
|
||||
|
||||
void PerThreadData::threadRemove()
|
||||
{
|
||||
DEBUG_FATAL(slot == BadSlot, ("not installed"));
|
||||
DEBUG_FATAL(!TlsGetValue(slot), ("thread not installed"));
|
||||
|
||||
// find our thread record and free the memory
|
||||
criticalSection->enter();
|
||||
|
||||
_threadRemove(_getData());
|
||||
|
||||
// wipe the data in the thread slot
|
||||
const BOOL result = TlsSetValue(slot, NULL);
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(!result, ("TlsSetValue failed"));
|
||||
|
||||
criticalSection->leave();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// ======================================================================
|
||||
// Determine if the per-thread-data is available for this thread
|
||||
//
|
||||
// Return value:
|
||||
//
|
||||
// True if the per-thread-data is installed correctly, false otherwise
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
//
|
||||
// -TRF- looks like Win98 does not zero out a new TLS slot for
|
||||
// threads existing at the time of slot creation. Thus, if you build a
|
||||
// plugin that only initializes the engine the first time it is
|
||||
// used, and other threads already exist in the app, those threads
|
||||
// will contain bogus non-null data in the TLS slot. If the plugin really
|
||||
// wants to do lazy initialization of the engine, it will need
|
||||
// to handle calling PerThreadData::threadInstall() for all existing threads
|
||||
// (except the thread that initialized the engine, which already
|
||||
// has its PerThreadData::threadInstall() called).
|
||||
|
||||
bool PerThreadData::isThreadInstalled()
|
||||
{
|
||||
return (_getData(true) != NULL);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the exit chain running flag value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
*
|
||||
* @return True if the exit chain is running, false otherwise.
|
||||
* @see ExitChain::isRunning()
|
||||
*/
|
||||
|
||||
bool PerThreadData::getExitChainRunning()
|
||||
{
|
||||
return _getData()->exitChainRunning;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the exit chain running flag value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
*
|
||||
* @param newValue New value for the exit chain running flag
|
||||
*/
|
||||
|
||||
void PerThreadData::setExitChainRunning(bool newValue)
|
||||
{
|
||||
_getData()->exitChainRunning = newValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the exit chain fataling flag value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
*
|
||||
* @return True if the exit chain is fataling, false otherwise.
|
||||
* @see ExitChain::isFataling()
|
||||
*/
|
||||
|
||||
bool PerThreadData::getExitChainFataling()
|
||||
{
|
||||
return _getData()->exitChainFataling;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the exit chain fataling flag value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
*
|
||||
* @param newValue New value for the exit chain fataling flag
|
||||
*/
|
||||
|
||||
void PerThreadData::setExitChainFataling(bool newValue)
|
||||
{
|
||||
_getData()->exitChainFataling = newValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the first entry for the exit chain.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
* This routine may return NULL.
|
||||
*
|
||||
* @return Pointer to the first entry on the exit chain
|
||||
* @see ExitChain::isFataling()
|
||||
*/
|
||||
|
||||
ExitChain::Entry *PerThreadData::getExitChainFirstEntry()
|
||||
{
|
||||
return _getData()->exitChainFirstEntry;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the exit chain fataling flag value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the ExitChain class.
|
||||
* The parameter to this routine may be NULL.
|
||||
*
|
||||
* @param newValue New value for the exit chain first entry
|
||||
*/
|
||||
|
||||
void PerThreadData::setExitChainFirstEntry(ExitChain::Entry *newValue)
|
||||
{
|
||||
_getData()->exitChainFirstEntry = newValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the debug print flags.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the DebugPrint functions.
|
||||
*
|
||||
* @return Current value of the debug print flags
|
||||
*/
|
||||
|
||||
int PerThreadData::getDebugPrintFlags()
|
||||
{
|
||||
return _getData()->debugPrintFlags;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the debug print flags value.
|
||||
*
|
||||
* This routine is not intended for general use; it should only be used by the DebugPrint functions.
|
||||
*/
|
||||
|
||||
void PerThreadData::setDebugPrintFlags(int newValue)
|
||||
{
|
||||
_getData()->debugPrintFlags = newValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Gate *PerThreadData::getFileStreamerReadGate()
|
||||
{
|
||||
return _getData()->fileStreamerReadGate;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,57 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PerThreadData.h
|
||||
//
|
||||
// Portions copyright 1998 Bootprint Entertainment
|
||||
// Portions Copyright 2002 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_PerThreadData_H
|
||||
#define INCLUDED_PerThreadData_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Gate;
|
||||
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// Provide thread local storage functionality.
|
||||
//
|
||||
// This class' purpose is to allow each thread to maintain some storage that is local and private to each thread.
|
||||
// The system must be installed before use. Each thread that may use per-thread-data will also need to call the
|
||||
// threadInstall() routine after creation and threadRemove() just before termination of the thread.
|
||||
|
||||
class PerThreadData
|
||||
{
|
||||
public:
|
||||
|
||||
static void install(void);
|
||||
static void remove(void);
|
||||
|
||||
static void threadInstall(bool isNewThread = true);
|
||||
static void threadRemove(void);
|
||||
|
||||
static bool isThreadInstalled(void);
|
||||
|
||||
static bool getExitChainRunning(void);
|
||||
static void setExitChainRunning(bool newValue);
|
||||
|
||||
static bool getExitChainFataling(void);
|
||||
static void setExitChainFataling(bool newValue);
|
||||
|
||||
static ExitChain::Entry *getExitChainFirstEntry(void);
|
||||
static void setExitChainFirstEntry(ExitChain::Entry *newValue);
|
||||
|
||||
static int getDebugPrintFlags(void);
|
||||
static void setDebugPrintFlags(int newValue);
|
||||
|
||||
static Gate *getFileStreamerReadGate(void);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PlatformGlue.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/PlatformGlue.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class GmTimeSection
|
||||
{
|
||||
public:
|
||||
|
||||
GmTimeSection()
|
||||
{
|
||||
InitializeCriticalSection(&m_section);
|
||||
}
|
||||
|
||||
~GmTimeSection()
|
||||
{
|
||||
DeleteCriticalSection(&m_section);
|
||||
}
|
||||
|
||||
void enter()
|
||||
{
|
||||
EnterCriticalSection(&m_section);
|
||||
}
|
||||
|
||||
void leave()
|
||||
{
|
||||
LeaveCriticalSection(&m_section);
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION m_section;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static GmTimeSection s_gmTimeSection;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Tokenizing a string.
|
||||
// Like strtok, except re-entrant.
|
||||
|
||||
char *strsep(char **string, const char *delim)
|
||||
{
|
||||
char *result = *string;
|
||||
|
||||
// handle no string specified, or the end of the string
|
||||
if (result == 0)
|
||||
return 0;
|
||||
|
||||
// skip leading delimiters
|
||||
result = result + strspn(result, delim);
|
||||
|
||||
// handle trailing delimiters
|
||||
if (*result == '\0')
|
||||
return 0;
|
||||
|
||||
// look for the first delimiter
|
||||
const int len = strcspn(result, delim);
|
||||
if (result[len] == '\0')
|
||||
{
|
||||
// hit the end of the string
|
||||
*string = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// terminate the string and return the substring
|
||||
result[len] = '\0';
|
||||
*string = result + len + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int snprintf(char *buffer, size_t count, const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
const int result = _vsnprintf(buffer, count, format, va);
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
s_gmTimeSection.enter();
|
||||
tm *t = gmtime(timep);
|
||||
*result = *t;
|
||||
s_gmTimeSection.leave();
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int finite(double value)
|
||||
{
|
||||
return _finite(value);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,32 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PlatformGlue.h
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_PlatformGlue_H
|
||||
#define INCLUDED_PlatformGlue_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include <time.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
char * strsep(char **string, const char *delim);
|
||||
int snprintf(char *buffer, size_t count, const char *format, ...);
|
||||
struct tm * gmtime_r(const time_t *timep, struct tm *result);
|
||||
int finite(double value);
|
||||
|
||||
//Format specifier for non-portable printf
|
||||
#define UINT64_FORMAT_SPECIFIER "%I64u"
|
||||
#define INT64_FORMAT_SPECIFIER "%I64i"
|
||||
|
||||
//Constant definition macro for 64 bit values
|
||||
#define UINT64_LITERAL(a) a ## ui64
|
||||
#define INT64_LITERAL(a) a ## i64
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,310 @@
|
||||
//
|
||||
// ProcessSpawner.cpp
|
||||
//
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/ProcessSpawner.h"
|
||||
|
||||
#include "sharedFoundation/Os.h"
|
||||
|
||||
#include <minmax.h>
|
||||
|
||||
ProcessSpawner::ProcessSpawner()
|
||||
{
|
||||
m_asConsole=false;
|
||||
hProcess=0;
|
||||
hOutputRead=0;
|
||||
hInputWrite=0;
|
||||
currentLine=currentRead=readBuffer;
|
||||
}
|
||||
|
||||
|
||||
ProcessSpawner::~ProcessSpawner()
|
||||
{
|
||||
if (hProcess)
|
||||
{
|
||||
CloseHandle(hProcess);
|
||||
hProcess=0;
|
||||
}
|
||||
if (hOutputRead)
|
||||
{
|
||||
CloseHandle(hOutputRead);
|
||||
hOutputRead=0;
|
||||
}
|
||||
if (hInputWrite)
|
||||
{
|
||||
CloseHandle(hInputWrite);
|
||||
hInputWrite=0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::terminate(unsigned exitCode)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return TerminateProcess(hProcess, exitCode)!=0;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::create(const char *commandLine, const char *startupFolder, bool asConsole)
|
||||
{
|
||||
if (hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!commandLine)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!startupFolder)
|
||||
{
|
||||
startupFolder=Os::getProgramStartupDirectory();
|
||||
}
|
||||
|
||||
m_asConsole=asConsole;
|
||||
|
||||
STARTUPINFO sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
sinfo.cb=sizeof(sinfo);
|
||||
|
||||
HANDLE hOutputWrite=0;
|
||||
HANDLE hErrorWrite=0;
|
||||
HANDLE hInputRead=0;
|
||||
|
||||
if (asConsole)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength=sizeof(sa);
|
||||
sa.lpSecurityDescriptor=0;
|
||||
sa.bInheritHandle=true;
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
||||
// Create the child output pipe.
|
||||
HANDLE hOutputReadTmp;
|
||||
CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0);
|
||||
|
||||
// Create a duplicate of the output write handle for the std error
|
||||
// write handle. This is necessary in case the child application
|
||||
// closes one of its std output handles.
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hOutputWrite,
|
||||
GetCurrentProcess(),&hErrorWrite,
|
||||
0,
|
||||
TRUE,DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
|
||||
// Create the child input pipe.
|
||||
HANDLE hInputWriteTmp;
|
||||
CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0);
|
||||
|
||||
// Create new output read handle and the input write handles. Set
|
||||
// the Properties to FALSE. Otherwise, the child inherits the
|
||||
// properties and, as a result, non-closeable handles to the pipes
|
||||
// are created.
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hOutputReadTmp,
|
||||
GetCurrentProcess(), &hOutputRead, // Address of new handle.
|
||||
0, FALSE, // Make it uninheritable.
|
||||
DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hInputWriteTmp,
|
||||
GetCurrentProcess(), &hInputWrite, // Address of new handle.
|
||||
0,FALSE, // Make it uninheritable.
|
||||
DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
|
||||
// Close inheritable copies of the handles you do not want to be
|
||||
// inherited.
|
||||
CloseHandle(hOutputReadTmp); hOutputReadTmp=0;
|
||||
CloseHandle(hInputWriteTmp); hInputWriteTmp=0;
|
||||
|
||||
sinfo.dwFlags|=(STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
|
||||
sinfo.hStdError=hErrorWrite;
|
||||
sinfo.hStdInput=hInputRead;
|
||||
sinfo.hStdOutput=hOutputWrite;
|
||||
sinfo.wShowWindow = SW_HIDE;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION pinfo;
|
||||
BOOL result = CreateProcess(
|
||||
0,
|
||||
(char *)commandLine,
|
||||
0,
|
||||
0,
|
||||
TRUE,
|
||||
CREATE_NEW_CONSOLE,
|
||||
0,
|
||||
startupFolder,
|
||||
&sinfo,
|
||||
&pinfo
|
||||
);
|
||||
|
||||
if (asConsole)
|
||||
{
|
||||
// Close pipe handles (do not continue to modify the parent).
|
||||
// You need to make sure that no handles to the write end of the
|
||||
// output pipe are maintained in this process or else the pipe will
|
||||
// not close when the child process exits and the ReadFile will hang.
|
||||
CloseHandle(hOutputWrite); hOutputWrite=0;
|
||||
CloseHandle(hErrorWrite); hErrorWrite=0;
|
||||
CloseHandle(hInputRead); hInputRead=0;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
CloseHandle(pinfo.hThread);
|
||||
hProcess=pinfo.hProcess;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to launch turf
|
||||
hProcess=0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::isFinished(unsigned waitTime)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD waitResult = WaitForSingleObject(hProcess, waitTime);
|
||||
|
||||
return waitResult==WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::getExitCode(unsigned &o_code)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD exitCode;
|
||||
BOOL result = GetExitCodeProcess(hProcess, &exitCode);
|
||||
if (result)
|
||||
{
|
||||
o_code=exitCode;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::_returnExistingLine(char *buffer, const int bufferSize)
|
||||
{
|
||||
const char *const bufferStop = buffer + bufferSize;
|
||||
char *iter = currentLine;
|
||||
while (iter!=currentRead)
|
||||
{
|
||||
if (buffer==bufferStop)
|
||||
{
|
||||
currentLine=iter;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*iter=='\n')
|
||||
{
|
||||
*buffer++=0;
|
||||
_stepIter(iter);
|
||||
currentLine=iter;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buffer++=*iter;
|
||||
_stepIter(iter);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::getOutputString(char *buffer, int bufferSize)
|
||||
{
|
||||
if (_returnExistingLine(buffer, bufferSize))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
if (!hOutputRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwAvail = 0;
|
||||
if (!::PeekNamedPipe(hOutputRead, NULL, 0, NULL, &dwAvail, NULL))
|
||||
{
|
||||
// ERROR
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dwAvail)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwRead;
|
||||
|
||||
if (currentRead >= currentLine)
|
||||
{
|
||||
const unsigned bufferAvailable = sizeof(readBuffer) - (currentRead - readBuffer);
|
||||
unsigned toRead = dwAvail;
|
||||
if (toRead > bufferAvailable)
|
||||
{
|
||||
toRead=bufferAvailable;
|
||||
}
|
||||
|
||||
dwRead=0;
|
||||
if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
dwAvail-=dwRead;
|
||||
currentRead+=dwRead;
|
||||
if (currentRead==readBuffer+sizeof(readBuffer))
|
||||
{
|
||||
currentRead=readBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwAvail>0)
|
||||
{
|
||||
const unsigned bufferAvailable = currentLine - currentRead - 1;
|
||||
if (bufferAvailable)
|
||||
{
|
||||
unsigned toRead = dwAvail;
|
||||
if (toRead > bufferAvailable)
|
||||
{
|
||||
toRead=bufferAvailable;
|
||||
}
|
||||
|
||||
dwRead=0;
|
||||
if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
currentRead+=dwRead;
|
||||
|
||||
DEBUG_FATAL(currentRead>=currentLine, (""));
|
||||
}
|
||||
}
|
||||
|
||||
return _returnExistingLine(buffer, bufferSize);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef INCLUDED_ProcessSpawner_H
|
||||
#define INCLUDED_ProcessSpawner_H
|
||||
|
||||
class ProcessSpawner
|
||||
{
|
||||
public:
|
||||
|
||||
ProcessSpawner();
|
||||
~ProcessSpawner();
|
||||
|
||||
bool create(const char *commandLine, const char *startupFolder=0, bool asConsole=true);
|
||||
|
||||
bool terminate(unsigned exitCode=0);
|
||||
bool isFinished(unsigned waitTime=0);
|
||||
bool getExitCode(unsigned &o_code);
|
||||
|
||||
bool getOutputString(char *buffer, int bufferSize);
|
||||
|
||||
protected:
|
||||
|
||||
bool _returnExistingLine(char *buffer, int bufferSize);
|
||||
|
||||
void _stepIter(char *&i)
|
||||
{
|
||||
if (i==readBuffer+sizeof(readBuffer)-1)
|
||||
{
|
||||
i=readBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE hProcess;
|
||||
HANDLE hOutputRead, hInputWrite;
|
||||
bool m_asConsole;
|
||||
char *currentLine, *currentRead, readBuffer[4096];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,918 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RegistryKey.cpp
|
||||
// Todd Fiala
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/RegistryKey.h"
|
||||
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// keyname for config file parameter containing relative registry path
|
||||
// for the product
|
||||
|
||||
const char * const RegistryKey::PRODUCT_REGISTRY_PATH_KEYNAME = "ProductRegistryPath";
|
||||
const char * const RegistryKey::DEFAULT_PRODUCT_REGISTRY_PATH = "Software\\Sony Online Entertainment\\Default";
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
const char * const RegistryKey::STATISTICS_KEYNAME = "Statistics";
|
||||
const char * const RegistryKey::STAT_EXEC_STARTED_COUNT_VALUENAME = "StartedExecutions";
|
||||
const char * const RegistryKey::STAT_EXEC_INCOMPLETE_COUNT_VALUENAME = "IncompleteExecutions";
|
||||
const char * const RegistryKey::STAT_TIME_AVERAGE_VALUENAME = "AverageClockTime";
|
||||
const char * const RegistryKey::STAT_TIME_MIN_VALUENAME = "MinimumClockTime";
|
||||
const char * const RegistryKey::STAT_TIME_MAX_VALUENAME = "MaximumClockTime";
|
||||
const char * const RegistryKey::STAT_TIME_START_VALUENAME = "StartClockTime";
|
||||
|
||||
#endif
|
||||
|
||||
bool RegistryKey::installed;
|
||||
bool RegistryKey::setProductKeyPathFromConfig;
|
||||
|
||||
RegistryKey *RegistryKey::usersKey;
|
||||
RegistryKey *RegistryKey::currentUserKey;
|
||||
RegistryKey *RegistryKey::classRootKey;
|
||||
RegistryKey *RegistryKey::localMachineKey;
|
||||
RegistryKey *RegistryKey::productUserKey;
|
||||
RegistryKey *RegistryKey::productMachineKey;
|
||||
|
||||
// ======================================================================
|
||||
// construct a RegistryKey instance
|
||||
//
|
||||
// Remarks:
|
||||
// This function does not create the underlying registry object. It
|
||||
// solely attaches such a registry object with a RegistryKey class
|
||||
// instance.
|
||||
|
||||
RegistryKey::RegistryKey(
|
||||
HKEY newKeyHandle, // [IN] handle of existing registry key
|
||||
bool newCloseKeyOnDestroy // [IN] true if RegCloseKey() should be called on key at destruction time
|
||||
) :
|
||||
keyHandle(newKeyHandle),
|
||||
closeKeyOnDestroy(newCloseKeyOnDestroy)
|
||||
{
|
||||
// -qq- don't know which of these indicates an invalid handle, so check for both
|
||||
DEBUG_FATAL(!newKeyHandle, ("null newKeyHandle arg"));
|
||||
DEBUG_FATAL(newKeyHandle == INVALID_HANDLE_VALUE, ("newKeyHandle arg is an invalid handle"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* destroy a RegistryKey instance.
|
||||
*/
|
||||
|
||||
RegistryKey::~RegistryKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
|
||||
if (closeKeyOnDestroy)
|
||||
{
|
||||
const LONG result = RegCloseKey(keyHandle);
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(result != ERROR_SUCCESS, ("failed to close registry key, error = %ld\n", result));
|
||||
}
|
||||
keyHandle = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* enumerate all child subkeys of the current key.
|
||||
*
|
||||
* @param context [IN] user-specified context variable passed to callback
|
||||
* @param callback [IN] function to call for each subkey enumerated
|
||||
* @see EnumerateKeyCallback, enumerateValues()
|
||||
*/
|
||||
|
||||
void RegistryKey::enumerateSubkeys(void *context, EnumerateKeyCallback callback) const
|
||||
{
|
||||
const size_t MAX_NAME_LENGTH = 256;
|
||||
|
||||
LONG result;
|
||||
FILETIME lastModifiedFileTime;
|
||||
char subkeyName[MAX_NAME_LENGTH];
|
||||
DWORD subkeyNameLength;
|
||||
DWORD index;
|
||||
|
||||
DEBUG_FATAL(!callback, ("null callback arg\n"));
|
||||
|
||||
for (
|
||||
index = 0, subkeyNameLength = MAX_NAME_LENGTH;
|
||||
ERROR_SUCCESS == (result = RegEnumKeyEx(keyHandle, index, subkeyName, &subkeyNameLength, 0, 0, 0, &lastModifiedFileTime));
|
||||
++index, subkeyNameLength = MAX_NAME_LENGTH
|
||||
)
|
||||
{
|
||||
bool continueEnum = callback(context, subkeyName, &lastModifiedFileTime);
|
||||
if (!continueEnum) break;
|
||||
}
|
||||
|
||||
// ensure we finished enumeration cleanly
|
||||
FATAL(
|
||||
(result != ERROR_SUCCESS) && (result != ERROR_NO_MORE_ITEMS),
|
||||
("failed to enumerate registry subkeys, error = %ld\n", result));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* open and return a subkey under this RegistryKey instance.
|
||||
*
|
||||
* The function will fail if the specified subkey does not exist.
|
||||
*
|
||||
* @param subkeyName [IN] registry path for subkey to open, relative to this RegistryKey instance
|
||||
* @param accessFlags [IN] flags indicating access granted to the returned RegistryKey
|
||||
* @return This function returns a RegistryKey instance for the specified
|
||||
* subkey.
|
||||
*/
|
||||
|
||||
RegistryKey *RegistryKey::openSubkey(const char *subkeyName, uint32 accessFlags) const
|
||||
{
|
||||
REGSAM samDesired = 0;
|
||||
LONG result;
|
||||
HKEY newKey = 0;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!subkeyName, ("null subkeyName arg"));
|
||||
DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg"));
|
||||
|
||||
// configure security access desired
|
||||
if (accessFlags & AF_READ)
|
||||
samDesired |= KEY_READ;
|
||||
if (accessFlags & AF_WRITE)
|
||||
samDesired |= KEY_WRITE;
|
||||
|
||||
// open the key
|
||||
result = RegOpenKeyEx(keyHandle, subkeyName, 0, samDesired, &newKey);
|
||||
FATAL(result != ERROR_SUCCESS, ("failed to open registry subkey \"%s\", error = %ld\n", subkeyName, result));
|
||||
|
||||
// Create the RegistryKey object. Assume the key must be closed upon
|
||||
// destruction.
|
||||
return new RegistryKey(newKey, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* create and return a subkey under this RegistryKey instance.
|
||||
*
|
||||
* The function will succeed even if the specified subkey
|
||||
* already exists.
|
||||
*
|
||||
* @return This function returns a RegistryKey instance for the specified
|
||||
* subkey.
|
||||
*/
|
||||
|
||||
RegistryKey *RegistryKey::createSubkey(const char *subkeyName, uint32 accessFlags) const
|
||||
{
|
||||
REGSAM samDesired = 0;
|
||||
LONG result;
|
||||
HKEY newKey = 0;
|
||||
DWORD disposition;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!subkeyName, ("null subkeyName arg"));
|
||||
DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg"));
|
||||
|
||||
// configure security access desired
|
||||
if (accessFlags & AF_READ)
|
||||
samDesired |= KEY_READ;
|
||||
if (accessFlags & AF_WRITE)
|
||||
samDesired |= KEY_WRITE;
|
||||
|
||||
// open the key
|
||||
result = RegCreateKeyEx(
|
||||
keyHandle,
|
||||
subkeyName,
|
||||
0, // reserved
|
||||
const_cast<char *>(""), // class
|
||||
REG_OPTION_NON_VOLATILE, // options
|
||||
samDesired,
|
||||
NULL, // security
|
||||
&newKey,
|
||||
&disposition);
|
||||
FATAL(result != ERROR_SUCCESS, ("failed to create registry subkey \"%s\", error = %ld\n", subkeyName, result));
|
||||
|
||||
// Create the RegistryKey object. Assume the key must be closed upon
|
||||
// destruction.
|
||||
return new RegistryKey(newKey, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* delete a subkey relative to this RegistryKey instance.
|
||||
*
|
||||
* Under Windows NT, deleting a key that has subkeys is considered an
|
||||
* error. Therefore, the client should ensure the target key for
|
||||
* deletion does not have any subkeys. (Under Windows 9X, deletion of
|
||||
* the target registry key will automatically delete all subkeys
|
||||
* underneath the target key.)
|
||||
*/
|
||||
|
||||
void RegistryKey::deleteSubkey(const char *subkeyName)
|
||||
{
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!subkeyName, ("null subkeyName arg"));
|
||||
DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg"));
|
||||
|
||||
IGNORE_RETURN(RegDeleteKey(keyHandle, subkeyName));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* test for the existence of a subkey under this RegistryKey instance.
|
||||
*
|
||||
* @param subkeyName [IN] registry path for subkey to open, relative to this RegistryKey instance
|
||||
*/
|
||||
|
||||
bool RegistryKey::subKeyExists(const char *subkeyName)
|
||||
{
|
||||
REGSAM samDesired = KEY_READ;
|
||||
LONG result;
|
||||
HKEY newKey = 0;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!subkeyName, ("null subkeyName arg"));
|
||||
DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg"));
|
||||
|
||||
// open the key
|
||||
result = RegOpenKeyEx(keyHandle, subkeyName, 0, samDesired, &newKey);
|
||||
return (result == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* enumerate all values under the current key.
|
||||
*
|
||||
* @param context [IN] user-specified context variable passed to callback
|
||||
* @param callback [IN] function to call for each value enumerated
|
||||
* @see EnumerateValueCallback, enumerateSubkeys()
|
||||
*/
|
||||
|
||||
void RegistryKey::enumerateValues(void *context, EnumerateValueCallback callback) const
|
||||
{
|
||||
const size_t MAX_NAME_LENGTH = 256;
|
||||
|
||||
LONG result;
|
||||
char valueName[MAX_NAME_LENGTH];
|
||||
DWORD valueNameLength;
|
||||
DWORD index;
|
||||
DWORD dataSize;
|
||||
DWORD valueType;
|
||||
|
||||
DEBUG_FATAL(!callback, ("null callback arg\n"));
|
||||
|
||||
for (
|
||||
index = 0, valueNameLength = MAX_NAME_LENGTH, dataSize = 0;
|
||||
ERROR_SUCCESS == (result = RegEnumValue(keyHandle, index, valueName, &valueNameLength, 0, &valueType, 0, &dataSize));
|
||||
++index, valueNameLength = MAX_NAME_LENGTH, dataSize = 0
|
||||
)
|
||||
{
|
||||
bool continueEnum = callback(context, valueName, static_cast<uint32>(dataSize), valueType);
|
||||
if (!continueEnum) break;
|
||||
}
|
||||
|
||||
// ensure we finished enumeration cleanly
|
||||
FATAL(
|
||||
(result != ERROR_SUCCESS) && (result != ERROR_NO_MORE_ITEMS),
|
||||
("failed to enumerate registry values, error = %ld\n", result));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* query if a value exists and how many bytes that value occupies.
|
||||
*
|
||||
* The client does can pass null for the valueSize and/or valueType
|
||||
* parameter if that information is not desired. The value returned
|
||||
* within the valueSize and valueType parameter is only valid
|
||||
* if the doesExist parameter is set to true upon function return.
|
||||
* The value of the valueType parameter is one of the Windows-defined
|
||||
* REG_* constants provided for use with the Win32 Reg* registry
|
||||
* API. Common values are REG_BINARY (binary data), REG_DWORD
|
||||
* (unsigned integral type data) and REG_SZ (C-style zero-terminated
|
||||
* strings). Consult the Win32 documentation for RegGetValueEx()
|
||||
* for a description of all the type constants.
|
||||
*
|
||||
* @param valueName [IN] name of the value to query
|
||||
* @param doesExist [OUT] true if value exists under this key, false otherwise
|
||||
* @param valueSize [OUT] number of bytes occupied by value's data
|
||||
* @param valueType [OUT] type flag for registry value (see REG_* in RegSetValueEx())
|
||||
*/
|
||||
|
||||
void RegistryKey::getValueInfo(const char *valueName, bool *doesExist, uint32 *valueSize, DWORD *valueType) const
|
||||
{
|
||||
LONG result;
|
||||
DWORD dwSize = 0;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!valueName, ("null valueName arg"));
|
||||
DEBUG_FATAL(!doesExist, ("null doesExist arg"));
|
||||
DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg"));
|
||||
|
||||
// get information on the value
|
||||
result = RegQueryValueEx(keyHandle, valueName, 0, valueType, 0, &dwSize);
|
||||
|
||||
// assume a query failure indicates the value was not found
|
||||
*doesExist = (result == ERROR_SUCCESS);
|
||||
if (valueSize)
|
||||
*valueSize = static_cast<uint32>(dwSize);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* set the data for this key's value.
|
||||
*
|
||||
* The value of the valueType parameter is one of the Windows-defined
|
||||
* REG_* constants provided for use with the Win32 Reg* registry
|
||||
* API. Common values are REG_BINARY (binary data), REG_DWORD
|
||||
* (unsigned integral type data) and REG_SZ (C-style zero-terminated
|
||||
* strings). Consult the Win32 documentation for RegGetValueEx()
|
||||
* for a description of all the type constants.
|
||||
*
|
||||
* @param valueName [IN] name of value under which data will be stored
|
||||
* @param dataPtr [IN] pointer to buffer containing value's data
|
||||
* @param dataSize [IN] # bytes to store
|
||||
* @param valueType [IN] type field for value (indicates nature of data stored with value)
|
||||
*/
|
||||
|
||||
void RegistryKey::setValue(const char *valueName, const void *dataPtr, uint32 dataSize, DWORD valueType)
|
||||
{
|
||||
LONG result;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!valueName, ("null valueName arg"));
|
||||
DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg"));
|
||||
DEBUG_FATAL(!dataPtr, ("null dataPtr arg"));
|
||||
|
||||
// get information on the value
|
||||
result = RegSetValueEx(keyHandle, valueName, 0, valueType, static_cast<CONST BYTE*>(dataPtr), static_cast<DWORD>(dataSize));
|
||||
FATAL(result != ERROR_SUCCESS, ("failed to set registry value \"%s\", error = %ld\n", valueName, result));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve the data for the this key's value.
|
||||
*
|
||||
* The valueType and/or the valueDataSize parameter may be set
|
||||
* to null if the client doesn't need this information.
|
||||
* The value of the valueType parameter is one of the Windows-defined
|
||||
* REG_* constants provided for use with the Win32 Reg* registry
|
||||
* API. Common values are REG_BINARY (binary data), REG_DWORD
|
||||
* (unsigned integral type data) and REG_SZ (C-style zero-terminated
|
||||
* strings). Consult the Win32 documentation for RegGetValueEx()
|
||||
* for a description of all the type constants.
|
||||
*
|
||||
* @param valueName [IN] the name of the value to retrieve
|
||||
* @param dataPtr [OUT] the buffer where the value's data will be stored
|
||||
* @param maxDataSize [IN] size of the data buffer in bytes
|
||||
* @param valueDataSize [OUT] number of bytes retrieved from the named value
|
||||
* @param valueType [OUT] type field for value's data (see REG_* codes in RegSetValueEx)
|
||||
*/
|
||||
|
||||
void RegistryKey::getValue(const char *valueName, void *dataPtr, uint32 maxDataSize, uint32 *valueDataSize, DWORD *valueType) const
|
||||
{
|
||||
LONG result;
|
||||
DWORD dwSize = maxDataSize;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!valueName, ("null valueName arg"));
|
||||
DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg"));
|
||||
|
||||
// get information on the value
|
||||
result = RegQueryValueEx(keyHandle, valueName, 0, valueType, static_cast<LPBYTE>(dataPtr), &dwSize);
|
||||
FATAL(result != ERROR_SUCCESS, ("failed to read registry value \"%s\", error = %ld\n", valueName, result));
|
||||
|
||||
// assume a query failure indicates the value was not found
|
||||
if (valueDataSize)
|
||||
*valueDataSize = static_cast<uint32>(dwSize);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a string from of this key's values, returning a default string
|
||||
* if the value doesn't exist.
|
||||
*
|
||||
* The defaultValue arg is required, must be non-null.
|
||||
*
|
||||
* If the specified value exists but is not of type REG_SZ, the default
|
||||
* string will be returned.
|
||||
*
|
||||
* This routine will DEBUG_FATAL on null args, even if optional is set.
|
||||
* Optional only controls whether a FATAL occurs if there is an issue
|
||||
* retrieving the value.
|
||||
*
|
||||
* @param valueName [IN] name of the string value to retrieve
|
||||
* @param defaultValue [IN] string to return if registry key does not contain thev value
|
||||
* @param dest [OUT] buffer for returned string
|
||||
* @param destSize [IN] max number of bytes (including terminating null) that can be placed in dest
|
||||
* @param optional [IN] if set, the function will return false if there is a problem retrieving the value. otherwise, a DEBUG_FATAL will occur
|
||||
*/
|
||||
|
||||
bool RegistryKey::getStringValue(const char *valueName, const char *defaultValue, char *dest, DWORD destSize, bool optional)
|
||||
{
|
||||
DEBUG_FATAL(!defaultValue, ("null defaultValue arg"));
|
||||
DEBUG_FATAL(!dest, ("null dest arg"));
|
||||
|
||||
bool doesExist;
|
||||
DWORD valueType;
|
||||
DWORD valueSize;
|
||||
|
||||
// clear out string
|
||||
memset(dest, 0, static_cast<size_t>(destSize));
|
||||
|
||||
// get info on the value
|
||||
getValueInfo (valueName, &doesExist, &valueSize, &valueType);
|
||||
if (!doesExist || (valueType != REG_SZ))
|
||||
strncpy(dest, defaultValue, destSize-1);
|
||||
else
|
||||
{
|
||||
// value exists and is a string, retrieve it
|
||||
getValue (valueName, dest, destSize, &valueSize);
|
||||
if (!valueSize)
|
||||
{
|
||||
FATAL(!optional, ("failed to get registry data for key %s\n", valueName));
|
||||
return false;
|
||||
}
|
||||
|
||||
// terminate the string
|
||||
dest [valueSize] = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* delete a value from this registry key.
|
||||
*/
|
||||
|
||||
void RegistryKey::deleteValue(const char *valueName)
|
||||
{
|
||||
LONG result;
|
||||
|
||||
DEBUG_FATAL(!keyHandle, ("null keyHandle"));
|
||||
DEBUG_FATAL(!valueName, ("null valueName arg"));
|
||||
DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg"));
|
||||
|
||||
result = RegDeleteValue(keyHandle, valueName);
|
||||
FATAL(result != ERROR_SUCCESS, ("failed to delete registry value \"%s\", error = %ld\n", valueName, result));
|
||||
}
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* updates beginning-of-execution statistics using the values under a
|
||||
* given key.
|
||||
*
|
||||
* Call this function at the beginning of execution of the code
|
||||
* for which statistics are desired. At the end of execution,
|
||||
* call updateShutdownKey() to finish generating statistics.
|
||||
* This function should only be called once per execution,
|
||||
* and should be followed by a call to updateShutdownKey().
|
||||
* If the latter is not called, the next call to updateStartupKey()
|
||||
* will assume the application terminated abnormally before
|
||||
* proper shutdown could occur.
|
||||
*/
|
||||
|
||||
void RegistryKey::updateStartupKey(RegistryKey *key)
|
||||
{
|
||||
bool valueExist;
|
||||
uint32 valueSize;
|
||||
DWORD valueType;
|
||||
DWORD execStartedCount = 0;
|
||||
clock_t startTime = clock();
|
||||
|
||||
DEBUG_FATAL(!key, ("null key arg\n"));
|
||||
|
||||
// handle improper shutdown of last run
|
||||
key->getValueInfo(STAT_TIME_START_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
// appears the product did not run to completion on last run.
|
||||
// increment the incomplete run counts
|
||||
|
||||
DWORD execIncompleteCount = 0;
|
||||
|
||||
key->getValueInfo(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
key->getValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &execIncompleteCount, sizeof(DWORD), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s key not DWORD type as expected\n", STAT_EXEC_INCOMPLETE_COUNT_VALUENAME));
|
||||
}
|
||||
++execIncompleteCount;
|
||||
key->setValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &execIncompleteCount, sizeof(DWORD), REG_DWORD);
|
||||
}
|
||||
|
||||
// get the start count
|
||||
key->getValueInfo(STAT_EXEC_STARTED_COUNT_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
key->getValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &execStartedCount, sizeof(DWORD), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s key not DWORD type as expected\n", STAT_EXEC_STARTED_COUNT_VALUENAME));
|
||||
}
|
||||
++execStartedCount;
|
||||
|
||||
// save the data
|
||||
key->setValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &execStartedCount, sizeof(DWORD), REG_DWORD);
|
||||
key->setValue(STAT_TIME_START_VALUENAME, &startTime, sizeof(clock_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* updates end-of-execution statistics using the values under a given key.
|
||||
*
|
||||
* This function should only be called after updateStartupKey()
|
||||
* has been called on the same key. After this call returns,
|
||||
* this function should not be called again until another
|
||||
* call to updateStartupKey() is made.
|
||||
*/
|
||||
|
||||
void RegistryKey::updateShutdownKey(RegistryKey *key)
|
||||
{
|
||||
bool valueExist;
|
||||
uint32 valueSize;
|
||||
DWORD valueType;
|
||||
clock_t minTime;
|
||||
clock_t maxTime;
|
||||
clock_t averageTime = 0;
|
||||
clock_t startTime;
|
||||
clock_t stopTime = clock();
|
||||
clock_t runTime;
|
||||
DWORD startExecCount;
|
||||
DWORD incompleteExecCount = 0;
|
||||
DWORD completeExecCount;
|
||||
real averageFraction;
|
||||
|
||||
DEBUG_FATAL(!key, ("null key arg\n"));
|
||||
|
||||
// find the number of complete execution runs of the product
|
||||
key->getValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &startExecCount, sizeof(DWORD), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueSize != sizeof(DWORD)) || (valueType != REG_DWORD), ("invalid start count statistic registry value\n"));
|
||||
|
||||
key->getValueInfo(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
key->getValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &incompleteExecCount, sizeof(DWORD), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s expected to be DWORD type, was %lu instead\n", STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, valueType));
|
||||
}
|
||||
completeExecCount = startExecCount - incompleteExecCount;
|
||||
|
||||
// retrieve the start time
|
||||
key->getValue(STAT_TIME_START_VALUENAME, &startTime, sizeof(clock_t), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid start time statistic registry value\n"));
|
||||
|
||||
// -qq- we don't handle clock wraparound
|
||||
runTime = stopTime - startTime;
|
||||
minTime = runTime;
|
||||
maxTime = runTime;
|
||||
|
||||
// calculate average time
|
||||
key->getValueInfo(STAT_TIME_AVERAGE_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
key->getValue(STAT_TIME_AVERAGE_VALUENAME, &averageTime, sizeof(clock_t), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid average exec time statistic registry value\n"));
|
||||
}
|
||||
averageFraction = CONST_REAL(1.0 / completeExecCount);
|
||||
averageTime = static_cast<clock_t>(( CONST_REAL(averageTime) * (completeExecCount-1) + runTime) * averageFraction);
|
||||
if (averageTime < 1)
|
||||
averageTime = 1;
|
||||
|
||||
// check min exec time
|
||||
key->getValueInfo(STAT_TIME_MIN_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
clock_t testValue;
|
||||
key->getValue(STAT_TIME_MIN_VALUENAME, &testValue, sizeof(clock_t), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid min exec time statistic registry value\n"));
|
||||
if (testValue < minTime)
|
||||
minTime = testValue;
|
||||
}
|
||||
|
||||
// check for max exec time
|
||||
key->getValueInfo(STAT_TIME_MAX_VALUENAME, &valueExist);
|
||||
if (valueExist)
|
||||
{
|
||||
clock_t testValue;
|
||||
key->getValue(STAT_TIME_MAX_VALUENAME, &testValue, sizeof(clock_t), &valueSize, &valueType);
|
||||
DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid max exec time statistic registry value\n"));
|
||||
if (testValue > maxTime)
|
||||
maxTime = testValue;
|
||||
}
|
||||
|
||||
// save the data
|
||||
key->setValue(STAT_TIME_AVERAGE_VALUENAME, &averageTime, sizeof(clock_t));
|
||||
key->setValue(STAT_TIME_MIN_VALUENAME, &minTime, sizeof(clock_t));
|
||||
key->setValue(STAT_TIME_MAX_VALUENAME, &maxTime, sizeof(clock_t));
|
||||
|
||||
// delete the start time value
|
||||
key->deleteValue(STAT_TIME_START_VALUENAME);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* An EnumValueCallback that prints each value name, type and size
|
||||
*
|
||||
* @param valueName name of value
|
||||
* @param valueSize size of value in bytes
|
||||
* @param valueTye type of value
|
||||
*/
|
||||
|
||||
bool RegistryKey::enumValueInfoPrint(
|
||||
void*, // unused user context
|
||||
const char *valueName,
|
||||
uint32 valueSize,
|
||||
DWORD valueType
|
||||
)
|
||||
{
|
||||
char *valueTypeStr;
|
||||
char buffer[64];
|
||||
|
||||
switch (valueType)
|
||||
{
|
||||
case REG_BINARY:
|
||||
valueTypeStr = "REG_BINARY";
|
||||
break;
|
||||
case REG_DWORD:
|
||||
valueTypeStr = "REG_DWORD [little endian]";
|
||||
break;
|
||||
case REG_DWORD_BIG_ENDIAN:
|
||||
valueTypeStr = "REG_DWORD_BIG_ENDIAN";
|
||||
break;
|
||||
case REG_EXPAND_SZ:
|
||||
valueTypeStr = "REG_EXPAND_SZ";
|
||||
break;
|
||||
case REG_NONE:
|
||||
valueTypeStr = "REG_NONE";
|
||||
break;
|
||||
case REG_SZ:
|
||||
valueTypeStr = "REG_SZ";
|
||||
break;
|
||||
default:
|
||||
valueTypeStr = buffer;
|
||||
sprintf(buffer, "<TYPE %lu>", valueType);
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_PRINT_LOG(true, (" Key: \"%s\", %s, %u bytes\n", valueName, valueTypeStr, valueSize));
|
||||
|
||||
// continue enumerating
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Update per-startup registry values.
|
||||
*
|
||||
* This routine is used primarily to test registry read/write
|
||||
* functionality; however, it does provide statistics related
|
||||
* to game usage. These include the following statistics on
|
||||
* a per-game and per-machine basis:
|
||||
* # times product was executed
|
||||
* average real-time duration of execution
|
||||
* minimum execution time
|
||||
* maximum execution time
|
||||
* # times product failed to execute to completion
|
||||
* (i.e. updateRegistryShutdown() never executed---hard crash, stop debugging)
|
||||
*/
|
||||
|
||||
void RegistryKey::updateStartupStatistics(void)
|
||||
{
|
||||
DEBUG_FATAL(!productUserKey, ("null productUserKey\n"));
|
||||
DEBUG_FATAL(!productMachineKey, ("null productMachineKey\n"));
|
||||
|
||||
// create required keys
|
||||
RegistryKey *userStatKey = productUserKey->createSubkey(STATISTICS_KEYNAME);
|
||||
RegistryKey *machineStatKey = productMachineKey->createSubkey(STATISTICS_KEYNAME);
|
||||
|
||||
FATAL(!userStatKey, ("failed to create user statistics key"));
|
||||
FATAL(!machineStatKey, ("failed to create machine statistics key"));
|
||||
|
||||
// handle machine stat key
|
||||
|
||||
#if 1
|
||||
// print existing machine stat keys
|
||||
DEBUG_PRINT_LOG(true, ("BEGIN machine stat key enumeration:\n"));
|
||||
machineStatKey->enumerateValues(0, enumValueInfoPrint);
|
||||
DEBUG_PRINT_LOG(true, ("END machine stat key enumeration:\n"));
|
||||
#endif
|
||||
|
||||
updateStartupKey(machineStatKey);
|
||||
|
||||
|
||||
// handle user stat key
|
||||
|
||||
#if 1
|
||||
// print existing user stat keys
|
||||
DEBUG_PRINT_LOG(true, ("BEGIN user stat key enumeration:\n"));
|
||||
userStatKey->enumerateValues(0, enumValueInfoPrint);
|
||||
DEBUG_PRINT_LOG(true, ("END user stat key enumeration:\n"));
|
||||
#endif
|
||||
|
||||
updateStartupKey(userStatKey);
|
||||
|
||||
// cleanup
|
||||
delete machineStatKey;
|
||||
delete userStatKey;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Update per-shutdown registry values.
|
||||
*
|
||||
* @see updateRegistryStartup()
|
||||
*/
|
||||
|
||||
void RegistryKey::updateShutdownStatistics(void)
|
||||
{
|
||||
DEBUG_FATAL(!productUserKey, ("null productUserKey\n"));
|
||||
DEBUG_FATAL(!productMachineKey, ("null productMachineKey\n"));
|
||||
|
||||
// create required keys
|
||||
RegistryKey *userStatKey = productUserKey->createSubkey(STATISTICS_KEYNAME);
|
||||
RegistryKey *machineStatKey = productMachineKey->createSubkey(STATISTICS_KEYNAME);
|
||||
|
||||
FATAL(!userStatKey, ("failed to create user statistics key"));
|
||||
FATAL(!machineStatKey, ("failed to create machine statistics key"));
|
||||
|
||||
// handle machine stat key
|
||||
updateShutdownKey(machineStatKey);
|
||||
|
||||
// handle user stat key
|
||||
updateShutdownKey(userStatKey);
|
||||
|
||||
// cleanup
|
||||
delete machineStatKey;
|
||||
delete userStatKey;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* install the RegistryKey class.
|
||||
*
|
||||
* After installation, the following predefined keys are available:
|
||||
*
|
||||
* usersKey: HKEY_USERS
|
||||
* currentUserKey: HKEY_CURRENT_USER
|
||||
* classRootKey: HKEY_CLASSES_ROOT
|
||||
* localMachineKey: HKEY_LOCAL_MACHINE
|
||||
* productUserKey: HKEY_CURENT_USER\<product relative registry path>
|
||||
* productMachineKey: HKEY_LOCAL_MACHINE\<product relative registry path>
|
||||
*
|
||||
* The client is free to create any other keys required.
|
||||
*
|
||||
* The product relative registry path is determined by the first of the
|
||||
* following methods that succeed:
|
||||
* 1. If the config file key "ProductRegistryPath" is set, that value is
|
||||
* used for the relative path. If the product relative path is set
|
||||
* in this manner, the client's attempt to change the product relative
|
||||
* path via the setProductKey() function will silently fail.
|
||||
* 2. If the productKeyRelativePath parameter is a non-null positive length
|
||||
* string, that value is used as the product keys' relative path.
|
||||
* 3. The default value DEFAULT_PRODUCT_REGISTRY_PATH ("Software\\Bootprint\\Default")
|
||||
* is used.
|
||||
*
|
||||
* RegistryKey::remove() is added to the exit chain.
|
||||
*
|
||||
* Do not delete any of the predefined registry keys.
|
||||
*
|
||||
* @param productKeyRelativePath [IN] relative registry path for the product keys
|
||||
* @see setProductKeyPath()
|
||||
*/
|
||||
|
||||
void RegistryKey::install(const char *productKeyRelativePath)
|
||||
{
|
||||
UNREF(productKeyRelativePath);
|
||||
char *useRegistryPath = 0;
|
||||
|
||||
DEBUG_FATAL(installed, ("attempted to install RegistryKey when already installed\n"));
|
||||
installed = true;
|
||||
|
||||
// add to exit chain
|
||||
ExitChain::add(remove, "RegistryKey::remove", 0, true);
|
||||
|
||||
// if no passed in value, use the default
|
||||
setProductKeyPathFromConfig = false;
|
||||
useRegistryPath = DuplicateString(DEFAULT_PRODUCT_REGISTRY_PATH);
|
||||
|
||||
// create the Windows-defined RegistryKeys (these keys don't get closed at object destruction time)
|
||||
usersKey = new RegistryKey(HKEY_USERS, false); //lint !e1924 // Note -- C-style cast
|
||||
currentUserKey = new RegistryKey(HKEY_CURRENT_USER, false); //lint !e1924 // Note -- C-style cast
|
||||
classRootKey = new RegistryKey(HKEY_CLASSES_ROOT, false); //lint !e1924 // Note -- C-style cast
|
||||
localMachineKey = new RegistryKey(HKEY_LOCAL_MACHINE, false); //lint !e1924 // Note -- C-style cast
|
||||
|
||||
// check for errors --- unnecessary if new cannot return NULL
|
||||
FATAL(
|
||||
!usersKey || !currentUserKey || !classRootKey || !localMachineKey,
|
||||
("failed to create standard RegistryKey objects"));
|
||||
|
||||
// create/open the product user key
|
||||
productUserKey = currentUserKey->createSubkey(useRegistryPath, AF_READ | AF_WRITE);
|
||||
|
||||
// create/open the product machine key
|
||||
productMachineKey = localMachineKey->createSubkey(useRegistryPath, AF_READ);
|
||||
|
||||
delete [] useRegistryPath;
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
updateStartupStatistics();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* release all resources and state associated with the RegistryKey system.
|
||||
*
|
||||
* It is invalid to call any RegistryKey functions other than install()
|
||||
* after calling remove().
|
||||
*/
|
||||
|
||||
void RegistryKey::remove(void)
|
||||
{
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
updateShutdownStatistics();
|
||||
#endif
|
||||
|
||||
DEBUG_FATAL(!installed, ("attempted to remove RegistryKey when not installed\n"));
|
||||
installed = false;
|
||||
|
||||
delete productMachineKey;
|
||||
delete productUserKey;
|
||||
delete localMachineKey;
|
||||
delete classRootKey;
|
||||
delete currentUserKey;
|
||||
delete usersKey;
|
||||
|
||||
productMachineKey = 0;
|
||||
productUserKey = 0;
|
||||
localMachineKey = 0;
|
||||
classRootKey = 0;
|
||||
currentUserKey = 0;
|
||||
usersKey = 0;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* reset the path to the product's machine and user keys.
|
||||
*
|
||||
* This routine will redefine the following keys:
|
||||
* productUserKey: HKEY_CURENT_USER\<productKeyRelativePath>
|
||||
* productMachineKey: HKEY_LOCAL_MACHINE\<productKeyRelativePath>
|
||||
*
|
||||
* If the product key relative paths were specified in the config
|
||||
* file, this routine will essentially do nothing --- the client
|
||||
* is not able to ovveride the config file settings.
|
||||
*/
|
||||
|
||||
void RegistryKey::setProductKeyPath(const char *productKeyRelativePath)
|
||||
{
|
||||
DEBUG_FATAL(
|
||||
!productKeyRelativePath || !productKeyRelativePath[0],
|
||||
("invalid productKeyRelativePath arg\n"));
|
||||
|
||||
// don't allow client to overwrite if path set by config file
|
||||
if (setProductKeyPathFromConfig)
|
||||
{
|
||||
DEBUG_REPORT_LOG_PRINT(true, ("attempted to set product registry key path to '%s' but config file setting will override\n", productKeyRelativePath));
|
||||
return;
|
||||
}
|
||||
|
||||
delete productUserKey;
|
||||
delete productMachineKey;
|
||||
|
||||
productUserKey = currentUserKey->createSubkey(productKeyRelativePath, AF_READ | AF_WRITE);
|
||||
productMachineKey = localMachineKey->createSubkey(productKeyRelativePath, AF_READ | AF_WRITE);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,270 @@
|
||||
#ifndef REGISTRY_KEY_H
|
||||
#define REGISTRY_KEY_H
|
||||
|
||||
// ======================================================================
|
||||
//
|
||||
// RegistryKey.h
|
||||
// Todd Fiala
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
// provide read and write access to the Windows Registry
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// Each RegistryKey can create or open a subkey relative to that
|
||||
// key. This process produces another RegistryKey. RegistryKeys
|
||||
// provide a mechanism to enumerate all the child subkeys and values
|
||||
// associated with the key. In addition, clients may query for
|
||||
// the presence, type and size of a specific value, get a specific
|
||||
// value's data, and set a named value's data and type.
|
||||
//
|
||||
// The RegistryKey class provides the client with six RegistryKey
|
||||
// objects as starting points into the registry. See documentation
|
||||
// for install() for more info on these starting points.
|
||||
//
|
||||
// The client must install() the RegistryKey class before using it.
|
||||
|
||||
class RegistryKey
|
||||
{
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// flags used to indicate what type of access (e.g. read, write) should
|
||||
// be granted when creating or opening a key.
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// createSubkey(), openSubkey()
|
||||
|
||||
enum // AccessFlags
|
||||
{
|
||||
AF_READ = BINARY1(0001), // query values, enumerate subkeys
|
||||
AF_WRITE = BINARY1(0010) // set values, create subkeys
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// callback prototype for subkey enumeration
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// A return value of true indicates the enumeration of subkeys should
|
||||
// continue. A return value of false stops further enumeration of
|
||||
// subkeys.
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// The context parameter is specified in the call to
|
||||
// enumerateSubkeys(). One use for this could be to pass a class
|
||||
// instance, with the callack defined as a static member function.
|
||||
// The function can then cast the context to a pointer to class
|
||||
// instance, allowing the static function to access per-instance
|
||||
// data explicitly in place of an assumed this pointer.
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// enumerateSubkeys()
|
||||
|
||||
typedef bool (*EnumerateKeyCallback)(
|
||||
void *context, // [IN] user-specified context variable
|
||||
const char *keyName, // [IN] name of the key being enumerated
|
||||
const FILETIME *lastWriteTime // [IN] last time this key was modified
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// callback prototype for value enumeration
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// A return value of true indicates the enumeration of values should
|
||||
// continue. A return value of false stops further enumeration of
|
||||
// values .
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// The context parameter is specified in the call to
|
||||
// enumerateValues(). One use for this could be to pass a class
|
||||
// instance, with the callack defined as a static member function.
|
||||
// The function can then cast the context to a pointer to class
|
||||
// instance, allowing the static function to access per-instance
|
||||
// data explicitly in place of an assumed this pointer.
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// enumerateValues()
|
||||
|
||||
typedef bool (*EnumerateValueCallback)(
|
||||
void *context, // [IN] user-specified context variable
|
||||
const char *valueName, // [IN] name of the value being enumerated
|
||||
uint32 valueSize, // [IN] number of bytes occupied by this value's data
|
||||
DWORD valueType // [IN] type of value (one of REG_* as in RegSetValueEx documentation)
|
||||
);
|
||||
|
||||
private:
|
||||
static const char * const PRODUCT_REGISTRY_PATH_KEYNAME;
|
||||
static const char * const DEFAULT_PRODUCT_REGISTRY_PATH;
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
static const char * const STATISTICS_KEYNAME;
|
||||
static const char * const STAT_EXEC_STARTED_COUNT_VALUENAME;
|
||||
static const char * const STAT_EXEC_INCOMPLETE_COUNT_VALUENAME;
|
||||
static const char * const STAT_TIME_AVERAGE_VALUENAME;
|
||||
static const char * const STAT_TIME_MIN_VALUENAME;
|
||||
static const char * const STAT_TIME_MAX_VALUENAME;
|
||||
static const char * const STAT_TIME_START_VALUENAME;
|
||||
#endif
|
||||
|
||||
static bool installed;
|
||||
static bool setProductKeyPathFromConfig;
|
||||
|
||||
// private instance member variables
|
||||
HKEY keyHandle;
|
||||
bool closeKeyOnDestroy;
|
||||
|
||||
private:
|
||||
// public member variables
|
||||
static RegistryKey *usersKey;
|
||||
static RegistryKey *currentUserKey;
|
||||
static RegistryKey *classRootKey;
|
||||
static RegistryKey *localMachineKey;
|
||||
static RegistryKey *productUserKey;
|
||||
static RegistryKey *productMachineKey;
|
||||
|
||||
private:
|
||||
// private member functions
|
||||
static void remove(void);
|
||||
RegistryKey(HKEY newKeyHandle, bool newCloseKeyOnDestroy);
|
||||
|
||||
#if USE_REGISTRY_EXECUTION_STATISTICS
|
||||
static void updateStartupKey(RegistryKey *key);
|
||||
static void updateShutdownKey(RegistryKey *key);
|
||||
static bool enumValueInfoPrint(void *context, const char *valueName, uint32 valueSize, DWORD valueType);
|
||||
|
||||
static void updateStartupStatistics(void);
|
||||
static void updateShutdownStatistics(void);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// disable: default constructor, copy constructor, assignment operator
|
||||
// NOTE: last two can be implemented, but must be specially handled
|
||||
RegistryKey(void);
|
||||
RegistryKey(const RegistryKey&);
|
||||
RegistryKey &operator =(const RegistryKey&);
|
||||
|
||||
public:
|
||||
// public member functions
|
||||
|
||||
static void install(const char *productKeyRelativePath = 0);
|
||||
static void setProductKeyPath(const char *productKeyRelativePath);
|
||||
|
||||
// pre-defined RegistryKey retrieval
|
||||
static RegistryKey *getUsersKey(void);
|
||||
static RegistryKey *getCurrentUserKey(void);
|
||||
static RegistryKey *getClassRootKey(void);
|
||||
static RegistryKey *getLocalMachineKey(void);
|
||||
static RegistryKey *getProductUserKey(void);
|
||||
static RegistryKey *getProductMachineKey(void);
|
||||
|
||||
~RegistryKey(void);
|
||||
|
||||
// subkey interface
|
||||
void enumerateSubkeys(void *context, EnumerateKeyCallback callback) const;
|
||||
RegistryKey *openSubkey(const char *subkeyName, uint32 accessFlags = AF_READ) const;
|
||||
RegistryKey *createSubkey(const char *subkeyName, uint32 accessFlags = AF_READ | AF_WRITE) const;
|
||||
void deleteSubkey(const char *subkeyName);
|
||||
bool subKeyExists(const char *subkeyName);
|
||||
|
||||
// value interface
|
||||
void enumerateValues(void *context, EnumerateValueCallback callback) const;
|
||||
void setValue(const char *valueName, const void *dataPtr, uint32 dataSize, DWORD valueType = REG_BINARY);
|
||||
void deleteValue(const char *valueName);
|
||||
|
||||
void getValueInfo(const char *valueName, bool *doesExist, uint32 *valueSize = 0, DWORD *valueType = 0) const;
|
||||
void getValue(const char *valueName, void *dataPtr, uint32 maxDataSize, uint32 *valueDataSize, DWORD *valueType = 0) const;
|
||||
bool getStringValue(const char *valueName, const char *defaultValue, char *dest, DWORD destSize, bool optional = false);
|
||||
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// retrieve a key to the HKEY_USERS registry key with read access
|
||||
|
||||
inline RegistryKey *RegistryKey::getUsersKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return usersKey;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a key to the HKEY_CURRENT_USER registry key with read/write
|
||||
* access.
|
||||
*/
|
||||
|
||||
inline RegistryKey *RegistryKey::getCurrentUserKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return currentUserKey;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a key to the HKEY_CLASSES_ROOT registry key with read/write
|
||||
* access.
|
||||
*/
|
||||
|
||||
inline RegistryKey *RegistryKey::getClassRootKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return classRootKey;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a key to the HKEY_LOCAL_MACHINE registry key with read/write
|
||||
* access.
|
||||
*/
|
||||
|
||||
inline RegistryKey *RegistryKey::getLocalMachineKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return localMachineKey;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a key to the product's user key with read/write access.
|
||||
*
|
||||
* The product user key is the root key for storing user-specific
|
||||
* product-related information. install() describes where this
|
||||
* information exists in the registry.
|
||||
*
|
||||
* @see install(), getProductMachineKey()
|
||||
*/
|
||||
|
||||
inline RegistryKey *RegistryKey::getProductUserKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return productUserKey;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* retrieve a key to the product's machine key with read/write access.
|
||||
*
|
||||
* The product machine key is the root key for storing machine-specific
|
||||
* product-related information. install() describes where this
|
||||
* information exists in the registry.
|
||||
*
|
||||
* @see install(), getProductUserKey()
|
||||
*/
|
||||
|
||||
inline RegistryKey *RegistryKey::getProductMachineKey(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n"));
|
||||
return productMachineKey;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedFoundation.cpp
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/SetupSharedFoundation.h"
|
||||
|
||||
#include "sharedDebug/DebugMonitor.h"
|
||||
#include "sharedDebug/InstallTimer.h"
|
||||
#include "sharedDebug/Profiler.h"
|
||||
|
||||
#include "sharedFoundation/ApplicationVersion.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/CommandLine.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
#include "sharedFoundation/CrashReportInformation.h"
|
||||
#include "sharedFoundation/CrcLowerString.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedFoundation/Production.h"
|
||||
#include "sharedFoundation/RegistryKey.h"
|
||||
#include "sharedFoundation/StaticCallbackEntry.h"
|
||||
#include "sharedFoundation/MemoryBlockManager.h"
|
||||
#include "sharedFoundation/Watcher.h"
|
||||
#include "sharedLog/TailFileLogObserver.h"
|
||||
|
||||
#include <eh.h>
|
||||
#include <cstdio>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace FatalNamespace
|
||||
{
|
||||
extern char ms_buffer[32 * 1024];
|
||||
}
|
||||
|
||||
namespace SetupSharedFoundationNamespace
|
||||
{
|
||||
LONG __stdcall MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS exceptionPointers);
|
||||
|
||||
bool ms_writeMiniDumps;
|
||||
}
|
||||
|
||||
using namespace SetupSharedFoundationNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
LONG __stdcall SetupSharedFoundationNamespace::MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS exceptionPointers)
|
||||
{
|
||||
// make the routine somewhat safe from re-entrance
|
||||
static bool entered = false;
|
||||
if (entered)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
entered = true;
|
||||
|
||||
// log some important information
|
||||
static char buffer[128];
|
||||
sprintf(buffer, "Exception %08x(%d)=code %08x=addr\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress);
|
||||
OutputDebugString(buffer);
|
||||
|
||||
// write the minidump if we're in here for the first time
|
||||
static bool ms_alreadyWroteMiniDump = false;
|
||||
if (ms_writeMiniDumps && !ms_alreadyWroteMiniDump)
|
||||
{
|
||||
ms_alreadyWroteMiniDump = true;
|
||||
|
||||
uint64 timestamp;
|
||||
time_t now;
|
||||
tm t;
|
||||
|
||||
IGNORE_RETURN(time(&now));
|
||||
IGNORE_RETURN(gmtime_r(&now, &t));
|
||||
timestamp = t.tm_year+1900; //lint !e732 !e737 !e776
|
||||
timestamp *= 100;
|
||||
timestamp += t.tm_mon+1; //lint !e737 !e776
|
||||
timestamp *= 100;
|
||||
timestamp += static_cast<unsigned int>(t.tm_mday);
|
||||
timestamp *= 100;
|
||||
timestamp += static_cast<unsigned int>(t.tm_hour);
|
||||
timestamp *= 100;
|
||||
timestamp += static_cast<unsigned int>(t.tm_min);
|
||||
timestamp *= 100;
|
||||
timestamp += static_cast<unsigned int>(t.tm_sec);
|
||||
|
||||
static char fileName[512];
|
||||
|
||||
sprintf(fileName, "%s-%s-%I64d.txt", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp);
|
||||
HANDLE const file = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char text1[] = "automated crash dump from ";
|
||||
DWORD bytesWritten;
|
||||
WriteFile(file, text1, strlen(text1), &bytesWritten, NULL);
|
||||
|
||||
char const * text2 = Os::getShortProgramName();
|
||||
WriteFile(file, text2, strlen(text2), &bytesWritten, NULL);
|
||||
|
||||
char text3[] = " ";
|
||||
WriteFile(file, text3, strlen(text3), &bytesWritten, NULL);
|
||||
|
||||
char const * text4 = ApplicationVersion::getInternalVersion();
|
||||
WriteFile(file, text4, strlen(text4), &bytesWritten, NULL);
|
||||
|
||||
char text5[] = "\n\n\n";
|
||||
WriteFile(file, text5, strlen(text5), &bytesWritten, NULL);
|
||||
|
||||
if (exceptionPointers->ExceptionRecord->ExceptionCode == 0x80000003)
|
||||
{
|
||||
// write out the fatal buffer
|
||||
char const * text6 = FatalNamespace::ms_buffer;
|
||||
WriteFile(file, text6, strlen(text6), &bytesWritten, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
char const * text6 = buffer;
|
||||
WriteFile(file, text6, strlen(text6), &bytesWritten, NULL);
|
||||
}
|
||||
|
||||
char text7[] = "\n\n";
|
||||
WriteFile(file, text7, strlen(text7), &bytesWritten, NULL);
|
||||
|
||||
char const * text8 = "";
|
||||
for (int i = 0; text8; ++i)
|
||||
{
|
||||
text8 = CrashReportInformation::getEntry(i);
|
||||
if (text8)
|
||||
{
|
||||
int const text8Length = strlen(text8);
|
||||
if (text8Length)
|
||||
WriteFile(file, text8, text8Length, &bytesWritten, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
}
|
||||
|
||||
sprintf(fileName, "%s-%s-%I64d.mdmp", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp);
|
||||
OutputDebugString("Generating minidump ");
|
||||
OutputDebugString(fileName);
|
||||
OutputDebugString("\n");
|
||||
DebugHelp::writeMiniDump(fileName, exceptionPointers);
|
||||
|
||||
sprintf(fileName, "%s-%s-%I64d.log", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp);
|
||||
TailFileLogObserver::flushAllTailFileLogObservers(fileName);
|
||||
}
|
||||
|
||||
// tell the Os not to abort so we can rethrow the exception
|
||||
Os::returnFromAbort();
|
||||
|
||||
// Let the ExitChain do its job
|
||||
Fatal("ExceptionHandler invoked");
|
||||
|
||||
// rethrow the exception so that the debugger can catch it
|
||||
entered = false;
|
||||
return EXCEPTION_CONTINUE_SEARCH; //lint !e527 // Unreachable
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void setFatalVersionString()
|
||||
{
|
||||
char buffer[256];
|
||||
sprintf(buffer, "%s: %s\n", Os::getShortProgramName(), ApplicationVersion::getInternalVersion());
|
||||
FatalSetVersionString(buffer);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Install the engine
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// The settings in the Data structure will determine which subsystems
|
||||
// get initialized.
|
||||
|
||||
void SetupSharedFoundation::install(const Data &data)
|
||||
{
|
||||
InstallTimer const installTimer("SetupSharedFoundation::install");
|
||||
|
||||
DEBUG_REPORT_LOG(true, ("SetupSharedFoundation::install: version %s\n", ApplicationVersion::getInternalVersion()));
|
||||
|
||||
ms_writeMiniDumps = data.writeMiniDumps;
|
||||
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
|
||||
|
||||
// and get the command line stuff in quick so we can make decisions based on the command line settings
|
||||
CommandLine::install();
|
||||
|
||||
// feed CommandLine with appropriate strings
|
||||
if (data.commandLine)
|
||||
CommandLine::absorbString(data.commandLine);
|
||||
if (data.argc)
|
||||
CommandLine::absorbStrings(const_cast<const char**>(data.argv+1), data.argc-1);
|
||||
|
||||
// load the config file
|
||||
ConfigFile::install();
|
||||
if (data.configFile)
|
||||
IGNORE_RETURN(ConfigFile::loadFile(data.configFile));
|
||||
|
||||
// get the post command-line text for the ConfigFile (key-value pairs)
|
||||
const char *configString = CommandLine::getPostCommandLineString();
|
||||
if (configString)
|
||||
{
|
||||
IGNORE_RETURN(ConfigFile::loadFromCommandLine(configString));
|
||||
}
|
||||
|
||||
// @todo codereorg should this be here?
|
||||
MemoryManager::registerDebugFlags();
|
||||
#if PRODUCTION == 0
|
||||
Profiler::registerDebugFlags();
|
||||
#endif
|
||||
FatalInstall();
|
||||
|
||||
// @todo move these, it's part of sharedDebug. However, sharedDebug is installed before sharedFoundation, but these need the ConfigFile. ugh.
|
||||
#if PRODUCTION == 0
|
||||
DebugMonitor::install();
|
||||
#endif
|
||||
SetWarningStrictFatal(ConfigFile::getKeyBool("SharedDebug", "strict", false));
|
||||
|
||||
{
|
||||
ConfigSharedFoundation::Defaults defaults;
|
||||
defaults.frameRateLimit = data.frameRateLimit;
|
||||
defaults.demoMode = data.demoMode;
|
||||
defaults.verboseWarnings = data.verboseWarnings;
|
||||
ConfigSharedFoundation::install(defaults);
|
||||
|
||||
if (ConfigSharedFoundation::getCauseAccessViolation())
|
||||
static_cast<int*>(0)[0] = 0;
|
||||
}
|
||||
|
||||
// @todo codereorg should this be here?
|
||||
#ifdef _DEBUG
|
||||
MemoryManager::setReportAllocations (ConfigSharedFoundation::getMemoryManagerReportAllocations ());
|
||||
#endif
|
||||
|
||||
MemoryBlockManager::install (ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove ());
|
||||
|
||||
ExitChain::install();
|
||||
Report::install();
|
||||
Clock::install(data.clockUsesSleep, data.clockUsesRecalibrationThread);
|
||||
CrashReportInformation::install();
|
||||
RegistryKey::install(data.productRegistryKey);
|
||||
|
||||
PersistentCrcString::install();
|
||||
CrcLowerString::install();
|
||||
|
||||
WatchedByList::install();
|
||||
|
||||
if (data.createWindow)
|
||||
{
|
||||
DEBUG_FATAL(data.useWindowHandle, ("exactly one of createWindow and useWindowHandle must be true"));
|
||||
Os::install(data.hInstance, data.windowName, data.windowNormalIcon, data.windowSmallIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.useWindowHandle)
|
||||
Os::install(data.windowHandle, data.processMessagePump);
|
||||
else
|
||||
Os::install();
|
||||
}
|
||||
|
||||
StaticCallbackEntry::install();
|
||||
|
||||
setFatalVersionString();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Call a function with appropriate exception handling
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// If exception handling has been disabled in the config file, this routine
|
||||
// will call the callback without exception handling.
|
||||
|
||||
void SetupSharedFoundation::callbackWithExceptionHandling(
|
||||
void (*callback)(void) // Routine to call with exception handling
|
||||
)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Uninstall the engine
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine will properly uninstall the engine componenets that were
|
||||
// installed by SetupSharedFoundation::install().
|
||||
|
||||
void SetupSharedFoundation::remove(void)
|
||||
{
|
||||
ExitChain::quit();
|
||||
|
||||
if (!ConfigSharedFoundation::getDemoMode() && GetNumberOfWarnings())
|
||||
REPORT(true, Report::RF_print | Report::RF_log | Report::RF_dialog, ("%d warnings logged", GetNumberOfWarnings()));
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
SetupSharedFoundation::Data::Data(Defaults defaults)
|
||||
{
|
||||
Zero(*this);
|
||||
|
||||
switch (defaults)
|
||||
{
|
||||
case D_console: setupConsoleDefaults(); break;
|
||||
case D_game: setupGameDefaults(); break;
|
||||
case D_mfc: setupMfcDefaults(); break;
|
||||
default: DEBUG_FATAL(true, ("invalid enum value"));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SetupSharedFoundation::Data::setupGameDefaults()
|
||||
{
|
||||
createWindow = true;
|
||||
windowName = NULL;
|
||||
windowNormalIcon = NULL;
|
||||
windowSmallIcon = NULL;
|
||||
hInstance = NULL;
|
||||
useWindowHandle = false;
|
||||
processMessagePump = true;
|
||||
windowHandle = NULL;
|
||||
clockUsesSleep = false;
|
||||
clockUsesRecalibrationThread = true;
|
||||
writeMiniDumps = false;
|
||||
|
||||
commandLine = NULL;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
|
||||
configFile = NULL;
|
||||
|
||||
productRegistryKey = NULL;
|
||||
|
||||
frameRateLimit = CONST_REAL(0);
|
||||
|
||||
lostFocusCallback = NULL;
|
||||
|
||||
demoMode = false;
|
||||
verboseWarnings = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SetupSharedFoundation::Data::setupConsoleDefaults()
|
||||
{
|
||||
createWindow = false;
|
||||
windowName = NULL;
|
||||
windowNormalIcon = NULL;
|
||||
windowSmallIcon = NULL;
|
||||
hInstance = NULL;
|
||||
useWindowHandle = false;
|
||||
processMessagePump = true;
|
||||
windowHandle = NULL;
|
||||
clockUsesSleep = false;
|
||||
clockUsesRecalibrationThread = false;
|
||||
writeMiniDumps = false;
|
||||
|
||||
commandLine = NULL;
|
||||
argc = NULL;
|
||||
argv = NULL;
|
||||
|
||||
configFile = NULL;
|
||||
|
||||
productRegistryKey = NULL;
|
||||
|
||||
frameRateLimit = CONST_REAL(0);
|
||||
|
||||
lostFocusCallback = NULL;
|
||||
|
||||
demoMode = false;
|
||||
verboseWarnings = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SetupSharedFoundation::Data::setupMfcDefaults()
|
||||
{
|
||||
createWindow = false;
|
||||
windowName = NULL;
|
||||
windowNormalIcon = NULL;
|
||||
windowSmallIcon = NULL;
|
||||
hInstance = NULL;
|
||||
useWindowHandle = false;
|
||||
processMessagePump = true;
|
||||
windowHandle = NULL;
|
||||
clockUsesSleep = false;
|
||||
clockUsesRecalibrationThread = false;
|
||||
writeMiniDumps = false;
|
||||
|
||||
commandLine = NULL;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
|
||||
configFile = NULL;
|
||||
|
||||
productRegistryKey = NULL;
|
||||
|
||||
frameRateLimit = CONST_REAL(0);
|
||||
|
||||
demoMode = false;
|
||||
verboseWarnings = false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,99 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedFoundation.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_SetupSharedFoundation_H
|
||||
#define INCLUDED_SetupSharedFoundation_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class SetupSharedFoundation
|
||||
{
|
||||
public:
|
||||
|
||||
struct Data
|
||||
{
|
||||
typedef void (*LostFocusCallbackFuction)();
|
||||
|
||||
// window creation stuff
|
||||
bool createWindow;
|
||||
const char *windowName;
|
||||
HICON windowNormalIcon;
|
||||
HICON windowSmallIcon;
|
||||
HINSTANCE hInstance;
|
||||
|
||||
// window use stuff
|
||||
bool useWindowHandle;
|
||||
bool processMessagePump;
|
||||
HWND windowHandle;
|
||||
|
||||
bool writeMiniDumps;
|
||||
|
||||
bool clockUsesSleep;
|
||||
bool clockUsesRecalibrationThread;
|
||||
|
||||
// pointer to command line
|
||||
const char *commandLine;
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
// name of the config file to lead
|
||||
const char *configFile;
|
||||
|
||||
// registry stuff
|
||||
const char *productRegistryKey;
|
||||
|
||||
real frameRateLimit;
|
||||
|
||||
|
||||
bool demoMode;
|
||||
|
||||
bool verboseWarnings;
|
||||
|
||||
LostFocusCallbackFuction lostFocusCallback;
|
||||
|
||||
public:
|
||||
|
||||
enum Defaults
|
||||
{
|
||||
D_console,
|
||||
D_game,
|
||||
D_mfc
|
||||
};
|
||||
|
||||
Data(Defaults defaults);
|
||||
|
||||
private:
|
||||
|
||||
Data();
|
||||
|
||||
void setupGameDefaults();
|
||||
void setupConsoleDefaults();
|
||||
void setupMfcDefaults();
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
typedef void (*MainFunction)();
|
||||
|
||||
public:
|
||||
|
||||
static void install(const Data &data);
|
||||
static void remove(void);
|
||||
|
||||
static void callbackWithExceptionHandling(MainFunction mainFunction);
|
||||
|
||||
private:
|
||||
|
||||
SetupSharedFoundation();
|
||||
SetupSharedFoundation(const SetupSharedFoundation &);
|
||||
SetupSharedFoundation &operator =(const SetupSharedFoundation &);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// WindowsWrapper.h
|
||||
// copyright (c) 1998 Bootprint Entertainment
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_WindowsWrapper_H
|
||||
#define INCLUDED_WindowsWrapper_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// C4201 nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable: 4201)
|
||||
|
||||
// make windows.h more strict in the types of handles
|
||||
#ifndef STRICT
|
||||
#define STRICT 1
|
||||
#endif
|
||||
|
||||
// trim down the amount of stuff windows.h includes
|
||||
#define NOGDICAPMASKS
|
||||
#define NOVIRTUALKEYCODE
|
||||
#define NOKEYSTATES
|
||||
#define NORASTEROPS
|
||||
#define NOATOM
|
||||
#define NOCOLOR
|
||||
#define NODRAWTEXT
|
||||
#define NOMEMMGR
|
||||
#define NOMETAFILE
|
||||
#define NOMINMAX
|
||||
#define NOOPENFILE
|
||||
#define NOSERVICE
|
||||
#define NOSOUND
|
||||
#define NOCOMM
|
||||
#define NOHELP
|
||||
#define NOPROFILER
|
||||
#define NODEFERWINDOWPOS
|
||||
#define NOMCX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
#include <wtypes.h>
|
||||
|
||||
// reenable warnings disables for windows.h
|
||||
#pragma warning(default: 4201)
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// PRIVATE. Do not export this header file outside the package.
|
||||
|
||||
// ======================================================================
|
||||
//
|
||||
// FoundationTypesWin32.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_FoundationTypesWin32_H
|
||||
#define INCLUDED_FoundationTypesWin32_H
|
||||
|
||||
// ======================================================================
|
||||
// specify what platform we're running on.
|
||||
|
||||
#define PLATFORM_WIN32
|
||||
|
||||
// ======================================================================
|
||||
// basic types that we assume to be around
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed __int64 int64;
|
||||
typedef int FILE_HANDLE;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstFractal.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFractal/FirstSharedFractal.h"
|
||||
@@ -0,0 +1,9 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstSharedGame.cpp
|
||||
// Copyright 2002-2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedGame/FirstSharedGame.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstImage.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedImage/FirstSharedImage.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstIoWin.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedIoWin/FirstSharedIoWin.h"
|
||||
@@ -0,0 +1,35 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// StderrLogger.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedLog/FirstSharedLog.h"
|
||||
#include "sharedLog/StderrLogger.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// Unimplemented for win32
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void StderrLogger::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StderrLogger::remove()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StderrLogger::update()
|
||||
{
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstMath.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMath/FirstSharedMath.h"
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SseMath.cpp
|
||||
// Copyright 2002 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMath/FirstSharedMath.h"
|
||||
#include "sharedMath/SseMath.h"
|
||||
|
||||
#include "sharedMath/Transform.h"
|
||||
#include "sharedMath/Vector.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#define SSE_ALIGN __declspec(align(16))
|
||||
#define SSE_VARIABLE_COUNT 5
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
SSE_ALIGN float sseVariable[SSE_VARIABLE_COUNT][4];
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* Retrieve whether the hardware can do SSE math.
|
||||
*
|
||||
* @return true if SSE math processing is available; false otherwise.
|
||||
*/
|
||||
|
||||
bool SseMath::canDoSseMath()
|
||||
{
|
||||
#if 0
|
||||
return false;
|
||||
#else
|
||||
//-- First check the CPUID instruction. If it raises an exception,
|
||||
// the CPUID instruction doesn't exist and SSE math support is not available.
|
||||
bool cpuHasSse = false;
|
||||
bool cpuHasSaveRestore = false;
|
||||
|
||||
uint32 featureBits;
|
||||
|
||||
#if 0
|
||||
bool osSupportsSaveRestore = false;
|
||||
bool osSimdExceptionSupport = false;
|
||||
bool x87EmulationDisabled = false;
|
||||
|
||||
uint32 controlRegister4;
|
||||
uint32 controlRegister0;
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
__asm {
|
||||
//-- Get features bits.
|
||||
mov eax, 1
|
||||
cpuid
|
||||
|
||||
mov featureBits, edx
|
||||
|
||||
#if 0
|
||||
//-- Get control registers.
|
||||
mov ecx, CR4
|
||||
mov controlRegister4, ecx
|
||||
|
||||
mov ecx, CR0
|
||||
mov controlRegister0, ecx
|
||||
#endif
|
||||
}
|
||||
|
||||
cpuHasSse = ((featureBits & 0x02000000) != 0); //lint !e530 // featureBits not initialized - yes it is, in the asm
|
||||
cpuHasSaveRestore = ((featureBits & 0x01000000) != 0);
|
||||
|
||||
#if 0
|
||||
osSupportsSaveRestore = ((controlRegister4 & 0x00000200) != 0);
|
||||
osSimdExceptionSupport = ((controlRegister4 & 0x00000400) != 0);
|
||||
x87EmulationDisabled = ((controlRegister0 & 0x00000004) == 0);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{ //lint !e1775 // catch block does not catch any declared exceptions
|
||||
}
|
||||
|
||||
#if 1
|
||||
return cpuHasSse && cpuHasSaveRestore;
|
||||
#else
|
||||
return cpuHasSse && cpuHasSaveRestore && osSupportsSaveRestore && osSimdExceptionSupport && x87EmulationDisabled;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Vector SseMath::rotateTranslateScale_l2p(const Transform &transform, const Vector &vector, float scale)
|
||||
{
|
||||
// NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value.
|
||||
|
||||
__asm {
|
||||
//-- Keep track of ebx. Client is crashing if I trash this.
|
||||
push ebx
|
||||
|
||||
//-- Load up matrix.
|
||||
mov ebx, transform
|
||||
|
||||
movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4
|
||||
movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4
|
||||
movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4
|
||||
}
|
||||
|
||||
//-- Prepare source vector.
|
||||
sseVariable[0][0] = vector.x;
|
||||
sseVariable[0][1] = vector.y;
|
||||
sseVariable[0][2] = vector.z;
|
||||
sseVariable[0][3] = 1.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
mov ebx, offset sseVariable
|
||||
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
}
|
||||
|
||||
//-- Prepare the scale vector.
|
||||
__asm {
|
||||
movss xmm6, scale // xmm6 = scale ? ? ?
|
||||
shufps xmm6, xmm6, 0x00 // xmm6 = scale scale
|
||||
movlhps xmm6, xmm6 // xmm6 = scale scale scale scale
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
|
||||
//-- Restore EBX
|
||||
pop ebx
|
||||
}
|
||||
|
||||
// @todo consider twizzling/detwizzling to be able to perform add in sse.
|
||||
return Vector(
|
||||
sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3],
|
||||
sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3],
|
||||
sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3]);
|
||||
} //lint !e715 // scale/transform not referenced - it's in the asm
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Vector SseMath::rotateScale_l2p(const Transform &transform, const Vector &vector, float scale)
|
||||
{
|
||||
#if 0
|
||||
// @todo do the real thing.
|
||||
return transform.rotate_l2p(vector) * scale;
|
||||
#else
|
||||
|
||||
// NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value.
|
||||
|
||||
__asm {
|
||||
//-- Keep track of ebx. Client is crashing if I trash this.
|
||||
push ebx
|
||||
|
||||
//-- Load up matrix.
|
||||
mov ebx, transform
|
||||
|
||||
movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4
|
||||
movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4
|
||||
movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4
|
||||
}
|
||||
|
||||
//-- Prepare source vector.
|
||||
sseVariable[0][0] = vector.x;
|
||||
sseVariable[0][1] = vector.y;
|
||||
sseVariable[0][2] = vector.z;
|
||||
sseVariable[0][3] = 0.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
mov ebx, offset sseVariable
|
||||
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
}
|
||||
|
||||
//-- Prepare the scale vector.
|
||||
__asm {
|
||||
movss xmm6, scale // xmm6 = scale ? ? ?
|
||||
shufps xmm6, xmm6, 0x00 // xmm6 = scale scale
|
||||
movlhps xmm6, xmm6 // xmm6 = scale scale scale scale
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz 0
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz 0
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz 0
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale 0
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale 0
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale 0
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
|
||||
//-- Restore EBX
|
||||
pop ebx
|
||||
}
|
||||
|
||||
// @todo consider twizzling/detwizzling to be able to perform add in sse.
|
||||
return Vector(
|
||||
sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2],
|
||||
sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2],
|
||||
sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2]);
|
||||
|
||||
#endif
|
||||
} //lint !e715 // scale/transform not referenced - it's in the asm
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SseMath::skinPositionNormal_l2p(const Transform &transform, const Vector &sourcePosition, const Vector &sourceNormal, float scale, Vector &destPosition, Vector &destNormal)
|
||||
{
|
||||
// NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value.
|
||||
|
||||
__asm {
|
||||
//-- Keep track of ebx. Client is crashing if I trash this.
|
||||
push ebx
|
||||
|
||||
//-- Load up matrix.
|
||||
mov ebx, transform
|
||||
|
||||
movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4
|
||||
movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4
|
||||
movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4
|
||||
}
|
||||
|
||||
//-- Prepare source position.
|
||||
sseVariable[0][0] = sourcePosition.x;
|
||||
sseVariable[0][1] = sourcePosition.y;
|
||||
sseVariable[0][2] = sourcePosition.z;
|
||||
sseVariable[0][3] = 1.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
mov ebx, offset sseVariable
|
||||
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
|
||||
//-- Prepare the scale vector.
|
||||
movss xmm6, scale // xmm6 = scale ? ? ?
|
||||
shufps xmm6, xmm6, 0x00 // xmm6 = scale scale
|
||||
movlhps xmm6, xmm6 // xmm6 = scale scale scale scale
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
}
|
||||
|
||||
destPosition.x = sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3];
|
||||
destPosition.y = sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3];
|
||||
destPosition.z = sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3];
|
||||
|
||||
//-- Prepare source normal.
|
||||
sseVariable[0][0] = sourceNormal.x;
|
||||
sseVariable[0][1] = sourceNormal.y;
|
||||
sseVariable[0][2] = sourceNormal.z;
|
||||
sseVariable[0][3] = 1.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
|
||||
//-- Restore EBX
|
||||
pop ebx
|
||||
}
|
||||
|
||||
destNormal.x = sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2];
|
||||
destNormal.y = sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2];
|
||||
destNormal.z = sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2];
|
||||
} //lint !e715 // scale/transform not referenced - it's in the asm
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SseMath::skinPositionNormalAdd_l2p(const Transform &transform, const Vector &sourcePosition, const Vector &sourceNormal, float scale, Vector &destPosition, Vector &destNormal)
|
||||
{
|
||||
// NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value.
|
||||
|
||||
__asm {
|
||||
//-- Keep track of ebx. Client is crashing if I trash this.
|
||||
push ebx
|
||||
|
||||
//-- Load up matrix.
|
||||
mov ebx, transform
|
||||
|
||||
movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4
|
||||
movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4
|
||||
movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4
|
||||
}
|
||||
|
||||
//-- Prepare source position.
|
||||
sseVariable[0][0] = sourcePosition.x;
|
||||
sseVariable[0][1] = sourcePosition.y;
|
||||
sseVariable[0][2] = sourcePosition.z;
|
||||
sseVariable[0][3] = 1.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
mov ebx, offset sseVariable
|
||||
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
|
||||
//-- Prepare the scale vector.
|
||||
movss xmm6, scale // xmm6 = scale ? ? ?
|
||||
shufps xmm6, xmm6, 0x00 // xmm6 = scale scale
|
||||
movlhps xmm6, xmm6 // xmm6 = scale scale scale scale
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
}
|
||||
|
||||
destPosition.x += sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3];
|
||||
destPosition.y += sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3];
|
||||
destPosition.z += sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3];
|
||||
|
||||
//-- Prepare source normal.
|
||||
sseVariable[0][0] = sourceNormal.x;
|
||||
sseVariable[0][1] = sourceNormal.y;
|
||||
sseVariable[0][2] = sourceNormal.z;
|
||||
sseVariable[0][3] = 1.0f;
|
||||
|
||||
__asm {
|
||||
//-- Load up the source vector.
|
||||
movaps xmm3, [ebx] // xmm3 = sx sy sz 1
|
||||
|
||||
//-- Copy source to workspaces.
|
||||
movaps xmm4, xmm3 // xmm4 = sx sy sz 1
|
||||
movaps xmm5, xmm3 // xmm5 = sx sy sz 1
|
||||
|
||||
//-- Do the transform multiplies.
|
||||
mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4
|
||||
mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4
|
||||
mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4
|
||||
|
||||
//-- Do the scale multiplies.
|
||||
mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale
|
||||
mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale
|
||||
mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale
|
||||
|
||||
//-- Save out data.
|
||||
movaps [ebx + 32], xmm3
|
||||
movaps [ebx + 48], xmm4
|
||||
movaps [ebx + 64], xmm5
|
||||
|
||||
//-- Restore EBX
|
||||
pop ebx
|
||||
}
|
||||
|
||||
destNormal.x += sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2];
|
||||
destNormal.y += sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2];
|
||||
destNormal.z += sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2];
|
||||
} //lint !e715 // scale/transform not referenced - it's in the asm
|
||||
|
||||
// ======================================================================
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SseMath.h
|
||||
// Copyright 2002 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_SseMath_H
|
||||
#define INCLUDED_SseMath_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Transform;
|
||||
class Vector;
|
||||
|
||||
// ======================================================================
|
||||
#define MXCSR_FLUSH_TO_ZERO (1<<15)
|
||||
#define MXCSR_PRECISION_MASK (1<<12)
|
||||
#define MXCSR_UNDERFLOW_MASK (1<<11)
|
||||
#define MXCSR_OVERFLOW_MASK (1<<10)
|
||||
#define MXCSR_DIVIDE_BY_ZERO_MASK (1<< 9)
|
||||
#define MXCSR_DENORMAL_MASK (1<< 8)
|
||||
|
||||
class SseMath
|
||||
{
|
||||
public:
|
||||
|
||||
static bool canDoSseMath();
|
||||
|
||||
static Vector rotateTranslateScale_l2p(const Transform &transform, const Vector &vector, float scale);
|
||||
static Vector rotateScale_l2p(const Transform &transform, const Vector &vector, float scale);
|
||||
|
||||
static void skinPositionNormal_l2p(const Transform &transform, const Vector &position, const Vector &normal, float scale, Vector &destPosition, Vector &destNormal);
|
||||
static void skinPositionNormalAdd_l2p(const Transform &transform, const Vector &position, const Vector &normal, float scale, Vector &destPosition, Vector &destNormal);
|
||||
static void prefetch(void const * const sourceData, size_t const objectSize);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void SseMath::prefetch(void const * const sourceData, size_t const objectSize)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_asm
|
||||
{
|
||||
mov esi, sourceData
|
||||
prefetchnta objectSize[esi]
|
||||
}
|
||||
#else
|
||||
// rls - add linux version here.
|
||||
UNREF(sourceData);
|
||||
UNREF(objectSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsMemory.cpp
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
|
||||
#include "sharedMemoryManager/OsMemory.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void OsMemory::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void OsMemory::remove()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *OsMemory::reserve(size_t bytes)
|
||||
{
|
||||
return VirtualAlloc(0, bytes, MEM_RESERVE, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *OsMemory::commit(void *addr, size_t bytes)
|
||||
{
|
||||
return VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool OsMemory::free(void *addr, size_t bytes)
|
||||
{
|
||||
UNREF(bytes);
|
||||
return VirtualFree(addr, 0, MEM_RELEASE) ? true : false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool OsMemory::protect(void *addr, size_t bytes, bool allowAccess)
|
||||
{
|
||||
DWORD old;
|
||||
BOOL result = VirtualProtect(addr, bytes, allowAccess ? PAGE_READWRITE : PAGE_NOACCESS, &old);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsMemory.h
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_OsMemory_H
|
||||
#define INCLUDED_OsMemory_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class OsMemory
|
||||
{
|
||||
public:
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static void * reserve(size_t bytes);
|
||||
static void * commit(void *addr, size_t bytes);
|
||||
static bool free(void *addr, size_t bytes);
|
||||
static bool protect(void *addr, size_t bytes, bool allowAccess);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif INCLUDED_OsMemory_H
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsNewDel.cpp
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
|
||||
#include "sharedMemoryManager/OsNewDel.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// this is here because MSVC won't call MemoryManager::allocate() from asm directly
|
||||
static void * __cdecl localAllocate(size_t size, uint32 owner, bool array, bool leakTest)
|
||||
{
|
||||
return MemoryManager::allocate(size, owner, array, leakTest);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// We are using the arguments (except for file and line), but MSVC can't tell that.
|
||||
#pragma warning(disable: 4100)
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
__declspec(naked) void *operator new(size_t size, MemoryManagerNotALeak)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], false, false)
|
||||
push 0
|
||||
push 0
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
__declspec(naked) void *operator new(size_t size)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], false, true)
|
||||
push 1
|
||||
push 0
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
__declspec(naked) void *operator new[](size_t size)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], true, true)
|
||||
push 1
|
||||
push 1
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
__declspec(naked) void *operator new(size_t size, const char *file, int line)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], false, true)
|
||||
push 1
|
||||
push 0
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
__declspec(naked) void *operator new[](size_t size, const char *file, int line)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], true, true)
|
||||
push 1
|
||||
push 1
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#pragma warning(default: 4100)
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete(void *pointer)
|
||||
{
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete[](void *pointer)
|
||||
{
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete(void *pointer, const char *file, int line)
|
||||
{
|
||||
UNREF(file);
|
||||
UNREF(line);
|
||||
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete[](void *pointer, const char *file, int line)
|
||||
{
|
||||
UNREF(file);
|
||||
UNREF(line);
|
||||
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, true);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// WARNING!!!!!!!
|
||||
//
|
||||
// The init_seg pragma command is used to create certain static objects first, before other static objects are created.
|
||||
// However, multiple static variables that use the same init_seg category(i.e. compiler) are not guaranteed to destroy in any
|
||||
// particular order. It is completely random based on how all the linking of static objects occurs. Since this command is being
|
||||
// used on our memory manager(to overwrite new/delete) - NO OTHER STATIC SHOULD EVER USE INIT_SEG(COMPILER)!!!! This static object
|
||||
// *MUST* be the final static object that is destroyed.
|
||||
//
|
||||
#pragma warning(disable: 4074)
|
||||
#pragma init_seg(compiler) // ^-Read warning above.-^
|
||||
static MemoryManager memoryManager;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsNewDel.h
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_OsNewDel_H
|
||||
#define INCLUDED_OsNewDel_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
enum MemoryManagerNotALeak
|
||||
{
|
||||
MM_notALeak
|
||||
};
|
||||
|
||||
void * __cdecl operator new(size_t size, MemoryManagerNotALeak);
|
||||
void * __cdecl operator new(size_t size);
|
||||
void * __cdecl operator new[](size_t size);
|
||||
void * __cdecl operator new(size_t size, char const *file, int line);
|
||||
void * __cdecl operator new[](size_t size, char const *file, int line);
|
||||
void * __cdecl operator new(size_t size, void *placement);
|
||||
|
||||
void operator delete(void *pointer);
|
||||
void operator delete[](void *pointer);
|
||||
void operator delete(void *pointer, char const *file, int line);
|
||||
void operator delete[](void *pointer, char const *file, int line);
|
||||
void operator delete(void *pointer, void *placement);
|
||||
|
||||
#ifndef __PLACEMENT_NEW_INLINE
|
||||
#define __PLACEMENT_NEW_INLINE
|
||||
|
||||
inline void *operator new(size_t size, void *placement)
|
||||
{
|
||||
static_cast<void>(size);
|
||||
return placement;
|
||||
}
|
||||
|
||||
inline void operator delete(void *pointer, void *placement)
|
||||
{
|
||||
static_cast<void>(pointer);
|
||||
static_cast<void>(placement);
|
||||
}
|
||||
|
||||
#endif // __PLACEMENT_NEW_INLINE
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif INCLUDED_OsNewDel_H
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstMessageDispatch.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMessageDispatch/FirstSharedMessageDispatch.h"
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
// Address.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <winsock.h>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Construct an empty address (INADDR_ANY)
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address() :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("0.0.0.0")
|
||||
{
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_family = AF_INET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct an address from a human readable dotted-decimal
|
||||
host address and port
|
||||
|
||||
Care should be taken when using this constructor. It could potentially
|
||||
invoke gethostbyname() and block while the resolver returns a
|
||||
valid ip address.
|
||||
|
||||
@author Justin Randall
|
||||
|
||||
@todo Add a static resolver cache to Address to reduce potential
|
||||
calls to gethostbyname()
|
||||
*/
|
||||
Address::Address(const std::string & newHostAddress, const unsigned short newHostPort) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(newHostAddress)
|
||||
{
|
||||
HOSTENT * h;
|
||||
unsigned long u;
|
||||
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_port = htons(newHostPort);
|
||||
addr4->sin_family = AF_INET;
|
||||
// was an address supplied?
|
||||
if(hostAddress.size() > 0)
|
||||
{
|
||||
// Is the first byte a number? (IP names begin with an alpha)
|
||||
if(!isdigit(hostAddress[0]))
|
||||
{
|
||||
// The first byte is a letter, resolve it
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
int i = 0;
|
||||
while (h->h_addr_list[i] != 0) {
|
||||
memcpy(&addr4->sin_addr, h->h_addr_list[i++], sizeof(addr4->sin_addr));
|
||||
//addr4->sin_addr = *(u_long *) h->h_addr_list[i++];
|
||||
//printf("\tIP Address #%d: %s\n", i, inet_ntoa(addr));
|
||||
}
|
||||
//memcpy(&addr4->sin_addr, h->h_addr_list[0], sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// boom! grab the entry from the h_addr member instead!
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
memcpy(&addr4->sin_addr, h->h_addr, sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// no resolution, INADDR_ANY
|
||||
// could be that the network needs a kick in the ass
|
||||
memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
|
||||
}
|
||||
}
|
||||
|
||||
// extract IP bytes from ipv4add4
|
||||
const unsigned char * ip;
|
||||
char name[17] = {"\0"};
|
||||
|
||||
ip = reinterpret_cast<const unsigned char *>(&addr4->sin_addr);
|
||||
_snprintf(name, 17, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); //lint !e534
|
||||
hostAddress = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A dotted decimal ip number string was supplied. Convert for sin_addr
|
||||
u = inet_addr(hostAddress.c_str());
|
||||
memcpy(&addr4->sin_addr, &u, sizeof(addr4->sin_addr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing was supplied, assign INADDR_ANY
|
||||
addr4->sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
convertFromSockAddr(*addr4);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Address copy constructor
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address(const Address & source) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(source.hostAddress)
|
||||
{
|
||||
*addr4 = *source.addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Constructs an address from a BSD sockaddr structure
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address(const struct sockaddr_in & ipv4addr) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress()
|
||||
{
|
||||
convertFromSockAddr(ipv4addr);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Destroy an address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::~Address()
|
||||
{
|
||||
delete addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Aassign an address to anothe address
|
||||
*/
|
||||
Address & Address::operator = (const Address & rhs)
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
hostAddress = rhs.hostAddress;
|
||||
*addr4 = *rhs.addr4;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Assign an address to a BSD sockaddr_in structure
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address & Address::operator = (const struct sockaddr_in & rhs)
|
||||
{
|
||||
convertFromSockAddr(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Address::convertFromSockAddr(const struct sockaddr_in & source)
|
||||
{
|
||||
// extract IP bytes from ipv4add4
|
||||
const unsigned char * ip;
|
||||
char name[17] = {"\0"};
|
||||
|
||||
ip = reinterpret_cast<const unsigned char *>(&source.sin_addr);
|
||||
_snprintf(name, 17, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); //lint !e534
|
||||
hostAddress = name;
|
||||
if(addr4 != &source)
|
||||
*addr4 = source;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get a human readable host address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("address = %%s\\n", b.getHostAddress().c_str());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable host address string
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const std::string & Address::getHostAddress() const
|
||||
{
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the port associated with this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("port = %%i\\n", b.getHostPort());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable port in host-byte order associated with
|
||||
this address.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned short Address::getHostPort() const
|
||||
{
|
||||
return ntohs(addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the BSD sockaddr describing this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(SOCKET s, unsigned char * d, int l, const Address & a)
|
||||
{
|
||||
int t = sizeof(struct sockaddr_in);
|
||||
sendto(s, s, l, 0, reinterpret_cast<const struct sockaddr *>(&(a.getSockAddr4())), t);
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return a BSD sockaddr that describes this IPv4 address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const struct sockaddr_in & Address::getSockAddr4() const
|
||||
{
|
||||
return *addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief equality operator
|
||||
|
||||
The equality operator compares the ip address, ip port,
|
||||
and address family to establish equality.
|
||||
|
||||
Example:
|
||||
\code
|
||||
Address a("127.0.0.1", 55443);
|
||||
Address b;
|
||||
|
||||
b = a;
|
||||
\endcode
|
||||
|
||||
@return True of the right hand side is equal to this address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator == (const Address & rhs) const
|
||||
{
|
||||
return (addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_family == rhs.addr4->sin_family &&
|
||||
addr4->sin_port == rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief less-than comparison operator
|
||||
|
||||
The < comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the left hand side port is
|
||||
less than the right hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is less than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is less
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator < (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr < rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port < rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief inequality operator
|
||||
|
||||
Leverages the equality operator, so whenever == returns true,
|
||||
this returns false, and visa versa.
|
||||
|
||||
@return true if the right hand side is not equal to the left
|
||||
hand side. False if they are equal.
|
||||
|
||||
@see Adress::operator==
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator != (const Address & rhs) const
|
||||
{
|
||||
return(! (rhs == *this));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief greater-than comparison operator
|
||||
|
||||
The > comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the right hand side port is
|
||||
lesser than the left hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is greater than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is greater
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator > (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr > rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port > rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief a hash_map support routine
|
||||
|
||||
The STL hash_map (present in most STL implementations) requires
|
||||
a size_t return from a hash function to identify which bucket
|
||||
a particular value should reside in. On 32 bit or better platforms
|
||||
the sockaddr_in.sin_addr.s_addr member is small enough to
|
||||
qualify as a hash-result, provides reasonably unique values
|
||||
and is reproducable given an address input.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return the ip number member of a sockaddr_in struct
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::hashFunction() const
|
||||
{
|
||||
return addr4->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL map support routine
|
||||
|
||||
STL maps (including hash_maps) require unique keys, and therefore
|
||||
need to compare a key for equality with an existing target.
|
||||
|
||||
The functor uses Address::operator = for the comparison.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::unordered_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return true if the left hand side and right hand side are equal
|
||||
using Address::operator =
|
||||
@see Address::operator=
|
||||
|
||||
*/
|
||||
bool Address::EqualFunction::operator () (const Address & lhs, const Address & rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL hash_map support routine
|
||||
|
||||
The HashFunction::operator() invokes Address::hashFunction to
|
||||
determine an appropriate hash for the address.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@see Address::hashFunction
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::HashFunction::operator () (const Address & a) const
|
||||
{
|
||||
return a.hashFunction();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
@@ -0,0 +1,9 @@
|
||||
// FirstSharedNetwork.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// NetworkGetHostName.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HN
|
||||
{
|
||||
HN();
|
||||
std::string hostName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HN::HN()
|
||||
{
|
||||
WSADATA wsaData;
|
||||
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
char name[512] = {"\0"};
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
Address a(name, 0);
|
||||
hostName = a.getHostAddress();//name;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & NetworkHandler::getHostName()
|
||||
{
|
||||
static HN hn;
|
||||
return hn.hostName;
|
||||
}
|
||||
|
||||
const std::string & NetworkHandler::getHumanReadableHostName()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
static std::string nameString;
|
||||
if(nameString.empty())
|
||||
{
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
name[sizeof(name) - 1] = 0;
|
||||
//hostName = name;
|
||||
nameString = name;
|
||||
}
|
||||
}
|
||||
return nameString;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > & NetworkHandler::getInterfaceAddresses()
|
||||
{
|
||||
static std::vector<std::pair<std::string, std::string> > s;
|
||||
return s;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -0,0 +1,85 @@
|
||||
// OverlappedTcp.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include <vector>
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp::~OverlappedTcp()
|
||||
{
|
||||
delete[] m_acceptData;
|
||||
delete[] m_recvBuf.buf;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
struct OverlappedFreeList
|
||||
{
|
||||
~OverlappedFreeList();
|
||||
std::vector<OverlappedTcp *> allOverlapped;
|
||||
std::vector<OverlappedTcp *> freeOverlapped;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedFreeList::~OverlappedFreeList()
|
||||
{
|
||||
std::vector<OverlappedTcp *>::const_iterator i;
|
||||
for(i = allOverlapped.begin(); i != allOverlapped.end(); ++i)
|
||||
{
|
||||
OverlappedTcp * t = (*i);
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedFreeList overlappedFreeList;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp * getFreeOverlapped()
|
||||
{
|
||||
OverlappedTcp * result = NULL;
|
||||
|
||||
if(! overlappedFreeList.freeOverlapped.empty())
|
||||
{
|
||||
result = overlappedFreeList.freeOverlapped.back();
|
||||
overlappedFreeList.freeOverlapped.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new OverlappedTcp;
|
||||
result->m_bytes = 0;
|
||||
memset(&result->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||
result->m_recvBuf.buf = new char[1024];
|
||||
result->m_recvBuf.len = 1024;
|
||||
result->m_tcpClient = 0;
|
||||
result->m_tcpServer = 0;
|
||||
result->m_acceptData = 0;
|
||||
overlappedFreeList.allOverlapped.push_back(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void releaseOverlapped(OverlappedTcp * o)
|
||||
{
|
||||
o->m_bytes = 0;
|
||||
o->m_tcpClient = 0;
|
||||
o->m_tcpServer = 0;
|
||||
o->m_acceptData = 0;
|
||||
memset(&o->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||
overlappedFreeList.freeOverlapped.push_back(o);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// OverlappedTcp.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_OverlappedTcp_H
|
||||
#define _INCLUDED_OverlappedTcp_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient;
|
||||
class TcpServer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct OverlappedTcp
|
||||
{
|
||||
~OverlappedTcp();
|
||||
OVERLAPPED m_overlapped;
|
||||
|
||||
enum OPERATIONS
|
||||
{
|
||||
INVALID,
|
||||
ACCEPT,
|
||||
SEND,
|
||||
RECV
|
||||
};
|
||||
|
||||
unsigned char * m_acceptData; // getting peer name during accept
|
||||
DWORD m_bytes;
|
||||
enum OPERATIONS m_operation;
|
||||
const TcpServer * m_tcpServer;
|
||||
TcpClient * m_tcpClient; // accepted sock when operation is accept
|
||||
WSABUF m_recvBuf;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp * getFreeOverlapped();
|
||||
void releaseOverlapped(OverlappedTcp *);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_OverlappedTcp_H
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
// Sock.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/Sock.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
struct WinsockStartupObject
|
||||
{
|
||||
WinsockStartupObject();
|
||||
~WinsockStartupObject();
|
||||
};
|
||||
|
||||
WinsockStartupObject::WinsockStartupObject()
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested;
|
||||
|
||||
wVersionRequested = MAKEWORD(2,0);
|
||||
int err;
|
||||
err = WSAStartup(wVersionRequested, &wsaData);
|
||||
}
|
||||
|
||||
WinsockStartupObject::~WinsockStartupObject()
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
WinsockStartupObject wso;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a Sock
|
||||
|
||||
This constructor sets handle to INVALID_SOCKET, lastError to
|
||||
Sock::SOCK_NO_ERROR and the bindAddress to the default Address.
|
||||
|
||||
@see Address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Sock::Sock() :
|
||||
handle(INVALID_SOCKET),
|
||||
lastError(Sock::SOCK_NO_ERROR),
|
||||
bindAddress()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the Sock object
|
||||
|
||||
checks for a valid socket close. It is an error to close a socket
|
||||
that will fail a close operation.
|
||||
|
||||
Also resets handle to INVALID_SOCKET
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Sock::~Sock()
|
||||
{
|
||||
// ensure we don't block, and that pending
|
||||
// data is sent with a graceful shutdown
|
||||
int err;
|
||||
err = closesocket(handle);
|
||||
if(err == SOCKET_ERROR)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
handle = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Bind the socket to the specified local address
|
||||
*/
|
||||
bool Sock::bind(const Address & newBindAddress)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
int enable = 1;
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||
|
||||
bindAddress = newBindAddress;
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
int err = ::bind(handle, reinterpret_cast<const struct sockaddr *>(&(bindAddress.getSockAddr4())), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
struct sockaddr_in a;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
bindAddress = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
OutputDebugString(getLastError().c_str());
|
||||
OutputDebugString("\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief bind the socket to the first available local address
|
||||
as provided by the operating system.
|
||||
|
||||
This bind call is useful for client sockets, or server sockets that
|
||||
can report their new address to a locator service.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
bool Sock::bind()
|
||||
{
|
||||
bool result = false;
|
||||
struct sockaddr_in a;
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
memset(&a, 0, sizeof(struct sockaddr_in));
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = 0;
|
||||
a.sin_addr.s_addr = INADDR_ANY;
|
||||
int err = ::bind(handle, reinterpret_cast<struct sockaddr *>(&a), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
bindAddress = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine if a socket is ready to receive
|
||||
|
||||
On Win32, select is invoked. On Linux, the poll() system call is
|
||||
used to deterine readability of a socket.
|
||||
|
||||
@return true if the socket can read data without blocking.
|
||||
|
||||
@author Justin Randall
|
||||
|
||||
@todo Win32 should be using WSAEventSelect and WSAEnumNetworkEvents
|
||||
if they outperform select.
|
||||
*/
|
||||
bool Sock::canRecv() const
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set r;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&r);
|
||||
#pragma warning (disable : 4127)
|
||||
FD_SET(handle, &r); //lint !e717 // I have no idea why MS makes this a do { .. } while(0); macro?! Pointless.
|
||||
return (select(1, &r, 0, 0, &tv) > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine writeability of the socket
|
||||
|
||||
Win32 systems use select, Linux use poll.
|
||||
|
||||
@return true if the socket can send data without blocking.
|
||||
@author Justin Randall
|
||||
|
||||
@todo Win32 should be using WSAEventSelect and WSAEnumNetworkEvents
|
||||
if they outperform select.
|
||||
*/
|
||||
bool Sock::canSend() const
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set w;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&w);
|
||||
FD_SET(handle, &w); //lint !e717 // I have no idea why MS makes this a do { .. } while(0); macro?! Pointless.
|
||||
|
||||
return (select(1, 0, &w, 0, &tv) > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine the number of bytes pending on the socket
|
||||
|
||||
Uses ioctl (ioctlsocket on win32) to determine the number
|
||||
of bytes pending.
|
||||
|
||||
@return the number of unread bytes pending on the socket
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int Sock::getInputBytesPending() const
|
||||
{
|
||||
unsigned long int bytes = 0;
|
||||
int err;
|
||||
err = ioctlsocket(handle, FIONREAD, &bytes); //lint !e1924 (I don't know WHAT Microsoft is doing here!)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine the error state of the socket
|
||||
|
||||
This routine also sets the lastError member of the Sock object, which
|
||||
is used to determine common errors (connection failure, connection
|
||||
closed, connection reset, etc..)
|
||||
|
||||
@return an STL string that describes the error state of the socket,
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const std::string Sock::getLastError() const
|
||||
{
|
||||
std::string errString;
|
||||
int iErr = WSAGetLastError();
|
||||
|
||||
switch(iErr)
|
||||
{
|
||||
case WSAENOPROTOOPT:
|
||||
errString = "Bad protocol option. An unknown, invalid or unsupported option or level was specified in a getsockopt or setsockopt call.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
errString = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
errString = "The buf parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
errString = "The socket is not connected.";
|
||||
lastError = Sock::CONNECTION_FAILED;
|
||||
break;
|
||||
case WSAEINTR:
|
||||
errString = "The (blocking) call was canceled through WSACancelBlockingCall.";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
errString = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
errString = "The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
errString = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
errString = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
errString = "The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
errString = "The socket is marked as nonblocking and the receive operation would block.";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
errString = "The message was too large to fit into the specified buffer and was truncated.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
errString = "The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative.";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
errString = "The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable.";
|
||||
lastError = Sock::CONNECTION_RESET;
|
||||
break;
|
||||
case WSAETIMEDOUT:
|
||||
errString = "The connection has been dropped because of a network failure or because the peer system failed to respond.";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
errString = "The virtual circuit was reset by the remote side executing a \"hard\" or \"abortive\" close. The application should close the socket as it is no longer usable. On a UDP datagram socket this error would indicate that a previous send operation resulted in an ICMP \"Port Unreachable\" message.";
|
||||
lastError = Sock::CONNECTION_RESET;
|
||||
break;
|
||||
case WSAECONNREFUSED:
|
||||
errString = "No connection could be made because the target machine actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host - i.e. one with no server application running. ";
|
||||
lastError = Sock::CONNECTION_FAILED;
|
||||
break;
|
||||
default:
|
||||
errString = "An unknown socket error has occurred.";
|
||||
break;
|
||||
}
|
||||
|
||||
return errString;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** @brief determine the maximum message size that may be sent on this socket
|
||||
*/
|
||||
const unsigned int Sock::getMaxMessageSendSize() const
|
||||
{
|
||||
/*
|
||||
int maxMsgSize = 400;
|
||||
int optlen = sizeof(int);
|
||||
int result = getsockopt(handle, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char *>(&maxMsgSize), &optlen);
|
||||
if(result != 0)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
OutputDebugString("A successful WSAStartup call must occur before using this function. ");
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
OutputDebugString("The network subsystem has failed. ");
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
OutputDebugString("One of the optval or the optlen parameters is not a valid part of the user address space, or the optlen parameter is too small. ");
|
||||
case WSAEINPROGRESS:
|
||||
OutputDebugString("A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. ");
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
OutputDebugString("The level parameter is unknown or invalid. ");
|
||||
break;
|
||||
case WSAENOPROTOOPT:
|
||||
OutputDebugString("The option is unknown or unsupported by the indicated protocol family. ");
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
OutputDebugString("The descriptor is not a socket. ");
|
||||
break;
|
||||
default:
|
||||
OutputDebugString("An unknown error occurred while processing getsockopt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return 400;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get a BSD sockaddr struct describing the remote address
|
||||
of a socket
|
||||
|
||||
@param target a BSD sockaddr struct that will receive the peer
|
||||
address
|
||||
@param s the socket to query for the peername
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Sock::getPeerName(struct sockaddr_in & target, SOCKET s)
|
||||
{
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
int err;
|
||||
err = getpeername(s, reinterpret_cast<sockaddr *>(&(target)), &namelen);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/** @brief a support routine to place the socket in non-blocking mode
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Sock::setNonBlocking() const
|
||||
{
|
||||
unsigned long int nb = 1;
|
||||
int err;
|
||||
err = ioctlsocket(handle, FIONBIO, &nb); //lint !e569 // loss of precision in the FIONBIO macro, beyond my control
|
||||
if(err == SOCKET_ERROR)
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Sock.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Sock_H
|
||||
#define INCLUDED_Sock_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const unsigned int SOCK_ERROR = 0xFFFFFFFF;
|
||||
typedef unsigned int SOCKET;
|
||||
|
||||
/**
|
||||
@brief a BSD socket abstraction
|
||||
|
||||
Sock abstracts BSD sockets for platform independant operation. It
|
||||
also provides common socket operations to simplify socket management.
|
||||
|
||||
@see BroadcastSock
|
||||
@see TcpSock
|
||||
@see UdpSock
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Sock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@brief failure states for a socket
|
||||
*/
|
||||
enum ErrorCodes
|
||||
{
|
||||
SOCK_NO_ERROR,
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_CLOSED,
|
||||
CONNECTION_RESET
|
||||
};
|
||||
|
||||
Sock();
|
||||
virtual ~Sock() = 0;
|
||||
bool bind(const Address & bindAddress);
|
||||
bool bind();
|
||||
bool canSend() const;
|
||||
bool canRecv() const;
|
||||
const Address & getBindAddress() const;
|
||||
const SOCKET getHandle() const;
|
||||
const unsigned int getInputBytesPending() const;
|
||||
const std::string getLastError() const;
|
||||
const enum ErrorCodes getLastErrorCode() const;
|
||||
const unsigned int getMaxMessageSendSize() const;
|
||||
static void getPeerName(struct sockaddr_in & target, SOCKET s);
|
||||
|
||||
private:
|
||||
// disabled
|
||||
Sock(const Sock & source);
|
||||
Sock & operator= (const Sock & source);
|
||||
|
||||
protected:
|
||||
void setNonBlocking() const;
|
||||
protected:
|
||||
int handle;
|
||||
|
||||
/**
|
||||
@brief support for setting/getting last error from derived
|
||||
sock classes
|
||||
*/
|
||||
mutable enum ErrorCodes lastError;
|
||||
private:
|
||||
Address bindAddress;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the local address of the socket
|
||||
|
||||
Until a socket is bound, the bind address may be reported as
|
||||
0.0.0.0:0
|
||||
|
||||
@return a const Address reference describing the local address
|
||||
of the socket.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const Address & Sock::getBindAddress() const
|
||||
{
|
||||
return bindAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the platform specific socket handle
|
||||
|
||||
the handle returned is not portable and should only be used locally
|
||||
for Sock specific operations.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const SOCKET Sock::getHandle() const
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the last error code on the socket
|
||||
|
||||
@return the last error code on the socket
|
||||
|
||||
@see Sock::ErrorCodes
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const enum Sock::ErrorCodes Sock::getLastErrorCode() const
|
||||
{
|
||||
return lastError;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _Sock_H
|
||||
|
||||
+631
@@ -0,0 +1,631 @@
|
||||
// TcpClient.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "Archive/Archive.h"
|
||||
#include "Archive/ByteStream.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include "TcpClient.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned long KEEPALIVE_MS = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace TcpClientNamespace
|
||||
{
|
||||
std::set<TcpClient *> s_pendingConnectionSends;
|
||||
std::set<TcpClient *> s_pendingConnectionRemoves;
|
||||
std::set<TcpClient *> s_tcpClients;
|
||||
QOS s_sqos;
|
||||
QOS s_gqos;
|
||||
}
|
||||
|
||||
using namespace TcpClientNamespace;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient(HANDLE parentIOCP) :
|
||||
m_connectEvent(INVALID_HANDLE_VALUE),
|
||||
m_socket(),
|
||||
m_tcpServer(0),
|
||||
m_localIOCP(INVALID_HANDLE_VALUE),
|
||||
m_pendingSend(),
|
||||
m_connection(0),
|
||||
m_refCount(0),
|
||||
m_connected(false),
|
||||
m_ownHandle(false),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
static PROTOENT * p = getprotobyname ("tcp");
|
||||
if (p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_socket = WSASocket (AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
char optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
unsigned long opt = 1;
|
||||
ioctlsocket(m_socket, FIONBIO, &opt);
|
||||
|
||||
struct sockaddr_in bindAddr;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
m_localIOCP = CreateIoCompletionPort (reinterpret_cast<HANDLE> (m_socket), parentIOCP, 0, 0);
|
||||
queueReceive();
|
||||
}
|
||||
s_tcpClients.insert(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient(const std::string & remoteAddress, const unsigned short remotePort) :
|
||||
m_connectEvent(INVALID_HANDLE_VALUE),
|
||||
m_socket(),
|
||||
m_localIOCP(INVALID_HANDLE_VALUE),
|
||||
m_connection(0),
|
||||
m_refCount(0),
|
||||
m_connected(false),
|
||||
m_ownHandle(true),
|
||||
m_lastSendTime(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
static PROTOENT * p = getprotobyname ("tcp");
|
||||
if (p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_socket = WSASocket (AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
if (m_socket != INVALID_SOCKET)
|
||||
{
|
||||
int nameLen = sizeof (struct sockaddr_in);
|
||||
static WSABUF emptyBuf;
|
||||
emptyBuf.buf = 0;
|
||||
emptyBuf.len = 0;
|
||||
|
||||
Address a(remoteAddress, remotePort);
|
||||
char optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
unsigned long opt = 1;
|
||||
ioctlsocket(m_socket, FIONBIO, &opt);
|
||||
|
||||
int result;
|
||||
result = WSAConnect (m_socket, reinterpret_cast<const struct sockaddr *> (&a.getSockAddr4 () ), nameLen, 0, &emptyBuf, &s_sqos, &s_gqos);
|
||||
m_connectEvent = WSACreateEvent ();
|
||||
WSAEventSelect (m_socket, m_connectEvent, FD_CONNECT);
|
||||
m_localIOCP = CreateIoCompletionPort (reinterpret_cast<HANDLE> (m_socket), 0, 0, 0);
|
||||
struct sockaddr_in bindAddr;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
s_tcpClients.insert(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::~TcpClient()
|
||||
{
|
||||
s_pendingConnectionRemoves.insert(this);
|
||||
std::set<TcpClient *>::iterator f = s_tcpClients.find(this);
|
||||
if(f != s_tcpClients.end())
|
||||
s_tcpClients.erase(f);
|
||||
|
||||
closesocket (m_socket);
|
||||
if(m_ownHandle)
|
||||
CloseHandle(m_localIOCP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::addRef()
|
||||
{
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
std::string const &TcpClient::getRemoteAddress() const
|
||||
{
|
||||
// TODO: implement this
|
||||
static std::string dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getRemotePort() const
|
||||
{
|
||||
// TODO: implement this
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::commit(const unsigned char * const buffer, const int bufferLen)
|
||||
{
|
||||
WSABUF wsaBuf;
|
||||
|
||||
// yuck, docs say this is actually going to be const for the send,
|
||||
// but WSABUF::buf is not const!
|
||||
wsaBuf.buf = (char *)buffer;
|
||||
wsaBuf.len = bufferLen;
|
||||
|
||||
OverlappedTcp * op = getFreeOverlapped ();
|
||||
if (op)
|
||||
{
|
||||
op->m_operation = OverlappedTcp::SEND;
|
||||
op->m_tcpClient = const_cast<TcpClient *>(this);
|
||||
int sent;
|
||||
sent = WSASend (m_socket, &wsaBuf, 1, &op->m_bytes, 0, &op->m_overlapped, NULL);
|
||||
if(sent == SOCKET_ERROR)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
char * err;
|
||||
if(errCode != WSA_IO_PENDING)
|
||||
{
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
err = "A successful WSAStartup must occur before using this function.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
err = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
err = "The socket is not connected.";
|
||||
break;
|
||||
case WSAEINTR:
|
||||
err = "The (blocking) call was canceled through WSACancelBlockingCall. \n";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
err = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
err = "The connection has been broken due to \"keep-alive\" activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
err = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
err = "The lpBuffers parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
err = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
err = "The socket has been shut down; it is not possible to call WSARecv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. \n";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
err = "Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the receive operation cannot be completed immediately. \n";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
err = "The message was too large to fit into the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
err = "The socket has not been bound (for example, with bind).";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
err = "The virtual circuit was terminated due to a time-out or other failure. \n";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
err = "The virtual circuit was reset by the remote side. \n";
|
||||
break;
|
||||
case WSAEDISCON:
|
||||
err = "Socket s is message oriented and the virtual circuit was gracefully closed by the remote side. \n";
|
||||
break;
|
||||
case WSA_IO_PENDING:
|
||||
err = "An overlapped operation was successfully initiated and completion will be indicated at a later time. \n";
|
||||
break;
|
||||
case WSA_OPERATION_ABORTED:
|
||||
err = "The overlapped operation has been canceled due to the closure of the socket. \n";
|
||||
break;
|
||||
default:
|
||||
err = "An unknown error occured while processing WSARecv().";
|
||||
break;
|
||||
}
|
||||
onConnectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flush()
|
||||
{
|
||||
if(m_connected && m_pendingSend.getSize() > 0)
|
||||
{
|
||||
// put it on the wire
|
||||
commit(m_pendingSend.getBuffer(), m_pendingSend.getSize());
|
||||
m_pendingSend.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flushPendingWrites()
|
||||
{
|
||||
std::set<TcpClient *>::iterator f;
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_pendingConnectionSends.begin(); i != s_pendingConnectionSends.end(); ++i)
|
||||
{
|
||||
if(s_pendingConnectionRemoves.empty())
|
||||
{
|
||||
(*i)->flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
f = s_pendingConnectionRemoves.find((*i));
|
||||
if(f == s_pendingConnectionRemoves.end())
|
||||
(*i)->flush();
|
||||
}
|
||||
}
|
||||
s_pendingConnectionSends.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
SOCKET TcpClient::getSocket() const
|
||||
{
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::install()
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD(2,2);
|
||||
WSADATA wsaData;
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
s_sqos.ProviderSpecific.buf = 0;
|
||||
s_sqos.ProviderSpecific.len = 0;
|
||||
|
||||
s_sqos.ReceivingFlowspec.DelayVariation = 0;
|
||||
s_sqos.ReceivingFlowspec.Latency = 0;
|
||||
s_sqos.ReceivingFlowspec.MaxSduSize = 0;
|
||||
s_sqos.ReceivingFlowspec.MinimumPolicedSize = 0;
|
||||
s_sqos.ReceivingFlowspec.PeakBandwidth = 0;
|
||||
s_sqos.ReceivingFlowspec.ServiceType = 0;
|
||||
s_sqos.ReceivingFlowspec.TokenBucketSize = 0;
|
||||
s_sqos.ReceivingFlowspec.TokenRate = 0;
|
||||
|
||||
s_sqos.SendingFlowspec.DelayVariation = 0;
|
||||
s_sqos.SendingFlowspec.Latency = 0;
|
||||
s_sqos.SendingFlowspec.MaxSduSize = 0;
|
||||
s_sqos.SendingFlowspec.MinimumPolicedSize = 0;
|
||||
s_sqos.SendingFlowspec.PeakBandwidth = 0;
|
||||
s_sqos.SendingFlowspec.ServiceType = 0;
|
||||
s_sqos.SendingFlowspec.TokenBucketSize = 0;
|
||||
s_sqos.SendingFlowspec.TokenRate = 0;
|
||||
|
||||
s_gqos.ProviderSpecific.buf = 0;
|
||||
s_gqos.ProviderSpecific.len = 0;
|
||||
|
||||
s_gqos.ReceivingFlowspec.DelayVariation = 0;
|
||||
s_gqos.ReceivingFlowspec.Latency = 0;
|
||||
s_gqos.ReceivingFlowspec.MaxSduSize = 0;
|
||||
s_gqos.ReceivingFlowspec.MinimumPolicedSize = 0;
|
||||
s_gqos.ReceivingFlowspec.PeakBandwidth = 0;
|
||||
s_gqos.ReceivingFlowspec.ServiceType = 0;
|
||||
s_gqos.ReceivingFlowspec.TokenBucketSize = 0;
|
||||
s_gqos.ReceivingFlowspec.TokenRate = 0;
|
||||
|
||||
s_gqos.SendingFlowspec.DelayVariation = 0;
|
||||
s_gqos.SendingFlowspec.Latency = 0;
|
||||
s_gqos.SendingFlowspec.MaxSduSize = 0;
|
||||
s_gqos.SendingFlowspec.MinimumPolicedSize = 0;
|
||||
s_gqos.SendingFlowspec.PeakBandwidth = 0;
|
||||
s_gqos.SendingFlowspec.ServiceType = 0;
|
||||
s_gqos.SendingFlowspec.TokenBucketSize = 0;
|
||||
s_gqos.SendingFlowspec.TokenRate = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionClosed()
|
||||
{
|
||||
m_connected = false;
|
||||
if(m_connection)
|
||||
{
|
||||
NetworkHandler::onTerminate(m_connection);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionOpened()
|
||||
{
|
||||
m_connected = true;
|
||||
queueReceive();
|
||||
flush();
|
||||
if(m_connection)
|
||||
m_connection->onConnectionOpened();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onReceive(const unsigned char * const buffer, const int length)
|
||||
{
|
||||
queueReceive();
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->receive(buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queryConnect()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
WSANETWORKEVENTS w;
|
||||
if (WSAEnumNetworkEvents (m_socket, m_connectEvent, &w) != SOCKET_ERROR)
|
||||
{
|
||||
if (w.lNetworkEvents == FD_CONNECT)
|
||||
{
|
||||
if (w.iErrorCode[FD_CONNECT_BIT] == 0)
|
||||
{
|
||||
CloseHandle (m_connectEvent);
|
||||
result = true;
|
||||
onConnectionOpened();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queueReceive()
|
||||
{
|
||||
OverlappedTcp * op = getFreeOverlapped();
|
||||
op->m_operation = OverlappedTcp::RECV;
|
||||
op->m_tcpClient = const_cast<TcpClient *>(this);
|
||||
DWORD flags = 0;
|
||||
int result;
|
||||
result = WSARecv(m_socket, &op->m_recvBuf, 1, &op->m_bytes, &flags, &op->m_overlapped, NULL);
|
||||
|
||||
if(result == SOCKET_ERROR)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
char * err;
|
||||
if(errCode != WSA_IO_PENDING)
|
||||
{
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
err = "A successful WSAStartup must occur before using this function.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
err = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
err = "The socket is not connected.";
|
||||
break;
|
||||
case WSAEINTR:
|
||||
err = "The (blocking) call was canceled through WSACancelBlockingCall. \n";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
err = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
err = "The connection has been broken due to \"keep-alive\" activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
err = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
err = "The lpBuffers parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
err = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
err = "The socket has been shut down; it is not possible to call WSARecv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. \n";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
err = "Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the receive operation cannot be completed immediately. \n";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
err = "The message was too large to fit into the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
err = "The socket has not been bound (for example, with bind).";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
err = "The virtual circuit was terminated due to a time-out or other failure. \n";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
err = "The virtual circuit was reset by the remote side. \n";
|
||||
break;
|
||||
case WSAEDISCON:
|
||||
err = "Socket s is message oriented and the virtual circuit was gracefully closed by the remote side. \n";
|
||||
break;
|
||||
case WSA_IO_PENDING:
|
||||
err = "An overlapped operation was successfully initiated and completion will be indicated at a later time. \n";
|
||||
break;
|
||||
case WSA_OPERATION_ABORTED:
|
||||
err = "The overlapped operation has been canceled due to the closure of the socket. \n";
|
||||
break;
|
||||
default:
|
||||
err = "An unknown error occured while processing WSARecv().";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::send(const unsigned char * const buffer, const int length)
|
||||
{
|
||||
if (length)
|
||||
{
|
||||
m_lastSendTime = Clock::getFrameStartTimeMs();
|
||||
s_pendingConnectionSends.insert(this);
|
||||
if( !m_rawTCP )
|
||||
Archive::put(m_pendingSend, length);
|
||||
m_pendingSend.put(buffer, length);
|
||||
|
||||
static int const tcpMinimumFrame = ConfigSharedNetwork::getTcpMinimumFrame();
|
||||
if (static_cast<int>(m_pendingSend.getSize()) >= tcpMinimumFrame)
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setConnection(Connection * c)
|
||||
{
|
||||
m_connection = c;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::update()
|
||||
{
|
||||
OVERLAPPED * overlapped = 0;
|
||||
OverlappedTcp * op = 0;
|
||||
unsigned long int bytesTransferred = 0;
|
||||
unsigned long int completionKey = 0;
|
||||
bool success = false;
|
||||
|
||||
if (m_connected)
|
||||
{
|
||||
unsigned long timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(! m_connected)
|
||||
queryConnect();
|
||||
|
||||
//PlatformTcpClient::queryConnects();
|
||||
do
|
||||
{
|
||||
success = false;
|
||||
int ok = GetQueuedCompletionStatus(
|
||||
m_localIOCP, // completion port of interest
|
||||
&bytesTransferred, // number of bytes sent or received
|
||||
&completionKey,
|
||||
&overlapped,
|
||||
0 // timeout immediately if there are no completions
|
||||
);
|
||||
if(ok)
|
||||
{
|
||||
op = reinterpret_cast<OverlappedTcp *>(overlapped);
|
||||
if(op)
|
||||
{
|
||||
switch(op->m_operation)
|
||||
{
|
||||
case OverlappedTcp::RECV:
|
||||
{
|
||||
if(op->m_tcpClient != 0)
|
||||
{
|
||||
if(bytesTransferred > 0)
|
||||
{
|
||||
op->m_tcpClient->onReceive((const unsigned char * const)op->m_recvBuf.buf, bytesTransferred);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case OverlappedTcp::SEND:
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
releaseOverlapped(op);
|
||||
}
|
||||
}
|
||||
} while(success);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setRawTCP( bool bNewValue )
|
||||
{
|
||||
m_rawTCP = bNewValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::release()
|
||||
{
|
||||
m_refCount--;
|
||||
if(m_refCount < 1)
|
||||
{
|
||||
if(m_connected)
|
||||
onConnectionClosed();
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::remove()
|
||||
{
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_tcpClients.begin(); i != s_tcpClients.end(); ++i)
|
||||
{
|
||||
TcpClient * c = (*i);
|
||||
delete c;
|
||||
}
|
||||
s_tcpClients.clear();
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::checkKeepalive()
|
||||
{
|
||||
unsigned long const timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// TcpClient.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpClient_H
|
||||
#define _INCLUDED_TcpClient_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
#include "Archive/ByteStream.h"
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Connection;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient
|
||||
{
|
||||
public:
|
||||
explicit TcpClient(HANDLE parentIOCP);
|
||||
TcpClient(const std::string & address, const unsigned short port);
|
||||
~TcpClient();
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
void send(const unsigned char * const buffer, const int length);
|
||||
unsigned short getBindPort() const;
|
||||
std::string const &getRemoteAddress() const;
|
||||
unsigned short getRemotePort() const;
|
||||
void setPendingSendAllocatedSizeLimit(unsigned int limit);
|
||||
|
||||
// only used by clients
|
||||
void update();
|
||||
static void flushPendingWrites();
|
||||
|
||||
protected:
|
||||
friend TcpServer;
|
||||
friend Connection;
|
||||
|
||||
void addRef();
|
||||
void commit(const unsigned char * const buffer, const int bufferLen);
|
||||
SOCKET getSocket() const;
|
||||
void onConnectionClosed();
|
||||
void onConnectionOpened();
|
||||
void onReceive(const unsigned char * const recvBuf, const int bytes);
|
||||
void queryConnect();
|
||||
void queueReceive();
|
||||
void release();
|
||||
void setConnection(Connection *);
|
||||
|
||||
void checkKeepalive();
|
||||
void setRawTCP( bool bNewValue );
|
||||
|
||||
|
||||
private:
|
||||
TcpClient & operator = (const TcpClient & rhs);
|
||||
TcpClient(const TcpClient & source);
|
||||
void flush ();
|
||||
|
||||
WSAEVENT m_connectEvent;
|
||||
SOCKET m_socket;
|
||||
TcpServer * m_tcpServer;
|
||||
HANDLE m_localIOCP;
|
||||
Archive::ByteStream m_pendingSend;
|
||||
Connection * m_connection;
|
||||
int m_refCount;
|
||||
bool m_connected;
|
||||
bool m_ownHandle;
|
||||
unsigned long m_lastSendTime;
|
||||
unsigned short m_bindPort;
|
||||
|
||||
bool m_rawTCP;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline void TcpClient::setPendingSendAllocatedSizeLimit(const unsigned int limit)
|
||||
{
|
||||
m_pendingSend.setAllocatedSizeLimit(limit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpClient_H
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
// TcpServer.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpServer::TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort) :
|
||||
m_handle(),
|
||||
m_localIOCP(),
|
||||
m_pendingConnections(),
|
||||
m_bindAddress(bindAddress),
|
||||
m_bindPort(bindPort),
|
||||
m_service(service)
|
||||
{
|
||||
static PROTOENT * p = getprotobyname("tcp");
|
||||
if(p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_handle = WSASocket(AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
if(m_handle != INVALID_SOCKET)
|
||||
{
|
||||
m_localIOCP = CreateIoCompletionPort(reinterpret_cast<HANDLE>(m_handle), 0, 0, 0);
|
||||
Address a(bindAddress, bindPort);
|
||||
|
||||
int result = bind(m_handle, reinterpret_cast<const sockaddr *>(&a.getSockAddr4()), sizeof(struct sockaddr_in));
|
||||
if(result == 0)
|
||||
{
|
||||
struct sockaddr_in b;
|
||||
int addrlen = sizeof(struct sockaddr_in);
|
||||
getsockname(m_handle, (struct sockaddr *)(&b), &addrlen);
|
||||
m_bindPort = ntohs(b.sin_port);
|
||||
result = listen(m_handle, 256);
|
||||
queueAccept();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpServer::~TcpServer()
|
||||
{
|
||||
closesocket(m_handle);
|
||||
CloseHandle(m_localIOCP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient * TcpServer::accept()
|
||||
{
|
||||
TcpClient * result = 0;
|
||||
if(! m_pendingConnections.empty())
|
||||
{
|
||||
result = m_pendingConnections.back();
|
||||
m_pendingConnections.pop_back();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned short TcpServer::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::onConnectionClosed(TcpClient *)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::queueAccept()
|
||||
{
|
||||
OverlappedTcp * op = getFreeOverlapped();
|
||||
|
||||
// this will contain struct sockaddr data with additional
|
||||
// book keeping when Windows returns an overlapped
|
||||
// accept operation (nevermind that +16 or * 2, I don't have the MS
|
||||
// kb article handy, but it's a gross workaround for the documented
|
||||
// API and what acceptData really expects to have).
|
||||
op->m_acceptData = new unsigned char[(sizeof( struct sockaddr_in ) + 16 ) * 2];
|
||||
op->m_operation = OverlappedTcp::ACCEPT;
|
||||
op->m_tcpServer = this;
|
||||
op->m_tcpClient = new TcpClient(m_localIOCP);
|
||||
AcceptEx(
|
||||
m_handle,
|
||||
op->m_tcpClient->getSocket(),
|
||||
op->m_acceptData,
|
||||
0,
|
||||
sizeof(struct sockaddr_in) + 16,
|
||||
sizeof(struct sockaddr_in) + 16,
|
||||
&op->m_bytes,
|
||||
&op->m_overlapped);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::update()
|
||||
{
|
||||
OVERLAPPED * overlapped = 0;
|
||||
OverlappedTcp * op = 0;
|
||||
unsigned long int bytesTransferred = 0;
|
||||
unsigned long int completionKey = 0;
|
||||
bool success = false;
|
||||
|
||||
do
|
||||
{
|
||||
success = false;
|
||||
int ok = GetQueuedCompletionStatus(
|
||||
m_localIOCP, // completion port of interest
|
||||
&bytesTransferred, // number of bytes sent or received
|
||||
&completionKey,
|
||||
&overlapped,
|
||||
0 // timeout immediately if there are no completions
|
||||
);
|
||||
if(ok)
|
||||
{
|
||||
op = reinterpret_cast<OverlappedTcp *>(overlapped);
|
||||
if(op)
|
||||
{
|
||||
switch(op->m_operation)
|
||||
{
|
||||
case OverlappedTcp::ACCEPT:
|
||||
{
|
||||
if(op->m_tcpServer == this)
|
||||
{
|
||||
if(op->m_acceptData != 0)
|
||||
{
|
||||
// Extremely lame hack to keep things safe from Winsock stacktrashing
|
||||
//struct sockaddr_in local;
|
||||
//struct sockaddr_in remote;
|
||||
//memcpy(&local, reinterpret_cast<struct sockaddr_in *>(op->m_acceptData + 10), sizeof(struct sockaddr_in));
|
||||
//memcpy(&remote, reinterpret_cast<struct sockaddr_in *>(op->m_acceptData + 38), sizeof(struct sockaddr_in));
|
||||
delete[] op->m_acceptData;
|
||||
TcpClient * newClient = op->m_tcpClient;
|
||||
newClient->addRef();
|
||||
newClient->onConnectionOpened();
|
||||
m_pendingConnections.push_back(newClient);
|
||||
success = true;
|
||||
queueAccept();
|
||||
if(m_service)
|
||||
{
|
||||
m_service->onConnectionOpened(newClient);
|
||||
}
|
||||
newClient->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OverlappedTcp::RECV:
|
||||
{
|
||||
if(op->m_tcpClient != 0)
|
||||
{
|
||||
op->m_tcpClient->onReceive((const unsigned char * const)op->m_recvBuf.buf, bytesTransferred);
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
case OverlappedTcp::SEND:
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
releaseOverlapped(op);
|
||||
}
|
||||
}
|
||||
} while(success);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & TcpServer::getBindAddress() const
|
||||
{
|
||||
return m_bindAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// TcpServer.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpServer_H
|
||||
#define _INCLUDED_TcpServer_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Service;
|
||||
class TcpClient;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpServer
|
||||
{
|
||||
public:
|
||||
TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort);
|
||||
~TcpServer();
|
||||
|
||||
TcpClient * accept ();
|
||||
const std::string & getBindAddress () const;
|
||||
const unsigned short getBindPort () const;
|
||||
void onConnectionClosed (TcpClient *);
|
||||
void update ();
|
||||
|
||||
private:
|
||||
TcpServer & operator = (const TcpServer & rhs);
|
||||
TcpServer(const TcpServer & source);
|
||||
|
||||
void queueAccept ();
|
||||
|
||||
private:
|
||||
SOCKET m_handle;
|
||||
HANDLE m_localIOCP;
|
||||
std::vector<TcpClient *> m_pendingConnections;
|
||||
std::string m_bindAddress;
|
||||
unsigned short m_bindPort;
|
||||
Service * m_service;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpServer_H
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// UdpSock.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/UdpSock.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a UdpSock object
|
||||
|
||||
Allocates the socket descriptor, sets it to non-blocking mode.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
UdpSock::UdpSock() :
|
||||
Sock()
|
||||
{
|
||||
handle = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
setNonBlocking();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the UdpSock object
|
||||
|
||||
Doesn't do anything special.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
UdpSock::~UdpSock()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief receive a datagram
|
||||
|
||||
Receives a datagram and populates the outAddr parameter with the
|
||||
source address of the message.
|
||||
|
||||
Calling Sock::getInputBytesPending can provide a hint before
|
||||
allocating the user supplied target buffer.
|
||||
|
||||
@param outAddr target Address reference that receives
|
||||
the message source IP address
|
||||
@param targetBuffer a user supplied buffer to receive the data.
|
||||
@param targetBufferSize the size of the user supplied buffer
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int UdpSock::recvFrom(Address & outAddr, void * targetBuffer, const unsigned int bufferSize) const
|
||||
{
|
||||
int fromLen = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr;
|
||||
unsigned int result = ::recvfrom(handle, static_cast<char *>(targetBuffer), static_cast<int>(bufferSize), 0, reinterpret_cast<struct sockaddr *>(&addr), &fromLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
outAddr = addr;
|
||||
if(result == SOCK_ERROR)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief send a datagram to a remote system
|
||||
|
||||
sendTo sends a datagram to a remote system.
|
||||
|
||||
@param targetAddress System to receive the datagram
|
||||
@param sourceBuffer A user supplied buffer containint the data
|
||||
to be sent
|
||||
@param length The amount of data in the source buffer to
|
||||
send
|
||||
|
||||
@return The number of bytes sent on success
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int UdpSock::sendTo(const Address & targetAddress, const void * sourceBuffer, const unsigned int length) const
|
||||
{
|
||||
unsigned int bytesSent = 0;
|
||||
if(canSend())
|
||||
{
|
||||
int toLen = sizeof(struct sockaddr_in);
|
||||
bytesSent = ::sendto(handle, static_cast<const char *>(sourceBuffer), static_cast<int>(length), 0, reinterpret_cast<const struct sockaddr *>(&(targetAddress.getSockAddr4())), toLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
if(bytesSent != length)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
}
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpSock::enableBroadcast()
|
||||
{
|
||||
char optval = 1;
|
||||
int err;
|
||||
err = setsockopt(getHandle(), SOL_SOCKET, SO_BROADCAST, &optval, sizeof(char));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstNetworkMessages.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetworkMessages/FirstSharedNetworkMessages.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstObject.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedObject/FirstSharedObject.h"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstSharedPathfinding.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedPathfinding/FirstSharedPathfinding.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstRandom.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedRandom/FirstSharedRandom.h"
|
||||
@@ -0,0 +1,9 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstSharedRegex.cpp
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedRegex/FirstSharedRegex.h"
|
||||
@@ -0,0 +1,57 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RegexServices.cpp
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedRegex/FirstSharedRegex.h"
|
||||
#include "sharedRegex/RegexServices.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static void * __cdecl localAllocate(size_t size, uint32 owner, bool array, bool leakTest)
|
||||
{
|
||||
return MemoryManager::allocate(size, owner, array, leakTest);
|
||||
}
|
||||
|
||||
static __declspec(naked) void * regexAllocate(size_t)
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// setup local call stack
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// MemoryManager::alloc(size, [return address], false, true)
|
||||
push 1
|
||||
push 0
|
||||
mov eax, dword ptr [ebp+4]
|
||||
push eax
|
||||
mov eax, dword ptr [ebp+8]
|
||||
push eax
|
||||
call localAllocate
|
||||
add esp, 12
|
||||
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *RegexServices::allocateMemory(size_t byteCount)
|
||||
{
|
||||
return regexAllocate(byteCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void RegexServices::freeMemory(void *pointer)
|
||||
{
|
||||
MemoryManager::free(pointer, false);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,25 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RegexServices.h
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_RegexServices_H
|
||||
#define INCLUDED_RegexServices_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class RegexServices
|
||||
{
|
||||
public:
|
||||
|
||||
static void *allocateMemory(size_t byteCount);
|
||||
static void freeMemory(void *pointer);
|
||||
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// FirstSharedSkillSystem.cpp
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedSkillSystem/FirstSharedSkillSystem.h"
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConditionVariable.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedSynchronization/FirstSharedSynchronization.h"
|
||||
#include "sharedSynchronization/ConditionVariable.h"
|
||||
|
||||
#include "sharedSynchronization/Mutex.h"
|
||||
|
||||
ConditionVariable::ConditionVariable(Mutex &m)
|
||||
: sem(1), _mutex(m), count(0)
|
||||
{
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable()
|
||||
{
|
||||
}
|
||||
|
||||
void ConditionVariable::wait()
|
||||
{
|
||||
++count;
|
||||
_mutex.leave();
|
||||
sem.wait();
|
||||
_mutex.enter();
|
||||
}
|
||||
|
||||
void ConditionVariable::signal()
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
--count;
|
||||
sem.signal();
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionVariable::broadcast()
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
int oldcount = count;
|
||||
count = 0;
|
||||
sem.signal(oldcount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConditionVariable.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ConditionVariable_h
|
||||
#define INCLUDED_ConditionVariable_h
|
||||
|
||||
class Mutex;
|
||||
|
||||
#include "sharedSynchronization/Semaphore.h"
|
||||
|
||||
/* Condition variable semantics follow pthreads semantics. You
|
||||
must have the mutex locked before calling signal or broadcast.
|
||||
When wait returns, the mutex is locked and you must unlock it.
|
||||
*/
|
||||
|
||||
class ConditionVariable
|
||||
{
|
||||
public:
|
||||
ConditionVariable(Mutex &m);
|
||||
~ConditionVariable();
|
||||
void wait();
|
||||
// You must own the mutex before calling signal.
|
||||
void signal();
|
||||
void broadcast();
|
||||
Mutex &mutex() { return _mutex; }
|
||||
private:
|
||||
ConditionVariable(const ConditionVariable &o);
|
||||
ConditionVariable &operator =(const ConditionVariable &o);
|
||||
|
||||
Semaphore sem;
|
||||
Mutex &_mutex;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstSynchronization.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedSynchronization/FirstSharedSynchronization.h"
|
||||
@@ -0,0 +1,60 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Gate.cpp
|
||||
//
|
||||
// Copyright 2001-2002 Sony Online Entertainment
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedSynchronization/FirstSharedSynchronization.h"
|
||||
#include "sharedSynchronization/Gate.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
Gate::Gate(bool open)
|
||||
{
|
||||
handle = CreateEvent(0, true, open, 0);
|
||||
DEBUG_FATAL(handle == NULL, ("CreateEvent failed"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Gate::~Gate()
|
||||
{
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Gate::wait()
|
||||
{
|
||||
int errors = 0;
|
||||
for (;;)
|
||||
{
|
||||
DWORD result = WaitForSingleObject(handle, INFINITE);
|
||||
if (result == WAIT_OBJECT_0)
|
||||
return;
|
||||
|
||||
++errors;
|
||||
FATAL(errors >= 3, ("WaitForSingleObject failed multiple times"));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Gate::close()
|
||||
{
|
||||
const BOOL result = ResetEvent(handle);
|
||||
FATAL(result == 0, ("ResetEvent failed"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Gate::open()
|
||||
{
|
||||
const BOOL result = SetEvent(handle);
|
||||
FATAL(result == 0, ("SetEvent failed"));
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,39 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Gate.h
|
||||
//
|
||||
// Copyright 2001-2002 Sony Online Entertainment
|
||||
// All Rights Reseved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Gate_h
|
||||
#define INCLUDED_Gate_h
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Gate
|
||||
{
|
||||
public:
|
||||
|
||||
Gate(bool initiallyOpen);
|
||||
~Gate();
|
||||
|
||||
void wait();
|
||||
|
||||
void close();
|
||||
void open();
|
||||
|
||||
private:
|
||||
|
||||
Gate(const Gate &o);
|
||||
Gate &operator =(const Gate &o);
|
||||
|
||||
private:
|
||||
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// InterlockedInteger.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_InterlockedInteger_h
|
||||
#define INCLUDED_InterlockedInteger_h
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
class InterlockedInteger
|
||||
{
|
||||
public:
|
||||
explicit InterlockedInteger(int initialValue=0);
|
||||
int operator =(int); // returns prior value (exchange)
|
||||
int operator ++(); // returns new value
|
||||
int operator --(); // returns new value
|
||||
operator int() const { return static_cast<int>(value); }
|
||||
private:
|
||||
InterlockedInteger(const InterlockedInteger &o);
|
||||
InterlockedInteger &operator =(const InterlockedInteger &o);
|
||||
volatile int value;
|
||||
};
|
||||
|
||||
inline InterlockedInteger::InterlockedInteger(int i_value)
|
||||
: value(i_value)
|
||||
{
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator =(int i_value)
|
||||
{
|
||||
long * ptr = (long *)&value;
|
||||
return static_cast<int>(InterlockedExchange(ptr, static_cast<long>(i_value)));
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator ++()
|
||||
{
|
||||
long * ptr = (long *)&value;
|
||||
return static_cast<int>(InterlockedIncrement(ptr));
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator --()
|
||||
{
|
||||
long * ptr = (long *)&value;
|
||||
return static_cast<int>(InterlockedDecrement(ptr));
|
||||
}
|
||||
|
||||
#endif
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// InterlockedVoidPointer.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_InterlockedVoidPointer_h
|
||||
#define INCLUDED_InterlockedVoidPointer_h
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
class InterlockedVoidPointer
|
||||
{
|
||||
public:
|
||||
explicit InterlockedVoidPointer(void * initialValue=0);
|
||||
void * compareExchange(void * compare, void * exchange); // compare and exchange if same
|
||||
operator void * () const { return reinterpret_cast<void *>(value); }
|
||||
private:
|
||||
InterlockedVoidPointer(const InterlockedVoidPointer &o);
|
||||
InterlockedVoidPointer &operator =(const InterlockedVoidPointer &o);
|
||||
void * volatile value;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class InterlockedPointer: public InterlockedVoidPointer
|
||||
{
|
||||
public:
|
||||
explicit InterlockedPointer(T * initialValue): InterlockedVoidPointer(initialValue) {}
|
||||
operator T * () const { return static_cast<const T *>(value); }
|
||||
};
|
||||
|
||||
inline InterlockedVoidPointer::InterlockedVoidPointer(void * initialValue)
|
||||
{
|
||||
value = initialValue;
|
||||
}
|
||||
|
||||
inline void * InterlockedVoidPointer::compareExchange(void * compare, void * exchange)
|
||||
{
|
||||
return (void *)InterlockedCompareExchange((void **)&value, exchange, compare);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Mutex.cpp
|
||||
//
|
||||
// Copyright 2001-2002 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedSynchronization/FirstSharedSynchronization.h"
|
||||
#include "sharedSynchronization/Mutex.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void Mutex::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Mutex::remove()
|
||||
{
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
Mutex::Mutex()
|
||||
{
|
||||
InitializeCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
DeleteCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Mutex::enter()
|
||||
{
|
||||
EnterCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Mutex::leave()
|
||||
{
|
||||
LeaveCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user