2 * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
26 #include <semaphore.h>
29 #include <sys/prctl.h>
30 #include <sys/signalfd.h>
31 #include <sys/types.h>
34 #include <sys/syscall.h>
36 #include <sys/resource.h>
38 #include <native_service/cl_process.h>
39 #include "cl_process_internal.h"
41 #include "cl_cgroup.h"
42 #include "cl_monitor_internal.h"
44 #define assert_static(e) \
46 enum { assert_static__ = 1/(e) }; \
49 struct linux_dirent64 {
52 unsigned short d_reclen;
58 * Initialize the process
60 int CL_ProcessInit(void) {
65 assert_static(sizeof(CL_ProcessAttr_t) == sizeof(CL_ProcessAttrInternal_t));
67 name = getenv(CL_PROCESS_NAME_ENV);
68 if (name != NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
69 if (prctl(PR_SET_NAME, name) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
70 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
72 CL_PERROR("prctl"); // LCOV_EXCL_LINE 5: fail safe for libc getenv
73 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc getenv
77 if (sigemptyset(&mask) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigemptyset
78 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
80 CL_PERROR("sigemptyset"); // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
81 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
83 if (sigaddset(&mask, SIGCHLD) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigaddset
84 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
86 CL_PERROR("sigaddset"); // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
87 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
89 if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigprocmask
90 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
92 CL_PERROR("sigprocmask"); // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
93 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
96 if ((sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC)) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc signalfd
97 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
99 CL_PERROR("signalfd"); // LCOV_EXCL_LINE 5: fail safe for libc signalfd
100 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc signalfd
108 * start of the functions to be executed from fork to exec
110 static void cl_process_pf_err(char no) {
111 char errorstr[17] = "err:post_fork:0\n";
115 if (write(STDERR_FILENO, errorstr, 16) == -1 && errno == EINTR) { // LCOV_EXCL_BR_LINE 5: fail safe for libc write
116 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
117 continue; // LCOV_EXCL_LINE 5: fail safe for libc write
123 static inline int cl_process_pf_set_schedule(const CL_ProcessAttrInternal_t *ia) {
125 struct sched_param param;
128 switch (ia->sched_policy) {
129 case CL_PROCESS_SCHED_POLICY_RR:
131 param.sched_priority = ia->sched_priority;
133 case CL_PROCESS_SCHED_POLICY_FIFO:
134 param.sched_priority = ia->sched_priority;
138 param.sched_priority = 0;
139 policy = SCHED_OTHER;
142 if (sched_setscheduler(getpid(), policy, ¶m) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
143 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
144 cl_process_pf_err('3');// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
145 goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
147 if (ia->sched_policy == CL_PROCESS_SCHED_POLICY_OTHER) {
148 if (setpriority(PRIO_PROCESS, (__id_t)getpid(), ia->sched_priority) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpriority
149 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
151 cl_process_pf_err('4');// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
152 goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
161 static inline int cl_process_pf_check_close_fd(int check_fd, int dirfd, int hold_fds_num, const int *hold_fds) {
164 if (check_fd < 3 || check_fd == dirfd) {
168 for (i = 0; i < hold_fds_num; i++) {
169 if (check_fd == *(hold_fds + i)) {
177 static inline int cl_process_pf_fname2fd(const char *s) {
179 for (; *s != '\0'; s++) {
180 result = result * 10 + (*s - '0');
185 static inline int cl_process_pf_cleanup_fds(const CL_ProcessAttrInternal_t *ia) {
190 struct linux_dirent64 *d;
193 for (i = 0; i < CL_PROCESSS_ATTR_HOLD_FDS_NUM; i++) {
194 if (ia->hold_fds[i] == 0) {
200 if ((dfd = open("/proc/self/fd/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function open
201 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
203 cl_process_pf_err('8');// LCOV_EXCL_LINE 5: fail safe for glibc function open
204 goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function open
212 nread = syscall(SYS_getdents64, dfd, buf, sizeof(buf));
213 if (nread == -1) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
214 // LCOV_EXCL_START 5: fail safe for glibc function syscall
216 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
218 cl_process_pf_err('9');
224 if (nread == 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
228 for (bpos = 0; bpos < nread;) {
229 d = (struct linux_dirent64 *)(buf + bpos);
230 fd = cl_process_pf_fname2fd(d->d_name);
231 if (cl_process_pf_check_close_fd(fd, dfd, hold_fds_num, ia->hold_fds)) {
244 static void cl_process_post_fork(const char *file, char *const argv[], char *const envp[],
245 const CL_ProcessAttrInternal_t *ia) {
247 char intfy_fname[32] = "/tmp/intfy_00000";
248 pid_t pid = getpid();
250 intfy_fname[11] = (char)(intfy_fname[11] + (pid / 10000));
251 intfy_fname[12] = (char)(intfy_fname[12] + ((pid / 1000) % 10));
252 intfy_fname[13] = (char)(intfy_fname[13] + ((pid / 100) % 10));
253 intfy_fname[14] = (char)(intfy_fname[14] + ((pid / 10) % 10));
254 intfy_fname[15] = (char)(intfy_fname[15] + (pid % 10));
257 if ((intfy_fd = open(intfy_fname, O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function open
258 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
259 cl_process_pf_err('0'); // LCOV_EXCL_LINE 5:libc fail safe for open
260 goto exit; // LCOV_EXCL_LINE 5:libc fail safe for open
262 if (close(intfy_fd) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function close
263 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
264 cl_process_pf_err('1'); // LCOV_EXCL_LINE 5:libc fail safe for close
265 goto exit; // LCOV_EXCL_LINE 5:libc fail safe for close
269 if (ia->create_group) {
270 if (setpgid(getpid(), getpid()) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpgid
271 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
272 cl_process_pf_err('2'); // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
273 goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
277 // Scheduling Policy/Priority
278 if (cl_process_pf_set_schedule(ia) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
279 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
280 goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
285 if (setgid(ia->gid) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setgid
286 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
287 cl_process_pf_err('5'); // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
288 goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
293 uid_t uid = (ia->uid == UINT_MAX) ? 0 : ia->uid;
294 if (setuid(uid) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setuid
295 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
296 cl_process_pf_err('6');// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
297 goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
302 if (ia->stack_size) {
304 getrlimit(RLIMIT_STACK, &rlim);
305 rlim.rlim_cur = (rlim_t)ia->stack_size;
306 if (setrlimit(RLIMIT_STACK, &rlim) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setrlimit
307 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
309 cl_process_pf_err('7');// LCOV_EXCL_LINE 5: fail safe for glibc function setrlimit
314 if (ia->disable_close_fds == 0) {
315 if (cl_process_pf_cleanup_fds(ia) < 0) {
321 if (execve(file, argv, envp) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function execve
322 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
323 cl_process_pf_err('A');// LCOV_EXCL_LINE 5: fail safe for glibc function execve
330 * end of the functions to be executed from fork to exec
333 static int cl_process_pre_fork(char *const envp[], char ***new_env, const CL_ProcessAttrInternal_t *ia) {
339 size_t name_env_len = strlen(CL_PROCESS_NAME_ENV);
340 int last_name_env_pos = -1;
348 for (i = 0; e[i] != NULL; i++) {
349 if (strncmp(e[i], CL_PROCESS_NAME_ENV, name_env_len) == 0) {
350 last_name_env_pos = i;
352 envlen += strlen(e[i]) + 1;
356 if (ia->name[0] != 0) {
357 envlen += strlen(CL_PROCESS_NAME_ENV) + 1 + strlen(ia->name) + 1;
361 if ((b = malloc(envlen)) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
362 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
363 CL_ERR_PRINT("malloc fail"); // LCOV_EXCL_LINE 5: fail safe for libc malloc
364 errno = EFAULT; // LCOV_EXCL_LINE 5: fail safe for libc malloc
365 goto error; // LCOV_EXCL_LINE 5: fail safe for libc malloc
367 memset(b, 0, envlen);
369 if ((*new_env = malloc(sizeof(char *) * (size_t)(i + 1))) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
370 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
371 free(b); // LCOV_EXCL_LINE 5: fail safe for libc malloc
372 CL_ERR_PRINT("malloc fail"); // LCOV_EXCL_LINE 5: fail safe for libc malloc
373 errno = EFAULT; // LCOV_EXCL_LINE 5: fail safe for libc malloc
374 goto error; // LCOV_EXCL_LINE 5: fail safe for libc malloc
376 memset(*new_env, 0, sizeof(char *) * (size_t)(i + 1));
379 for (i = 0; e[i] != NULL; i++) {
380 if (i == last_name_env_pos) {
385 b += strlen(e[i]) + 1;
389 if (ia->name[0] != 0) {
390 *(*new_env + new_env_count) = b;
391 b += sprintf(b, "%s=%s", CL_PROCESS_NAME_ENV, ia->name);
405 int CL_ProcessCreate(const char *file, char *const argv[], char *const envp[], const CL_ProcessAttr_t *attr) {
406 const CL_ProcessAttrInternal_t *ia = (const CL_ProcessAttrInternal_t *)attr;
408 char intfy_fname[32];
414 if (file == NULL || argv == NULL || attr == NULL) {
419 if (cl_process_pre_fork(envp, &new_env, ia) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc function malloc
424 switch (childpid) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function fork
425 case 0: /* child process */
426 cl_process_post_fork(file, argv, new_env, ia);
427 _exit(CL_PROCESS_EXIT_INTERNAL);
433 default: /* parent process */
437 if (ia->cpu_assign != 0) {
440 for (i = 0; i < (sizeof(ia->cpu_assign) * 8); i++) {
441 if ((ia->cpu_assign >> i) & 0x1) {
445 // LCOV_EXCL_BR_START 5: fail safe for libc sched_setaffinity
446 if (sched_setaffinity(childpid, sizeof(set), &set) < 0) {
448 int last_errno = errno;
449 CL_PERROR("sched_setaffinity");
456 ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, childpid);
457 if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for libc snprintf
458 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
459 CL_ERR_PRINT("snprintf fail:%d", ret); // LCOV_EXCL_LINE 5: fail safe for libc snprintf
460 childpid = -1; // LCOV_EXCL_LINE 5: fail safe for libc snprintf
461 goto exit; // LCOV_EXCL_LINE 5: fail safe for libc snprintf
464 if (ia->cgroup_name[0] != '\0') {
465 if (cl_cgroup_exist(CL_CGROUP_CPU, ia->cgroup_name) == 0) {
466 if (cl_cgroup_set_num(CL_CGROUP_CPU, ia->cgroup_name, "tasks", childpid) < 0) {
467 int last_errno = errno;
468 CL_PERROR("cl_cgroup_set_num");
474 // LCOV_EXCL_BR_START 5: fail safe for glibc function access
475 if (cl_cgroup_exist(CL_CGROUP_MEMORY, ia->cgroup_name) == 0) {
477 if (cl_cgroup_set_num(CL_CGROUP_MEMORY, ia->cgroup_name, "tasks", childpid) < 0) {
478 int last_errno = errno;
479 CL_PERROR("cl_cgroup_set_num");
487 for (retry = 100; retry >= 0; retry--) {
488 if (access(intfy_fname, F_OK) == 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
502 * Initialize process attribute
504 int CL_ProcessCreateAttrInit(CL_ProcessAttr_t *attr) {
510 memset(attr, 0, sizeof(CL_ProcessAttr_t));
515 * Set process attribute (process name)
517 int CL_ProcessCreateAttrSetName(CL_ProcessAttr_t *attr, const char *name) {
518 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
520 if (attr == NULL || name == NULL) {
525 strncpy(ia->name, name, 16);
532 * Set process attribute (user ID)
534 int CL_ProcessCreateAttrSetUid(CL_ProcessAttr_t *attr, uid_t uid) {
535 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
548 * Set process attribute (group ID)
550 int CL_ProcessCreateAttrSetGid(CL_ProcessAttr_t *attr, gid_t gid) {
551 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
564 * Set process attribute (schedule policy and priority)
566 int CL_ProcessCreateAttrSetSchedule(CL_ProcessAttr_t *attr, CL_ProcessSchedPolicy_t policy, int priority) {
567 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
574 if (policy == CL_PROCESS_SCHED_POLICY_RR || policy == CL_PROCESS_SCHED_POLICY_FIFO) {
575 if (priority < 1 || priority > 99) {
579 } else if (policy == CL_PROCESS_SCHED_POLICY_OTHER) {
580 if (priority < -20 || priority > 19) {
581 CL_ERR_PRINT("Invlid SCHED_OTHER priority:%d", priority);
588 ia->sched_policy = policy;
589 ia->sched_priority = priority;
595 * Set process attribute (process group)
597 int CL_ProcessCreateAttrSetGroup(CL_ProcessAttr_t *attr, int create) {
598 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
605 if (create < 0 || create > 1) {
610 ia->create_group = create;
615 static int32_t CL_CpuAssignMsbCpu(int cpu_assign) {
619 for (i = 0; i < (sizeof(cpu_assign) * 8); i++) {
620 if ((cpu_assign >> i) & 0x1)
628 * Set process attribute (CPU Assign)
630 int CL_ProcessCreateAttrSetCpuAssign(CL_ProcessAttr_t *attr, int cpu_assign) {
631 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
638 if (cpu_assign < 0) {
643 if (CL_CpuAssignMsbCpu(cpu_assign) >= sysconf(_SC_NPROCESSORS_CONF)) {
648 ia->cpu_assign = cpu_assign;
654 * Set process attribute (Stack Size)
656 int CL_ProcessCreateAttrSetStackSize(CL_ProcessAttr_t *attr, int stack_size) {
657 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
664 ia->stack_size = stack_size;
670 * Set process attribute (FD to maintain)
672 int CL_ProcessCreateAttrSetHoldFds(CL_ProcessAttr_t *attr, int hold_fds[]) {
673 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
675 if (attr == NULL || hold_fds == NULL) {
680 memcpy(ia->hold_fds, hold_fds, sizeof(ia->hold_fds));
686 * Set process attribute (to suspend forced FD close)
688 int CL_ProcessCreateAttrSetDisableCloseFds(CL_ProcessAttr_t *attr) {
689 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
696 ia->disable_close_fds = 1;
702 * Set process attribute (Cgroup)
704 int CL_ProcessCreateAttrSetCgroup(CL_ProcessAttr_t *attr, const char *cgroup_name) {
705 CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
707 if (attr == NULL || cgroup_name == NULL) {
712 if (strlen(cgroup_name) >= sizeof(ia->cgroup_name)) {
717 strcpy(ia->cgroup_name, cgroup_name);
725 int CL_ProcessTerminate(pid_t pid) {
726 return kill(pid, SIGKILL);
732 int CL_ProcessTerminateGroup(pid_t pid) {
733 return killpg(pid, SIGKILL);
737 * Forced process termination
739 int CL_ProcessAbort(pid_t pid) {
740 return kill(pid, SIGABRT);
744 * Forced process group termination
746 int CL_ProcessAbortGroup(pid_t pid) {
747 return killpg(pid, SIGABRT);
751 * Euthanize process group
753 int CL_ProcessEuthanizeGroup(pid_t pid) {
755 return killpg(pid, SIGKILL);
759 * Collect child process
761 int CL_ProcessCleanup(int sigchld_fd, CL_ProcessCleanupInfo_t *cleanup_info) {
762 struct signalfd_siginfo fdsi;
766 char intfy_fname[32];
768 if (cleanup_info == NULL) {
774 s = read(sigchld_fd, &fdsi, sizeof(struct signalfd_siginfo));
775 if (s != sizeof(struct signalfd_siginfo)) {
776 if (s == -1 && errno == EINTR) {
785 ret = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
788 } else if (ret == 0 && info.si_pid == 0) {
795 cleanup_info->pid = info.si_pid;
796 cleanup_info->code = info.si_code;
797 cleanup_info->status = info.si_status;
799 cl_monitor_cleanup(info.si_pid);
801 ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, info.si_pid);
803 if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function snprintf
804 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
805 CL_ERR_PRINT("snprintf fail:%d\n", ret);// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
806 goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
808 if (unlink(intfy_fname) < 0) {
814 ret = waitid(P_ALL, 0, &info, WEXITED | WNOWAIT | WNOHANG);
815 if (ret == 0 && info.si_pid != 0) {
817 } else if (ret == -1 && errno != ECHILD) {
825 CL_ThreadAttrInternal_t *ia;
826 void *(*start_routine)(void *);
828 } create_thread_arg_t;
830 static void *thread_start_func(void *arg) {
831 create_thread_arg_t *p = (create_thread_arg_t *)arg;
832 void *(*start_routine)(void *) = p->start_routine;
833 void *start_arg = p->start_arg;
835 prctl(PR_SET_NAME, p->ia->name != 0 ? p->ia->name : NULL);
837 if (sem_post(&p->sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_post
838 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
839 CL_PERROR("sem_post"); // LCOV_EXCL_LINE 5: fail safe for libc sem_post
842 return (*start_routine)(start_arg);
848 int CL_ThreadCreate(pthread_t *thread, pthread_attr_t *attr, CL_ThreadAttr_t *cl_attr, void *(*start_routine)(void *),
851 create_thread_arg_t cr_arg = { .ia = (CL_ThreadAttrInternal_t *)cl_attr,
852 .start_routine = start_routine,
856 if (thread == NULL || cl_attr == NULL || start_routine == NULL) {
861 if (sem_init(&cr_arg.sem, 0, 0) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sem_init
862 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
864 return -1; // LCOV_EXCL_LINE 5: fail safe for libc sem_init
867 // LCOV_EXCL_BR_START 5: fail safe for libc pthread_create
868 if ((ret = pthread_create(thread, attr, thread_start_func, &cr_arg)) != 0) {
871 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
873 errno = ret; // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
874 return -1; // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
877 if (sem_wait(&cr_arg.sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_wait
878 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
880 return -1; // LCOV_EXCL_LINE 5: fail safe for libc sem_wait
887 * Initialize CommonLibrary extension thread attribute
889 int CL_ThreadCreateAttrInit(CL_ThreadAttr_t *attr) {
890 assert_static(sizeof(CL_ThreadAttr_t) == sizeof(CL_ThreadAttrInternal_t));
897 memset(attr, 0, sizeof(CL_ThreadAttr_t));
902 * Set CommonLibrary extension thread attribute (thread name)
904 int CL_ThreadCreateAttrSetName(CL_ThreadAttr_t *attr, const char *name) {
905 CL_ThreadAttrInternal_t *ia = (CL_ThreadAttrInternal_t *)attr;
907 if (attr == NULL || name == NULL) {
912 strncpy(ia->name, name, 16);
921 int CL_ProcessCreateCgroupCreate(const char *cgroup_name, CL_ProcessCreateCgroupAttr_t *attr) {
922 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
923 CL_ProcessCreateCgroupAttrInternal_t cmp;
925 if (cgroup_name == NULL || attr == NULL) {
930 memset(&cmp, 0, sizeof(CL_ProcessCreateCgroupAttrInternal_t));
931 if (memcmp(ia, &cmp, sizeof(CL_ProcessCreateCgroupAttrInternal_t)) == 0) {
936 if (ia->rt_runtime_us || ia->cfs_quota_us || ia->cpu_shares) {
937 // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
938 if (cl_cgroup_make(CL_CGROUP_CPU, cgroup_name) < 0) {
943 if (ia->rt_runtime_us) {
944 // LCOV_EXCL_BR_START 5: fail safe for glibc function write
945 if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.rt_runtime_us", ia->rt_runtime_us) < 0) {
948 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
950 return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
954 if (ia->cfs_quota_us) {
955 // LCOV_EXCL_BR_START 5: fail safe for glibc function write
956 if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.cfs_quota_us", ia->cfs_quota_us) < 0) {
959 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
961 return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
965 if (ia->cpu_shares) {
966 // LCOV_EXCL_BR_START 5: fail safe for glibc function write
967 if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.shares", ia->cpu_shares) < 0) {
969 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
970 return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
975 if (ia->memory_limit || ia->usage_in_bytes || ia->event_fd) {
976 // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
977 if (cl_cgroup_make(CL_CGROUP_MEMORY, cgroup_name) < 0) {
982 if (ia->memory_limit) {
983 // LCOV_EXCL_BR_START 5: fail safe for glibc function write
984 if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.limit_in_bytes", ia->memory_limit) < 0) {
989 if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.limit_in_bytes", ia->memory_limit) < 0) {
995 if (ia->usage_in_bytes || ia->event_fd) {
999 // LCOV_EXCL_BR_START 5: fail safe for glibc function open
1000 if ( (checkfd = cl_cgroup_open(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.usage_in_bytes", O_RDONLY)) < 0) {
1001 // LCOV_EXCL_BR_STOP
1002 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
1003 return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function open
1006 snprintf(setstr, sizeof(setstr), "%d %d %d", ia->event_fd, checkfd, ia->usage_in_bytes);
1007 // LCOV_EXCL_BR_START 5: fail safe for glibc function write
1008 if (cl_cgroup_set_string(CL_CGROUP_MEMORY, cgroup_name, "cgroup.event_control", setstr) < 0) {
1009 // LCOV_EXCL_BR_STOP
1011 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
1013 return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
1022 * Initialize Cgroup attribute
1024 int CL_ProcessCreateCgroupAttrInit(CL_ProcessCreateCgroupAttr_t *attr) {
1025 assert_static(sizeof(CL_ProcessCreateCgroupAttr_t) == sizeof(CL_ProcessCreateCgroupAttrInternal_t));
1032 memset(attr, 0, sizeof(CL_ProcessCreateCgroupAttr_t));
1037 * Set Cgroup attribute (RT Throttling)
1039 int CL_ProcessCreateCgroupAttrSetRtThrottling(CL_ProcessCreateCgroupAttr_t *attr, int runtime_us) {
1040 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1047 ia->rt_runtime_us = runtime_us;
1053 * Set Cgroup attribute (CFS Bandwidth Control)
1055 int CL_ProcessCreateCgroupAttrSetCfsBandwidthControl(CL_ProcessCreateCgroupAttr_t *attr, int cfs_quota_us) {
1056 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1063 ia->cfs_quota_us = cfs_quota_us;
1069 * Set Cgroup attribute (CPU Shares)
1071 int CL_ProcessCreateCgroupAttrSetCpuShares(CL_ProcessCreateCgroupAttr_t *attr, int cpu_shares) {
1072 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1079 ia->cpu_shares = cpu_shares;
1085 * Set Cgroup attribute (Memory Limit)
1087 int CL_ProcessCreateCgroupAttrSetMemoryLimit(CL_ProcessCreateCgroupAttr_t *attr, int memory_limit) {
1088 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1095 ia->memory_limit = memory_limit;
1101 * Set Cgroup attribute (Memory Usage Notification)
1103 int CL_ProcessCreateCgroupAttrSetMemoryUsageNotification(CL_ProcessCreateCgroupAttr_t *attr, int usage_in_bytes,
1105 CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1117 ia->usage_in_bytes = usage_in_bytes;
1118 ia->event_fd = event_fd;
1126 int CL_ProcessCreateCgroupDelete(const char *cgroup_name) {
1127 int mem_ret = 1, mem_err;
1128 int cpu_ret = 1, cpu_err;
1130 if (cgroup_name == NULL) {
1134 // LCOV_EXCL_BR_START 5: fail safe for glibc function access
1135 if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {
1136 // LCOV_EXCL_BR_STOP
1137 mem_ret = cl_cgroup_remove(CL_CGROUP_MEMORY, cgroup_name);
1141 // LCOV_EXCL_BR_START 5: fail safe for glibc function access
1142 if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {
1143 // LCOV_EXCL_BR_STOP
1144 cpu_ret = cl_cgroup_remove(CL_CGROUP_CPU, cgroup_name);
1148 if (mem_ret == 1 && cpu_ret == 1) {
1151 } else if (mem_ret < 0) {
1154 } else if (cpu_ret < 0) {
1163 * Move process to the Cgroup
1165 int CL_ProcessCreateCgroupClassify(const char *cgroup_name, pid_t pid) {
1166 int mem_ret = 1, mem_err;
1167 int cpu_ret = 1, cpu_err;
1169 if (cgroup_name == NULL) {
1174 if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
1175 mem_ret = cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "tasks", pid);
1179 if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
1180 cpu_ret = cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "tasks", pid);
1184 if (mem_ret == 1 && cpu_ret == 1) {
1187 } else if (mem_ret < 0) {
1190 } else if (cpu_ret < 0) {
1198 /* vim:set ts=8 sts=2 sw=2: */