resource: process-group: Change update attributes method 13/272913/3
authorDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 23 Mar 2022 10:27:02 +0000 (19:27 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Mon, 28 Mar 2022 09:35:22 +0000 (18:35 +0900)
Instead of get process group list at individual callback,
prepare_update operation of resource is used now. Thus, all other
attributes can be retrieved at same sequence of group list.

Change-Id: I239380864cd05f5ac24017fbee6e02b069538bd0
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
lib/tmonitor/tmonitor.h
src/resource/resource-process-group.c

index 224a186..4992e11 100644 (file)
@@ -125,7 +125,7 @@ extern "C" {
 #define PROCESS_CTRL_TGID                      BIT(0)
 
 /* Process List Resource */
-#define PROCESS_GROUP_ATTR_LIST                        BIT(0)  /* DATA_TYPE_ARRAY */
+#define PROCESS_GROUP_ATTR_PID_LIST            BIT(0)  /* DATA_TYPE_ARRAY(INT) */
 
 #define PROCESS_GROUP_CTRL_ROOT_PID            BIT(0)
 
index a7fc7e1..9934442 100644 (file)
@@ -19,6 +19,7 @@
 #include <util/log.h>
 #include <util/resource.h>
 #include <util/kernel.h>
+#include <linux/taskstats.h>
 
 #include <tmonitor/tmonitor.h>
 
 struct process_info {
        pid_t pid;
        pid_t ppid;
-       struct process_info *parent;
+       char comm[TS_COMM_LEN];
 };
 
-static int process_group_get_list(const struct resource *res,
+struct process_info_node {
+       struct process_info pi;
+       struct process_info_node *parent;
+};
+
+struct process_group_context {
+       struct process_info root_pi;
+       GPtrArray *pi_list;
+};
+
+static int process_group_get_pid_list(const struct resource *res,
                                const struct resource_attribute *attr,
                                void *data)
 {
-       struct process_info *pi, *target_pi, *parent_pi;
-       struct dirent *task_entry;
+       struct process_group_context *ctx;
        struct array_value *list = data;
+       struct process_info *pi;
+       int *data_array;
+       int i;
+
+       if (!res || !res->priv || !attr || !data)
+               return -EINVAL;
+
+       ctx = res->priv;
+
+       if (!ctx->pi_list)
+               return -EINVAL;
+
+       if (list->data)
+               free(list->data);
+
+       data_array = list->data = malloc(sizeof(int) * ctx->pi_list->len);
+       if (!data_array)
+               return -ENOMEM;
+
+       list->type = DATA_TYPE_INT;
+       list->length = ctx->pi_list->len;
+
+       for (i = 0; i < list->length; i++) {
+               pi = g_ptr_array_index(ctx->pi_list, i);
+               data_array[i] = pi->pid;
+       }
+
+       return 0;
+}
+
+static const struct resource_attribute process_group_attrs[] = {
+       {
+               .name   = "PROCESS_GROUP_ATTR_PID_LIST",
+               .id     = PROCESS_GROUP_ATTR_PID_LIST,
+               .type   = DATA_TYPE_ARRAY,
+               .ops    = {
+                       .get = process_group_get_pid_list,
+                       .is_supported = resource_attr_supported_always,
+               },
+       },
+};
+
+static int process_group_setup_root_pid(const struct resource *res,
+                               const struct resource_control *ctrl,
+                               const void *data)
+{
+       struct process_group_context *ctx;
+       struct process_info *target;
+       char *statfields[PROCESS_STAT_FIELD_MAX];
+       char buf[BUFF_MAX];
+       int target_pid;
+       int ret;
+
+       if (!res || !res->priv || !ctrl)
+               return -EINVAL;
+
+       ctx = res->priv;
+
+       target = &ctx->root_pi;
+
+       target_pid = (int)(intptr_t)data;
+
+       if (target_pid < 0) {
+               target->pid = target->ppid = -1;
+               return 0;
+       }
+
+       ret = kernel_get_process_stat_fields(target_pid, buf, BUFF_MAX, statfields);
+       if (ret < 0) {
+               _E("target process pid is not valid");
+               target->pid = target->ppid = -1;
+               return ret;
+       }
+
+       target->pid = atoi(statfields[PROCESS_STAT_FIELD_PID]);
+       target->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
+
+       return 0;
+}
+
+static const struct resource_control process_group_ctrls[] = {
+       {
+               .name = "PROCESS_GROUP_CTRL_ROOT_PID",
+               .id = PROCESS_GROUP_CTRL_ROOT_PID,
+               .ops = {
+                       .set = process_group_setup_root_pid,
+               },
+       },
+};
+
+static int process_group_prepare_update(struct resource *res)
+{
+       struct process_group_context *ctx;
+       struct process_info_node *pnode, *parent_pnode;
+       struct process_info *pi, *root_pi;
+       struct dirent *task_entry;
        char *statfields[PROCESS_STAT_FIELD_MAX];
        char buf[BUFF_MAX];
+       GPtrArray *pi_list;
        GHashTableIter iter;
        gpointer key, value;
        GHashTable *process_hash;
-       GArray *process_array;
        DIR *task_dir;
-       int i, ret = 0;
-       int *data_array;
-       pid_t pid;
+       int len, ret = 0;
+       pid_t pid, ppid, pgrp;
 
-       if (!res || !res->priv || !attr || !data)
+       if (!res || !res->priv)
                return -EINVAL;
 
+       ctx = res->priv;
+
        task_dir = opendir(PROC_DIR_PATH);
        if (!task_dir)
                return -ESRCH;
@@ -77,76 +184,106 @@ static int process_group_get_list(const struct resource *res,
                if (ret < 0)
                        continue; /* process might be terminated */
 
-               pi = calloc(1, sizeof(struct process_info));
-               if (!pi) {
+               ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
+               pgrp = atoi(statfields[PROCESS_STAT_FIELD_PGID]);
+
+               /* except kthreads */
+               if (pid == 2 || ppid == 2 || pgrp == 2)
+                       continue;
+
+               pnode = calloc(1, sizeof(struct process_info_node));
+               if (!pnode) {
                        ret = -ENOMEM;
                        goto out_free_hash;
                }
 
-               pi->pid = pid;
-               pi->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
+               pnode->pi.pid = pid;
+               pnode->pi.ppid = ppid;
+
+               len = strlen(statfields[PROCESS_STAT_FIELD_COMM]) - 2/* '(', ')' */;
+               len = (len < TS_COMM_LEN - 1) ? len : TS_COMM_LEN - 1;
+               strncpy(pnode->pi.comm, statfields[PROCESS_STAT_FIELD_COMM] + 1, len);
 
-               if (g_hash_table_contains(process_hash, (gpointer)&pi->ppid)) {
-                       parent_pi = g_hash_table_lookup(process_hash, (gpointer)&pi->ppid);
+               if (g_hash_table_contains(process_hash, (gpointer)&pnode->pi.ppid)) {
+                       parent_pnode = g_hash_table_lookup(process_hash, (gpointer)&pnode->pi.ppid);
 
-                       pi->parent = parent_pi;
+                       pnode->parent = parent_pnode;
                }
 
-               g_hash_table_insert(process_hash, (gpointer)&pi->pid, (gpointer)pi);
+               g_hash_table_insert(process_hash, (gpointer)&pnode->pi.pid, (gpointer)pnode);
        }
 
-       target_pi = res->priv;
-
-       process_array = g_array_new(false, false, sizeof(int));
-       if (!process_array) {
+       pi_list = g_ptr_array_new_full(100, free);
+       if (!pi_list) {
                ret = -ENOMEM;
                goto out_free_hash;
        }
 
-       if (target_pi->pid < 0) {
+       root_pi = &ctx->root_pi;
+
+       if (root_pi->pid < 0) {
                /* just add all processes into array if parent pid is negative */
                g_hash_table_iter_init(&iter, process_hash);
                while (g_hash_table_iter_next(&iter, &key, &value)) {
-                       pi = (struct process_info *)value;
-                       g_array_append_val(process_array, pi->pid);
+                       pnode = (struct process_info_node *)value;
+
+                       pi = malloc(sizeof(struct process_info));
+                       if (!pi) {
+                               g_ptr_array_free(pi_list, true);
+                               ctx->pi_list = NULL;
+                               goto out_free_hash;
+                       }
+
+                       memcpy(pi, &pnode->pi, sizeof(struct process_info));
+                       g_ptr_array_add(pi_list, pi);
                }
        } else {
                g_hash_table_iter_init(&iter, process_hash);
                while (g_hash_table_iter_next(&iter, &key, &value)) {
-                       pi = (struct process_info *)value;
+                       pnode = (struct process_info_node *)value;
 
-                       if (target_pi->pid == pi->pid || target_pi->pid == pi->ppid) {
-                               g_array_append_val(process_array, pi->pid);
+                       if (root_pi->pid == pnode->pi.pid || root_pi->pid == pnode->pi.ppid) {
+
+                               pi = malloc(sizeof(struct process_info));
+                               if (!pi) {
+                                       g_ptr_array_free(pi_list, true);
+                                       ctx->pi_list = NULL;
+                                       goto out_free_hash;
+                               }
+
+                               memcpy(pi, &pnode->pi, sizeof(struct process_info));
+                               g_ptr_array_add(pi_list, pi);
                                continue;
                        }
 
-                       parent_pi = pi->parent;
-                       while (parent_pi != NULL) {
-                               if (parent_pi->ppid == target_pi->pid) {
-                                       g_array_append_val(process_array, pi->pid);
+                       parent_pnode = pnode->parent;
+                       while (parent_pnode != NULL) {
+                               if (parent_pnode->pi.ppid == root_pi->pid) {
+                                       pi = malloc(sizeof(struct process_info));
+                                       if (!pi) {
+                                               g_ptr_array_free(pi_list, true);
+                                               ctx->pi_list = NULL;
+                                               goto out_free_hash;
+                                       }
+
+                                       memcpy(pi, &pnode->pi, sizeof(struct process_info));
+                                       g_ptr_array_add(pi_list, pi);
                                        break;
                                }
-                               parent_pi = parent_pi->parent;
+                               parent_pnode = parent_pnode->parent;
                        }
                }
        }
 
-       if (list->data)
-               free(list->data);
-
-       data_array = list->data = malloc(sizeof(int) * process_array->len);
-       if (!data_array) {
-               ret = -ENOMEM;
-               goto out_free_array;
+       if (ctx->pi_list) {
+               /* remove previous list */
+               g_ptr_array_free(ctx->pi_list, true);
+               ctx->pi_list = NULL;
        }
-       list->type = DATA_TYPE_INT;
-       list->length = process_array->len;
 
-       for (i = 0; i < list->length; i++)
-               data_array[i] = g_array_index(process_array, int, i);
+       ctx->pi_list = pi_list;
 
-out_free_array:
-       g_array_free(process_array, true);
+       ret = 0;
 out_free_hash:
        g_hash_table_destroy(process_hash);
 out_close:
@@ -155,71 +292,18 @@ out_close:
        return ret;
 }
 
-static const struct resource_attribute process_group_attrs[] = {
-       {
-               .name   = "PROCESS_GROUP_ATTR_LIST",
-               .id     = PROCESS_GROUP_ATTR_LIST,
-               .type   = DATA_TYPE_ARRAY,
-               .ops    = {
-                       .get = process_group_get_list,
-                       .is_supported = resource_attr_supported_always,
-               },
-       },
-};
-
-static int process_group_setup_root_pid(const struct resource *res,
-                               const struct resource_control *ctrl,
-                               const void *data)
-{
-       struct process_info *target;
-       char *statfields[PROCESS_STAT_FIELD_MAX];
-       char buf[BUFF_MAX];
-       int target_pid;
-       int ret;
-
-       if (!res || !res->priv || !ctrl)
-               return -EINVAL;
-
-       target = res->priv;
-
-       target_pid = (int)(intptr_t)data;
-
-       ret = kernel_get_process_stat_fields(target_pid, buf, BUFF_MAX, statfields);
-       if (ret < 0) {
-               _E("target process pid is not valid");
-               target->pid = -1;
-               target->ppid = -1;
-               return ret;
-       }
-
-       target->pid = atoi(statfields[PROCESS_STAT_FIELD_PID]);
-       target->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
-
-       return 0;
-}
-
-static const struct resource_control process_group_ctrls[] = {
-       {
-               .name = "PROCESS_GROUP_CTRL_ROOT_PID",
-               .id = PROCESS_GROUP_CTRL_ROOT_PID,
-               .ops = {
-                       .set = process_group_setup_root_pid,
-               },
-       },
-};
-
 static int process_group_init(struct resource *res)
 {
-       struct process_info *target;
+       struct process_group_context *ctx;
 
-       target = malloc(sizeof(struct process_info));
-       if (!target)
+       ctx = malloc(sizeof(struct process_group_context));
+       if (!ctx)
                return -ENOMEM;
 
-       target->pid = -1;
-       target->ppid = -1;
+       ctx->root_pi.pid = ctx->root_pi.ppid = -1;
+       ctx->pi_list = NULL;
 
-       res->priv = target;
+       res->priv = ctx;
 
        return 0;
 }
@@ -240,6 +324,7 @@ static const struct resource_driver process_group_driver = {
        .ops            = {
                .init = process_group_init,
                .exit = process_group_exit,
+               .prepare_update = process_group_prepare_update,
        },
 };
 RESOURCE_DRIVER_REGISTER(&process_group_driver)