sv_restartProcess restarts the child process

uptime print child process, parent process and map uptimes
This commit is contained in:
myT 2017-10-12 03:45:24 +02:00
parent 484e9e7e40
commit 9a7ab19245
7 changed files with 199 additions and 1 deletions

View file

@ -1,6 +1,8 @@
DD Mmm 17 - 1.49
add: uptime command that prints uptimes for the process, the current map and the parent process
add: keys F13 to F24 are now bindable
add: new cvar type and range extension for compatible mods like CPMA 1.50
@ -142,6 +144,7 @@ Linux:
add: automatic dedicated server process restarts for crashes and timed reboots (sv_minRebootDelayMins)
this means 2 CNQ3 processes run per server: a parent (fixed pid) and a child (new pid after each restart)
this behavior can be disabled by passing "nohardreboot" as a command-line argument
the new command sv_restartProcess can be used to shut down the child process and start a new one
fix: color codes (e.g. "^1") don't get printed to the terminal anymore

View file

@ -1106,6 +1106,9 @@ qbool Sys_LowPhysicalMemory( void );
qbool Sys_HardReboot(); // qtrue when the server can restart itself
qbool Sys_HasCNQ3Parent(); // qtrue if a child of CNQ3
int Sys_GetUptimeSeconds( qbool parent ); // negative if not available
// huffman.cpp - id's original code
// used for out-of-band (OOB) datagrams with dynamically created trees
void DynHuff_Compress( msg_t* buf, int offset );

View file

@ -77,6 +77,8 @@ struct server_t {
int gameClientSize; // will be > sizeof(playerState_t) due to game private data
int restartTime;
int mapLoadTime;
};

View file

@ -695,6 +695,65 @@ static void SV_ServerRestart_f()
}
static void SV_RestartProcess_f()
{
if ( !Sys_HasCNQ3Parent() ) {
Com_Printf( "this server isn't controlled by a parent CNQ3 process\n" );
return;
}
Com_Quit(1);
}
static const char* SV_FormatUptime( int seconds )
{
static char result[32];
static const int unitCount = 4;
static const char* units[unitCount] = { "s", "m", "h", "d" };
static const int divisors[unitCount] = { 1, 60, 60, 24 };
if ( seconds <= 0 )
return "nada";
int uptime[unitCount] = { seconds, 0, 0, 0 };
for ( int i = 1; i < unitCount; ++i ) {
uptime[i] = uptime[i-1] / divisors[i];
uptime[i-1] -= uptime[i] * divisors[i];
}
result[0] = '\0';
for ( int i = unitCount - 1; i >= 0; --i ) {
if ( uptime[i] <= 0 )
continue;
Q_strcat( result, sizeof( result ), va( "%d%s", uptime[i], units[i] ) );
if ( i > 0 && uptime[i-1] > 0 )
Q_strcat( result, sizeof( result ), " " );
}
return result;
}
static void SV_Uptime_f()
{
if (Sys_HasCNQ3Parent()) {
const int parentTime = Sys_GetUptimeSeconds( qtrue );
Com_Printf( "Parent process : %s\n", parentTime >= 0 ? SV_FormatUptime(parentTime) : "unknown" );
}
const int childTime = Sys_GetUptimeSeconds( qfalse );
Com_Printf( "This process : %s\n", childTime >= 0 ? SV_FormatUptime(childTime) : "unknown" );
int mapTime = -1;
if ( Cvar_VariableIntegerValue( "sv_running" ) )
mapTime = ( Sys_Milliseconds() - sv.mapLoadTime ) / 1000;
Com_Printf( "Current map : %s\n", mapTime >= 0 ? SV_FormatUptime(mapTime) : "no map loaded" );
}
static const cmdTableItem_t sv_cmds[] =
{
{ "heartbeat", SV_Heartbeat_f, NULL, "sends a heartbeat to master servers" },
@ -711,7 +770,9 @@ static const cmdTableItem_t sv_cmds[] =
{ "map", SV_Map_f, SV_CompleteMap_f, "loads a map" },
{ "devmap", SV_DevMap_f, SV_CompleteMap_f, "loads a map with cheats enabled" },
{ "killserver", SV_KillServer_f, NULL, "shuts the server down" },
{ "sv_restart", SV_ServerRestart_f, NULL, "restarts the server" }
{ "sv_restart", SV_ServerRestart_f, NULL, "restarts the server" },
{ "sv_restartProcess", SV_RestartProcess_f, NULL, "restarts the server's child process" },
{ "uptime", SV_Uptime_f, NULL, "prints the server's uptimes" }
};

