diff --git a/common/const.h b/common/const.h index bffcebc7..fe4469fa 100644 --- a/common/const.h +++ b/common/const.h @@ -14,9 +14,6 @@ ****/ #ifndef CONST_H #define CONST_H - -#include // ptrdiff_t - // // Constants shared by the engine and dlls // This header file included by engine files and DLL files. @@ -724,7 +721,7 @@ enum }; typedef int func_t; -typedef ptrdiff_t string_t; +typedef int string_t; typedef unsigned short word; diff --git a/engine/common/lib_common.c b/engine/common/lib_common.c index c4ff6cb1..7c4fb8aa 100644 --- a/engine/common/lib_common.c +++ b/engine/common/lib_common.c @@ -126,20 +126,14 @@ dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath ) ============================================================================= */ -static void COM_GenerateCommonLibraryName( const char *name, const char *ext, const char *suffix, char *out, size_t size ) +static void COM_GenerateCommonLibraryName( const char *name, const char *ext, char *out, size_t size ) { #if ( XASH_WIN32 || XASH_LINUX || XASH_APPLE ) && XASH_X86 - if( suffix ) - Q_snprintf( out, size, "%s_%s.%s", name, suffix, ext ); - else Q_snprintf( out, size, "%s.%s", name, ext ); + Q_snprintf( out, size, "%s.%s", name, ext ); #elif ( XASH_WIN32 || XASH_LINUX || XASH_APPLE ) - if( suffix ) - Q_snprintf( out, size, "%s_%s_%s.%s", name, Q_buildarch(), suffix, ext ); - else Q_snprintf( out, size, "%s_%s.%s", name, Q_buildarch(), ext ); + Q_snprintf( out, size, "%s_%s.%s", name, Q_buildarch(), ext ); #else - if( suffix ) - Q_snprintf( out, size, "%s_%s_%s_%s.%s", name, Q_buildos(), Q_buildarch(), suffix, ext ); - else Q_snprintf( out, size, "%s_%s_%s.%s", name, Q_buildos(), Q_buildarch(), ext ); + Q_snprintf( out, size, "%s_%s_%s.%s", name, Q_buildos(), Q_buildarch(), ext ); #endif } @@ -160,7 +154,7 @@ static void COM_GenerateClientLibraryPath( const char *name, char *out, size_t s // we don't have any library prefixes, so we can safely append dll_path here Q_snprintf( dllpath, sizeof( dllpath ), "%s/%s", GI->dll_path, name ); - COM_GenerateCommonLibraryName( dllpath, OS_LIB_EXT, NULL, out, size ); + COM_GenerateCommonLibraryName( dllpath, OS_LIB_EXT, out, size ); #endif } @@ -217,13 +211,7 @@ static void COM_GenerateServerLibraryPath( char *out, size_t size ) COM_StripExtension( dllpath ); COM_StripIntelSuffix( dllpath ); -#if XASH_ARCH_USES_ONLY_ABI2 - COM_GenerateCommonLibraryName( dllpath, ext, NULL, out, size ); -#elif XASH_64BIT - COM_GenerateCommonLibraryName( dllpath, ext, "st64", out, size ); -#else - COM_GenerateCommonLibraryName( dllpath, ext, NULL, out, size ); -#endif + COM_GenerateCommonLibraryName( dllpath, ext, out, size ); #endif } diff --git a/engine/eiface.h b/engine/eiface.h index 3bda3265..e18cdedb 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -125,7 +125,7 @@ typedef struct enginefuncs_s void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up ); edict_t* (*pfnCreateEntity)( void ); void (*pfnRemoveEntity)( edict_t* e ); - edict_t* (*pfnCreateNamedEntity)( string_t className ); + edict_t* (*pfnCreateNamedEntity)( int className ); void (*pfnMakeStatic)( edict_t *ent ); int (*pfnEntIsOnFloor)( edict_t *e ); int (*pfnDropToFloor)( edict_t* e ); @@ -168,8 +168,8 @@ typedef struct enginefuncs_s void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); void* (*pfnPvEntPrivateData)( edict_t *pEdict ); void (*pfnFreeEntPrivateData)( edict_t *pEdict ); - const char *(*pfnSzFromIndex)( string_t iString ); - string_t (*pfnAllocString)( const char *szValue ); + const char *(*pfnSzFromIndex)( int iString ); + int (*pfnAllocString)( const char *szValue ); struct entvars_s *(*pfnGetVarsOfEnt)( edict_t *pEdict ); edict_t* (*pfnPEntityOfEntOffset)( int iEntOffset ); int (*pfnEntOffsetOfPEntity)( const edict_t *pEdict ); diff --git a/engine/progdefs.h b/engine/progdefs.h index fb636827..2a0e133b 100644 --- a/engine/progdefs.h +++ b/engine/progdefs.h @@ -85,8 +85,8 @@ typedef struct entvars_s int modelindex; string_t model; - string_t viewmodel; // player's viewmodel - string_t weaponmodel; // what other players see + int viewmodel; // player's viewmodel + int weaponmodel; // what other players see vec3_t absmin; // BB max translated to world coord vec3_t absmax; // BB max translated to world coord @@ -144,7 +144,7 @@ typedef struct entvars_s int flags; int colormap; // lowbyte topcolor, highbyte bottomcolor - string_t team; + int team; float max_health; float teleport_time; diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index f424656a..29d53549 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -3000,6 +3000,25 @@ static void *GAME_EXPORT pfnPvEntPrivateData( edict_t *pEdict ) } +#ifdef XASH_64BIT +static struct str64_s +{ + size_t maxstringarray; + qboolean allowdup; + char *staticstringarray; + char *pstringarray; + char *pstringarraystatic; + char *pstringbase; + char *poldstringbase; + char *plast; + qboolean dynamic; + size_t maxalloc; + size_t numdups; + size_t numoverflows; + size_t totalalloc; +} str64; +#endif + /* ================== SV_EmptyStringPool @@ -3009,7 +3028,17 @@ Free strings on server stop. Reset string pointer on 64 bits */ void SV_EmptyStringPool( void ) { +#ifdef XASH_64BIT + if( str64.dynamic ) // switch only after array fill (more space for multiplayer games) + str64.pstringbase = str64.pstringarray; + else + { + str64.pstringbase = str64.poldstringbase = str64.pstringarraystatic; + str64.plast = str64.pstringbase + 1; + } +#else Mem_EmptyPool( svgame.stringspool ); +#endif } /* @@ -3023,8 +3052,23 @@ this helps not to lose strings that belongs to static game part */ void SV_SetStringArrayMode( qboolean dynamic ) { +#ifdef XASH_64BIT + Con_Reportf( "%s(%d) %d\n", __func__, dynamic, str64.dynamic ); + + if( dynamic == str64.dynamic ) + return; + + str64.dynamic = dynamic; + + SV_EmptyStringPool(); +#endif } +#if XASH_AMD64 && XASH_LINUX && !XASH_ANDROID +#define USE_MMAP +#include +#endif + /* ================== SV_AllocStringPool @@ -3037,13 +3081,104 @@ this case need patched game dll with MAKE_STRING checking ptrdiff size */ static void SV_AllocStringPool( void ) { +#ifdef XASH_64BIT + void *ptr = NULL; + string lenstr; + + Con_Reportf( "%s()\n", __func__ ); + if( Sys_GetParmFromCmdLine( "-str64alloc", lenstr ) ) + { + str64.maxstringarray = Q_atoi( lenstr ); + if( str64.maxstringarray < 1024 || str64.maxstringarray >= INT_MAX ) + str64.maxstringarray = 65536; + } + else str64.maxstringarray = 65536; + if( Sys_CheckParm( "-str64dup" ) ) + str64.allowdup = true; + +#ifdef USE_MMAP + { + uint flags; + size_t pagesize = sysconf( _SC_PAGESIZE ); + int arrlen = (str64.maxstringarray * 2) & ~(pagesize - 1); + void *base = svgame.dllFuncs.pfnGameInit; + void *start = svgame.hInstance - arrlen; + +#if defined(MAP_ANON) + flags = MAP_ANON | MAP_PRIVATE; +#elif defined(MAP_ANONYMOUS) + flags = MAP_ANONYMOUS | MAP_PRIVATE; +#endif + + while( start - base > INT_MIN ) + { + void *mapptr = mmap((void*)((unsigned long)start & ~(pagesize - 1)), arrlen, PROT_READ | PROT_WRITE, flags, 0, 0 ); + if( mapptr && mapptr != (void*)-1 && mapptr - base > INT_MIN && mapptr - base < INT_MAX ) + { + ptr = mapptr; + break; + } + if( mapptr ) munmap( mapptr, arrlen ); + start -= arrlen; + } + + if( !ptr ) + { + start = base; + while( start - base < INT_MAX ) + { + void *mapptr = mmap((void*)((unsigned long)start & ~(pagesize - 1)), arrlen, PROT_READ | PROT_WRITE, flags, 0, 0 ); + if( mapptr && mapptr != (void*)-1 && mapptr - base > INT_MIN && mapptr - base < INT_MAX ) + { + ptr = mapptr; + break; + } + if( mapptr ) munmap( mapptr, arrlen ); + start += arrlen; + } + } + + + if( ptr ) + { + Con_Reportf( "%s: Allocated string array near the server library: %p %p\n", __func__, base, ptr ); + + } + else + { + Con_Reportf( "%s: Failed to allocate string array near the server library!\n", __func__ ); + ptr = str64.staticstringarray = Mem_Calloc( host.mempool, str64.maxstringarray * 2 ); + } + } +#else + ptr = str64.staticstringarray = Mem_Calloc( host.mempool, str64.maxstringarray * 2 ); +#endif + + str64.pstringarray = ptr; + str64.pstringarraystatic = (byte*)ptr + str64.maxstringarray; + str64.pstringbase = str64.poldstringbase = ptr; + str64.plast = (byte*)ptr + 1; + svgame.globals->pStringBase = ptr; +#else svgame.stringspool = Mem_AllocPool( "Server Strings" ); svgame.globals->pStringBase = ""; +#endif } static void SV_FreeStringPool( void ) { +#ifdef XASH_64BIT + Con_Reportf( "%s()\n", __func__ ); + +#ifdef USE_MMAP + if( str64.pstringarray != str64.staticstringarray ) + munmap( str64.pstringarray, (str64.maxstringarray * 2) & ~(sysconf( _SC_PAGESIZE ) - 1) ); + else +#endif + Mem_Free( str64.staticstringarray ); +#else Mem_FreePool( &svgame.stringspool ); +#endif } /* @@ -3114,6 +3249,9 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue ) { char *newString = NULL; uint len; +#ifdef XASH_64BIT + int cmp; +#endif if( svgame.physFuncs.pfnAllocString != NULL ) { @@ -3129,16 +3267,67 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue ) return i; } +#ifdef XASH_64BIT + cmp = 1; + + if( !str64.allowdup ) + { + for( newString = str64.poldstringbase + 1; + newString < str64.plast && ( cmp = Q_strcmp( newString, szValue ) ); + newString += Q_strlen( newString ) + 1 ); + } + + if( cmp ) + { + uint len = SV_ProcessString( NULL, szValue ); + + if( str64.plast - str64.poldstringbase + len + 1 > str64.maxstringarray ) + { + str64.plast = str64.pstringbase + 1; + str64.poldstringbase = str64.pstringbase; + str64.numoverflows++; + } + + //MsgDev( D_NOTE, "SV_AllocString: %ld %s\n", str64.plast - svgame.globals->pStringBase, szValue ); + SV_ProcessString( str64.plast, szValue ); + str64.totalalloc += len; + + newString = str64.plast; + str64.plast += len; + } + else + { + str64.numdups++; + //MsgDev( D_NOTE, "SV_AllocString: dup %ld %s\n", newString - svgame.globals->pStringBase, szValue ); + } + + if( newString - str64.pstringarray > str64.maxalloc ) + str64.maxalloc = newString - str64.pstringarray; + + return newString - svgame.globals->pStringBase; +#else len = SV_ProcessString( NULL, szValue ); newString = Mem_Malloc( svgame.stringspool, len ); SV_ProcessString( newString, szValue ); return newString - svgame.globals->pStringBase; +#endif } void SV_PrintStr64Stats_f( void ) { +#ifdef XASH_64BIT + Con_Printf( "====================\n" ); + Con_Printf( "64 bit string pool statistics\n" ); + Con_Printf( "====================\n" ); + Con_Printf( "string array size: %lu\n", str64.maxstringarray ); + Con_Printf( "total alloc %lu\n", str64.totalalloc ); + Con_Printf( "maximum array usage: %lu\n", str64.maxalloc ); + Con_Printf( "overflow counter: %lu\n", str64.numoverflows ); + Con_Printf( "dup string counter: %lu\n", str64.numdups ); +#else Con_Printf( "Not implemented\n" ); +#endif } /* @@ -3152,8 +3341,17 @@ string_t SV_MakeString( const char *szValue ) { if( svgame.physFuncs.pfnMakeString != NULL ) return svgame.physFuncs.pfnMakeString( szValue ); - +#ifdef XASH_64BIT + { + long long ptrdiff = szValue - svgame.globals->pStringBase; + if( ptrdiff > INT_MAX || ptrdiff < INT_MIN ) + return SV_AllocString(szValue); + else + return (int)ptrdiff; + } +#else return szValue - svgame.globals->pStringBase; +#endif } /*