// processinfo_linux2.cpp

#include "processinfo.h"

#include <iostream>
#include <stdio.h>

using namespace std;

#define KLONG long
#define KLF "l"

namespace mongo {
    
    class LinuxProc {
    public:
        LinuxProc( pid_t pid = getpid() ){
            char name[128];
            sprintf( name , "/proc/%d/stat"  , pid );
  
            FILE * f = fopen( name , "r");

            fscanf(f,
                   "%d %s %c "
                   "%d %d %d %d %d "
                   "%lu %lu %lu %lu %lu "
                   "%lu %lu %ld %ld "  /* utime stime cutime cstime */
                   "%ld %ld "
                   "%ld "
                   "%ld "
                   "%lu "  /* start_time */
                   "%lu "
                   "%ld " // rss
                   "%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
                   /*
                     "%*s %*s %*s %*s " 
                     "%"KLF"u %*lu %*lu "
                     "%d %d "
                     "%lu %lu"
                   */

                   ,

                   &_pid,
                   _comm,
                   &_state,
                   &_ppid, &_pgrp, &_session, &_tty, &_tpgid,
                   &_flags, &_min_flt, &_cmin_flt, &_maj_flt, &_cmaj_flt,
                   &_utime, &_stime, &_cutime, &_cstime,
                   &_priority, &_nice,
                   &_alarm,
                   &_nlwp,
                   &_start_time,
                   &_vsize,
                   &_rss,
                   &_rss_rlim, &_start_code, &_end_code, &_start_stack, &_kstk_esp, &_kstk_eip

                   /*
                     &_wchan, 
                     &_exit_signal, &_processor,  
                     &_rtprio, &_sched  
                   */
                   );

            fclose( f );
        }
        
        unsigned long getVirtualMemorySize(){
            return _vsize;
        }
        
        unsigned long getResidentSize(){
            return (unsigned long)_rss * 4 * 1024;
        }
        
    private:
        int _pid; 
        // The process ID.
        
        char _comm[128]; 
        // The filename of the executable, in parentheses.  This is visible whether or not the executable is swapped out.
        
        char _state;
        //One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting  in  uninterruptible
        //  disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
        
        int _ppid;
        // The PID of the parent.
        
        int _pgrp;
        // The process group ID of the process.
        
        int _session;
        // The session ID of the process.
        
        int _tty;
        // The tty the process uses.
        
        int _tpgid;
        // The process group ID of the process which currently owns the tty that the process is connected to.
        
        unsigned long _flags; // %lu
        // The  kernel flags word of the process. For bit meanings, see the PF_* defines in <linux/sched.h>.  Details depend on the kernel version.
        
        unsigned long _min_flt; // %lu
        // The number of minor faults the process has made which have not required loading a memory page from disk.
        
        unsigned long _cmin_flt; // %lu
        // The number of minor faults that the process
        
        unsigned long _maj_flt; // %lu
        // The number of major faults the process has made which have required loading a memory page from disk.
        
        unsigned long _cmaj_flt; // %lu
        // The number of major faults that the process
        
        unsigned long _utime; // %lu
        // The number of jiffies that this process has been scheduled in user mode.
        
        unsigned long _stime; //  %lu
        // The number of jiffies that this process has been scheduled in kernel mode.
        
        long _cutime; // %ld
        // The number of jiffies that this removed field.
        
        long _cstime; // %ld
        
        long _priority;
        long _nice;
        
        long _nlwp; // %ld
        // The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
        
        unsigned long _alarm;
        
        unsigned long _start_time; // %lu
        // The time in jiffies the process started after system boot.
        
        unsigned long _vsize; // %lu
        // Virtual memory size in bytes.
        
        long _rss; // %ld
        // Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which
        // count  towards  text,  data, or stack space.  This does not include pages which have not been demand-loaded in, or which are swapped out
        
        unsigned long _rss_rlim; // %lu
        // Current limit in bytes on the rss of the process (usually 4294967295 on i386).
        
        unsigned long _start_code; // %lu
        // The address above which program text can run.
        
        unsigned long _end_code; // %lu
        // The address below which program text can run.
        
        unsigned long _start_stack; // %lu
        // The address of the start of the stack.
        
        unsigned long _kstk_esp; // %lu
        // The current value of esp (stack pointer), as found in the kernel stack page for the process.
        
        unsigned long _kstk_eip; // %lu
        // The current EIP (instruction pointer).
        
  
  
    };


    ProcessInfo::ProcessInfo( pid_t pid ) : _pid( pid ){
    }

    ProcessInfo::~ProcessInfo(){
    }

    bool ProcessInfo::supported(){
        return true;
    }
    
    int ProcessInfo::getVirtualMemorySize(){
        LinuxProc p(_pid);
        return (int)( p.getVirtualMemorySize() / ( 1024.0 * 1024 ) );
    }
    
    int ProcessInfo::getResidentSize(){
        LinuxProc p(_pid);
        return (int)( p.getResidentSize() / ( 1024.0 * 1024 ) );
    }

}