View file

@ -522,6 +522,8 @@ void SV_SpawnServer( const char* mapname )
Hunk_SetMark();
sv.mapLoadTime = Sys_Milliseconds();
QSUBSYSTEM_INIT_DONE( "Server" );
}

View file

@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <string.h>
#include <ctype.h>
#include <sys/wait.h>
@ -909,6 +910,96 @@ static void Lin_HardRebootHandler( int argc, char** argv )
#endif
static qbool lin_hasParent = qfalse;
static pid_t lix_parentPid;
static const char* Lin_GetExeName(const char* path)
{
const char* lastSlash = strrchr(path, '/');
if (lastSlash == NULL)
return path;
return lastSlash + 1;
}
static void Lin_TrackParentProcess()
{
static char cmdLine[1024];
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%d/cmdline", (int)getppid());
const int fd = open(fileName, O_RDONLY);
if (fd == -1)
return;
const qbool hasCmdLine = read(fd, cmdLine, sizeof(cmdLine)) > 0;
close(fd);
if (!hasCmdLine)
return;
cmdLine[sizeof(cmdLine) - 1] = '\0';
lin_hasParent = strcmp(Lin_GetExeName(cmdLine), Lin_GetExeName(q_argv[0])) == 0;
}
qbool Sys_HasCNQ3Parent()
{
return lin_hasParent;
}
static int Sys_GetProcessUptime( pid_t pid )
{
// length must be in sync with the fscanf call!
static char word[256];
// The process start time is the 22nd column and
// encoded as jiffies after system boot.
const int jiffiesPerSec = sysconf(_SC_CLK_TCK);
if (jiffiesPerSec <= 0)
return -1;
char fileName[128];
Com_sprintf(fileName, sizeof(fileName), "/proc/%ld/stat", (long)pid);
FILE* const file = fopen(fileName, "r");
if (file == NULL)
return -1;
for (int i = 0; i < 21; ++i) {
if (fscanf(file, "%255s", word) != 1) {
fclose(file);
return -1;
}
}
int jiffies;
const qbool success = fscanf(file, "%d", &jiffies) == 1;
fclose(file);
if (!success)
return -1;
const int secondsSinceBoot = jiffies / jiffiesPerSec;
struct sysinfo info;
sysinfo(&info);
return (int)info.uptime - secondsSinceBoot;
}
int Sys_GetUptimeSeconds( qbool parent )
{
if (!lin_hasParent)
return -1;
return Sys_GetProcessUptime( parent ? getppid() : getpid() );
}
int main( int argc, char** argv )
{
q_argc = argc;
@ -938,6 +1029,7 @@ int main( int argc, char** argv )
Com_Printf( "Working directory: %s\n", Sys_Cwd() );
Sys_ConsoleInputInit();
Lin_TrackParentProcess();
for (;;) {
SIG_Frame();

View file

@ -47,3 +47,38 @@ qbool Sys_HardReboot()
return qfalse;
}
qbool Sys_HasCNQ3Parent()
{
return qfalse;
}
int Sys_GetUptimeSeconds( qbool parent )
{
if (parent)
return -1;
FILETIME startFileTime;
FILETIME trash[3];
if (GetProcessTimes(GetCurrentProcess(), &startFileTime, &trash[0], &trash[1], &trash[2]) == 0)
return -1;
SYSTEMTIME endSystemTime;
GetSystemTime(&endSystemTime);
FILETIME endFileTime;
if (SystemTimeToFileTime(&endSystemTime, &endFileTime) == 0)
return -1;
// 1 FILETIME unit is 100-nanoseconds
ULARGE_INTEGER start, end;
start.LowPart = startFileTime.dwLowDateTime;
start.HighPart = startFileTime.dwHighDateTime;
end.LowPart = endFileTime.dwLowDateTime;
end.HighPart = endFileTime.dwHighDateTime;
const int seconds = (int)((end.QuadPart - start.QuadPart) / 1e7);
return seconds;
}