#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;
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:
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;
}
.ops = {
.init = process_group_init,
.exit = process_group_exit,
+ .prepare_update = process_group_prepare_update,
},
};
RESOURCE_DRIVER_REGISTER(&process_group_driver)