8 #include <sys/resource.h>
10 #include <sys/socket.h>
12 #include <systemd/sd-daemon.h>
14 #include <system/syscommon-plugin-resourced-cpu-boosting.h>
21 #include "resourced.h"
22 #include "cpu-common.h"
23 #include "fd-handler.h"
24 #include "proc-common.h"
25 /* key = tid, value = cpu_boosting info per thread */
26 static GHashTable *g_cpu_boosting_info_table[CPU_BOOSTING_LEVEL_END] = { NULL, };
27 static GHashTable *dest_table; /* key = destiation process name, value = cpu_boosting_input */
28 /* Key = tid, value = cpu_contention_handle_data */
29 static GHashTable *g_cpu_contention_handle_data_table;
31 pthread_t cpu_boosting_thread;
32 static struct sched_attr cpu_boosting_attr[CPU_BOOSTING_LEVEL_END];
33 static bool cpu_boosting_success[CPU_BOOSTING_LEVEL_END] = {false, };
35 GMainLoop *cpu_boosting_loop;
36 GMainContext *cpu_boosting_context;
38 static guint g_latest_timer_id;
40 #define CPU_CONTENTION_HANDLE_TIMEOUT_MSEC 500
41 #define SOCK_PATH "/run/.resourced.socket"
44 * Information to restore CPU boosting level
45 * before dealing with CPU contention
47 struct cpu_contention_handle_data {
50 cpu_boosting_level_e origin_cpu_boosting_level;
51 cpu_boosting_level_e current_cpu_boosting_level;
54 #define CPU_BOOSTING_SET_REQUEST(_input, _command, _level, \
55 _timeout_msec, _pid, _flags) \
57 (_input)->client_input.command = _command; \
58 (_input)->client_input.timeout_msec = _timeout_msec; \
59 (_input)->client_input.level = _level; \
60 (_input)->client_input.pid = _pid; \
61 (_input)->client_input.flags = _flags; \
64 static void cpu_boosting_handle_command(
65 struct syscommon_resourced_cpu_boosting_input *input);
67 static void free_cpu_boosting_info(gpointer data)
69 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info =
70 (struct syscommon_resourced_cpu_boosting_info *)data;
72 assert(cpu_boosting_info);
74 cpu_boosting_info->ref_cnt--;
75 if (cpu_boosting_info->ref_cnt == 0)
76 free(cpu_boosting_info);
79 static void free_cpu_contention_handle_data(gpointer data)
81 struct cpu_contention_handle_data *cpu_contention_handle_data =
82 (struct cpu_contention_handle_data *)data;
84 assert(cpu_contention_handle_data);
86 g_slice_free(struct cpu_contention_handle_data,
87 cpu_contention_handle_data);
90 static void remove_cpu_boosting_info_in_tables(int *tid)
93 for (cpu_boosting_level_e cpu_boosting_level = CPU_BOOSTING_LEVEL_STRONG;
94 cpu_boosting_level < CPU_BOOSTING_LEVEL_END; cpu_boosting_level++) {
95 ret_removed = g_hash_table_remove(
96 g_cpu_boosting_info_table[cpu_boosting_level], tid);
102 static void find_cpu_boosting_info_in_tables(
103 struct syscommon_resourced_cpu_boosting_info **cpu_boosting_info, int *tid)
105 assert(cpu_boosting_info);
107 for (cpu_boosting_level_e cpu_boosting_level = CPU_BOOSTING_LEVEL_STRONG;
108 cpu_boosting_level < CPU_BOOSTING_LEVEL_END; cpu_boosting_level++) {
109 *cpu_boosting_info = g_hash_table_lookup(
110 g_cpu_boosting_info_table[cpu_boosting_level], tid);
111 if (*cpu_boosting_info)
116 static int restore_cpu_boosting_level(void)
118 GHashTableIter cpu_contention_handle_data_iter;
119 guint **gsource_list = NULL;
120 pid_t **tid_list = NULL;
127 hash_size = g_hash_table_size(g_cpu_contention_handle_data_table);
128 if (hash_size == 0) {
129 _E("[CPU-BOOSTING] No thread to restore cpu boosting level");
130 return RESOURCED_ERROR_FAIL;
134 * Secure memory first before running main loop.
135 * If the current memory is not enough, then do not restore now
136 * and wait for interval time.
138 tid_list = (pid_t **)calloc(hash_size, sizeof(pid_t *));
139 if (tid_list == NULL) {
140 _E("[CPU-BOOSTING] Failed to allocate memory");
141 return RESOURCED_ERROR_OUT_OF_MEMORY;
144 gsource_list = (guint **)calloc(hash_size, sizeof(guint *));
145 if (gsource_list == NULL) {
146 _E("[CPU-BOOSTING] Failed to allocate memory");
150 for (hash_index = 0; hash_index < hash_size; hash_index++) {
151 tid_list[hash_index] = (pid_t *)calloc(1, sizeof(pid_t));
152 if (tid_list[hash_index] == NULL)
155 gsource_list[hash_index] = g_new(guint, 1);
159 g_hash_table_iter_init(&cpu_contention_handle_data_iter,
160 g_cpu_contention_handle_data_table);
162 struct syscommon_resourced_cpu_boosting_input *cpu_boosting_input;
163 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info;
164 struct cpu_contention_handle_data *cpu_contention_handle_data;
165 cpu_boosting_level_e current_cpu_boosting_level;
166 cpu_boosting_level_e origin_cpu_boosting_level;
167 resource_pid_t resource_pid;
169 ret = g_hash_table_iter_next(&cpu_contention_handle_data_iter,
174 cpu_contention_handle_data =
175 (struct cpu_contention_handle_data *)value;
176 current_cpu_boosting_level =
177 cpu_contention_handle_data->current_cpu_boosting_level;
178 origin_cpu_boosting_level =
179 cpu_contention_handle_data->origin_cpu_boosting_level;
182 * Cpu boosting can be already finished
183 * by clearing cpu boosting requets from the source or timeout.
184 * Therefore, first check whether the corresponding thread
185 * cpu boosting is still valid.
187 cpu_boosting_info = g_hash_table_lookup(
188 g_cpu_boosting_info_table[current_cpu_boosting_level], tid);
189 if (cpu_boosting_info == NULL)
193 g_slice_new0(struct syscommon_resourced_cpu_boosting_input);
195 resource_pid.pid = 0;
196 resource_pid.tid_count = 1;
197 resource_pid.tid = tid_list[hash_index];
198 resource_pid.tid[0] = g_int_hash(tid);
200 cpu_boosting_input->remove_input = true;
201 cpu_boosting_input->gsource_id = gsource_list[hash_index];
202 cpu_boosting_input->gsource_id[0] =
203 cpu_boosting_info->gsource_id;
207 CPU_BOOSTING_SET_REQUEST(cpu_boosting_input,
208 CPU_BOOSTING_COMMAND_SET, origin_cpu_boosting_level,
209 -1, resource_pid, cpu_boosting_info->cpu_boosting_flags);
212 * tid_list[index] and gsource_list[index] will be freed
213 * after calling this function.
215 cpu_boosting_handle_command(cpu_boosting_input);
218 for (int index = hash_index; index < hash_size; index++) {
219 free(tid_list[index]);
220 g_free(gsource_list[index]);
224 g_free(gsource_list);
225 g_hash_table_remove_all(g_cpu_contention_handle_data_table);
227 return RESOURCED_ERROR_NONE;
230 for (int index = 0; index < hash_index; index++) {
231 free(tid_list[index]);
232 g_free(gsource_list[index]);
238 return RESOURCED_ERROR_OUT_OF_MEMORY;
241 static gboolean cpu_contention_handle_timeout(gpointer data)
243 guint *timer_id =(guint *)data;
244 int ret = RESOURCED_ERROR_NONE;
246 if (timer_id == NULL) {
247 _E("[CPU-BOOSTING] Timer id cannot be NULL");
248 return G_SOURCE_REMOVE;
251 if (syscommon_plugin_resourced_is_cpu_contention_alleviated
252 (*timer_id, g_latest_timer_id))
253 ret = restore_cpu_boosting_level();
255 if (ret == RESOURCED_ERROR_OUT_OF_MEMORY)
256 return G_SOURCE_CONTINUE;
260 return G_SOURCE_REMOVE;
263 static void register_cpu_contention_handle_data(
264 struct syscommon_resourced_cpu_boosting_input *input,
265 cpu_boosting_level_e origin_cpu_boosting_level,
268 struct cpu_contention_handle_data *cpu_contention_handle_data = NULL;
273 * Register information to restore cpu boosting level
274 * before dealing with CPU contention.
276 for (int i = 0; i < input->client_input.pid.tid_count; i++) {
277 cpu_contention_handle_data = (struct cpu_contention_handle_data *)
278 g_hash_table_lookup(g_cpu_contention_handle_data_table,
279 &input->client_input.pid.tid[i]);
280 if (cpu_contention_handle_data) {
281 cpu_contention_handle_data->current_cpu_boosting_level =
282 input->client_input.level;
283 cpu_contention_handle_data->timer_id = timer_id;
287 cpu_contention_handle_data = (struct cpu_contention_handle_data *)
288 g_slice_new0(struct cpu_contention_handle_data);
289 cpu_contention_handle_data->tid = input->client_input.pid.tid[i];
290 cpu_contention_handle_data->origin_cpu_boosting_level =
291 origin_cpu_boosting_level;
292 cpu_contention_handle_data->current_cpu_boosting_level =
293 input->client_input.level;
294 cpu_contention_handle_data->timer_id = timer_id;
296 g_hash_table_insert(g_cpu_contention_handle_data_table,
297 &cpu_contention_handle_data->tid, cpu_contention_handle_data);
301 static gboolean cpu_boosting_governor_govern_request (gpointer user_data)
303 struct syscommon_resourced_cpu_boosting_input *input = NULL;
304 cpu_boosting_level_e cpu_boosting_level;
306 GSList *action_list = NULL;
314 * Search cpu boosted thread list from CPU_BOOSTING_LEVEL_STRONG to
315 * CPU_BOOSTING_LEVEL_WEAK. If the governor cannot find out victims,
316 * then just drop the event and wait for the next event from the monitor.
318 for (cpu_boosting_level = CPU_BOOSTING_LEVEL_STRONG;
319 cpu_boosting_level < CPU_BOOSTING_LEVEL_END; cpu_boosting_level++) {
320 ret = syscommon_plugin_resourced_cpu_boosting_governor_govern_request(
321 g_cpu_boosting_info_table[cpu_boosting_level],
322 cpu_boosting_level, &action_list, &is_cpu_busy);
324 return G_SOURCE_REMOVE;
329 if (action_list != NULL)
334 * action_list is NULL when there is not boosted thread to decrease
335 * cpu boosting level.
336 * In addition, g_cpu_contention_handle_data_table size is 0 when
337 * there is no boosted threads yet with decreased cpu boosting level.
338 * (resourced should check whehter no more stall event during
339 * CPU_CONTENTION_HANDLE_TIMEOUT_MSEC.)
341 * In conclusion, additional timer is useless to set when action_list is
342 * empty and no decreased boosted thread.
344 if (action_list == NULL &&
345 g_hash_table_size(g_cpu_contention_handle_data_table) == 0)
346 return G_SOURCE_REMOVE;
349 * Set timer to check whether cpu contention is alleviated or not
350 * after CPU_CONTENTION_HANDLE_TIMEOUT_MSEC.
352 timer_id = g_new(guint, 1);
353 source = g_timeout_source_new(CPU_CONTENTION_HANDLE_TIMEOUT_MSEC);
354 g_source_set_callback(source, cpu_contention_handle_timeout,
356 g_latest_timer_id = *timer_id =
357 g_source_attach(source, cpu_boosting_context);
358 g_source_unref(source);
360 gslist_for_each_safe(action_list, iter, next, input) {
363 register_cpu_contention_handle_data(input, cpu_boosting_level,
366 action_list = g_slist_remove(action_list, input);
369 * Control cpu boosting level of victims according to
370 * the governor policy.
372 cpu_boosting_handle_command(input);
375 return G_SOURCE_REMOVE;
378 void cpu_boosting_wakeup_cpu_boosting_thread(void)
381 * This function is called by a monitor thread,
382 * so, the monitor should wakeup the cpu boosting main thread
385 if (cpu_boosting_is_enabled_of_cpu_stall_handler())
386 g_main_context_invoke(cpu_boosting_context,
387 cpu_boosting_governor_govern_request, NULL);
389 _I("[CPU-BOOSTING] CPU stall handler is turned off");
392 static cpu_boosting_level_e cpu_boosting_level_search(struct sched_attr attr)
394 attr.sched_policy = attr.sched_policy & ~SCHED_RESET_ON_FORK;
396 for (int level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++) {
397 if (cpu_boosting_attr[level].sched_policy == SCHED_RR ||
398 cpu_boosting_attr[level].sched_policy == SCHED_FIFO) {
399 if (cpu_boosting_attr[level].sched_priority == attr.sched_priority)
402 else if (cpu_boosting_attr[level].sched_nice == attr.sched_nice)
406 return CPU_BOOSTING_LEVEL_NONE;
409 static int cpu_boosting_get_tids(pid_t pid, resource_pid_t *resource_pid)
414 pid_t *tid_list = NULL;
417 struct dirent *dirent;
418 _cleanup_free_ char *buf = NULL;
421 _E("[CPU-BOOSTING] Wrong pid = %d", pid);
422 return RESOURCED_ERROR_FAIL;
425 ret = asprintf(&buf, "/proc/%d/task", pid);
427 _E("[CPU-BOOSTING] Failed to allocate buf (dir = %s)", buf);
428 return RESOURCED_ERROR_OUT_OF_MEMORY;
433 _E("[CPU-BOOSTING] Failed to open (dir = %s)", buf);
434 return RESOURCED_ERROR_FAIL;
437 while ((dirent = readdir(dir))) {
438 const char *id = dirent->d_name;
444 if (alloc_count == tid_count) {
446 tid_list = (pid_t *)realloc(tid_list, alloc_count * sizeof(pid_t));
447 if (tid_list == NULL) {
448 _E("[CPU-BOOSTING] Failed to allocate memory");
450 resource_pid->tid = NULL;
451 resource_pid->tid_count = 0;
452 return RESOURCED_ERROR_OUT_OF_MEMORY;
455 tid_list[tid_count++] = tid;
458 _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid);
462 resource_pid->tid = tid_list;
463 resource_pid->tid_count = tid_count;
465 return RESOURCED_ERROR_NONE;
468 static void cpu_boosting_destroy_request(gpointer data)
470 struct syscommon_resourced_cpu_boosting_input *input =
471 (struct syscommon_resourced_cpu_boosting_input *)data;
476 if (input->client_input.pid.tid)
477 free(input->client_input.pid.tid);
479 if (input->client_input.dest) {
480 free((void *)input->client_input.dest);
483 if (input->gsource_id) {
484 g_free(input->gsource_id);
487 g_slice_free(struct syscommon_resourced_cpu_boosting_input, input);
490 static struct syscommon_resourced_cpu_boosting_input *
491 cpu_boosting_new_request(void)
493 struct syscommon_resourced_cpu_boosting_input *input =
494 g_slice_new0(struct syscommon_resourced_cpu_boosting_input);
496 _E("[CPU-BOOSTING] Failed to allocate memory for cpu boosting input");
503 static bool load_cpu_boosting_config(cpu_boosting_level_e level)
505 int cpu_nice, cpu_rt_priority, cpu_policy;
507 enum cpu_sched_type cpu_sched_type;
509 struct cpu_boosting_conf *cpu_boosting_conf = get_cpu_boosting_conf(level);
510 if (cpu_boosting_conf == NULL) {
511 _E("[CPU-BOOSTING] Boosting (level = %d) configuration structure should not be NULL",
516 if (!cpu_boosting_conf->enable) {
517 _D("[CPU-BOOSTING] Cpu boosting is disabled");
521 cpu_nice = cpu_boosting_conf->cpu_sched_info.cpu_nice;
522 cpu_rt_priority = cpu_boosting_conf->cpu_sched_info.cpu_rt_priority;
523 cpu_sched_type = cpu_boosting_conf->cpu_sched_info.cpu_sched_type;
525 if (cpu_sched_type < CPU_SCHED_BATCH || cpu_sched_type > CPU_SCHED_RR) {
526 _E("[CPU-BOOSTING] Cpu scheduler type is unknown or idle");
530 memset(&cpu_boosting_attr[level], 0, sizeof(struct sched_attr));
532 if (cpu_sched_type == CPU_SCHED_BATCH || cpu_sched_type == CPU_SCHED_OTHER) {
533 if (cpu_nice < CPU_MIN_NICE || cpu_nice > CPU_MAX_NICE) {
534 _E("[CPU-BOOSTING] Cpu nice (= %d) is out of scope", cpu_nice);
538 if (cpu_rt_priority != CPU_INIT_PRIO) {
539 _E("[CPU-BOOSTING] Cpu rt priority (= %d) is out of scope", cpu_rt_priority);
543 if (cpu_sched_type == CPU_SCHED_BATCH)
544 cpu_policy = SCHED_BATCH;
546 cpu_policy = SCHED_OTHER;
548 cpu_boosting_attr[level].sched_nice = cpu_nice;
551 if (cpu_rt_priority < CPU_MIN_PRIO || cpu_rt_priority > CPU_MAX_PRIO) {
552 _E("[CPU-BOOSTING] Cpu rt priority (= %d) is out of scope", cpu_rt_priority);
556 if (cpu_sched_type == CPU_SCHED_RR)
557 cpu_policy = SCHED_RR;
559 cpu_policy = SCHED_FIFO;
562 cpu_boosting_attr[level].size = sizeof(struct sched_attr);
563 cpu_boosting_attr[level].sched_policy = cpu_policy;
564 cpu_boosting_attr[level].sched_priority = cpu_rt_priority;
566 _I("[CPU-BOOSTING] Boosting (level = %d) policy = %s", level,
567 cpu_boosting_attr[level].sched_policy == SCHED_BATCH ? "SCHED_BATCH" :
568 cpu_boosting_attr[level].sched_policy == SCHED_OTHER ? "SCHED_OTHER" :
569 cpu_boosting_attr[level].sched_policy == SCHED_RR ? "SCHED_RR" : "SCHED_FIFO");
570 _I("[CPU-BOOSTING] Boosting (level = %d) nice = %d", level, cpu_boosting_attr[level].sched_nice);
571 _I("[CPU-BOOSTING] Boosting (level = %d) priority = %d", level, cpu_boosting_attr[level].sched_priority);
576 static void load_cpu_boosting_configs(void)
578 int level = CPU_BOOSTING_LEVEL_NONE;
580 /* Initialize type and nice of cpu throttling scheduler */
581 memset(&cpu_boosting_attr[level], 0, sizeof(struct sched_attr));
582 cpu_boosting_attr[level].size = sizeof(struct sched_attr);
583 cpu_boosting_attr[level].sched_nice = CPU_DEFAULT_NICE;
584 cpu_boosting_attr[level].sched_policy = SCHED_OTHER;
585 cpu_boosting_success[level] = true;
587 for (level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++) {
588 cpu_boosting_success[level] = load_cpu_boosting_config(level);
589 if (!cpu_boosting_success[level])
590 _I("[CPU-BOOSTING] Boosting (level = %d) is not supported", level);
591 free_cpu_boosting_conf(level);
595 static void cpu_boosting_send_reply(int sock, cpu_boosting_output_t output)
600 _E("[CPU-BOOSTING] socket cannot be negative");
604 if (output.success) {
605 /* Send a header first */
606 byte = send(sock, (const void *)&output, sizeof(output), 0);
607 if (byte != sizeof(output)) {
608 _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
609 (unsigned int)sizeof(output), byte);
613 /* Check body size */
614 byte = send(sock, (const void *)output.level.tid_level,
615 output.level.tid_count * sizeof(int), 0);
616 if (byte != output.level.tid_count * sizeof(int)) {
617 _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
618 output.level.tid_count * (unsigned int)sizeof(int), byte);
624 byte = send(sock, (const void *)&output.success, sizeof(output.success), 0);
625 if (byte != sizeof(output.success)) {
626 _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d",
627 (unsigned int)sizeof(output.success), byte);
633 if (output.level.tid_level)
634 free(output.level.tid_level);
637 static int cpu_boosting_enqueue_by_socket(int sock,
638 struct syscommon_resourced_cpu_boosting_input **input_p)
640 int ret = RESOURCED_ERROR_NONE;
643 struct syscommon_resourced_cpu_boosting_input *input =
644 cpu_boosting_new_request();
646 ret = RESOURCED_ERROR_OUT_OF_MEMORY;
652 /* Get a header from the client */
653 byte = recv(sock, (void *)&input->client_input, sizeof(input->client_input), 0);
654 if (byte != sizeof(input->client_input)) {
655 ret = RESOURCED_ERROR_FAIL;
657 _E("[CPU-BOOSTING] error is based on %m");
660 _E("[CPU-BOOSTING] client input size is %u, but received size is %d",
661 (unsigned int)sizeof(input->client_input), byte);
662 input->client_input.pid.tid = NULL;
663 input->client_input.dest = NULL;
668 input->client_input.pid.tid = NULL;
669 input->client_input.dest = NULL;
671 if (input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR ||
672 input->client_input.command == CPU_BOOSTING_COMMAND_SET) {
673 if (input->client_input.level > CPU_BOOSTING_LEVEL_WEAK) {
674 ret = RESOURCED_ERROR_FAIL;
675 _E("[CPU-BOOSTING] cpu boosting (level = %d) is out of scope",
676 input->client_input.level);
680 if (!cpu_boosting_success[input->client_input.level]) {
681 ret = RESOURCED_ERROR_FAIL;
682 _I("[CPU-BOOSTING] cpu boosting (level = %d) is not supported",
683 input->client_input.level);
688 /* Check body size */
689 if (input->client_input.body_len > 0 &&
690 input->client_input.pid.tid_count > 0) {
692 int body_len = input->client_input.body_len;
694 tid_list = (pid_t *)calloc(1, body_len);
695 if (tid_list == NULL) {
696 _E("[CPU-BOOSTING] Failed to allocate memory");
697 ret = RESOURCED_ERROR_OUT_OF_MEMORY;
701 input->client_input.pid.tid = tid_list;
703 /* Get a body from the client */
704 byte = recv(sock, (void *)tid_list, body_len, 0);
705 if (byte != body_len) {
706 ret = RESOURCED_ERROR_FAIL;
708 _E("[CPU-BOOSTING] error is based on %m");
711 _E("[CPU-BOOSTING] client input size is %d, but received size is %d",
717 else if (input->client_input.body_len == 0) {
718 switch (input->client_input.command) {
719 case CPU_BOOSTING_COMMAND_SET:
720 case CPU_BOOSTING_COMMAND_CLEAR:
721 case CPU_BOOSTING_COMMAND_GET:
722 case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
723 ret = cpu_boosting_get_tids(input->client_input.pid.pid, &input->client_input.pid);
724 if (ret != RESOURCED_ERROR_NONE)
734 _E("[CPU-BOOSTING] Unknown header format");
735 ret = RESOURCED_ERROR_FAIL;
739 if (input->client_input.command == CPU_BOOSTING_COMMAND_GET)
740 input->sock = sock; /* For a reply */
741 else if (input->client_input.command == CPU_BOOSTING_COMMAND_REGISTER_DESTINATION ||
742 input->client_input.command == CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION ||
743 input->client_input.command == CPU_BOOSTING_COMMAND_SET_INHERITANCE ||
744 input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE) {
747 if (input->client_input.dest_len <= 0 ||
748 input->client_input.dest_len >= MAX_PATH_LENGTH) {
749 _E("[CPU-BOOSTING] Wrong destination name");
750 ret = RESOURCED_ERROR_FAIL;
754 dest = (char *)calloc(input->client_input.dest_len + 1, sizeof(char));
756 _E("[CPU-BOOSTING] Failed to allocate memory");
757 ret = RESOURCED_ERROR_OUT_OF_MEMORY;
761 input->client_input.dest = dest;
763 byte = recv(sock, (void *)dest, input->client_input.dest_len, 0);
764 if (byte != input->client_input.dest_len) {
765 ret = RESOURCED_ERROR_FAIL;
767 _E("[CPU-BOOSTING] error is based on %m");
770 _E("[CPU-BOOSTING] client input size is %d, but received size is %d",
771 input->client_input.dest_len, byte);
777 return RESOURCED_ERROR_NONE;
780 cpu_boosting_destroy_request(input);
785 /* Called by resourced main thread */
786 static int cpu_boosting_enqueue_by_conf(void *data,
787 struct syscommon_resourced_cpu_boosting_input **input)
792 struct proc_status *ps = (struct proc_status *)data;
793 cpu_boosting_level_e cpu_boosting_level;
796 if (ps->pci == NULL) {
797 _E("[CPU-BOOSTING] Process conf should not be NULL");
798 return RESOURCED_ERROR_FAIL;
802 _E("[CPU-BOOSTING] pid should be larger than 0");
803 return RESOURCED_ERROR_FAIL;
806 cpu_boosting_level = ps->pci->cpu_boosting_level;
807 if (!cpu_boosting_success[cpu_boosting_level]) {
808 _I("[CPU-BOOSTING] cpu boosting (level = %d) is not supported", cpu_boosting_level);
809 return RESOURCED_ERROR_NONE;
812 ret = cpu_boosting_get_tids(ps->pid, &pid);
813 if (ret != RESOURCED_ERROR_NONE)
816 *input = cpu_boosting_new_request();
818 return RESOURCED_ERROR_FAIL;
820 CPU_BOOSTING_SET_REQUEST(*input, CPU_BOOSTING_COMMAND_SET,
821 cpu_boosting_level, -1, pid, 0);
823 return RESOURCED_ERROR_NONE;
826 static gboolean cpu_boosting_timeout(gpointer data)
829 struct syscommon_resourced_cpu_boosting_input *input =
830 (struct syscommon_resourced_cpu_boosting_input *)data;
833 _E("[CPU-BOOSTING] input argument of cpu boosting should not be NULL");
837 int tid_count = input->client_input.pid.tid_count;
838 int *tid_list = input->client_input.pid.tid;
840 for (int i = 0; i < tid_count; i++) {
841 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info = NULL;
843 if (tid_list[i] <= 0) {
844 _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
848 find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid_list[i]);
851 * cpu_boosting_info is NULL when clearing boosting before timeout.
852 * cpu_boosting_info->gsource_id != *(input->gsource_id)
853 * when setting cpu boosting again before timeout.
855 if (cpu_boosting_info == NULL || input->gsource_id == NULL
856 || cpu_boosting_info->gsource_id != *(input->gsource_id))
859 switch (cpu_boosting_info->level) {
860 case CPU_BOOSTING_LEVEL_STRONG:
861 case CPU_BOOSTING_LEVEL_MEDIUM:
862 case CPU_BOOSTING_LEVEL_WEAK:
864 g_cpu_boosting_info_table[cpu_boosting_info->level],
867 case CPU_BOOSTING_LEVEL_NONE:
869 _E("[CPU-BOOSTING] Unknown cpu boosting level (SIGABT)");
873 ret = sched_setattr(tid_list[i], &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
874 if (ret != RESOURCED_ERROR_NONE)
875 _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
878 if (input->remove_input)
879 cpu_boosting_destroy_request(input);
882 return G_SOURCE_REMOVE;
885 static void cpu_boosting_find_and_insert_info(pid_t tid,
886 cpu_boosting_flag_e cpu_boosting_flags, guint *timer_id,
887 cpu_boosting_level_e cpu_boosting_level)
889 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info = NULL;
891 switch (cpu_boosting_level) {
892 case CPU_BOOSTING_LEVEL_STRONG:
893 case CPU_BOOSTING_LEVEL_MEDIUM:
894 case CPU_BOOSTING_LEVEL_WEAK:
896 case CPU_BOOSTING_LEVEL_NONE:
898 _E("[CPU-BOOSTING] Cannot boosting unknown or none level");
902 find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid);
903 if (cpu_boosting_info == NULL) {
904 cpu_boosting_info = (struct syscommon_resourced_cpu_boosting_info *)
905 calloc(1, sizeof (struct syscommon_resourced_cpu_boosting_info));
906 if (cpu_boosting_info == NULL) {
907 _E("[CPU-BOOSTING] Failed to allocate memory");
911 cpu_boosting_info->tid = tid;
912 cpu_boosting_info->ref_cnt = 1;
914 g_hash_table_insert(g_cpu_boosting_info_table[cpu_boosting_level],
915 &cpu_boosting_info->tid, cpu_boosting_info);
916 } else if (cpu_boosting_info->level != cpu_boosting_level) {
918 * Do not free cpu_boosting_info in
919 * g_cpu_boosting_info_table[cpu_boosting_info->level].
920 * This is because the corresponding cpu_boosting_info
921 * will be reused as a value in another table
922 * (g_cpu_boosting_info_table[cpu_boosting_level]
924 cpu_boosting_info->ref_cnt++;
926 g_cpu_boosting_info_table[cpu_boosting_info->level],
927 &cpu_boosting_info->tid);
928 g_hash_table_insert(g_cpu_boosting_info_table[cpu_boosting_level],
929 &cpu_boosting_info->tid, cpu_boosting_info);
932 cpu_boosting_info->level = cpu_boosting_level;
935 * Register cpu_boosting_flags to handle cpu contention and
936 * restore cpu boosting level after solving cpu contention.
937 * For example, if resourced received CPU_BOOSTING_COMMAND_SET command
938 * with CPU_BOOSTING_RESET_ON_FORK, then turn on
939 * CPU_BOOSTING_RESET_ON_FORK flag
940 * when decreasing and restoring cpu boosting level.
942 cpu_boosting_info->cpu_boosting_flags = cpu_boosting_flags;
945 cpu_boosting_info->gsource_id = *timer_id;
947 cpu_boosting_info->gsource_id = 0;
951 cpu_boosting_set(struct syscommon_resourced_cpu_boosting_input *input)
956 struct sched_attr attr;
957 int tid_count = input->client_input.pid.tid_count;
958 int *tid_list = input->client_input.pid.tid;
959 int timeout_msec = input->client_input.timeout_msec;
960 cpu_boosting_level_e cpu_boosting_level = input->client_input.level;
961 cpu_boosting_flag_e cpu_boosting_flags = input->client_input.flags;
963 switch (cpu_boosting_level) {
964 case CPU_BOOSTING_LEVEL_STRONG:
965 case CPU_BOOSTING_LEVEL_MEDIUM:
966 case CPU_BOOSTING_LEVEL_WEAK:
968 case CPU_BOOSTING_LEVEL_NONE:
971 _E("[CPU-BOOSTING] Unknown boosting level");
975 attr = cpu_boosting_attr[cpu_boosting_level];
976 if (cpu_boosting_flags & CPU_BOOSTING_RESET_ON_FORK) {
977 _I("[CPU-BOOSTING] Turn on SCHED_RESET_ON_FORK flag");
978 attr.sched_policy |= SCHED_RESET_ON_FORK;
981 for (int i = 0; i < tid_count; i++) {
982 if (tid_list[i] <= 0) {
983 _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
988 if (sched_setattr(tid_list[i], &attr, 0) < 0) {
989 _W("[CPU-BOOSTING] Failed to boost cpu of (tid = %d) with (level = %d)",
990 tid_list[i], cpu_boosting_level);
999 _W("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt);
1001 if (success_cnt > 0) {
1003 * If timeout_msec is negative, then do not set timer.
1004 * This is because, cpu boosting should be continued until
1005 * clearing cpu boosting.
1006 * When the governor requests CPU_BOOSTING_COMMAND_SET command,
1007 * input->gsource_id is not NULL. Therefore, new timer is always
1008 * skipped during handling cpu contention.
1010 if (timeout_msec > 0 && input->gsource_id == NULL) {
1013 input->gsource_id = g_new(guint, 1);
1015 source = g_timeout_source_new(timeout_msec);
1016 g_source_set_callback(source, cpu_boosting_timeout, input, NULL);
1017 *(input->gsource_id) = g_source_attach(source, cpu_boosting_context);
1018 g_source_unref(source);
1020 id = *(input->gsource_id);
1023 for (int i = 0; i < tid_count; i++) {
1024 if (tid_list[i] <= 0)
1027 cpu_boosting_find_and_insert_info(tid_list[i], cpu_boosting_flags,
1028 input->gsource_id, cpu_boosting_level);
1032 if (id == 0 && input->remove_input)
1033 cpu_boosting_destroy_request(input);
1036 static void cpu_boosting_clear(struct syscommon_resourced_cpu_boosting_input *input)
1040 int success_cnt = 0;
1041 int tid_count = input->client_input.pid.tid_count;
1042 int *tid_list = input->client_input.pid.tid;
1044 for (int i = 0; i < tid_count; i++) {
1045 if (tid_list[i] <= 0) {
1046 _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0",
1051 remove_cpu_boosting_info_in_tables(&tid_list[i]);
1053 ret = sched_setattr(tid_list[i],
1054 &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
1055 if (ret != RESOURCED_ERROR_NONE) {
1056 _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
1064 _W("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt);
1066 if (input->remove_input)
1067 cpu_boosting_destroy_request(input);
1070 static void cpu_boosting_get(struct syscommon_resourced_cpu_boosting_input *input)
1073 int success_cnt = 0;
1074 struct sched_attr attr;
1075 cpu_boosting_output_t output;
1076 int tid_count = input->client_input.pid.tid_count;
1077 int *tid_list = input->client_input.pid.tid;
1079 memset(&output, 0, sizeof (output));
1080 output.level.tid_level = (int *)calloc(tid_count, sizeof (int));
1081 if (output.level.tid_level == NULL) {
1082 _E("[CPU-BOOSTING] Failed to allocate memory");
1087 for (int i = 0; i < tid_count; i++) {
1088 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info = NULL;
1090 if (tid_list[i] <= 0) {
1092 _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
1096 find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid_list[i]);
1097 if (cpu_boosting_info == NULL) {
1098 if (sched_getattr(tid_list[i], &attr, 0) < 0) {
1103 output.level.tid_level[success_cnt] = cpu_boosting_level_search(attr);
1106 output.level.tid_level[success_cnt] = cpu_boosting_info->level;
1110 output.level.tid_count = success_cnt;
1114 _W("[CPU-BOOSTING] Get boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt);
1115 output.success = false;
1118 output.success = true;
1120 cpu_boosting_send_reply(input->sock, output);
1121 cpu_boosting_destroy_request(input);
1125 cpu_boosting_set_inheritance(struct syscommon_resourced_cpu_boosting_input *input)
1127 struct syscommon_resourced_cpu_boosting_info *cpu_boosting_info = NULL;
1128 struct syscommon_resourced_cpu_boosting_input *input_dest;
1130 struct sched_attr attr;
1131 cpu_boosting_level_e boosting_level;
1134 source_tid = input->client_input.pid.pid;
1135 if (source_tid <= 0) {
1136 _E("[CPU-BOOSTING] source tid should be larger than 0");
1140 input_dest = g_hash_table_lookup(dest_table, input->client_input.dest);
1141 if (input_dest == NULL) {
1142 _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest);
1146 find_cpu_boosting_info_in_tables(&cpu_boosting_info, &source_tid);
1149 * This source thread is not boosted by resourced.
1150 * Therefore, resourced needs to figure out cpu priority or nice value through the kernel.
1152 if (cpu_boosting_info == NULL) {
1153 if (sched_getattr(source_tid, &attr, 0) < 0) {
1154 _E("[CPU-BOOSTING] Failed to get boost cpu of (tid = %d)", source_tid);
1158 boosting_level = cpu_boosting_level_search(attr);
1160 boosting_level = cpu_boosting_info->level;
1162 #ifdef CONFIG_DEBUG_CPU_BOOSTING
1163 int tid_count = input_dest->client_input.pid.tid_count;
1164 int *tid_list = input_dest->client_input.pid.tid;
1166 for (int i = 0; i < tid_count; i++) {
1167 if (tid_list[i] > 0)
1168 _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
1170 _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
1172 _D("[CPU-BOOSTING] %s is boost set", input_dest->client_input.dest);
1174 if (input_dest->gsource_id)
1175 g_free(g_steal_pointer(&input_dest->gsource_id));
1177 input_dest->client_input.timeout_msec = input->client_input.timeout_msec;
1178 input_dest->client_input.level = boosting_level;
1179 cpu_boosting_set(input_dest);
1182 cpu_boosting_destroy_request(input);
1186 cpu_boosting_clear_inheritance(struct syscommon_resourced_cpu_boosting_input *input)
1188 struct syscommon_resourced_cpu_boosting_input *input_dest =
1189 g_hash_table_lookup(dest_table, input->client_input.dest);
1190 if (input_dest == NULL) {
1191 _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest);
1195 #ifdef CONFIG_DEBUG_CPU_BOOSTING
1196 int tid_count = input_dest->client_input.pid.tid_count;
1197 int *tid_list = input_dest->client_input.pid.tid;
1199 for (int i = 0; i < tid_count; i++) {
1200 if (tid_list[i] > 0)
1201 _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
1203 _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
1205 _D("[CPU-BOOSTING] %s is boost cleared", input_dest->client_input.dest);
1208 cpu_boosting_clear(input_dest);
1211 cpu_boosting_destroy_request(input);
1214 static void cpu_boosting_register_destination(
1215 struct syscommon_resourced_cpu_boosting_input *input)
1217 if (input->client_input.dest == NULL) {
1218 _E("[CPU-BOOSTING] Boosting target name cannot be NULL");
1222 #ifdef CONFIG_DEBUG_CPU_BOOSTING
1223 int tid_count = input->client_input.pid.tid_count;
1224 int *tid_list = input->client_input.pid.tid;
1226 for (int i = 0; i < tid_count; i++) {
1227 if (tid_list[i] > 0)
1228 _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
1230 _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
1232 _D("[CPU-BOOSTING] %s is inserted", input->client_input.dest);
1235 input->remove_input = false;
1236 g_hash_table_insert(dest_table, (gpointer)input->client_input.dest, input);
1239 static void cpu_boosting_unregister_destination(
1240 struct syscommon_resourced_cpu_boosting_input *input)
1242 if (input->client_input.dest == NULL) {
1243 _E("[CPU-BOOSTING] Boosting target name cannot be NULL");
1247 #ifdef CONFIG_DEBUG_CPU_BOOSTING
1248 struct syscommon_resourced_cpu_boosting_input *input_dest =
1249 g_hash_table_lookup(dest_table, input->client_input.dest);
1250 if (input_dest == NULL) {
1251 _E("[CPU-BOOSTING] %s does not registered before", input->client_input.dest);
1255 int tid_count = input_dest->client_input.pid.tid_count;
1256 int *tid_list = input_dest->client_input.pid.tid;
1258 for (int i = 0; i < tid_count; i++) {
1259 if (tid_list[i] > 0)
1260 _D("[CPU-BOOSTING] tid = %d", tid_list[i]);
1262 _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
1266 #ifdef CONFIG_DEBUG_CPU_BOOSTING
1267 gboolean ret = g_hash_table_remove(dest_table, input->client_input.dest);
1268 _D("[CPU-BOOSTING] %s is %sremoved", input->client_input.dest,
1269 ret ? "" : "already ");
1271 g_hash_table_remove(dest_table, input->client_input.dest);
1273 cpu_boosting_destroy_request(input);
1276 static int cpu_boosting_init_socket(void)
1278 /* Create a server socket */
1282 struct sockaddr_un sockaddr = {0, };
1283 int n = sd_listen_fds(0);
1285 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
1286 if (sd_is_socket_unix(fd, SOCK_STREAM, 1, SOCK_PATH, 0) > 0) {
1294 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1296 _E("[CPU-BOOSTING] Failed to allocate a socket");
1300 sockaddr.sun_family = AF_UNIX;
1301 strncpy(sockaddr.sun_path, (const char *)SOCK_PATH, strlen(SOCK_PATH)+1);
1302 size = sizeof(sockaddr);
1303 ret = unlink(SOCK_PATH);
1305 _W("[CPU-BOOSTING] Failed to unlink because of %m");
1307 ret = bind(sock, (struct sockaddr *)&sockaddr, size);
1309 _E("[CPU-BOOSTING] Failed to bind socket");
1313 ret = listen(sock, SOMAXCONN);
1315 _E("[CPU-BOOSTING] Failed to listen socket");
1329 cpu_boosting_handle_command(struct syscommon_resourced_cpu_boosting_input *input)
1332 _E("[CPU-BOOSTING] Cpu boosting input data structure should not be NULL");
1337 * Whether current boosting level is supported or not should be checked before
1338 * calling CPU_BOOSTING_ENQUEUE_REQUEST. That is the cpu boosting thread ignores it
1340 switch (input->client_input.command) {
1341 case CPU_BOOSTING_COMMAND_SET:
1342 input->remove_input = true;
1343 cpu_boosting_set(input);
1345 case CPU_BOOSTING_COMMAND_CLEAR:
1346 input->remove_input = true;
1347 cpu_boosting_clear(input);
1349 case CPU_BOOSTING_COMMAND_GET:
1350 cpu_boosting_get(input);
1352 case CPU_BOOSTING_COMMAND_SET_INHERITANCE:
1353 cpu_boosting_set_inheritance(input);
1355 case CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE:
1356 cpu_boosting_clear_inheritance(input);
1358 case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
1359 cpu_boosting_register_destination(input);
1361 case CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION:
1362 cpu_boosting_unregister_destination(input);
1364 case CPU_BOOSTING_COMMAND_NONE:
1366 _E("[CPU-BOOSTING] Unknown cpu boosting (command = %d)", input->client_input.command);
1367 cpu_boosting_destroy_request(input);
1371 static int cpu_boosting_recv_from_conf(void *data)
1374 struct syscommon_resourced_cpu_boosting_input *input = NULL;
1376 if ((ret = cpu_boosting_enqueue_by_conf(data, &input)) < 0 ||
1380 if (input->client_input.pid.tid_count == 0) {
1381 _E("[CPU-BOOSTING] The number of tids should be larger than 0");
1382 cpu_boosting_destroy_request(input);
1383 return RESOURCED_ERROR_FAIL;
1386 cpu_boosting_handle_command(input);
1388 return RESOURCED_ERROR_NONE;
1391 /* Client asks send() to the resourced, so call recv() */
1392 static bool cpu_boosting_recv_from_client(int fd, void *data)
1394 int client_sock = fd;
1395 struct syscommon_resourced_cpu_boosting_input *input = NULL;
1397 if (client_sock <= 0) {
1398 _E("[CPU-BOOSTING] client socket should be larger than 0");
1399 goto remove_handler;
1402 if (cpu_boosting_enqueue_by_socket(client_sock, &input) < 0 ||
1404 goto remove_handler;
1407 cpu_boosting_handle_command(input);
1409 return G_SOURCE_CONTINUE;
1412 if (client_sock > 0)
1415 return G_SOURCE_REMOVE;
1418 /* Client asks connect() to the resourced */
1419 static bool cpu_boosting_connect_from_client(int fd, void *data)
1422 int master_sock = fd;
1424 if (master_sock <= 0) {
1425 _E("[CPU-BOOSTING] master socket should be larger than 0");
1426 goto remove_handler;
1429 int new_sock = accept(master_sock, NULL, NULL);
1431 _E("[CPU-BOOSTING] Failed to allocate a new socket for the client (%m)");
1432 goto remove_handler;
1435 /* Add an event handler to receive data from the client */
1436 ret = add_fd_read_handler(cpu_boosting_context, new_sock, cpu_boosting_recv_from_client,
1439 _E("[CPU-BOOSTING] Failed to add event handler of (sock = %d)", new_sock);
1443 return G_SOURCE_CONTINUE;
1446 if (master_sock > 0)
1449 return G_SOURCE_REMOVE;
1452 static int cpu_boosting_init_server(void)
1455 static fd_handler_h handler;
1456 int sock = cpu_boosting_init_socket();
1458 ret = add_fd_read_handler(cpu_boosting_context, sock,
1459 cpu_boosting_connect_from_client, NULL, NULL, &handler);
1461 _E("[CPU-BOOSTING] Failed to add event handler of (sock = %d)", sock);
1463 return RESOURCED_ERROR_FAIL;
1467 return RESOURCED_ERROR_FAIL;
1469 return RESOURCED_ERROR_NONE;
1472 /* Cpu boosting thread's main code */
1473 static void *cpu_boosting_func(void *data)
1475 /* Boost cpu boosting thread itself */
1476 setpriority(PRIO_PROCESS, 0, CPU_MIN_NICE);
1478 cpu_boosting_context = g_main_context_new();
1479 g_main_context_push_thread_default(cpu_boosting_context);
1480 cpu_boosting_loop = g_main_loop_new(cpu_boosting_context, FALSE);
1482 /* For the socket-based client */
1483 if (cpu_boosting_init_server() < 0) {
1484 _E("[CPU-BOOSTING] Failed to initialize server environment");
1488 _D("[CPU-BOOSTING] Success to initialize server environment");
1490 g_main_loop_run(cpu_boosting_loop);
1493 g_main_loop_unref(cpu_boosting_loop);
1494 g_main_context_unref(cpu_boosting_context);
1498 static int cpu_boosting_thread_activate(void)
1500 int ret = pthread_create(&cpu_boosting_thread, NULL,
1501 cpu_boosting_func, NULL);
1503 pthread_detach(cpu_boosting_thread);
1504 ret = RESOURCED_ERROR_NONE;
1507 _E("[CPU-BOOSTING] Failed to create cpu boosting thread");
1508 ret = RESOURCED_ERROR_FAIL;
1514 static void cpu_boosting_thread_deactivate(void)
1516 g_main_loop_quit(cpu_boosting_loop);
1519 /* Called by resourced main thread */
1520 static int cpu_boosting_init(void *data)
1524 load_cpu_boosting_configs();
1526 ret = cpu_boosting_thread_activate();
1527 if (ret != RESOURCED_ERROR_NONE)
1530 for (int level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++) {
1531 g_cpu_boosting_info_table[level] = g_hash_table_new_full(
1532 g_int_hash, g_int_equal, NULL, free_cpu_boosting_info);
1533 g_assert(g_cpu_boosting_info_table[level]);
1536 dest_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
1537 cpu_boosting_destroy_request);
1538 g_assert(dest_table);
1540 g_cpu_contention_handle_data_table =
1541 g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
1542 free_cpu_contention_handle_data);
1543 g_assert(g_cpu_contention_handle_data_table);
1545 /* For the conf-based client */
1546 register_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf);
1548 return RESOURCED_ERROR_NONE;
1551 /* Called by resourced main thread */
1552 static int cpu_boosting_finalize(void *data)
1554 cpu_boosting_thread_deactivate();
1555 for (int level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++)
1556 g_hash_table_destroy(g_cpu_boosting_info_table[level]);
1557 g_hash_table_destroy(dest_table);
1558 g_hash_table_destroy(g_cpu_contention_handle_data_table);
1560 unregister_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf);
1561 return RESOURCED_ERROR_NONE;
1564 static struct module_ops cpu_boosting_modules_ops = {
1565 .priority = MODULE_PRIORITY_EARLY,
1566 .name = "cpu-boosting",
1567 .init = cpu_boosting_init,
1568 .exit = cpu_boosting_finalize,
1571 MODULE_REGISTER(&cpu_boosting_modules_ops)