diff options
author | ToshikazuOhiwa <toshikazu_ohiwa@mail.toyota.co.jp> | 2020-03-30 09:32:17 +0900 |
---|---|---|
committer | ToshikazuOhiwa <toshikazu_ohiwa@mail.toyota.co.jp> | 2020-03-30 09:32:17 +0900 |
commit | b7e715753434f3a5ae242b751dd7077448579058 (patch) | |
tree | 7d5971d6e96a6a0610386b11643792c6c76d9b1d | |
parent | 706ad73eb02caf8532deaf5d38995bd258725cb8 (diff) |
ns-commonlibrary branch
23 files changed, 5330 insertions, 0 deletions
diff --git a/common_library/LICENSE b/common_library/LICENSE new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/common_library/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/common_library/Makefile.client b/common_library/Makefile.client new file mode 100644 index 00000000..66f890e6 --- /dev/null +++ b/common_library/Makefile.client @@ -0,0 +1,19 @@ +# +# @copyright Copyright (c) 2017-2019 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. +# + +SUBDIRS := client + +include ../native_service.mk diff --git a/common_library/client/Makefile b/common_library/client/Makefile new file mode 100644 index 00000000..9e02324f --- /dev/null +++ b/common_library/client/Makefile @@ -0,0 +1,30 @@ +# +# @copyright Copyright (c) 2016-2019 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. +# + +INST_SHLIBS := libcommon + +libcommon_SRCS := cl_process.c cl_sem.c cl_monitor.c cl_region.c cl_lock.c cl_cgroup.c +INST_HEADERS := common_library.h cl_process.h cl_sem.h cl_monitor.h cl_lock.h cl_region.h cl_lockid.h + +VPATH = ./src ./include/$(COMPONENT_NAME) + +CPPFLAGS += -I./include/ + +LDFLAGS += -Wl,--no-as-needed + +LDLIBS += -lrt + +include ../../native_service.mk diff --git a/common_library/client/include/cl_cgroup.h b/common_library/client/include/cl_cgroup.h new file mode 100644 index 00000000..684cd76c --- /dev/null +++ b/common_library/client/include/cl_cgroup.h @@ -0,0 +1,35 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_cgroup_h_ // NOLINT(build/header_guard) +#define _cl_cgroup_h_ // NOLINT(build/header_guard) + +typedef enum { + CL_CGROUP_MEMORY, + CL_CGROUP_CPU, +} cl_cgroup_t; + +int cl_cgroup_make(cl_cgroup_t cgroup, const char *cgroup_name); // NOLINT(readability/nolint) +int cl_cgroup_remove(cl_cgroup_t cgroup, const char *cgroup_name); // NOLINT(readability/nolint) +int cl_cgroup_exist(cl_cgroup_t cgroup, const char *cgroup_name); // NOLINT(readability/nolint) +int cl_cgroup_open(cl_cgroup_t cgroup, const char *cgroup_name, // NOLINT(readability/nolint) + const char *controler, int flags); +int cl_cgroup_set_string(cl_cgroup_t cgroup, const char *cgroup_name, // NOLINT(readability/nolint) + const char *controler, const char *str); +int cl_cgroup_set_num(cl_cgroup_t cgroup, const char *cgroup_name, // NOLINT(readability/nolint) + const char *controler, int64_t value); + +#endif // ifndef _cl_cgroup_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/cl_error.h b/common_library/client/include/cl_error.h new file mode 100644 index 00000000..f4e24c09 --- /dev/null +++ b/common_library/client/include/cl_error.h @@ -0,0 +1,44 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_error_h_ // NOLINT(build/header_guard) +#define _cl_error_h_ // NOLINT(build/header_guard) + +#include <stdio.h> +#include <unistd.h> +#include <asm/unistd.h> + +static inline int gettid(void) { // NOLINT(readability/nolint) + return (int)syscall(__NR_gettid); // NOLINT(readability/casting) +} + +#define _num_to_str(num) #num +#define num_to_str(num) _num_to_str(num) +#define CL_PERROR(msg) \ + perror(__FILE__ ":" num_to_str(__LINE__)":"msg) + +#define CL_ERR_PRINT(fmt, args...) \ + fprintf(stderr, "[ERR]%d %s:%d:"fmt"\n", gettid(), __func__, __LINE__, ##args) + +#if defined(CL_DBG_ENABLE) +#define CL_DBG_PRINT(fmt, args...) \ + fprintf(stdout, "[DBG]%d %s:%d:"fmt"\n", gettid(), __func__, __LINE__, ##args) +#else +#define CL_DBG_PRINT(fmt, args...) +#endif + + +#endif // #ifndef _cl_error_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/cl_lock_internal.h b/common_library/client/include/cl_lock_internal.h new file mode 100644 index 00000000..8d41be6b --- /dev/null +++ b/common_library/client/include/cl_lock_internal.h @@ -0,0 +1,55 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_lock_internal_h_ // NOLINT(build/header_guard) +#define _cl_lock_internal_h_ // NOLINT(build/header_guard) + +#include <native_service/cl_lockid.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file cl_lock_internal.h + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +#define LOCKFILE_NAME "lockfile" // lock file name +#define SLOT_SIZE 4096 // slot size +#define LOCKFILE_SIZE SLOT_SIZE * LID_NUM // the lock file size + +#define LOCK_TIMEOUT 3 // timeout(sec) for CL_LockTimedGet + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _cl_lock_internal_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/cl_monitor_internal.h b/common_library/client/include/cl_monitor_internal.h new file mode 100644 index 00000000..5d66db4e --- /dev/null +++ b/common_library/client/include/cl_monitor_internal.h @@ -0,0 +1,30 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_monitor_internal_h_ // NOLINT(build/header_guard) +#define _cl_monitor_internal_h_ // NOLINT(build/header_guard) + +#ifdef __cplusplus +extern "C" { +#endif + +int cl_monitor_cleanup(int pid); // NOLINT(readability/nolint) + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _cl_monitor_internal_h_ */ diff --git a/common_library/client/include/cl_process_internal.h b/common_library/client/include/cl_process_internal.h new file mode 100644 index 00000000..05fd6870 --- /dev/null +++ b/common_library/client/include/cl_process_internal.h @@ -0,0 +1,53 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_process_internal_h_ // NOLINT(build/header_guard) +#define _cl_process_internal_h_ // NOLINT(build/header_guard) + +typedef struct { + char name[20]; + uid_t uid; + gid_t gid; + int sched_policy; + int sched_priority; + int create_group; + int stack_size; + int cpu_assign; + int hold_fds[CL_PROCESSS_ATTR_HOLD_FDS_NUM]; + int disable_close_fds; + char cgroup_name[64]; +} CL_ProcessAttrInternal_t; + +typedef struct { + char name[20]; +} CL_ThreadAttrInternal_t; + +typedef struct { + int rt_runtime_us; + int cfs_quota_us; + int cpu_shares; + int memory_limit; + int usage_in_bytes; + int event_fd; +} CL_ProcessCreateCgroupAttrInternal_t; + +#define CL_PROCESS_NAME_ENV "CL_PROCESS_NAME" + +#define CL_PROCESS_EXIT_INTERNAL 0x80 + +#define CL_PROCESS_CGROUP_NAME_FORMAT "CGRP%05d" + +#endif // #ifndef _cl_process_internal_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/cl_lock.h b/common_library/client/include/native_service/cl_lock.h new file mode 100644 index 00000000..dcf61001 --- /dev/null +++ b/common_library/client/include/native_service/cl_lock.h @@ -0,0 +1,255 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ +#ifndef _cl_lock_h_ // NOLINT(build/header_guard) +#define _cl_lock_h_ // NOLINT(build/header_guard) + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file cl_lock.h + * @brief \~english This file contains the base api of cl_clock. + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockSystemInit +/// \~english @par Brief +/// Initialize the system lock. +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - On system call shm_open error, -1 is returned. +/// - On system call ftrancate error, -1 is returned. +/// - On system call mmap error, -1 is returned. +/// - On system call pthread_mutexattr_setpshared error, -1 is returned. +/// \~english @par Detail +/// This function will generate the Lock file, and initialize all the pthread_mutex_t slots.\n +/// This function must to be called in the system once, which is recommended on the SystemManager start.\n +/// \~english @par +/// Lock file is formed with lots of slots. Every slot occupies 4KB. +/// The slot layout is: +/// 0 ~ 4Byte : field of PID +/// 4Byte ~ 28Byte : field of pthread_mutex_t +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int32_t CL_LockSystemInit(void); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockProcessInit +/// \~english @par Brief +/// Initialize the process Lock file. +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// Should call CL_LockSystemInit() to generate Lock file. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - On system call shm_open error, -1 is returned. +/// \~english @par Detail +/// Open the Lock file.\n +/// If process want to use the Lock, this function should be called.\n +/// It is recommended that this function should be called since start main function. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int32_t CL_LockProcessInit(void); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockMap +/// \~english @par Brief +/// Mapping the Lock information address. +/// \~english @param [in] lid +/// int32_t - LockID of the Lock used.(0~LID_NUM) \n +/// \~english @retval addr Lock address +/// \~english @retval MAP_FAILED Error (errno) +/// \~english @par Prerequisite +/// Should call CL_LockSystemInit(), CL_LockProcessInit() to open the Lock file. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - If LockID(lid) < 0, errno is set as EINVAL, and MAP_FAILED is returned +/// - If LockID(lid) > LID_NUM, errno is set as EINVAL, and MAP_FAILED is returned +/// - If systemcall mmap is failure, errno is set euqal with the errno of mmap, and MAP_FAILED is returned +/// \~english @par Detail +/// Mapping the Lock information to the memory.\n +/// The related LockID should be assigned, when apply the share memory.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// CL_LockUnmap +//////////////////////////////////////////////////////////////////////////////////// +void *CL_LockMap(int32_t lid); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockUnmap +/// \~english @par Brief +/// Unmapping the Lock information. +/// \~english @param [in] addr +/// void* - Lock information address. +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// Should call CL_LockSystemInit(), CL_LockProcessInit() before this function is called +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - If systemcall munmap is failure, errno is set euqal with the errno of munmap, -1 is returned +/// \~english @par Detail +/// 0 would be returned, even if not get the Lock. +/// The addr is the Lock information address that acquired from CL_LockMap. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// CL_LockMap +//////////////////////////////////////////////////////////////////////////////////// +int32_t CL_LockUnmap(void *addr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockGet +/// \~english @par Brief +/// Get the Lock. Block until get the Lock. +/// \~english @param [in] addr +/// void* - Lock information address. +/// \~english @retval 0 Success +/// \~english @retval EINVAL Invalid parameter +/// \~english @retval EDEADLK Mutex already locked +/// \~english @par Prerequisite +/// Should call CL_LockMap to get the Lock information address. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - EINVAL as the parameter of Lock information address is NULL +/// - EINVAL as the parameter of Lock information address is MAP_FAILED +/// - EINVAL as the mutex does not be initialized in the systemcall pthread_mutex_lock failure. +/// - EDEADLK as the current thread already owns the mutex in the systemcall pthread_mutex_lock failure. +/// \~english @par Detail +/// Get the Lock until other threads release it. +/// It will be deadlock if the current thread already owns the mutex. +/// The addr is the Lock information address that should be acquired from CL_LockMap. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// CL_LockRelease +//////////////////////////////////////////////////////////////////////////////////// +int32_t CL_LockGet(void *addr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockNowait +/// \~english @par Brief +/// Try to get Lock, shall immediately return. +/// \~english @param [in] addr +/// void* - Lock information address. +/// \~english @retval 0 Success +/// \~english @retval EINVAL Invalid parameter +/// \~english @retval EBUSY Busy +/// \~english @par Prerequisite +/// Should call CL_LockMap to get the Lock information address. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - EINVAL as input parameter addr, the Lock information address is NULL +/// - EINVAL as input parameter addr, the Lock information address if MAP_FAILED +/// - EINVAL as the mutex does not be initialized in the systemcall pthread_mutex_trylock failure. +/// - EBUSY as the mutex could not be acquired as it was already locked in the +/// systemcall pthread_mutex_trylock failure. +/// \~english @par Detail +/// The addr is the Lock information address that should be acquired from CL_LockMap. +/// Get the Lock information from the pointed share memory. +/// Shall immediately return while not acquire the Lock. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// CL_LockRelease +//////////////////////////////////////////////////////////////////////////////////// +int32_t CL_LockNowait(void *addr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_LockRelease +/// \~english @par Brief +/// Release the Lock. +/// \~english @param [in] addr +/// addr - Lock information address. +/// \~english @retval 0 Success +/// \~english @retval EINVAL Invalid parameter +/// \~english @retval EPERM The current thread does not own the mutex +/// \~english @par Prerequisite +/// - Should call CL_LockMap to get the Lock information address. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - EINVAL as input parameter addr, the Lock information address is NULL +/// - EINVAL as input parameter addr, the Lock information address if MAP_FAILED +/// - EINVAL as the mutex does not be initialized in the systemcall pthread_mutex_unlock failure. +/// - EPERM as the current thread does not own the mutex in the systemcall pthread_mutex_unlock failure. +/// \~english @par Detail +/// 0 would be returned, even if not get the Lock. +/// The addr is the Lock information address that should be acquired from CL_LockMap. +/// Release the Lock related with the share memory. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync only +/// \~english @see +/// CL_LockGet, CL_LockNowait +//////////////////////////////////////////////////////////////////////////////////// +int CL_LockRelease(void *addr); // NOLINT(readability/nolint) + +#ifdef __cplusplus +} +#endif + + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#endif // #ifndef _cl_lock_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/cl_lockid.h b/common_library/client/include/native_service/cl_lockid.h new file mode 100644 index 00000000..c76be374 --- /dev/null +++ b/common_library/client/include/native_service/cl_lockid.h @@ -0,0 +1,162 @@ +/* + * @copyright Copyright (c) 2016-2019 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_lockid.h + * @brief Definition of LockID(LID) + * + */ + +#ifndef _cl_lockid_h_ // NOLINT(build/header_guard) +#define _cl_lockid_h_ // NOLINT(build/header_guard) + +/** + * @file cl_lockid.h + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +/* + * Numbering rules + * Assign LID corresponding to the Lock name specified when requesting shared memories. + */ + +typedef enum { +// LID_TEST_1 = 0, +// LID_TEST_2, + LOCK_ANA_LOG_SEM = 0, /* Exclusive Control to store application log on kernel unmanaged RAM*/ + LOCK_POS_MTX_1, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_2, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_3, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_4, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_5, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_6, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_7, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_8, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_9, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_10, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_11, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_12, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_13, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_14, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_15, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_16, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_17, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_18, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_19, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_20, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_21, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_22, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_23, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_24, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_25, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_26, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_27, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_28, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_29, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_30, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_31, /* Exclusive Control between POSITIONING and others */ + LOCK_POS_MTX_32, /* Exclusive Control between POSITIONING and others */ + LOCK_CLOCK_SEM_TZ, /* Access control to shared memory for TimeZone */ + LOCK_SEC_DATA_PROTECT, /* Exclusive control to shared memory for the application that use the security chip. */ + LOCK_OS_SEM_ID__CWORD68_, /* Exclusive Control for SSL library. */ + LOCK_ROM_ACCESS_IF, /* Exclusive access control for system manager nv area */ + LOCK_BOOT_ACCESS_IF, /* Exclusive access control for system manager nor area */ + LOCK_RAM_ACCESS_IF, /* Exclusive access control for system manager drambackup area */ + LOCK_HRDS_1, /* Exclusive Control between DataService and others */ + LOCK_HRDS_2, /* Exclusive Control between DataService and others */ + LOCK_HRDS_3, /* Exclusive Control between DataService and others */ + LOCK_HRDS_4, /* Exclusive Control between DataService and others */ + LOCK_HRDS_5, /* Exclusive Control between DataService and others */ + LOCK_HRDS_6, /* Exclusive Control between DataService and others */ + LOCK_HRDS_7, /* Exclusive Control between DataService and others */ + LOCK_HRDS_8, /* Exclusive Control between DataService and others */ + LOCK_LOGG_ACCESS_IF, /* Exclusive access control for NsLoggerService nv area */ + LOCK__CWORD76__HMI, /* Exclusive Control between _CWORD76_Service and HMI's */ + LOCK__CWORD76___CWORD58_, /* Exclusive Control between _CWORD76_Service and _CWORD58_Service */ + LOCK_DIAGCODE_MEM, /* Exclusive Control to diag code memory area */ + LOCK_MOUNTER_MOUNT, /* Exclusive Control for Mount */ + LOCK_NOR_ERCNT, /* Exclusive access control for NOR erase count information */ + LOCK_RS_WNG_HIS_LIST_DATA, /* Exclusive Control between RemoteService and RS-HMI. */ + LOCK_RS_WNG_SCREEN_DATA, /* Exclusive Control between RemoteService and RS-HMI. */ + LOCK_RS_SCREEN_DATA, /* Exclusive Control between RemoteService and RS-HMI. */ + LOCK_NSLOG_ACCES_IF_1, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_2, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_3, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_4, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_5, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_6, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_7, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_8, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_9, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_10, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_11, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_12, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_13, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_14, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_15, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_16, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_17, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_18, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_19, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_20, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_21, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_22, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_23, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_24, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_25, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_26, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_27, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_28, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_29, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_30, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_31, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_32, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_33, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_34, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_35, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_36, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_37, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_38, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_39, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_40, /* Exclusive Control between writing to log file */ + LOCK_NSLOG_ACCES_IF_41, /* Exclusive Control between writing to log file */ + + LOCK_NSLOG_ACCES_IF_42, /* Exclusive Control between writing to log file */ + + LOCK_NSLOG_ACCES_IF_43, /* Exclusive Control between writing to log file */ + LOCK_INFOSETTING_REV, /* Exclusive control revision information for managing the settings */ + LOCK_SUBMENU_SELECT, /* Exclusive control between writing the selection information of the sub-menu*/ + LOCK_DIAG_SEM1, /* Exclusive Control between DiagService and others */ + LOCK_DIAG_SEM2, /* Exclusive Control between Collect thread and Upload thread */ + LID_NUM /* Number of LockID */ +} ENUM_LOCK_ID; + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem + +#endif // #ifndef _cl_lockid_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/cl_monitor.h b/common_library/client/include/native_service/cl_monitor.h new file mode 100644 index 00000000..d2e3c503 --- /dev/null +++ b/common_library/client/include/native_service/cl_monitor.h @@ -0,0 +1,269 @@ +/* + * @copyright Copyright (c) 2016-2019 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 + * @brief \~english This file contains the enum,struct and api of cl_monitor. + */ +#ifndef _cl_monitor_h_ // NOLINT(build/header_guard) +#define _cl_monitor_h_ // NOLINT(build/header_guard) + +#include <stdint.h> + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor init enum +///////////////////////////////////////////////////////////////////////////////////// +typedef enum { + CL_MONITOR_INIT_SYSTEM = 0, + CL_MONITOR_INIT_USER +} CL_MonitorInit_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// the struct of Monitor Entry +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + uint16_t pid; + uint8_t type; + uint8_t state; + +// uint32_t timeout; + time_t timeout; + uint32_t id; + uint32_t user_data; +} CL_MonitorEntry_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor type enum +///////////////////////////////////////////////////////////////////////////////////// +typedef enum { + CL_MONITOR_TYPE_GENERIC = 0, + CL_MONITOR_TYPE_RPC +} CL_MonitorType_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor state enum +///////////////////////////////////////////////////////////////////////////////////// +typedef enum { + CL_MONITOR_STATE_SLEEP = 0, + CL_MONITOR_STATE_RUN +} CL_MonitorState_t; + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// the struct of Monitor Search +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + CL_MonitorEntry_t *entry_list; + int entry_num; +} CL_MonitorSearch_t; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @file cl_monitor.h + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor initialize +/// \~english @param [in] init_type +/// CL_MonitorInit_t - the type of initialzation +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorInit(CL_MonitorInit_t init_type); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Set Monitor Entry +/// \~english @param [in] type +/// CL_MonitorType_t - the type of monitor +/// \~english @param [in] state +/// CL_MonitorState_t - the state of monitor +/// \~english @param [in] timeout +/// uint32_t - the vlaue of timeout +/// \~english @param [in] user_data +/// uint32_t - the user data +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorSetEntry(CL_MonitorType_t type, uint32_t id, // NOLINT(readability/nolint) + CL_MonitorState_t state, uint32_t timeout, + uint32_t user_data); + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Get Monitor Entry +/// \~english @param [in] type +/// CL_MonitorType_t - the type of monitor +/// \~english @param [in] id +/// uint32_t - the monitor id +/// \~english @param [out] entry +/// CL_MonitorEntry_t* - the pointer to monitor entry +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorGetEntry(CL_MonitorType_t type, uint32_t id, CL_MonitorEntry_t *entry); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor searth intialize +/// \~english @param [in] serch +/// CL_MonitorSearch_t* - the pointor to monitory search +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorSearchInit(CL_MonitorSearch_t *serch); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor searth destroy +/// \~english @param [in] serch +/// CL_MonitorSearch_t* - the pointor to monitory search +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorSearchDestroy(CL_MonitorSearch_t *serch); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// Monitor searth timeout +/// \~english @param [in] serch +/// CL_MonitorSearch_t* - the pointor to monitory search +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +int CL_MonitorSearchTimeout(CL_MonitorSearch_t *search); // NOLINT(readability/nolint) + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _cl_monitor_h_ */ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/cl_process.h b/common_library/client/include/native_service/cl_process.h new file mode 100644 index 00000000..01dc064b --- /dev/null +++ b/common_library/client/include/native_service/cl_process.h @@ -0,0 +1,1288 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +#ifndef _cl_process_h_ // NOLINT(build/header_guard) +#define _cl_process_h_ // NOLINT(build/header_guard) + +#include <sys/types.h> + +#define CL_PROCESSS_ATTR_HOLD_FDS_NUM 8 + +#define CL_INTFY_FILENAME_FORMAT "/tmp/intfy_%05d" + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessAttr_t +/// \~english @par Brief +/// Process attribute structure +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + char body[148]; ///< process attribute +} CL_ProcessAttr_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCleanupInfo_t +/// \~english @par Brief +/// Child-process attribute structure +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + pid_t pid; ///< child-process ID + int code; ///< signal code + int status; ///< end status or signal +} CL_ProcessCleanupInfo_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessSchedPolicy_t +/// \~english @par Brief +/// Schedule policy +///////////////////////////////////////////////////////////////////////////////////// +typedef enum { + CL_PROCESS_SCHED_POLICY_OTHER = 0, ///< TSS + CL_PROCESS_SCHED_POLICY_RR, ///< Round robin + CL_PROCESS_SCHED_POLICY_FIFO, ///< FIFO +} CL_ProcessSchedPolicy_t; + +typedef struct { + char body[20]; +} CL_ThreadAttr_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttr_t +/// Cgroup attribute structure +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + char body[24]; ///< Cgroup attribute +} CL_ProcessCreateCgroupAttr_t; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @file cl_process.h + * @brief \~english This file contains the base api,enum and struct of cl_process. + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessInit +/// \~english @par Brief +/// Initialize the process +/// \~english @retval int file descriptor +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - Failed to set up process prctl, -1 is returned. +/// - Failed to set the signal set to the empty set sigemptyset, -1 is returned. +/// - Failed to add a signal to the signal mask sigaddset, -1 is returned. +/// - Failed to set sigprocmask, -1 is returned. +/// - Failed to create a scripter in the file for signal acceptance signalfd, -1 is returned. +/// \~english @par Detail +/// This API must be called before createing a thread. +/// Therefore, it is recommended that this API be called from within the main() function immediately after the API started.\n +/// Initialize the process.\n +/// The retuen value fd is assumed to be poll/select and used for waiting for event.\n +/// An ready occurs when the child process terminates.\n +/// Call process name setting(\ref CL_ProcessCreateAttrSetName) uniformly +/// because it is applied only to the number of architecture after exec.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessInit(void); // NOLINT(readability/nolint) + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreate +/// \~english @par Brief +/// Create the process +/// \~english @param [in] file +/// const char* - +/// \~english @param [in] argv[] +/// char* const - +/// \~english @param [in] envp[] +/// char* const +/// \~english @param [in] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval int Success(PID) +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Need to be running CL_ProcessInit. +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the executable name (file) in the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the ARG parameter (argv[]) in the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When memory (malloc) of the data storagee area of the environment variable parameter (envp[]) specified +/// by the arguments fails, set errno to EINVAL, -1 is returned. +/// - When memory (malloc) of the data control area of the environment variable parameter (envp[]) specified +/// by the arguments fails, set errno to EINVAL, -1 is returned. +/// - Process creation (fork) fail, -1 is returned. +/// - Process CPU affinity masking (sched_setaffinity) fail, -1 is returned. +/// - When the character string output processing (snprintf) for process creation fail, -1 is returned. +/// - When the character string output processing (snprintf) for PID setting of cgroup fail, -1 is returned. +/// - Failure to allocate the area fo sstoring the path name of cgroup (malloc), -1 is returned. +/// - Failure to open file descriptor (open) of cgroup, -1 is returned. +/// - Failure to write file descriptor (write) of cgroup, -1 is returned. +/// \~english @par Detail +/// - This API must be called before createing a thread. +/// \~english @par +/// Create the process.\n +/// The ARG parameter (argv[]) specified in the argment must satisfy the following conditions:\n +/// - Can not be omitted.\n +/// - The first argument must specify a pointer o the filename to be executed.\n +/// - An array of pointer to NULL terminated strings.\n +/// - Arrays must be terminated by NULL pointer.\n +/// \~english @par +/// Enviroment-variable parameters (envp[]) specified in arguments mus satisfy the following condiions:\n +/// - When NULL is specified, the parent process inherits the parent process's environment variables.\n +/// - An array of pointer to NULL terminated strings.\n +/// - Arrays must be terminated by NULL pointer.\n +/// \~english @par +/// Be aware of the following.\n +/// - Processing continues without interrupting event if setrlimit() fail.\n +/// - System call access() checks whether or not there is access privilege, +/// but returns PID regardless of the access privilege status. +/// (If the process does not have access privilege, 100 retries are executed at 100 microseconds.) +/// \~english @par +/// Since the process attribute of a process cannot be changed during processing, +/// if it is necessary to change the process attribute, +/// it is necessary to call the following API and change the process attribute before calling this API.\n +/// - CL_ProcessCreateAttrInit Initialize process attribute +/// - CL_ProcessCreateAttrSetCgroup Setting process attribute (Cgroup) +/// - CL_ProcessCreateAttrSetDisableCloseFds Setting process attribute (stop compulsion FD close) +/// - CL_ProcessCreateAttrSetGid Setting process attribute (group ID) +/// - CL_ProcessCreateAttrSetGroup Setting process attribute (process group) +/// - CL_ProcessCreateAttrSetHoldFds Setting process attribute (maintain FD) +/// - CL_ProcessCreateAttrSetName Setting process attribute (process name) +/// - CL_ProcessCreateAttrSetSchedule Setting process attribute (schedule policy and priority) +/// - CL_ProcessCreateAttrSetStackSize Setting process attribute (Stack Size) +/// - CL_ProcessCreateAttrSetUid Setting process attribute (user ID) +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Open Close +/// \~english @see +/// CL_ProcessTerminate, CL_ProcessTerminateGroup +/// CL_ProcessCreateAttrInit, CL_ProcessCreateAttrSetCgroup, +/// CL_ProcessCreateAttrSetDisableCloseFds, CL_ProcessCreateAttrSetGid, +/// CL_ProcessCreateAttrSetGroup, CL_ProcessCreateAttrSetHoldFds, +/// CL_ProcessCreateAttrSetName, CL_ProcessCreateAttrSetSchedule, +/// CL_ProcessCreateAttrSetStackSize, CL_ProcessCreateAttrSetUid +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreate(const char *file, char * const argv[], char * const envp[], // NOLINT(readability/nolint) + const CL_ProcessAttr_t *attr); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrInit +/// \~english @par Brief +/// Initialize process attribute +/// \~english @param [out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Initilize the CL_ProcessAttr_t structure that stores process attribute.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Method(Async) / Fire and Forget / Broadcast / Sync / Set Get / Open Close / Request Notify / No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrInit(CL_ProcessAttr_t *attr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetName +/// \~english @par Brief +/// Set process name in process attribute +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] name +/// const char* - process name (max length 16byte) +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the pointer (name) to the character string hat stores the process name specified +/// by the argument is NULL, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process name to process attribute.\n +/// The charactr string that stores the process name specified by the argument must satisfy the following conditions:\n +/// - Terminated by a NULL.\n +/// - The maximum lengthof character string is 16 byte including the termination character.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetName(CL_ProcessAttr_t *attr, const char *name); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetUid +/// \~english @par Brief +/// Set process attribute to user ID +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] uid +/// uid_t - user ID +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to user ID.\n +/// When UINT_MAX is set for the user ID, +/// the user ID is set to 0 in the process attribute in the processing of CL_ProcessCreate().\n +/// When 0 is set for the user ID, +/// it is not reflected in the process attribute becose if is played by the process of CL_ProcessCreate().\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetUid(CL_ProcessAttr_t *attr, uid_t uid); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetGid +/// \~english @par Brief +/// Set process attribute to group ID +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] gid +/// gid_t - Group ID +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to group ID.\n +/// When 0 is set for the group ID, +/// it is not reflected in the process attribute becose if is played by the process of CL_ProcessCreate().\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetGid(CL_ProcessAttr_t *attr, gid_t gid); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetSchedule +/// \~english @par Brief +/// Set process attribute to schedule policy and priority +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] policy +/// CL_ProcessSchedPolicy_t - schedule policy +/// \~english @param [in] priority +/// int - priority +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @par +/// enum CL_ProcessSchedPolicy_t Variable +/// \~english @code +/// typedef enum { +/// CL_PROCESS_SCHED_POLICY_OTHER = 0, // TSS +/// CL_PROCESS_SCHED_POLICY_RR, // Round-robin +/// CL_PROCESS_SCHED_POLICY_FIFO, // FIFO +/// } CL_ProcessSchedPolicy_t; +/// @endcode +/// \~english @par +/// target to priority +/// - -20~19 : CL_PROCESS_SCHED_POLICY_OTHER +/// - 1~99 : CL_PROCESS_SCHED_POLICY_RR or CL_PROCESS_SCHED_POLICY_FIFO +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the schedule policy (policy) specified in the parameter is CL_PROCESS_SCHED_POLICY_RR +/// and the priority (priority) is other than 1 to 99, set errno to EINVAL, -1 is returned. +/// - When the schedule policy (policy) specified in the parameter is CL_PROCESS_SCHED_POLICY_FIFO +/// and the priority (priority) is other than 1 to 99, set errno to EINVAL, -1 is returned. +/// - Incorrect parameters are specified for the schedule policy (policy) specified in the arguments, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to schedule policy and priority.\n +/// Error occur if the real-time schedule policy is set and +/// the priority is passed value outside the range of 1-99.\n +/// In the case of TSS, an error does not occur even if it is outside the range of -20 to 19, +/// but ti is rounded to the nearest integer by a system call when a process is created.\n +/// If not set by this funtion, the schedule policy set the TSS and priority sets 0.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetSchedule(CL_ProcessAttr_t *attr, // NOLINT(readability/nolint) + CL_ProcessSchedPolicy_t policy, + int priority); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetGroup +/// \~english @par Brief +/// Set process attribute to process group +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] create +/// int - (0 or 1) +/// \~english @par +/// - 1 make +/// - 0 not make(default) +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When a value oher than 0 or 1 is secified for the process group cration flag (create) +/// specified in the parameter, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to process group.\n +/// When a process group is created, all descendant process fork from child process also belong +/// to the same process group, and the entire process group can be forcibly terminated.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetGroup(CL_ProcessAttr_t *attr, int create); // NOLINT(readability/nolint) + +int CL_ProcessCreateAttrSetCpuAssign(CL_ProcessAttr_t *attr, int cpu_assign); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetStackSize +/// \~english @par Brief +/// Set process attribute to stack size +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] stack_size +/// int - stack size(byte) +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to stack size.\n +/// The muximum configurable stack size is 1MB.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetStackSize(CL_ProcessAttr_t *attr, int stack_size); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetHoldFds +/// \~english @par Brief +/// Set process attribute to FD to maintain +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] hold_fds[] +/// int - +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the array (hode_openfd[]) storing the list of the FD to be maintained specified +/// by the arguments is NULL, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to FD to maintain.\n +/// When nothing is set, FD other than 0, 1, and 2 are automatically close.\n +/// For hold_openfds is stored in a CL_PROCESSS_ATTR_HOLD_FDS_NUM array, +/// it is recommended that int hold_openfds[CL_PROCESSS_ATTR_HOLD_FDS_NUM] be used.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetHoldFds(CL_ProcessAttr_t *attr, int hold_fds[]); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetDisableCloseFds +/// \~english @par Brief +/// Set process attribute to suspend forced FD close +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to suspend forced FD close.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetDisableCloseFds(CL_ProcessAttr_t *attr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateAttrSetCgroup +/// \~english @par Brief +/// Set process attribute to Cgroup +/// \~english @param [in,out] attr +/// const CL_ProcessAttr_t* - Process attribute pointer +/// \~english @param [in] cgroup_name +/// const char* - Cgroup name +/// \~english @par +/// CL_ProcessAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[148]; +/// } CL_ProcessAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateAttrInit. +/// - cgroup specified by CL_ProcessCreateCgroupCreate() has been created. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the pointer (name) to the character string hat stores the process name specified +/// by the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the character string length of the character string (cgroup_name) storing the process name specified +/// by the argument is 64 byte or more, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set process attribute to Cgroup.\n +/// Creat new Cgroup with CL_ProcessCreateCgroupCreate().\n +/// An error occurs if an Cgroup name that does not exist is specified.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateAttrSetCgroup(CL_ProcessAttr_t *attr, // NOLINT(readability/nolint) + const char *cgroup_name); + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessTerminate +/// \~english @par Brief +/// Kill the process +/// \~english @param [in] pid +/// pid_t - PID +/// \~english @retval int file descriptor +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - CL_ProcessInit and CL_ProcessCreate must be running. +/// (Process ID to be forcibly terminated exists) +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the process ID to be forcibly terminated does not exist, -1 is returned. +/// \~english @par Detail +/// The PID of the process is he return value (PID) of CL_ProcessCreate(). +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Open Close +/// \~english @see +/// CL_ProcessCreate +///////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessTerminate(pid_t pid); // NOLINT(readability/nolint) + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessTerminateGroup +/// \~english @par Brief +/// Kill process group +/// \~english @param [in] pid +/// pid_t - process group ID +/// \~english @retval int file descriptor +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - CL_ProcessInit and CL_ProcessCreate must be running. +/// (Process ID to be forcibly terminated exists) +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the process ID to be forcibly terminated does not exist, -1 is returned. +/// \~english @par Detail +/// The process group ID is he return value (PID) of CL_ProcessCreate(). +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Open Close +/// \~english @see +/// CL_ProcessCreate +///////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessTerminateGroup(pid_t pid); // NOLINT(readability/nolint) + +int CL_ProcessAbort(pid_t pid); // NOLINT(readability/nolint) + +int CL_ProcessAbortGroup(pid_t pid); // NOLINT(readability/nolint) + +int CL_ProcessEuthanizeGroup(pid_t pid); // NOLINT(readability/nolint) + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCleanup +/// \~english @par Brief +/// Collect child process +/// \~english @param [in] sigchld_fd +/// int - CL_ProcessInit() function return to fd +/// \~english @param [out] cleanup_info +/// CL_ProcessCleanupInfo_t* - Pointer to chiled process info +/// \~english @par +/// CL_ProcessCleanupInfo_t struct +/// \~english @code +/// typedef struct { +/// pid_t pid; /* The process ID of the child. */ +/// int code; /* signal code */ +/// int status; /* the exit status of the child or the signal */ +/// } CL_ProcessCleanupInfo_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval 1 Success +/// (If WNOHANG was specified and no child(ren) specified by id has yet changed state) +/// \~english @retval -1 Error (setting to errno) +/// \~english @par Prerequisite +/// - Must be runnning CL_ProcessInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer (cleanup_info) to the child process information structure is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When a systemu call (waitid) fails, -1 is returned. +/// - When there are no child process in state waitable, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// This API must be called before createing a thread.\n +/// \~english @par +/// It must be called many times while the return valu is 1. +/// After the return value reaches 0, calling it again results in an error (ECHILD).\n +/// The code of CL_ProcessCleanupInfo_t cotains the following value:\n +/// - CLD_EXITED : Finished child process (exited) +/// - CLD_KILLED : Killed child process +/// - CLD_DUMPED : Ended abnormally child process +/// - CLD_TRAPPED : Trapped traced child process +/// - CLD_STOPPED : Stopped child process (stop) +/// - CLD_CONTINUED restarted the sopped child process (after Linux 2.6.9) +/// - The exit status is stored in status only when code is CLD_EXITED. Otherwise, signals are stored. +/// - Need to include signal.h to use CLD_*. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCleanup(int sigchld_fd, CL_ProcessCleanupInfo_t *cleanup_info); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ThreadCreate +/// \~english @par Brief +/// Create thread +/// \~english @param [out] thread +/// pthread_t* - thread hadle +/// \~english @param [in] attr +/// pthread_attr_t* - Thread attibute pointer for pthread +/// \~english @param [in] cl_attr +/// CL_ThreadAttr_t* - Tred attribute pointer for expansion +/// \~english @param [in] start_routine +/// void*(*)(void*) - Pointer to the entry function of the thread +/// \~english @param [in] arg +/// void* - Argument to the entry function of the thread +/// \~english @par +/// CL_ThreadAttr_t structure +/// \~english @code +/// typedef struct { +/// char body[20]; +/// } CL_ThreadAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error (set errno) +/// \~english @retval EAGAIN failure to create thread +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the thread handler (thread) specified in the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the pointer of the thread attribute specified in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the pointer (start_routine) of the entry function of the thread specified by the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - Failure to initialize semaphore, set errno to sem_init, -1 is returned. +/// - Failure to create thread (pthread_create), EAGAIN is returned. +/// - Failure to rock semaphore (sem_wait), set errno to sem_init, -1 is returned. +/// \~english @par Detail +/// Create thread.\n +/// The extension thread attribute (cl_attr) is used o assign the thread name set +/// by CL_ThreadCreateAttrSetName(CL_ThreadAttr_t*, const char*).\n +/// \~english @par Classification +/// Public +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ThreadCreate(pthread_t *thread, pthread_attr_t *attr, // NOLINT(readability/nolint) + CL_ThreadAttr_t *cl_attr, void *(*start_routine)(void *), + void *arg); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ThreadCreateAttrInit +/// \~english @par Brief +/// Initialize thread attribute +/// \~english @param [out] attr +/// CL_ThreadAttr_t* - thread attribute pointer +/// \~english @par +/// CL_ThreadAttr_t structure +/// \~english @code +/// typedef struct { +/// char body[20]; +/// } CL_ThreadAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error (set errno) +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer (attr) of the thread attributespecified by the argument is NULL, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Initialize structure CL_ThreadAttr_t that stores threade attribute.\n +/// \~english @par Classification +/// Public +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ThreadCreateAttrInit(CL_ThreadAttr_t *attr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ThreadCreateAttrSetName +/// \~english @par Brief +/// Set thread attribute to thread name +/// \~english @param [out] attr +/// CL_ThreadAttr_t* - thread attribute pointer +/// \~english @param [in] name +/// const char* - Pointer to the string storing the thread name (max length 16byte) +/// \~english @par +/// CL_ThreadAttr_t structure +/// \~english @code +/// typedef struct { +/// char body[20]; +/// } CL_ThreadAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error (set errno) +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer (attr) of thread attribute specified by the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the pointer (name) to the character string that stores the thread name specified +/// by the argument is NULL, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Set thread attribute to thread name\n +/// The characer string that stores the thread name specified by the argument must satisfy the following conditions:\n +/// - Terminated by a NULL.\n +/// - The maximum lengthof character string is 16 byte including the termination character.\n +/// \~english @par Classification +/// Public +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ThreadCreateAttrSetName(CL_ThreadAttr_t *attr, const char *name); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupCreate +/// \~english @par Brief +/// Create Cgroup +/// \~english @param [in] cgroup_name +/// const char* - cgroup name +/// \~english @param [in] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribut +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr by CL_ProcessCreateCgroupAttrInit +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the Cgroup name (cgroup_name) specified by the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the pointer (attr) of the Cgroup attribute specified by the argumet is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When the area for directory path name of the CPU subsystem of Cgroup could not be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When the area for directory of the CPU subsystem of Cgroup could not be create, -1 is returned. +/// - When the area for file path name of the CPU subsystem of Cgroup could not be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When file descriptor of the CPU subsystem of Cgroup could not be acquired, -1 is returned. +/// - When setting value to CPU subsystem of Cgroup could not be written, -1 is returned. +/// - When the area for directory path name of the memory subsystem of Cgroup could not be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When the area for directory of the memory subsystem of Cgroup could not be create, -1 is returned. +/// - When the area for file path name of the memory subsystem of Cgroup could not be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When file descriptor of the memory subsystem of Cgroup could not be acquired, -1 is returned. +/// - When setting value to memory subsystem of Cgroup could not be written, -1 is returned. +/// \~english @par Detail +/// Create Cgroup to which the process to be created belongs. +/// If it belongs to Cgroup that has already been created, it is not necessary to create it.\n +/// \~english @par +/// Since the Cgroup attribute cannot be changed during Cgroup, if it is necessary o chage the Cgroup attribute, +/// it is necessary to call the following API and change the Cgroup attribute calling this API.\n +/// - CL_ProcessCreateCgroupAttrInit :Initialize Cgroup attribute +/// - CL_ProcessCreateCgroupAttrSetCfsBandwidthControl :TSS process CPU time control by Bandwidth Control +/// - CL_ProcessCreateCgroupAttrSetCpuShares :TSS process CPU time control +/// - CL_ProcessCreateCgroupAttrSetMemoryLimit :Contol memory usage +/// - CL_ProcessCreateCgroupAttrSetMemoryUsageNotification :Memory usage notification setting +/// - CL_ProcessCreateCgroupAttrSetRtThrottling :FIFO/RR process CPU time control +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Open Close +/// \~english @see +/// CL_ProcessCreateCgroupDelete, +/// CL_ProcessCreateCgroupAttrInit, CL_ProcessCreateCgroupAttrSetCfsBandwidthControl, +/// CL_ProcessCreateCgroupAttrSetCpuShares, CL_ProcessCreateCgroupAttrSetMemoryLimit, +/// CL_ProcessCreateCgroupAttrSetMemoryUsageNotification, CL_ProcessCreateCgroupAttrSetRtThrottling, +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupCreate(const char *cgroup_name, // NOLINT(readability/nolint) + CL_ProcessCreateCgroupAttr_t *attr); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrInit +/// \~english @par Brief +/// Initialize Cgroup attribute +/// \~english @param [out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute pointer +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Prerequisites are nothing. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of Cgroup attribute (attr) specified in the arguments is NULL, set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Initialize Cgroup attibute with 0.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrInit(CL_ProcessCreateCgroupAttr_t *attr); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrSetRtThrottling +/// \~english @par Brief +/// Set FIFO/RR process CPU time control +/// \~english @param [in,out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute +/// \~english @param [in] runtime_us +/// int - CPU allocation time(us) +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateCgroupAttrInit. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of Cgroup attribute (attr) specified in the arguments is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Limiting the CPU time allocated to a process to +/// which a real-time class schedule policy (SCHED_FIFO/SCHED_RR) is applied.\n +/// Set the value of argument runtime_us to the cpu.rt_runtime_us (CPU allocation time) of created Cgroup.\n +/// cpu.rt_period_us(unit time:1000000us) is not changed.\n +/// If not set, Cgroup created will remain at default (CPU allocation time:950000us).\n +/// The configurable range of runtime_us depends on the use of Cgroup and the kernel version. +/// The user sets an appropriate value.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrSetRtThrottling( // NOLINT(readability/nolint) + CL_ProcessCreateCgroupAttr_t *attr, int runtime_us); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrSetCpuShares +/// \~english @par Brief +/// Set TSS process CPU time control +/// \~english @param [in,out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute pointer +/// \~english @param [in] cpu_shares +/// int - An integer value that sepcified the relative distribution of CPU time +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateCgroupAttrInit +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer (attr) of the Cgroup attribute specified by the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Cotrols the CPU time allocated to a process to which +/// a class TSS schedule policy (SCHED_OTHER, etc.) is applied.\n +/// If cpu_shares is set with this function, a single Cgroup is created and cpu.shares is set with that value.\n +/// If not set, remain at default.\n +/// cpu_shares is set to the standard value 1024, and CPU time is allocated according +/// to the allocaion value specified between Cgroup.\n +/// Task Cgroup with cpu.shares set to 1024 has twice as much CPU time as +/// task Cgroup with cpu.shares set to 512.\n +/// Processes belonging to the same Cgroup are equally allocated CPU time allocated to Cgroup.\n +/// Note that the time distribution is distributed across al CPU cores on a multi-core system.\n +/// In a multicore system, if Cgroup limit is set to 100% of the CPU, +/// 100% of each CPU core wil be available.\n\n +/// Examle) If Cgroup A is set to use 25% of the CPU and Cgroup B is set to use 75% of the CPU,\n +/// and a process that uses CPU intensively is started on a 4-core system (1 process in A and 3 processes in B),\n +/// the CPU allocaion is distributed as follows.\n\n +/// \~english @par +/// | PID | cgroup | CPU | CPU allotment | +/// |:---:|:------:|:---:|:-------:| +/// | 100 | A | 0 | CPU0 100% | +/// | 101 | B | 1 | CPU1 100% | +/// | 102 | B | 2 | CPU2 100% | +/// | 103 | B | 3 | CPU3 100% | +/// \~english @par +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrSetCpuShares(CL_ProcessCreateCgroupAttr_t *attr, // NOLINT(readability/nolint) + int cpu_shares); + +/////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrSetCfsBandwidthControl +/// \~english @par Brief +/// Set TS process CU time control by Bandwidth Control +/// \~english @param [in,out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute pointer +/// \~english @param [in] cfs_quota_us +/// int - CPU allocation time +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateCgroupAttrInit +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Controls the amount of time allocated to processes o whitch TSS class schedule plicy (SCHED_OTHER, etc.) are +/// applied using bandwidth control of CFS(Completely Fair Scheduler) implemented from kernel 3.2.\n +/// Set the value of argument cfs_quota_us to the cpu.cfs_quota_us of created Cgroup.\n +/// cpu.cfs_period_us(unit time:1000000us) is not changed.\n +/// If not set, the created Cgroup will not have CPU allocatio control. (set cpu.cfs_guota_us to -1).\n +/// The time (%) allocated to Cgroup can be set correctly, +/// and it can be allocated correctly if the CPU is free.\n +/// It is scheduled to be allocated as much as possible even if it conflicts with other Cgroup's.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrSetCfsBandwidthControl( // NOLINT(readability/nolint) + CL_ProcessCreateCgroupAttr_t *attr, int cfs_quota_us); + +///////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrSetMemoryLimit +/// \~english @par Brief +/// Control memory usage +/// \~english @param [in,out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute pointer +/// \~english @param [in] memory_limit +/// int - memory limit (byte) +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateCgroupAttrInit +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// Control the CPU time allocated to a process.\n +/// Set the value of argument memory_limit to the memory.limit_in_bytes of created Cgroup.\n +/// If not set, there is no memory limit.When a request exceeding the memory limit is issued, +/// a SIGKILL is sent from the kernel and the process is discarded. +/// Note: When the memory limit is exceeded, control moves to 00M, +/// but its operation ca be changed (Documentation/cgroup/memory.txt).\n +/// Write memory.oom_control to 1 to stop the OOM-Killer. +/// When OOM-Killer is stopped, the task below Cgroup becomes hang/sleep.\n +/// The task moves when the limit of the memory Cgroup increaes or when usage decreases. When usage decreases,\n +/// - Task was killed\n +/// - Task was moved other group\n +/// - File has been deleted\n +/// \~english @par +/// You can also receive a eventf notification from OOM.\n +/// Memory usage is counted as follows\n +/// - RSS(All mapped anon pages)\n +/// - Page Cache\n +/// - First acess Shared Pages in Cgroup\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrSetMemoryLimit(CL_ProcessCreateCgroupAttr_t *attr, // NOLINT(readability/nolint) + int memory_limit); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupAttrSetMemoryUsageNotification +/// \~english @par Brief +/// Set notificatio when memory usage exceeds the specified amount +/// \~english @param [in,out] attr +/// const CL_ProcessCreateCgroupAttr_t* - Cgroup attribute pointer +/// \~english @param [in] usage_in_bytes +/// int - usage in bytes(byte) +/// \~english @param [in] event_fd +/// int - File dexcriptor created by system call eventfd() +/// \~english @par +/// CL_ProcessCreateCgroupAttr_t struct +/// \~english @code +/// typedef struct { +/// char body[24]; +/// } CL_ProcessCreateCgroupAttr_t; +/// @endcode +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Initialize attr with CL_ProcessCreateCgroupAttrInit +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the pointer of the process attribute specified (attr) in the argument is NULL, +/// set errno to EINVAL, -1 is returned. +/// - When event_fd is negative for a file descriptor created by system call eventfd(), +/// set errno to EINVAL, -1 is returned. +/// \~english @par Detail +/// event_fd is notifued when memory usage exceeds argument usage_in_bytes.\n +/// See eventfd for details of event_fd.\n +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupAttrSetMemoryUsageNotification( // NOLINT(readability/nolint) + CL_ProcessCreateCgroupAttr_t *attr, int usage_in_bytes, int event_fd); + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupDelete +/// \~english @par Brief +/// Delete Cgroup +/// \~english @param [in] cgroup_name +/// const char* - cgroup name +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Need to be runnning CL_ProcessCreateCgroupCreate. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the Cgroup (cgroup_name) name specified inthe argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the area for directory path name of the CPU subsystem of Cgroup and +/// memory subsystem of Cgroup could not be allocated, set errno to EINVAL, -1 is returned. +/// - When the area for the directory path name of the memory subsystem of Cgroup cannot be allocated and +/// the directory for the CPU subsystem of Cgroup does not exist, set errno to EINVAL, -1 is returned. +/// - When the directory for the CPU subsystem of Cgroup does not exist and +/// the area for the directory path name of the memory subsystem of Cgroup cannot be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When the directory for the memory subsystem of Cgroup and +/// the directory for the CPU subsystem of Cgroup does not exist, set errno to EINVAL, -1 is returned. +/// - When the directory for the memory subsystem of Cgroup could not be deleted, -1 is returned. +/// - When the directory for the CPU subsystem of Cgroup could not be deleted, -1 is returned. +/// \~english @par Detail +/// Delete Cgroup. If there is a proess belonging to Cgroup, error code (EBUSY) is returned.\n +/// \~english @par +/// Success is also notified in the following cases:\n +/// - When the area for directory path name of memory subsyste Cgroup could not be allocated +/// but CPU subsystem of Cgroup was deleted successfully. +/// - When the directory for the memory subsystem of Cgroup does not exist, +/// but CPU subsystem of Cgroup was deleted successfully. +/// - When the area for directory path name of CPU subsyste Cgroup could not be allocated +/// but memory subsystem of Cgroup was deleted successfully. +/// - When the directory for the CPU subsystem of Cgroup does not exist, +/// but memory subsystem of Cgroup was deleted successfully. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Open Close +/// \~english @see +/// CL_ProcessCreateCgroupCreate +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupDelete(const char *cgroup_name); // NOLINT(readability/nolint) + +//////////////////////////////////////////////////////////////////////////////////// +/// \ingroup CL_ProcessCreateCgroupClassify +/// \~english @par Brief +/// Move process to the Cgroup +/// \~english @param [in,out] cgroup_name +/// const char* - Destination A name +/// \~english @param [in] pid +/// pid_t - process ID +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// - Need to be running CL_ProcessCreateCgroupCreate. +/// \~english @par Change of internal state +/// - Change of internal state according to the API does not occur. +/// \~english @par Conditions of processing failure +/// - When the Cgroup (cgroup_name) specified in the argument is NULL, set errno to EINVAL, -1 is returned. +/// - When the area for directory path name of memory subsystem of Cgroup and +/// CPU subsystem of Cgroup could not be allocated, set errno to EINVAL, -1 is returned. +/// - When the area for directory path name of memory subsystem of Cgroup could not be allocated, +/// and the directory for CPU subsystem of Cgroup does not exist, set errno to EINVAL, -1 is returned. +/// - When the directory for memory subsystem of Cgroup does not exist and +/// the directory for CU subsystem of Cgroup could not allocated , set errno to EINVAL, -1 is returned. +/// - When the directory for the memory subsystem of Cgroup and +/// the directory for the CPU subsystem of Cgroup does not exist, set errno to EINVAL, -1 is returned. +/// - When the area for directory path name of the memory subsystem of Cgroup could not allocated, +/// set errno to EINVAL, -1 is returned. +/// - When the file descripter for the memory subsystem of Cgroup could not be obtained, -1 is returned. +/// - When pid could not be written to the file for memory subsystem of Cgroup, -1 is returned. +/// - When the area for directory path name of the CPU subsystem of Cgroup could not be allocated, +/// set errno to EINVAL, -1 is returned. +/// - When the file decsripter for the CPU subsystem of Cgroup could not be allocated, -1 is returned. +/// - When pid could not be written to the file for CPU subsystem of Cgroup, -1 is returned. +/// \~english @par Detail +/// Move process to the Cgroup.\n +/// \~english @par +/// Success is also notified in the following cases:\n +/// - When the area for directory path name of memory subsyste Cgroup could not be allocated +/// but CPU subsystem of Cgroup was deleted successfully. +/// - When the directory for the memory subsystem of Cgroup does not exist, +/// but CPU subsystem of Cgroup was deleted successfully. +/// - When the area for directory path name of CPU subsyste Cgroup could not be allocated +/// but memory subsystem of Cgroup was deleted successfully. +/// - When the directory for the CPU subsystem of Cgroup does not exist, +/// but memory subsystem of Cgroup was deleted successfully. +/// \~english @par Classification +/// Public +/// \~english @par Type +/// No match +/// \~english @see +/// none +//////////////////////////////////////////////////////////////////////////////////// +int CL_ProcessCreateCgroupClassify(const char *cgroup_name, pid_t pid); // NOLINT(readability/nolint) + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _cl_process_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/cl_region.h b/common_library/client/include/native_service/cl_region.h new file mode 100644 index 00000000..0c935994 --- /dev/null +++ b/common_library/client/include/native_service/cl_region.h @@ -0,0 +1,257 @@ +/* + * @copyright Copyright (c) 2016-2019 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.h + * @brief region manage + * + */ + +#ifndef _CL_REGION_H_ // NOLINT(build/header_guard) +#define _CL_REGION_H_ // NOLINT(build/header_guard) + +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> + +#define CL_REGION_DEFAULT_SIZE (4 * 1024) + +#define CL_ALIGNOF(type) __alignof(type) + +typedef void (*cl_region_cleanup_pt)(void *data); + +typedef struct cl_region_cleanup_s cl_region_cleanup_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// region cleanup struct +///////////////////////////////////////////////////////////////////////////////////// +struct cl_region_cleanup_s { // NOLINT(readability/nolint) + cl_region_cleanup_pt handler; + void *data; + cl_region_cleanup_t *next; +}; + + +typedef struct cl_region_large_s cl_region_large_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// region large struct +///////////////////////////////////////////////////////////////////////////////////// +struct cl_region_large_s { // NOLINT(readability/nolint) + cl_region_large_t *next; + void *alloc; + size_t size; +}; + + +typedef struct cl_region_s cl_region_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// region data struct +///////////////////////////////////////////////////////////////////////////////////// +typedef struct { + uint8_t *last; + uint8_t *end; + cl_region_t *next; + int failed; +} cl_region_data_t; + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Monitor +/// \~english @par Brief +/// region struct +///////////////////////////////////////////////////////////////////////////////////// +struct cl_region_s { // NOLINT(readability/nolint) + cl_region_data_t d; + size_t max; + cl_region_t *current; + cl_region_large_t *large; + cl_region_cleanup_t *cleanup; +}; + + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @file cl_region.h + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Region +/// \~english @par Brief +/// Region create +/// \~english @param [in] size +/// size_t - the size to create +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +cl_region_t *CL_RegionCreate(size_t size); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Region +/// \~english @par Brief +/// Region destroy +/// \~english @param [in] region +/// cl_region_t * - the region to destroy +/// \~english @retval 0 Success +/// \~english @retval -1 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +void CL_RegionDestroy(cl_region_t *region); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Region +/// \~english @par Brief +/// Region allocation +/// \~english @param [in] region +/// cl_region_t * - the region to allocate +/// \~english @param [in] size +/// size_t * - the size to allocate +/// \~english @param [in] align_size +/// size_t * - the size to align +/// \~english @retval the pointer to region allocated +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +#define CL_RegionAlloc(region, type, length) \ + cl_region_alloc(region, sizeof(type) * length, CL_ALIGNOF(type)) +void *cl_region_alloc(cl_region_t *region, size_t size, size_t align_size); // NOLINT(readability/nolint) + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Region +/// \~english @par Brief +/// Region free +/// \~english @param [in] region +/// cl_region_t * - the region to free +/// \~english @param [in] p +/// void * - the pointer to region +/// \~english @retval true Success +/// \~english @retval false Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +bool CL_RegionFree(cl_region_t *region, void *p); // NOLINT(readability/nolint) + + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Region +/// \~english @par Brief +/// add region cleanup +/// \~english @param [in] region +/// cl_region_t * - the region to allocate +/// \~english @param [in] size +/// size_t * - the size to add +/// \~english @param [in] align_size +/// size_t * - the size to align +/// \~english @retval the pointer to region cleanup added +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +#define CL_RegionCleanupAdd(region, type, length) \ + cl_region_cleanup_add(region, sizeof(type) * length, CL_ALIGNOF(type)) +cl_region_cleanup_t *cl_region_cleanup_add(cl_region_t *region, size_t size, // NOLINT(readability/nolint) + size_t align_size); + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#ifdef __cplusplus +} +#endif + + +#endif /* _CL_REGION_H_ */ // NOLINT(build/header_guard) + +/* vim:set ts=8 sw=2 sts=2: */ diff --git a/common_library/client/include/native_service/cl_sem.h b/common_library/client/include/native_service/cl_sem.h new file mode 100644 index 00000000..a42f7ac4 --- /dev/null +++ b/common_library/client/include/native_service/cl_sem.h @@ -0,0 +1,73 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ +#ifndef _cl_sem_h_ // NOLINT(build/header_guard) +#define _cl_sem_h_ // NOLINT(build/header_guard) + +#include <semaphore.h> + +#ifdef __cplusplus +#define EXT_C extern "C" +#else +#define EXT_C +#endif // __cplusplus + +/** + * @file cl_sem.h + * @brief \~english This file contains the api of sem wait. + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +///////////////////////////////////////////////////////////////////////////////////// +/// \ingroup Sem +/// \~english @par Brief +/// Sem wait +/// \~english @param [in] semid +/// sem_t * - the pointer to the union sem_t +/// \~english @param [in] timeout +/// unsigned int - the count of timeout +/// \~english @retval 0 Success +/// \~english @retval not 0 Error +/// \~english @par Prerequisite +/// None +/// \~english @par Change of internal state +/// None +/// \~english @par Conditions of processing failure +/// None +/// \~english @par Classification +/// Public +/// \~english @par Type +/// Sync +/// \~english @par Detail +/// None +/// \~english @see None +//////////////////////////////////////////////////////////////////////////////////// +EXT_C int CL_SemWait(sem_t *semid, unsigned int timeout); // NOLINT(readability/nolint) + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem +#endif // #ifndef _cl_sem_h_ // NOLINT(build/header_guard) diff --git a/common_library/client/include/native_service/common_library.h b/common_library/client/include/native_service/common_library.h new file mode 100644 index 00000000..37b5e587 --- /dev/null +++ b/common_library/client/include/native_service/common_library.h @@ -0,0 +1,48 @@ +// +// @copyright Copyright (c) 2017-2019 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. +// +#ifndef NATIVESERVICE_COMMONLIBRARY_H_ // NOLINT(build/header_guard) +#define NATIVESERVICE_COMMONLIBRARY_H_ + +/** + * @file common_library.h + * @brief \~english include all common_library head files + */ + +/** @addtogroup BaseSystem + * @{ + */ +/** @addtogroup native_service + * @ingroup BaseSystem + * @{ + */ +/** @addtogroup common_library + * @ingroup native_service + * @{ + */ + +#include <native_service/cl_process.h> +#include <native_service/cl_sem.h> +#include <native_service/cl_monitor.h> +#include <native_service/cl_lock.h> +#include <native_service/cl_region.h> +#include <native_service/cl_lockid.h> + + +/** @}*/ // end of common_library +/** @}*/ // end of NativeService +/** @}*/ // end of BaseSystem + +#endif // NATIVESERVICE_COMMONLIBRARY_H_ diff --git a/common_library/client/libcommon.ver b/common_library/client/libcommon.ver new file mode 100644 index 00000000..1558e178 --- /dev/null +++ b/common_library/client/libcommon.ver @@ -0,0 +1,30 @@ +/* + * @copyright Copyright (c) 2016-2019 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. + */ + +# +# CommonLib version script +# +{ + global: + ### .text section ### + CL_*; + cl_region_alloc; + cl_region_cleanup_add; + ### .data section ### + local: + *; +}; + diff --git a/common_library/client/src/cl_cgroup.c b/common_library/client/src/cl_cgroup.c new file mode 100644 index 00000000..c889187c --- /dev/null +++ b/common_library/client/src/cl_cgroup.c @@ -0,0 +1,260 @@ +/* + * @copyright Copyright (c) 2016-2019 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/common_library/client/src/cl_lock.c b/common_library/client/src/cl_lock.c new file mode 100644 index 00000000..6e50d309 --- /dev/null +++ b/common_library/client/src/cl_lock.c @@ -0,0 +1,221 @@ +/* + * @copyright Copyright (c) 2016-2019 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/common_library/client/src/cl_monitor.c b/common_library/client/src/cl_monitor.c new file mode 100644 index 00000000..141a0283 --- /dev/null +++ b/common_library/client/src/cl_monitor.c @@ -0,0 +1,442 @@ +/* + * @copyright Copyright (c) 2016-2019 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/common_library/client/src/cl_process.c b/common_library/client/src/cl_process.c new file mode 100644 index 00000000..5d798966 --- /dev/null +++ b/common_library/client/src/cl_process.c @@ -0,0 +1,1176 @@ +/* + * @copyright Copyright (c) 2016-2019 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, ¶m) < 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; + + 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); + CPU_SET((size_t)ia->cpu_assign - 1, &set); // LCOV_EXCL_BR_LINE 15:CPU_SET define at sched.h + // 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; +} + +/** + * 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 || cpu_assign > 2) { + 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/common_library/client/src/cl_region.c b/common_library/client/src/cl_region.c new file mode 100644 index 00000000..594e8357 --- /dev/null +++ b/common_library/client/src/cl_region.c @@ -0,0 +1,295 @@ +/* + * @copyright Copyright (c) 2016-2019 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(®ion->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/common_library/client/src/cl_sem.c b/common_library/client/src/cl_sem.c new file mode 100644 index 00000000..e2cd3cb4 --- /dev/null +++ b/common_library/client/src/cl_sem.c @@ -0,0 +1,67 @@ +/* + * @copyright Copyright (c) 2016-2019 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; +} + diff --git a/native_service.mk b/native_service.mk new file mode 100644 index 00000000..5cf73b78 --- /dev/null +++ b/native_service.mk @@ -0,0 +1,44 @@ +############################################################# +# +# Common Makefile for native_service +# Copyright (C) 2017-2019 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. +# +############################################################# + +CURRENT_DIR := $(dir $(lastword $(MAKEFILE_LIST))) + +############################################################# +# COMPONENT_NAME must not be blank and be named snake_case + +COMPONENT_NAME := native_service + +############################################################# + + + +############################################################# +# You can add several flags and libraries. +# When you add -I or -L path, DO NOT USE relative path. +# Instead, use $(CURRENT_DIR) variable +# that indicates the path this .mk file is stored. + +COMPONENT_CFLAGS := +COMPONENT_CXXFLAGS := +COMPONENT_LDLIBS := +COMPONENT_LDFLAGS := + +############################################################## + +include $(SDKTARGETSYSROOT)/usr/agl/share/agl.mk |