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 m_handle = (void*)s_myPid;
00408 #endif
00409 m_needRelease = true;
00410 return;
00411 }
00412 }
00413 m_handle = processHandle();
00414 m_needRelease = false;
00415 }
00416
00417 System::ProcessDescriptor::ProcessHandle::~ProcessHandle() {
00418 if ( m_needRelease ) {
00419 #ifdef _WIN32
00420 ::CloseHandle(m_handle);
00421 #else
00422 m_handle = 0;
00423 #endif
00424 }
00425 }
00426
00427 System::ProcessDescriptor::ProcessDescriptor()
00428 {
00429 }
00430
00431 System::ProcessDescriptor::~ProcessDescriptor() {
00432 }
00433
00434 long System::ProcessDescriptor::query(long pid,
00435 InfoType fetch,
00436 IO_COUNTERS* info) {
00437 long status = 1;
00438 ProcessHandle h(pid);
00439 IO_COUNTERS* vb = &m_IO_COUNTERS[h.item()];
00440 if ( fetch == IO ) {
00441 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00442 status = NtApi::NtQueryInformationProcess(h.handle(),
00443 ProcessIoCounters,
00444 vb,
00445 sizeof(IO_COUNTERS),
00446 0);
00447 status = (status==0) ? 1 : 0;
00448 #elif defined(_WIN32) // Windows 95,98...
00449 #elif defined(linux)
00450 linux_proc prc;
00451 readProcStat(processID(pid), prc);
00452 rusage usage;
00453 getrusage(RUSAGE_SELF, &usage);
00454 vb->ReadOperationCount = usage.ru_inblock;
00455 vb->WriteOperationCount = usage.ru_oublock;
00456 vb->OtherOperationCount = 0;
00457 vb->ReadTransferCount = usage.ru_inblock;
00458 vb->WriteTransferCount = usage.ru_oublock;
00459 vb->OtherTransferCount = 0;
00460 #else // All Other
00461 #endif // End ALL OS
00462 }
00463 if ( info ) *info = *vb;
00464 return status;
00465 }
00466
00467 long System::ProcessDescriptor::query(long pid,
00468 InfoType fetch,
00469 POOLED_USAGE_AND_LIMITS* info) {
00470 long status = 1;
00471 ProcessHandle h(pid);
00472 POOLED_USAGE_AND_LIMITS* vb = &m_POOLED_USAGE_AND_LIMITS[h.item()];
00473 if ( fetch == Quota ) {
00474 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00475 status = NtApi::NtQueryInformationProcess(h.handle(),
00476 ProcessPooledUsageAndLimits,
00477 vb,
00478 sizeof(POOLED_USAGE_AND_LIMITS),
00479 0);
00480 status = (status==0) ? 1 : 0;
00481 #elif defined(_WIN32) // Windows 95,98...
00482 #elif defined(linux) // Linux
00483
00484
00485 rlimit lim;
00486
00487 getrlimit(RLIMIT_DATA, &lim);
00488 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00489 vb->PeakPagedPoolUsage = lim.rlim_cur;
00490 vb->PagedPoolUsage = lim.rlim_cur;
00491 vb->PagedPoolLimit = lim.rlim_max;
00492
00493 getrlimit(RLIMIT_STACK, &lim);
00494 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00495 vb->PeakNonPagedPoolUsage = lim.rlim_cur;
00496 vb->NonPagedPoolUsage = lim.rlim_cur;
00497 vb->NonPagedPoolLimit = lim.rlim_max;
00498
00499 linux_proc prc;
00500 readProcStat(processID(pid), prc);
00501 vb->PeakPagefileUsage = prc.rss * pg_size;
00502 vb->PagefileUsage = prc.rss * pg_size;
00503 vb->PagefileLimit = 0xFFFFFFFF;
00504 #elif defined(__APPLE__)
00505 #else // All Other
00506 #endif // End ALL OS
00507 }
00508 if ( info ) *info = *vb;
00509 return status;
00510 }
00511
00512 long System::ProcessDescriptor::query(long pid, InfoType fetch, long* info) {
00513 long status = 1, *vb = &status;
00514 ProcessHandle h(pid);
00515 vb = &m_PRIORITYBOOST[h.item()];
00516 *vb = 0;
00517 switch ( fetch ) {
00518 case PriorityBoost:
00519 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00520 status = NtApi::NtQueryInformationProcess(h.handle(),
00521 ProcessPriorityBoost,
00522 vb,
00523 sizeof(long),
00524 0);
00525 #elif defined(_WIN32) // Windows 95,98...
00526 #else
00527
00528 status = 0;
00529 *vb = 0;
00530 #endif // End ALL OS
00531 status = (status==0) ? 1 : 0;
00532 break;
00533 default:
00534 status = -1;
00535 vb = &status;
00536 break;
00537 }
00538 if ( info ) *info = *vb;
00539 return status;
00540 }
00541
00542 long System::ProcessDescriptor::query(long pid,
00543 InfoType fetch,
00544 VM_COUNTERS* info) {
00545 long status = 1;
00546 ProcessHandle h(pid);
00547 VM_COUNTERS* vb = &m_VM_COUNTERS[h.item()];
00548 if ( fetch == Memory ) {
00549 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00550 status = NtApi::NtQueryInformationProcess(h.handle(),
00551 ProcessVmCounters,
00552 vb,
00553 sizeof(VM_COUNTERS),
00554 0);
00555 status = (status==0) ? 1 : 0;
00556 #elif defined(_WIN32) // Windows 95,98...
00557 #elif defined(linux) // Linux
00558 const ssize_t bufsize = 1024;
00559 char buf[bufsize];
00560 sprintf(buf,"/proc/%ld/statm", processID(pid));
00561 long size, resident, share, trs, lrs, drs, dt;
00562 int fd = open(buf,O_RDONLY);
00563 ssize_t nread = read(fd, buf, bufsize);
00564 close(fd);
00565 if ( nread < bufsize && nread >= 0 )
00566 buf[nread]='\0';
00567 fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
00568 &size, &resident, &share, &trs, &drs, &lrs, &dt);
00569 linux_proc prc;
00570 readProcStat( processID(pid), prc);
00571 vb->PeakVirtualSize = prc.vsize;
00572 vb->VirtualSize = prc.vsize;
00573 vb->PeakWorkingSetSize = resident * pg_size;
00574 vb->WorkingSetSize = resident * pg_size;
00575 vb->QuotaPeakPagedPoolUsage = share * pg_size;
00576 vb->QuotaPagedPoolUsage = share * pg_size;
00577 vb->QuotaNonPagedPoolUsage = (trs+drs)* pg_size;
00578 vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;
00579 vb->PageFaultCount = prc.majflt + prc.minflt;
00580 vb->PagefileUsage = prc.vsize-resident*pg_size;
00581 vb->PeakPagefileUsage = prc.vsize-resident*pg_size;
00582 #elif defined(__APPLE__)
00583 #else // All Other
00584 #endif // End ALL OS
00585 }
00586 if ( info ) *info = *vb;
00587 return status;
00588 }
00589
00590 long System::ProcessDescriptor::query(long pid,
00591 InfoType fetch,
00592 QUOTA_LIMITS* info) {
00593 long status = 1;
00594 ProcessHandle h(pid);
00595 QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
00596 if ( fetch == Quota ) {
00597 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00598 status = NtApi::NtQueryInformationProcess(h.handle(),
00599 ProcessQuotaLimits,
00600 vb,
00601 sizeof(QUOTA_LIMITS),
00602 0);
00603 status = (status==0) ? 1 : 0;
00604 #elif defined(_WIN32) // Windows 95,98...
00605 #elif defined(linux) // Linux
00606
00607
00608 rlimit lim;
00609 getrlimit(RLIMIT_DATA, &lim);
00610 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00611 vb->PagedPoolLimit = lim.rlim_max;
00612
00613 getrlimit(RLIMIT_STACK, &lim);
00614 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00615 vb->NonPagedPoolLimit = lim.rlim_max;
00616 vb->MinimumWorkingSetSize = 0;
00617
00618 getrlimit(RLIMIT_RSS, &lim);
00619 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00620 vb->MaximumWorkingSetSize = lim.rlim_max;
00621
00622 getrlimit(RLIMIT_AS, &lim);
00623 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00624 vb->PagefileLimit = lim.rlim_max;
00625
00626 getrlimit(RLIMIT_CPU, &lim);
00627 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00628 vb->TimeLimit = lim.rlim_max;
00629 #elif defined(__APPLE__)
00630 #else // All Other
00631 #endif // End ALL OS
00632 }
00633 if ( info ) *info = *vb;
00634 return status;
00635 }
00636
00637 long System::ProcessDescriptor::query(long pid,
00638 InfoType fetch,
00639 PROCESS_BASIC_INFORMATION* info) {
00640 long status = 1;
00641 ProcessHandle h(pid);
00642 PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
00643 if ( fetch == ProcessBasics ) {
00644 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00645 status = NtApi::NtQueryInformationProcess(h.handle(),
00646 ProcessBasicInformation,
00647 vb,
00648 sizeof(PROCESS_BASIC_INFORMATION),
00649 0);
00650 status = (status==0) ? 1 : 0;
00651 #elif defined(_WIN32) // Windows 95,98...
00652 #elif defined(linux) // Linux
00653 linux_proc prc;
00654 readProcStat( processID(pid), prc);
00655 vb->ExitStatus = 0;
00656 vb->PebBaseAddress = (PPEB)prc.startcode;
00657 vb->BasePriority = 2*15-prc.priority;
00658
00659
00660 vb->AffinityMask = prc.flags;
00661
00662
00663 vb->UniqueProcessId = processID(pid);
00664 vb->InheritedFromUniqueProcessId = prc.ppid;
00665 #else // All Other
00666 #endif // End ALL OS
00667 }
00668 if ( info ) *info = *vb;
00669 return status;
00670 }
00671
00672 long System::ProcessDescriptor::query(long pid,
00673 InfoType fetch,
00674 KERNEL_USER_TIMES* info) {
00675 long status = 1;
00676 ProcessHandle h(pid);
00677 KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
00678 if ( fetch == Times ) {
00679 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00680 status = NtApi::NtQueryInformationProcess(h.handle(),
00681 ProcessTimes,
00682 tb,
00683 sizeof(KERNEL_USER_TIMES),
00684 0);
00685 status = (status==0) ? 1 : 0;
00686 #elif defined(_WIN32) // Windows 95,98...
00687 #elif defined(linux) // Linux
00688
00689
00690 tms tmsb;
00691 static longlong prc_start = 0;
00692
00693 static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
00694 if ( processID(pid) == s_myPid && prc_start == 0 ) {
00695 linux_proc prc;
00696 readProcStat( processID(pid), prc);
00697 prc_start = prc.starttime+offset;
00698 }
00699
00700 if ( processID(pid) == s_myPid ) {
00701 struct rusage r;
00702 getrusage( RUSAGE_SELF, &r );
00703 tb->UserTime = (static_cast<long long>(r.ru_utime.tv_sec) * 1000000 +
00704 r.ru_utime.tv_usec) * 10;
00705 tb->KernelTime = (static_cast<long long>(r.ru_stime.tv_sec) * 1000000 +
00706 r.ru_stime.tv_usec) * 10;
00707 tb->CreateTime = prc_start;
00708 }
00709 else {
00710 linux_proc prc;
00711 readProcStat( processID(pid), prc );
00712
00713 tms t;
00714 times(&t);
00715 tb->UserTime = t.tms_utime * TICK_TO_100NSEC;
00716 tb->KernelTime = t.tms_stime * TICK_TO_100NSEC;
00717 tb->CreateTime = (prc.starttime+offset);
00718 }
00719 tb->CreateTime *= TICK_TO_100NSEC;
00720 tb->ExitTime = 0;
00721
00722 status = 1;
00723
00724 #elif defined(__APPLE__)
00725
00726
00727 #else // no /proc file system: assume sys_start for the first call
00728 tms tmsb;
00729 static clock_t sys_start = times(0);
00730 static longlong offset = 100*longlong(time(0)) - sys_start;
00731 clock_t now = times(&tmsb);
00732 tb->CreateTime = offset + now;
00733 tb->UserTime = tmsb.tms_utime;
00734 tb->KernelTime = tmsb.tms_stime;
00735 tb->CreateTime *= TICK_TO_100NSEC;
00736 tb->UserTime *= TICK_TO_100NSEC;
00737 tb->KernelTime *= TICK_TO_100NSEC;
00738 tb->ExitTime = 0;
00739 status = 1;
00740 #endif
00741 }
00742 if ( info ) *info = *tb;
00743 return status;
00744 }