| # Gaudi Framework, version v21r11 |

Home |  | Generated: 30 Sep 2010

# ProcessDescriptor.cpp

Go to the documentation of this file.

    00001 // $Header: /tmp/svngaudi/tmp.jEpFh25751/Gaudi/GaudiKernel/src/Lib/ProcessDescriptor.cpp,v 1.16 2007/11/21 13:04:53 marcocle Exp $
    00002 //====================================================================
    00003 //      ProcStat.cpp
    00004 //--------------------------------------------------------------------
    00005 //
    00006 //      Package    : System (The LHCb System service)
    00007 //
    00008 //  Description: Invoke interactively the ProcStat from a
    00009 //               running application
    00010 //
    00011 //      Author     : M.Frank
    00012 //      Created    : 13/11/00
    00013 //      Changes    :
    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,          // Note: this is kernel mode only
    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 //__declspec(dllimport) long __stdcall NtQueryInformationProcess(
    00059 //  typedef __declspec(dllimport) long __stdcall (*__NtQueryInformationProcess)(
    00060 //  extern "C" long __cdecl NtQueryInformationProcess(
    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; // %d
    00096         char comm[400]; // %s
    00097         char state; // %c
    00098         int ppid; // %d
    00099         int pgrp; // %d
    00100         int session; // %d
    00101         int tty; // %d
    00102         int tpgid; // %d
    00103         unsigned int flags; // %u
    00104         unsigned int minflt; // %u
    00105         unsigned int cminflt; // %u
    00106         unsigned int majflt; // %u
    00107         unsigned int cmajflt; // %u
    00108         int utime; // %d
    00109         int stime; // %d
    00110         int cutime; // %d
    00111         int cstime; // %d
    00112         int counter; // %d
    00113         int priority; // %d
    00114         unsigned int timeout; // %u
    00115         unsigned int itrealvalue; // %u
    00116         int starttime; // %d
    00117         unsigned int vsize; // %u
    00118         unsigned int rss; // %u
    00119         unsigned int rlim; // %u
    00120         unsigned long startcode; // %u
    00121         unsigned long endcode; // %u
    00122         unsigned int startstack; // %u
    00123         unsigned int kstkesp; // %u
    00124         unsigned int kstkeip; // %u
    00125         int signal; // %d
    00126         int blocked; // %d
    00127         int sigignore; // %d
    00128         int sigcatch; // %d
    00129         unsigned int wchan; // %u
    00130 };
    00131
    00132 #ifdef __APPLE__
    00133 // static long  pg_size = 0;
    00134 #else
    00135 static long  pg_size = sysconf(_SC_PAGESIZE); // getpagesize();
    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, // %d
    00162            pinfo.comm, // %s
    00163            &pinfo.state, // %c
    00164            &pinfo.ppid, // %d
    00165            &pinfo.pgrp, // %d
    00166            &pinfo.session, // %d
    00167            &pinfo.tty, // %d
    00168            &pinfo.tpgid, // %d
    00169            &pinfo.flags, // %u
    00170            &pinfo.minflt, // %u
    00171            &pinfo.cminflt, // %u
    00172            &pinfo.majflt, // %u
    00173            &pinfo.cmajflt, // %u
    00174            &pinfo.utime, // %d
    00175            &pinfo.stime, // %d
    00176            &pinfo.cutime, // %d
    00177            &pinfo.cstime, // %d
    00178            &pinfo.counter, // %d
    00179            &pinfo.priority, // %d
    00180            &pinfo.timeout, // %u
    00181            &pinfo.itrealvalue, // %u
    00182            &pinfo.starttime, // %d
    00183            &pinfo.vsize, // %u
    00184            &pinfo.rss, // %u
    00185            &pinfo.rlim, // %u
    00186            &pinfo.startcode, // %l
    00187            &pinfo.endcode, // %l
    00188            &pinfo.startstack, // %u
    00189            &pinfo.kstkesp, // %u
    00190            &pinfo.kstkeip, // %u
    00191            &pinfo.signal, // %d
    00192            &pinfo.blocked, // %d
    00193            &pinfo.sigignore, // %d
    00194            &pinfo.sigcatch, // %d
    00195            &pinfo.wchan // %u
    00196            );
    00197   }
    00198   close(fd);
    00199 }
    00200 #endif
    00201
    00202 static long s_myPid  = ::getpid();
    00203 static inline long processID(long pid) {
    00204   long thePid = (pid>0) ? pid : s_myPid;
    00205   return thePid;
    00206 }
    00207
    00208 // Framework include files
    00209 #include "ProcessDescriptor.h"
    00210 #include "GaudiKernel/ModuleInfo.h"
    00211 #include "GaudiKernel/System.h"
    00212
    00213 System::ProcessDescriptor* System::getProcess()   {
    00214   static ProcessDescriptor p;
    00215 #ifdef _WIN32
    00216   static bool first = true;
    00217   if ( first )    {
    00218     first = false;
    00219     void* mh = ::LoadLibrary("NTDll.dll");
    00220     if ( mh )  {
    00221       NtApi::NtQueryInformationProcess = (NtApi::__NtQueryInformationProcess)
    00222         ::GetProcAddress((HINSTANCE)mh, "NtQueryInformationProcess");
    00223     }
    00224   }
    00225 #endif
    00226   return &p;
    00227 }
    00228
    00229 System::ProcessDescriptor::ProcessHandle::ProcessHandle(long pid)   {
    00230   if ( pid > 0 )    {
    00231     if ( pid != s_myPid )    {
    00232 #ifdef _WIN32
    00233       m_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
    00234                                pid);
    00235 #else
    00236       m_handle = (void*)s_myPid;
    00237 #endif
    00238       m_needRelease = true;
    00239       return;
    00240     }
    00241   }
    00242   m_handle = processHandle();
    00243   m_needRelease = false;
    00244 }
    00245
    00246 System::ProcessDescriptor::ProcessHandle::~ProcessHandle()   {
    00247   if ( m_needRelease )    {
    00248 #ifdef _WIN32
    00249     ::CloseHandle(m_handle);
    00250 #else
    00251       m_handle = 0;
    00252 #endif
    00253   }
    00254 }
    00255
    00256 System::ProcessDescriptor::ProcessDescriptor()
    00257 {
    00258 }
    00259
    00260 System::ProcessDescriptor::~ProcessDescriptor()   {
    00261 }
    00262
    00263 long System::ProcessDescriptor::query(long pid,
    00264                                       InfoType fetch,
    00265                                       IO_COUNTERS* info) {
    00266   long status = 1;
    00267   ProcessHandle h(pid);
    00268   IO_COUNTERS* vb = &m_IO_COUNTERS[h.item()];
    00269   if ( fetch == IO )   {
    00270 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00271     status = NtApi::NtQueryInformationProcess(h.handle(),
    00272                                               ProcessIoCounters,
    00273                                               vb,
    00274                                               sizeof(IO_COUNTERS),
    00275                                               0);
    00276     status = (status==0) ? 1 : 0;
    00277 #elif defined(_WIN32)                     // Windows 95,98...
    00278 #elif defined(linux)
    00279     linux_proc prc;
    00280     readProcStat(processID(pid), prc);
    00281     rusage usage;
    00282     getrusage(RUSAGE_SELF, &usage);
    00283     vb->ReadOperationCount    = usage.ru_inblock;
    00284     vb->WriteOperationCount   = usage.ru_oublock;
    00285     vb->OtherOperationCount   = 0;
    00286     vb->ReadTransferCount     = usage.ru_inblock;
    00287     vb->WriteTransferCount    = usage.ru_oublock;
    00288     vb->OtherTransferCount    = 0;
    00289 #else                                     // All Other
    00290 #endif                                    // End ALL OS
    00291   }
    00292   if ( info ) *info = *vb;
    00293   return status;
    00294 }
    00295
    00296 long System::ProcessDescriptor::query(long pid,
    00297                                       InfoType fetch,
    00298                                       POOLED_USAGE_AND_LIMITS* info)    {
    00299   long status = 1;
    00300   ProcessHandle h(pid);
    00301   POOLED_USAGE_AND_LIMITS* vb = &m_POOLED_USAGE_AND_LIMITS[h.item()];
    00302   if ( fetch == Quota )   {
    00303 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00304     status = NtApi::NtQueryInformationProcess(h.handle(),
    00305                                               ProcessPooledUsageAndLimits,
    00306                                               vb,
    00307                                               sizeof(POOLED_USAGE_AND_LIMITS),
    00308                                               0);
    00309     status = (status==0) ? 1 : 0;
    00310 #elif defined(_WIN32)                     // Windows 95,98...
    00311 #elif defined(linux)                      // Linux
    00312     //rusage usage;
    00313     //getrusage(RUSAGE_SELF, &usage);
    00314     rlimit lim;
    00315
    00316     getrlimit(RLIMIT_DATA, &lim);
    00317     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00318     vb->PeakPagedPoolUsage = lim.rlim_cur;
    00319     vb->PagedPoolUsage     = lim.rlim_cur;
    00320     vb->PagedPoolLimit     = lim.rlim_max;
    00321
    00322     getrlimit(RLIMIT_STACK, &lim);
    00323     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00324     vb->PeakNonPagedPoolUsage = lim.rlim_cur;
    00325     vb->NonPagedPoolUsage     = lim.rlim_cur;
    00326     vb->NonPagedPoolLimit     = lim.rlim_max;
    00327
    00328     linux_proc prc;
    00329     readProcStat(processID(pid), prc);
    00330     vb->PeakPagefileUsage     = prc.rss * pg_size;
    00331     vb->PagefileUsage         = prc.rss * pg_size;
    00332     vb->PagefileLimit         = 0xFFFFFFFF;
    00333 #elif defined(__APPLE__)
    00334 #else                                     // All Other
    00335 #endif                                    // End ALL OS
    00336   }
    00337   if ( info ) *info = *vb;
    00338   return status;
    00339 }
    00340
    00341 long System::ProcessDescriptor::query(long pid, InfoType fetch, long* info)    {
    00342   long status = 1, *vb = &status;
    00343   ProcessHandle h(pid);
    00344   vb = &m_PRIORITYBOOST[h.item()];
    00345   *vb = 0;
    00346   switch ( fetch )    {
    00347   case PriorityBoost:
    00348 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00349     status = NtApi::NtQueryInformationProcess(h.handle(),
    00350                                               ProcessPriorityBoost,
    00351                                               vb,
    00352                                               sizeof(long),
    00353                                               0);
    00354 #elif defined(_WIN32)                     // Windows 95,98...
    00355 #else
    00356     // Not applicable
    00357     status = 0;
    00358     *vb = 0;
    00359 #endif                                    // End ALL OS
    00360     status = (status==0) ? 1 : 0;
    00361     break;
    00362   default:
    00363     status = -1;
    00364     vb = &status;
    00365     break;
    00366   }
    00367   if ( info ) *info = *vb;
    00368   return status;
    00369 }
    00370
    00371 long System::ProcessDescriptor::query(long pid,
    00372                                       InfoType fetch,
    00373                                       VM_COUNTERS* info)    {
    00374   long status = 1;
    00375   ProcessHandle h(pid);
    00376   VM_COUNTERS* vb = &m_VM_COUNTERS[h.item()];
    00377   if ( fetch == Memory )   {
    00378 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00379     status = NtApi::NtQueryInformationProcess(h.handle(),
    00380                                               ProcessVmCounters,
    00381                                               vb,
    00382                                               sizeof(VM_COUNTERS),
    00383                                               0);
    00384     status = (status==0) ? 1 : 0;
    00385 #elif defined(_WIN32)                     // Windows 95,98...
    00386 #elif defined(linux)                      // Linux
    00387     const ssize_t bufsize = 1024;
    00388     char buf[bufsize];
    00389     sprintf(buf,"/proc/%ld/statm", processID(pid));
    00390     long size, resident, share, trs, lrs, drs, dt;
    00391     int fd = open(buf,O_RDONLY);
    00392     ssize_t nread = read(fd, buf, bufsize);
    00393     close(fd);
    00394     if ( nread < bufsize && nread >= 0 )
    00395       buf[nread]='\0';
    00396     fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
    00397                      &size, &resident, &share, &trs, &drs, &lrs, &dt);
    00398     linux_proc prc;
    00399     readProcStat( processID(pid), prc);
    00400     vb->PeakVirtualSize            = prc.vsize;
    00401     vb->VirtualSize                = prc.vsize;
    00402     vb->PeakWorkingSetSize         = resident * pg_size;
    00403     vb->WorkingSetSize             = resident * pg_size;
    00404     vb->QuotaPeakPagedPoolUsage    = share    * pg_size;
    00405     vb->QuotaPagedPoolUsage        = share    * pg_size;
    00406     vb->QuotaNonPagedPoolUsage     = (trs+drs)* pg_size;// drs = data/stack size
    00407     vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;// trs = VmExe size
    00408     vb->PageFaultCount             = prc.majflt + prc.minflt;
    00409     vb->PagefileUsage              = prc.vsize-resident*pg_size;
    00410     vb->PeakPagefileUsage          = prc.vsize-resident*pg_size;
    00411 #elif defined(__APPLE__)
    00412 #else                                     // All Other
    00413 #endif                                    // End ALL OS
    00414   }
    00415   if ( info ) *info = *vb;
    00416   return status;
    00417 }
    00418
    00419 long System::ProcessDescriptor::query(long pid,
    00420                                       InfoType fetch,
    00421                                       QUOTA_LIMITS* info)    {
    00422   long status = 1;
    00423   ProcessHandle h(pid);
    00424   QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
    00425   if ( fetch == Quota )   {
    00426 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00427     status = NtApi::NtQueryInformationProcess(h.handle(),
    00428                                               ProcessQuotaLimits,
    00429                                               vb,
    00430                                               sizeof(QUOTA_LIMITS),
    00431                                               0);
    00432     status = (status==0) ? 1 : 0;
    00433 #elif defined(_WIN32)                     // Windows 95,98...
    00434 #elif defined(linux)                      // Linux
    00435     // On linux all this stuff typically is not set
    00436     // (ie. rlim_max=RLIM_INFINITY...)
    00437     rlimit lim;
    00438     getrlimit(RLIMIT_DATA, &lim);
    00439     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00440     vb->PagedPoolLimit        = lim.rlim_max;
    00441
    00442     getrlimit(RLIMIT_STACK, &lim);
    00443     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00444     vb->NonPagedPoolLimit     = lim.rlim_max;
    00445     vb->MinimumWorkingSetSize = 0;
    00446
    00447     getrlimit(RLIMIT_RSS, &lim);
    00448     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00449     vb->MaximumWorkingSetSize = lim.rlim_max;
    00450
    00451     getrlimit(RLIMIT_AS, &lim);
    00452     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00453     vb->PagefileLimit         = lim.rlim_max;
    00454
    00455     getrlimit(RLIMIT_CPU, &lim);
    00456     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
    00457     vb->TimeLimit             = lim.rlim_max;
    00458 #elif defined(__APPLE__)
    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                                       PROCESS_BASIC_INFORMATION* info)    {
    00469   long status = 1;
    00470   ProcessHandle h(pid);
    00471   PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
    00472   if ( fetch == ProcessBasics )   {
    00473 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00474     status = NtApi::NtQueryInformationProcess(h.handle(),
    00475                                               ProcessBasicInformation,
    00476                                               vb,
    00477                                               sizeof(PROCESS_BASIC_INFORMATION),
    00478                                               0);
    00479     status = (status==0) ? 1 : 0;
    00480 #elif defined(_WIN32)                     // Windows 95,98...
    00481 #elif defined(linux)                      // Linux
    00482     linux_proc prc;
    00483     readProcStat( processID(pid), prc);
    00484     vb->ExitStatus                   = 0;
    00485     vb->PebBaseAddress               = (PPEB)prc.startcode;
    00486     vb->BasePriority                 = 2*15-prc.priority;
    00487     // std::cout << "Base Priority=" << vb->BasePriority << "|"
    00488     // << prc.priority << std::endl;
    00489     vb->AffinityMask                 = prc.flags;
    00490     // std::cout << "Flags        =" << vb->AffinityMask << "|"
    00491     // << prc.flags << std::endl;
    00492     vb->UniqueProcessId              = processID(pid);
    00493     vb->InheritedFromUniqueProcessId = prc.ppid;
    00494 #else                                     // All Other
    00495 #endif                                    // End ALL OS
    00496   }
    00497   if ( info ) *info = *vb;
    00498   return status;
    00499 }
    00500
    00501 long System::ProcessDescriptor::query(long pid,
    00502                                       InfoType fetch,
    00503                                       KERNEL_USER_TIMES* info)   {
    00504   long status = 1;
    00505   ProcessHandle h(pid);
    00506   KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
    00507   if ( fetch == Times )   {
    00508 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
    00509     status = NtApi::NtQueryInformationProcess(h.handle(),
    00510                                               ProcessTimes,
    00511                                               tb,
    00512                                               sizeof(KERNEL_USER_TIMES),
    00513                                               0);
    00514     status = (status==0) ? 1 : 0;
    00515 #elif defined(_WIN32)                     // Windows 95,98...
    00516 #elif defined(linux)                      // Linux
    00517     // prc.startup is in ticks since system start :
    00518     // need to offset for absolute time
    00519     tms tmsb;
    00520     static longlong prc_start = 0;
    00521     //    static longlong offset = 100*longlong(time(0)) - longlong(times(0));
    00522     static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
    00523     if ( processID(pid) == s_myPid && prc_start == 0 ) {
    00524       linux_proc prc;
    00525       readProcStat( processID(pid), prc);
    00526       prc_start = prc.starttime+offset;
    00527     }
    00528
    00529     if ( processID(pid) == s_myPid ) {
    00530       struct rusage r;
    00531       getrusage( RUSAGE_SELF, &r );
    00532       tb->UserTime   = (static_cast<long long>(r.ru_utime.tv_sec) * 1000000 +
    00533                         r.ru_utime.tv_usec) * 10;
    00534       tb->KernelTime = (static_cast<long long>(r.ru_stime.tv_sec) * 1000000 +
    00535                         r.ru_stime.tv_usec) * 10;
    00536       tb->CreateTime = prc_start;
    00537     }
    00538     else {
    00539       linux_proc prc;
    00540       readProcStat( processID(pid), prc );
    00541
    00542       tms t;
    00543       times(&t);
    00544       tb->UserTime   = t.tms_utime * TICK_TO_100NSEC;
    00545       tb->KernelTime = t.tms_stime * TICK_TO_100NSEC;
    00546       tb->CreateTime = (prc.starttime+offset);
    00547     }
    00548     tb->CreateTime *= TICK_TO_100NSEC;
    00549     tb->ExitTime    = 0;
    00550
    00551     status = 1;
    00552
    00553 #elif defined(__APPLE__)
    00554     // FIXME (MCl): Make an alternative function get timing on OSX
    00555     // times() seems to cause a segmentation fault
    00556 #else  // no /proc file system: assume sys_start for the first call
    00557     tms tmsb;
    00558     static clock_t sys_start = times(0);
    00559     static longlong offset = 100*longlong(time(0)) - sys_start;
    00560     clock_t now = times(&tmsb);
    00561     tb->CreateTime    = offset + now;
    00562     tb->UserTime      = tmsb.tms_utime;
    00563     tb->KernelTime    = tmsb.tms_stime;
    00564     tb->CreateTime   *= TICK_TO_100NSEC;
    00565     tb->UserTime     *= TICK_TO_100NSEC;
    00566     tb->KernelTime   *= TICK_TO_100NSEC;
    00567     tb->ExitTime      = 0;
    00568     status = 1;
    00569 #endif
    00570   }
    00571   if ( info ) *info = *tb;
    00572   return status;
    00573 }