#include "fd-handler.h"
#include "proc-common.h"
-static GHashTable *tid_table; /* cpu_boosting info per thread (tid, attr, gsource_id) hash table */
+static GHashTable *tid_table; /* key = tid, value = cpu_boosting info per thread (tid, attr, gsource_id) hash table */
+static GHashTable *dest_table; /* key = destiation process name, value = cpu_boosting_input */
+
pthread_t cpu_boosting_thread;
static struct sched_attr cpu_boosting_attr[CPU_BOOSTING_LEVEL_END];
static bool cpu_boosting_success[CPU_BOOSTING_LEVEL_END] = {false, };
GMainLoop *cpu_boosting_loop;
GMainContext *cpu_boosting_context;
-static void cpu_boosting_destroy_request(struct cpu_boosting_input *input);
-
#define SOCK_PATH "/run/.resourced.socket"
#define CPU_BOOSTING_SET_REQUEST(_input, _command, _level, _timeout_msec, _pid) \
struct dirent *dirent;
_cleanup_free_ char *buf = NULL;
+ if (pid <= 0) {
+ _E("[CPU-BOOSTING] Wrong pid = %d", pid);
+ return RESOURCED_ERROR_FAIL;
+ }
+
ret = asprintf(&buf, "/proc/%d/task", pid);
if (ret < 0) {
_E("[CPU-BOOSTING] Failed to allocate buf (dir = %s)", buf);
return RESOURCED_ERROR_NONE;
}
-static void cpu_boosting_destroy_request(struct cpu_boosting_input *input)
+static void cpu_boosting_destroy_request(gpointer data)
{
+ struct cpu_boosting_input *input = (struct cpu_boosting_input *)data;
+
if (input == NULL)
return;
if (input->client_input.pid.tid)
free(input->client_input.pid.tid);
+ if (input->client_input.dest)
+ free((void *)input->client_input.dest);
+
if (input->gsource_id)
g_free(input->gsource_id);
{
int byte;
- if (sock == 0)
- return;
- else if (sock < 0) {
+ if (sock < 0) {
_E("[CPU-BOOSTING] socket cannot be negative");
- return;
+ goto remove_output;
}
if (output.success) {
if (byte != sizeof(output)) {
_E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
(unsigned int)sizeof(output), byte);
- return;
+ goto remove_output;
}
/* Check body size */
if (byte != output.level.tid_count * sizeof(int)) {
_E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
output.level.tid_count * (unsigned int)sizeof(int), byte);
- return;
+ goto remove_output;
}
-
}
else {
/* Send a header */
if (byte != sizeof(output.success)) {
_E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
(unsigned int)sizeof(output.success), byte);
- return;
+ goto remove_output;
}
}
+remove_output:
if (output.level.tid_level)
free(output.level.tid_level);
}
_E("[CPU-BOOSTING] client input size is %u, but received size is %d",
(unsigned int)sizeof(input->client_input), byte);
input->client_input.pid.tid = NULL;
+ input->client_input.dest = NULL;
}
goto destroy_input;
}
+ input->client_input.pid.tid = NULL;
+ input->client_input.dest = NULL;
if (input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR ||
input->client_input.command == CPU_BOOSTING_COMMAND_SET) {
}
/* Check body size */
- input->client_input.pid.tid = NULL;
- if (input->client_input.body_size > 0 &&
+ if (input->client_input.body_len > 0 &&
input->client_input.pid.tid_count > 0) {
int *tid_list;
- int body_size = input->client_input.body_size;
+ int body_len = input->client_input.body_len;
int tid_count = input->client_input.pid.tid_count;
tid_list = (int *)calloc(tid_count, sizeof(int));
input->client_input.pid.tid = tid_list;
/* Get a body from the client */
- byte = recv(sock, (void *)tid_list, body_size, 0);
- if (byte != body_size) {
+ byte = recv(sock, (void *)tid_list, body_len, 0);
+ if (byte != body_len) {
ret = RESOURCED_ERROR_FAIL;
if (byte < 0) {
_E("[CPU-BOOSTING] error is based on %m");
}
else if (byte > 0)
_E("[CPU-BOOSTING] client input size is %d, but received size is %d",
- body_size, byte);
+ body_len, byte);
goto destroy_input;
}
+ }
+ else if (input->client_input.body_len == 0) {
+ switch (input->client_input.command) {
+ case CPU_BOOSTING_COMMAND_SET:
+ case CPU_BOOSTING_COMMAND_CLEAR:
+ case CPU_BOOSTING_COMMAND_GET:
+ case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
+ ret = cpu_boosting_get_tids(input->client_input.pid.pid, &input->client_input.pid);
+ if (ret != RESOURCED_ERROR_NONE)
+ goto destroy_input;
- /*
- * TODO: Checking whether Thread ID is valid or not
- *
- * for (int i = 0; i < tid_count; i++) {
- * if (tid_list[i] <= 0)
- * goto destroy_input;
- }*/
- }
- else if (input->client_input.body_size == 0 &&
- input->client_input.pid.pid > 0) {
- ret = cpu_boosting_get_tids(input->client_input.pid.pid, &input->client_input.pid);
- if (ret != RESOURCED_ERROR_NONE)
- goto destroy_input;
+ break;
+ default:
+ //do nothing
+ break;
+ }
}
else {
_E("[CPU-BOOSTING] Unknown header format");
+ ret = RESOURCED_ERROR_FAIL;
goto destroy_input;
}
if (input->client_input.command == CPU_BOOSTING_COMMAND_GET)
input->sock = sock; /* For a reply */
+ else if (input->client_input.command == CPU_BOOSTING_COMMAND_REGISTER_DESTINATION ||
+ input->client_input.command == CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION ||
+ input->client_input.command == CPU_BOOSTING_COMMAND_SET_INHERITANCE ||
+ input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE) {
+ char *dest;
+
+ if (input->client_input.dest_len <= 0) {
+ _E("[CPU-BOOSTING] Wrong destination name");
+ ret = RESOURCED_ERROR_FAIL;
+ goto destroy_input;
+ }
+
+ dest = (char *)calloc(input->client_input.dest_len, sizeof(char));
+ if (dest == NULL) {
+ _E("[CPU-BOOSTING] Failed to allocate memory");
+ ret = RESOURCED_ERROR_OUT_OF_MEMORY;
+ goto destroy_input;
+ }
+ else
+ input->client_input.dest = dest;
+
+ byte = recv(sock, (void *)dest, input->client_input.dest_len, 0);
+ if (byte != input->client_input.dest_len) {
+ ret = RESOURCED_ERROR_FAIL;
+ if (byte < 0) {
+ _E("[CPU-BOOSTING] error is based on %m");
+ }
+ else if (byte > 0)
+ _E("[CPU-BOOSTING] client input size is %d, but received size is %d",
+ input->client_input.dest_len, byte);
+
+ goto destroy_input;
+ }
+ }
return RESOURCED_ERROR_NONE;
_E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
}
- cpu_boosting_destroy_request(input);
+ if (input->remove_input)
+ cpu_boosting_destroy_request(input);
timer_out:
return G_SOURCE_REMOVE;
}
-static void cpu_boosting_find_and_insert_attr(pid_t tid, cpu_boosting_level_e level, guint id)
+static void cpu_boosting_find_and_insert_info(pid_t tid, cpu_boosting_level_e level, guint id)
{
struct cpu_boosting_info *info = g_hash_table_lookup(tid_table, &tid);
if (info == NULL) {
static void cpu_boosting_set(struct cpu_boosting_input *input)
{
+ guint id = 0;
int fail_cnt = 0;
int success_cnt = 0;
struct sched_attr attr;
_E("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt);
if (success_cnt > 0) {
- guint id;
/*
* If timeout value is larger than 0 and at least one boosting succeed,
* then set the timer to restore
id = *(input->gsource_id);
}
- else
- id = 0; /* No timer source */
for (int i = 0; i < tid_count; i++) {
if (tid_list[i] > 0)
- cpu_boosting_find_and_insert_attr(tid_list[i], cpu_boosting_level, id);
+ cpu_boosting_find_and_insert_info(tid_list[i], cpu_boosting_level, id);
}
}
+
+ if (id == 0 && input->remove_input)
+ cpu_boosting_destroy_request(input);
}
static void cpu_boosting_clear(struct cpu_boosting_input *input)
if (fail_cnt > 0)
_E("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt);
- cpu_boosting_destroy_request(input);
+ if (input->remove_input)
+ cpu_boosting_destroy_request(input);
}
static void cpu_boosting_get(struct cpu_boosting_input *input)
cpu_boosting_destroy_request(input);
}
+static void cpu_boosting_set_inheritance(struct cpu_boosting_input *input)
+{
+ pid_t source_tid;
+ struct sched_attr attr;
+ cpu_boosting_level_e boosting_level;
+ struct cpu_boosting_info *info;
+ struct cpu_boosting_input *input_dest;
+
+ source_tid = input->client_input.pid.pid;
+ if (source_tid <= 0) {
+ _E("[CPU-BOOSTING] source tid should be larger than 0");
+ goto destroy_input;
+ }
+
+ input_dest = g_hash_table_lookup(dest_table, input->client_input.dest);
+ if (input_dest == NULL) {
+ _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest);
+ goto destroy_input;
+ }
+
+ info = g_hash_table_lookup(tid_table, &source_tid);
+ if (info == NULL) {
+ if (sched_getattr(source_tid, &attr, 0) < 0) {
+ _E("[CPU-BOOSTING] Failed to get boost cpu of (tid = %d)", source_tid);
+ goto destroy_input;
+ }
+ else
+ boosting_level = cpu_boosting_level_search(attr);
+ }
+ else
+ boosting_level = info->level;
+
+#ifdef CONFIG_DEBUG_CPU_BOOSTING
+ int tid_count = input_dest->client_input.pid.tid_count;
+ int *tid_list = input_dest->client_input.pid.tid;
+
+ for (int i = 0; i < tid_count; i++) {
+ if (tid_list[i] > 0)
+ _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
+ else
+ _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+ }
+ _D("[CPU-BOOSTING] %s is boost set", input_dest->client_input.dest);
+#endif
+
+ input_dest->client_input.timeout_msec = input->client_input.timeout_msec;
+ input_dest->client_input.level = boosting_level;
+ cpu_boosting_set(input_dest);
+
+destroy_input:
+ cpu_boosting_destroy_request(input);
+}
+
+static void cpu_boosting_clear_inheritance(struct cpu_boosting_input *input)
+{
+ struct cpu_boosting_input *input_dest = g_hash_table_lookup(dest_table, input->client_input.dest);
+ if (input_dest == NULL) {
+ _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest);
+ goto destroy_input;
+ }
+
+#ifdef CONFIG_DEBUG_CPU_BOOSTING
+ int tid_count = input_dest->client_input.pid.tid_count;
+ int *tid_list = input_dest->client_input.pid.tid;
+
+ for (int i = 0; i < tid_count; i++) {
+ if (tid_list[i] > 0)
+ _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
+ else
+ _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+ }
+ _D("[CPU-BOOSTING] %s is boost cleared", input_dest->client_input.dest);
+#endif
+
+ cpu_boosting_clear(input_dest);
+
+destroy_input:
+ cpu_boosting_destroy_request(input);
+}
+
+static void cpu_boosting_register_destination(struct cpu_boosting_input *input)
+{
+ if (input->client_input.dest == NULL) {
+ _E("[CPU-BOOSTING] Boosting target name cannot be NULL");
+ return;
+ }
+
+#ifdef CONFIG_DEBUG_CPU_BOOSTING
+ int tid_count = input->client_input.pid.tid_count;
+ int *tid_list = input->client_input.pid.tid;
+
+ for (int i = 0; i < tid_count; i++) {
+ if (tid_list[i] > 0)
+ _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
+ else
+ _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+ }
+ _D("[CPU-BOOSTING] %s is inserted", input->client_input.dest);
+#endif
+
+ input->remove_input = false;
+ g_hash_table_insert(dest_table, (gpointer)input->client_input.dest, input);
+}
+
+static void cpu_boosting_unregister_destination(struct cpu_boosting_input *input)
+{
+ if (input->client_input.dest == NULL) {
+ _E("[CPU-BOOSTING] Boosting target name cannot be NULL");
+ return;
+ }
+
+#ifdef CONFIG_DEBUG_CPU_BOOSTING
+ struct cpu_boosting_input *input_dest = g_hash_table_lookup(dest_table, input->client_input.dest);
+ if (input_dest == NULL) {
+ _E("[CPU-BOOSTING] %s does not registered before", input->client_input.dest);
+ return;
+ }
+
+ int tid_count = input_dest->client_input.pid.tid_count;
+ int *tid_list = input_dest->client_input.pid.tid;
+
+ for (int i = 0; i < tid_count; i++) {
+ if (tid_list[i] > 0)
+ _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
+ else
+ _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+ }
+#endif
+
+#ifdef CONFIG_DEBUG_CPU_BOOSTING
+ gboolean ret = g_hash_table_remove(dest_table, input->client_input.dest);
+ _D("[CPU-BOOSTING] %s is %sremoved", input->client_input.dest,
+ ret ? "" : "already ");
+#else
+ g_hash_table_remove(dest_table, input->client_input.dest);
+#endif
+ cpu_boosting_destroy_request(input);
+}
+
static int cpu_boosting_init_socket(void)
{
/* Create a server socket */
*/
switch (input->client_input.command) {
case CPU_BOOSTING_COMMAND_SET:
+ input->remove_input = true;
cpu_boosting_set(input);
break;
case CPU_BOOSTING_COMMAND_CLEAR:
+ input->remove_input = true;
cpu_boosting_clear(input);
break;
case CPU_BOOSTING_COMMAND_GET:
-
cpu_boosting_get(input);
break;
+ case CPU_BOOSTING_COMMAND_SET_INHERITANCE:
+ cpu_boosting_set_inheritance(input);
+ break;
+ case CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE:
+ cpu_boosting_clear_inheritance(input);
+ break;
+ case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
+ cpu_boosting_register_destination(input);
+ break;
+ case CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION:
+ cpu_boosting_unregister_destination(input);
+ break;
case CPU_BOOSTING_COMMAND_NONE:
default:
_E("[CPU-BOOSTING] Unknown cpu boosting (command = %d)", input->client_input.command);
goto remove_handler;
}
- if (input->client_input.pid.tid_count == 0) {
- _E("[CPU-BOOSTING] The number of tids should be larger than 0");
- cpu_boosting_destroy_request(input);
- goto remove_handler;
- }
-
cpu_boosting_handle_command(input);
return G_SOURCE_CONTINUE;
tid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free);
g_assert(tid_table);
+ dest_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ cpu_boosting_destroy_request);
+ g_assert(dest_table);
+
/* For the conf-based client */
register_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf);
{
cpu_boosting_thread_deactivate();
g_hash_table_destroy(tid_table);
+ g_hash_table_destroy(dest_table);
unregister_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf);
return RESOURCED_ERROR_NONE;