//
// File: hzProcess.h
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
// Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#ifndef hzProcess_h
#define hzProcess_h
#include "hzDate.h"
#include "hzLock.h"
#include "hzString.h"
/*
** SECTION 1: The hzProcess and hzProginfo classes
*/
class hzLogger ;
class hzProcess
{
// Category: System
//
// The hzProcess class holds information on the current thread. This is for the purpose of directing log messages and facilitating stack traces. An instance of hzProcess per
// thread is COMPULSORY in all programs based on the HadronZoo library, including single threaded programs.
class _fncall_rec
{
// Record of a function call
public:
const char* m_func ; // Function full name (class::fnname)
uint32_t m_callNo ; // Sequence number
uint16_t m_series ; // Number of times sequence flipped back to zero
uint16_t m_callLevel ; // Call depth of call
_fncall_rec () { m_func = 0 ; m_callNo = 0 ; m_series = m_callLevel = 0 ; }
} ;
const char** m_Stack ; // Function call stack
_fncall_rec* m_Hist ; // Recent function call history
hzLogger* m_pLog ; // The default (first) logger for the thread
void* m_CurrentLock ; // Memory location Microlock
pthread_t m_TID ; // The current thread id
hzString m_LastErrmsg ; // Last error message in current thread
uint32_t m_Id ; // Short form ID (based on position in the global array of hzProcess instances)
uint32_t m_nFuncs ; // The current function (current position in stack)
uint32_t m_nPeak ; // Function depth high water mark
uint32_t m_nSeqCall ; // Function call sequence number
uint32_t m_nCallOset ; // Current offset into history
uint32_t m_nScratchOset ; // Current offset into scratch buffer (after allocation)
uint32_t m_nScratchAdvn ; // Current offset into scratch buffer (before allocation)
hzEcode m_LastEcode ; // Last error code
char m_Scratch[16384] ; // Scratch pad
static void _register (hzProcess* pProc) ;
static void _deregister (hzProcess* pProc) ;
public:
hzProcess (void) ;
~hzProcess (void) ;
// Set the default logger for the thread to the supplied logger unless already set
void SetLog (hzLogger* pLog) { m_pLog = pLog ; }
hzLogger* GetLog (void) { return m_pLog ; } // Get logger for thread
pthread_t GetTID (void) { return m_TID ; } // Get the thread id
uint32_t GetId (void) { return m_Id ; } // Get the short form thread id
uint32_t Level (void) { return m_nFuncs-1 ; } // Return current function call level
const char* GetCurrFunc (void)
{
if (m_nFuncs > 0)
return m_Stack[m_nFuncs-1] ;
return 0 ;
}
void PushFunction (const char* funcname) ; // Notify thread stack of function call
void PullFunction (void) ; // Notify thread of function return
void StackTrace (void) ; // Export Current Stack Trace
void CallHistory (void) ; // Export recent function call history
char* ScratchPad (int32_t nSize) ; // Provide a temporary non-deletable buffer for values (to feed to printf type functions)
} ;
class hzProginfo
{
// Category: System
//
// Information on currently running program - as held in the /proc directory.
public:
hzString m_Progname ; // Name of program
hzString m_Executable ; // Full path to the executable
uint32_t m_PID ; // Process ID (from proc)
uint32_t m_Resv ; // Reserved
} ;
/*
** SECTION 2: Shared Memory
*/
class hzShmem
{
// Category: System
//
// Shared memory segment for Inter-process Communication.
void* m_pStart ; // Pointer to start
hzString m_name ; // Shared memory segment name
uint32_t m_size ; // Shared memory segment size
uint32_t m_perm ; // Access permissions
uint32_t m_fd ; // Shared memory 'file descriptor'
uint32_t m_resv ; // Reserved
public:
hzShmem (void) { m_size = 0 ; m_pStart = 0 ; }
~hzShmem (void) {}
hzEcode Init (const char* name, uint32_t size, uint32_t mask) ;
uint32_t Size (void) ;
void* GetMem (void) { return m_pStart ; }
} ;
/*
** SECTION 3: Resource locking. The hzSysLock class
*/
class hzSysLock
{
// Category: System
//
// Controls 'external' resources such as files
int32_t m_nSemId ; // Unique id for semahore group
int32_t m_lockval ; // The thread that has the lock
uint32_t m_nResource ; // Slot within semaphore group
uint32_t m_count ; // Number of nested calls to lock by same thread
void _init (void) ; // Obtain a semaphore from a semaphore set
void _halt (void) ; // Free the semaphore back to the set (for possible reallocation)
public:
hzSysLock (void) { m_lockval = 0 ; m_count = 0 ; _init() ; }
~hzSysLock (void) { _halt() ; }
void Lock (void) ;
void Unlock (void) ;
} ;
/*
** SECTION 4: Event Loging Regime. This covers the following:-
**
** 1) Periodic log files
** 2) Dynamic debug levels
** 3) A naming regime to build function names into log output.
** 4) A protocol for loging via the HadronZoo logserver.
** 5) The hzLogger class for writing log output to.
*/
#define PORT_LOGSERVER 4592
#define HZ_LOGCHUNK 1449 // HZ_MAXPACKET - 11
enum hzLogRotate
{
// Category: Diagnostics
//
// Enum to control periodicity of roliing logfiles
LOGROTATE_NEVER, // Never change logfile and truncate logfile at runtime
LOGROTATE_OFLOW, // Change file when filesize reached 2GB (appname.log .. appname.1.log)
LOGROTATE_YEAR, // Change logfile once per year appname_YYYY.log
LOGROTATE_QTR, // Change logfile every quarter appname_YYYYQ?.log
LOGROTATE_MONTH, // Change logfile every month appname_YYYYMM.log
LOGROTATE_MON, // Change logfile every Monday appname_YYYYMMDDMon.log
LOGROTATE_TUE, // Change logfile every Tuesday appname_YYYYMMDDTue.log
LOGROTATE_WED, // Change logfile every Wednesday appname_YYYYMMDDWed.log
LOGROTATE_THR, // Change logfile every Thursday appname_YYYYMMDDThr.log
LOGROTATE_FRI, // Change logfile every Friday appname_YYYYMMDDFri.log
LOGROTATE_SAT, // Change logfile every Saturday appname_YYYYMMDDSat.log
LOGROTATE_SUN, // Change logfile every Sunday appname_YYYYMMDDSun.log
LOGROTATE_DAY, // Change logfile every day appname_YYYYMMDD.log
LOGROTATE_12HR, // Change logfile every half day appname_YYYYMMDD?M.log
LOGROTATE_HOUR, // Change logfile every hour appname_YYYYMMDDHH.log
} ;
enum hzDebug
{
// Category: Diagnostics
//
// Controls which log messages are printed.
DEBUG_NONE = 0, // No debug messages (the default)
DEBUG_LEVEL1 = 1, // Mega critical
DEBUG_LEVEL2 = 2, // Importantish
DEBUG_LEVEL3 = 3 // Trivial
} ;
/*
** SECTION 5: Thread information prototypes
*/
hzProcess* GetThreadInfo (void) ;
hzLogger* GetThreadLogger (void) ;
void SetThreadLogger (hzLogger* plog) ;
class hzFuncname
{
// Category: Diagnostics
//
// hzFuncname is a const char pointer storing a function name. It was created as a class to avoid the compiler confusing it with anything else.
const char* m_pStr ; // Current function name
public:
hzFuncname (void) { m_pStr = 0 ; }
~hzFuncname (void) { m_pStr = 0 ; }
void operator= (const char* fnName)
{
// Argument: fnName Sets the current function name
// Returns: None
if (!m_pStr)
m_pStr = fnName ;
}
const char* operator* (void) const { return m_pStr ; }
operator const char* (void) const { return m_pStr ; }
} ;
class _hz_func_reg
{
// Category: Diagnostics
//
// Internal class to facilitate registration of a function call to the calling thread. The macro _hzfunc is placed at the top of most HadronZoo functions (both independent and
// class members). This macro takes a char* argument, the value of which is assumed to be the fully qualified name of the function or a close variant of it. The macro declares
// an instance of _hz_func_reg called _thisfn and assigns the function name to it.
//
// The _hz_func_reg assignment operator calls GetThreadInfo to obtain a pointer to the hzProcess instance for the current thread and stores in the the public member _phz. Then
// it uses the pointer to call hzProcess::PushFunction - which pushes the function name on to the stack.
//
// In any function with the _hzfunc macro, the current thread is available without a further call to GetThreadInfo, as _thisfn._phz - not that a GetThreadInfo call is onerous.
// The ready availablity of the hzProcess instance has a lot of potential for holding data 'private to the thread'.
//
// The _hzfunc macro must not be called outside the scope of a function even though the compiler would allow it. Doing so would place a false entry in the hzProcess stack. The
// macro when called at the top of a function as intended, creates the _hz_func_reg instance _thisfn as an automatic variable. This is deleted when the function returns so the
// call to hzProcess::PullFunction which pulls the function name from the hzProcess stack, is placed in the _hz_func_reg destructor.
public:
hzProcess* _phz ; // Pointer to hzProcess instance (process information)
_hz_func_reg (void) { _phz = 0 ; }
~_hz_func_reg (void)
{
// This destructor is called as any function starting with a call to _hzfunc() ends. As the latter pushes a function name onto the function stack for
// the thread, this must be pulled here.
if (_phz)
_phz->PullFunction() ;
}
void operator= (const char* fnName)
{
// Set the function name and push it onto the function stack for the thread.
//
// Argument: fnName The fully qualified function name
// Returns: None
if (!_phz)
_phz = GetThreadInfo() ;
if (_phz)
_phz->PushFunction(fnName) ;
}
char* ScratchPad (int32_t nSize)
{
if (!_phz)
_phz = GetThreadInfo() ;
return _phz->ScratchPad(nSize) ;
}
} ;
#define _hzfunc(x) static hzFuncname _fn ; _fn = x ; _hz_func_reg _thisfn ; _thisfn = *_fn
#define _hzlevel() _thisfn._phz->Level()
// Specific to Collection Class Templates
#define _hzfunc_ct(x) static hzFuncname _fn ; _fn = x ; _hz_func_reg _thisfn ; if (_hzGlobal_Debug & HZ_DEBUG_CTMPLS) _thisfn = *_fn
/*
** Error reporting prototypes
*/
hzEcode hzwarn (hzEcode eError, const char* va_alist ...) ;
hzEcode hzerr (hzEcode eError, const char* va_alist ...) ;
void hzexit (hzEcode eError, const char* va_alist ...) ;
void Fatal (hzChain& error) ;
void Fatal (const char* va_alist ...) ;
/*
** SECTION 6: Log signals to and from the HadronZoo logserver
*/
enum hzLogSignal
{
// Category: Diagnostics
//
// Commands to server
LS_NULL = 0, // No action
LS_OPEN_PUB = 1, // Open a channel to a public logfile
LS_OPEN_PVT = 2, // Open a channel to a private logfile
LS_STOP = 3, // Close a channel (either public or private)
LS_LOG = 4, // Log to a log file (either public or private)
// Server responses
LS_ERR_CONN = 10, // Could not connect to logserver
LS_ERR_SEND = 11, // Data could not be written to a socket
LS_ERR_RECV = 12, // Date could not be read from a socket
LS_ERR_PERM = 13, // Process does not have write permission
LS_ERR_DUP = 14, // Channel already open
LS_FAIL = 15, // Request failed
LS_OK = 16, // Request succesful
} ;
/*
** The LogChannel class
*/
class hzTcpClient ;
class hzLogger
{
// Category: Diagnostics
//
// The hzLogger class manages a 'log channel'. Instead of writing to a logfile applications write to a hzLogger instance. This
// usually is a file but it might be a logserver instance (socket program)
// Variables for operation on direct files
FILE* m_pFile ; // The active logfile
hzLockS m_Lock ; // Mutex (if required)
hzXDate m_datCurr ; // Current date & time
hzXDate m_datLast ; // Last date & time rotation occured
hzString m_Base ; // Basename of logfile
hzString m_File ; // Full name of logfile
// Variables for operation with logserver
hzTcpClient* m_pConnection ; // Connection as client to logserver
uchar* m_pData ; // Buffer for preparation of log message
uint16_t m_nIndent ; // No of tabs to indent
uint16_t m_nSessID ; // Session ID
// Variable for both types of operation
char* m_pDataPtr ; // Set at m_cvData or an offset to allow packet hdr
hzLogRotate m_eRotate ; // Log rotate edict
bool m_bVerbose ; // Send log messages to stdin as well as file
char m_cvData[HZ_MAXPACKET+4] ; // Buffer for preparation of log message
void _logrotate (void) ; // Functions for operation on direct files
hzEcode _write (uint32_t nBytes) ; // Internal write function
// Prevent copying
hzLogger (const hzLogger& never) ;
hzLogger& operator= (const hzLogger& never) ;
public:
hzLogger (void) ;
~hzLogger (void) ;
void Verbose (bool bVerbose) { m_bVerbose = bVerbose ; }
void SetIndent (uint16_t nIndent) { m_nIndent = nIndent ; }
bool IsOpen (void) { return m_Base || m_pFile || m_nSessID ? true : false ; }
bool IsVerbose (void) { return m_bVerbose ; }
hzEcode OpenFile (const char* cpPath, hzLogRotate eRotate) ;
hzEcode OpenPublic (const char* cpPath, hzLogRotate eRotate) ;
hzEcode OpenPrivate (const char* cpPath, hzLogRotate eRotate, uint32_t Perms) ;
hzEcode Close (void) ;
hzEcode Log (const hzChain& msg) ;
hzEcode Log (const char* va_alist ...) ;
hzEcode Out (const hzChain& msg) ;
hzEcode Out (const char* va_alist ...) ;
hzLogger& operator<< (hzChain& Z) ;
hzLogger& operator<< (hzString& Z) ;
hzLogger& operator<< (const char* cpStr) ;
} ;
hzEcode threadLog (const hzChain& msg) ;
hzEcode threadLog (const char* va_alist ...) ;
hzEcode threadOut (const hzChain& msg) ;
hzEcode threadOut (const char* va_alist ...) ;
/*
** Globals
*/
extern __thread hzProcess* _hzGlobal_currProc ; // Process data for the current thread
extern hzString _hzGlobal_HOME ; // Environment variable $HOME
extern hzString _hzGlobal_HADRONZOO ; // Environment variable $HADRONZOO
extern hzString _hzGlobal_SysImages ; // HadronZoo system images
extern uint32_t _hzGlobal_callStack_size ; // Depth of per-thread call stack
extern uint32_t _hzGlobal_callHist_size ; // Depth of per-thread call history
extern bool _hzGlobal_MT ; // Set true be set true by the application if it is to be run in multi-threaded mode
extern bool _hzGlobal_kill ; // True if shutdown pending. Don't accept new connections.
/*
** Prototypes
*/
// Process control
hzEcode HadronZooInitEnv (void) ; // Read environment variables $HOME and $HADRONZOO
void Demonize (void) ; // Run the program as a demon
void SingleProc (void) ; // Ensure singleton operation (prevent further program instances)
void StackTrace (void) ; // Log current stack trace for calling thread
void CallHistory (void) ; // Log recent function call history for calling thread
void CatchSegVio (int32_t sig) ; // Provides backtrace of function calls in event of segment violation (SIGSEG)
void CatchCtrlC (int32_t sig) ; // Catches Ctrl-C keypress (SIGINT)
// General Diagnostics
hzEcode RegisterCollection (const hzString, void*) ;
uint32_t ActiveThreadCount (void) ;
void ReportMutexContention (hzChain& Z, bool bHtm) ;
void ReportStringAllocations (hzChain& Z, bool bHtm) ;
void ReportMemoryUsage (hzChain& Z, bool bHtm) ;
void RecordMemoryUsage (bool bHtml=true) ;
#endif // hzProcess_h