3 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is furnished
10 * to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "cpu-boosting-type.h"
25 #include "cpu-boosting-private.h"
31 #include <sys/socket.h>
32 #include <sys/types.h>
35 #include <sys/syscall.h>
38 #define gettid() (pid_t) syscall(SYS_gettid)
40 #error "SYS_gettid unavailable on this system"
44 #define MAX_THREAD_NUM 131072 /* This value is based on the max value of pid_max */
45 #define SOCK_PATH "/run/.resourced.socket"
47 static int resource_create_and_connect_sock(void)
51 struct sockaddr_un sockaddr;
53 sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
55 _E("[CPU-BOOSTING-PLUGIN] Failed to allocate a socket");
59 sockaddr.sun_family = AF_UNIX;
60 strncpy(sockaddr.sun_path, SOCK_PATH, strlen(SOCK_PATH) + 1);
61 len = sizeof(sockaddr);
63 if (connect(sock, (struct sockaddr *)&sockaddr, len) < 0) {
64 _E("[CPU-BOOSTING-PLUGIN] Failed to connect to the resourced module");
72 static inline bool resource_pid_input_is_valid(resource_pid_t pid)
75 _E("[CPU-BOOSTING-PLUGIN] pid should be euqal or larger than 0");
79 if (pid.pid == 0 && pid.tid != NULL) {
80 if (pid.tid_count <= 0) {
81 _E("[CPU-BOOSTING-PLUGIN] tid count should be larger than 0");
85 for (int i = 0; i < pid.tid_count; i++) {
86 if (pid.tid[i] <= 0) {
87 _E("[CPU-BOOSTING-PLUGIN] Thread (id = %d) should be larger than 0",
97 static inline bool resource_cpu_boosting_level_input_is_valid(cpu_boosting_level_e level)
99 if (level < CPU_BOOSTING_LEVEL_STRONG || level > CPU_BOOSTING_LEVEL_WEAK) {
100 _E("[CPU-BOOSTING-PLUGIN] cpu boosting level should be located between %d and %d, but current level = %d", CPU_BOOSTING_LEVEL_STRONG, CPU_BOOSTING_LEVEL_WEAK, level);
107 static int resource_cpu_boosting_send_command (cpu_boosting_input_t input, int sock)
112 if (input.pid.pid != 0)
115 if (input.pid.tid == NULL) {
117 input.pid.tid = &tid;
118 input.pid.tid_count = 1;
121 input.body_len = input.pid.tid_count * sizeof(pid_t);
124 byte = send(sock, (const void *)&input, sizeof(input), 0);
125 if (byte != sizeof(input)) {
126 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
127 _E("[CPU-BOOSTING-PLUGIN] client input size is %u, but sent size is %d",
128 (unsigned int)sizeof(input), byte);
132 if (input.body_len > 0) {
133 switch (input.command) {
134 case CPU_BOOSTING_COMMAND_SET:
135 case CPU_BOOSTING_COMMAND_CLEAR:
136 case CPU_BOOSTING_COMMAND_GET:
137 case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
138 byte = send(sock, (const void *)input.pid.tid, input.body_len, 0);
139 if (byte != input.body_len) {
140 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
141 _E("[CPU-BOOSTING-PLUGIN] client input size is %d, but sent size is %d",
142 input.body_len, byte);
149 if (input.dest && input.dest_len > 0) {
150 byte = send(sock, (const void *)input.dest, input.dest_len, 0);
151 if (byte != input.dest_len) {
152 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
153 _E("[CPU-BOOSTING-PLUGIN] client input size is %d, but sent size is %d",
154 input.dest_len, byte);
162 API int resource_set_cpu_boosting (resource_pid_t pid,
163 cpu_boosting_level_e level, cpu_boosting_flag_e flags, int timeout_msec)
167 cpu_boosting_input_t input;
169 if (!resource_pid_input_is_valid(pid))
172 if (!resource_cpu_boosting_level_input_is_valid(level))
175 if ((sock = resource_create_and_connect_sock()) < 0)
178 memset(&input, 0, sizeof(input));
179 input.command = CPU_BOOSTING_COMMAND_SET;
183 input.timeout_msec = timeout_msec;
185 ret = resource_cpu_boosting_send_command(input, sock);
191 API int resource_clear_cpu_boosting (resource_pid_t pid)
195 cpu_boosting_input_t input;
197 if (!resource_pid_input_is_valid(pid))
200 if ((sock = resource_create_and_connect_sock()) < 0)
203 memset(&input, 0, sizeof(input));
204 input.command = CPU_BOOSTING_COMMAND_CLEAR;
206 input.level = CPU_BOOSTING_LEVEL_NONE;
208 ret = resource_cpu_boosting_send_command(input, sock);
214 API int resource_get_cpu_boosting_level (resource_pid_t pid,
215 cpu_boosting_level_info_t *level)
221 cpu_boosting_output_t output;
222 cpu_boosting_input_t input;
224 if (!resource_pid_input_is_valid(pid))
227 if ((sock = resource_create_and_connect_sock()) < 0)
230 memset(&input, 0, sizeof(input));
231 input.command = CPU_BOOSTING_COMMAND_GET;
233 input.level = CPU_BOOSTING_LEVEL_NONE;
235 ret = resource_cpu_boosting_send_command(input, sock);
242 if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(tv)) < 0)
243 _E("[CPU-BOOSTING-PLUGIN] Failed to set timeout of receive (error = %m)");
245 memset(&output, 0, sizeof(output));
247 byte = recv(sock, (void *)&output, sizeof(output), 0);
248 if (byte != sizeof(output)) {
250 if (errno == EAGAIN && retry == false) {
256 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
259 _E("[CPU-BOOSTING-PLUGIN] client output size is %u, but received size is %d",
260 (unsigned int)sizeof(output), byte);
265 if (output.level.tid_count > 0 && output.level.tid_count < MAX_THREAD_NUM) {
266 level->tid_level = (int *)calloc(output.level.tid_count, sizeof(int));
267 if (level->tid_level == NULL) {
268 _E("[CPU-BOOSTING-PLUGIN] Failed to allocate memory");
273 level->tid_count = output.level.tid_count;
276 byte = recv(sock, (void *)level->tid_level, level->tid_count * sizeof(int), 0);
277 if (byte != level->tid_count * sizeof(int)) {
279 if (errno == EAGAIN && retry == false) {
285 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
288 _E("[CPU-BOOSTING-PLUGIN] client output size is %u, but received size is %d",
289 level->tid_count * (unsigned int)sizeof(int), byte);
291 free(level->tid_level);
296 if (!output.success) {
297 _E("[CPU-BOOSTING-PLUGIN] Failed to get boosting from the server");
298 free(level->tid_level);
303 _E("[CPU-BOOSTING-PLUGIN] Returned tid_count is out of scope");
314 API int resource_set_cpu_inheritance (pid_t source_tid, const char *dest_process, int timeout_msec)
318 cpu_boosting_input_t input;
322 else if (source_tid == 0)
323 source_tid = gettid();
325 if (dest_process == NULL)
328 if ((sock = resource_create_and_connect_sock()) < 0)
331 memset(&input, 0, sizeof(input));
332 input.command = CPU_BOOSTING_COMMAND_SET_INHERITANCE;
333 input.pid.pid = source_tid;
334 input.timeout_msec = timeout_msec;
335 input.dest = dest_process;
336 input.dest_len = strlen(dest_process);
338 ret = resource_cpu_boosting_send_command(input, sock);
344 API int resource_clear_cpu_inheritance (pid_t source_tid, const char *dest_process)
348 cpu_boosting_input_t input;
352 else if (source_tid == 0)
353 source_tid = gettid();
355 if (dest_process == NULL)
358 if ((sock = resource_create_and_connect_sock()) < 0)
361 memset(&input, 0, sizeof(input));
362 input.command = CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE;
363 input.pid.pid = source_tid;
364 input.dest = dest_process;
365 input.dest_len = strlen(dest_process);
367 ret = resource_cpu_boosting_send_command(input, sock);
373 API int resource_register_cpu_inheritance_destination (const char *dest_process, resource_pid_t pid)
377 cpu_boosting_input_t input;
379 if (!resource_pid_input_is_valid(pid))
382 if (dest_process == NULL)
385 if ((sock = resource_create_and_connect_sock()) < 0)
388 memset(&input, 0, sizeof(input));
389 input.command = CPU_BOOSTING_COMMAND_REGISTER_DESTINATION;
391 input.dest = dest_process;
392 input.dest_len = strlen(dest_process);
394 ret = resource_cpu_boosting_send_command(input, sock);
400 API int resource_unregister_cpu_inheritance_destination (const char *dest_process)
404 cpu_boosting_input_t input;
406 if (dest_process == NULL)
409 if ((sock = resource_create_and_connect_sock()) < 0)
412 memset(&input, 0, sizeof(input));
413 input.command = CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION;
415 input.dest = dest_process;
416 input.dest_len = strlen(dest_process);
418 ret = resource_cpu_boosting_send_command(input, sock);
424 void __CONSTRUCTOR__ cpu_boosting_plugin_init(void)
426 _D("[CPU-BOOSTING-PLUGIN] CPU boosting plugin Module is loaded");
429 void __DESTRUCTOR__ cpu_boosting_plugin_exit(void)
431 _D("[CPU-BOOSTING-PLUGIN] CPU boosting plugin Module is unloaded");