ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
processinfo.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !defined(ALIB_DOX)
10#if !defined(HPP_ALIB_CAMP_PROCESSINFO)
12#endif
13
14#if !defined(HPP_ALIB_STRINGS_UTIL_TOKENIZER)
16#endif
17
18#if ALIB_THREADS && !defined(HPP_ALIB_THREADS_THREADLOCKNR)
20#endif
21#if !defined(HPP_ALIB_CAMP_MESSAGE_REPORT)
23#endif
24
25#if defined(__GLIBCXX__) || defined(__ANDROID_NDK__)
26 #include <unistd.h>
27#elif defined(__APPLE__)
28 #include <unistd.h>
29 #include <sys/sysctl.h>
30 #include <libproc.h>
31
32#elif defined( _WIN32 )
33 #include <direct.h>
34#else
35 #pragma message ("Unknown Platform in file: " __FILE__ )
36#endif
37
38#if !defined(_GLIBCXX_FSTREAM) && !defined(_FSTREAM_)
39 #include <fstream>
40#endif
41#endif // !defined(ALIB_DOX)
42
43
44
45namespace alib { namespace lang::system {
46
47// static instance representing current process
49
50
52{
53 ALIB_IF_THREADS( static ThreadLockNR lock; )
54 if( current.PID == 0 )
55 {
56 // Own global lock and check if still nulled.
57 // (If not, this is a very unlikely parallel access )
58 ALIB_LOCK_WITH( lock )
59 if ( ProcessInfo::current.PID == 0 )
61 }
62 return current;
63}
64
65
66#if defined(__GLIBC__) && defined(__unix__) || defined(__ANDROID_NDK__)
67 bool readProcFile( const NCString& fileName, AString& result );
68 bool readProcFile( const NCString& fileName, AString& result )
69 {
70 std::ifstream file( fileName );
71
72 std::string buffer;
73 getline(file, buffer);
74
75 // spaces are replaced with '\0'. Revert this.
76 if (buffer.size() > 2 )
77 for( size_t i= 0 ; i < buffer.size() -2 ; ++i )
78 if ( buffer[i] == '\0' )
79 buffer[i]= ' ';
80
81 result.Reset( buffer.c_str() );
82 file.close();
83 return true;
84 }
85
86 bool ProcessInfo::getStatField( int fieldNo, AString& target)
87 {
88 Tokenizer tknzr( Stat, ' ');
89 bool result= true;
90 while ( --fieldNo >= 0 && (result= tknzr.HasNext()) )
91 tknzr.Next();
92
93 target.Reset( tknzr.Next() );
94 return result;
95 }
96
97 bool ProcessInfo::get( uinteger pid )
98 {
99 // use current thread if no PID given
100 uinteger newPID= 0;
101 if ( pid == 0 )
102 {
103 auto np= getpid();
104 if(np > 0 )
105 newPID= static_cast<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._<false>( 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= static_cast<uinteger>( Name.ParseInt() );
127 getStatField( 1, Name );
129 || ( Name.Length() >= 2
130 && Name.CharAtStart<false>()=='('
131 && Name.CharAtEnd <false>()==')' ),
132 "CAMP", "Error reading process Info" )
133
134 if ( Name.CharAtEnd () == ')' ) Name.DeleteEnd <false>( 1 );
135 if ( Name.CharAtStart() == '(' ) Name.DeleteStart<false>( 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 {
150 ExecFilePath.Append( buffer, length );
151 integer idx= ExecFilePath.LastIndexOf( '/' );
152 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
153 "Executable path does not contain directory separator character.\n"
154 " Path: {}", ExecFilePath )
155 ExecFileName._( ExecFilePath, idx + 1 );
156 ExecFilePath.ShortenTo( idx );
157 }
158 else
159 {
160 // obviously no rights to read the link. We use the process name
162 }
163 return true;
164 }
165
166#elif defined (__APPLE__)
167
168 bool ProcessInfo::get( uinteger pid )
169 {
170 PID= PPID= 0;
171 if( pid == 0 )
172 pid= static_cast<uinteger>( getpid() );
173
174 struct proc_bsdinfo proc;
175 int st = proc_pidinfo( static_cast<int>(pid), PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE);
176 if (st != PROC_PIDTBSDINFO_SIZE)
177 return false;
178
179 // pid and parent pid
180 PID= pid;
181 PPID= static_cast<uinteger>( proc.pbi_ppid );
182
183 // get name
184 Name._(reinterpret_cast<const char*>( proc.pbi_comm ) );
185
186 // get executable filename and path
187 {
188 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
189
190 if ( proc_pidpath (static_cast<int>( PID ), pathbuf, PROC_PIDPATHINFO_MAXSIZE) > 0 )
191 {
192 ExecFilePath._( reinterpret_cast<const char*>( pathbuf ) );
193 integer sepPos= ExecFilePath.LastIndexOf( '/' );
194 if( sepPos > 0 )
195 {
196 ExecFileName._(ExecFilePath, sepPos + 1 );
197 ExecFilePath.SetLength( sepPos );
198 }
199 }
200 }
201
202 return true;
203 }
204
205#elif defined (_WIN32)
206
208 {
209 // get pid
210 if (pid != 0 )
211 return false;
212
213 DWORD wPID= GetCurrentProcessId();
214 PID = (uinteger) wPID;
215
216
217 // get command line
218 CmdLine.Reset( NString( GetCommandLineA()) );
219
220 // get executable filename and path
223 Name.Reset();
224
225
226 char buf[MAX_PATH];
227 GetModuleFileNameA( NULL, buf, MAX_PATH );
228 ExecFilePath.Reset( (const char*) buf );
229 integer idx= ExecFilePath.LastIndexOf( '\\' );
230 ALIB_ASSERT_ERROR( idx>= 0, "CAMP",
231 "Executable path does not contain directory separator character: ",
233 Name= ExecFileName._( ExecFilePath, idx + 1 );
234 ExecFilePath.SetLength( idx );
235
236 // get console title
237 STARTUPINFOA startupInfo;
238 GetStartupInfoA( &startupInfo );
239 ConsoleTitle.Reset( NString(startupInfo.lpTitle) );
240
241 return true;
242 }
243
244#else
245 #pragma message ("Unknown Platform in file: " __FILE__ )
246#endif
247
248}} // namespace [alib::lang::system]
bool getStatField(int fieldNo, AString &target)
static ALIB_API const ProcessInfo & Current()
ALIB_API bool get(uinteger PID)
static ALIB_API ProcessInfo current
TAString & ShortenTo(integer newLength)
Definition astring.hpp:908
TAString & Append(const TCharSrc *src, integer srcLength)
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
Definition astring.hpp:1056
void SetLength(integer newLength)
Definition astring.hpp:861
constexpr bool IsEmpty() const
Definition string.hpp:414
constexpr integer Length() const
Definition string.hpp:357
TChar CharAtStart() const
Definition string.hpp:459
ALIB_API int64_t ParseInt(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
TChar CharAtEnd() const
Definition string.hpp:481
ALIB_WARNINGS_RESTORE integer LastIndexOf(TChar needle, integer startIndex=MAX_LEN) const
Definition string.hpp:1027
#define A_CHAR(STR)
#define ALIB_IF_THREADS(...)
Definition alib.hpp:303
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_LOCK_WITH(lock)
platform_specific integer
Definition integers.hpp:50
platform_specific uinteger
Definition integers.hpp:56
Definition alib.cpp:57
lang::system::ProcessInfo ProcessInfo
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:289
NLocalString< 64 > NString64
Type alias name for TLocalString<nchar,64> .
strings::TString< nchar > NString
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.