diff mbox

[ovs-dev,RFC,v3,02/18] process: Add helper functions to retrieve process related info.

Message ID 1497813871-27572-3-git-send-email-bhanuprakash.bodireddy@intel.com
State RFC
Headers show

Commit Message

Bodireddy, Bhanuprakash June 18, 2017, 7:24 p.m. UTC
Implement helper functions to retrieve the process status, name and last
core the process was scheduled. The APIs will be used by keepalive monitoring
framework in future commits.

Signed-off-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy@intel.com>
---
 lib/process.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/process.h |  13 +++++
 2 files changed, 165 insertions(+)
diff mbox

Patch

diff --git a/lib/process.c b/lib/process.c
index e9d0ba9..4c029c1 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -50,6 +50,20 @@  struct process {
     int status;
 };
 
+struct pstate2Num {
+    char *pidstate;
+    int num;
+};
+
+const struct pstate2Num pstate_map[] = {
+    { "S", STOPPED_STATE },
+    { "R", ACTIVE_STATE },
+    { "t", TRACED_STATE },
+    { "Z", DEFUNC_STATE },
+    { "D", UNINTERRUPTIBLE_SLEEP_STATE },
+    { "NULL", UNUSED_STATE },
+};
+
 /* Pipe used to signal child termination. */
 static int fds[2];
 
@@ -390,6 +404,144 @@  process_run(void)
 #endif
 }
 
+int
+get_process_status(int pid, int *pstate)
+{
+#ifdef __linux__
+    static char process_name[20];
+    FILE *stream;
+    char line[75];
+    char Name[15], value[5], status[20];
+    int i, ln;
+
+    snprintf(process_name, sizeof(process_name),
+             "/proc/%d/status", pid);
+    stream = fopen(process_name, "r");
+    if (stream == NULL) {
+        VLOG_WARN_ONCE("%s: open failed: %s", process_name,
+            ovs_strerror(errno));
+        return errno;
+    }
+
+    ln=0;
+    while (fgets(line, sizeof line, stream)) {
+        if (!ovs_scan(line,
+                      "%6s %2s %14s\n",
+                       Name, value, status)) {
+            VLOG_WARN_ONCE("%s: could not parse line %d: %s",
+                    process_name, ln, line);
+            continue;
+        }
+        if (!strcmp(Name, "State:")) {
+            for (i=0; pstate_map[i].pidstate != NULL; i++) {
+                if (strcmp(pstate_map[i].pidstate, value) == 0) {
+                    VLOG_WARN_ONCE("The state is %s, status is %d\n",
+                        pstate_map[i].pidstate, pstate_map[i].num);
+                    *pstate = pstate_map[i].num;
+                    break;
+                }
+            }
+            break;
+        }
+        ln++;
+   }
+   return 0;
+#else
+   return ENOSYS;
+#endif
+}
+
+bool
+process_is_active(int pid)
+{
+#ifdef __linux__
+    int pstate;
+    int err = get_process_status(pid, &pstate);
+    if (!err) {
+        if (pstate == ACTIVE_STATE) {
+            return true;
+        }
+    }
+    return false;
+#else
+   return false;
+#endif
+}
+
+char *
+get_process_name(int pid)
+{
+#ifdef __linux__
+    static char proc_path[PATH_MAX];
+    FILE *stream;
+    char line[20];
+    char *pname = xmalloc(20);
+
+    if (pid == -1) {
+       VLOG_ERR("Invalid process id : %d", pid);
+       return NULL;
+    }
+
+    snprintf(proc_path, sizeof(proc_path),
+             "/proc/%d/task/%d/comm", pid, pid);
+    stream = fopen(proc_path, "r");
+    if (!stream) {
+        VLOG_WARN("%s: open failed: %s", proc_path, ovs_strerror(errno));
+        return NULL;
+    }
+
+    if (fgets(line, sizeof line, stream) != NULL) {
+        if (ovs_scan(line, "%s", pname)) {
+            return pname;
+        }
+    }
+    return NULL;
+#else
+    return NULL;
+#endif
+}
+
+/* Retrieve the last core id that executed the process.
+ *
+ * Refer http://man7.org/linux/man-pages/man5/proc.5.html
+ * and the processor field in /proc/[pid]/stat.
+ */
+int
+get_cpu_num(int pid)
+{
+#ifdef __linux__
+    static char proc_path[PATH_MAX];
+    FILE *stream;
+    char line[500];
+
+    snprintf(proc_path, sizeof(proc_path),
+             "/proc/%d/stat", pid);
+    stream = fopen(proc_path, "r");
+    if (!stream) {
+        VLOG_WARN_ONCE("%s: open failed: %s", proc_path, ovs_strerror(errno));
+        return errno;
+    }
+
+    int i;
+    int cpu_id = -1;
+    if (fgets(line, sizeof line, stream) != NULL) {
+        char *tok, *endptr = NULL;
+        for (tok = strtok_r(line, " ", &endptr), i = 1; tok != NULL;
+                tok = strtok_r(NULL, " ", &endptr), i++) {
+            VLOG_DBG("token :%s", tok);
+            if (i == 39) {
+                cpu_id = atoi(tok);
+                break;
+            }
+        }
+    }
+
+    ovs_assert(cpu_id >= 0)
+    return cpu_id;
+#else
+    return ENOSYS;
+#endif
+}
 
 /* Causes the next call to poll_block() to wake up when process 'p' has
  * exited. */
diff --git a/lib/process.h b/lib/process.h
index 3feac7e..041767d 100644
--- a/lib/process.h
+++ b/lib/process.h
@@ -20,6 +20,15 @@ 
 #include <stdbool.h>
 #include <sys/types.h>
 
+enum process_states {
+    UNUSED_STATE,
+    STOPPED_STATE,
+    ACTIVE_STATE,
+    TRACED_STATE,
+    DEFUNC_STATE,
+    UNINTERRUPTIBLE_SLEEP_STATE
+};
+
 struct process;
 
 /* Starting and monitoring subprocesses.
@@ -38,6 +47,10 @@  bool process_exited(struct process *);
 int process_status(const struct process *);
 void process_run(void);
 void process_wait(struct process *);
+int get_process_status(int, int *);
+bool process_is_active(int pid);
+char *get_process_name(int);
+int get_cpu_num(int pid);
 
 /* These functions are thread-safe. */
 char *process_status_msg(int);