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