From: Dongwoo Lee Date: Mon, 14 Mar 2022 01:43:38 +0000 (+0900) Subject: resource: Add process group resource driver X-Git-Tag: accepted/tizen/unified/20220321.141108~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3c3c861f69383c90245f1e4060f1756658535a63;p=platform%2Fcore%2Fsystem%2Fpass.git resource: Add process group resource driver This resource is pseudo-device driver which provides information of related process group. Controls: - PROCESS_GROUP_CTRL_ROOT_PID: pid of top-level process in a group what we want to see. Atrributes: - PROCESS_GROUP_ATTR_LIST: array of pid which includes all processes related with root pid. if root pid is negative, list contains all processes. Change-Id: I0b7a85dd7d8f2bd4628e17c8db923dd4abd112a8 Signed-off-by: Dongwoo Lee --- diff --git a/CMakeLists.txt b/CMakeLists.txt index b100c63..b1bf42e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ SET(SRCS src/resource/resource-system.c src/resource/resource-battery.c src/resource/resource-process.c + src/resource/resource-process-group.c src/monitor/monitor.c src/monitor/monitor-thread.c src/monitor/monitor-command.c diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index d64ad51..5cda25d 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -40,6 +40,7 @@ extern "C" { #define RESOURCE_TYPE_PROCESS 6 #define RESOURCE_TYPE_DISPLAY 7 #define RESOURCE_TYPE_SYSTEM 8 +#define RESOURCE_TYPE_PROCESS_GROUP 9 #define RESOURCE_TYPE_NONSTANDARD 99 /** @@ -122,6 +123,11 @@ extern "C" { #define PROCESS_CTRL_TGID BIT(0) +/* Process List Resource */ +#define PROCESS_GROUP_ATTR_LIST BIT(0) /* DATA_TYPE_ARRAY */ + +#define PROCESS_GROUP_CTRL_ROOT_PID BIT(0) + /** * @brief Initialize the tizen monitor * @return @c positive integer as tizen monitor id on success, otherwise a negative error value diff --git a/src/resource/resource-process-group.c b/src/resource/resource-process-group.c new file mode 100644 index 0000000..a7fc7e1 --- /dev/null +++ b/src/resource/resource-process-group.c @@ -0,0 +1,245 @@ +/* + * PASS (Power Aware System Service) - Process Group Resource Driver + * + * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#define PROC_DIR_PATH "/proc/" + +struct process_info { + pid_t pid; + pid_t ppid; + struct process_info *parent; +}; + +static int process_group_get_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 array_value *list = data; + char *statfields[PROCESS_STAT_FIELD_MAX]; + char buf[BUFF_MAX]; + GHashTableIter iter; + gpointer key, value; + GHashTable *process_hash; + GArray *process_array; + DIR *task_dir; + int i, ret = 0; + int *data_array; + pid_t pid; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + task_dir = opendir(PROC_DIR_PATH); + if (!task_dir) + return -ESRCH; + + process_hash = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free); + if (!process_hash) { + ret = -ENOMEM; + goto out_close; + } + + /* create list of all processes */ + while ((task_entry = readdir(task_dir)) != NULL) { + const char *name = task_entry->d_name; + + if (task_entry->d_type != DT_DIR && task_entry->d_type != DT_UNKNOWN) + continue; + + if (name[0] < '0' || name[0] > '9') + continue; + + pid = atoi(name); + + ret = kernel_get_process_stat_fields(pid, buf, BUFF_MAX, statfields); + if (ret < 0) + continue; /* process might be terminated */ + + pi = calloc(1, sizeof(struct process_info)); + if (!pi) { + ret = -ENOMEM; + goto out_free_hash; + } + + pi->pid = pid; + pi->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]); + + if (g_hash_table_contains(process_hash, (gpointer)&pi->ppid)) { + parent_pi = g_hash_table_lookup(process_hash, (gpointer)&pi->ppid); + + pi->parent = parent_pi; + } + + g_hash_table_insert(process_hash, (gpointer)&pi->pid, (gpointer)pi); + } + + target_pi = res->priv; + + process_array = g_array_new(false, false, sizeof(int)); + if (!process_array) { + ret = -ENOMEM; + goto out_free_hash; + } + + if (target_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); + } + } else { + g_hash_table_iter_init(&iter, process_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + pi = (struct process_info *)value; + + if (target_pi->pid == pi->pid || target_pi->pid == pi->ppid) { + g_array_append_val(process_array, pi->pid); + continue; + } + + parent_pi = pi->parent; + while (parent_pi != NULL) { + if (parent_pi->ppid == target_pi->pid) { + g_array_append_val(process_array, pi->pid); + break; + } + parent_pi = parent_pi->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; + } + 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); + +out_free_array: + g_array_free(process_array, true); +out_free_hash: + g_hash_table_destroy(process_hash); +out_close: + closedir(task_dir); + + 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; + + target = malloc(sizeof(struct process_info)); + if (!target) + return -ENOMEM; + + target->pid = -1; + target->ppid = -1; + + res->priv = target; + + return 0; +} + +static void process_group_exit(struct resource *res) +{ + if (res && res->priv) + free(res->priv); +} + +static const struct resource_driver process_group_driver = { + .name = "PROCESS_GROUP", + .type = RESOURCE_TYPE_PROCESS_GROUP, + .attrs = process_group_attrs, + .num_attrs = ARRAY_SIZE(process_group_attrs), + .ctrls = process_group_ctrls, + .num_ctrls = ARRAY_SIZE(process_group_ctrls), + .ops = { + .init = process_group_init, + .exit = process_group_exit, + }, +}; +RESOURCE_DRIVER_REGISTER(&process_group_driver)