From 16c87ae2c93cf4c9de43871d0aae8c626d6ae69c Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 16 Jun 2023 08:43:16 +0300 Subject: [PATCH] engine: platform: reorganize UpdateStatusLine, make it shared but implemented only if platform has SetStatus. Implement SetStatus for systemd/Linux --- engine/platform/linux/sys_linux.c | 53 +++++++++++++++++++++++++++++++ engine/platform/platform.h | 28 ++++++++++++---- engine/platform/win32/con_win.c | 6 ++-- engine/platform/win32/sys_win.c | 21 ------------ engine/server/sv_main.c | 43 +++++++++++++++++++++++-- 5 files changed, 117 insertions(+), 34 deletions(-) diff --git a/engine/platform/linux/sys_linux.c b/engine/platform/linux/sys_linux.c index 23d0aa13..0734dbc3 100644 --- a/engine/platform/linux/sys_linux.c +++ b/engine/platform/linux/sys_linux.c @@ -16,8 +16,12 @@ GNU General Public License for more details. #include #include #include +#include #include "platform/platform.h" +static void *g_hsystemd; +static int (*g_pfn_sd_notify)( int unset_environment, const char *state ); + qboolean Sys_DebuggerPresent( void ) { char buf[4096]; @@ -50,3 +54,52 @@ qboolean Sys_DebuggerPresent( void ) return false; } + +void Platform_SetStatus( const char *status ) +{ + string notify_str; + + if( !g_pfn_sd_notify ) + return; + + // TODO: report STOPPING=1 + Q_snprintf( notify_str, sizeof( notify_str ), + "READY=1\n" + "WATCHDOG=1\n" + "STATUS=%s\n", status ); + + // Quote: In order to support both service managers that implement this + // scheme and those which do not, it is generally recommended to ignore + // the return value of this call + // a1ba: ok, you asked for no error handling :) + g_pfn_sd_notify( false, notify_str ); +} + +void Linux_Init( void ) +{ + // sd_notify only for dedicated targets, don't waste time on full client + if( !Host_IsDedicated( )) + return; + + if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL ) + return; + + if(( g_pfn_sd_notify = dlsym( g_hsystemd, "sd_notify" )) == NULL ) + { + dlclose( g_hsystemd ); + g_hsystemd = NULL; + } + + Con_Reportf( "%s: sd_notify found, will report status to systemd\n", __func__ ); +} + +void Linux_Shutdown( void ) +{ + g_pfn_sd_notify = NULL; + + if( g_hsystemd ) + { + dlclose( g_hsystemd ); + g_hsystemd = NULL; + } +} diff --git a/engine/platform/platform.h b/engine/platform/platform.h index 3083ca53..c447b839 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -35,6 +35,13 @@ void Platform_Sleep( int msec ); void Platform_ShellExecute( const char *path, const char *parms ); void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow ); qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak +void Platform_SetStatus( const char *status ); + +#if XASH_WIN32 || XASH_LINUX +#define XASH_PLATFORM_HAVE_STATUS 1 +#else +#undef XASH_PLATFORM_HAVE_STATUS +#endif #if XASH_POSIX void Posix_Daemonize( void ); @@ -57,9 +64,6 @@ int Android_GetKeyboardHeight( void ); #if XASH_WIN32 void Wcon_CreateConsole( void ); void Wcon_DestroyConsole( void ); -void Platform_UpdateStatusLine( void ); -#else -static inline void Platform_UpdateStatusLine( void ) { } #endif #if XASH_NSWITCH @@ -80,16 +84,18 @@ void DOS_Init( void ); void DOS_Shutdown( void ); #endif +#if XASH_LINUX +void Linux_Init( void ); +void Linux_Shutdown( void ); +#endif + static inline void Platform_Init( void ) { #if XASH_POSIX + // daemonize as early as possible, because we need to close our file descriptors Posix_Daemonize( ); #endif -#if XASH_WIN32 - Wcon_CreateConsole( ); -#endif - #if XASH_SDL SDLash_Init( ); #endif @@ -102,6 +108,10 @@ static inline void Platform_Init( void ) PSVita_Init( ); #elif XASH_DOS DOS_Init( ); +#elif XASH_WIN32 + Wcon_CreateConsole( ); +#elif XASH_LINUX + Linux_Init( ); #endif } @@ -113,6 +123,10 @@ static inline void Platform_Shutdown( void ) PSVita_Shutdown( ); #elif XASH_DOS DOS_Shutdown( ); +#elif XASH_WIN32 + Wcon_DestroyConsole( ); +#elif XASH_LINUX + Linux_Shutdown( ); #endif #if XASH_SDL diff --git a/engine/platform/win32/con_win.c b/engine/platform/win32/con_win.c index dfea3f27..5a0bb584 100644 --- a/engine/platform/win32/con_win.c +++ b/engine/platform/win32/con_win.c @@ -663,14 +663,14 @@ char *Wcon_Input( void ) /* ================ -Wcon_SetStatus +Platform_SetStatus set server status string in console ================ */ -void Wcon_SetStatus( const char *pStatus ) +void Platform_SetStatus( const char *pStatus ) { - if( host.type != HOST_DEDICATED || s_wcd.attached ) + if( s_wcd.attached ) return; Q_strncpy( s_wcd.statusLine, pStatus, sizeof( s_wcd.statusLine ) - 1 ); diff --git a/engine/platform/win32/sys_win.c b/engine/platform/win32/sys_win.c index ecc5070b..5b459a4c 100644 --- a/engine/platform/win32/sys_win.c +++ b/engine/platform/win32/sys_win.c @@ -54,27 +54,6 @@ void Platform_ShellExecute( const char *path, const char *parms ) ShellExecute( NULL, "open", path, parms, NULL, SW_SHOW ); } -void Platform_UpdateStatusLine( void ) -{ - int clientsCount, botsCountUnused; - char szStatus[128]; - static double lastTime; - - if( host.type != HOST_DEDICATED ) - return; - - // update only every 1/2 seconds - if(( sv.time - lastTime ) < 0.5f ) - return; - - SV_GetPlayerCount( &clientsCount, &botsCountUnused ); - Q_snprintf( szStatus, sizeof( szStatus ) - 1, "%.1f fps %2i/%2i on %16s", 1.f / sv.frametime, clientsCount, svs.maxclients, host.game.levelName ); -#ifdef XASH_WIN32 - Wcon_SetStatus( szStatus ); -#endif - lastTime = sv.time; -} - #if XASH_MESSAGEBOX == MSGBOX_WIN32 void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow ) { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index b452b51a..64176adc 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -625,6 +625,43 @@ qboolean SV_RunGameFrame( void ) } } +static void SV_UpdateStatusLine( void ) +{ +#if XASH_PLATFORM_HAVE_STATUS + static double lasttime; + string status; + + if( !Host_IsDedicated( )) + return; + + // update only every 1/2 seconds + if(( host.realtime - lasttime ) < 0.5f ) + return; + + if( sv.state == ss_active ) + { + int clients, bots; + SV_GetPlayerCount( &clients, &bots ); + + Q_snprintf( status, sizeof( status ), + "%.1f fps %2i/%2i on %16s", + 1.f / sv.frametime, + clients, svs.maxclients, host.game.levelName ); + } + else if( sv.state == ss_loading ) + Q_strncpy( status, "Loading level", sizeof( status )); + else if( !svs.initialized ) + Q_strncpy( status, "Server is not loaded", sizeof( status )); + // FIXME: unreachable branch + // else if( host.status == HOST_SHUTDOWN ) + // Q_strncpy( status, "Shutting down...", sizeof( status )); + else Q_strncpy( status, "Unknown status", sizeof( status )); + + Platform_SetStatus( status ); + lasttime = host.realtime; +#endif // XASH_PLATFORM_HAVE_STATUS +} + /* ================== Host_ServerFrame @@ -633,6 +670,9 @@ Host_ServerFrame */ void Host_ServerFrame( void ) { + // update dedicated server status line in console + SV_UpdateStatusLine (); + // if server is not active, do nothing if( !svs.initialized ) return; @@ -667,9 +707,6 @@ void Host_ServerFrame( void ) // clear edict flags for next frame SV_PrepWorldFrame (); - // update dedicated server status line in console - Platform_UpdateStatusLine (); - // send a heartbeat to the master if needed NET_MasterHeartbeat (); }