rtop
proc_info.h
Go to the documentation of this file.
1 #include <string>
2 #include <map>
3 #include <dirent.h>
4 #include <fstream>
5 #include <sstream>
6 #include <cstdlib>
7 #include <vector>
8 #include <string.h>
9 #include <stdexcept>
10 
11 #ifndef PROC_INFO_H_
12 #define PROC_INFO_H_
13 #include "rtop_logger.h"
14 #include "info.h"
15 #include "rtop_utils.h"
16 
17 extern src::severity_logger<severity_level> lg;
18 extern logSpacer log_spacer;
19 
20 namespace rtop
21 {
22 
24  class ProcInfo
25  {
26  private:
27  int uuid;
29  std::string sortkey;
31  std::unordered_set<int> pid_set;
33  std::unordered_set<std::string> prop_set;
35  void sort();
37  void read();
40  public:
42  ProcInfo(int id):uuid{id}{}
44  void kill(){}
46  void update(std::vector<std::string>& prop_vec, std::string sort_key);
47  friend class XMLTree;
48  };
49 
50 
51  void ProcInfo::update(std::vector<std::string>& prop_vec, std::string sort_key)
52  {
54  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"--> ProcInfo-"<<uuid<<"_update::, id: "<<uuid;
55  proc_database->access.lock(); // acquire lock on ProcDb before changing it
56  sortkey = sort_key;
57  for(auto p: prop_vec)
58  prop_set.insert(p);
59  read(); // reads the /proc database and updates proc_database based on supplied properties
60  sort(); // reads a specific prop vector, and updates the proc_database.sorted_indices vector field.
61  proc_database->access.unlock();
62 
63  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"<-- ProcInfo-"<<uuid<<"_update::, id: "<<uuid;
65  }
66 
67 
69  {
71  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"--> ProcInfo-"<<uuid<<"_read::";
72 
73  // parse all sub-directories corresponding to numeric pids from /proc directory
74  DIR* dirp = opendir("/proc"); // open /proc directory and returns handle to parse directory contents
75  if (dirp == NULL) // if error in opening directory
76  {
77  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"ProcInfo-"<<uuid<<"_read::, failed to open directory";
78  throw std::runtime_error("ProcInfo::read, failed to open directory\n");
79  }
80 
81  struct dirent* dp;
82  while(1) // iterate over all contents of /proc using directory pointer dirp obtained above
83  {
84  dp = readdir(dirp); // returns object of type dirent, that contains sub-directory name
85  if (dp == NULL) // reached end of /proc directory
86  break;
87  std::string str(dp->d_name);
88  if (str.find_first_not_of("0123456789") == std::string::npos) // if sub-directory name is all numeric, insert into pid hashset
89  pid_set.insert(std::stoi(str));
90 
91  }
92  if (closedir(dirp) == -1) // finished reading /proc, close dir stream
93  {
94  BOOST_LOG_SEV(lg, fatal)<<log_spacer<<"ProcInfo-"<<uuid<<"_read::, failed to close /proc directory";
95  throw std::runtime_error("ProcInfo::read, failed to closed /proc directory\n");
96  }
97 
98  // update ProcDb::database
99  for(auto p=prop_set.begin(); p != prop_set.end(); p++) // clear those property process vectors that need to be update
100  proc_database->database[*p].clear();
101 
102  // read /proc/pid/stat, /proc/pid/status and /proc/pid/cmdline files to updates the property process vectors in ProcDb::database
103  std::stringstream ss(std::ios_base::out | std::ios_base::in | std::ios_base::ate);
104  ss.exceptions(std::ios::failbit);
105  std::ifstream ifs_stat, ifs_cmdline, ifs_status; // file streams to open stat, status and cmdline files in /pid directory
106 
107  int d_val; // temp variable to hold parsed value
108  long l_val; // temp variable to hold parsed value
109  int proc_added = 0; // counter to track number of processes added
110 
111  // iterate over recently creted pid_set and parse cmdline, status and stat files for info
112  for(auto pid: pid_set)
113  {
114  ss.str("");
115  ss.clear();
116  ss<<"/proc/"<<pid<<"/stat";
117  ifs_stat.open(ss.str()); // open file descriptor for /proc/pid/stat
118  ss.str("");
119  ss.clear();
120  ss<<"/proc/"<<pid<<"/cmdline";
121  ifs_cmdline.open(ss.str()); // open file descriptor for /proc/pid/cmdline
122  ss.str("");
123  ss.clear();
124  ss<<"/proc/"<<pid<<"/status";
125  ifs_status.open(ss.str()); // open file descriptor for /proc/pid/status
126 
127  if (!ifs_stat || !ifs_cmdline || !ifs_status) // if process has been deleted already, one of the file opening could have failed.
128  {
129  if (!ifs_stat)
130  BOOST_LOG_SEV(lg, error)<<log_spacer<<"/proc/"<<pid<<"/stat "<<strerror(errno);
131  if (!ifs_cmdline)
132  BOOST_LOG_SEV(lg, error)<<log_spacer<<"/proc/"<<pid<<"/cmdline "<<strerror(errno);
133  if (!ifs_status)
134  BOOST_LOG_SEV(lg, error)<<log_spacer<<"/proc/"<<pid<<"/status "<<strerror(errno);
135 
136  ifs_stat.clear(); // clear status before moving to next pid
137  ifs_cmdline.clear();
138  ifs_status.clear();
139  }
140  else // if files were successfully opened
141  {
142  std::string line, cmdline_str, status_line;
143 
144  // read command line string
145  std::getline(ifs_cmdline, cmdline_str); // read from command line string for process from cmdline file
146  ifs_cmdline.close();
147 
148  cmdline_str.clear();
149  if (cmdline_str == "") // if cmdline file is empty, read command string info from status file
150  {
151  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"/proc/"<<pid<<"/cmdline"<<" empty";
152  std::string tmpstr = "";
153  ss.str("");
154  ss.clear();
155  std::getline(ifs_status, status_line);
156  ss<<status_line;
157  ss>>tmpstr;
158  while(ss.good()) // concatenate all white-space separated content into command line string
159  {
160  ss>>tmpstr;
161  cmdline_str += tmpstr;
162  }
163  }
164  ifs_status.close();
165 
166  // read other process properties
167  std::getline(ifs_stat, line); // read data string containing property field from stat file
168  ifs_stat.close();
169 
170  std::string discard_str;
171  ss.str("");
172  ss.clear();
173  ss<<line; // read the /proc/PID/stat file with a single line
174  int loc = 0;
176  while(ss.good()) // parse the line containing white-spaced separated property values
177  {
178  loc++;
179  if (proc_database->field_prop_dict.find(loc) != proc_database->field_prop_dict.end()) // if loc corresponds to property field location recognized by ProcDb
180  {
181  if (prop_set.find(proc_database->field_prop_dict[loc].first) == prop_set.end()) // if property is not in prop_set to be updated, skip
182  {
183  ss>> discard_str;
184  continue;
185  }
186  std::string strval;
187  if(proc_database->field_prop_dict[loc].second == "int") // if prop_type is integer type read into integer var
188  {
189  try{
190  ss>>d_val;
191  }
192  catch(std::runtime_error e)
193  {
194  BOOST_LOG_SEV(lg, error)<<log_spacer<<e.what();
195  ss.clear();
196  }
197  strval = std::to_string(d_val);
198  InfoProc<std::string> inf{strval}; // construct InfoProc object for storage into ProcDb database
199  proc_database->database[proc_database->field_prop_dict[loc].first].push_back(inf);// put InfoProc object into approprirate property process vector
200  continue;
201  }
202  if(proc_database->field_prop_dict[loc].second == "long") // if prop_type is long type, read into long var
203  {
204  ss>>l_val;
205  if (loc == 14 || loc == 15) // perform data computation for time calculation
206  strval = msecToTimeStr(l_val*10);
207  else
208  strval = std::to_string(l_val);
209  InfoProc<std::string> inf{strval};
210  proc_database->database[proc_database->field_prop_dict[loc].first].push_back(inf); // put InfoProc object into appropriate property process vector
211  continue;
212  }
213  }
214  else // if loc does not correspond to any location recognoized ProcDb
215  ss>>discard_str;
216  }
217  InfoProc<std::string> inf{cmdline_str};
219  proc_database->database["Command"].push_back(inf); // update "Command" property process vector
220  proc_added++;
221  }
222  }
223  proc_database->dbsize = proc_added; // update ProcDb::dbsize variable by number of processes parsed
224  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"<-- ProcInfo-"<<uuid<<"_read::";
226  }
227 
230  {
232  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"--> ProcInfo-"<<uuid<<"_sort::, sortkey: "<<sortkey<<" sorted_indices size: "<<proc_database->sorted_indices.size()<<"database size: "<<proc_database->database[sortkey].size();
233 
234  proc_database->sorted_indices.clear();
235  if (proc_database->prop_type_dict[sortkey] == "int") // if property type is int
236  {
237  // copy property process vector corresponding to sortkey
238  std::vector<int> v;
239  for(auto item: proc_database->database[sortkey])
240  v.push_back(std::stoi(item.Val()));
241  // sort the property process vector, store resulting permutation vector in ProcDb::sorted_indices
242  proc_database->sorted_indices = sort_permutation(v, [](int const& a, int const& b){return a<b;});
243  }
244  if (proc_database->prop_type_dict[sortkey] == "long") // if property type is long
245  {
246  // copy property process vector corresponding to sortkey
247  std::vector<long> v;
248  for(auto item: proc_database->database[sortkey])
249  v.push_back(std::stol(item.Val()));
250  // sort the property process vector, store resulting permutation vector in ProcDb::sorted_indices
251  proc_database->sorted_indices = sort_permutation(v, [](const long& a, const long& b){return a<b;});
252 
253  }
254  BOOST_LOG_SEV(lg, debug)<<log_spacer<<"<-- ProcInfo-"<<uuid<<"_sort:: sorted_indices size: "<<proc_database->sorted_indices.size()<<"database size: "<<proc_database->database[sortkey].size();
255 ;
256  log_spacer.delSpace();
257  }
258 
259 } // rtop
260 
261 #endif
void kill()
Definition: proc_info.h:44
ProcInfo(int id)
ProcInfo constructor. Instantiates ProcInfo object with provided unique identifier.
Definition: proc_info.h:42
int dbsize
size of property vector i.e. number of processes whose properties are being maintained
Definition: info.h:123
void read()
reads property values specified in ProcInfo::prop_set for each process and stores result in ProcDb::d...
Definition: proc_info.h:68
std::unordered_set< int > pid_set
hashset for storing processs PIDs
Definition: proc_info.h:31
std::string msecToTimeStr(unsigned long msec)
converts msec to TimerStr for display as min:sec.secs_fraction
Definition: rtop_utils.h:138
data structure that hold property values for processes. contains facilities to enable their proper ac...
Definition: info.h:109
std::vector< int > sorted_indices
vector that holds the permutation order to parse property vectors in sorted order
Definition: info.h:117
src::severity_logger< severity_level > lg
Definition: rtop_logger.h:108
void delSpace()
deletes one white-space from white-space string corresponding to invoking thread
Definition: rtop_logger.h:151
ProcDb * proc_database
pointer to access ProcDb data structure
Definition: proc_info.h:39
logSpacer log_spacer
Definition: rtop_logger.h:186
std::map< std::string, std::vector< InfoProc< std::string > > > database
dictionary that holds vector of values corresponding to each property name string
Definition: info.h:115
void sort()
sorts property value vector corresponding to sortkey, and stores resulting permutation vector in Proc...
Definition: proc_info.h:229
std::vector< int > sort_permutation(const std::vector< T > &vec, Compare compare)
returns permutation vector after sorting the given vector based on the provided compare function
Definition: rtop_utils.h:27
void addSpace()
adds one white-space to white-space string corresponding to invoking thread
Definition: rtop_logger.h:135
std::map< int, std::pair< std::string, std::string > > field_prop_dict
dictionary that holds property locations in /proc/pid/stat file, and correspondingg prop name and typ...
Definition: info.h:119
std::unordered_set< std::string > prop_set
hashset for storing property names, whose corresponding vectors in ProcDb need to be updated
Definition: proc_info.h:33
std::map< std::string, std::string > prop_type_dict
dictionary hold property name and corresponding type
Definition: info.h:121
enables indentation of logs for easy viewing
Definition: rtop_logger.h:118
data structure that defines type of entry from which panel menu entries obtain their c-string data
Definition: info.h:71
interfaces with linux API to read process information and update ProcDb with it
Definition: proc_info.h:24
void update(std::vector< std::string > &prop_vec, std::string sort_key)
invoked by Columns::read. reads process prop values, sorts them and then updates ProcDb
Definition: proc_info.h:51
parses config file
Definition: fileio.h:28
std::string sortkey
variable to hold property name to be sorted. used by ProcInfo::sort to sort process values correspond...
Definition: proc_info.h:29
Definition: action.h:7
std::mutex access
Definition: info.h:112