summaryrefslogtreecommitdiffstats
path: root/nsframework/common_library/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'nsframework/common_library/client/src')
-rw-r--r--nsframework/common_library/client/src/cl_cgroup.c260
-rw-r--r--nsframework/common_library/client/src/cl_lock.c221
-rw-r--r--nsframework/common_library/client/src/cl_monitor.c442
-rw-r--r--nsframework/common_library/client/src/cl_process.c1198
-rw-r--r--nsframework/common_library/client/src/cl_region.c295
-rw-r--r--nsframework/common_library/client/src/cl_sem.c67
6 files changed, 2483 insertions, 0 deletions
diff --git a/nsframework/common_library/client/src/cl_cgroup.c b/nsframework/common_library/client/src/cl_cgroup.c
new file mode 100644
index 00000000..812ccaaa
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_cgroup.c
@@ -0,0 +1,260 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "cl_cgroup.h"
+
+#define CL_CGROOT "/sys/fs/cgroup/"
+
+static char *cl_cgroup_base(cl_cgroup_t cgroup) {
+ switch (cgroup) { // LCOV_EXCL_BR_LINE 200: internal interface,code make sure
+ case CL_CGROUP_MEMORY:
+ return CL_CGROOT "/memory";
+ case CL_CGROUP_CPU:
+ return CL_CGROOT "/cpu";
+ }
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return NULL;// LCOV_EXCL_LINE 200:internal interface,code make sure nerver run
+}
+
+static char *cl_cgroup_create_path(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler) {
+ char *path = malloc(FILENAME_MAX);
+
+ if (path == NULL) { // LCOV_EXCL_BR_LINE 5:fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = ENOMEM; // LCOV_EXCL_LINE 5:fail safe for libc malloc
+ goto error; // LCOV_EXCL_LINE 5:fail safe for libc malloc
+ }
+
+ if (cgroup != CL_CGROUP_MEMORY && cgroup != CL_CGROUP_CPU) { // LCOV_EXCL_BR_LINE 200: internal interface,code make sure
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = EINVAL; // LCOV_EXCL_LINE 200: internal interface,code make sure
+ goto error; // LCOV_EXCL_LINE 200: internal interface,code make sure
+ }
+
+ if (cgroup_name == NULL) { // LCOV_EXCL_BR_LINE 200: internal interface,code make sure
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = EINVAL; // LCOV_EXCL_LINE 200: internal interface,code make sure
+ goto error; // LCOV_EXCL_LINE 200: internal interface,code make sure
+ }
+
+ if (controler) {
+ snprintf(path, FILENAME_MAX, "%s/%s/%s", cl_cgroup_base(cgroup), cgroup_name, controler);
+ } else {
+ snprintf(path, FILENAME_MAX, "%s/%s", cl_cgroup_base(cgroup), cgroup_name);
+ }
+
+ return path;
+
+error:
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ free(path); // LCOV_EXCL_LINE 200: internal interface,code make sure
+ return NULL; // LCOV_EXCL_LINE 200: internal interface,code make sure
+}
+
+int cl_cgroup_make(cl_cgroup_t cgroup, const char *cgroup_name) {
+ int r = -1;
+ char *path = cl_cgroup_create_path(cgroup, cgroup_name, NULL);
+
+ if (path == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ goto exit; // LCOV_EXCL_LINE 6: double check
+ }
+
+ if (mkdir(path, 0777) < 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc mkdir
+ goto exit;
+ }
+
+ r = 0;
+
+exit:
+ if (path) {// LCOV_EXCL_BR_LINE 6: double check
+ free(path);
+ }
+ return r;
+}
+
+int cl_cgroup_remove(cl_cgroup_t cgroup, const char *cgroup_name) {
+ int r = -1;
+ char *path = cl_cgroup_create_path(cgroup, cgroup_name, NULL);
+
+ if (path == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ goto exit; // LCOV_EXCL_LINE 6: double check
+ }
+
+ if (rmdir(path) < 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc rmdir
+ goto exit;
+ }
+
+ r = 0;
+
+exit:
+ if (path) { // LCOV_EXCL_BR_LINE 6: double check
+ free(path);
+ }
+ return r;
+}
+
+int cl_cgroup_exist(cl_cgroup_t cgroup, const char *cgroup_name) {
+ int r = -1;
+ char *path = cl_cgroup_create_path(cgroup, cgroup_name, NULL);
+
+ if (path == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ goto exit; // LCOV_EXCL_LINE 6: double check
+ }
+
+ r = access(path, F_OK);
+
+exit:
+ if (path) { // LCOV_EXCL_BR_LINE 6: double check
+ free(path);
+ }
+ return r;
+}
+
+int cl_cgroup_open(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler, int flags) {
+ int r = -1;
+ char *path = cl_cgroup_create_path(cgroup, cgroup_name, controler);
+ int fd = -1;
+
+ if (path == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ goto exit; // LCOV_EXCL_LINE 6: double check
+ }
+
+ if (controler == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = EINVAL; // LCOV_EXCL_LINE 6: double check
+ goto exit; // LCOV_EXCL_LINE 6: double check
+ }
+
+ if ((fd = open(path, flags | O_CLOEXEC)) < 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc open
+ goto exit;
+ }
+
+ r = fd;
+
+exit:
+ if (path) { // LCOV_EXCL_BR_LINE 6: double check
+ free(path);
+ }
+ return r;
+}
+
+int cl_cgroup_set_string(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler, const char *string) {
+ int r = -1;
+ int fd = -1;
+
+ if (controler == NULL || string == NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = EINVAL;// LCOV_EXCL_LINE 6: double check
+ goto exit;// LCOV_EXCL_LINE 6: double check
+ }
+
+ fd = cl_cgroup_open(cgroup, cgroup_name, controler, O_WRONLY);
+ if (fd < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc funtion open
+ goto exit;
+ }
+
+ if (write(fd, string, strlen(string)) < 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc write
+ goto exit;
+ }
+
+ r = 0;
+
+exit:
+ if (fd >= 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc funtion open
+ int save_err = errno;
+ close(fd);
+ errno = save_err;
+ }
+ return r;
+}
+
+int cl_cgroup_set_num(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler, int64_t value) {
+ char num_str[22];
+
+ snprintf(num_str, sizeof(num_str), "%" PRId64, value);
+
+ return cl_cgroup_set_string(cgroup, cgroup_name, controler, num_str);
+}
+
+int cl_cgroup_get_string(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler, char *string, size_t length) { // LCOV_EXCL_START 8: dead code // NOLINT (readability/nolint)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ int r = -1;
+ int fd = -1;
+
+ if (controler == NULL || string == NULL) {
+ errno = EINVAL;
+ goto exit;
+ }
+
+ fd = cl_cgroup_open(cgroup, cgroup_name, controler, O_RDONLY);
+ if (fd < 0) {
+ goto exit;
+ }
+
+ if (read(fd, string, length) < 0) {
+ goto exit;
+ }
+
+ r = 0;
+
+exit:
+ if (fd >= 0) {
+ int save_err = errno;
+ close(fd);
+ errno = save_err;
+ }
+ return r;
+}
+// LCOV_EXCL_STOP
+
+int64_t cl_cgroup_get_num(cl_cgroup_t cgroup, const char *cgroup_name, const char *controler) { // LCOV_EXCL_START 8: dead code // NOLINT (readability/nolint)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ int r;
+ char num_str[22];
+
+ if ((r = cl_cgroup_get_string(cgroup, cgroup_name, controler, num_str, sizeof(num_str))) < 0) {
+ return r;
+ }
+
+ return atoll(num_str);
+}
+// LCOV_EXCL_STOP
diff --git a/nsframework/common_library/client/src/cl_lock.c b/nsframework/common_library/client/src/cl_lock.c
new file mode 100644
index 00000000..6add2a5a
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_lock.c
@@ -0,0 +1,221 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 <stdio.h>
+// #include <stdlib.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <native_service/cl_lock.h>
+#include <native_service/cl_lockid.h>
+#include "cl_lock_internal.h"
+#include "cl_error.h"
+
+static int shm_id = -1;
+
+/*
+ * Lock file is consists of slots(4KB)
+ * The slot layout is:
+ * 0 ~ 4Byte : field of PID
+ * 4Byte ~ 28Byte : field of pthread_mutex_t
+ */
+
+
+static int cl_LockfileInit(void *base) {
+ int i;
+ /*
+ int j;
+ */
+ void *addr;
+ pthread_mutexattr_t attr;
+
+ if (pthread_mutexattr_init(&attr) != 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc pthread_mutexattr_init
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5:fail safe for libc pthread_mutexattr_init
+ }
+ if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc pthread_mutexattr_setpshared
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5:fail safe for libc pthread_mutexattr_setpshared
+ }
+// if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP) != 0) {
+// return -1;
+// }
+ if (pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) != 0) {
+ return -1;
+ }
+
+ for (i = 0; i < LID_NUM; i++) {
+ /*
+ addr = SLOT_SIZE * 1 + base;
+ for (j = 0; j < 1024; j++) {
+ *(int*)(addr + j * sizeof(int)) = j;
+ }
+ */
+ addr = SLOT_SIZE * i + (char *)base + sizeof(int);
+ pthread_mutex_init((pthread_mutex_t *)addr, &attr);
+
+ }
+ if (pthread_mutexattr_destroy(&attr) != 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc pthread_mutexattr_destroy
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5:fail safe for libc pthread_mutexattr_destroy
+ }
+ return 0;
+}
+
+/*
+ * Initialize in the system
+ * This function will generate the Lock file, and initialize pthread_mutex_t for all slots
+ */
+int CL_LockSystemInit(void) {
+ int fd = -1;
+ int ret = 0;
+ void *base = MAP_FAILED;
+
+ fd = shm_open(LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, (S_IRWXG | S_IRWXO | S_IRWXU));
+ if (fd < 0) {
+ ret = -1;
+ goto exit;
+ }
+ if (ftruncate(fd, LOCKFILE_SIZE) != 0) { // LCOV_EXCL_BR_LINE 5:fail safe for libc ftruncate
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ ret = -1; // LCOV_EXCL_LINE 5:fail safe for libc ftruncate
+ goto exit; // LCOV_EXCL_LINE 5:fail safe for libc ftruncate
+ }
+
+ base = mmap(NULL, LOCKFILE_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) { // LCOV_EXCL_BR_LINE 5:fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ ret = -1; // LCOV_EXCL_LINE 5:fail safe for libc mmap
+ goto exit; // LCOV_EXCL_LINE 5:fail safe for libc mmap
+ }
+
+ if (cl_LockfileInit(base) < 0) { // LCOV_EXCL_BR_LINE 11:out branch
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ ret = -1; // LCOV_EXCL_LINE 5:fail safe for libc
+ goto exit; // LCOV_EXCL_LINE 5:fail safe for libc
+ }
+
+exit:
+ if (fd >= 0) {
+ close(fd);
+ }
+ if (base != MAP_FAILED) {
+ munmap(base, LOCKFILE_SIZE);
+ }
+ return ret;
+}
+
+void CL_LockSystemFin_debug(void) {
+ if (shm_id >= 0) {
+ close(shm_id);
+ }
+ shm_unlink(LOCKFILE_NAME);
+ shm_id = -1;
+}
+
+/*
+ * Initialize in the process
+ * Open the Lock file
+ */
+int CL_LockProcessInit(void) {
+ if (shm_id < 0) {
+ shm_id = shm_open(LOCKFILE_NAME, O_RDWR, (S_IRWXG | S_IRWXO | S_IRWXU));
+ }
+ if (shm_id < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function shm_open
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function shm_open
+ }
+ return 0;
+}
+
+void *CL_LockMap(int lid) {
+ if ((lid < 0) || (lid >= LID_NUM)) {
+ errno = EINVAL;
+ return MAP_FAILED;
+ }
+ return mmap(NULL, SLOT_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, shm_id, (off_t)(lid * SLOT_SIZE));
+}
+
+int CL_LockUnmap(void *addr) {
+ return munmap(addr, SLOT_SIZE);
+}
+
+int CL_LockGet(void *addr) {
+ int ret;
+
+ if ((addr == NULL) || (addr == MAP_FAILED)) {
+ ret = EINVAL;
+ } else {
+ CL_DBG_PRINT("@@@@@ %s Start: pid = %d\n", __func__, *(int *)addr);
+ // LCOV_EXCL_BR_START 5:fail safe for libc pthread_mutex_lock
+ if ((ret = pthread_mutex_lock((pthread_mutex_t*)((char *)addr + sizeof(int)))) == 0) {
+ // LCOV_EXCL_BR_STOP
+ *(int *)addr = (int)getpid();
+ } else if (ret == EOWNERDEAD) {
+ if ((ret = pthread_mutex_consistent((pthread_mutex_t *)((char *)addr + sizeof(int)))) == 0) {
+ *(int *)addr = (int)getpid();
+ }
+ }
+ CL_DBG_PRINT("@@@@@ %s End: pid = %d\n", __func__, *(int *)addr);
+ }
+ return ret;
+}
+
+int CL_LockNowait(void *addr) {
+ int ret;
+
+ if ((addr == NULL) || (addr == MAP_FAILED)) {
+ ret = EINVAL;
+ } else {
+ CL_DBG_PRINT("@@@@@ %s Start: pid = %d\n", __func__, *(int *)addr);
+ if ((ret = pthread_mutex_trylock((pthread_mutex_t*)((char *)addr + sizeof(int)))) == 0) {
+ *(int *)addr = (int)getpid();
+ } else if (ret == EOWNERDEAD) {
+ if ((ret = pthread_mutex_consistent((pthread_mutex_t *)((char *)addr + sizeof(int)))) == 0) {
+ *(int *)addr = (int)getpid();
+ }
+ }
+ CL_DBG_PRINT("@@@@@ %s End: pid = %d\n", __func__, *(int *)addr);
+ }
+ return ret;
+}
+
+
+int CL_LockRelease(void *addr) {
+ int ret;
+ if ((addr == NULL) || (addr == MAP_FAILED)) {
+ ret = EINVAL;
+ } else {
+ CL_DBG_PRINT("@@@@@ %s : pid = %d\n", __func__, *(int *)addr);
+ *(int *)addr = (int)0;
+ ret = pthread_mutex_unlock((pthread_mutex_t*)((char *)addr + sizeof(int)));
+ }
+ return ret;
+}
+
+
+
diff --git a/nsframework/common_library/client/src/cl_monitor.c b/nsframework/common_library/client/src/cl_monitor.c
new file mode 100644
index 00000000..26d8e2e5
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_monitor.c
@@ -0,0 +1,442 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <semaphore.h>
+
+#include "cl_error.h"
+#include <native_service/cl_region.h>
+#include <native_service/cl_monitor.h>
+
+#define CL_MONITOR_SHM_NAME "/cl_monitor"
+
+#define CL_MONITOR_ID_REAL_GENERIC_START (0)
+#define CL_MONITOR_ID_REAL_GENERIC_END (1023)
+#define CL_MONITOR_ID_REAL_RPC_START (49952)
+#define CL_MONITOR_ID_REAL_RPC_END (59999)
+
+#define CL_MONITOR_ID_FLAT_GENERIC_START (0)
+#define CL_MONITOR_ID_FLAT_GENERIC_END \
+ (CL_MONITOR_ID_FLAT_GENERIC_START + (CL_MONITOR_ID_REAL_GENERIC_END - CL_MONITOR_ID_REAL_GENERIC_START))
+#define CL_MONITOR_ID_FLAT_RPC_START (CL_MONITOR_ID_FLAT_GENERIC_END + 1)
+#define CL_MONITOR_ID_FLAT_RPC_END \
+ (CL_MONITOR_ID_FLAT_RPC_START + (CL_MONITOR_ID_REAL_RPC_END - CL_MONITOR_ID_REAL_RPC_START))
+#define CL_MONITOR_ENTRY_NUM (CL_MONITOR_ID_FLAT_RPC_END + 1)
+
+#define CL_MONITOR_BITMAP_LENGTH ((CL_MONITOR_ENTRY_NUM + 63) / 64) // aligned
+
+#define CL_ALIGN(x, a) (((x) + (a - 1)) / (a) * (a))
+
+struct cl_monitor_header {
+ char signature[4];
+ uint64_t bitmap[CL_MONITOR_BITMAP_LENGTH];
+ sem_t sem;
+};
+
+#define CL_MONITOR_OBJECT_SIZE \
+ CL_ALIGN((sizeof(struct cl_monitor_header) + (sizeof(CL_MonitorEntry_t) * CL_MONITOR_ENTRY_NUM)), 4096)
+
+#define CL_MONITOR_SET_BIT(a, i) (a[i / 64] |= (1ULL << (i % 64)))
+#define CL_MONITOR_CLEAR_BIT(a, i) (a[i / 64] &= ~(1ULL << (i % 64)))
+
+static struct cl_monitor_header *cl_monitor_obj;
+static CL_MonitorEntry_t *cl_monitor_entry_head;
+
+int CL_MonitorInit(CL_MonitorInit_t init_type) {
+ int fd;
+ int oflag;
+ mode_t mode;
+
+ if (init_type != CL_MONITOR_INIT_SYSTEM && init_type != CL_MONITOR_INIT_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cl_monitor_obj != NULL) {
+ return 0;
+ }
+
+ if (init_type == CL_MONITOR_INIT_SYSTEM) {
+ oflag = O_RDWR | O_CREAT | O_EXCL;
+ mode = 0666;
+ } else {
+ oflag = O_RDWR;
+ mode = 0;
+ }
+
+ if ((fd = shm_open(CL_MONITOR_SHM_NAME, oflag, mode)) == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function shm_open
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function shm_open
+ }
+
+ if (init_type == CL_MONITOR_INIT_SYSTEM) {
+ if (ftruncate(fd, CL_MONITOR_OBJECT_SIZE) == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function ftruncate
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function ftruncate
+ }
+ } else {
+ struct stat st_buf;
+ if (fstat(fd, &st_buf) == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function fstat
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function fstat
+ }
+
+ if (st_buf.st_size != CL_MONITOR_OBJECT_SIZE) {
+ errno = EAGAIN;
+ return -1;
+ }
+ }
+
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function mmap
+ if ((cl_monitor_obj = mmap(NULL, CL_MONITOR_OBJECT_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ // LCOV_EXCL_BR_STOP
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function mmap
+ }
+
+ if (init_type == CL_MONITOR_INIT_SYSTEM) { // LCOV_EXCL_BR_LINE 11: out branch
+ memcpy(cl_monitor_obj->signature, "CLAM", 4);
+ memset(cl_monitor_obj->bitmap, 0, sizeof(cl_monitor_obj->bitmap));
+ sem_init(&cl_monitor_obj->sem, 1, 1);
+ }
+ cl_monitor_entry_head = (CL_MonitorEntry_t *)(((char *)cl_monitor_obj) + sizeof(struct cl_monitor_header));
+
+ return 0;
+}
+
+static inline int cl_monitor_check_type_id(CL_MonitorType_t type, uint32_t id, int *offset) {
+ if (type == CL_MONITOR_TYPE_GENERIC) {
+ if (id > CL_MONITOR_ID_REAL_GENERIC_END) {
+ errno = ENOENT;
+ return -1;
+ }
+ *offset = (int)((id - CL_MONITOR_ID_REAL_GENERIC_START) + CL_MONITOR_ID_FLAT_GENERIC_START);
+ } else if (type == CL_MONITOR_TYPE_RPC) {
+ if (id < CL_MONITOR_ID_REAL_RPC_START || id > CL_MONITOR_ID_REAL_RPC_END) {
+ errno = ENOENT;
+ return -1;
+ }
+ *offset = (int)((id - CL_MONITOR_ID_REAL_RPC_START) + CL_MONITOR_ID_FLAT_RPC_START);
+ } else {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int cl_monitor_sem_wait(sem_t *sem) {
+ int ret;
+
+retry:
+ ret = sem_wait(sem);
+ if (ret == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sem_wait
+ // LCOV_EXCL_START 5: fail safe for libc sem_wait
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ if (errno == EINTR) {
+ goto retry;
+ }
+ CL_PERROR("sem_wait");
+ }
+ // LCOV_EXCL_STOP
+
+ return ret;
+}
+
+static inline int cl_monitor_sem_post(sem_t *sem) {
+ int ret;
+
+ if ((ret = sem_post(sem)) == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sem_post
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("sem_post"); // LCOV_EXCL_LINE 5: fail safe for libc sem_post
+ }
+
+ return ret;
+}
+
+int CL_MonitorSetEntry(CL_MonitorType_t type, uint32_t id, CL_MonitorState_t state, uint32_t timeout,
+ uint32_t user_data) {
+ int offset;
+ CL_MonitorEntry_t *e;
+ struct timespec ts;
+
+ if (cl_monitor_obj == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (cl_monitor_check_type_id(type, id, &offset) == -1) {
+ return -1;
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { // LCOV_EXCL_BR_LINE 5: fail safe for libc clock_gettime
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for libc clock_gettime
+ }
+
+ e = cl_monitor_entry_head + offset;
+ cl_monitor_sem_wait(&cl_monitor_obj->sem);
+
+ if (state == CL_MONITOR_STATE_SLEEP) {
+ memset(e, 0, sizeof(CL_MonitorEntry_t));
+ CL_MONITOR_CLEAR_BIT(cl_monitor_obj->bitmap, offset);
+ } else {
+ e->pid = (uint16_t)getpid();
+ e->type = type;
+ e->state = state;
+
+// e->timeout = (uint32_t)ts.tv_sec + timeout;
+ e->timeout = ts.tv_sec + timeout;
+ e->id = id;
+ e->user_data = user_data;
+ CL_MONITOR_SET_BIT(cl_monitor_obj->bitmap, offset);
+ }
+
+ cl_monitor_sem_post(&cl_monitor_obj->sem);
+
+ return 0;
+}
+
+int CL_MonitorGetEntry(CL_MonitorType_t type, uint32_t id, CL_MonitorEntry_t *entry) {
+ int offset;
+ CL_MonitorEntry_t *e;
+
+ if (cl_monitor_obj == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (entry == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cl_monitor_check_type_id(type, id, &offset) == -1) {
+ return -1;
+ }
+
+ e = cl_monitor_entry_head + offset;
+ cl_monitor_sem_wait(&cl_monitor_obj->sem);
+
+ memcpy(entry, e, sizeof(CL_MonitorEntry_t));
+
+ cl_monitor_sem_post(&cl_monitor_obj->sem);
+
+ return 0;
+}
+
+int CL_MonitorSearchInit(CL_MonitorSearch_t *serch) {
+ if (serch == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ serch->entry_list = NULL;
+ serch->entry_num = 0;
+ return 0;
+}
+
+int CL_MonitorSearchDestroy(CL_MonitorSearch_t *serch) {
+ if (serch == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ free(serch->entry_list);
+ serch->entry_num = 0;
+ return 0;
+}
+
+static inline int cl_monitor_popcnt64(uint64_t x) {
+ uint64_t n;
+
+ n = (x >> 1) & 0x7777777777777777ULL;
+ x = x - n;
+ n = (n >> 1) & 0x7777777777777777ULL;
+ x = x - n;
+ n = (n >> 1) & 0x7777777777777777ULL;
+ x = x - n;
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+ x = x * 0x0101010101010101ULL;
+ return (int)(x >> 56);
+}
+
+typedef struct cl_monitor_offset_s cl_monitor_offset_t;
+struct cl_monitor_offset_s {
+ cl_monitor_offset_t *next;
+ int offset;
+};
+
+int CL_MonitorSearchTimeout(CL_MonitorSearch_t *search) {
+ int i;
+ int offset;
+ CL_MonitorEntry_t *e;
+ struct timespec ts;
+ int timeout_entry_num = 0;
+ cl_region_t *r;
+ cl_monitor_offset_t *o, *head = NULL, *tail = NULL;
+
+ if (cl_monitor_obj == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (search == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((r = CL_RegionCreate(CL_REGION_DEFAULT_SIZE)) == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ free(search->entry_list);
+ search->entry_list = NULL;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {// LCOV_EXCL_BR_LINE 5: fail safe for libc clock_gettime
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1;// LCOV_EXCL_LINE 5: fail safe for libc clock_gettime
+ }
+
+ cl_monitor_sem_wait(&cl_monitor_obj->sem);
+
+ for (i = 0; i < CL_MONITOR_BITMAP_LENGTH; i++) {
+ if (cl_monitor_obj->bitmap[i] != 0) {
+ uint64_t bits, mrb1; // most right bit 1
+
+ bits = cl_monitor_obj->bitmap[i];
+ while (bits) {
+ mrb1 = bits & (-bits);
+ offset = i * 64 + cl_monitor_popcnt64(mrb1 - 1);
+ e = cl_monitor_entry_head + offset;
+
+ if (e->timeout <= ts.tv_sec) {
+ timeout_entry_num++;
+ if ((o = CL_RegionAlloc(r, cl_monitor_offset_t, 1)) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for mmap
+ // LCOV_EXCL_START 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ errno = ENOMEM;
+ timeout_entry_num = -1;
+ goto exit;
+ // LCOV_EXCL_STOP
+ }
+
+ o->offset = offset;
+ o->next = NULL;
+
+ if (head == NULL) {
+ head = tail = o;
+ } else {
+ tail->next = o;
+ tail = o;
+ }
+ }
+ bits &= ~mrb1;
+ }
+ }
+ }
+
+ if (timeout_entry_num) {
+ CL_MonitorEntry_t *src, *dst;
+ dst = malloc(sizeof(CL_MonitorEntry_t) * (size_t)timeout_entry_num);
+ if (dst == NULL) { // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = ENOMEM; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ timeout_entry_num = -1; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ }
+
+ search->entry_list = dst;
+ o = head;
+ for (i = 0; i < timeout_entry_num; i++) {
+ src = cl_monitor_entry_head + o->offset;
+ memcpy(dst, src, sizeof(CL_MonitorEntry_t));
+
+ o = o->next;
+ dst++;
+ }
+ }
+
+exit:
+ cl_monitor_sem_post(&cl_monitor_obj->sem);
+
+ CL_RegionDestroy(r);
+ search->entry_num = (timeout_entry_num == -1) ? 0 : timeout_entry_num; // LCOV_EXCL_BR_LINE 11: out branch
+ return timeout_entry_num;
+}
+
+int cl_monitor_cleanup(int pid) {
+ int ret = 0;
+ int i;
+ int offset;
+ CL_MonitorEntry_t *e;
+
+ if (cl_monitor_obj == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (pid <= 0) { // LCOV_EXCL_LINE 5: fail safe for glibc function waitid
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = EINVAL;// LCOV_EXCL_LINE 5: fail safe for glibc function waitid
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function waitid
+ }
+
+ cl_monitor_sem_wait(&cl_monitor_obj->sem);
+
+ for (i = 0; i < CL_MONITOR_BITMAP_LENGTH; i++) {
+ if (cl_monitor_obj->bitmap[i] != 0) {
+ uint64_t bits, mrb1; // most right bit 1
+
+ bits = cl_monitor_obj->bitmap[i];
+ while (bits) {
+ mrb1 = bits & (-bits);
+ offset = i * 64 + cl_monitor_popcnt64(mrb1 - 1);
+
+ e = cl_monitor_entry_head + offset;
+ if (e->pid == pid) {
+ memset(e, 0, sizeof(CL_MonitorEntry_t));
+ CL_MONITOR_CLEAR_BIT(cl_monitor_obj->bitmap, offset);
+ ret++;
+ }
+
+ bits &= ~mrb1;
+ }
+ }
+ }
+
+ cl_monitor_sem_post(&cl_monitor_obj->sem);
+
+ return ret;
+}
diff --git a/nsframework/common_library/client/src/cl_process.c b/nsframework/common_library/client/src/cl_process.c
new file mode 100644
index 00000000..5c9f5a4b
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_process.c
@@ -0,0 +1,1198 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <semaphore.h>
+#include <pthread.h>
+#include <limits.h>
+#include <sys/prctl.h>
+#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <native_service/cl_process.h>
+#include "cl_process_internal.h"
+#include "cl_error.h"
+#include "cl_cgroup.h"
+#include "cl_monitor_internal.h"
+
+#define assert_static(e) \
+ do { \
+ enum { assert_static__ = 1/(e) }; \
+ } while (0)
+
+struct linux_dirent64 {
+ ino64_t d_ino;
+ off64_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[];
+};
+
+/*
+ * Initialize the process
+ */
+int CL_ProcessInit(void) {
+ int sfd = -1;
+ char *name;
+ sigset_t mask;
+
+ assert_static(sizeof(CL_ProcessAttr_t) == sizeof(CL_ProcessAttrInternal_t));
+
+ name = getenv(CL_PROCESS_NAME_ENV);
+ if (name != NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
+ if (prctl(PR_SET_NAME, name) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("prctl"); // LCOV_EXCL_LINE 5: fail safe for libc getenv
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc getenv
+ }
+ }
+
+ if (sigemptyset(&mask) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigemptyset
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("sigemptyset"); // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
+ }
+ if (sigaddset(&mask, SIGCHLD) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigaddset
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("sigaddset"); // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
+ }
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigprocmask
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("sigprocmask"); // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
+ }
+
+ if ((sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC)) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc signalfd
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ CL_PERROR("signalfd"); // LCOV_EXCL_LINE 5: fail safe for libc signalfd
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc signalfd
+ }
+
+exit:
+ return sfd;
+}
+
+/*
+ * start of the functions to be executed from fork to exec
+ */
+static void cl_process_pf_err(char no) {
+ char errorstr[17] = "err:post_fork:0\n";
+
+ errorstr[14] = no;
+ while (1) {
+ if (write(STDERR_FILENO, errorstr, 16) == -1 && errno == EINTR) { // LCOV_EXCL_BR_LINE 5: fail safe for libc write
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue; // LCOV_EXCL_LINE 5: fail safe for libc write
+ }
+ break;
+ }
+}
+
+static inline int cl_process_pf_set_schedule(const CL_ProcessAttrInternal_t *ia) {
+ int ret = -1;
+ struct sched_param param;
+ int policy;
+
+ switch (ia->sched_policy) {
+ case CL_PROCESS_SCHED_POLICY_RR:
+ policy = SCHED_RR;
+ param.sched_priority = ia->sched_priority;
+ break;
+ case CL_PROCESS_SCHED_POLICY_FIFO:
+ param.sched_priority = ia->sched_priority;
+ policy = SCHED_FIFO;
+ break;
+ default:
+ param.sched_priority = 0;
+ policy = SCHED_OTHER;
+ break;
+ }
+ if (sched_setscheduler(getpid(), policy, &param) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('3');// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
+ goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
+ }
+ if (ia->sched_policy == CL_PROCESS_SCHED_POLICY_OTHER) {
+ if (setpriority(PRIO_PROCESS, (__id_t)getpid(), ia->sched_priority) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpriority
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ cl_process_pf_err('4');// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
+ goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
+ }
+ }
+ ret = 0;
+
+exit:
+ return ret;
+}
+
+static inline int cl_process_pf_check_close_fd(int check_fd, int dirfd, int hold_fds_num, const int *hold_fds) {
+ int i;
+
+ if (check_fd < 3 || check_fd == dirfd) {
+ return 0;
+ }
+
+ for (i = 0; i < hold_fds_num; i++) {
+ if (check_fd == *(hold_fds + i)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static inline int cl_process_pf_fname2fd(const char *s) {
+ int result = 0;
+ for (; *s != '\0'; s++) {
+ result = result * 10 + (*s - '0');
+ }
+ return result;
+}
+
+static inline int cl_process_pf_cleanup_fds(const CL_ProcessAttrInternal_t *ia) {
+ int ret = -1;
+ int dfd;
+#define BUF_SIZE 128
+ char buf[BUF_SIZE];
+ struct linux_dirent64 *d;
+ int hold_fds_num, i;
+
+ for (i = 0; i < CL_PROCESSS_ATTR_HOLD_FDS_NUM; i++) {
+ if (ia->hold_fds[i] == 0) {
+ break;
+ }
+ }
+ hold_fds_num = i;
+
+ if ((dfd = open("/proc/self/fd/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function open
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ cl_process_pf_err('8');// LCOV_EXCL_LINE 5: fail safe for glibc function open
+ goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function open
+ }
+
+ while (1) {
+ long nread;
+ int fd;
+ int bpos;
+
+ nread = syscall(SYS_getdents64, dfd, buf, sizeof(buf));
+ if (nread == -1) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
+ // LCOV_EXCL_START 5: fail safe for glibc function syscall
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ cl_process_pf_err('9');
+ close(dfd);
+ goto exit;
+ }
+ // LCOV_EXCL_STOP
+
+ if (nread == 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
+ break;
+ }
+
+ for (bpos = 0; bpos < nread;) {
+ d = (struct linux_dirent64 *)(buf + bpos);
+ fd = cl_process_pf_fname2fd(d->d_name);
+ if (cl_process_pf_check_close_fd(fd, dfd, hold_fds_num, ia->hold_fds)) {
+ close(fd);
+ }
+ bpos += d->d_reclen;
+ }
+ }
+ close(dfd);
+ ret = 0;
+
+exit:
+ return ret;
+}
+
+static void cl_process_post_fork(const char *file, char *const argv[], char *const envp[],
+ const CL_ProcessAttrInternal_t *ia) {
+ int intfy_fd;
+ char intfy_fname[32] = "/tmp/intfy_00000";
+ pid_t pid = getpid();
+
+ intfy_fname[11] = (char)(intfy_fname[11] + (pid / 10000));
+ intfy_fname[12] = (char)(intfy_fname[12] + ((pid / 1000) % 10));
+ intfy_fname[13] = (char)(intfy_fname[13] + ((pid / 100) % 10));
+ intfy_fname[14] = (char)(intfy_fname[14] + ((pid / 10) % 10));
+ intfy_fname[15] = (char)(intfy_fname[15] + (pid % 10));
+
+ unlink(intfy_fname);
+ 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
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('0'); // LCOV_EXCL_LINE 5:libc fail safe for open
+ goto exit; // LCOV_EXCL_LINE 5:libc fail safe for open
+ }
+ if (close(intfy_fd) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function close
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('1'); // LCOV_EXCL_LINE 5:libc fail safe for close
+ goto exit; // LCOV_EXCL_LINE 5:libc fail safe for close
+ }
+
+ // Process group
+ if (ia->create_group) {
+ if (setpgid(getpid(), getpid()) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpgid
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('2'); // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
+ }
+ }
+
+ // Scheduling Policy/Priority
+ if (cl_process_pf_set_schedule(ia) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
+ }
+
+ // UID/GID
+ if (ia->gid) {
+ if (setgid(ia->gid) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setgid
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('5'); // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
+ }
+ }
+
+ if (ia->uid) {
+ uid_t uid = (ia->uid == UINT_MAX) ? 0 : ia->uid;
+ if (setuid(uid) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setuid
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('6');// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
+ goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
+ }
+ }
+
+ // stack size
+ if (ia->stack_size) {
+ struct rlimit rlim;
+ getrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = (rlim_t)ia->stack_size;
+ if (setrlimit(RLIMIT_STACK, &rlim) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setrlimit
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ cl_process_pf_err('7');// LCOV_EXCL_LINE 5: fail safe for glibc function setrlimit
+ }
+ }
+
+ // cleanup fds
+ if (ia->disable_close_fds == 0) {
+ if (cl_process_pf_cleanup_fds(ia) < 0) {
+ goto exit;
+ }
+ }
+
+ // exec
+ if (execve(file, argv, envp) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function execve
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ cl_process_pf_err('A');// LCOV_EXCL_LINE 5: fail safe for glibc function execve
+ }
+
+exit:
+ return;
+}
+/*
+ * end of the functions to be executed from fork to exec
+ */
+
+static int cl_process_pre_fork(char *const envp[], char ***new_env, const CL_ProcessAttrInternal_t *ia) {
+ int i;
+ size_t envlen = 0;
+ char **e;
+ char *b;
+ int new_env_count;
+ size_t name_env_len = strlen(CL_PROCESS_NAME_ENV);
+ int last_name_env_pos = -1;
+
+ if (envp == NULL) {
+ e = environ;
+ } else {
+ e = (char **)envp;
+ }
+
+ for (i = 0; e[i] != NULL; i++) {
+ if (strncmp(e[i], CL_PROCESS_NAME_ENV, name_env_len) == 0) {
+ last_name_env_pos = i;
+ } else {
+ envlen += strlen(e[i]) + 1;
+ }
+ }
+
+ if (ia->name[0] != 0) {
+ envlen += strlen(CL_PROCESS_NAME_ENV) + 1 + strlen(ia->name) + 1;
+ i++;
+ }
+
+ if ((b = malloc(envlen)) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_ERR_PRINT("malloc fail"); // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ errno = EFAULT; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ goto error; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ }
+ memset(b, 0, envlen);
+
+ if ((*new_env = malloc(sizeof(char *) * (size_t)(i + 1))) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ free(b); // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ CL_ERR_PRINT("malloc fail"); // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ errno = EFAULT; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ goto error; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ }
+ memset(*new_env, 0, sizeof(char *) * (size_t)(i + 1));
+
+ new_env_count = 0;
+ for (i = 0; e[i] != NULL; i++) {
+ if (i == last_name_env_pos) {
+ continue;
+ }
+ strcpy(b, e[i]);
+ *(*new_env + i) = b;
+ b += strlen(e[i]) + 1;
+ new_env_count++;
+ }
+
+ if (ia->name[0] != 0) {
+ *(*new_env + new_env_count) = b;
+ b += sprintf(b, "%s=%s", CL_PROCESS_NAME_ENV, ia->name);
+ b++;
+ new_env_count++;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/*
+ * Create process
+ */
+int CL_ProcessCreate(const char *file, char *const argv[], char *const envp[], const CL_ProcessAttr_t *attr) {
+ const CL_ProcessAttrInternal_t *ia = (const CL_ProcessAttrInternal_t *)attr;
+ pid_t childpid;
+ char intfy_fname[32];
+ char **new_env;
+ int ret;
+ int retry;
+ int i = 0;
+
+ if (file == NULL || argv == NULL || attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cl_process_pre_fork(envp, &new_env, ia) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc function malloc
+ return -1;
+ }
+
+ childpid = fork();
+ switch (childpid) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function fork
+ case 0: /* child process */
+ cl_process_post_fork(file, argv, new_env, ia);
+ _exit(CL_PROCESS_EXIT_INTERNAL);
+ break;
+
+ case -1: /* error */
+ goto exit;
+
+ default: /* parent process */
+ break;
+ }
+
+ if (ia->cpu_assign != 0) {
+ cpu_set_t set;
+ CPU_ZERO(&set);
+ for (i = 0; i < (sizeof(ia->cpu_assign) * 8); i++) {
+ if ((ia->cpu_assign >> i) & 0x1) {
+ CPU_SET(i, &set);
+ }
+ }
+ // LCOV_EXCL_BR_START 5: fail safe for libc sched_setaffinity
+ if (sched_setaffinity(childpid, sizeof(set), &set) < 0) {
+ // LCOV_EXCL_BR_STOP
+ int last_errno = errno;
+ CL_PERROR("sched_setaffinity");
+ errno = last_errno;
+ childpid = -1;
+ goto exit;
+ }
+ }
+
+ ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, childpid);
+ if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for libc snprintf
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_ERR_PRINT("snprintf fail:%d", ret); // LCOV_EXCL_LINE 5: fail safe for libc snprintf
+ childpid = -1; // LCOV_EXCL_LINE 5: fail safe for libc snprintf
+ goto exit; // LCOV_EXCL_LINE 5: fail safe for libc snprintf
+ }
+
+ if (ia->cgroup_name[0] != '\0') {
+ if (cl_cgroup_exist(CL_CGROUP_CPU, ia->cgroup_name) == 0) {
+ if (cl_cgroup_set_num(CL_CGROUP_CPU, ia->cgroup_name, "tasks", childpid) < 0) {
+ int last_errno = errno;
+ CL_PERROR("cl_cgroup_set_num");
+ errno = last_errno;
+ childpid = -1;
+ goto exit;
+ }
+ }
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function access
+ if (cl_cgroup_exist(CL_CGROUP_MEMORY, ia->cgroup_name) == 0) {
+ // LCOV_EXCL_BR_STOP
+ if (cl_cgroup_set_num(CL_CGROUP_MEMORY, ia->cgroup_name, "tasks", childpid) < 0) {
+ int last_errno = errno;
+ CL_PERROR("cl_cgroup_set_num");
+ errno = last_errno;
+ childpid = -1;
+ goto exit;
+ }
+ }
+ }
+
+ for (retry = 100; retry >= 0; retry--) {
+ if (access(intfy_fname, F_OK) == 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
+ break;
+ }
+ usleep(100);
+ }
+
+exit:
+ free(new_env[0]);
+ free(new_env);
+
+ return childpid;
+}
+
+/*
+ * Initialize process attribute
+ */
+int CL_ProcessCreateAttrInit(CL_ProcessAttr_t *attr) {
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(attr, 0, sizeof(CL_ProcessAttr_t));
+ return 0;
+}
+
+/*
+ * Set process attribute (process name)
+ */
+int CL_ProcessCreateAttrSetName(CL_ProcessAttr_t *attr, const char *name) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL || name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strncpy(ia->name, name, 16);
+ ia->name[15] = 0;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (user ID)
+ */
+int CL_ProcessCreateAttrSetUid(CL_ProcessAttr_t *attr, uid_t uid) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->uid = uid;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (group ID)
+ */
+int CL_ProcessCreateAttrSetGid(CL_ProcessAttr_t *attr, gid_t gid) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->gid = gid;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (schedule policy and priority)
+ */
+int CL_ProcessCreateAttrSetSchedule(CL_ProcessAttr_t *attr, CL_ProcessSchedPolicy_t policy, int priority) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (policy == CL_PROCESS_SCHED_POLICY_RR || policy == CL_PROCESS_SCHED_POLICY_FIFO) {
+ if (priority < 1 || priority > 99) {
+ errno = EINVAL;
+ return -1;
+ }
+ } else if (policy == CL_PROCESS_SCHED_POLICY_OTHER) {
+ if (priority < -20 || priority > 19) {
+ CL_ERR_PRINT("Invlid SCHED_OTHER priority:%d", priority);
+ }
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->sched_policy = policy;
+ ia->sched_priority = priority;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (process group)
+ */
+int CL_ProcessCreateAttrSetGroup(CL_ProcessAttr_t *attr, int create) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (create < 0 || create > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->create_group = create;
+
+ return 0;
+}
+
+static int32_t CL_CpuAssignMsbCpu(int cpu_assign) {
+ int32_t i;
+ int32_t ret = 0;
+
+ for (i = 0; i < (sizeof(cpu_assign) * 8); i++) {
+ if ((cpu_assign >> i) & 0x1)
+ ret = i;
+ }
+
+ return ret;
+}
+
+/**
+ * Set process attribute (CPU Assign)
+ */
+int CL_ProcessCreateAttrSetCpuAssign(CL_ProcessAttr_t *attr, int cpu_assign) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cpu_assign < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (CL_CpuAssignMsbCpu(cpu_assign) >= sysconf(_SC_NPROCESSORS_CONF)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->cpu_assign = cpu_assign;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (Stack Size)
+ */
+int CL_ProcessCreateAttrSetStackSize(CL_ProcessAttr_t *attr, int stack_size) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->stack_size = stack_size;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (FD to maintain)
+ */
+int CL_ProcessCreateAttrSetHoldFds(CL_ProcessAttr_t *attr, int hold_fds[]) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL || hold_fds == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memcpy(ia->hold_fds, hold_fds, sizeof(ia->hold_fds));
+
+ return 0;
+}
+
+/*
+ * Set process attribute (to suspend forced FD close)
+ */
+int CL_ProcessCreateAttrSetDisableCloseFds(CL_ProcessAttr_t *attr) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->disable_close_fds = 1;
+
+ return 0;
+}
+
+/*
+ * Set process attribute (Cgroup)
+ */
+int CL_ProcessCreateAttrSetCgroup(CL_ProcessAttr_t *attr, const char *cgroup_name) {
+ CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
+
+ if (attr == NULL || cgroup_name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strlen(cgroup_name) >= sizeof(ia->cgroup_name)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strcpy(ia->cgroup_name, cgroup_name);
+
+ return 0;
+}
+
+/*
+ * Kill process
+ */
+int CL_ProcessTerminate(pid_t pid) {
+ return kill(pid, SIGKILL);
+}
+
+/*
+ * Kill process group
+ */
+int CL_ProcessTerminateGroup(pid_t pid) {
+ return killpg(pid, SIGKILL);
+}
+
+/**
+ * Forced process termination
+ */
+int CL_ProcessAbort(pid_t pid) {
+ return kill(pid, SIGABRT);
+}
+
+/**
+ * Forced process group termination
+ */
+int CL_ProcessAbortGroup(pid_t pid) {
+ return killpg(pid, SIGABRT);
+}
+
+/**
+ * Euthanize process group
+ */
+int CL_ProcessEuthanizeGroup(pid_t pid) {
+ usleep(10 * 1000);
+ return killpg(pid, SIGKILL);
+}
+
+/*
+ * Collect child process
+ */
+int CL_ProcessCleanup(int sigchld_fd, CL_ProcessCleanupInfo_t *cleanup_info) {
+ struct signalfd_siginfo fdsi;
+ ssize_t s;
+ siginfo_t info;
+ int ret;
+ char intfy_fname[32];
+
+ if (cleanup_info == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (1) {
+ s = read(sigchld_fd, &fdsi, sizeof(struct signalfd_siginfo));
+ if (s != sizeof(struct signalfd_siginfo)) {
+ if (s == -1 && errno == EINTR) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ info.si_pid = 0;
+ while (1) {
+ ret = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
+ if (ret == -1) {
+ return -1;
+ } else if (ret == 0 && info.si_pid == 0) {
+ errno = ECHILD;
+ return -1;
+ }
+ break;
+ }
+
+ cleanup_info->pid = info.si_pid;
+ cleanup_info->code = info.si_code;
+ cleanup_info->status = info.si_status;
+
+ cl_monitor_cleanup(info.si_pid);
+
+ ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, info.si_pid);
+
+ if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function snprintf
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_ERR_PRINT("snprintf fail:%d\n", ret);// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
+ goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
+ }
+ if (unlink(intfy_fname) < 0) {
+ CL_PERROR("unlink");
+ }
+
+exit:
+ info.si_pid = 0;
+ ret = waitid(P_ALL, 0, &info, WEXITED | WNOWAIT | WNOHANG);
+ if (ret == 0 && info.si_pid != 0) {
+ return 1;
+ } else if (ret == -1 && errno != ECHILD) {
+ return -1;
+ }
+ return 0;
+}
+
+typedef struct {
+ sem_t sem;
+ CL_ThreadAttrInternal_t *ia;
+ void *(*start_routine)(void *);
+ void *start_arg;
+} create_thread_arg_t;
+
+static void *thread_start_func(void *arg) {
+ create_thread_arg_t *p = (create_thread_arg_t *)arg;
+ void *(*start_routine)(void *) = p->start_routine;
+ void *start_arg = p->start_arg;
+
+ prctl(PR_SET_NAME, p->ia->name != 0 ? p->ia->name : NULL);
+
+ if (sem_post(&p->sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_post
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_PERROR("sem_post"); // LCOV_EXCL_LINE 5: fail safe for libc sem_post
+ }
+
+ return (*start_routine)(start_arg);
+}
+
+/*
+ * Create thread
+ */
+int CL_ThreadCreate(pthread_t *thread, pthread_attr_t *attr, CL_ThreadAttr_t *cl_attr, void *(*start_routine)(void *),
+ void *arg) {
+ int ret;
+ create_thread_arg_t cr_arg = { .ia = (CL_ThreadAttrInternal_t *)cl_attr,
+ .start_routine = start_routine,
+ .start_arg = arg
+ };
+
+ if (thread == NULL || cl_attr == NULL || start_routine == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sem_init(&cr_arg.sem, 0, 0) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sem_init
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for libc sem_init
+ }
+
+ // LCOV_EXCL_BR_START 5: fail safe for libc pthread_create
+ if ((ret = pthread_create(thread, attr, thread_start_func, &cr_arg)) != 0) {
+ // LCOV_EXCL_BR_STOP
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ errno = ret; // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
+ return -1; // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
+ }
+
+ if (sem_wait(&cr_arg.sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_wait
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1; // LCOV_EXCL_LINE 5: fail safe for libc sem_wait
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize CommonLibrary extension thread attribute
+ */
+int CL_ThreadCreateAttrInit(CL_ThreadAttr_t *attr) {
+ assert_static(sizeof(CL_ThreadAttr_t) == sizeof(CL_ThreadAttrInternal_t));
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(attr, 0, sizeof(CL_ThreadAttr_t));
+ return 0;
+}
+
+/*
+ * Set CommonLibrary extension thread attribute (thread name)
+ */
+int CL_ThreadCreateAttrSetName(CL_ThreadAttr_t *attr, const char *name) {
+ CL_ThreadAttrInternal_t *ia = (CL_ThreadAttrInternal_t *)attr;
+
+ if (attr == NULL || name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strncpy(ia->name, name, 16);
+ ia->name[15] = 0;
+
+ return 0;
+}
+
+/*
+ * Create Cgroup
+ */
+int CL_ProcessCreateCgroupCreate(const char *cgroup_name, CL_ProcessCreateCgroupAttr_t *attr) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+ CL_ProcessCreateCgroupAttrInternal_t cmp;
+
+ if (cgroup_name == NULL || attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(&cmp, 0, sizeof(CL_ProcessCreateCgroupAttrInternal_t));
+ if (memcmp(ia, &cmp, sizeof(CL_ProcessCreateCgroupAttrInternal_t)) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ia->rt_runtime_us || ia->cfs_quota_us || ia->cpu_shares) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
+ if (cl_cgroup_make(CL_CGROUP_CPU, cgroup_name) < 0) {
+ // LCOV_EXCL_BR_STOP
+ return -1;
+ }
+
+ if (ia->rt_runtime_us) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function write
+ if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.rt_runtime_us", ia->rt_runtime_us) < 0) {
+ // LCOV_EXCL_BR_STOP
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
+ }
+ }
+
+ if (ia->cfs_quota_us) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function write
+ if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.cfs_quota_us", ia->cfs_quota_us) < 0) {
+ // LCOV_EXCL_BR_STOP
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
+ }
+ }
+
+ if (ia->cpu_shares) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function write
+ if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.shares", ia->cpu_shares) < 0) {
+ // LCOV_EXCL_BR_STOP
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
+ }
+ }
+ }
+
+ if (ia->memory_limit || ia->usage_in_bytes || ia->event_fd) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
+ if (cl_cgroup_make(CL_CGROUP_MEMORY, cgroup_name) < 0) {
+ // LCOV_EXCL_BR_STOP
+ return -1;
+ }
+
+ if (ia->memory_limit) {
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function write
+ if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.limit_in_bytes", ia->memory_limit) < 0) {
+ // LCOV_EXCL_BR_STOP
+ return -1;
+ }
+
+ if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.limit_in_bytes", ia->memory_limit) < 0) {
+ return -1;
+ }
+
+ }
+
+ if (ia->usage_in_bytes || ia->event_fd) {
+ int checkfd;
+ char setstr[64];
+
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function open
+ if ( (checkfd = cl_cgroup_open(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.usage_in_bytes", O_RDONLY)) < 0) {
+ // LCOV_EXCL_BR_STOP
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return -1; // LCOV_EXCL_LINE 5: fail safe for glibc function open
+ }
+
+ snprintf(setstr, sizeof(setstr), "%d %d %d", ia->event_fd, checkfd, ia->usage_in_bytes);
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function write
+ if (cl_cgroup_set_string(CL_CGROUP_MEMORY, cgroup_name, "cgroup.event_control", setstr) < 0) {
+ // LCOV_EXCL_BR_STOP
+
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+
+ return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize Cgroup attribute
+ */
+int CL_ProcessCreateCgroupAttrInit(CL_ProcessCreateCgroupAttr_t *attr) {
+ assert_static(sizeof(CL_ProcessCreateCgroupAttr_t) == sizeof(CL_ProcessCreateCgroupAttrInternal_t));
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(attr, 0, sizeof(CL_ProcessCreateCgroupAttr_t));
+ return 0;
+}
+
+/*
+ * Set Cgroup attribute (RT Throttling)
+ */
+int CL_ProcessCreateCgroupAttrSetRtThrottling(CL_ProcessCreateCgroupAttr_t *attr, int runtime_us) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->rt_runtime_us = runtime_us;
+
+ return 0;
+}
+
+/*
+ * Set Cgroup attribute (CFS Bandwidth Control)
+ */
+int CL_ProcessCreateCgroupAttrSetCfsBandwidthControl(CL_ProcessCreateCgroupAttr_t *attr, int cfs_quota_us) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->cfs_quota_us = cfs_quota_us;
+
+ return 0;
+}
+
+/*
+ * Set Cgroup attribute (CPU Shares)
+ */
+int CL_ProcessCreateCgroupAttrSetCpuShares(CL_ProcessCreateCgroupAttr_t *attr, int cpu_shares) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->cpu_shares = cpu_shares;
+
+ return 0;
+}
+
+/*
+ * Set Cgroup attribute (Memory Limit)
+ */
+int CL_ProcessCreateCgroupAttrSetMemoryLimit(CL_ProcessCreateCgroupAttr_t *attr, int memory_limit) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->memory_limit = memory_limit;
+
+ return 0;
+}
+
+/*
+ * Set Cgroup attribute (Memory Usage Notification)
+ */
+int CL_ProcessCreateCgroupAttrSetMemoryUsageNotification(CL_ProcessCreateCgroupAttr_t *attr, int usage_in_bytes,
+ int event_fd) {
+ CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
+
+ if (attr == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (event_fd < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ia->usage_in_bytes = usage_in_bytes;
+ ia->event_fd = event_fd;
+
+ return 0;
+}
+
+/*
+ * Delete Cgroup
+ */
+int CL_ProcessCreateCgroupDelete(const char *cgroup_name) {
+ int mem_ret = 1, mem_err;
+ int cpu_ret = 1, cpu_err;
+
+ if (cgroup_name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function access
+ if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {
+ // LCOV_EXCL_BR_STOP
+ mem_ret = cl_cgroup_remove(CL_CGROUP_MEMORY, cgroup_name);
+ mem_err = errno;
+ }
+
+ // LCOV_EXCL_BR_START 5: fail safe for glibc function access
+ if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {
+ // LCOV_EXCL_BR_STOP
+ cpu_ret = cl_cgroup_remove(CL_CGROUP_CPU, cgroup_name);
+ cpu_err = errno;
+ }
+
+ if (mem_ret == 1 && cpu_ret == 1) {
+ errno = ENOENT;
+ return -1;
+ } else if (mem_ret < 0) {
+ errno = mem_err;
+ return -1;
+ } else if (cpu_ret < 0) {
+ errno = cpu_err;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Move process to the Cgroup
+ */
+int CL_ProcessCreateCgroupClassify(const char *cgroup_name, pid_t pid) {
+ int mem_ret = 1, mem_err;
+ int cpu_ret = 1, cpu_err;
+
+ if (cgroup_name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
+ mem_ret = cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "tasks", pid);
+ mem_err = errno;
+ }
+
+ if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
+ cpu_ret = cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "tasks", pid);
+ cpu_err = errno;
+ }
+
+ if (mem_ret == 1 && cpu_ret == 1) {
+ errno = ENOENT;
+ return -1;
+ } else if (mem_ret < 0) {
+ errno = mem_err;
+ return -1;
+ } else if (cpu_ret < 0) {
+ errno = cpu_err;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* vim:set ts=8 sts=2 sw=2: */
diff --git a/nsframework/common_library/client/src/cl_region.c b/nsframework/common_library/client/src/cl_region.c
new file mode 100644
index 00000000..0f6d470c
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_region.c
@@ -0,0 +1,295 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file cl_region.c
+ * @brief region manage
+ *
+ */
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <native_service/cl_region.h>
+#include "cl_error.h"
+
+#define cl_align_ptr(p, a) \
+ (uint8_t *) (((long)(p) + ((long)a - 1)) & ~((long)a - 1))
+
+static void *cl_region_anonmmap(size_t size);
+static void *cl_region_expand(cl_region_t *region, size_t size, size_t align_size);
+static void *cl_region_alloc_large(cl_region_t *region, size_t size);
+
+cl_region_t *
+CL_RegionCreate(size_t size) {
+ cl_region_t *r;
+ long pagesize;
+
+ pagesize = sysconf(_SC_PAGE_SIZE);
+ size = ((size + (size_t)pagesize - 1) / (size_t)pagesize) * (size_t)pagesize;
+
+ r = cl_region_anonmmap(size);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ r->d.last = (uint8_t *) r + sizeof(cl_region_t);
+ r->d.end = (uint8_t *) r + size;
+ r->d.next = NULL;
+ r->d.failed = 0;
+
+ size = size - sizeof(cl_region_t);
+ r->max = (size < (pagesize - 1)) ? size : (size_t)(pagesize - 1);
+
+ r->current = r;
+ r->large = NULL;
+ r->cleanup = NULL;
+
+ return r;
+}
+
+
+void
+CL_RegionDestroy(cl_region_t *region) {
+ cl_region_t *r, *n;
+ cl_region_large_t *l;
+ cl_region_cleanup_t *c;
+
+ for (c = region->cleanup; c; c = c->next) {
+ if (c->handler) {
+ CL_DBG_PRINT("run cleanup: %p\n", c->handler);
+ c->handler(c->data);
+ }
+ }
+
+ for (l = region->large; l; l = l->next) {
+
+ CL_DBG_PRINT("free: %p\n", l->alloc);
+
+ if (l->alloc) { // LCOV_EXCL_BR_LINE 6: double check, mmap in cl_monitor.c
+ if (munmap(l->alloc, l->size) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_PERROR("munmap"); // LCOV_EXCL_LINE 5: fail safe for libc munmap
+ }
+ }
+ }
+
+ for (r = region, n = region->d.next; /* void */; r = n, n = n->d.next) {
+ if (munmap(r, (size_t)(r->d.end - (uint8_t *)r)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_PERROR("munmap"); // LCOV_EXCL_LINE 5: fail safe for libc munmap
+ }
+
+ if (n == NULL) {
+ break;
+ }
+ }
+}
+
+
+void *
+cl_region_alloc(cl_region_t *region, size_t size, size_t align_size) {
+ uint8_t *m;
+ volatile uint8_t *old_last;
+ cl_region_t *r;
+
+ if (size <= region->max) {
+
+ r = region->current;
+
+ do {
+ retry:
+ old_last = r->d.last;
+ m = cl_align_ptr(old_last, align_size);
+ if ((size_t)(r->d.end - m) >= size) {
+ if (false == __sync_bool_compare_and_swap(&r->d.last, old_last, m + size)) {
+ goto retry;
+ }
+ return m;
+ }
+
+ r = r->d.next;
+
+ } while (r);
+
+ return cl_region_expand(region, size, align_size);
+ }
+
+ return cl_region_alloc_large(region, size);
+}
+
+
+static void *
+cl_region_anonmmap(size_t size) {
+ uint8_t *p;
+
+ p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) { /* pgr0203 */
+ CL_PERROR("mmap");
+ return NULL;
+ }
+
+ return p;
+}
+
+
+static void *
+cl_region_expand(cl_region_t *region, size_t size, size_t align_size) {
+ uint8_t *m;
+ size_t psize;
+ cl_region_t *r, *new, *current;
+
+ psize = (size_t)(region->d.end - (uint8_t *)region);
+
+ m = cl_region_anonmmap(psize);
+ if (m == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL;// LCOV_EXCL_LINE 5: fail safe for libc mmap
+ }
+
+ new = (cl_region_t *)m;
+
+ new->d.end = m + psize;
+ new->d.next = NULL;
+ new->d.failed = 0;
+
+ m += sizeof(cl_region_data_t);
+ m = cl_align_ptr(m, align_size);
+ new->d.last = m + size;
+
+ current = region->current;
+
+ for (r = current; r->d.next; r = r->d.next) { /* pgr0689 */
+ if (r->d.failed++ > 4) {
+ current = r->d.next;
+ }
+ }
+
+ while (false == __sync_bool_compare_and_swap(&r->d.next, NULL, new)) {
+ for (r = r->d.next; r->d.next; r = r->d.next) {} /* pgr0689 */
+ }
+
+ region->current = current ? current : new;
+
+ return m;
+}
+
+
+static void *
+cl_region_alloc_large(cl_region_t *region, size_t size) {
+ void *p;
+ int n;
+ long pagesize;
+ cl_region_large_t *large;
+
+ pagesize = sysconf(_SC_PAGE_SIZE);
+ size = ((size + (size_t)pagesize - 1) / (size_t)pagesize) * (size_t)pagesize;
+
+ p = cl_region_anonmmap(size);
+
+ if (p == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL;// LCOV_EXCL_LINE 5: fail safe for libc mmap
+ }
+
+ n = 0;
+
+ for (large = region->large; large; large = large->next) {
+ if (large->alloc == NULL) {
+ if (false == __sync_bool_compare_and_swap(&large->alloc, NULL, p)) {
+ break;
+ }
+ large->size = size;
+ return p;
+ }
+
+ if (n++ > 3) {
+ break;
+ }
+ }
+
+ large = CL_RegionAlloc(region, cl_region_large_t, 1);
+ if (large == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ if (munmap(p, size) < 0) {
+ CL_PERROR("munmap");
+ }
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ large->alloc = p;
+ large->size = size;
+ large->next = region->large;
+ while (false == __sync_bool_compare_and_swap(&region->large, large->next, large)) { // LCOV_EXCL_BR_LINE 100: race condition // NOLINT (readability/nolint)
+ // LCOV_EXCL_START 100: race condition
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ large->next = region->large;
+ } // LCOV_EXCL_STOP
+
+ return p;
+}
+
+
+bool
+CL_RegionFree(cl_region_t *region, void *p) {
+ cl_region_large_t *l;
+
+ for (l = region->large; l; l = l->next) {
+ if (p == l->alloc) {
+ CL_DBG_PRINT("free: %p\n", l->alloc);
+ if (munmap(l->alloc, l->size) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ CL_PERROR("munmap");// LCOV_EXCL_LINE 5: fail safe for libc munmap
+ }
+ l->alloc = NULL;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+cl_region_cleanup_t *
+cl_region_cleanup_add(cl_region_t *region, size_t size, size_t align_size) {
+ cl_region_cleanup_t *c;
+
+ c = CL_RegionAlloc(region, cl_region_cleanup_t, 1);
+ if (c == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ if (size) {
+ c->data = cl_region_alloc(region, size, align_size);
+ if (c->data == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL;
+ } // LCOV_EXCL_STOP
+ } else {
+ c->data = NULL;
+ }
+
+ c->handler = NULL;
+ c->next = region->cleanup;
+
+ region->cleanup = c;
+
+ CL_DBG_PRINT("add cleanup: %p\n", c);
+
+ return c;
+}
+
+/* vim:set ts=8 sw=2 sts=2: */
diff --git a/nsframework/common_library/client/src/cl_sem.c b/nsframework/common_library/client/src/cl_sem.c
new file mode 100644
index 00000000..911daff4
--- /dev/null
+++ b/nsframework/common_library/client/src/cl_sem.c
@@ -0,0 +1,67 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <time.h>
+
+#include <native_service/cl_sem.h>
+#include "cl_error.h"
+
+#define CL_MILLI_TO_NANO(time) ((time) * 1000000U)
+#define CL_SEC_TO_NANO(time) ((time) * 1000000000U)
+#define CL_NANO_TO_SEC(time) ((time) / 1000000000U)
+
+static void cl_TimeoutCalc(struct timespec *ts, unsigned int timeout) {
+ unsigned long long nsec;
+
+ clock_gettime(CLOCK_REALTIME, ts);
+ nsec = (unsigned long long)ts->tv_nsec + (CL_MILLI_TO_NANO((unsigned long long)timeout));
+ ts->tv_sec = ts->tv_sec + (time_t)CL_NANO_TO_SEC(nsec);
+ ts->tv_nsec = (__syscall_slong_t)(nsec - CL_SEC_TO_NANO((unsigned long long)CL_NANO_TO_SEC(nsec)));
+}
+
+int CL_SemWait(sem_t *semid, unsigned int timeout) {
+ struct timespec ts, tmp;
+ int ret;
+
+ while (1) {
+ cl_TimeoutCalc(&ts, timeout);
+ if ((ret = sem_timedwait(semid, &ts)) != 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc
+ // LCOV_EXCL_START 5: fail safe for libc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ if (errno == ETIMEDOUT) {
+ /* Check the time considering the case where the time has been changed by clock_settime/settimeofday */
+ /* If the current time is much larger than the timeout specified time,
+ the system assumes that the time has changed and re-executes the command.
+ (A threshold of 100 is appropriate) */
+ clock_gettime(CLOCK_REALTIME, &tmp);
+ if (difftime(tmp.tv_sec, ts.tv_sec) > 100.0) {
+ CL_DBG_PRINT("detect clock changed\n");
+ continue;
+ }
+ }
+ }
+ // LCOV_EXCL_STOP 5: fail safe for libc
+ break;
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ } // LCOV_EXCL_LINE 10: end line
+
+ return ret;
+}
+