ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
processinfo.cpp
1//##################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
16#if !DOXYGEN
17# if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__ANDROID_NDK__)
18# include <unistd.h>
19# if defined(__APPLE__)
20# include <unistd.h>
21# include <sys/sysctl.h>
22# include <libproc.h>
23# endif
24# elif defined( _WIN32 )
25# include <direct.h>
26# else
27# pragma message ("Unknown Platform in file: " __FILE__ )
28# endif
29# include <fstream>
30#endif // !DOXYGEN
31//============================================== Module ============================================
32#if ALIB_C20_MODULES
33 module ALib.System;
34 import ALib.Lang;
35# if !ALIB_SINGLE_THREADED
36 import ALib.Threads;
37# endif
38 import ALib.Strings;
39 import ALib.Strings.Tokenizer;
40#else
41# include "ALib.Lang.H"
42# if !ALIB_SINGLE_THREADED
43# include "ALib.Threads.H"
44# endif
45# include "ALib.Strings.H"
47# include "ALib.System.H"
48#endif
49//========================================== Implementation ========================================
50namespace alib { namespace system {
51
52// static instance representing current process
54
57 IF_ALIB_THREADS( static Lock lock; ALIB_DBG(lock.Dbg.Name= "ProcessInfo";) )
58 if( current.PID == 0 ) {
59 // Own global lock and check if still nulled.
60 // (If not, this was a very unlikely parallel access )
61 ALIB_LOCK_WITH( lock )
62 if ( ProcessInfo::current.PID == 0 )
63 ProcessInfo::current.get( 0 );
64 }
65 return current;
66}
67# include "ALib.Lang.CIMethods.H"
68
69
70#if defined(__GLIBC__) && defined(__unix__) || defined(__ANDROID_NDK__)
71bool readProcFile( const NCString& fileName, AString& result );
72bool readProcFile( const NCString& fileName, AString& result ) {
73 std::ifstream file( fileName );
74
75 std::string buffer;
76 getline(file, buffer);
77
78 // spaces are replaced with '\0'. Revert this.
79 if (buffer.size() > 2 )
80 for( size_t i= 0 ; i < buffer.size() -2 ; ++i )
81 if ( buffer[i] == '\0' )
82 buffer[i]= ' ';
83
84 result.Reset( buffer.c_str() );
85 file.close();
86 return true;
87}
88
89bool ProcessInfo::getStatField( int fieldNo, AString& target) {
90 Tokenizer tknzr( Stat, ' ');
91 bool result= true;
92 while ( --fieldNo >= 0 && (result= tknzr.HasNext()) )
93 tknzr.Next();
94
95 target.Reset( tknzr.Next() );
96 return result;
97}
98
99bool ProcessInfo::get( uinteger pid ) {
100 // use current thread if no PID given
101 uinteger newPID= 0;
102 if ( pid == 0 ) {
103 auto np= getpid();
104 if(np > 0 )
105 newPID= uinteger( np );
106 }
107 else
108 newPID= pid;
109
110 if ( newPID == 0 )
111 return false;
112
113
114 PID= newPID;
115
116 // cmdline, stat from proc
117 NString64 procDir("/proc/"); procDir._<NC>( PID )._( '/' );
118 integer procPathLen= procDir.Length();
119 {
120 // read things
121 procDir << "cmdline"; readProcFile( procDir, CmdLine ); procDir.ShortenTo(procPathLen);
122 procDir << "stat"; readProcFile( procDir, Stat ); procDir.ShortenTo(procPathLen);
123 }
124
125 getStatField( 3, Name ); // PPID
126 PPID= uinteger( Name.ParseInt() );
127 getStatField( 1, Name );
128 ALIB_ASSERT_ERROR( Name.IsEmpty()
129 || ( Name.Length() >= 2
130 && Name.CharAtStart<NC>()=='('
131 && Name.CharAtEnd <NC>()==')' ),
132 "CAMP", "Error reading process Info" )
133
134 if ( Name.CharAtEnd () == ')' ) Name.DeleteEnd <NC>( 1 );
135 if ( Name.CharAtStart() == '(' ) Name.DeleteStart<NC>( 1 );
138
139 // get executable path and name
140 ExecFileName.Reset();
141 ExecFilePath.Reset();
142
143 procDir << A_CHAR("exe");
144 nchar buffer[2048];
145 ssize_t length= readlink( procDir, buffer, 2048 );
146 procDir.ShortenTo(procPathLen);
147
148 if( length > 0 ) {
149 ExecFilePath.Append( buffer, length );
150 integer idx= ExecFilePath.LastIndexOf( '/' );
151 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
152 "Executable path does not contain directory separator character.\n"
153 " Path: {}", ExecFilePath )
154 ExecFileName._( ExecFilePath, idx + 1 );
155 ExecFilePath.ShortenTo( idx );
156 } else {
157 // obviously no rights to read the link. We use the process name
158 ExecFileName._( Name );
159 }
160 return true;
161}
162
163#elif defined (__APPLE__)
164
165 bool ProcessInfo::get( uinteger pid )
166 {
167 PID= PPID= 0;
168 if( pid == 0 )
169 pid= uinteger( getpid() );
170
171 struct proc_bsdinfo proc;
172 int st = proc_pidinfo( int(pid), PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE);
173 if (st != PROC_PIDTBSDINFO_SIZE)
174 return false;
175
176 // pid and parent pid
177 PID= pid;
178 PPID= uinteger( proc.pbi_ppid );
179
180 // get name
181 Name._(reinterpret_cast<const char*>( proc.pbi_comm ) );
182
183 // get executable filename and path
184 {
185 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
186
187 if ( proc_pidpath (int( PID ), pathbuf, PROC_PIDPATHINFO_MAXSIZE) > 0 )
188 {
189 ExecFilePath._( reinterpret_cast<const char*>( pathbuf ) );
190 integer sepPos= ExecFilePath.LastIndexOf( '/' );
191 if( sepPos > 0 )
192 {
193 ExecFileName._(ExecFilePath, sepPos + 1 );
194 ExecFilePath.SetLength( sepPos );
195 }
196 }
197 }
198
199 return true;
200 }
201
202#elif defined (_WIN32)
203
205 {
206 // get pid
207 if (pid != 0 )
208 return false;
209
210 DWORD wPID= GetCurrentProcessId();
211 PID = (uinteger) wPID;
212
213
214 // get command line
215 CmdLine.Reset( NString( GetCommandLineA()) );
216
217 // get executable filename and path
218 ExecFileName.Reset();
219 ExecFilePath.Reset();
220 Name.Reset();
221
222 char buf[MAX_PATH];
223 GetModuleFileNameA( NULL, buf, MAX_PATH );
224 ExecFilePath.Reset( (const char*) buf );
225 integer idx= ExecFilePath.LastIndexOf( '\\' );
226 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
227 "Executable path does not contain directory separator character: ",
229 Name= ExecFileName._( ExecFilePath, idx + 1 );
230 ExecFilePath.SetLength( idx );
231
232 // get console title
233 STARTUPINFOA startupInfo;
234 GetStartupInfoA( &startupInfo );
235 ConsoleTitle.Reset( NString(startupInfo.lpTitle) );
236
237 return true;
238 }
239
240#else
241 #pragma message ("Unknown Platform in file: " __FILE__ )
242#endif
243
244}} // namespace [alib::system]
This class represents process information.
AString StatPGRP
The process group field (4) within Stat. (Unix like OS only.)
ProcessInfo()
Default constructor to create an empty instance.
AString Stat
The contents of /proc/PID/stat file. (Unix like OS only.)
ALIB_DLL bool get(uinteger PID)
uinteger PPID
The parent's process id as AString. (Unix like OS / Mac OS only.)
AString ExecFilePath
The path of the executable (if available to us).
AString StatState
The state field (2) within Stat. (Unix like OS only.)
static ALIB_DLL ProcessInfo current
uinteger PID
The process id as AString.
static ALIB_DLL const ProcessInfo & Current()
AString CmdLine
The command line which invoked this process.
AString ConsoleTitle
For console processes, this is the title displayed in the title bar. (Windows OS only....
bool getStatField(int fieldNo, AString &target)
#define IF_ALIB_THREADS(...)
Definition alib.inl:401
#define A_CHAR(STR)
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
#define ALIB_LOCK_WITH(lock)
Definition alib.inl:1339
threads::Lock Lock
Type alias in namespace alib.
Definition lock.inl:124
NLocalString< 64 > NString64
Type alias name for TLocalString<nchar,64>.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
strings::util::TTokenizer< character > Tokenizer
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2198
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:484
characters::nchar nchar
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152