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