00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GAUDIKERNEL_PROCSTAT_CPP
00017
00018 static const long TICK_TO_100NSEC = 100000;
00019
00020 namespace System {
00021 enum ProcessInfoCommand {
00022 ProcessBasicInformation,
00023 ProcessQuotaLimits,
00024 ProcessIoCounters,
00025 ProcessVmCounters,
00026 ProcessTimes,
00027 ProcessBasePriority,
00028 ProcessRaisePriority,
00029 ProcessDebugPort,
00030 ProcessExceptionPort,
00031 ProcessAccessToken,
00032 ProcessLdtInformation,
00033 ProcessLdtSize,
00034 ProcessDefaultHardErrorMode,
00035 ProcessIoPortHandlers,
00036 ProcessPooledUsageAndLimits,
00037 ProcessWorkingSetWatch,
00038 ProcessUserModeIOPL,
00039 ProcessEnableAlignmentFaultFixup,
00040 ProcessPriorityClass,
00041 ProcessWx86Information,
00042 ProcessHandleCount,
00043 ProcessAffinityMask,
00044 ProcessPriorityBoost,
00045 MaxProcessInfoClass,
00046 ProcessEllapsedTime
00047 };
00048 }
00049 #ifdef _WIN32
00050 # define strcasecmp _stricmp
00051 # define strncasecmp _strnicmp
00052 #define NOMSG
00053 #define NOGDI
00054 #include "process.h"
00055 #include "windows.h"
00056 #define getpid _getpid
00057 namespace NtApi {
00058
00059
00060
00061
00062 typedef long (WINAPI *__NtQueryInformationProcess)(
00063
00064 void* ProcessHandle,
00065 long ProcessInformationClass,
00066 void* ProcessInformation,
00067 unsigned long ProcessInformationLength,
00068 unsigned long* ReturnLength
00069 );
00070 __NtQueryInformationProcess NtQueryInformationProcess;
00071 };
00072 #else // UNIX...: first the EGCS stuff, then the OS dependent includes
00073 #define WINVER 0
00074 #include <errno.h>
00075 #include <string>
00076 #include "unistd.h"
00077 #include "libgen.h"
00078 #include <cstdio>
00079 #include <unistd.h>
00080 #include <sstream>
00081 #include <iostream>
00082 #include <fcntl.h>
00083 #include "sys/times.h"
00084 #include <sys/types.h>
00085 #include <sys/signal.h>
00086 #include <sys/syscall.h>
00087 #ifndef __APPLE__
00088 #include <sys/procfs.h>
00089 #endif
00090 #include <sys/time.h>
00091 #include <sys/resource.h>
00092 #include <cstdio>
00093
00094 struct linux_proc {
00095 int pid;
00096 char comm[400];
00097 char state;
00098 int ppid;
00099 int pgrp;
00100 int session;
00101 int tty;
00102 int tpgid;
00103 unsigned int flags;
00104 unsigned int minflt;
00105 unsigned int cminflt;
00106 unsigned int majflt;
00107 unsigned int cmajflt;
00108 int utime;
00109 int stime;
00110 int cutime;
00111 int cstime;
00112 int counter;
00113 int priority;
00114 unsigned int timeout;
00115 unsigned int itrealvalue;
00116 int starttime;
00117 unsigned int vsize;
00118 unsigned int rss;
00119 unsigned int rlim;
00120 unsigned long startcode;
00121 unsigned long endcode;
00122 unsigned int startstack;
00123 unsigned int kstkesp;
00124 unsigned int kstkeip;
00125 int signal;
00126 int blocked;
00127 int sigignore;
00128 int sigcatch;
00129 unsigned int wchan;
00130 };
00131
00132 #ifdef __APPLE__
00133
00134 #else
00135 static long pg_size = sysconf(_SC_PAGESIZE);
00136 #endif
00137 void readProcStat(long pid, linux_proc& pinfo) {
00138
00139 int cnt, fd;
00140 char buf[512];
00141
00142 std::ostringstream ost;
00143
00144 ost << "/proc/" << pid << "/stat";
00145 std::string fname = ost.str();
00146 if((fd=open(fname.c_str(),O_RDONLY))<0) {
00147 std::cerr << "Failed to open " << ost.str() << std::endl;
00148 return;
00149 }
00150
00151 lseek(fd,0,SEEK_SET);
00152 if((cnt=read(fd,buf,sizeof(buf)))<0) {
00153 std::cout << "LINUX Read of Proc file failed:" << std::endl;
00154 return;
00155 }
00156
00157 if(cnt>0) {
00158 buf[cnt]='\0';
00159 sscanf(buf,
00160 "%d %s %c %d %d %d %d %d %u %u %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %lu %lu %u %u %u %d %d %d %d %u",
00161 &pinfo.pid,
00162 pinfo.comm,
00163 &pinfo.state,
00164 &pinfo.ppid,
00165 &pinfo.pgrp,
00166 &pinfo.session,
00167 &pinfo.tty,
00168 &pinfo.tpgid,
00169 &pinfo.flags,
00170 &pinfo.minflt,
00171 &pinfo.cminflt,
00172 &pinfo.majflt,
00173 &pinfo.cmajflt,
00174 &pinfo.utime,
00175 &pinfo.stime,
00176 &pinfo.cutime,
00177 &pinfo.cstime,
00178 &pinfo.counter,
00179 &pinfo.priority,
00180 &pinfo.timeout,
00181 &pinfo.itrealvalue,
00182 &pinfo.starttime,
00183 &pinfo.vsize,
00184 &pinfo.rss,
00185 &pinfo.rlim,
00186 &pinfo.startcode,
00187 &pinfo.endcode,
00188 &pinfo.startstack,
00189 &pinfo.kstkesp,
00190 &pinfo.kstkeip,
00191 &pinfo.signal,
00192 &pinfo.blocked,
00193 &pinfo.sigignore,
00194 &pinfo.sigcatch,
00195 &pinfo.wchan
00196 );
00197 }
00198 close(fd);
00199 }
00200 #endif
00201
00202
00203
00204 #define s_myPid (::getpid())
00205 static inline long processID(long pid) {
00206 long thePid = (pid>0) ? pid : s_myPid;
00207 return thePid;
00208 }
00209
00210
00211 #include "ProcessDescriptor.h"
00212 #include "GaudiKernel/ModuleInfo.h"
00213 #include "GaudiKernel/System.h"
00214
00215 System::ProcessDescriptor* System::getProcess() {
00216 static ProcessDescriptor p;
00217 #ifdef _WIN32
00218 static bool first = true;
00219 if ( first ) {
00220 first = false;
00221 void* mh = ::LoadLibrary("NTDll.dll");
00222 if ( mh ) {
00223 NtApi::NtQueryInformationProcess = (NtApi::__NtQueryInformationProcess)
00224 ::GetProcAddress((HINSTANCE)mh, "NtQueryInformationProcess");
00225 }
00226 }
00227 #endif
00228 return &p;
00229 }
00230
00231 System::ProcessDescriptor::ProcessHandle::ProcessHandle(long pid) {
00232 if ( pid > 0 ) {
00233 if ( pid != s_myPid ) {
00234 #ifdef _WIN32
00235 m_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
00236 pid);
00237 #else
00238 m_handle = (void*)s_myPid;
00239 #endif
00240 m_needRelease = true;
00241 return;
00242 }
00243 }
00244 m_handle = processHandle();
00245 m_needRelease = false;
00246 }
00247
00248 System::ProcessDescriptor::ProcessHandle::~ProcessHandle() {
00249 if ( m_needRelease ) {
00250 #ifdef _WIN32
00251 ::CloseHandle(m_handle);
00252 #else
00253 m_handle = 0;
00254 #endif
00255 }
00256 }
00257
00258 System::ProcessDescriptor::ProcessDescriptor()
00259 {
00260 }
00261
00262 System::ProcessDescriptor::~ProcessDescriptor() {
00263 }
00264
00265 long System::ProcessDescriptor::query(long pid,
00266 InfoType fetch,
00267 IO_COUNTERS* info) {
00268 long status = 1;
00269 ProcessHandle h(pid);
00270 IO_COUNTERS* vb = &m_IO_COUNTERS[h.item()];
00271 if ( fetch == IO ) {
00272 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00273 status = NtApi::NtQueryInformationProcess(h.handle(),
00274 ProcessIoCounters,
00275 vb,
00276 sizeof(IO_COUNTERS),
00277 0);
00278 status = (status==0) ? 1 : 0;
00279 #elif defined(_WIN32) // Windows 95,98...
00280 #elif defined(linux)
00281 linux_proc prc;
00282 readProcStat(processID(pid), prc);
00283 rusage usage;
00284 getrusage(RUSAGE_SELF, &usage);
00285 vb->ReadOperationCount = usage.ru_inblock;
00286 vb->WriteOperationCount = usage.ru_oublock;
00287 vb->OtherOperationCount = 0;
00288 vb->ReadTransferCount = usage.ru_inblock;
00289 vb->WriteTransferCount = usage.ru_oublock;
00290 vb->OtherTransferCount = 0;
00291 #else // All Other
00292 #endif // End ALL OS
00293 }
00294 if ( info ) *info = *vb;
00295 return status;
00296 }
00297
00298 long System::ProcessDescriptor::query(long pid,
00299 InfoType fetch,
00300 POOLED_USAGE_AND_LIMITS* info) {
00301 long status = 1;
00302 ProcessHandle h(pid);
00303 POOLED_USAGE_AND_LIMITS* vb = &m_POOLED_USAGE_AND_LIMITS[h.item()];
00304 if ( fetch == Quota ) {
00305 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00306 status = NtApi::NtQueryInformationProcess(h.handle(),
00307 ProcessPooledUsageAndLimits,
00308 vb,
00309 sizeof(POOLED_USAGE_AND_LIMITS),
00310 0);
00311 status = (status==0) ? 1 : 0;
00312 #elif defined(_WIN32) // Windows 95,98...
00313 #elif defined(linux) // Linux
00314
00315
00316 rlimit lim;
00317
00318 getrlimit(RLIMIT_DATA, &lim);
00319 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00320 vb->PeakPagedPoolUsage = lim.rlim_cur;
00321 vb->PagedPoolUsage = lim.rlim_cur;
00322 vb->PagedPoolLimit = lim.rlim_max;
00323
00324 getrlimit(RLIMIT_STACK, &lim);
00325 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00326 vb->PeakNonPagedPoolUsage = lim.rlim_cur;
00327 vb->NonPagedPoolUsage = lim.rlim_cur;
00328 vb->NonPagedPoolLimit = lim.rlim_max;
00329
00330 linux_proc prc;
00331 readProcStat(processID(pid), prc);
00332 vb->PeakPagefileUsage = prc.rss * pg_size;
00333 vb->PagefileUsage = prc.rss * pg_size;
00334 vb->PagefileLimit = 0xFFFFFFFF;
00335 #elif defined(__APPLE__)
00336 #else // All Other
00337 #endif // End ALL OS
00338 }
00339 if ( info ) *info = *vb;
00340 return status;
00341 }
00342
00343 long System::ProcessDescriptor::query(long pid, InfoType fetch, long* info) {
00344 long status = 1, *vb = &status;
00345 ProcessHandle h(pid);
00346 vb = &m_PRIORITYBOOST[h.item()];
00347 *vb = 0;
00348 switch ( fetch ) {
00349 case PriorityBoost:
00350 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00351 status = NtApi::NtQueryInformationProcess(h.handle(),
00352 ProcessPriorityBoost,
00353 vb,
00354 sizeof(long),
00355 0);
00356 #elif defined(_WIN32) // Windows 95,98...
00357 #else
00358
00359 status = 0;
00360 *vb = 0;
00361 #endif // End ALL OS
00362 status = (status==0) ? 1 : 0;
00363 break;
00364 default:
00365 status = -1;
00366 vb = &status;
00367 break;
00368 }
00369 if ( info ) *info = *vb;
00370 return status;
00371 }
00372
00373 long System::ProcessDescriptor::query(long pid,
00374 InfoType fetch,
00375 VM_COUNTERS* info) {
00376 long status = 1;
00377 ProcessHandle h(pid);
00378 VM_COUNTERS* vb = &m_VM_COUNTERS[h.item()];
00379 if ( fetch == Memory ) {
00380 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00381 status = NtApi::NtQueryInformationProcess(h.handle(),
00382 ProcessVmCounters,
00383 vb,
00384 sizeof(VM_COUNTERS),
00385 0);
00386 status = (status==0) ? 1 : 0;
00387 #elif defined(_WIN32) // Windows 95,98...
00388 #elif defined(linux) // Linux
00389 const ssize_t bufsize = 1024;
00390 char buf[bufsize];
00391 sprintf(buf,"/proc/%ld/statm", processID(pid));
00392 long size, resident, share, trs, lrs, drs, dt;
00393 int fd = open(buf,O_RDONLY);
00394 ssize_t nread = read(fd, buf, bufsize);
00395 close(fd);
00396 if ( nread < bufsize && nread >= 0 )
00397 buf[nread]='\0';
00398 fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
00399 &size, &resident, &share, &trs, &drs, &lrs, &dt);
00400 linux_proc prc;
00401 readProcStat( processID(pid), prc);
00402 vb->PeakVirtualSize = prc.vsize;
00403 vb->VirtualSize = prc.vsize;
00404 vb->PeakWorkingSetSize = resident * pg_size;
00405 vb->WorkingSetSize = resident * pg_size;
00406 vb->QuotaPeakPagedPoolUsage = share * pg_size;
00407 vb->QuotaPagedPoolUsage = share * pg_size;
00408 vb->QuotaNonPagedPoolUsage = (trs+drs)* pg_size;
00409 vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;
00410 vb->PageFaultCount = prc.majflt + prc.minflt;
00411 vb->PagefileUsage = prc.vsize-resident*pg_size;
00412 vb->PeakPagefileUsage = prc.vsize-resident*pg_size;
00413 #elif defined(__APPLE__)
00414 #else // All Other
00415 #endif // End ALL OS
00416 }
00417 if ( info ) *info = *vb;
00418 return status;
00419 }
00420
00421 long System::ProcessDescriptor::query(long pid,
00422 InfoType fetch,
00423 QUOTA_LIMITS* info) {
00424 long status = 1;
00425 ProcessHandle h(pid);
00426 QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
00427 if ( fetch == Quota ) {
00428 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00429 status = NtApi::NtQueryInformationProcess(h.handle(),
00430 ProcessQuotaLimits,
00431 vb,
00432 sizeof(QUOTA_LIMITS),
00433 0);
00434 status = (status==0) ? 1 : 0;
00435 #elif defined(_WIN32) // Windows 95,98...
00436 #elif defined(linux) // Linux
00437
00438
00439 rlimit lim;
00440 getrlimit(RLIMIT_DATA, &lim);
00441 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00442 vb->PagedPoolLimit = lim.rlim_max;
00443
00444 getrlimit(RLIMIT_STACK, &lim);
00445 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00446 vb->NonPagedPoolLimit = lim.rlim_max;
00447 vb->MinimumWorkingSetSize = 0;
00448
00449 getrlimit(RLIMIT_RSS, &lim);
00450 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00451 vb->MaximumWorkingSetSize = lim.rlim_max;
00452
00453 getrlimit(RLIMIT_AS, &lim);
00454 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00455 vb->PagefileLimit = lim.rlim_max;
00456
00457 getrlimit(RLIMIT_CPU, &lim);
00458 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00459 vb->TimeLimit = lim.rlim_max;
00460 #elif defined(__APPLE__)
00461 #else // All Other
00462 #endif // End ALL OS
00463 }
00464 if ( info ) *info = *vb;
00465 return status;
00466 }
00467
00468 long System::ProcessDescriptor::query(long pid,
00469 InfoType fetch,
00470 PROCESS_BASIC_INFORMATION* info) {
00471 long status = 1;
00472 ProcessHandle h(pid);
00473 PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
00474 if ( fetch == ProcessBasics ) {
00475 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00476 status = NtApi::NtQueryInformationProcess(h.handle(),
00477 ProcessBasicInformation,
00478 vb,
00479 sizeof(PROCESS_BASIC_INFORMATION),
00480 0);
00481 status = (status==0) ? 1 : 0;
00482 #elif defined(_WIN32) // Windows 95,98...
00483 #elif defined(linux) // Linux
00484 linux_proc prc;
00485 readProcStat( processID(pid), prc);
00486 vb->ExitStatus = 0;
00487 vb->PebBaseAddress = (PPEB)prc.startcode;
00488 vb->BasePriority = 2*15-prc.priority;
00489
00490
00491 vb->AffinityMask = prc.flags;
00492
00493
00494 vb->UniqueProcessId = processID(pid);
00495 vb->InheritedFromUniqueProcessId = prc.ppid;
00496 #else // All Other
00497 #endif // End ALL OS
00498 }
00499 if ( info ) *info = *vb;
00500 return status;
00501 }
00502
00503 long System::ProcessDescriptor::query(long pid,
00504 InfoType fetch,
00505 KERNEL_USER_TIMES* info) {
00506 long status = 1;
00507 ProcessHandle h(pid);
00508 KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
00509 if ( fetch == Times ) {
00510 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00511 status = NtApi::NtQueryInformationProcess(h.handle(),
00512 ProcessTimes,
00513 tb,
00514 sizeof(KERNEL_USER_TIMES),
00515 0);
00516 status = (status==0) ? 1 : 0;
00517 #elif defined(_WIN32) // Windows 95,98...
00518 #elif defined(linux) // Linux
00519
00520
00521 tms tmsb;
00522 static longlong prc_start = 0;
00523
00524 static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
00525 if ( processID(pid) == s_myPid && prc_start == 0 ) {
00526 linux_proc prc;
00527 readProcStat( processID(pid), prc);
00528 prc_start = prc.starttime+offset;
00529 }
00530
00531 if ( processID(pid) == s_myPid ) {
00532 struct rusage r;
00533 getrusage( RUSAGE_SELF, &r );
00534 tb->UserTime = (static_cast<long long>(r.ru_utime.tv_sec) * 1000000 +
00535 r.ru_utime.tv_usec) * 10;
00536 tb->KernelTime = (static_cast<long long>(r.ru_stime.tv_sec) * 1000000 +
00537 r.ru_stime.tv_usec) * 10;
00538 tb->CreateTime = prc_start;
00539 }
00540 else {
00541 linux_proc prc;
00542 readProcStat( processID(pid), prc );
00543
00544 tms t;
00545 times(&t);
00546 tb->UserTime = t.tms_utime * TICK_TO_100NSEC;
00547 tb->KernelTime = t.tms_stime * TICK_TO_100NSEC;
00548 tb->CreateTime = (prc.starttime+offset);
00549 }
00550 tb->CreateTime *= TICK_TO_100NSEC;
00551 tb->ExitTime = 0;
00552
00553 status = 1;
00554
00555 #elif defined(__APPLE__)
00556
00557
00558 #else // no /proc file system: assume sys_start for the first call
00559 tms tmsb;
00560 static clock_t sys_start = times(0);
00561 static longlong offset = 100*longlong(time(0)) - sys_start;
00562 clock_t now = times(&tmsb);
00563 tb->CreateTime = offset + now;
00564 tb->UserTime = tmsb.tms_utime;
00565 tb->KernelTime = tmsb.tms_stime;
00566 tb->CreateTime *= TICK_TO_100NSEC;
00567 tb->UserTime *= TICK_TO_100NSEC;
00568 tb->KernelTime *= TICK_TO_100NSEC;
00569 tb->ExitTime = 0;
00570 status = 1;
00571 #endif
00572 }
00573 if ( info ) *info = *tb;
00574 return status;
00575 }