From 88a1c860eb062f1f3e72ad2c0a3dba7696b91fae Mon Sep 17 00:00:00 2001 From: Charles PIGNEROL <> Date: Fri, 14 Mar 2025 14:11:38 +0100 Subject: [PATCH] Version 6.13.0 of 03/14/25. Possibility of delegating to the Process class the destruction of processes at the end of software execution. --- cmake/version.cmake | 4 +- src/TkUtil/ApplicationStats.cpp | 86 +++++++++++++++++++++++------- src/TkUtil/Process.cpp | 24 +++++++++ src/TkUtil/public/TkUtil/Process.h | 25 ++++++++- versions.txt | 6 +++ 5 files changed, 123 insertions(+), 22 deletions(-) diff --git a/cmake/version.cmake b/cmake/version.cmake index e4fd4f9..21d9b8d 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -3,8 +3,8 @@ # set (TK_UTIL_MAJOR_VERSION "6") -set (TK_UTIL_MINOR_VERSION "12") -set (TK_UTIL_RELEASE_VERSION "1") +set (TK_UTIL_MINOR_VERSION "13") +set (TK_UTIL_RELEASE_VERSION "0") set (TK_UTIL_VERSION ${TK_UTIL_MAJOR_VERSION}.${TK_UTIL_MINOR_VERSION}.${TK_UTIL_RELEASE_VERSION}) set (TK_UTIL_SCRIPTING_MAJOR_VERSION ${TK_UTIL_MAJOR_VERSION}) diff --git a/src/TkUtil/ApplicationStats.cpp b/src/TkUtil/ApplicationStats.cpp index 3f69c74..13098d0 100644 --- a/src/TkUtil/ApplicationStats.cpp +++ b/src/TkUtil/ApplicationStats.cpp @@ -3,6 +3,7 @@ #include "TkUtil/Exception.h" #include "TkUtil/File.h" #include "TkUtil/NumericConversions.h" +#include "TkUtil/Process.h" #include "TkUtil/UTF8String.h" #include @@ -62,30 +63,38 @@ string ApplicationStats::getFileName (const string& appName, const string& logDi void ApplicationStats::logUsage (const string& appName, const string& logDir) { - // En vue de ne pas altérer le comportement de l'application tout est effectuée dans un processus fils. - // Par ailleurs on quitte le processus fils par return et non exit pour passer dans le destructeur des variables automatiques créées (TermAutoStyle, ...). + // En vue de ne pas altérer le comportement de l'application tout est effectuée dans un processus fils => exit (0) en toutes circonstances. errno = 0; const pid_t pid = fork ( ); if ((pid_t)-1 == pid) { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); ConsoleOutput::cerr ( ) << "ApplicationStats::logUsage : échec de fork : " << strerror (errno) << co_endl; return; } // if ((pid_t)-1 == pid) if (0 != pid) + { + Process::killAtEnd (pid); return; // Parent + } // On détache complètement le fils du parent => peut importe qui fini en premier, l'autre ira jusqu'au bout : const pid_t sid = setsid ( ); if ((pid_t)-1 == sid) { - ConsoleOutput::cerr ( ) << "ApplicationStats::logUsage : échec de setsid : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "ApplicationStats::logUsage : échec de setsid : " << strerror (errno) << co_endl; + } exit (0); } // if ((pid_t)-1 == sid) - TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); if ((true == appName.empty ( )) || (true == logDir.empty ( ))) { - ConsoleOutput::cerr ( ) << "ApplicationStats::logUsage : nom d'application ou répertoire des logs non renseigné (" << appName << "/" << logDir << ")." << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "ApplicationStats::logUsage : nom d'application ou répertoire des logs non renseigné (" << appName << "/" << logDir << ")." << co_endl; + } exit (0); } // if ((true == appName.empty ( )) || (true == logDir.empty ( ))) @@ -105,26 +114,38 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) File dir (logDir); if ((false == dir.exists ( )) || (false == dir.isDirectory ( )) || (false == dir.isExecutable ( )) || (false == dir.isWritable ( ))) { - ConsoleOutput::cerr ( ) << "Erreur, " << logDir << " n'est pas un répertoire existant avec les droits en écriture pour vous." << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur, " << logDir << " n'est pas un répertoire existant avec les droits en écriture pour vous." << co_endl; + } exit (0); } // if ((false == dir.exists ( )) || (false == dir.isDirectory ( )) || ... File logFile (fileName.utf8 ( )); if (false == logFile.isWritable ( )) { - ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : absence de droits en écriture." << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : absence de droits en écriture." << co_endl; + } exit (0); } // if (false == logFile.isWritable ( )) } catch (const Exception& exc) { - ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : " << exc.getFullMessage ( ) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : " << exc.getFullMessage ( ) << co_endl; + } exit (0); } catch (...) { } - ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : erreur non documentée." << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << " : erreur non documentée." << co_endl; + } exit (0); } // if (NULL == file) @@ -133,7 +154,10 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) int fd = fileno (file); if (-1 == fd) { - ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de l'ouverture du fichier de logs " << fileName << co_endl; + } exit (0); } // if (-1 == fd) @@ -141,7 +165,10 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) errno = 0; if (0 != flock (fd, LOCK_EX)) { - ConsoleOutput::cerr ( ) << "Erreur lors du verrouillage du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors du verrouillage du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + } fclose (file); exit (0); } // if (0 != flock (fd, LOCK_EX)) @@ -151,7 +178,10 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) { if (0 != fchmod (fd, S_IRWXU | S_IRWXG | S_IRWXO)) { - ConsoleOutput::cerr ( ) << "Erreur lors du confèrement à autrui des droits en écriture sur le fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors du confèrement à autrui des droits en écriture sur le fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + } fclose (file); exit (0); @@ -178,13 +208,19 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) } // while (2 == fscanf (file, "%s\t%u", name, &count)) if (0 != errno) { - ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " en ligne " << (unsigned long)line << " : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " en ligne " << (unsigned long)line << " : " << strerror (errno) << co_endl; + } fclose (file); exit (0); } // if (0 != errno) else if ((flag < 2) && (EOF != flag)) { - ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " en ligne " << (unsigned long)line << " : fichier probablement corrompu." << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " en ligne " << (unsigned long)line << " : fichier probablement corrompu." << co_endl; + } fclose (file); exit (0); } // if (flag < 2) @@ -195,7 +231,10 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) errno = 0; if (0 != fseek (file, 0, SEEK_SET)) { - ConsoleOutput::cerr ( ) << "Erreur lors de la réécriture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de la réécriture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + } fclose (file); exit (0); } // if (0 != fseek (file, 0, SEEK_SET)) @@ -204,7 +243,10 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) { if (fprintf (file, "%s\t%u\n", (*itl).first.c_str ( ), (*itl).second) < 0) { - ConsoleOutput::cerr ( ) << "Erreur lors de la réécriture du fichier de logs " << fileName << "."<< co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors de la réécriture du fichier de logs " << fileName << "."<< co_endl; + } fclose (file); exit (0); } @@ -212,16 +254,22 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir) errno = 0; if (0 != fflush (file)) { + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); ConsoleOutput::cerr ( ) << "Erreur lors de la réécriture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; - fclose (file); - exit (0); + } + fclose (file); + exit (0); } // if (0 != fflush (file)) // Libération du verrou : errno = 0; if (0 != flock (fd, LOCK_UN)) { - ConsoleOutput::cerr ( ) << "Erreur lors du déverrouillage du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Erreur lors du déverrouillage du fichier de logs " << fileName << " : " << strerror (errno) << co_endl; + } fclose (file); } // if (0 != flock (fd, LOCK_UN)) diff --git a/src/TkUtil/Process.cpp b/src/TkUtil/Process.cpp index 70588cd..99a7cdb 100644 --- a/src/TkUtil/Process.cpp +++ b/src/TkUtil/Process.cpp @@ -1,3 +1,4 @@ +#include "TkUtil/AnsiEscapeCodes.h" #include "TkUtil/Process.h" #include "TkUtil/File.h" #include "TkUtil/UTF8String.h" @@ -80,6 +81,7 @@ const vector& Process::ProcessOptions::getOptions ( ) const // =========================================================================== vector Process::_tasks; +set Process::_toKill; int Process::_argc = 0; char** Process::_argv = 0; char** Process::_envp = 0; @@ -444,6 +446,28 @@ void Process::initialize (char* envp []) } // Process::initialize +void Process::finalize ( ) +{ + for (set::iterator itk = _toKill.begin ( ); _toKill.end ( ) != itk; itk++) + { + int res = ::kill (*itk, SIGKILL); + if (0 != res) + { + TermAutoStyle as (cerr, AnsiEscapeCodes::blueFg); + ConsoleOutput::cerr ( ) << "Process::finalize. Erreur lors de l'appel à kill pour le processus de PID " << (unsigned long)*itk << " : " << strerror (errno) << co_endl; + } // if (0 != res) + } // for (set::iterator itk = _toKill.begin ( ); _toKill.end ( ) != itk; itk++) + + _toKill.clear ( ); +} // Process::finalize + + +void Process::killAtEnd (pid_t tokill) +{ + _toKill.insert (tokill); +} // Process::killAtEnd + + string Process::getChildLine ( ) { if ((true == isCompleted ( )) && (0 == _childBuffer.length ( ))) diff --git a/src/TkUtil/public/TkUtil/Process.h b/src/TkUtil/public/TkUtil/Process.h index 22e0a74..c02e12e 100644 --- a/src/TkUtil/public/TkUtil/Process.h +++ b/src/TkUtil/public/TkUtil/Process.h @@ -11,6 +11,7 @@ #include #endif // !defined(__GNUC__) && !defined(__ia64__) +#include #include #define PROCESS_ERROR_MESSAGE_SIZE (1025) @@ -286,7 +287,8 @@ class Process * @param environnement d'execution (3eme argument du main de l'application, où main est défini comme suit : * int main (int argc, char* argv[], char* envp []) * @warning il est essentiel d'appeler cette fonction avant le lancement de tout process fils. En son absence - * il est possible que l'exécution du process fils échoue. + * il est possible que l'exécution du process fils échoue. + * @see finalize */ static void initialize (int argc, char* argv [], char* envp []); @@ -300,6 +302,21 @@ class Process */ static void initialize (char* envp []); + /** + * Détruit tous les processus dont la destruction a été confiée à cette classe. Ce peut être par exemple des processus + * fils lancés via fork et non attendus. + * @see killAtEnd + * @since 6.13.0 + */ + static void finalize ( ); + + /** + * Délègue à cette classe le fait de tuer le processus de pid transmis en argument lorsque Process::finalize sera appelé. + * @see finalize + * @since 6.13.0 + */ + static void killAtEnd (pid_t tokill); + /** * @return Le répertoire courrant de l'application, ou, en cas d'erreur, une chaine vide. */ @@ -455,6 +472,12 @@ class Process /** La table comprenant les ids des tâches et les pointeurs sur les instances associées de cette classe. */ static IN_STD vector _tasks; + + /** + * Les processus à tuer à lappel de finalize. + * @see killAtEnd + */ + static IN_STD set _toKill; /** Le nombre d'arguments de lancement de cette application. */ static int _argc; diff --git a/versions.txt b/versions.txt index 2d3bc9c..0d71abf 100644 --- a/versions.txt +++ b/versions.txt @@ -1,3 +1,9 @@ +Version 6.13.0 : 14/03/25 +================= + +Possibilité de déléguer à la classe Process la destruction de processus en fin d'exécution via Process::killAtEnd () et Process::finalize (). + + Version 6.12.1 : 12/03/25 =================