mirror of
https://github.com/SWG-Source/client-tools.git
synced 2026-10-13 05:12:52 -04:00
cleanup some junk we don't need here
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
/* 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 <sqltypes.h>
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedDebugLinux.cpp
|
||||
// Copyright 2002 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/ConfigSharedDebugLinux.h"
|
||||
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
|
||||
//===================================================================
|
||||
|
||||
namespace ConfigSharedDebugLinuxNamespace
|
||||
{
|
||||
bool s_useTty;
|
||||
const char *s_debugMonitorOutputFilename;
|
||||
bool s_logTtySetup;
|
||||
}
|
||||
|
||||
using namespace ConfigSharedDebugLinuxNamespace;
|
||||
|
||||
//===================================================================
|
||||
|
||||
#define KEY_BOOL(a,b) (s_ ## a = ConfigFile::getKeyBool("SharedDebugLinux", #a, b))
|
||||
#define KEY_STRING(a,b) (s_ ## a = ConfigFile::getKeyString("SharedDebugLinux", #a, b))
|
||||
// #define KEY_INT(a,b) (s_ ## a = ConfigFile::getKeyInt("ClientAnimation", #a, b))
|
||||
// #define KEY_FLOAT(a,b) (s_ ## a = ConfigFile::getKeyFloat("ClientAnimation", #a, b))
|
||||
|
||||
//===================================================================
|
||||
|
||||
void ConfigSharedDebugLinux::install(void)
|
||||
{
|
||||
KEY_BOOL(useTty, false);
|
||||
KEY_STRING(debugMonitorOutputFilename, "ttySpecifier.txt");
|
||||
KEY_BOOL(logTtySetup, false);
|
||||
|
||||
//-- Handle startup profiler handling here.
|
||||
// @todo this should move into ConfigSharedDebug or be loaded
|
||||
// by Profiler. Profiler can't load this config file option
|
||||
// because the Profiler is installed prior to the config file
|
||||
// system.
|
||||
Profiler::enableProfilerOutput(ConfigFile::getKeyBool("SharedDebugLinux", "reportProfiler", false));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedDebugLinux::getUseTty()
|
||||
{
|
||||
return s_useTty;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
char const *ConfigSharedDebugLinux::getDebugMonitorOutputFilename()
|
||||
{
|
||||
return s_debugMonitorOutputFilename;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedDebugLinux::getLogTtySetup()
|
||||
{
|
||||
return s_logTtySetup;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
@@ -1,29 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedDebugLinux.h
|
||||
// Copyright 2002 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ConfigSharedDebugLinux_H
|
||||
#define INCLUDED_ConfigSharedDebugLinux_H
|
||||
|
||||
//===================================================================
|
||||
|
||||
class ConfigSharedDebugLinux
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
static bool getUseTty();
|
||||
static char const *getDebugMonitorOutputFilename();
|
||||
static bool getLogTtySetup();
|
||||
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,677 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugHelp.cpp
|
||||
// Copyright 2001-2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/DebugHelp.h"
|
||||
#include "sharedSynchronization/Mutex.h"
|
||||
#include <execinfo.h>
|
||||
#include <elf.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stddef.h>
|
||||
// ======================================================================
|
||||
|
||||
class SymbolCache
|
||||
{
|
||||
public:
|
||||
|
||||
struct SymbolInfo
|
||||
{
|
||||
char const *srcLib;
|
||||
char const *srcFile;
|
||||
int srcLine;
|
||||
bool found;
|
||||
};
|
||||
|
||||
static void clear();
|
||||
static SymbolInfo const &lookup(void const *addr);
|
||||
static char const *uniqueString(char const *s);
|
||||
static void *memPoolAllocate(size_t size);
|
||||
static const size_t cms_memPoolMaxBytes = 8*1024*1024;
|
||||
|
||||
private:
|
||||
static size_t ms_memPoolUsed;
|
||||
static char ms_memPool[cms_memPoolMaxBytes];
|
||||
static char *ms_memPoolFreeList;
|
||||
static Mutex ms_memPoolMutex;
|
||||
static SymbolInfo ms_nullSym;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template <class T>
|
||||
class SymbolCacheAllocator
|
||||
{
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T * pointer;
|
||||
typedef T const * const_pointer;
|
||||
typedef T & reference;
|
||||
typedef T const & const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
public:
|
||||
SymbolCacheAllocator() {}
|
||||
template <class U> SymbolCacheAllocator(SymbolCacheAllocator<U> const &) {}
|
||||
template <class U> struct rebind { typedef SymbolCacheAllocator<U> other; };
|
||||
|
||||
pointer allocate(size_type n, const_pointer = 0) { return reinterpret_cast<pointer>(SymbolCache::memPoolAllocate(n*sizeof(value_type))); }
|
||||
void deallocate(const_pointer p, size_type n) {}
|
||||
pointer address(reference x) const { return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
size_type max_size() const { return SymbolCache::cms_memPoolMaxBytes; }
|
||||
void construct(pointer p, value_type const & x) { new(p) value_type(x); }
|
||||
void destroy(pointer p) { p->~value_type(); }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
size_t SymbolCache::ms_memPoolUsed;
|
||||
char SymbolCache::ms_memPool[SymbolCache::cms_memPoolMaxBytes];
|
||||
char *SymbolCache::ms_memPoolFreeList;
|
||||
Mutex SymbolCache::ms_memPoolMutex;
|
||||
SymbolCache::SymbolInfo SymbolCache::ms_nullSym;
|
||||
typedef std::map<void const *, SymbolCache::SymbolInfo, std::less<void const *>, SymbolCacheAllocator<std::pair<void const *, SymbolCache::SymbolInfo> > > SymbolMap;
|
||||
typedef std::vector<char const *, SymbolCacheAllocator<char const *> > UniqueStringVector;
|
||||
static SymbolMap ms_cacheMap;
|
||||
static UniqueStringVector ms_uniqueStringVector;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static Elf32_Shdr const *elfGetObjSectionHeader(void const *objBaseAddr, int sectionIndex)
|
||||
{
|
||||
Elf32_Ehdr const *eh = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr);
|
||||
if (sectionIndex >= 0 && sectionIndex < eh->e_shnum)
|
||||
return reinterpret_cast<Elf32_Shdr const *>(static_cast<char const *>(objBaseAddr)+eh->e_shoff+sectionIndex*eh->e_shentsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static char const *elfGetObjSectionData(void const *objBaseAddr, int sectionIndex)
|
||||
{
|
||||
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
|
||||
if (sh)
|
||||
return reinterpret_cast<char const *>(objBaseAddr)+sh->sh_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static unsigned int elfGetObjSectionSize(void const *objBaseAddr, int sectionIndex)
|
||||
{
|
||||
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
|
||||
if (sh)
|
||||
return sh->sh_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static char const *elfGetObjSectionName(void const *objBaseAddr, int sectionIndex)
|
||||
{
|
||||
Elf32_Ehdr const *eh = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr);
|
||||
char const *sectionStr = elfGetObjSectionData(objBaseAddr, eh->e_shstrndx);
|
||||
if (sectionStr)
|
||||
{
|
||||
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
|
||||
if (sh)
|
||||
return sectionStr+sh->sh_name;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static int elfGetObjSectionByName(void const *objBaseAddr, char const *sectionName)
|
||||
{
|
||||
int n = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr)->e_shnum;
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (!strcmp(elfGetObjSectionName(objBaseAddr, i), sectionName))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline unsigned int dwarfGet(char const *src, u_int8_t &dest)
|
||||
{
|
||||
memcpy(&dest, src, sizeof(u_int8_t));
|
||||
return sizeof(u_int8_t);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline unsigned int dwarfGet(char const *src, u_int16_t &dest)
|
||||
{
|
||||
memcpy(&dest, src, sizeof(u_int16_t));
|
||||
return sizeof(u_int16_t);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline unsigned int dwarfGet(char const *src, u_int32_t &dest)
|
||||
{
|
||||
memcpy(&dest, src, sizeof(u_int32_t));
|
||||
return sizeof(u_int32_t);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class LEB128
|
||||
{
|
||||
public:
|
||||
operator int() const { return value; }
|
||||
int value;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline unsigned int dwarfGet(char const *src, LEB128 &dest)
|
||||
{
|
||||
unsigned int pos = 0;
|
||||
int shift = 7;
|
||||
int byte = ((u_int8_t*)src)[pos++];
|
||||
dest.value = byte;
|
||||
while (byte >= 0x80)
|
||||
{
|
||||
byte = ((u_int8_t *)src)[pos++] ^ 1;
|
||||
dest.value ^= byte << shift;
|
||||
shift += 7;
|
||||
}
|
||||
if (shift < 32 && (byte & 0x40))
|
||||
dest.value |= -(1L<<shift);
|
||||
return pos;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class LEB128u
|
||||
{
|
||||
public:
|
||||
operator unsigned int() const { return value; }
|
||||
unsigned int value;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline unsigned int dwarfGet(char const *src, LEB128u &dest)
|
||||
{
|
||||
unsigned int pos = 0;
|
||||
int shift = 7;
|
||||
unsigned int byte = ((u_int8_t*)src)[pos++];
|
||||
dest.value = byte;
|
||||
while (byte >= 0x80)
|
||||
{
|
||||
byte = ((u_int8_t *)src)[pos++] ^ 1;
|
||||
dest.value ^= byte << shift;
|
||||
shift += 7;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static bool dwarfSearch(char const *dwarfLines, unsigned int linesLength, void const *addr, Dl_info const &info, char const *&retSrcFile, int &retSrcLine)
|
||||
{
|
||||
enum
|
||||
{
|
||||
DW_LNE_end_sequence = 1,
|
||||
DW_LNE_set_address = 2,
|
||||
|
||||
DW_LNS_copy = 1,
|
||||
DW_LNS_advance_pc = 2,
|
||||
DW_LNS_advance_line = 3,
|
||||
DW_LNS_set_file = 4,
|
||||
DW_LNS_set_column = 5,
|
||||
DW_LNS_negate_stmt = 6,
|
||||
DW_LNS_set_basic_block = 7,
|
||||
DW_LNS_const_add_pc = 8,
|
||||
DW_LNS_fixed_advance_pc = 9,
|
||||
};
|
||||
////
|
||||
void const *bestOverAddr = reinterpret_cast<void const *>(0xffffffff);
|
||||
void const *bestUnderAddr = 0;
|
||||
char const *bestUnderSrcFileTable = 0;
|
||||
int bestUnderSrcFileNum = 0;
|
||||
int bestUnderSrcLine = 0;
|
||||
|
||||
unsigned int stmtProgMaxLen = linesLength;
|
||||
u_int32_t stmtProgLen = 0;
|
||||
|
||||
for (unsigned int progBeginOffset = 0; progBeginOffset < linesLength; progBeginOffset += stmtProgLen+4, stmtProgMaxLen -= stmtProgLen+4)
|
||||
{
|
||||
char const *stmtProg = dwarfLines+progBeginOffset;
|
||||
// get program length
|
||||
stmtProg += dwarfGet(stmtProg, stmtProgLen);
|
||||
if (stmtProgLen < 12 || stmtProgLen+4 > stmtProgMaxLen)
|
||||
continue;
|
||||
|
||||
char const *stmtProgEnd = stmtProg+stmtProgLen;
|
||||
stmtProg += 2; // skip version
|
||||
// get prologue length
|
||||
u_int32_t stmtProgPrologueLen; stmtProg += dwarfGet(stmtProg, stmtProgPrologueLen);
|
||||
if (stmtProgPrologueLen+10 > stmtProgMaxLen)
|
||||
continue;
|
||||
|
||||
char const *stmtProgStart = stmtProg;
|
||||
u_int8_t stmtProgMinInstructionLen; stmtProg += dwarfGet(stmtProg, stmtProgMinInstructionLen);
|
||||
if (stmtProgMinInstructionLen == 0)
|
||||
continue;
|
||||
++stmtProg; // skip default_is_stmt
|
||||
int8_t stmtProgLineBase; stmtProg += dwarfGet(stmtProg, *(u_int8_t*)&stmtProgLineBase);
|
||||
u_int8_t stmtProgLineRange; stmtProg += dwarfGet(stmtProg, stmtProgLineRange);
|
||||
if (stmtProgLineRange == 0)
|
||||
continue;
|
||||
u_int8_t stmtProgOpcodeBase; stmtProg += dwarfGet(stmtProg, stmtProgOpcodeBase);
|
||||
u_int8_t const *stmtProgOpcodeLengths = reinterpret_cast<u_int8_t const *>(stmtProg);
|
||||
stmtProg += stmtProgOpcodeBase-1;
|
||||
// include dirs here
|
||||
while (*stmtProg)
|
||||
while (*stmtProg++);
|
||||
char const *stmtProgFilenames = stmtProg;
|
||||
stmtProg = stmtProgStart+stmtProgPrologueLen;
|
||||
|
||||
// run program
|
||||
|
||||
while (stmtProg < stmtProgEnd)
|
||||
{
|
||||
int progFile = 0;
|
||||
int progLine = 1;
|
||||
u_int32_t progAddr = 0;
|
||||
bool done = false;
|
||||
bool valid = false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
u_int8_t opcode = *stmtProg++;
|
||||
if (opcode < stmtProgOpcodeBase)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: // extended
|
||||
{
|
||||
u_int8_t size, extendedOpcode;
|
||||
stmtProg += dwarfGet(stmtProg, size);
|
||||
stmtProg += dwarfGet(stmtProg, extendedOpcode);
|
||||
switch (extendedOpcode)
|
||||
{
|
||||
case DW_LNE_end_sequence:
|
||||
valid = true;
|
||||
done = true;
|
||||
break;
|
||||
case DW_LNE_set_address:
|
||||
stmtProg += dwarfGet(stmtProg, progAddr);
|
||||
break;
|
||||
default: // unimplemented extended opcode, skip parms
|
||||
stmtProg += size-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DW_LNS_advance_pc:
|
||||
{
|
||||
LEB128u incr; stmtProg += dwarfGet(stmtProg, incr);
|
||||
progAddr += incr*stmtProgMinInstructionLen;
|
||||
}
|
||||
break;
|
||||
case DW_LNS_const_add_pc:
|
||||
progAddr += (255-stmtProgOpcodeBase)/stmtProgLineRange*stmtProgMinInstructionLen;
|
||||
break;
|
||||
case DW_LNS_fixed_advance_pc:
|
||||
{
|
||||
u_int16_t incr; stmtProg += dwarfGet(stmtProg, incr);
|
||||
progAddr += incr;
|
||||
}
|
||||
break;
|
||||
case DW_LNS_advance_line:
|
||||
{
|
||||
LEB128 incr; stmtProg += dwarfGet(stmtProg, incr);
|
||||
progLine += incr;
|
||||
}
|
||||
break;
|
||||
case DW_LNS_set_file:
|
||||
{
|
||||
LEB128u fileNum; stmtProg += dwarfGet(stmtProg, fileNum);
|
||||
progFile = fileNum-1;
|
||||
}
|
||||
break;
|
||||
case DW_LNS_copy:
|
||||
valid = true;
|
||||
break;
|
||||
// ignored
|
||||
case DW_LNS_set_column:
|
||||
{
|
||||
LEB128u col; stmtProg += dwarfGet(stmtProg, col);
|
||||
}
|
||||
break;
|
||||
case DW_LNS_negate_stmt:
|
||||
case DW_LNS_set_basic_block:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// unimplemented standard opcode
|
||||
// look up standard opcode length and skip that many LEB128u's
|
||||
LEB128u temp;
|
||||
for (int i = 0; i < stmtProgOpcodeLengths[opcode-1]; ++i)
|
||||
stmtProg += dwarfGet(stmtProg, temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // special opcode
|
||||
{
|
||||
progLine += stmtProgLineBase+(opcode-stmtProgOpcodeBase)%stmtProgLineRange;
|
||||
progAddr += (opcode-stmtProgOpcodeBase)/stmtProgLineRange*stmtProgMinInstructionLen;
|
||||
valid = true;
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
unsigned int addrOffset = 0;
|
||||
if (progAddr < reinterpret_cast<unsigned int>(info.dli_fbase))
|
||||
addrOffset = reinterpret_cast<unsigned int>(info.dli_fbase);
|
||||
const void *testAddr = reinterpret_cast<const void *>(progAddr+addrOffset);
|
||||
if (testAddr >= addr)
|
||||
{
|
||||
if (testAddr < bestOverAddr)
|
||||
bestOverAddr = testAddr;
|
||||
}
|
||||
else if (testAddr > bestUnderAddr)
|
||||
{
|
||||
bestUnderAddr = testAddr;
|
||||
bestUnderSrcFileTable = stmtProgFilenames;
|
||||
bestUnderSrcFileNum = progFile;
|
||||
bestUnderSrcLine = progLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestUnderAddr && bestOverAddr != reinterpret_cast<void const *>(0xffffffff))
|
||||
{
|
||||
char const *srcFile = bestUnderSrcFileTable+1;
|
||||
for (int i = 0; i < bestUnderSrcFileNum; ++i)
|
||||
{
|
||||
while (*srcFile++);
|
||||
srcFile += 3;
|
||||
}
|
||||
retSrcFile = SymbolCache::uniqueString(srcFile);
|
||||
retSrcLine = bestUnderSrcLine;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static bool dwarfFind(void const *addr, Dl_info const &info, char const *& retSrcFile, int &retSrcLine)
|
||||
{
|
||||
bool found = false;
|
||||
int fd = open(info.dli_fname, O_RDONLY);
|
||||
if (fd != -1)
|
||||
{
|
||||
int fileSize = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
void const *mappedAddr = reinterpret_cast<void const *>(mmap(0, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
|
||||
close(fd);
|
||||
if (mappedAddr != MAP_FAILED)
|
||||
{
|
||||
int dwarfLinesIndex = elfGetObjSectionByName(mappedAddr, ".debug_line");
|
||||
if (dwarfLinesIndex != -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
found = dwarfSearch(
|
||||
elfGetObjSectionData(mappedAddr, dwarfLinesIndex),
|
||||
elfGetObjSectionSize(mappedAddr, dwarfLinesIndex),
|
||||
addr,
|
||||
info,
|
||||
retSrcFile,
|
||||
retSrcLine);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
munmap(const_cast<void *>(mappedAddr), fileSize);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
munmap(const_cast<void *>(mappedAddr), fileSize);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
struct Stab
|
||||
{
|
||||
unsigned int n_strx; // index into string table
|
||||
unsigned char n_type; // type of stab entry
|
||||
char n_other;
|
||||
unsigned short n_desc; // for N_SLINE entries, line number
|
||||
unsigned int n_value; // value of symbol
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static bool stabSearch(Stab const *stab, unsigned int stabSize, char const *stabStr, void const *addr, Dl_info const &info, char const *&retSrcFile, int &retSrcLine)
|
||||
{
|
||||
enum
|
||||
{
|
||||
N_UNDF = 0, // undefined
|
||||
N_FUN = 0x24, // function
|
||||
N_SLINE = 0x44, // source line
|
||||
N_SO = 0x64, // source file name
|
||||
N_SOL = 0x84 // local source file name
|
||||
};
|
||||
|
||||
unsigned int stabCount = stabSize/sizeof(Stab);
|
||||
char const *srcFile = "";
|
||||
void const *funcBase = 0;
|
||||
int foundSrcLine = -1;
|
||||
|
||||
for (unsigned int i = 0; i < stabCount; ++i, ++stab)
|
||||
{
|
||||
if (stab->n_type == N_UNDF) // new stabs section, do a recursive search of it
|
||||
{
|
||||
if (stabSearch(stab+1, stab->n_desc*sizeof(Stab), stabStr, addr, info, retSrcFile, retSrcLine))
|
||||
return true;
|
||||
i += stab->n_desc;
|
||||
stab += stab->n_desc;
|
||||
srcFile = "";
|
||||
continue;
|
||||
}
|
||||
else if (stab->n_type == N_SO || stab->n_type == N_SOL) // source or header file specification
|
||||
srcFile = stabStr+stab->n_strx;
|
||||
else if (stab->n_type == N_FUN) // function specification
|
||||
{
|
||||
// This may not be terribly accurate - it's attempting to differentiate between already relocated symbols (main program)
|
||||
// and shared libs, which need to be offset by their file base
|
||||
if (reinterpret_cast<void const *>(stab->n_value) > info.dli_fbase)
|
||||
funcBase = reinterpret_cast<void const *>(stab->n_value);
|
||||
else
|
||||
funcBase = reinterpret_cast<void const *>(reinterpret_cast<unsigned int>(info.dli_fbase)+stab->n_value);
|
||||
foundSrcLine = -1;
|
||||
}
|
||||
else if (stab->n_type == N_SLINE && addr >= funcBase) // source line
|
||||
{
|
||||
if (stab->n_value < reinterpret_cast<unsigned int>(addr)-reinterpret_cast<unsigned int>(funcBase))
|
||||
foundSrcLine = stab->n_desc;
|
||||
else
|
||||
{
|
||||
retSrcLine = foundSrcLine == -1 ? stab->n_desc : foundSrcLine;
|
||||
retSrcFile = SymbolCache::uniqueString(srcFile);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static bool stabsFind(void const *addr, Dl_info const &info, char const *& retSrcFile, int &retSrcLine)
|
||||
{
|
||||
bool found = false;
|
||||
int fd = open(info.dli_fname, O_RDONLY);
|
||||
if (fd != -1)
|
||||
{
|
||||
int fileSize = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
void const *mappedAddr = reinterpret_cast<void const *>(mmap(0, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
|
||||
close(fd);
|
||||
if (mappedAddr != MAP_FAILED)
|
||||
{
|
||||
int stabIndex = elfGetObjSectionByName(mappedAddr, ".stab");
|
||||
int stabStrIndex = elfGetObjSectionByName(mappedAddr, ".stabstr");
|
||||
if (stabIndex != -1 && stabStrIndex != -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
found = stabSearch(
|
||||
reinterpret_cast<Stab const *>(elfGetObjSectionData(mappedAddr, stabIndex)),
|
||||
elfGetObjSectionSize(mappedAddr, stabIndex),
|
||||
elfGetObjSectionData(mappedAddr, stabStrIndex),
|
||||
addr,
|
||||
info,
|
||||
retSrcFile,
|
||||
retSrcLine);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
munmap(const_cast<void *>(mappedAddr), fileSize);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
munmap(const_cast<void *>(mappedAddr), fileSize);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
SymbolCache::SymbolInfo const &SymbolCache::lookup(void const *addr)
|
||||
{
|
||||
SymbolMap::const_iterator i = ms_cacheMap.find(addr);
|
||||
if (i != ms_cacheMap.end())
|
||||
return (*i).second;
|
||||
|
||||
// allow for running out of the fixed memory pool and recover gracefully
|
||||
for (int tries = 0; tries < 2; ++tries)
|
||||
{
|
||||
try
|
||||
{
|
||||
SymbolInfo &symInfo = ms_cacheMap[addr];
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info))
|
||||
{
|
||||
symInfo.srcLib = uniqueString(info.dli_fname);
|
||||
if ( stabsFind(addr, info, symInfo.srcFile, symInfo.srcLine)
|
||||
|| dwarfFind(addr, info, symInfo.srcFile, symInfo.srcLine))
|
||||
symInfo.found = true;
|
||||
}
|
||||
return symInfo;
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
ms_uniqueStringVector.clear();
|
||||
ms_cacheMap.clear();
|
||||
ms_memPoolUsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ms_nullSym;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
char const *SymbolCache::uniqueString(char const *s)
|
||||
{
|
||||
for (UniqueStringVector::const_iterator i = ms_uniqueStringVector.begin(); i != ms_uniqueStringVector.end(); ++i)
|
||||
if (!strcmp(s, *i))
|
||||
return *i;
|
||||
char *newString = static_cast<char *>(memPoolAllocate((strlen(s)+8)&(~7)));
|
||||
strcpy(newString, s);
|
||||
ms_uniqueStringVector.push_back(newString);
|
||||
return newString;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *SymbolCache::memPoolAllocate(size_t size)
|
||||
{
|
||||
ms_memPoolMutex.enter();
|
||||
if (ms_memPoolUsed+size > cms_memPoolMaxBytes)
|
||||
{
|
||||
ms_memPoolMutex.leave();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
void *ret = ms_memPool+ms_memPoolUsed;
|
||||
ms_memPoolUsed += size;
|
||||
ms_memPoolMutex.leave();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool lookupAddressInfo(void const *addr, char *retSrcLib, char *retSrcFile, int &retSrcLine, int stringBufLengths)
|
||||
{
|
||||
SymbolCache::SymbolInfo const &symInfo = SymbolCache::lookup(addr);
|
||||
if (retSrcLib && symInfo.srcLib)
|
||||
{
|
||||
strncpy(retSrcLib, symInfo.srcLib, stringBufLengths);
|
||||
retSrcLib[stringBufLengths-1] = '\0';
|
||||
}
|
||||
if (symInfo.found && retSrcFile)
|
||||
{
|
||||
strncpy(retSrcFile, symInfo.srcFile, stringBufLengths);
|
||||
retSrcFile[stringBufLengths-1] = '\0';
|
||||
}
|
||||
retSrcLine = symInfo.srcLine;
|
||||
return symInfo.found;
|
||||
}
|
||||
|
||||
////
|
||||
// ======================================================================
|
||||
|
||||
void DebugHelp::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugHelp::remove()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool DebugHelp::lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line)
|
||||
{
|
||||
return lookupAddressInfo(reinterpret_cast<void const *>(address), libName, fileName, line, fileNameLength);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack)
|
||||
{
|
||||
for (int i = 0; i < sizeOfCallStack; ++i)
|
||||
callStack[i] = 0;
|
||||
IGNORE_RETURN(backtrace(reinterpret_cast<void **>(callStack), sizeOfCallStack));
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugHelp.h
|
||||
// copyright 2000 Verant Interactive
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef DEBUG_HELP_H
|
||||
#define DEBUG_HELP_H
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
typedef unsigned long uint32;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class DebugHelp
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static void getCallStack(uint32 *callStack, int sizeOfCallStack);
|
||||
static bool lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugMonitor.cpp
|
||||
// Copyright 2002, Sony Online Entertainment.h
|
||||
// All rights reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/DebugMonitor.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include "sharedDebug/ConfigSharedDebugLinux.h"
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
|
||||
#include <curses.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace DebugMonitorNamespace
|
||||
{
|
||||
bool s_installed;
|
||||
SCREEN *s_initialScreen;
|
||||
WINDOW *s_initialWindow;
|
||||
|
||||
FILE *s_ttyOutputFile;
|
||||
FILE *s_ttyInputFile;
|
||||
SCREEN *s_outputScreen;
|
||||
WINDOW *s_outputWindow;
|
||||
}
|
||||
|
||||
using namespace DebugMonitorNamespace;
|
||||
|
||||
// ======================================================================
|
||||
// Install the debug monitor subsystem
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine will first attempt to install the selected debug monitor.
|
||||
|
||||
void DebugMonitor::install(void)
|
||||
{
|
||||
DEBUG_FATAL(s_installed, ("DebugMonitor already installed."));
|
||||
|
||||
//-- Check if user wants to use a TTY for the DebugMonitor.
|
||||
if (!ConfigSharedDebugLinux::getUseTty())
|
||||
{
|
||||
// Do not use the DebugMonitor.
|
||||
DEBUG_REPORT_LOG(ConfigSharedDebugLinux::getLogTtySetup(), ("DebugMonitor: skipping install, ConfigSharedDebugLinux/useTty is false.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Open and retrieve the name of the TTY file for output from the TTY Specification file.
|
||||
char const *const configFilename = ConfigSharedDebugLinux::getDebugMonitorOutputFilename();
|
||||
|
||||
if (!configFilename || (*configFilename == '\0'))
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor(): skipping installation, no debugMonitorOutputFilename specified."));
|
||||
return;
|
||||
}
|
||||
|
||||
char ttyFilename[1024];
|
||||
|
||||
if (configFilename[0] != '@')
|
||||
{
|
||||
// filename is the real output filename (usually a device) for DebugMonitor output.
|
||||
strncpy(ttyFilename, configFilename, sizeof(ttyFilename) - 1);
|
||||
ttyFilename[sizeof(ttyFilename)-1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// filename is actually an indirection filename, the contents of this file contains the real filename.
|
||||
FILE *ttySpecifierFile = fopen(configFilename + 1, "r");
|
||||
if (!ttySpecifierFile)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty specifier file [%s]: [%s].", configFilename + 1, strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the TTY file name.
|
||||
fgets(ttyFilename, sizeof(ttyFilename), ttySpecifierFile);
|
||||
fclose(ttySpecifierFile);
|
||||
}
|
||||
|
||||
// Strip trailing newline from TTY filename.
|
||||
const int filenameLength = strlen(ttyFilename);
|
||||
if (filenameLength > 0)
|
||||
{
|
||||
// chop off trailing newline if present.
|
||||
if (ttyFilename[filenameLength - 1] == '\n')
|
||||
ttyFilename[filenameLength - 1] = '\0';
|
||||
}
|
||||
|
||||
//-- Open the TTY file for output.
|
||||
DEBUG_REPORT_LOG(ConfigSharedDebugLinux::getLogTtySetup(), ("DebugMonitor: opening TTY file [%s] for reading and writing.\n", ttyFilename));
|
||||
FILE *s_ttyOutputFile = fopen(ttyFilename, "w");
|
||||
if (!s_ttyOutputFile)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty file for output [%s]: [%s].", ttyFilename, strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Open the TTY file for input.
|
||||
FILE *s_ttyInputFile = fopen(ttyFilename, "r");
|
||||
if (!s_ttyInputFile)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty file for input [%s]: [%s].", ttyFilename, strerror(errno)));
|
||||
fclose(s_ttyOutputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// NOTE: -TRF- I would not expect this chunk of termios setup
|
||||
// code to be necessary. My expectation is that it should
|
||||
// be handled by the curs_inopts (see man page) options I have
|
||||
// selected below. Alas, these are needed.
|
||||
|
||||
//-- Setup profiler window input mode.
|
||||
const int inputFd = STDIN_FILENO;
|
||||
|
||||
// Get terminal attributes.
|
||||
termios terminalAttributes;
|
||||
if (tcgetattr(inputFd, &terminalAttributes) != 0)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: tcgetattr failed [%s].", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn off line-processing mode. We want a character at a time.
|
||||
terminalAttributes.c_lflag &= ~ICANON;
|
||||
|
||||
// Turn off echo.
|
||||
terminalAttributes.c_lflag &= ~ECHO;
|
||||
|
||||
// Specify that read should return immediately (non-blocking).
|
||||
terminalAttributes.c_cc[VMIN] = 0;
|
||||
terminalAttributes.c_cc[VTIME] = 0;
|
||||
|
||||
// Set terminal attributes.
|
||||
if (tcsetattr(inputFd, TCSAFLUSH, &terminalAttributes) != 0)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: tcsetattr failed [%s].", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-- Create a curses screen to represent the DebugMonitor output tty.
|
||||
// NOTE: for now the curses input is hooked up to the application's
|
||||
// standard input. Later we may want to change that to
|
||||
// handle input from the output terminal, particularly to
|
||||
// handle profiler modifications when the output window
|
||||
// is active.
|
||||
s_outputScreen = newterm(NULL, s_ttyOutputFile, stdin);
|
||||
if (!s_outputScreen)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: newterm() failed [%s].", strerror(errno)));
|
||||
fclose(s_ttyOutputFile);
|
||||
fclose(s_ttyInputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Initialize the curses library.
|
||||
s_initialWindow = initscr();
|
||||
if (!s_initialWindow)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: initscr(): failed [%s].", strerror(errno)));
|
||||
fclose(s_ttyOutputFile);
|
||||
fclose(s_ttyInputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Restore the stdout window to its previous state. We won't use stdout.
|
||||
endwin();
|
||||
|
||||
//-- Set the default terminal to be the output TTY's terminal screen.
|
||||
s_initialScreen = set_term(s_outputScreen);
|
||||
if (!s_initialScreen)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: set_term(): failed [%s].", strerror(errno)));
|
||||
delscreen(s_outputScreen);
|
||||
fclose(s_ttyOutputFile);
|
||||
fclose(s_ttyInputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Create the curses WINDOW at the full size of the TTY.
|
||||
s_outputWindow = newwin(0, 0, 0, 0);
|
||||
if (!s_outputWindow)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: newwin(): failed [%s].", strerror(errno)));
|
||||
delscreen(s_outputScreen);
|
||||
fclose(s_ttyOutputFile);
|
||||
fclose(s_ttyInputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Destroy curses data structures associated with the stdout TTY
|
||||
delwin(s_initialWindow);
|
||||
delscreen(s_initialScreen);
|
||||
|
||||
//-- Additional profiler input setup.
|
||||
// Allow translation of arrow keys.
|
||||
if (keypad(s_outputWindow, true) == ERR)
|
||||
{
|
||||
DEBUG_WARNING(true, ("DebugMonitor: keypad() failed [%s].", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Add the removal routine to the ExitChain.
|
||||
s_installed = true;
|
||||
|
||||
// NOTE: this can't go on the exit chain because the MemoryManager
|
||||
// will write to it way late in processing.
|
||||
//ExitChain::add(remove, "DebugMonitor");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void DebugMonitor::remove(void)
|
||||
{
|
||||
if (!s_installed)
|
||||
{
|
||||
// Exit silently rather than FATAL. There's any number of reasons why
|
||||
// we might not be installed, and the ExitChain does not call remove,
|
||||
// so this should be valid.
|
||||
return;
|
||||
}
|
||||
|
||||
s_installed = false;
|
||||
|
||||
//-- Restore the TTY's state.
|
||||
endwin();
|
||||
|
||||
//-- Delete curses data structures associated with the output terminal.
|
||||
delwin(s_outputWindow);
|
||||
s_outputWindow = 0;
|
||||
|
||||
delscreen(s_outputScreen);
|
||||
s_outputScreen = 0;
|
||||
|
||||
//-- Close file handle to output terminal.
|
||||
fclose(s_ttyOutputFile);
|
||||
s_ttyOutputFile = 0;
|
||||
|
||||
fclose(s_ttyInputFile);
|
||||
s_ttyInputFile = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the debug window's z-order.
|
||||
*/
|
||||
|
||||
void DebugMonitor::setBehindWindow(HWND window)
|
||||
{
|
||||
UNREF(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(void)
|
||||
{
|
||||
//-- Ignore request if DebugMonitor isn't installed.
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
//-- Tell curses to clear the virtual screen. The actual
|
||||
// clear will not take effect until the next showOutput() call
|
||||
// is made.
|
||||
IGNORE_RETURN(wclear(s_outputWindow));
|
||||
|
||||
//-- Goto upper left corner.
|
||||
gotoXY(0, 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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(void)
|
||||
{
|
||||
//-- Ignore request if DebugMonitor isn't installed.
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
//-- I don't see this functionality in curses. Just clear
|
||||
// the entire screen.
|
||||
clearScreen();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//-- Ignore request if DebugMonitor isn't installed.
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
//-- Move the cursor position to the specified location.
|
||||
const int result = wmove(s_outputWindow, y, x);
|
||||
DEBUG_REPORT_LOG(result == ERR, ("DebugMonitor: wmove(%d, %d) failed [%s].\n", y, x, strerror(errno)));
|
||||
UNREF(result);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//-- Ignore request if DebugMonitor isn't installed.
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
const int result = wprintw(s_outputWindow, const_cast<char*>(string));
|
||||
DEBUG_REPORT_LOG(result == ERR, ("WARNING: DebugMonitor: wprintw failed [%s].\n", strerror(errno)));
|
||||
UNREF(result);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
//-- Ignore request if DebugMonitor isn't installed.
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
//-- Tell curses to refresh the output window so that
|
||||
// the virtual curses display is rendered to the real
|
||||
// terminal display.
|
||||
const int result = wrefresh(s_outputWindow);
|
||||
DEBUG_REPORT_LOG(result == ERR, ("WARNING: DebugMonitor: wrefresh failed [%s].\n", strerror(errno)));
|
||||
UNREF(result);
|
||||
|
||||
//-- Handle tty input here. This is somewhat hacky. Unix tty input
|
||||
// and output currently are intimately tied to the profiler. Later
|
||||
// this can be separated out so we can handle multiple TTYs for
|
||||
// multiple purposes, such as for handling a TTY-based popup debug
|
||||
// menu for on-the-fly options changing.
|
||||
const int input = wgetch(s_outputWindow);
|
||||
if (input != ERR)
|
||||
{
|
||||
#if 0
|
||||
DEBUG_REPORT_LOG(true, ("DebugMonitor: received key [index=%d].\n", input));
|
||||
#endif
|
||||
|
||||
//-- Handle input.
|
||||
switch (input)
|
||||
{
|
||||
case '8':
|
||||
case KEY_UP:
|
||||
Profiler::selectionMoveUp();
|
||||
break;
|
||||
|
||||
case '9':
|
||||
case KEY_DOWN:
|
||||
Profiler::selectionMoveDown();
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case 10:
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
Profiler::selectionToggleExpanded();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// DebugMonitor.h
|
||||
// Portions Copyright 1998, Bootprint Entertainment, Inc.
|
||||
// Portions Copyright 2002, Sony Online Entertainment, Inc.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_DebugMonitor_H
|
||||
#define INCLUDED_DebugMonitor_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
class DebugMonitor
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
static void install(void);
|
||||
static void remove(void);
|
||||
|
||||
typedef void* HWND;
|
||||
|
||||
static void setBehindWindow(HWND window);
|
||||
|
||||
static void clearScreen(void);
|
||||
static void clearToCursor(void);
|
||||
|
||||
static void home(void);
|
||||
static void gotoXY(int x, int y);
|
||||
static void print(const char *string);
|
||||
|
||||
static void flushOutput();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
// 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()
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
inline void DebugMonitor::home(void)
|
||||
{
|
||||
gotoXY(0,0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
//=================================================================== //
|
||||
//
|
||||
// PerformanceTimer.cpp
|
||||
// copyright 2000-2004 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedDebug/PerformanceTimer.h"
|
||||
|
||||
//===================================================================
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//===================================================================
|
||||
|
||||
void PerformanceTimer::install()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
PerformanceTimer::PerformanceTimer()
|
||||
{
|
||||
startTime.tv_sec = 0;
|
||||
startTime.tv_usec = 0;
|
||||
stopTime.tv_sec = 0;
|
||||
stopTime.tv_usec = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
PerformanceTimer::~PerformanceTimer()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::start()
|
||||
{
|
||||
int const result = gettimeofday(&startTime, NULL);
|
||||
FATAL(result != 0,("PerformanceTimer::start failed"));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::resume()
|
||||
{
|
||||
long sec = stopTime.tv_sec - startTime.tv_sec;
|
||||
long usec = stopTime.tv_usec - startTime.tv_usec;
|
||||
if(usec < 0)
|
||||
{
|
||||
--sec;
|
||||
usec += 1000000;
|
||||
}
|
||||
|
||||
int const result = gettimeofday(&startTime, NULL);
|
||||
FATAL(result != 0,("PerformanceTimer::resume failed"));
|
||||
|
||||
startTime.tv_sec -= sec;
|
||||
startTime.tv_usec -= usec;
|
||||
if(startTime.tv_usec < 0)
|
||||
{
|
||||
--startTime.tv_sec;
|
||||
startTime.tv_usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void PerformanceTimer::stop()
|
||||
{
|
||||
int result = gettimeofday(&stopTime, NULL);
|
||||
FATAL(result != 0,("PerformanceTimer::start failed"));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
float PerformanceTimer::getElapsedTime() const
|
||||
{
|
||||
long sec = stopTime.tv_sec - startTime.tv_sec;
|
||||
long usec = stopTime.tv_usec - startTime.tv_usec;
|
||||
if(usec < 0)
|
||||
{
|
||||
--sec;
|
||||
usec += 1000000;
|
||||
}
|
||||
return static_cast<float>(sec) +(static_cast<float>(usec) / 1000000.0f);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
float PerformanceTimer::getSplitTime() const
|
||||
{
|
||||
timeval currentTime;
|
||||
|
||||
int const result = gettimeofday(¤tTime, NULL);
|
||||
FATAL(result != 0,("PerformanceTimer::getSplitTime failed"));
|
||||
|
||||
long sec = currentTime.tv_sec - startTime.tv_sec;
|
||||
long usec = currentTime.tv_usec - startTime.tv_usec;
|
||||
if(usec < 0)
|
||||
{
|
||||
--sec;
|
||||
usec += 1000000;
|
||||
}
|
||||
|
||||
return static_cast<float>(sec) +(static_cast<float>(usec) / 1000000.0f);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
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));
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
@@ -1,51 +0,0 @@
|
||||
//=================================================================== //
|
||||
//
|
||||
// PerformanceTimer.h
|
||||
// copyright 2000-2004 Sony Online Entertainment
|
||||
// All Rights Reserved
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#ifndef INCLUDED_PerformaceTimer_H
|
||||
#define INCLUDED_PerformaceTimer_H
|
||||
|
||||
//===================================================================
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
//===================================================================
|
||||
|
||||
class PerformanceTimer
|
||||
{
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
public:
|
||||
|
||||
PerformanceTimer();
|
||||
~PerformanceTimer();
|
||||
|
||||
void start();
|
||||
void resume();
|
||||
void stop();
|
||||
|
||||
float getElapsedTime() const;
|
||||
float getSplitTime() const;
|
||||
void logElapsedTime(const char* string) const;
|
||||
|
||||
private:
|
||||
|
||||
timeval startTime;
|
||||
timeval stopTime;
|
||||
|
||||
private:
|
||||
|
||||
PerformanceTimer(PerformanceTimer const &);
|
||||
PerformanceTimer & operator=(PerformanceTimer const &);
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ProfilerTimer.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedDebug/ProfilerTimer.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void ProfilerTimer::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ProfilerTimer::getTime(Type &time)
|
||||
{
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
time = static_cast<Type>(tv.tv_sec)*static_cast<Type>(1000000)+static_cast<Type>(tv.tv_usec);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ProfilerTimer::getCalibratedTime(Type &time, Type &frequency)
|
||||
{
|
||||
getTime(time);
|
||||
frequency = 1000000;
|
||||
}
|
||||
|
||||
void ProfilerTimer::getFrequency(Type &frequency)
|
||||
{
|
||||
frequency = 1000000;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,29 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ProfilerTimer.h
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ProfilerTimer_H
|
||||
#define INCLUDED_ProfilerTimer_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ProfilerTimer
|
||||
{
|
||||
public:
|
||||
|
||||
typedef uint64 Type;
|
||||
|
||||
public:
|
||||
|
||||
static void install();
|
||||
static void getTime(Type &type);
|
||||
static void getCalibratedTime(Type &time, Type &frequency);
|
||||
static void getFrequency(Type &frequency);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,123 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsFile.cpp
|
||||
// Copyright 2002, Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFile/FirstSharedFile.h"
|
||||
#include "sharedFile/OsFile.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void OsFile::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool OsFile::exists(const char *fileName)
|
||||
{
|
||||
struct stat statBuffer;
|
||||
if (stat(fileName, &statBuffer) != 0)
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(statBuffer.st_mode))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::getFileSize(const char *fileName)
|
||||
{
|
||||
struct stat statBuffer;
|
||||
int fileSize = 0;
|
||||
|
||||
if (stat(fileName, &statBuffer) == 0)
|
||||
{
|
||||
fileSize = static_cast<int>(statBuffer.st_size);
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile *OsFile::open(const char *fileName, bool randomAccess)
|
||||
{
|
||||
UNREF(randomAccess);
|
||||
|
||||
if (!exists(fileName))
|
||||
return 0;
|
||||
|
||||
// attempt to open the file
|
||||
const int handle = ::open(fileName, O_RDONLY);
|
||||
FATAL(handle < 0, ("OsFile::open failed to open file %s, errno=%d, which does exist.", fileName, errno));
|
||||
|
||||
return new OsFile(handle, DuplicateString(fileName));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile::OsFile(int handle, char *fileName)
|
||||
:
|
||||
m_handle(handle),
|
||||
m_length(0),
|
||||
m_offset(0),
|
||||
m_fileName(fileName)
|
||||
{
|
||||
m_length = lseek(m_handle, 0, SEEK_END);
|
||||
lseek(m_handle, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
OsFile::~OsFile()
|
||||
{
|
||||
close(m_handle);
|
||||
delete [] m_fileName;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::length() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void OsFile::seek(int newFilePosition)
|
||||
{
|
||||
if (m_offset != newFilePosition)
|
||||
{
|
||||
const int result = lseek(m_handle, newFilePosition, SEEK_SET);
|
||||
DEBUG_FATAL(result != newFilePosition, ("SetFilePointer failed"));
|
||||
UNREF(result);
|
||||
m_offset = newFilePosition;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int OsFile::read(void *destinationBuffer, int numberOfBytes)
|
||||
{
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = ::read(m_handle, destinationBuffer, numberOfBytes);
|
||||
DEBUG_FATAL((result < 0 && errno != EAGAIN), ("Read failed for %s: %d %d %s", m_fileName, result, errno, strerror(errno)));
|
||||
} while (result < 0);
|
||||
|
||||
m_offset += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,51 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// 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 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(int handle, char *fileName);
|
||||
|
||||
OsFile();
|
||||
OsFile(const OsFile &);
|
||||
OsFile &operator =(const OsFile &);
|
||||
|
||||
private:
|
||||
|
||||
int m_handle;
|
||||
int m_length;
|
||||
int m_offset;
|
||||
char *m_fileName;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ByteOrder.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef BYTE_ORDER_H
|
||||
#define BYTE_ORDER_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "../../../../../../engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstPlatform.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedFoundation.cpp
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const int c_defaultFatalCallStackDepth = 32;
|
||||
const int c_defaultWarningCallStackDepth = 8;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace ConfigSharedFoundationNamespace
|
||||
{
|
||||
real ms_frameRateLimit;
|
||||
real ms_minFrameRate;
|
||||
bool ms_noExceptionHandling;
|
||||
|
||||
bool ms_fpuExceptionPrecision;
|
||||
bool ms_fpuExceptionUnderflow;
|
||||
bool ms_fpuExceptionOverflow;
|
||||
bool ms_fpuExceptionZeroDivide;
|
||||
bool ms_fpuExceptionDenormal;
|
||||
bool ms_fpuExceptionInvalid;
|
||||
|
||||
bool ms_demoMode;
|
||||
|
||||
bool ms_useRemoteDebug;
|
||||
int ms_defaultRemoteDebugPort;
|
||||
|
||||
bool ms_profilerExpandAllBranches = true;
|
||||
|
||||
bool ms_memoryManagerReportAllocations;
|
||||
bool ms_memoryManagerReportOnOutOfMemory;
|
||||
|
||||
bool ms_useMemoryBlockManager;
|
||||
bool ms_memoryBlockManagerDebugDumpOnRemove;
|
||||
|
||||
int ms_fatalCallStackDepth;
|
||||
int ms_warningCallStackDepth;
|
||||
bool ms_lookUpCallStackNames;
|
||||
|
||||
bool ms_alwaysCanSeeWorldCell;
|
||||
|
||||
bool ms_verboseWarnings;
|
||||
|
||||
float ms_debugReportLongFrameTime;
|
||||
}
|
||||
|
||||
using namespace ConfigSharedFoundationNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#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))
|
||||
|
||||
// ======================================================================
|
||||
// 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, false);
|
||||
|
||||
KEY_FLOAT(frameRateLimit, defaults.frameRateLimit);
|
||||
KEY_FLOAT(minFrameRate, 0.0f);
|
||||
|
||||
KEY_BOOL(useRemoteDebug, false);
|
||||
KEY_INT(defaultRemoteDebugPort, 4445);
|
||||
|
||||
KEY_BOOL(profilerExpandAllBranches, true);
|
||||
KEY_BOOL(memoryManagerReportAllocations, true);
|
||||
KEY_BOOL(memoryManagerReportOnOutOfMemory, true);
|
||||
|
||||
KEY_BOOL(useMemoryBlockManager, true);
|
||||
KEY_BOOL(memoryBlockManagerDebugDumpOnRemove, false);
|
||||
|
||||
KEY_INT(fatalCallStackDepth, c_defaultFatalCallStackDepth);
|
||||
KEY_INT(warningCallStackDepth, c_defaultWarningCallStackDepth);
|
||||
KEY_BOOL(lookUpCallStackNames, true);
|
||||
|
||||
KEY_BOOL(alwaysCanSeeWorldCell, false);
|
||||
|
||||
KEY_BOOL(verboseWarnings, false);
|
||||
|
||||
KEY_FLOAT(debugReportLongFrameTime, 0.25f);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* Return the frame rate limit value for the game.
|
||||
*
|
||||
* @return The initial frame rate limiter value
|
||||
*/
|
||||
|
||||
real ConfigSharedFoundation::getFrameRateLimit(void)
|
||||
{
|
||||
return ms_frameRateLimit;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the minimum frame rate limit value for the game. Frame that take longer
|
||||
* will be set to the minimum and a message will be logged.
|
||||
*
|
||||
* @return The minimum frame rate value
|
||||
*/
|
||||
|
||||
real ConfigSharedFoundation::getMinFrameRate(void)
|
||||
{
|
||||
return ms_minFrameRate;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return whether to run with exception handling enabled.
|
||||
*
|
||||
* @return True to run without exception handling
|
||||
*/
|
||||
|
||||
bool ConfigSharedFoundation::getNoExceptionHandling(void)
|
||||
{
|
||||
return ms_noExceptionHandling;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionPrecision(void)
|
||||
{
|
||||
return ms_fpuExceptionPrecision;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionUnderflow(void)
|
||||
{
|
||||
return ms_fpuExceptionUnderflow;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionOverflow(void)
|
||||
{
|
||||
return ms_fpuExceptionOverflow;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionZeroDivide(void)
|
||||
{
|
||||
return ms_fpuExceptionZeroDivide;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionDenormal(void)
|
||||
{
|
||||
return ms_fpuExceptionDenormal;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getFpuExceptionInvalid(void)
|
||||
{
|
||||
return ms_fpuExceptionInvalid;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getFatalCallStackDepth()
|
||||
{
|
||||
return ms_fatalCallStackDepth;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getWarningCallStackDepth()
|
||||
{
|
||||
return ms_warningCallStackDepth;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getProfilerExpandAllBranches()
|
||||
{
|
||||
return ms_profilerExpandAllBranches;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getUseRemoteDebug()
|
||||
{
|
||||
return ms_useRemoteDebug;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedFoundation::getDefaultRemoteDebugPort()
|
||||
{
|
||||
return ms_defaultRemoteDebugPort;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getDemoMode()
|
||||
{
|
||||
return ms_demoMode;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getAlwaysCanSeeWorldCell()
|
||||
{
|
||||
return ms_alwaysCanSeeWorldCell;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getLookUpCallStackNames()
|
||||
{
|
||||
return ms_lookUpCallStackNames;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryManagerReportAllocations()
|
||||
{
|
||||
return ms_memoryManagerReportAllocations;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory()
|
||||
{
|
||||
return ms_memoryManagerReportOnOutOfMemory;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getUseMemoryBlockManager()
|
||||
{
|
||||
return ms_useMemoryBlockManager;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove ()
|
||||
{
|
||||
return ms_memoryBlockManagerDebugDumpOnRemove;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedFoundation::getVerboseWarnings()
|
||||
{
|
||||
return ms_verboseWarnings;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float ConfigSharedFoundation::getDebugReportLongFrameTime()
|
||||
{
|
||||
return ms_debugReportLongFrameTime;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,64 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConfigSharedFoundation.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ConfigSharedFoundation_H
|
||||
#define INCLUDED_ConfigSharedFoundation_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ConfigSharedFoundation
|
||||
{
|
||||
public:
|
||||
|
||||
struct Defaults
|
||||
{
|
||||
real frameRateLimit;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void install (const Defaults &defaults);
|
||||
|
||||
static real getFrameRateLimit();
|
||||
static real getMinFrameRate();
|
||||
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 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 bool getAlwaysCanSeeWorldCell();
|
||||
|
||||
static bool getVerboseWarnings();
|
||||
|
||||
static float getDebugReportLongFrameTime();
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FirstPlatform.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef FIRST_PLATFORM_H
|
||||
#define FIRST_PLATFORM_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#define DLLEXPORT
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// C4514 unreferenced inline function has been removed
|
||||
// C4710 inline function not expanded
|
||||
// C4291 no matching operator delete found; memory will not be freed if initialization throws an exception
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "../../../../../../engine/shared/library/sharedFoundation/include/public/sharedFoundation/PlatformGlue.h"
|
||||
#include "sharedMemoryManager/MemoryManager.h"
|
||||
|
||||
|
||||
// ======================================================================
|
||||
|
||||
template <class T>
|
||||
inline int ComGetReferenceCount(T *t)
|
||||
{
|
||||
t->AddRef();
|
||||
return t->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#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)))
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,266 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FloatingPointUnit.cpp
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1999 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/FloatingPointUnit.h"
|
||||
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
int FloatingPointUnit::updateNumber;
|
||||
WORD 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", updateNumber, static_cast<int>(currentStatus), static_cast<int>(status)));
|
||||
setControlWord(status);
|
||||
}
|
||||
|
||||
++updateNumber;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
WORD FloatingPointUnit::getControlWord(void)
|
||||
{
|
||||
//TODO wtf is this asm statement?
|
||||
#if 0
|
||||
WORD controlWord = 0;
|
||||
__asm fnstcw controlWord;
|
||||
return controlWord;
|
||||
#else
|
||||
return status;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FloatingPointUnit::setControlWord(WORD controlWord)
|
||||
{
|
||||
//TODO see above?
|
||||
|
||||
UNREF(controlWord);
|
||||
#if 0
|
||||
__asm fldcw controlWord;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,102 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// FloatingPointUnit.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1999 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef FLOATING_POINT_UNIT_H
|
||||
#define FLOATING_POINT_UNIT_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class FloatingPointUnit
|
||||
{
|
||||
public:
|
||||
|
||||
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 exception)
|
||||
{
|
||||
DEBUG_FATAL(static_cast<int>(exception) < 0 || static_cast<int>(exception) >= static_cast<int>(E_max), ("exception out of range")); //lint !e568 // non-negative quantity is never less than 0
|
||||
return exceptionEnabled[exception];
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,468 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Os.cpp
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
#include "sharedDebug/DebugMonitor.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/FloatingPointUnit.h"
|
||||
#include "sharedIoWin/IoWinManager.h"
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
bool Os::installed;
|
||||
bool Os::runInBackground;
|
||||
int Os::numberOfUpdates;
|
||||
int Os::menuValue;
|
||||
bool Os::paused;
|
||||
bool Os::wasPaused;
|
||||
bool Os::gameOver;
|
||||
bool Os::shouldReturnFromAbort;
|
||||
char Os::programName[PROGRAM_NAME_SIZE];
|
||||
char *Os::shortProgramName;
|
||||
pthread_t Os::mainThreadId;
|
||||
bool Os::threadDied;
|
||||
|
||||
bool Os::isMp;
|
||||
int Os::processorCount;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
namespace OsNamespace
|
||||
{
|
||||
class UncatchableException
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Install the Os subsystem for non-games.
|
||||
*
|
||||
* This routine is supported for all platforms, although different platforms may
|
||||
* require different arguments to this routine.
|
||||
*
|
||||
* This routine will add Os::remove to the ExitChain.
|
||||
*
|
||||
* @see Os::remove()
|
||||
*/
|
||||
|
||||
void Os::install(void)
|
||||
{
|
||||
installCommon();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* This routine will remove the Os subsystem.
|
||||
*
|
||||
* This routine should not be called directly. It will be called from the ExitChain.
|
||||
*
|
||||
* @see Os::install()
|
||||
*/
|
||||
|
||||
void Os::remove(void)
|
||||
{
|
||||
DEBUG_FATAL(!installed, ("not installed"));
|
||||
installed = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Os::installCommon(void)
|
||||
{
|
||||
DEBUG_FATAL(installed, ("already installed"));
|
||||
|
||||
ExitChain::add(Os::remove, "Os::remove", 0, true);
|
||||
|
||||
#if 0 //TODO For now we won't screw with the priority of the process
|
||||
HANDLE threadHandle = GetCurrentThread();
|
||||
DEBUG_FATAL(!SetThreadPriority(threadHandle, THREAD_PRIORITY_ABOVE_NORMAL), ("Failed to set game thread priority"));
|
||||
#endif
|
||||
|
||||
numberOfUpdates = 0;
|
||||
mainThreadId = pthread_self();
|
||||
|
||||
// get the name of the executable
|
||||
//Can't find UNIX call for this: DWORD result = GetModuleFileName(NULL, programName, sizeof(programName));
|
||||
strcpy(programName, "TempName");
|
||||
DWORD result = 1;
|
||||
|
||||
|
||||
FATAL(result == 0, ("GetModuleFileName failed"));
|
||||
|
||||
// get the file name without the path
|
||||
shortProgramName = strrchr(programName, '\\');
|
||||
if (shortProgramName)
|
||||
++shortProgramName;
|
||||
else
|
||||
shortProgramName = programName;
|
||||
|
||||
// determine the number of processors by parsing /proc/cpuinfo
|
||||
processorCount = 1;
|
||||
FILE * f = fopen("/proc/cpuinfo", "r");
|
||||
if (f)
|
||||
{
|
||||
char buffer[512];
|
||||
while (!feof(f))
|
||||
{
|
||||
fgets(buffer, 512, f);
|
||||
if (strncmp(buffer, "processor\t: ", 12)==0)
|
||||
{
|
||||
processorCount = atoi(buffer+12)+1;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
isMp = processorCount > 1;
|
||||
|
||||
// switch into single-precision floating point mode
|
||||
FloatingPointUnit::install();
|
||||
|
||||
installed = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Os::isMainThread(void)
|
||||
{
|
||||
// if the Os class hasn't been installed, then assume we are the main thread.
|
||||
// otherwise, check to see if our thread id is the main thread id
|
||||
return !installed || (pthread_self() == mainThreadId);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Terminate the application because of an error condition.
|
||||
*
|
||||
* This routine is supported for all platforms.
|
||||
*
|
||||
* This routine should not be called directly. The engine and game should use the
|
||||
* FATAL macro to terminate the application because of an error.
|
||||
*
|
||||
* Calling Os::returnFromAbort() will cause the routine to do nothing but return
|
||||
* immediately.
|
||||
*
|
||||
* @see Os::returnFromAbort(), FATAL()
|
||||
*/
|
||||
#include <signal.h>
|
||||
void Os::abort(void)
|
||||
{
|
||||
if (!isMainThread())
|
||||
{
|
||||
threadDied = true;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
if (!shouldReturnFromAbort)
|
||||
{
|
||||
// let the C runtime deal with the abnormal termination
|
||||
int * dummy = NULL;
|
||||
int forceCrash = *dummy;
|
||||
UNREF(forceCrash);
|
||||
for (;;)
|
||||
{
|
||||
// One of these should work:
|
||||
pthread_kill(pthread_self(), SIGSEGV);
|
||||
::kill(0,SIGSEGV);
|
||||
::abort();
|
||||
OsNamespace::UncatchableException ex;
|
||||
throw ex;
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
/**
|
||||
* Create the specified directory and all of it's parents.
|
||||
* @param directory the path to a directory
|
||||
* @return always true currently
|
||||
*/
|
||||
|
||||
bool Os::createDirectories (const char *directory)
|
||||
{
|
||||
//-- construct list of subdirectories all the way down to root
|
||||
std::stack<std::string> directoryStack;
|
||||
|
||||
std::string currentDirectory = directory;
|
||||
|
||||
static const char path_seps [] = { '\\', '/', 0 };
|
||||
|
||||
// build the stack
|
||||
while (!currentDirectory.empty())
|
||||
{
|
||||
// remove trailing backslash
|
||||
if (currentDirectory[currentDirectory.size()-1] == '\\' || currentDirectory[currentDirectory.size()-1] == '/')
|
||||
IGNORE_RETURN(currentDirectory.erase(currentDirectory.size()-1));
|
||||
|
||||
if (currentDirectory[currentDirectory.size()-1] == ':')
|
||||
{
|
||||
// we've hit something like c:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!currentDirectory.empty())
|
||||
directoryStack.push(currentDirectory);
|
||||
|
||||
// now strip off current directory
|
||||
size_t previousDirIndex = currentDirectory.find_last_of (path_seps);
|
||||
if (previousDirIndex == currentDirectory.npos)
|
||||
break;
|
||||
else
|
||||
IGNORE_RETURN(currentDirectory.erase(previousDirIndex));
|
||||
}
|
||||
|
||||
//-- build all directories specified by the initial directory
|
||||
while (!directoryStack.empty())
|
||||
{
|
||||
// get the directory
|
||||
currentDirectory = directoryStack.top();
|
||||
directoryStack.pop();
|
||||
|
||||
// try to create it (don't pass any security attributes)
|
||||
IGNORE_RETURN (mkdir (currentDirectory.c_str(), 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Write out a file.
|
||||
*
|
||||
* The file name and where the file is written is system-dependent.
|
||||
*
|
||||
* @param fileName Name of the file to write
|
||||
* @param data Data buffer to write to the file
|
||||
*/
|
||||
|
||||
bool Os::writeFile(const char *fileName, const void *data, int length) // Length of the data bufferto write
|
||||
{
|
||||
BOOL result;
|
||||
HANDLE handle;
|
||||
DWORD written;
|
||||
|
||||
// open the file for writing
|
||||
handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
// check if it was opened
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
// attempt to write the data
|
||||
result = WriteFile(handle, data, static_cast<DWORD>(length), &written, NULL);
|
||||
|
||||
// make sure the data was written okay
|
||||
if (!result || written != static_cast<DWORD>(length))
|
||||
{
|
||||
static_cast<void>(CloseHandle(handle));
|
||||
return false;
|
||||
}
|
||||
|
||||
// close the file
|
||||
result = CloseHandle(handle);
|
||||
|
||||
// make sure the close was sucessful
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Update the Os subsystem.
|
||||
*
|
||||
* This routine is supported for all platforms.
|
||||
*
|
||||
* For the Win* platforms, this routine will process the windows message pump.
|
||||
*/
|
||||
|
||||
bool Os::update(void)
|
||||
{
|
||||
static int ppid = getppid();
|
||||
|
||||
FloatingPointUnit::update();
|
||||
|
||||
++numberOfUpdates;
|
||||
|
||||
#if 0
|
||||
#ifdef _DEBUG
|
||||
|
||||
if (DEBUG_FLAG_PLATFORM(validateHeap))
|
||||
{
|
||||
PROFILER_START("validate heap");
|
||||
MemoryManager::validate();
|
||||
PROFILER_STOP("validate heap");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Clock::update();
|
||||
|
||||
wasPaused = false;
|
||||
|
||||
// if our parent's pid has changed, we tell our caller it should exit
|
||||
if (getppid() != ppid)
|
||||
{
|
||||
WARNING(true, ("Parent process exited!"));
|
||||
// reset the parent process id, so we don't keep spamming warnings for processes that don't exit because of this
|
||||
ppid = getppid();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Formats a message error using GetLastError() and FormatMessge().
|
||||
*
|
||||
* The buffer returned from this function is dynamically allocated to prevent
|
||||
* issues with this routine being called from multiple threads. The caller
|
||||
* must delete the buffer when it is done.
|
||||
*
|
||||
* @return A dynamically allocated buffer containing the error message
|
||||
*/
|
||||
|
||||
char *Os::getLastError(void)
|
||||
{
|
||||
return DuplicateString(strerror(errno));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Os::getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize)
|
||||
{
|
||||
// realpath sucks and could cause a buffer overrun. however, it's better than writing it ourselves for now.
|
||||
char *result = realpath(relativePath, absolutePath);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
FATAL(istrlen(absolutePath)+1 > absolutePathBufferSize, ("buffer overrun"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the actual system time, in seconds since the epoch.
|
||||
*
|
||||
* Do not use this for most game systems, since it does not take into account
|
||||
* clock sku, game loop times, etc.
|
||||
*/
|
||||
time_t Os::getRealSystemTime(void)
|
||||
{
|
||||
return time(0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Convert a time in seconds since the epoch to GMT.
|
||||
*
|
||||
*/
|
||||
|
||||
void Os::convertTimeToGMT(const time_t &time, tm &zulu)
|
||||
{
|
||||
zulu=*gmtime(&time); // gmtime uses a single static tm structure. Yuck!
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Convert a tm structure to the time in seconds since the epoch.
|
||||
*
|
||||
*/
|
||||
|
||||
time_t Os::convertGMTToTime(const tm &zulu)
|
||||
{
|
||||
return mktime(const_cast<tm*>(&zulu));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get a unique identifier for this thread.
|
||||
*
|
||||
* @return A unique identifier for this thread.
|
||||
*/
|
||||
|
||||
Os::ThreadId Os::getThreadId()
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Assign the given thread a reasonable name (only works for MSDev 6.0 debugger)
|
||||
* Since this is Linux-specific, make sure this fuction does nothing
|
||||
*
|
||||
*/
|
||||
|
||||
void Os::setThreadName(DWORD threadID, const char* threadName)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Cause the current thread to sleep for a period of time. If the period is
|
||||
* zero, the current thread yields it's timeslice.
|
||||
*/
|
||||
|
||||
void Os::sleep(int ms)
|
||||
{
|
||||
if (ms == 0)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
usleep(ms * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Copy text to the system clipboard.
|
||||
*
|
||||
* This routine can be used if the application wants to make some data easily available for pasting (like crash call stacks).
|
||||
*/
|
||||
|
||||
bool Os::copyTextToClipboard(const char *text)
|
||||
{
|
||||
UNREF(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Os::OsPID_t Os::getProcessId()
|
||||
{
|
||||
return getpid();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Os::setProgramName(const char * name)
|
||||
{
|
||||
strncpy(programName, name, Os::PROGRAM_NAME_SIZE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Os::isFocused()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -1,264 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Os.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef OS_H
|
||||
#define OS_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
struct DebugMenuEntry;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Os
|
||||
{
|
||||
public:
|
||||
|
||||
typedef pthread_t ThreadId;
|
||||
typedef pid_t OsPID_t;
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_PATH_LENGTH = 512
|
||||
};
|
||||
|
||||
typedef void (*QueueCharacterHookFunction)(int keyboard, int character);
|
||||
typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y);
|
||||
typedef void (*QueueKeyDownHookFunction)(int keyboard, int character);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Os(void);
|
||||
Os(const Os &);
|
||||
Os &operator =(const Os &);
|
||||
|
||||
enum
|
||||
{
|
||||
PROGRAM_NAME_SIZE = 512
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static void remove(void);
|
||||
|
||||
static void installCommon(void);
|
||||
|
||||
private:
|
||||
|
||||
static bool installed;
|
||||
static bool runInBackground;
|
||||
static int numberOfUpdates;
|
||||
static int menuValue;
|
||||
static DebugMenuEntry *debugMenuGame;
|
||||
static bool paused;
|
||||
static bool wasPaused;
|
||||
static bool gameOver;
|
||||
static bool shouldReturnFromAbort;
|
||||
static bool wantPopupDebugMenu;
|
||||
static char programName[PROGRAM_NAME_SIZE];
|
||||
static char *shortProgramName;
|
||||
static pthread_t mainThreadId;
|
||||
static bool threadDied;
|
||||
static bool isMp;
|
||||
static int processorCount;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
static void install(void);
|
||||
|
||||
static bool isGameOver(void);
|
||||
static bool isMainThread(void);
|
||||
static bool wasApplicationPaused(void);
|
||||
|
||||
static bool update(void);
|
||||
|
||||
static void returnFromAbort(void);
|
||||
static void abort(void);
|
||||
|
||||
static void requestPopupDebugMenu();
|
||||
|
||||
static bool createDirectories (const char *dirname);
|
||||
|
||||
static bool writeFile(const char *fileName, const void *data, int length);
|
||||
|
||||
static int getNumberOfUpdates(void);
|
||||
|
||||
static char *getLastError(void);
|
||||
|
||||
static void setThreadName(DWORD threadID, const char* name);
|
||||
static ThreadId getThreadId();
|
||||
|
||||
static const char *getProgramName(void);
|
||||
static const char *getShortProgramName(void);
|
||||
static void setProgramName(const char * name);
|
||||
|
||||
static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize);
|
||||
|
||||
static void sleep(int ms);
|
||||
|
||||
static time_t getRealSystemTime(void);
|
||||
static void convertTimeToGMT(const time_t &time, tm &zulu);
|
||||
static time_t convertGMTToTime(const tm &zulu);
|
||||
|
||||
static bool isMultiprocessor();
|
||||
static int getProcessorCount();
|
||||
|
||||
static bool copyTextToClipboard(const char *text);
|
||||
|
||||
static bool wasFocusLost();
|
||||
static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction);
|
||||
static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction);
|
||||
static OsPID_t getProcessId();
|
||||
static bool isFocused();
|
||||
|
||||
static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the full name of the running executable.
|
||||
*
|
||||
* The program name will include the path as well.
|
||||
*
|
||||
* @return The full name of the running executable
|
||||
* @see Os::getShortProgramName()
|
||||
*/
|
||||
|
||||
inline const char *Os::getProgramName(void)
|
||||
{
|
||||
return programName;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the short name of the running executable.
|
||||
*
|
||||
* The program name will not include the path, but will just be the file name.
|
||||
*
|
||||
* @return The short name of the running executable
|
||||
* @see Os::getProgramName()
|
||||
*/
|
||||
|
||||
inline const char *Os::getShortProgramName(void)
|
||||
{
|
||||
return shortProgramName;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Cause Os::abort() to return instead of abort the process.
|
||||
*
|
||||
* This routine should not be called directly by users.
|
||||
*
|
||||
* This routine is provided so that structured exception handling can catch
|
||||
* an exception, call Fatal to run the ExitChain, and rethrow the exception
|
||||
* so that the debugger will catch it.
|
||||
*/
|
||||
|
||||
inline void Os::returnFromAbort(void)
|
||||
{
|
||||
shouldReturnFromAbort = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Check if the Os knows the game needs to shut down.
|
||||
*
|
||||
* The Os can decide that the game need to end for a number of reasons,
|
||||
* including closing the application or shutting the machine down.
|
||||
*
|
||||
* @return True if the game should quit, otherwise false
|
||||
*/
|
||||
|
||||
inline bool Os::isGameOver(void)
|
||||
{
|
||||
return gameOver;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the number of updates that the have occurred.
|
||||
*
|
||||
* @return This value is updated during the Os::update() routine.
|
||||
*/
|
||||
|
||||
inline int Os::getNumberOfUpdates(void)
|
||||
{
|
||||
return numberOfUpdates;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Indicate whether or not the application was paused.
|
||||
*
|
||||
* @return True if the application was in the background (paused), otherwise false
|
||||
*/
|
||||
|
||||
inline bool Os::wasApplicationPaused(void)
|
||||
{
|
||||
return wasPaused;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return a flag indicating whether we are running a multiprocessor machine or not.
|
||||
*
|
||||
* @return True if the machine has more than one processor, false if not.
|
||||
*/
|
||||
|
||||
inline bool Os::isMultiprocessor(void)
|
||||
{
|
||||
return isMp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the number of processors.
|
||||
*
|
||||
* @return The number of processors in the machine.
|
||||
*/
|
||||
|
||||
inline int Os::getProcessorCount(void)
|
||||
{
|
||||
return processorCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool Os::wasFocusLost()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Os::setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Os::setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Os::setQueueKeyDownHookFunction(QueueKeyDownHookFunction)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@@ -1,161 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PerThreadData.cpp
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/PerThreadData.h"
|
||||
|
||||
#include "sharedSynchronization/Gate.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
pthread_key_t PerThreadData::slot;
|
||||
bool PerThreadData::slotCreated=false;
|
||||
|
||||
// ======================================================================
|
||||
// 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(void)
|
||||
{
|
||||
if (pthread_key_create(&slot, 0)!=0)
|
||||
{
|
||||
FATAL(true, ("pthread_key_create failed"));
|
||||
}
|
||||
slotCreated=true;
|
||||
|
||||
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(void)
|
||||
{
|
||||
threadRemove();
|
||||
|
||||
if (pthread_key_delete(slot)!=0)
|
||||
{
|
||||
FATAL(true, ("pthread_key_delete failed"));
|
||||
}
|
||||
|
||||
slotCreated=false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
PerThreadData::Data *PerThreadData::getData(bool allowReturnNull)
|
||||
{
|
||||
UNREF(allowReturnNull);
|
||||
|
||||
if (!slotCreated)
|
||||
{
|
||||
DEBUG_FATAL(true && !allowReturnNull, ("not installed"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Data * const data = reinterpret_cast<Data *>(pthread_getspecific(slot));
|
||||
DEBUG_FATAL(!data && !allowReturnNull, ("not installed for this thread"));
|
||||
return data;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* 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(!slotCreated, ("not installed"));
|
||||
|
||||
// only check for already-set data if this is supposed to be a new thread
|
||||
DEBUG_FATAL(isNewThread && pthread_getspecific(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->readGate = new Gate(false);
|
||||
|
||||
// set the data into the thread slot
|
||||
const BOOL result = pthread_setspecific(slot, data);
|
||||
UNREF(result);
|
||||
DEBUG_FATAL(result, ("pthread_setspecific failed")); //NB: unlike Windows, returns 0 on success.
|
||||
} //lint !e429 // Warning -- Custodial pointer 'data' has not been freed or returned) // stored int thread-local-storage
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Destroythe 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(void)
|
||||
{
|
||||
DEBUG_FATAL(!slotCreated, ("not installed"));
|
||||
DEBUG_FATAL(!pthread_getspecific(slot), ("thread not installed"));
|
||||
|
||||
// get the data
|
||||
Data *data = getData();
|
||||
|
||||
//close the event used for file streaming reads
|
||||
delete data->readGate;
|
||||
data->readGate = NULL;
|
||||
|
||||
// wipe the data in the thread slot
|
||||
const BOOL result2 = pthread_setspecific(slot, NULL);
|
||||
UNREF(result2);
|
||||
DEBUG_FATAL(result2, ("TlsSetValue failed")); //NB: unlike Windows, returns 0 on success.
|
||||
|
||||
// free the memory
|
||||
delete data;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,232 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// PerThreadData.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef PER_THREAD_DATA_H
|
||||
#define PER_THREAD_DATA_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "../../../../../../engine/shared/library/sharedFoundation/include/public/sharedFoundation/ExitChain.h"
|
||||
|
||||
class Gate;
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
private:
|
||||
|
||||
struct Data
|
||||
{
|
||||
bool exitChainRunning;
|
||||
bool exitChainFataling;
|
||||
ExitChain::Entry *exitChainFirstEntry;
|
||||
|
||||
int debugPrintFlags;
|
||||
|
||||
Gate *readGate;
|
||||
};
|
||||
|
||||
static pthread_key_t slot;
|
||||
static bool slotCreated;
|
||||
|
||||
private:
|
||||
|
||||
static Data *getData(bool allowReturnNull=false);
|
||||
|
||||
private:
|
||||
|
||||
PerThreadData(void);
|
||||
PerThreadData(const PerThreadData &);
|
||||
PerThreadData &operator =(const 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);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
|
||||
inline bool PerThreadData::isThreadInstalled(void)
|
||||
{
|
||||
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()
|
||||
*/
|
||||
|
||||
inline bool PerThreadData::getExitChainRunning(void)
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
inline 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()
|
||||
*/
|
||||
|
||||
inline bool PerThreadData::getExitChainFataling(void)
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
inline 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()
|
||||
*/
|
||||
|
||||
inline ExitChain::Entry *PerThreadData::getExitChainFirstEntry(void)
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
inline 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
|
||||
*/
|
||||
|
||||
inline int PerThreadData::getDebugPrintFlags(void)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
inline void PerThreadData::setDebugPrintFlags(int newValue)
|
||||
{
|
||||
getData()->debugPrintFlags = newValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline Gate *PerThreadData::getFileStreamerReadGate(void)
|
||||
{
|
||||
return getData()->readGate;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,273 +0,0 @@
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/PlatformGlue.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
real abs(real x)
|
||||
{
|
||||
return fabs(x);
|
||||
}
|
||||
|
||||
int _stricmp(const char* string1, const char* string2)
|
||||
{
|
||||
int first, second;
|
||||
|
||||
do
|
||||
{
|
||||
first = toupper(*string1);
|
||||
second = toupper(*string2);
|
||||
string1++;
|
||||
string2++;
|
||||
} while (first && first==second);
|
||||
|
||||
return (first - second);
|
||||
}
|
||||
|
||||
char* _itoa(int value, char* stringOut, int radix)
|
||||
{
|
||||
DEBUG_FATAL((radix != 10), ("itoa only supprts base 10"));
|
||||
sprintf(stringOut, "%d", value);
|
||||
return stringOut;
|
||||
}
|
||||
|
||||
bool QueryPerformanceCounter(__int64* time)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
*time = static_cast<LARGE_INTEGER>(tv.tv_sec);
|
||||
*time = (*time * 1000000) + static_cast<LARGE_INTEGER>(tv.tv_usec);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool QueryPerformanceFrequency(__int64 *freq)
|
||||
{
|
||||
*freq = CLOCKS_PER_SEC;
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
void Sleep(DWORD msecs)
|
||||
{
|
||||
//Sleep takes a time to sleep in milliseconds.
|
||||
usleep(msecs*1000); //usleep works with microseconds
|
||||
}
|
||||
|
||||
int GetLastError()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
void OutputDebugString(const char* stringOut)
|
||||
{
|
||||
fprintf(stderr,"%s",stringOut);
|
||||
}
|
||||
|
||||
|
||||
//File Support
|
||||
BOOL WriteFile(FILE* hFile, const void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesWritten, void* unsup)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if(unsup)
|
||||
return FALSE; //Windows doesn't support this overrlap buffer
|
||||
|
||||
retval = fwrite(lpBuffer, sizeof(char), numBytesToWrite, hFile);
|
||||
*numBytesWritten = retval;
|
||||
return (retval < 0) ? FALSE : TRUE;
|
||||
|
||||
}
|
||||
|
||||
BOOL ReadFile(FILE* hFile, void* lpBuffer, DWORD numBytesToRead, DWORD* numBytesRead, void* unsup)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if(unsup)
|
||||
return FALSE; //Windows doesn't support this overrlap buffer
|
||||
|
||||
retval = fread(lpBuffer, sizeof(char), numBytesToRead, hFile);
|
||||
*numBytesRead = retval;
|
||||
return (retval <= 0) ? FALSE : TRUE;
|
||||
|
||||
}
|
||||
|
||||
DWORD SetFilePointer(FILE* hFile, long lDistanceToMove, long* lpDistanceToMoveHigh, DWORD dwMoveMethod)
|
||||
{
|
||||
//Mimics the Win32 function to set the position of a file pointer. return -1 on failure else current position.
|
||||
|
||||
int retval;
|
||||
retval = fseek(hFile, lDistanceToMove, dwMoveMethod);
|
||||
|
||||
return (retval == 0) ? ftell(hFile) : -1;
|
||||
}
|
||||
|
||||
//TODO Consider using a call to open() instead of fopen() to get a better mapping of parameters to Win32
|
||||
FILE* CreateFile(const char* fileName, DWORD access, DWORD shareMode, void* unsupA, DWORD creationDisposition, DWORD flagsAndAttributes, FILE* unsupB)
|
||||
{
|
||||
FILE* retval = 0;
|
||||
|
||||
DEBUG_FATAL(flagsAndAttributes != FILE_ATTRIBUTE_NORMAL, ("Unsupported File mode call to CreateFile()"));
|
||||
DEBUG_FATAL(unsupB != NULL, ("Unsupported File mode call to CreateFile()"));
|
||||
//DEBUG_FATAL(shareMode != 0, ("Unsupported File mode call to CreateFile()"));
|
||||
DEBUG_FATAL(unsupA != 0, ("Unsupported File mode call to CreateFile()"));
|
||||
|
||||
switch(creationDisposition)
|
||||
{
|
||||
case CREATE_NEW:
|
||||
retval = fopen(fileName, "r");
|
||||
if (retval)
|
||||
{
|
||||
fclose(retval);
|
||||
retval = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(retval);
|
||||
retval = fopen(fileName, "w");
|
||||
}
|
||||
break;
|
||||
|
||||
case CREATE_ALWAYS:
|
||||
retval = fopen(fileName, "w");
|
||||
break;
|
||||
|
||||
case OPEN_EXISTING:
|
||||
retval = fopen(fileName, "r");
|
||||
if ((access & GENERIC_WRITE) && retval)
|
||||
{
|
||||
fclose(retval);
|
||||
retval = fopen(fileName, "a");
|
||||
rewind(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPEN_ALWAYS:
|
||||
if (access & GENERIC_WRITE)
|
||||
{
|
||||
retval = fopen(fileName, "a");
|
||||
rewind(retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = fopen(fileName, "r");
|
||||
}
|
||||
break;
|
||||
|
||||
case TRUNCATE_EXISTING:
|
||||
DEBUG_FATAL(!(access & GENERIC_WRITE),("Must open truncate file with write access"));
|
||||
retval = fopen(fileName, "w");
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
BOOL CloseHandle(FILE* hFile)
|
||||
{
|
||||
int retval = fclose(hFile);
|
||||
return (retval == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
//TODO There must be a more elegant UNIX command to get file size...fstat() needs filename
|
||||
DWORD GetFileSize(FILE* hFile, DWORD* lpHighSize)
|
||||
{
|
||||
long int curPos;
|
||||
DWORD endPos;
|
||||
curPos = ftell(hFile);
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
endPos = ftell(hFile);
|
||||
fseek(hFile, curPos, SEEK_SET);
|
||||
return endPos;
|
||||
|
||||
#if 0
|
||||
//This is what I want to do, but I have no file des number
|
||||
struct stat buf;
|
||||
fstat(hFile, &buf);
|
||||
return buf->st_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL FileExists(const char* filename)
|
||||
{
|
||||
BOOL retval = false;
|
||||
|
||||
struct stat info;
|
||||
if (stat(filename, &info) == 0)
|
||||
{
|
||||
if (S_ISREG(info.st_mode))
|
||||
retval = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Memory Functions
|
||||
|
||||
void* VirtualAlloc(void* location, DWORD size, DWORD flAllocationType, DWORD flProtect)
|
||||
{
|
||||
if (location)
|
||||
return location;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
BOOL VirtualFree(void* location, DWORD size, DWORD freeType)
|
||||
{
|
||||
free(location);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL VirtualProtect(void* location, DWORD size, DWORD newProtect, DWORD* oldProect)
|
||||
{
|
||||
//Unused. Function stub for compatibility
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL IsBadReadPtr(const void* location, unsigned int size)
|
||||
{
|
||||
//unused
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void MessageBox (void* unused, const char* message, const char* unused2, int flags)
|
||||
{
|
||||
OutputDebugString(message);
|
||||
}
|
||||
|
||||
char *ConvertCommandLine(int argc, char ** argv)
|
||||
{
|
||||
static char buffer[2048];
|
||||
|
||||
int totalSize=0;
|
||||
for (int i=0; i<argc; ++i)
|
||||
{
|
||||
totalSize+=strlen(argv[i])+1;
|
||||
}
|
||||
|
||||
if(totalSize>1023)
|
||||
{
|
||||
int argIndex = 0;
|
||||
fprintf(stderr, "Exceeded command line args length of %d. Total size is %d\n", sizeof(buffer), totalSize);
|
||||
for(argIndex = 0; argIndex < argc; ++argIndex)
|
||||
{
|
||||
fprintf(stderr, "argv[%d]=\"%s\"\n", argIndex, argv[argIndex]);
|
||||
}
|
||||
FATAL(true,("Command line exceeds maximum length."));
|
||||
}
|
||||
|
||||
buffer[0]='\0';
|
||||
|
||||
for (int i=0; i<argc; ++i)
|
||||
{
|
||||
strcat(buffer,argv[i]);
|
||||
if (i!=argc-1)
|
||||
{
|
||||
strcat(buffer," ");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
#ifndef INCLUDED_MISC_H
|
||||
#define INCLUDED_MISC_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef unsigned short int WORD;
|
||||
typedef unsigned long int DWORD;
|
||||
typedef bool BOOL;
|
||||
typedef long long __int64; //lint !e13 !e19 // Error: 13 (Bad type), Error: 19 (Useless declaration) // -TRF- Lint preprocessor discrepency, @todo look into this.
|
||||
typedef __int64 LARGE_INTEGER;
|
||||
|
||||
const BOOL FALSE = 0;
|
||||
const BOOL TRUE = 1;
|
||||
|
||||
|
||||
float abs(float x);
|
||||
int _stricmp(const char* string1, const char* string2);
|
||||
|
||||
//String to numeric conversions
|
||||
char* _itoa(int value, char* stringOut, int radix);
|
||||
|
||||
//Format specifier for non-portable printf
|
||||
#define UINT64_FORMAT_SPECIFIER "%llu"
|
||||
#define INT64_FORMAT_SPECIFIER "%lli"
|
||||
|
||||
//Constant definition macro for 64 bit values
|
||||
#define UINT64_LITERAL(a) a ## ull
|
||||
#define INT64_LITERAL(a) a ## ll
|
||||
|
||||
bool QueryPerformanceCounter(__int64 *time);
|
||||
bool QueryPerformanceFrequency(__int64 *freq);
|
||||
void Sleep(DWORD msecs);
|
||||
int GetLastError();
|
||||
void OutputDebugString(const char* stringOut);
|
||||
|
||||
//File Support
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef FILE* HANDLE;
|
||||
|
||||
#define INVALID_HANDLE_VALUE NULL //Have to use a #define because this may be a FILE*
|
||||
|
||||
|
||||
const int GENERIC_READ = 1 << 0;
|
||||
const int GENERIC_WRITE = 1 << 1;
|
||||
|
||||
const int CREATE_NEW = 1;
|
||||
const int CREATE_ALWAYS = 2;
|
||||
const int OPEN_EXISTING = 3;
|
||||
const int OPEN_ALWAYS = 4;
|
||||
const int TRUNCATE_EXISTING = 5;
|
||||
|
||||
const DWORD FILE_ATTRIBUTE_NORMAL = 1;
|
||||
|
||||
const int FILE_CURRENT = SEEK_CUR;
|
||||
const int FILE_BEGIN = SEEK_SET;
|
||||
const int FILE_END = SEEK_END;
|
||||
|
||||
const int FILE_SHARE_READ = 1;
|
||||
|
||||
BOOL WriteFile(FILE* hFile, const void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesWritten, void* unsup=NULL);
|
||||
BOOL ReadFile(FILE* hFile, void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesRead, void* unsup=NULL);
|
||||
DWORD SetFilePointer(FILE* hFile, long lDistanceToMove, long* lpDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
FILE* CreateFile(const char* fileName, DWORD access, DWORD shareMode, void* unsupA, DWORD creationDisposition, DWORD flagsAndAttributes, FILE* unsup2);
|
||||
BOOL CloseHandle(FILE* hFile);
|
||||
DWORD GetFileSize(FILE* hFile, DWORD* lpHighSize);
|
||||
BOOL FileExists(const char* fileName);
|
||||
|
||||
|
||||
//Memory Support
|
||||
|
||||
const int MEM_RESERVE = 0;
|
||||
const int MEM_COMMIT = 1;
|
||||
const int PAGE_READWRITE = 0;
|
||||
const int MEM_RELEASE = 0;
|
||||
const int PAGE_NOACCESS = 0;
|
||||
|
||||
void* VirtualAlloc(void* location, DWORD size, DWORD flAllocationType, DWORD flProtect);
|
||||
BOOL VirtualFree(void* location, DWORD size, DWORD freeType);
|
||||
BOOL VirtualProtect(void* location, DWORD size, DWORD newProtect, DWORD* oldProect);
|
||||
BOOL IsBadReadPtr(const void* location, unsigned int size);
|
||||
|
||||
//Misc output stuff
|
||||
|
||||
const int MB_OK = 0;
|
||||
const int MB_ICONEXCLAMATION = 1;
|
||||
void MessageBox (void* unused, const char* message, const char* unused2, int flags);
|
||||
char *ConvertCommandLine(int argc, char ** argv);
|
||||
|
||||
//String functions
|
||||
#define _vsnprintf vsnprintf
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
inline int _strnicmp (const char * a, const char * b, size_t count)
|
||||
{
|
||||
return ::strncasecmp (a, b, count);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
inline int _open(const char *filename, int oflag) { return open(filename, oflag); }
|
||||
inline int _open(const char *filename, int oflag, mode_t pmode) { return open(filename, oflag, pmode); }
|
||||
inline int _creat(const char *filename, mode_t pmode) { return creat(filename, pmode); }
|
||||
inline int _close(int fd) { return close(fd); }
|
||||
inline int _write(int fd, const void *buffer, unsigned int count) { return write(fd, buffer, count); }
|
||||
inline int _dup(int fd) { return dup(fd); }
|
||||
inline int _dup2(int oldfd, int newfd) { return dup2(oldfd, newfd); }
|
||||
inline long _lseek(int fd, long offset, int origin) { return lseek(fd, offset, origin); }
|
||||
inline int _read(int fd, void *buffer, unsigned int count) { return read(fd, buffer, count); }
|
||||
inline long _tell(int fd) { return _lseek(fd,0,SEEK_CUR); }
|
||||
inline int _umask(int pmode) { return umask(pmode); }
|
||||
inline int _unlink(const char *pathname) { return unlink(pathname); }
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
#endif //INCLUDED_MISC_H
|
||||
@@ -1,185 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedFoundation.cpp
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 - 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/SetupSharedFoundation.h"
|
||||
|
||||
#include "sharedDebug/ConfigSharedDebugLinux.h"
|
||||
#include "sharedDebug/DebugMonitor.h"
|
||||
#include "sharedDebug/Profiler.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/CommandLine.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
#include "sharedFoundation/CrcLowerString.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedFoundation/PerThreadData.h"
|
||||
#include "sharedFoundation/StaticCallbackEntry.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <math.h>
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* Install the engine.
|
||||
*
|
||||
* The settings in the Data structure will determine which subsystems
|
||||
* get initialized.
|
||||
*/
|
||||
|
||||
void SetupSharedFoundation::install(const Data &data)
|
||||
{
|
||||
// and get the command line stuff in quick so we can make decisions based on the command line settings
|
||||
CommandLine::install();
|
||||
ConfigFile::install();
|
||||
|
||||
if (data.lpCmdLine)
|
||||
CommandLine::absorbString(data.lpCmdLine);
|
||||
if (data.argc)
|
||||
CommandLine::absorbStrings(const_cast<const char**>(data.argv+1), data.argc-1);
|
||||
|
||||
#if 0
|
||||
//currently there's a problem that we cannot override the defaults here.
|
||||
if (data.configFile)
|
||||
IGNORE_RETURN(ConfigFile::loadFile(data.configFile));
|
||||
#endif
|
||||
|
||||
// get the post command-line text for the ConfigFile (key-value pairs)
|
||||
const char *configString = CommandLine::getPostCommandLineString();
|
||||
if (configString)
|
||||
ConfigFile::loadFromCommandLine(configString);
|
||||
|
||||
//@todo there is a lot of stuff in win32 setup not here...like exitchain
|
||||
Profiler::registerDebugFlags();
|
||||
#if _DEBUG
|
||||
MemoryManager::registerDebugFlags();
|
||||
#endif//_DEBUG
|
||||
|
||||
// Setup Linux DebugMonitor support.
|
||||
// @todo fix this dependency: DebugMonitor really should be moved into Foundation the way things currently are. TRF is following the existing win32 setup.
|
||||
#ifdef _DEBUG
|
||||
ConfigSharedDebugLinux::install();
|
||||
DebugMonitor::install();
|
||||
#endif
|
||||
|
||||
// setup the engine configuration
|
||||
ConfigSharedFoundation::Defaults defaults;
|
||||
defaults.frameRateLimit = data.frameRateLimit;
|
||||
ConfigSharedFoundation::install(defaults);
|
||||
SetWarningStrictFatal(ConfigFile::getKeyBool("SharedDebug", "strict", false));
|
||||
Report::install();
|
||||
Clock::install(data.runInBackground, false);
|
||||
|
||||
PersistentCrcString::install();
|
||||
CrcLowerString::install();
|
||||
StaticCallbackEntry::install();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Call a function with appropriate exception handling (not)
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// this is stubbed and exception handling is ignored currently
|
||||
|
||||
void SetupSharedFoundation::callbackWithExceptionHandling(
|
||||
void (*callback)(void) // Routine to call with exception handling
|
||||
)
|
||||
{
|
||||
if (ConfigSharedFoundation::getNoExceptionHandling())
|
||||
{
|
||||
callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
try
|
||||
{
|
||||
callback();
|
||||
}
|
||||
catch (__exception * mathException)
|
||||
{
|
||||
FATAL(true, ("Math Exception: %s\n", mathException->name));
|
||||
}
|
||||
catch (const char* message)
|
||||
{
|
||||
FATAL(true, ("Character Exception: %s\n", message));
|
||||
}
|
||||
catch(std::exception & m)
|
||||
{
|
||||
const char * c = m.what();
|
||||
FATAL(true, ("Std::exception: %s\n", c));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
FATAL(true, ("Unknown exception\n"));
|
||||
}
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Uninstall the engine.
|
||||
*
|
||||
* This routine will properly uninstall the engine componenets that were
|
||||
* installed by SetupSharedFoundation::install().
|
||||
*/
|
||||
|
||||
void SetupSharedFoundation::remove(void)
|
||||
{
|
||||
ExitChain::quit();
|
||||
|
||||
if (GetNumberOfWarnings())
|
||||
REPORT(true, Report::RF_print | Report::RF_log | Report::RF_dialog, ("%d warnings logged", GetNumberOfWarnings()));
|
||||
|
||||
// this routine can't be on the exit chain because the exit chain depends upon the PerThreadData class being around
|
||||
//PerThreadData::remove();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
SetupSharedFoundation::Data::Data(Defaults defaults)
|
||||
{
|
||||
Zero(*this);
|
||||
|
||||
switch (defaults)
|
||||
{
|
||||
case D_game:
|
||||
runInBackground = true;
|
||||
|
||||
lpCmdLine = NULL;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
|
||||
configFile = NULL;
|
||||
|
||||
frameRateLimit = CONST_REAL(0);
|
||||
break;
|
||||
|
||||
case D_console:
|
||||
runInBackground = true;
|
||||
|
||||
lpCmdLine = NULL;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
|
||||
configFile = NULL;
|
||||
|
||||
frameRateLimit = CONST_REAL(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_FATAL(true, ("unknown case"));
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,58 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedFoundation.h
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
// copyright 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_SetupSharedFoundation_H
|
||||
#define INCLUDED_SetupSharedFoundation_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
struct DebugMenuEntry;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class SetupSharedFoundation
|
||||
{
|
||||
public:
|
||||
|
||||
struct Data
|
||||
{
|
||||
// allow running in background
|
||||
bool runInBackground;
|
||||
|
||||
// pointer to command line
|
||||
char* lpCmdLine;
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
const char *configFile;
|
||||
|
||||
real frameRateLimit;
|
||||
|
||||
public:
|
||||
|
||||
enum Defaults
|
||||
{
|
||||
D_game,
|
||||
D_console
|
||||
};
|
||||
|
||||
Data(Defaults defaults);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void install(const Data &data);
|
||||
static void remove(void);
|
||||
|
||||
static void callbackWithExceptionHandling(void (*callback)(void));
|
||||
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// vsnprintf.cpp
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/vsnprintf.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
// ======================================================================
|
||||
// Format a printf-style string into a text buffer of fixed size
|
||||
//
|
||||
// Return value:
|
||||
//
|
||||
// The number of characters written into the buffer, or -1 if the buffer was too small
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// If the buffer would overflow, the null terminating character is not written and -1
|
||||
// will be returned.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
int vsnprintf(char *buffer, size_t count, const char *format, va_list va)
|
||||
{
|
||||
return _vsnprintf(buffer, count, format, va);
|
||||
}
|
||||
|
||||
#endif
|
||||
// ======================================================================
|
||||
@@ -1,24 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// vsnprintf.h
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef VSNPRINTF_H
|
||||
#define VSNPRINTF_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
int vsnprintf(char *buffer, size_t count, const char *format, va_list va);
|
||||
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/ConfigSharedFoundation.h"
|
||||
#include "sharedFoundation/CrashReportInformation.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/FloatingPointUnit.h"
|
||||
#include "sharedFoundation/Production.h"
|
||||
@@ -80,7 +79,6 @@ namespace OsNamespace
|
||||
Os::IMEHookFunction ms_IMEHookFunction;
|
||||
Os::QueueKeyDownHookFunction ms_queueKeyDownHookFunction;
|
||||
|
||||
int ms_processorCount;
|
||||
int ms_debugKeyIndex;
|
||||
int ms_SystemMouseCursorPositionX;
|
||||
int ms_SystemMouseCursorPositionY;
|
||||
@@ -245,106 +243,6 @@ void Os::installCommon()
|
||||
// switch into single-precision floating point mode
|
||||
FloatingPointUnit::install();
|
||||
|
||||
// get the amount of memory
|
||||
MEMORYSTATUS memoryStatus;
|
||||
GlobalMemoryStatus(&memoryStatus);
|
||||
CrashReportInformation::addStaticText("Ram: %dmb\n", memoryStatus.dwTotalPhys / (1024 * 1024));
|
||||
|
||||
// log the os information
|
||||
{
|
||||
OSVERSIONINFO versionInfo;
|
||||
Zero(versionInfo);
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&versionInfo);
|
||||
CrashReportInformation::addStaticText("Os1: %d.%d.%d\n", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion, versionInfo.dwBuildNumber);
|
||||
|
||||
char const * os = "Unknown";
|
||||
|
||||
char CDECL pwine_get_version;
|
||||
HMODULE hntdll = GetModuleHandle("ntdll.dll");
|
||||
|
||||
switch (versionInfo.dwMajorVersion) {
|
||||
case 4:
|
||||
switch (versionInfo.dwMinorVersion){
|
||||
case 10:
|
||||
os = "Windows 98";
|
||||
break;
|
||||
case 90:
|
||||
os = "Windows ME";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (versionInfo.dwMinorVersion) {
|
||||
case 0:
|
||||
os = "Windows 2000";
|
||||
break;
|
||||
case 1:
|
||||
os = "Windows XP";
|
||||
break;
|
||||
case 2:
|
||||
os = "Windows 2003";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
switch (versionInfo.dwMinorVersion){
|
||||
case 0:
|
||||
os = "Windows Vista";
|
||||
break;
|
||||
case 1:
|
||||
os = "Windows 7";
|
||||
break;
|
||||
case 2:
|
||||
os = "Windows 8";
|
||||
break;
|
||||
case 3:
|
||||
os = "Windows 8.1";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
os = "Windows 10";
|
||||
break;
|
||||
}
|
||||
|
||||
//detect WINE
|
||||
if (hntdll)
|
||||
{
|
||||
pwine_get_version = (char)GetProcAddress(hntdll, "wine_get_version");
|
||||
if (pwine_get_version)
|
||||
{
|
||||
os = strcat("Wine ", &pwine_get_version);
|
||||
}
|
||||
}
|
||||
|
||||
CrashReportInformation::addStaticText("Os2: %s %s\n", os, versionInfo.szCSDVersion);
|
||||
}
|
||||
|
||||
// get the number of processors
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
ms_processorCount = static_cast<int>(si.dwNumberOfProcessors);
|
||||
REPORT_LOG (ConfigSharedFoundation::getVerboseHardwareLogging(), ("Processor Count: %i\n", ms_processorCount));
|
||||
CrashReportInformation::addStaticText("NumProc: %d\n", ms_processorCount);
|
||||
|
||||
{
|
||||
HKEY key;
|
||||
LONG result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_EXECUTE, &key);
|
||||
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD data;
|
||||
DWORD type = REG_DWORD;
|
||||
DWORD size = sizeof (data);
|
||||
result = RegQueryValueEx (key, "~MHz", NULL, &type, reinterpret_cast<LPBYTE> (&data), &size);
|
||||
if ((result == ERROR_SUCCESS) && (size > 0))
|
||||
REPORT_LOG (ConfigSharedFoundation::getVerboseHardwareLogging(), ("Processor Speed: %i MHz\n", data));
|
||||
|
||||
RegCloseKey (key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetKeyboardLayoutName(ms_keyboardLayout))
|
||||
ms_keyboardLayout[0] = '\0';
|
||||
|
||||
@@ -495,30 +393,6 @@ bool Os::wasFocusLost()
|
||||
return ms_wasFocusLost;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return a flag indicating whether we are running a multiprocessor machine or not.
|
||||
*
|
||||
* @return True if the machine has more than one processor, false if not.
|
||||
*/
|
||||
|
||||
bool Os::isMultiprocessor()
|
||||
{
|
||||
return ms_processorCount > 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Return the number of processors.
|
||||
*
|
||||
* @return The number of processors in the machine.
|
||||
*/
|
||||
|
||||
int Os::getProcessorCount()
|
||||
{
|
||||
return ms_processorCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Os::isMainThread()
|
||||
@@ -1662,10 +1536,7 @@ bool Os::isFocused()
|
||||
bool Os::launchBrowser(std::string const & website)
|
||||
{
|
||||
std::string URL("http://");
|
||||
if (strncmp(URL.c_str(), website.c_str(),7)!=0)
|
||||
URL+=website;
|
||||
else
|
||||
URL=website;
|
||||
URL=website;
|
||||
int result = reinterpret_cast<int>(ShellExecute(NULL, "open", URL.c_str(), NULL, NULL, SW_SHOWNORMAL));
|
||||
return (result > 32);
|
||||
}
|
||||
|
||||
@@ -109,9 +109,6 @@ public:
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// PRIVATE. Do not export this header file outside the package.
|
||||
|
||||
#ifndef INCLUDED_FoundationTypesLinux_H
|
||||
#define INCLUDED_FoundationTypesLinux_H
|
||||
|
||||
// ======================================================================
|
||||
// specify what platform we're running on.
|
||||
|
||||
#define PLATFORM_UNIX
|
||||
#define PLATFORM_LINUX
|
||||
|
||||
#include <cstdio>
|
||||
// ======================================================================
|
||||
// basic types that we assume to be around
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed long long int int64;
|
||||
typedef unsigned long long int uint64;
|
||||
typedef float real;
|
||||
typedef FILE* FILE_HANDLE;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// StderrLogger.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedLog/FirstSharedLog.h"
|
||||
#include "sharedLog/StderrLogger.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include <string>
|
||||
#include <fcntl.h>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace StderrLoggerNamespace
|
||||
{
|
||||
bool s_installed;
|
||||
int s_oldStderr;
|
||||
int s_stderrPipe[2];
|
||||
}
|
||||
using namespace StderrLoggerNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void StderrLogger::install()
|
||||
{
|
||||
DEBUG_FATAL(s_installed, ("StderrLogger already installed"));
|
||||
s_installed = true;
|
||||
s_oldStderr = dup(2);
|
||||
pipe(s_stderrPipe);
|
||||
dup2(s_stderrPipe[1], 2);
|
||||
fcntl(s_stderrPipe[0], F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StderrLogger::remove()
|
||||
{
|
||||
DEBUG_FATAL(!s_installed, ("StderrLogger not installed"));
|
||||
dup2(s_oldStderr, 2);
|
||||
close(s_stderrPipe[0]);
|
||||
close(s_stderrPipe[1]);
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StderrLogger::update()
|
||||
{
|
||||
if (!s_installed)
|
||||
return;
|
||||
|
||||
char buf[8192];
|
||||
int nRead = read(s_stderrPipe[0], buf, sizeof(buf)-1);
|
||||
if (nRead > 0)
|
||||
{
|
||||
int startPos = 0;
|
||||
while (startPos < nRead)
|
||||
{
|
||||
int endPos = startPos;
|
||||
while (buf[endPos] != '\n' && endPos < nRead)
|
||||
++endPos;
|
||||
buf[endPos] = 0;
|
||||
if (endPos > startPos)
|
||||
LOG("stderr", ("%s", buf+startPos));
|
||||
startPos = endPos+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsMemory.cpp
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
|
||||
#include "sharedMemoryManager/OsMemory.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void OsMemory::install()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void OsMemory::remove()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *OsMemory::commit(void *, size_t bytes)
|
||||
{
|
||||
return ::malloc(bytes);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool OsMemory::free(void *addr, size_t)
|
||||
{
|
||||
::free(addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,29 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// 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
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsNewDel.cpp
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
|
||||
#include "sharedMemoryManager/MemoryManager.h"
|
||||
#include "sharedMemoryManager/OsNewDel.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static MemoryManager memoryManager __attribute__ ((init_priority (101)));
|
||||
|
||||
#define USE_LIBC_MALLOC_HOOKS 0
|
||||
|
||||
#if USE_LIBC_MALLOC_HOOKS
|
||||
extern "C"
|
||||
{
|
||||
void memoryManagerFreeHook(__malloc_ptr_t __ptr, __const __malloc_ptr_t)
|
||||
{
|
||||
delete[] (char *)__ptr;
|
||||
}
|
||||
|
||||
__malloc_ptr_t memoryManagerMallocHook(size_t __size, const __malloc_ptr_t)
|
||||
{
|
||||
return new char[__size];
|
||||
}
|
||||
|
||||
__malloc_ptr_t memoryManagerReallocHook(__malloc_ptr_t __ptr, size_t size, __const __malloc_ptr_t)
|
||||
{
|
||||
if(! __ptr)
|
||||
return new char[size];
|
||||
|
||||
return MemoryManager::reallocate(__ptr, size);
|
||||
}
|
||||
|
||||
__malloc_ptr_t memoryManagerMemAlignHook(size_t alignment, size_t size, __const __malloc_ptr_t)
|
||||
{
|
||||
DEBUG_FATAL(true, ("memalign not implemented!"));
|
||||
return new char[size];
|
||||
}
|
||||
|
||||
static void memoryManagerMallocInitializeHook(void)
|
||||
{
|
||||
__free_hook = memoryManagerFreeHook;
|
||||
__malloc_hook = memoryManagerMallocHook;
|
||||
__realloc_hook = memoryManagerReallocHook;
|
||||
__memalign_hook = memoryManagerMemAlignHook;
|
||||
}
|
||||
void (*__malloc_initialize_hook) (void) = memoryManagerMallocInitializeHook;
|
||||
}
|
||||
|
||||
#endif//USE_LIBC_MALLOC_HOOKS
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void *operator new(size_t size, MemoryManagerNotALeak) throw (std::bad_alloc)
|
||||
{
|
||||
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *operator new(size_t size) throw (std::bad_alloc)
|
||||
{
|
||||
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *operator new[](size_t size) throw (std::bad_alloc)
|
||||
{
|
||||
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), true, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *operator new(size_t size, const char *file, int line) throw (std::bad_alloc)
|
||||
{
|
||||
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *operator new[](size_t size, const char *file, int line) throw (std::bad_alloc)
|
||||
{
|
||||
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), true, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete(void *pointer) throw()
|
||||
{
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete[](void *pointer) throw()
|
||||
{
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete(void *pointer, const char *file, int line) throw()
|
||||
{
|
||||
UNREF(file);
|
||||
UNREF(line);
|
||||
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void operator delete[](void *pointer, const char *file, int line) throw()
|
||||
{
|
||||
UNREF(file);
|
||||
UNREF(line);
|
||||
|
||||
if (pointer)
|
||||
MemoryManager::free(pointer, true);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// OsNewDel.h
|
||||
//
|
||||
// Copyright 2002 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_OsNewDel_H
|
||||
#define INCLUDED_OsNewDel_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
enum MemoryManagerNotALeak
|
||||
{
|
||||
MM_notALeak
|
||||
};
|
||||
|
||||
void *operator new(size_t size, MemoryManagerNotALeak) throw(std::bad_alloc);
|
||||
void *operator new(size_t size) throw(std::bad_alloc);
|
||||
void *operator new[](size_t size) throw(std::bad_alloc);
|
||||
void *operator new(size_t size, char const *file, int line) throw(std::bad_alloc);
|
||||
void *operator new[](size_t size, char const *file, int line) throw(std::bad_alloc);
|
||||
|
||||
void operator delete(void *pointer) throw();
|
||||
void operator delete[](void *pointer) throw();
|
||||
void operator delete(void *pointer, char const *file, int line) throw();
|
||||
void operator delete[](void *pointer, char const *file, int line) throw();
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // INCLUDED_OsNewDel_H
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include "Address.h"
|
||||
#include <cassert>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstdio>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address() :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("0.0.0.0")
|
||||
{
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_family = AF_INET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const std::string & newHostAddress, unsigned short newHostPort) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(newHostAddress)
|
||||
{
|
||||
struct 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)
|
||||
{
|
||||
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
|
||||
memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
|
||||
|
||||
// in debug, fail, something is wrong.
|
||||
// potential problems - an insanely bogus address was
|
||||
// passed or the host system is misconfigured and cannot
|
||||
// resolve the name
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
char addrbuf[17] = {"\0"};
|
||||
unsigned char * a = (unsigned char *)&addr4->sin_addr;
|
||||
snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
hostAddress = addrbuf;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const Address & source) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(source.hostAddress)
|
||||
{
|
||||
*addr4 = *source.addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const struct sockaddr_in & ipv4addr) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("")
|
||||
{
|
||||
convertFromSockAddr(ipv4addr);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::~Address()
|
||||
{
|
||||
delete addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address & Address::operator = (const Address & rhs)
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
hostAddress = rhs.hostAddress;
|
||||
*addr4 = *rhs.addr4;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
*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;
|
||||
assert(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::hash_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();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
// NetworkGetHostName.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include "Address.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HN
|
||||
{
|
||||
HN();
|
||||
std::string hostName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HN::HN()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
Address a(name, 0);
|
||||
//hostName = name;
|
||||
hostName = a.getHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HL
|
||||
{
|
||||
HL();
|
||||
std::vector<std::pair<std::string, std::string> > addrList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HL::HL() :
|
||||
addrList()
|
||||
{
|
||||
struct ifconf ifc;
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
// create a socket to perform SIOCGIFCONF on
|
||||
if(sock > -1)
|
||||
{
|
||||
// determine buffer size to receive array of if_req's, initialize it
|
||||
// when length is appropriate
|
||||
int reqSize = 100 * sizeof(struct ifreq);
|
||||
int lastReqSize = reqSize;
|
||||
for(;;)
|
||||
{
|
||||
char * buf = new char[reqSize];
|
||||
ifc.ifc_len = reqSize;
|
||||
ifc.ifc_buf = buf;
|
||||
memset(ifc.ifc_buf, 0, reqSize);
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if (errno != EINVAL || lastReqSize != 0)
|
||||
{
|
||||
WARNING(true, ("Error getting interface list: %s", strerror(errno)));
|
||||
delete buf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ifc.ifc_len == lastReqSize)
|
||||
break; // we have the reqs
|
||||
lastReqSize = ifc.ifc_len;
|
||||
}
|
||||
|
||||
// need more buffer space for request
|
||||
reqSize += sizeof(struct ifreq);
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
int reqCount = reqSize / sizeof(struct ifreq);
|
||||
int i;
|
||||
ifreq * reqs = (struct ifreq *)ifc.ifc_buf;
|
||||
for(i = 0; i < reqCount; ++i)
|
||||
{
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&reqs[i].ifr_addr;
|
||||
if(sa->sin_family == AF_INET)
|
||||
{
|
||||
char addrbuf[17] = {"\0"};
|
||||
unsigned char * a = (unsigned char *)&sa->sin_addr;
|
||||
snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
addrList.push_back(std::make_pair(std::string(reqs[i].ifr_name), std::string(addrbuf)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > & NetworkHandler::getInterfaceAddresses()
|
||||
{
|
||||
static HL hl;
|
||||
return hl.addrList;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -1,236 +0,0 @@
|
||||
//---------------------------------------------------------------------
|
||||
#pragma warning(disable : 4127)
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include <cassert>
|
||||
#include "Sock.h"
|
||||
#include <netdb.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
const int INVALID_SOCKET = 0xFFFFFFFF;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Sock::Sock() :
|
||||
handle(INVALID_SOCKET),
|
||||
lastError(Sock::SOCK_NO_ERROR),
|
||||
bindAddress()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Sock::~Sock()
|
||||
{
|
||||
// ensure we don't block, and that pending
|
||||
// data is sent with a graceful shutdown
|
||||
int err;
|
||||
err = close(handle);
|
||||
assert(err == 0);
|
||||
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, &enable, sizeof(enable));
|
||||
|
||||
bindAddress = newBindAddress;
|
||||
assert(handle != INVALID_SOCKET);
|
||||
socklen_t 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);
|
||||
assert(r == 0);
|
||||
bindAddress = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
assert(err == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::bind()
|
||||
{
|
||||
bool result = false;
|
||||
struct sockaddr_in a;
|
||||
socklen_t 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;
|
||||
assert(handle != INVALID_SOCKET);
|
||||
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);
|
||||
assert(r == 0);
|
||||
bindAddress = a;
|
||||
}
|
||||
assert(err == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::canRecv() const
|
||||
{
|
||||
pollfd r;
|
||||
r.fd = handle;
|
||||
r.events = POLLIN | POLLPRI | POLLERR;
|
||||
|
||||
int err = poll(&r, 1, 0);
|
||||
|
||||
if(err < 0)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: // the system has interrupted the call, it's too busy to send right now
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (err > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::canSend() const
|
||||
{
|
||||
pollfd w;
|
||||
w.fd = handle;
|
||||
w.events = POLLOUT | POLLERR;
|
||||
int err = poll(&w, 1, 0);
|
||||
|
||||
if(err < 0)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: // the system has interrupted the call, it's too busy to send right now
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (err > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int Sock::getInputBytesPending() const
|
||||
{
|
||||
unsigned long int bytes = 0;
|
||||
int err;
|
||||
err = ioctl(handle, FIONREAD, &bytes); //lint !e1924 (I don't know WHAT Microsoft is doing here!)
|
||||
assert(err == 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const std::string Sock::getLastError() const
|
||||
{
|
||||
std::string errString;
|
||||
|
||||
switch(errno)
|
||||
{
|
||||
case EBADF:
|
||||
errString = "The argument s is not a valid descriptor.";
|
||||
break;
|
||||
case ENOTSOCK:
|
||||
errString = "The argument s is a file, not a socket.";
|
||||
break;
|
||||
case ENOPROTOOPT:
|
||||
errString = "The option is unknown at the level indicated.";
|
||||
break;
|
||||
case EFAULT:
|
||||
errString = "The address pointed to by optval is not in a valid part of the process address space. For getsockopt, this error may also be returned if optlen is not in a valid part of the process address space.";
|
||||
break;
|
||||
case ENOTTY:
|
||||
errString = "The scoket handle is not associated with a character special device.";
|
||||
break;
|
||||
case EINVAL:
|
||||
errString = "argument is not valid.";
|
||||
break;
|
||||
case EAGAIN:
|
||||
errString = "EAGAIN";
|
||||
break;
|
||||
case EDEADLK:
|
||||
errString = "EDEADLK";
|
||||
break;
|
||||
case ECONNRESET:
|
||||
errString = "The connection was reset by the peer.";
|
||||
lastError = CONNECTION_RESET;
|
||||
break;
|
||||
default:
|
||||
errString = strerror(errno);
|
||||
break;
|
||||
}
|
||||
|
||||
return errString;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Sock::getPeerName(struct sockaddr_in & target, int s)
|
||||
{
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
int err;
|
||||
err = getpeername(s, reinterpret_cast<sockaddr *>(&(target)), &namelen);
|
||||
assert(err != -1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** @brief determine the maximum message size that may be sent on this socket
|
||||
*/
|
||||
const unsigned int Sock::getMaxMessageSendSize() const
|
||||
{
|
||||
int maxMsgSize = 1500;
|
||||
/** @todo get msg size via IP interface on Linux
|
||||
int optlen = sizeof(int);
|
||||
int result = getsockopt(handle, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char *>(&maxMsgSize), &optlen);
|
||||
if(result != 0)
|
||||
{
|
||||
perror("Sock::getMaxMessageSendSize() : getsockopt()");
|
||||
}
|
||||
*/
|
||||
return static_cast<unsigned int>(maxMsgSize);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Sock::setNonBlocking() const
|
||||
{
|
||||
assert(handle != INVALID_SOCKET);
|
||||
unsigned long int nb = 1;
|
||||
int err;
|
||||
err = ioctl(handle, FIONBIO, &nb); //lint !e569 // loss of precision in the FIONBIO macro, beyond my control
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// 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;
|
||||
|
||||
/**
|
||||
@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 int 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, int 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 int 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
|
||||
|
||||
@@ -1,610 +0,0 @@
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
#include "Archive/Archive.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedLog/NetLogConnection.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include <map>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned long KEEPALIVE_MS = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace TcpClientNamespace
|
||||
{
|
||||
std::set<TcpClient *> s_pendingConnectionSends;
|
||||
std::set<TcpClient *> s_tcpClients;
|
||||
bool s_installed = false;
|
||||
}
|
||||
|
||||
using namespace TcpClientNamespace;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient (int sockHandle, TcpServer * server) :
|
||||
m_socket(sockHandle),
|
||||
m_tcpServer(server),
|
||||
m_pendingSend(),
|
||||
m_connection(0),
|
||||
m_recvBuffer(0),
|
||||
m_recvBufferLength(0),
|
||||
m_remoteAddress(),
|
||||
m_refCount(0),
|
||||
m_connected (true),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
s_tcpClients.insert(this);
|
||||
setSockOptions();
|
||||
|
||||
struct sockaddr_in target;
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
if (getpeername(sockHandle, reinterpret_cast<sockaddr *>(&target), &namelen) == 0)
|
||||
m_remoteAddress = target;
|
||||
struct sockaddr_in bindAddr;
|
||||
|
||||
if(getsockname(sockHandle, reinterpret_cast<struct sockaddr *>(&bindAddr), &namelen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient (const std::string & a, const unsigned short port) :
|
||||
m_socket(-1),
|
||||
m_tcpServer(0),
|
||||
m_connection(0),
|
||||
m_recvBuffer(0),
|
||||
m_recvBufferLength(0),
|
||||
m_remoteAddress(a, port),
|
||||
m_refCount(0),
|
||||
m_connected (false),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
FATAL(! s_installed, ("TcpClient is not installed!"));
|
||||
|
||||
s_tcpClients.insert(this);
|
||||
setupSocket();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpClient::~TcpClient()
|
||||
{
|
||||
FATAL(m_refCount > 0, ("Attempting to destroy a TcpClient while references still exist!"));
|
||||
std::set<TcpClient *>::iterator f = s_tcpClients.find(this);
|
||||
if(f != s_tcpClients.end())
|
||||
s_tcpClients.erase(f);
|
||||
f = s_pendingConnectionSends.find(this);
|
||||
if(f != s_pendingConnectionSends.end())
|
||||
s_pendingConnectionSends.erase(f);
|
||||
|
||||
delete[] m_recvBuffer;
|
||||
if(m_socket != -1)
|
||||
close (m_socket);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::addRef()
|
||||
{
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
std::string const &TcpClient::getRemoteAddress() const
|
||||
{
|
||||
return m_remoteAddress.getHostAddress();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getRemotePort() const
|
||||
{
|
||||
return m_remoteAddress.getHostPort();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setSockOptions()
|
||||
{
|
||||
int optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
ioctl(m_socket, FIONBIO, &optval);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
void TcpClient::commit()
|
||||
{
|
||||
int sent = 0;
|
||||
const unsigned char * ptr = m_pendingSend.getBuffer();
|
||||
const unsigned char * const end = ptr + m_pendingSend.getSize();
|
||||
static Archive::ByteStream s_localScratchBuffer;
|
||||
s_localScratchBuffer.clear();
|
||||
int retries = 0;
|
||||
static const int maxRetries = ConfigSharedNetwork::getMaxTCPRetries();
|
||||
bool sentSomething = false;
|
||||
|
||||
do
|
||||
{
|
||||
// attempt to push pending data to socket
|
||||
sent = ::send (m_socket, ptr, end - ptr, MSG_NOSIGNAL);
|
||||
if(sent == -1)
|
||||
{
|
||||
// failed
|
||||
switch(errno)
|
||||
{
|
||||
// because it would block on a non-blocking socket
|
||||
case EAGAIN:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
case EINTR:
|
||||
{
|
||||
retries++;
|
||||
// requeue
|
||||
break;
|
||||
}
|
||||
// an unhandled error (connection reset, for example)
|
||||
default:
|
||||
{
|
||||
m_pendingSend.clear();
|
||||
perror("send: ");
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::commit send returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sent > 0)
|
||||
{
|
||||
sentSomething=true;
|
||||
ptr += sent;
|
||||
if(sent < end - ptr)
|
||||
{
|
||||
// data was passed to the socket, but not all
|
||||
// of it could be committed, keep trying!
|
||||
retries = 0;
|
||||
Os::sleep(1);
|
||||
}
|
||||
}
|
||||
else if(sent == 0)
|
||||
{
|
||||
// tried to send and got nothing through (should have returned an error, but be thorough)
|
||||
retries ++;
|
||||
Os::sleep(1);
|
||||
}
|
||||
|
||||
} while(ptr < end && retries < maxRetries);
|
||||
|
||||
if(ptr == end)
|
||||
{
|
||||
// all data was committed, clear pending buffer
|
||||
m_pendingSend.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// bailed out before all data was committed, save unsent data for
|
||||
// next pass on commit()
|
||||
if (sentSomething)
|
||||
{
|
||||
s_localScratchBuffer.put(ptr, end - ptr);
|
||||
m_pendingSend.clear();
|
||||
m_pendingSend.put(s_localScratchBuffer.getBuffer(), s_localScratchBuffer.getSize());
|
||||
}
|
||||
s_pendingConnectionSends.insert(this);
|
||||
}
|
||||
|
||||
// clean up local accounting
|
||||
s_localScratchBuffer.clear();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flush()
|
||||
{
|
||||
if (m_connected && m_pendingSend.getSize() > 0)
|
||||
{
|
||||
// flush pending buffer
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flushPendingWrites()
|
||||
{
|
||||
std::set<TcpClient *> sends = s_pendingConnectionSends;
|
||||
s_pendingConnectionSends.clear();
|
||||
|
||||
for (std::set<TcpClient *>::const_iterator i = sends.begin(); i != sends.end(); ++i)
|
||||
{
|
||||
TcpClient * const c = *i;
|
||||
|
||||
if (c->m_connected)
|
||||
{
|
||||
c->flush();
|
||||
|
||||
if ( c->m_connection
|
||||
&& c->m_pendingSend.getSize()
|
||||
&& ConfigSharedNetwork::getLogSendingTooMuchData()
|
||||
&& !dynamic_cast<NetLogConnection const *>(c->m_connection))
|
||||
{
|
||||
WARNING(true, ("(%s) Failed to commit %d bytes this frame to %s:%d. This process is sending more data than the remote can receive!", c->m_connection->getConnectionDescription().c_str(), c->m_pendingSend.getSize(), c->getRemoteAddress().c_str(), c->getRemotePort()));
|
||||
LOG("Network", ("(%s) Failed to commit %d bytes this frame to %s:%d. This process is sending more data than the remote can receive!", c->m_connection->getConnectionDescription().c_str(), c->m_pendingSend.getSize(), c->getRemoteAddress().c_str(), c->getRemotePort()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
int TcpClient::getSocket() const
|
||||
{
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::install()
|
||||
{
|
||||
FATAL(s_installed, ("TcpClient is already installed!"));
|
||||
s_installed = true;
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionClosed()
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::onConnectionClosed called");
|
||||
m_connected = false;
|
||||
shutdown(m_socket, SHUT_RDWR);
|
||||
if(m_tcpServer)
|
||||
{
|
||||
m_tcpServer->removeClient(this);
|
||||
}
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
if(m_connection)
|
||||
{
|
||||
NetworkHandler::onTerminate(m_connection);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionOpened()
|
||||
{
|
||||
// Get the local port this socket was bound to. If
|
||||
// a client socket repeatedly attempts to connect to a local
|
||||
// service that should be listening on a port that the operating
|
||||
// system may assign AND the service isn't actually running and
|
||||
// using the port, the client socket may connect to itself.
|
||||
// For example, A client connecting to 127.0.0.1:50005, the operating
|
||||
// system may assign the client socket port 50005 and the connection
|
||||
// succeeds, but it is in fact a connection to itself, meaning the
|
||||
// client isn't actually talking to any valid service.
|
||||
struct sockaddr_in bindAddr;
|
||||
socklen_t addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
// this *might* be a valid connection to a remote address, but
|
||||
// to easily catch all cases of loopback connections, attempt a
|
||||
// reconnect if the remote port is identical to the local port
|
||||
if(m_remoteAddress.getHostPort() == m_bindPort && ! m_tcpServer)
|
||||
{
|
||||
shutdown(m_socket, SHUT_RDWR);
|
||||
DEBUG_FATAL(m_tcpServer, ("Detected a loopback client connection on a TCP SERVER!!!"));
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
|
||||
// reconnect the socket
|
||||
// address and port info is initialized in the constructor
|
||||
setupSocket();
|
||||
LOG("Network", ("Detected a loopback, closing socket and reconnecting"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_connected = true;
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->onConnectionOpened();
|
||||
}
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onReceive (const unsigned char * const recvBuf, const int bytes)
|
||||
{
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->receive(recvBuf, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queryConnect ()
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_socket;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
int pollResult = poll(&pfd, 1, 0);
|
||||
if(pollResult > 0)
|
||||
{
|
||||
if (pfd.revents & POLLERR)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::queryConnect POLLERR");
|
||||
onConnectionClosed();
|
||||
}
|
||||
else if (pfd.revents & POLLHUP)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::queryConnect POLLHUP");
|
||||
onConnectionClosed();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionOpened();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::release()
|
||||
{
|
||||
m_refCount--;
|
||||
if(m_refCount == 0)
|
||||
{
|
||||
if (m_connected)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::release called");
|
||||
onConnectionClosed();
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::remove()
|
||||
{
|
||||
FATAL(!s_installed, ("TcpClient already removed!"));
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_tcpClients.begin(); i != s_tcpClients.end(); ++i)
|
||||
{
|
||||
TcpClient * c = (*i);
|
||||
c->release();
|
||||
}
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::send(const unsigned char * const buffer, const int bufferLen)
|
||||
{
|
||||
if (bufferLen)
|
||||
{
|
||||
m_lastSendTime = Clock::getFrameStartTimeMs();
|
||||
s_pendingConnectionSends.insert(this);
|
||||
if( !m_rawTCP )
|
||||
Archive::put(m_pendingSend, bufferLen);
|
||||
m_pendingSend.put(buffer, bufferLen);
|
||||
|
||||
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::checkKeepalive()
|
||||
{
|
||||
if (m_connected)
|
||||
{
|
||||
unsigned long const timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::update()
|
||||
{
|
||||
addRef();
|
||||
if(!m_connected)
|
||||
{
|
||||
queryConnect();
|
||||
}
|
||||
|
||||
if(m_connected)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_socket;
|
||||
pfd.events = POLLIN|POLLHUP;
|
||||
pfd.revents = 0;
|
||||
int pollResult = poll (&pfd, 1, 0);
|
||||
// POLLERR is mutually exclusive with POLLIN and POLLHUP.
|
||||
// POLLIN and POLLHUP are not consistent cross-platform. Additionally,
|
||||
// a POLLHUP doesn't mean that there's not data available. The best,
|
||||
// cross-platform way to check for disconnection is to see if either
|
||||
// POLLHUP or POLLIN are set, and then read from the socket.
|
||||
// In cases where there's data, we'll just end up checking it next
|
||||
// frame anyway. In cases where there's no data, it means we've
|
||||
// disconnected so we can handle cleanup.
|
||||
if (pollResult)
|
||||
{
|
||||
if (m_recvBuffer == NULL)
|
||||
{
|
||||
m_recvBufferLength = 1500;
|
||||
m_recvBuffer = new unsigned char [m_recvBufferLength];
|
||||
}
|
||||
int bytesReceived = recv(m_socket, m_recvBuffer, m_recvBufferLength, 0);
|
||||
if (bytesReceived > 0)
|
||||
{
|
||||
onReceive(m_recvBuffer, bytesReceived);
|
||||
}
|
||||
else if (bytesReceived == -1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
break;
|
||||
default:
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::update recv returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (bytesReceived == 0)
|
||||
{
|
||||
// peer closed connection
|
||||
|
||||
|
||||
|
||||
if (m_connection)
|
||||
{
|
||||
// Log this, as it's a pretty deep change.
|
||||
LOG("Network", ("(%s) Read zero bytes on a successful poll (POLLIN|POLLHUP). Closing socket since we think it is closed.", m_connection->getConnectionDescription().c_str()));
|
||||
m_connection->setDisconnectReason("TcpClient::update recv returned 0");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Network", ("(null connection object) Read zero bytes on a successful poll (POLLIN|POLLHUP). Closing socket since we think it is closed."));
|
||||
}
|
||||
onConnectionClosed();
|
||||
}
|
||||
|
||||
if (bytesReceived == m_recvBufferLength)
|
||||
{
|
||||
// grow the buffer
|
||||
delete [] m_recvBuffer;
|
||||
m_recvBufferLength = m_recvBufferLength * 2;
|
||||
m_recvBuffer = new unsigned char [m_recvBufferLength];
|
||||
}
|
||||
}
|
||||
}
|
||||
release();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setupSocket()
|
||||
{
|
||||
FATAL(! s_installed, ("TcpClient is not installed!"));
|
||||
|
||||
protoent * p = getprotobyname ("tcp");
|
||||
const int entry = p->p_proto;
|
||||
m_socket = socket (AF_INET, SOCK_STREAM, entry);
|
||||
if (m_socket != -1)
|
||||
{
|
||||
setSockOptions();
|
||||
|
||||
int nameLen = sizeof (struct sockaddr_in);
|
||||
int result;
|
||||
result = connect (m_socket, reinterpret_cast<const struct sockaddr *> (&m_remoteAddress.getSockAddr4 () ), nameLen);
|
||||
if(result == -1)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
break;
|
||||
default:
|
||||
perror("connect ");
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::TcpClient connect returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in bindAddr;
|
||||
socklen_t addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
void TcpClient::setRawTCP( bool bNewValue )
|
||||
{
|
||||
m_rawTCP = bNewValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::clearTcpServer()
|
||||
{
|
||||
m_tcpServer = 0;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
// TcpClient.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpClient_H
|
||||
#define _INCLUDED_TcpClient_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "Archive/ByteStream.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include <string>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Connection;
|
||||
class TcpServer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient
|
||||
{
|
||||
public:
|
||||
TcpClient(int sock, TcpServer *);
|
||||
TcpClient(const std::string & address, const unsigned short port);
|
||||
|
||||
void addRef();
|
||||
static void install();
|
||||
void release();
|
||||
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 class TcpServer;
|
||||
friend class Connection;
|
||||
|
||||
void setSockOptions();
|
||||
void commit();
|
||||
int getSocket() const;
|
||||
void onConnectionClosed();
|
||||
void onConnectionOpened();
|
||||
void onReceive(const unsigned char * const recvBuf, const int bytes);
|
||||
void queryConnect();
|
||||
void queueReceive();
|
||||
void setConnection(Connection *);
|
||||
void checkKeepalive();
|
||||
void clearTcpServer();
|
||||
void setRawTCP( bool bNewValue );
|
||||
|
||||
private:
|
||||
TcpClient & operator = (const TcpClient & rhs);
|
||||
TcpClient(const TcpClient & source);
|
||||
~TcpClient();
|
||||
void flush ();
|
||||
void setupSocket();
|
||||
int m_socket;
|
||||
TcpServer * m_tcpServer;
|
||||
Archive::ByteStream m_pendingSend;
|
||||
Connection * m_connection;
|
||||
unsigned char * m_recvBuffer;
|
||||
int m_recvBufferLength;
|
||||
Address m_remoteAddress;
|
||||
int m_refCount;
|
||||
bool m_connected;
|
||||
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
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
// TcpServer.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "TcpClient.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <vector>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpServer::TcpServer(Service * service, const std::string & a, const unsigned short port) :
|
||||
m_bindAddress(a, port),
|
||||
m_handle(-1),
|
||||
m_service(service),
|
||||
m_connections(),
|
||||
m_connectionSockets(),
|
||||
m_inputBuffer(0),
|
||||
m_inputBufferSize(0)
|
||||
{
|
||||
protoent * p = getprotobyname("tcp");
|
||||
if(p)
|
||||
{
|
||||
int entry = p->p_proto;
|
||||
m_handle = socket(AF_INET, SOCK_STREAM, entry);
|
||||
FATAL(m_handle == -1, ("Failed to create a server socket %s:%d", a.c_str(), port));
|
||||
int optval = 1;
|
||||
if(m_handle != -1)
|
||||
{
|
||||
int optResult = setsockopt(m_handle, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
FATAL(optResult == -1, ("Failed to set socket option SO_REUSEADDR"));
|
||||
unsigned long nb = 1;
|
||||
int ctlResult = ioctl(m_handle, FIONBIO, &nb);
|
||||
FATAL(ctlResult == -1, ("Failed to set socket non-blocking"));
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
int bindResult = bind(m_handle, (struct sockaddr *)(&m_bindAddress.getSockAddr4()), addrlen);
|
||||
FATAL(bindResult != 0, ("Failed to bind to port %d", port));
|
||||
if(bindResult == 0)
|
||||
{
|
||||
int result = listen(m_handle, 256);
|
||||
if(result == -1)
|
||||
perror("listen ");
|
||||
FATAL(result == -1, ("Failed to start listening on port %d", port));
|
||||
struct sockaddr_in b;
|
||||
getsockname(m_handle, (struct sockaddr *)(&b), &addrlen);
|
||||
m_bindAddress = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpServer::~TcpServer()
|
||||
{
|
||||
close(m_handle);
|
||||
for (std::map<int, TcpClient *>::const_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||
(*i).second->clearTcpServer();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const std::string & TcpServer::getBindAddress() const
|
||||
{
|
||||
return m_bindAddress.getHostAddress();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned short TcpServer::getBindPort() const
|
||||
{
|
||||
return m_bindAddress.getHostPort();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpServer::onConnectionClosed(TcpClient * c)
|
||||
{
|
||||
if(c)
|
||||
{
|
||||
std::set<TcpClient *>::iterator f = m_pendingDestroys.find(c);
|
||||
if(f == m_pendingDestroys.end())
|
||||
{
|
||||
m_pendingDestroys.insert(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
void TcpServer::removeClient(TcpClient * c)
|
||||
{
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find(c->getSocket());
|
||||
if(f != m_connections.end())
|
||||
{
|
||||
// c->release();
|
||||
m_connections.erase(f);
|
||||
}
|
||||
|
||||
std::vector<pollfd>::iterator s;
|
||||
for(s = m_connectionSockets.begin(); s != m_connectionSockets.end(); ++s)
|
||||
{
|
||||
if((*s).fd == c->getSocket())
|
||||
{
|
||||
m_connectionSockets.erase(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpServer::update()
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_handle;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
|
||||
int result = poll(&pfd, 1, 0);
|
||||
if(result > 0)
|
||||
{
|
||||
// connection established
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
int newSock = accept(m_handle, (struct sockaddr *)(&addr), &len);
|
||||
if(newSock != -1)
|
||||
{
|
||||
TcpClient * ptc = new TcpClient(newSock, this);
|
||||
ptc->addRef();
|
||||
m_connections.insert(std::make_pair(newSock, ptc));
|
||||
struct pollfd readFd;
|
||||
readFd.fd = ptc->getSocket();
|
||||
readFd.events = POLLIN|POLLERR|POLLHUP;
|
||||
readFd.revents = 0;
|
||||
m_connectionSockets.push_back(readFd);
|
||||
ptc->onConnectionOpened();
|
||||
if(m_service)
|
||||
m_service->onConnectionOpened(ptc);
|
||||
ptc->release();
|
||||
}
|
||||
}
|
||||
|
||||
struct pollfd * clients = &m_connectionSockets[0];
|
||||
|
||||
int readResult = poll (clients, m_connectionSockets.size (), 0);
|
||||
if (readResult > 0)
|
||||
{
|
||||
std::vector<struct pollfd>::iterator i;
|
||||
std::vector<struct pollfd> cs = m_connectionSockets;
|
||||
for (i = cs.begin (); i != cs.end (); ++i)
|
||||
{
|
||||
if ((*i).revents & POLLERR)
|
||||
{
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
|
||||
if (f != m_connections.end ())
|
||||
{
|
||||
TcpClient * c = (*f).second;
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update POLLERR");
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
}
|
||||
// POLLERR is mutually exclusive with POLLIN and POLLHUP.
|
||||
// POLLIN and POLLHUP are not consistent cross-platform. Additionally,
|
||||
// a POLLHUP doesn't mean that there's not data available. The best,
|
||||
// cross-platform way to check for disconnection is to see if either
|
||||
// POLLHUP or POLLIN are set, and then read from the socket.
|
||||
// In cases where there's data, we'll just end up checking it next
|
||||
// frame anyway. In cases where there's no data, it means we've
|
||||
// disconnected so we can handle cleanup.
|
||||
else if( (*i).revents & (POLLIN|POLLHUP) )
|
||||
{
|
||||
|
||||
if (m_inputBuffer == 0)
|
||||
{
|
||||
m_inputBuffer = new unsigned char[1500];
|
||||
m_inputBufferSize = 1500;
|
||||
}
|
||||
int bytesReceived = recv ( (*i).fd, m_inputBuffer, m_inputBufferSize, 0);
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
|
||||
if (f != m_connections.end ())
|
||||
{
|
||||
TcpClient * c = (*f).second;
|
||||
std::set<TcpClient *>::iterator pd = m_pendingDestroys.find(c);
|
||||
if(pd == m_pendingDestroys.end())
|
||||
{
|
||||
c->addRef();
|
||||
if(bytesReceived > 0)
|
||||
{
|
||||
c->onReceive(m_inputBuffer, bytesReceived);
|
||||
}
|
||||
else if (bytesReceived == -1)
|
||||
{
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update recv returned %d, errno=%d", bytesReceived, errno);
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
else if (bytesReceived == 0)
|
||||
{
|
||||
// 0 bytes received on a read is the guaranteed signal for a
|
||||
// closed connection.
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update recv returned no bytes, singaling a closed socket (bytes=%d, errno=%d", bytesReceived, errno);
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
c->release();
|
||||
}
|
||||
}
|
||||
if (bytesReceived == m_inputBufferSize)
|
||||
{
|
||||
delete [] m_inputBuffer;
|
||||
m_inputBufferSize = m_inputBufferSize * 2;
|
||||
m_inputBuffer = new unsigned char [m_inputBufferSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
std::set<TcpClient *>::iterator pdIter;
|
||||
for(pdIter = m_pendingDestroys.begin(); pdIter != m_pendingDestroys.end(); ++pdIter)
|
||||
{
|
||||
removeClient((*pdIter));
|
||||
}
|
||||
m_pendingDestroys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// TcpServer.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpServer_H
|
||||
#define _INCLUDED_TcpServer_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "Address.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Service;
|
||||
class TcpClient;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpServer
|
||||
{
|
||||
public:
|
||||
TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort);
|
||||
~TcpServer();
|
||||
|
||||
const std::string & getBindAddress () const;
|
||||
const unsigned short getBindPort () const;
|
||||
void onConnectionClosed (TcpClient *);
|
||||
void removeClient (TcpClient *);
|
||||
void update ();
|
||||
|
||||
private:
|
||||
TcpServer & operator = (const TcpServer & rhs);
|
||||
TcpServer(const TcpServer & source);
|
||||
|
||||
private:
|
||||
Address m_bindAddress;
|
||||
int m_handle;
|
||||
Service * m_service;
|
||||
std::map<int, TcpClient *> m_connections;
|
||||
std::vector<struct pollfd> m_connectionSockets;
|
||||
unsigned char * m_inputBuffer;
|
||||
int m_inputBufferSize;
|
||||
std::set<TcpClient *> m_pendingDestroys;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpServer_H
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include <cassert>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include "sharedNetwork/UdpSock.h"
|
||||
|
||||
const int INVALID_SOCKET = 0xFFFFFFFF;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
UdpSock::UdpSock() :
|
||||
Sock()
|
||||
{
|
||||
handle = socket(AF_INET, SOCK_DGRAM, 17);
|
||||
assert(handle != INVALID_SOCKET);
|
||||
setNonBlocking();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
UdpSock::~UdpSock()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int UdpSock::recvFrom(Address & outAddr, void * targetBuffer, const unsigned int bufferSize) const
|
||||
{
|
||||
socklen_t 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;
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int UdpSock::sendTo(const Address & targetAddress, const void * sourceBuffer, const unsigned int length) const
|
||||
{
|
||||
unsigned int bytesSent = 0;
|
||||
if(canSend())
|
||||
{
|
||||
socklen_t toLen = sizeof(struct sockaddr_in);
|
||||
bytesSent = ::sendto(handle, sourceBuffer, static_cast<const int>(length), 0, reinterpret_cast<const struct sockaddr *>(&(targetAddress.getSockAddr4())), toLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
}
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpSock::enableBroadcast()
|
||||
{
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(int);
|
||||
setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &optval, optlen);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RegexServices.cpp
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedRegex/FirstSharedRegex.h"
|
||||
#include "sharedRegex/RegexServices.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void *RegexServices::allocateMemory(size_t byteCount)
|
||||
{
|
||||
return new char[byteCount];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void RegexServices::freeMemory(void *pointer)
|
||||
{
|
||||
delete [] reinterpret_cast<char *>(pointer);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1,25 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// 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
|
||||
@@ -1,38 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConditionVariable.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedSynchronization/ConditionVariable.h"
|
||||
|
||||
ConditionVariable::ConditionVariable(Mutex &m)
|
||||
: _mutex(m)
|
||||
{
|
||||
pthread_cond_init(&cond, 0);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable()
|
||||
{
|
||||
pthread_cond_destroy(&cond);
|
||||
}
|
||||
|
||||
void ConditionVariable::wait()
|
||||
{
|
||||
pthread_cond_wait(&cond, &_mutex.getInternalMutex());
|
||||
}
|
||||
|
||||
void ConditionVariable::signal()
|
||||
{
|
||||
pthread_cond_signal(&cond);
|
||||
}
|
||||
|
||||
void ConditionVariable::broadcast()
|
||||
{
|
||||
pthread_cond_broadcast(&cond);
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConditionVariable.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_ConditionVariable_h
|
||||
#define INCLUDED_ConditionVariable_h
|
||||
|
||||
#include "sharedSynchronization/Mutex.h"
|
||||
|
||||
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);
|
||||
|
||||
Mutex &_mutex;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Gate.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedSynchronization/Gate.h"
|
||||
|
||||
Gate::Gate(bool open)
|
||||
: cond(lock)
|
||||
{
|
||||
opened = open;
|
||||
}
|
||||
|
||||
Gate::~Gate()
|
||||
{
|
||||
}
|
||||
|
||||
void Gate::wait()
|
||||
{
|
||||
lock.enter();
|
||||
while (!opened)
|
||||
cond.wait();
|
||||
lock.leave();
|
||||
}
|
||||
|
||||
void Gate::close()
|
||||
{
|
||||
lock.enter();
|
||||
opened = false;
|
||||
lock.leave();
|
||||
}
|
||||
|
||||
void Gate::open()
|
||||
{
|
||||
lock.enter();
|
||||
opened = true;
|
||||
cond.broadcast();
|
||||
lock.leave();
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Gate.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Gate_h
|
||||
#define INCLUDED_Gate_h
|
||||
|
||||
#include "sharedSynchronization/ConditionVariable.h"
|
||||
|
||||
class Gate
|
||||
{
|
||||
public:
|
||||
Gate(bool open);
|
||||
~Gate();
|
||||
|
||||
void wait();
|
||||
|
||||
void close();
|
||||
void open();
|
||||
private:
|
||||
Gate(const Gate &o);
|
||||
Gate &operator =(const Gate &o);
|
||||
|
||||
Mutex lock;
|
||||
bool opened;
|
||||
ConditionVariable cond;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// 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 value; }
|
||||
private:
|
||||
InterlockedInteger(const InterlockedInteger &o);
|
||||
InterlockedInteger &operator =(const InterlockedInteger &o);
|
||||
pthread_mutex_t lock;
|
||||
volatile int value;
|
||||
};
|
||||
|
||||
inline InterlockedInteger::InterlockedInteger(int i_value)
|
||||
: value(i_value)
|
||||
{
|
||||
pthread_mutex_init(&lock, 0);
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator =(int i_value)
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
int oldvalue = value;
|
||||
value = i_value;
|
||||
pthread_mutex_unlock(&lock);
|
||||
return oldvalue;
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator ++()
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
int newvalue = value+1;
|
||||
value = newvalue;
|
||||
pthread_mutex_unlock(&lock);
|
||||
return newvalue;
|
||||
}
|
||||
|
||||
inline int InterlockedInteger::operator --()
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
int newvalue = value-1;
|
||||
value = newvalue;
|
||||
pthread_mutex_unlock(&lock);
|
||||
return newvalue;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// InterlockedVoidPointer.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_InterlockedVoidPointer_h
|
||||
#define INCLUDED_InterlockedVoidPointer_h
|
||||
|
||||
#include "sharedSynchronization/Mutex.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);
|
||||
Mutex lock;
|
||||
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)
|
||||
{
|
||||
lock.enter();
|
||||
void * temp = value;
|
||||
if (temp == compare)
|
||||
value = exchange;
|
||||
lock.leave();
|
||||
return temp;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Mutex.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedSynchronization/Mutex.h"
|
||||
|
||||
Mutex::Mutex()
|
||||
{
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
void Mutex::enter()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
|
||||
void Mutex::leave()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Mutex.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Mutex_h
|
||||
#define INCLUDED_Mutex_h
|
||||
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void enter();
|
||||
void leave();
|
||||
|
||||
pthread_mutex_t &getInternalMutex() { return mutex; }
|
||||
private:
|
||||
Mutex(const Mutex &o);
|
||||
Mutex &operator =(const Mutex &o);
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RecursiveMutex.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedSynchronization/RecursiveMutex.h"
|
||||
|
||||
RecursiveMutex::RecursiveMutex()
|
||||
{
|
||||
pthread_mutexattr_t attributes;
|
||||
|
||||
pthread_mutexattr_init(&attributes);
|
||||
pthread_mutexattr_settype(&attributes,PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mutex,&attributes);
|
||||
pthread_mutexattr_destroy(&attributes);
|
||||
}
|
||||
|
||||
RecursiveMutex::~RecursiveMutex()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
void RecursiveMutex::enter()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
|
||||
void RecursiveMutex::leave()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// RecursiveMutex.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_RecursiveMutex_h
|
||||
#define INCLUDED_RecursiveMutex_h
|
||||
|
||||
#include "sharedSynchronization/InterlockedInteger.h"
|
||||
|
||||
class RecursiveMutex
|
||||
{
|
||||
public:
|
||||
RecursiveMutex();
|
||||
~RecursiveMutex();
|
||||
|
||||
void enter();
|
||||
void leave();
|
||||
private:
|
||||
RecursiveMutex(const RecursiveMutex &o);
|
||||
RecursiveMutex &operator =(const RecursiveMutex &o);
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Semaphore.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedSynchronization/Semaphore.h"
|
||||
|
||||
Semaphore::Semaphore(int count, int initial)
|
||||
{
|
||||
sem_init(&sem, false, initial);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
|
||||
void Semaphore::wait()
|
||||
{
|
||||
sem_wait(&sem);
|
||||
}
|
||||
|
||||
void Semaphore::wait(unsigned int maxDurationMs)
|
||||
{
|
||||
timespec ts;
|
||||
ts.tv_sec = maxDurationMs/1000000;
|
||||
ts.tv_nsec = maxDurationMs%1000000;
|
||||
sem_timedwait(&sem, &ts);
|
||||
}
|
||||
|
||||
void Semaphore::signal(int count)
|
||||
{
|
||||
sem_post(&sem);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Semaphore.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Semaphore_h
|
||||
#define INCLUDED_Semaphore_h
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(int count=0x7FFFFFFF, int initial=0);
|
||||
~Semaphore();
|
||||
|
||||
void wait();
|
||||
void wait(unsigned int maxDurationMs);
|
||||
void signal(int count=1);
|
||||
private:
|
||||
Semaphore(const Semaphore &o);
|
||||
Semaphore &operator =(const Semaphore &o);
|
||||
|
||||
sem_t sem;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
#include "sharedTemplateDefinition/FirstSharedTemplateDefinition.h"
|
||||
@@ -1,159 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Thread.cpp
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedThread/Thread.h"
|
||||
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedFoundation/PerThreadData.h"
|
||||
#include <cstdio>
|
||||
|
||||
class MainThread: public Thread
|
||||
{
|
||||
public:
|
||||
MainThread(const std::string &name): Thread(name) {}
|
||||
protected:
|
||||
void run() {}
|
||||
private:
|
||||
MainThread(const MainThread &o);
|
||||
MainThread &operator =(const MainThread &o);
|
||||
};
|
||||
|
||||
pthread_key_t Thread::implindex;
|
||||
Thread * Thread::mainThread;
|
||||
|
||||
void Thread::install()
|
||||
{
|
||||
DEBUG_FATAL(mainThread, ("Thread::install: already installed"));
|
||||
ExitChain::add(remove, "Thread::remove");
|
||||
|
||||
pthread_key_create(&implindex, 0);
|
||||
mainThread = new MainThread("Main");
|
||||
mainThread->attach();
|
||||
}
|
||||
|
||||
void Thread::remove()
|
||||
{
|
||||
DEBUG_FATAL(!mainThread, ("Thread::remove: not installed"));
|
||||
DEBUG_FATAL(mainThread->refcount > 1, ("Someone still holds the main thread"));
|
||||
delete mainThread;
|
||||
pthread_key_delete(implindex);
|
||||
|
||||
mainThread = 0;
|
||||
}
|
||||
|
||||
Thread::Thread(const std::string &i_name)
|
||||
: refcount(1), name(i_name)
|
||||
{
|
||||
doneFlag = false;
|
||||
}
|
||||
|
||||
void Thread::start()
|
||||
{
|
||||
pthread_create(&thread, 0, threadFunc, this);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
}
|
||||
|
||||
void Thread::attach()
|
||||
{
|
||||
thread = pthread_self();
|
||||
pthread_setspecific(implindex, this);
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
pthread_detach(thread);
|
||||
}
|
||||
|
||||
void * Thread::threadFunc(void * i)
|
||||
{
|
||||
Thread * impl = static_cast<Thread *>(i);
|
||||
pthread_setspecific(implindex, impl);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
Os::setThreadName(impl->thread, impl->name.c_str());
|
||||
PerThreadData::threadInstall(true);
|
||||
impl->run();
|
||||
PerThreadData::threadRemove();
|
||||
impl->kill();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::kill()
|
||||
{
|
||||
int t = getCurrentThread()->thread;
|
||||
doneFlag = true;
|
||||
deref();
|
||||
if (this == getCurrentThread())
|
||||
{
|
||||
pthread_exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_cancel(t);
|
||||
}
|
||||
}
|
||||
|
||||
bool Thread::done()
|
||||
{
|
||||
return doneFlag;
|
||||
}
|
||||
|
||||
void Thread::wait()
|
||||
{
|
||||
if (!doneFlag)
|
||||
{
|
||||
void * junk;
|
||||
pthread_join(thread, &junk);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int interpPriority(float t, int policy)
|
||||
{
|
||||
return (int)(sched_get_priority_max(policy)*t + sched_get_priority_min(policy)*(1-t));
|
||||
}
|
||||
|
||||
void Thread::setPriority(ePriority priority)
|
||||
{
|
||||
static int policies[] =
|
||||
{
|
||||
SCHED_OTHER,
|
||||
SCHED_OTHER,
|
||||
SCHED_OTHER,
|
||||
SCHED_OTHER,
|
||||
SCHED_FIFO
|
||||
};
|
||||
static int priorities[] =
|
||||
{
|
||||
interpPriority(0.0, SCHED_OTHER),
|
||||
interpPriority(0.25, SCHED_OTHER),
|
||||
interpPriority(0.5, SCHED_OTHER),
|
||||
interpPriority(0.75, SCHED_OTHER),
|
||||
interpPriority(0.75, SCHED_FIFO)
|
||||
};
|
||||
sched_param p;
|
||||
p.sched_priority = priorities[priority];
|
||||
pthread_setschedparam(thread, policies[priority], &p);
|
||||
}
|
||||
|
||||
// Make sure the header-only files compile :)
|
||||
|
||||
#if 0
|
||||
|
||||
#include "sharedSynchronization/CountingSemaphore.h"
|
||||
#include "sharedSynchronization/BlockingPointer.h"
|
||||
#include "sharedSynchronization/BlockingQueue.h"
|
||||
#include "sharedSynchronization/WriteOnce.h"
|
||||
|
||||
Mutex t;
|
||||
BlockingQueue<int> bqint(t, 0, 0);
|
||||
BlockingPointer<int> bpint(t, 0, 0);
|
||||
WriteOnce<int> woint;
|
||||
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Thread.h
|
||||
// Acy Stapp
|
||||
//
|
||||
// Copyright 6/19/2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Thread_h
|
||||
#define INCLUDED_Thread_h
|
||||
|
||||
#include "sharedSynchronization/InterlockedInteger.h"
|
||||
#include <string>
|
||||
|
||||
class Thread
|
||||
{
|
||||
template <class T> friend class TypedThreadHandle;
|
||||
public:
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
Thread(const std::string &i_name=std::string());
|
||||
|
||||
void kill();
|
||||
bool done();
|
||||
void wait();
|
||||
|
||||
enum ePriority
|
||||
{
|
||||
kIdle = 0,
|
||||
kLow = 1,
|
||||
kNormal = 2,
|
||||
kHigh = 3,
|
||||
kCritical = 4
|
||||
};
|
||||
void setPriority(ePriority priority);
|
||||
|
||||
const std::string &getName() const;
|
||||
void setName(const std::string &i_name);
|
||||
|
||||
static Thread * getCurrentThread();
|
||||
static Thread * getMainThread();
|
||||
protected:
|
||||
virtual ~Thread();
|
||||
virtual void run()=0;
|
||||
|
||||
pthread_t thread;
|
||||
|
||||
InterlockedInteger refcount;
|
||||
private:
|
||||
Thread(const Thread &o);
|
||||
Thread &operator =(const Thread &o);
|
||||
|
||||
void start();
|
||||
void attach(); // pick up the currently running thread
|
||||
|
||||
void ref();
|
||||
void deref();
|
||||
|
||||
bool doneFlag;
|
||||
|
||||
std::string name;
|
||||
|
||||
static pthread_key_t implindex;
|
||||
static Thread * mainThread;
|
||||
static void * threadFunc(void * data);
|
||||
};
|
||||
|
||||
inline void Thread::ref()
|
||||
{
|
||||
++refcount;
|
||||
}
|
||||
|
||||
inline void Thread::deref()
|
||||
{
|
||||
if (--refcount == 0) delete this;
|
||||
}
|
||||
|
||||
inline Thread * Thread::getCurrentThread()
|
||||
{
|
||||
return static_cast<Thread *>(pthread_getspecific(implindex));
|
||||
}
|
||||
|
||||
inline Thread * Thread::getMainThread()
|
||||
{
|
||||
return mainThread;
|
||||
}
|
||||
|
||||
inline const std::string &Thread::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
inline void Thread::setName(const std::string &i_name)
|
||||
{
|
||||
name = i_name;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user