ALib C++ Library
Library Version: 2510 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;
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{
58 IF_ALIB_THREADS( static Lock lock; ALIB_DBG(lock.Dbg.Name= "ProcessInfo";) )
59 if( current.PID == 0 )
60 {
61 // Own global lock and check if still nulled.
62 // (If not, this was a very unlikely parallel access )
63 ALIB_LOCK_WITH( lock )
64 if ( ProcessInfo::current.PID == 0 )
65 ProcessInfo::current.get( 0 );
66 }
67 return current;
68}
69# include "ALib.Lang.CIMethods.H"
70
71
72#if defined(__GLIBC__) && defined(__unix__) || defined(__ANDROID_NDK__)
73 bool readProcFile( const NCString& fileName, AString& result );
74 bool readProcFile( const NCString& fileName, AString& result )
75 {
76 std::ifstream file( fileName );
77
78 std::string buffer;
79 getline(file, buffer);
80
81 // spaces are replaced with '\0'. Revert this.
82 if (buffer.size() > 2 )
83 for( size_t i= 0 ; i < buffer.size() -2 ; ++i )
84 if ( buffer[i] == '\0' )
85 buffer[i]= ' ';
86
87 result.Reset( buffer.c_str() );
88 file.close();
89 return true;
90 }
91
92 bool ProcessInfo::getStatField( int fieldNo, AString& target)
93 {
94 Tokenizer tknzr( Stat, ' ');
95 bool result= true;
96 while ( --fieldNo >= 0 && (result= tknzr.HasNext()) )
97 tknzr.Next();
98
99 target.Reset( tknzr.Next() );
100 return result;
101 }
102
103 bool ProcessInfo::get( uinteger pid )
104 {
105 // use current thread if no PID given
106 uinteger newPID= 0;
107 if ( pid == 0 )
108 {
109 auto np= getpid();
110 if(np > 0 )
111 newPID= uinteger( np );
112 }
113 else
114 newPID= pid;
115
116 if ( newPID == 0 )
117 return false;
118
119
120 PID= newPID;
121
122 // cmdline, stat from proc
123 NString64 procDir("/proc/"); procDir._<NC>( PID )._( '/' );
124 integer procPathLen= procDir.Length();
125 {
126 // read things
127 procDir << "cmdline"; readProcFile( procDir, CmdLine ); procDir.ShortenTo(procPathLen);
128 procDir << "stat"; readProcFile( procDir, Stat ); procDir.ShortenTo(procPathLen);
129 }
130
131 getStatField( 3, Name ); // PPID
132 PPID= uinteger( Name.ParseInt() );
133 getStatField( 1, Name );
134 ALIB_ASSERT_ERROR( Name.IsEmpty()
135 || ( Name.Length() >= 2
136 && Name.CharAtStart<NC>()=='('
137 && Name.CharAtEnd <NC>()==')' ),
138 "CAMP", "Error reading process Info" )
139
140 if ( Name.CharAtEnd () == ')' ) Name.DeleteEnd <NC>( 1 );
141 if ( Name.CharAtStart() == '(' ) Name.DeleteStart<NC>( 1 );
144
145 // get executable path and name
146 ExecFileName.Reset();
147 ExecFilePath.Reset();
148
149 procDir << A_CHAR("exe");
150 nchar buffer[2048];
151 ssize_t length= readlink( procDir, buffer, 2048 );
152 procDir.ShortenTo(procPathLen);
153
154 if( length > 0 )
155 {
156 ExecFilePath.Append( buffer, length );
157 integer idx= ExecFilePath.LastIndexOf( '/' );
158 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
159 "Executable path does not contain directory separator character.\n"
160 " Path: {}", ExecFilePath )
161 ExecFileName._( ExecFilePath, idx + 1 );
162 ExecFilePath.ShortenTo( idx );
163 }
164 else
165 {
166 // obviously no rights to read the link. We use the process name
167 ExecFileName._( Name );
168 }
169 return true;
170 }
171
172#elif defined (__APPLE__)
173
174 bool ProcessInfo::get( uinteger pid )
175 {
176 PID= PPID= 0;
177 if( pid == 0 )
178 pid= uinteger( getpid() );
179
180 struct proc_bsdinfo proc;
181 int st = proc_pidinfo( int(pid), PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE);
182 if (st != PROC_PIDTBSDINFO_SIZE)
183 return false;
184
185 // pid and parent pid
186 PID= pid;
187 PPID= uinteger( proc.pbi_ppid );
188
189 // get name
190 Name._(reinterpret_cast<const char*>( proc.pbi_comm ) );
191
192 // get executable filename and path
193 {
194 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
195
196 if ( proc_pidpath (int( PID ), pathbuf, PROC_PIDPATHINFO_MAXSIZE) > 0 )
197 {
198 ExecFilePath._( reinterpret_cast<const char*>( pathbuf ) );
199 integer sepPos= ExecFilePath.LastIndexOf( '/' );
200 if( sepPos > 0 )
201 {
202 ExecFileName._(ExecFilePath, sepPos + 1 );
203 ExecFilePath.SetLength( sepPos );
204 }
205 }
206 }
207
208 return true;
209 }
210
211#elif defined (_WIN32)
212
214 {
215 // get pid
216 if (pid != 0 )
217 return false;
218
219 DWORD wPID= GetCurrentProcessId();
220 PID = (uinteger) wPID;
221
222
223 // get command line
224 CmdLine.Reset( NString( GetCommandLineA()) );
225
226 // get executable filename and path
227 ExecFileName.Reset();
228 ExecFilePath.Reset();
229 Name.Reset();
230
231 char buf[MAX_PATH];
232 GetModuleFileNameA( NULL, buf, MAX_PATH );
233 ExecFilePath.Reset( (const char*) buf );
234 integer idx= ExecFilePath.LastIndexOf( '\\' );
235 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
236 "Executable path does not contain directory separator character: ",
238 Name= ExecFileName._( ExecFilePath, idx + 1 );
239 ExecFilePath.SetLength( idx );
240
241 // get console title
242 STARTUPINFOA startupInfo;
243 GetStartupInfoA( &startupInfo );
244 ConsoleTitle.Reset( NString(startupInfo.lpTitle) );
245
246 return true;
247 }
248
249#else
250 #pragma message ("Unknown Platform in file: " __FILE__ )
251#endif
252
253}} // 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:836
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
#define ALIB_LOCK_WITH(lock)
Definition alib.inl:1322
threads::Lock Lock
Type alias in namespace alib.
Definition lock.inl:132
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:2390
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:512
characters::nchar nchar
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152