ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
processinfo.cpp
1//##################################################################################################
2// ALib C++ Framework
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 "Configuration MACRO 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]
#define IF_ALIB_THREADS(...)
Definition alib.inl:466
#define A_CHAR(STR)
Definition alib.inl:1325
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define ALIB_LOCK_WITH(lock)
Definition alib.inl:1413
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.).
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 ProcessInfo current
uinteger PID
The process id as AString.
static 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)
threads::Lock Lock
Type alias in namespace alib.
Definition lock.inl:124
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2181
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:408
strings::util::TTokenizer< character > Tokenizer
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
characters::nchar nchar
Type alias in namespace alib.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
NLocalString< 64 > NString64
Type alias name for #"TLocalString;TLocalString<nchar,64>".