You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ipc_imp.cpp 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include "ipc_imp.h"
  2. #if __linux__
  3. #include <sys/prctl.h>
  4. #include <sys/wait.h>
  5. #endif
  6. #ifdef __ANDROID__
  7. #include <android/log.h>
  8. #include <sys/system_properties.h>
  9. #endif
  10. namespace ipc_imp {
  11. namespace {
  12. //! max count if shm
  13. #define MAX_SHM_COUNT 15
  14. struct ServerConfig {
  15. #ifdef _LITE_SUPPORT_IPC
  16. pid_t server_id;
  17. #else
  18. size_t server_id;
  19. #endif
  20. void* cb;
  21. int fd_s[2];
  22. int fd_c[2];
  23. fd_set select_s;
  24. fd_set select_c;
  25. void* shm_ptr[MAX_SHM_COUNT];
  26. size_t shm_mem_conut;
  27. //! all shm use the same shm_size
  28. size_t shm_size;
  29. };
  30. static LITE_MUTEX m_mtx;
  31. static ServerConfig server_config;
  32. #ifdef _LITE_SUPPORT_IPC
  33. static size_t config_shm_memory() {
  34. //! default config to 10MB
  35. size_t shm_size = 10 * 1024 * 1024;
  36. //! env to config LITE_DEBUG_IPC_SHM_SIZE
  37. //! for example , export LITE_DEBUG_IPC_SHM_SIZE=20, means config SHM size 20MB
  38. if (auto env = ::std::getenv("LITE_DEBUG_IPC_SHM_SIZE"))
  39. shm_size = std::stoi(env) * 1024 * 1024;
  40. #ifdef __ANDROID__
  41. //! special for Android prop, attention: getprop may need permission
  42. char buf[PROP_VALUE_MAX];
  43. if (__system_property_get("LITE_DEBUG_IPC_SHM_SIZE", buf) > 0) {
  44. shm_size = std::stoi(buf) * 1024 * 1024;
  45. }
  46. #endif
  47. return shm_size;
  48. }
  49. //! FIXME: detail at create_server(), at this stage, we only support enable lite fork
  50. //! debug by: LITE_enable_lite_ipc_debug, after issue fix, may support env:
  51. //! LITE_ENABLE_C_API_WITH_FORK_MODE
  52. // bool config_enable_debug_fork() {
  53. // //! debug off, we only support enable fork debug mode with env
  54. // //! LITE_ENABLE_C_API_WITH_FORK_MODE, not support api to config
  55. // //! as we will fork as soon as possible by __attribute__((constructor)),
  56. // //! user may not have to chance to call any normal api before it
  57. // bool ret = false;
  58. // //! env to config LITE_ENABLE_C_API_WITH_FORK_MODE
  59. // //! for example , export LITE_ENABLE_C_API_WITH_FORK_MODE=1, means enable LITE c
  60. // api
  61. // //! with fork mode
  62. // if (auto env = ::std::getenv("LITE_ENABLE_C_API_WITH_FORK_MODE")) {
  63. // if (std::stoi(env) > 0) {
  64. // ret = true;
  65. // }
  66. // }
  67. //
  68. //#ifdef __ANDROID__
  69. // //! special for Android prop, attention: getprop may need permission
  70. // char buf[PROP_VALUE_MAX];
  71. // if (__system_property_get("LITE_ENABLE_C_API_WITH_FORK_MODE", buf) > 0) {
  72. // ret = std::stoi(buf);
  73. // if (std::stoi(buf) > 0) {
  74. // ret = true;
  75. // }
  76. // }
  77. //#endif
  78. //
  79. // return ret;
  80. //}
  81. #endif
  82. static bool is_enable_debug_fork = false;
  83. //! internal recycle server when IPC_ASSERT happen
  84. static void recycle_server() {
  85. static struct timeval tv = {1, 0};
  86. struct MsgBody msg;
  87. msg.type = IPC_SERVER_EXIT;
  88. if (server_config.server_id > 0) {
  89. send_msg(&msg, &tv);
  90. }
  91. }
  92. #define ipc_unlikely(v) __builtin_expect((v), 0)
  93. #define IPC_ASSERT(expr, msg) \
  94. do { \
  95. if (ipc_unlikely(!(expr))) { \
  96. LITE_ERROR("ipc fatal error: assert failed: %s with msg: %s", #expr, msg); \
  97. recycle_server(); \
  98. __builtin_trap(); \
  99. } \
  100. } while (0)
  101. #ifdef _LITE_SUPPORT_IPC
  102. static size_t config_shm_memory_count() {
  103. //! default config to 2
  104. size_t shm_cnt = 2;
  105. //! env to config LITE_DEBUG_IPC_SHM_COUNT
  106. //! for example , export LITE_DEBUG_IPC_SHM_COUNT=8, means config SHM count 8
  107. if (auto env = ::std::getenv("LITE_DEBUG_IPC_SHM_COUNT"))
  108. shm_cnt = std::stoi(env);
  109. #ifdef __ANDROID__
  110. //! special for Android prop, attention: getprop may need permission
  111. char buf[PROP_VALUE_MAX];
  112. if (__system_property_get("LITE_DEBUG_IPC_SHM_COUNT", buf) > 0) {
  113. shm_cnt = std::stoi(buf);
  114. }
  115. #endif
  116. IPC_ASSERT(
  117. shm_cnt >= 2 && shm_cnt <= MAX_SHM_COUNT,
  118. "error config LITE_DEBUG_IPC_SHM_COUNT, should be range of [2, "
  119. "MAX_SHM_COUNT]");
  120. return shm_cnt;
  121. }
  122. #endif
  123. #ifdef _LITE_SUPPORT_IPC
  124. static void handle_remote_call(struct MsgBody* msg) {
  125. LITE_DEBUG("into %s: %d", __func__, __LINE__);
  126. IPC_ASSERT(
  127. server_config.cb,
  128. "handle_remote_call failed: can not find valid "
  129. "remote_call_cb, please call "
  130. "register_remote_call_cb firstly!!");
  131. remote_call_cb cb = (remote_call_cb)server_config.cb;
  132. cb(msg);
  133. }
  134. static void* ipc_mmap(
  135. void* addr, size_t length, int prot, int flags, int fd, off_t offset) {
  136. void* ret = mmap(addr, length, prot, flags, fd, offset);
  137. IPC_ASSERT(ret != MAP_FAILED, "call mmap failed");
  138. return ret;
  139. }
  140. static int ipc_munmap(void* addr, size_t length) {
  141. int ret = munmap(addr, length);
  142. IPC_ASSERT(0 == ret, "call munmap failed");
  143. return ret;
  144. }
  145. #endif
  146. //! start server as soon as possible
  147. //! FIXME: when use __attribute__((constructor)) on clang, will init before all
  148. //! static class object, which will lead to flatbuffer runtime issue, env config
  149. //! with init_priority, do not take effect on diff cpp src file on clang
  150. // static __attribute__((constructor)) void create_server() {
  151. void create_server() {
  152. #ifdef _LITE_SUPPORT_IPC
  153. LITE_LOCK_GUARD(m_mtx);
  154. LITE_LOG("try to config lite fork debug model");
  155. if (is_enable_debug_fork)
  156. return;
  157. is_enable_debug_fork = true;
  158. //! is_enable_debug_fork = config_enable_debug_fork();
  159. //! init default server_config
  160. server_config.server_id = 0;
  161. if (!is_enable_debug_fork)
  162. return;
  163. server_config.cb = nullptr;
  164. server_config.shm_size = config_shm_memory();
  165. server_config.shm_mem_conut = config_shm_memory_count();
  166. for (size_t i = 0; i < server_config.shm_mem_conut; i++) {
  167. server_config.shm_ptr[i] = ipc_mmap(
  168. NULL, server_config.shm_size, PROT_READ | PROT_WRITE,
  169. MAP_SHARED | MAP_ANON, -1, 0);
  170. }
  171. IPC_ASSERT(-1 != pipe(server_config.fd_s), "create server pipe failed");
  172. IPC_ASSERT(-1 != pipe(server_config.fd_c), "create client pipe failed");
  173. FD_ZERO(&server_config.select_s);
  174. FD_ZERO(&server_config.select_c);
  175. //! config server and client
  176. FD_SET(server_config.fd_s[0], &server_config.select_s);
  177. FD_SET(server_config.fd_c[0], &server_config.select_c);
  178. server_config.server_id = fork();
  179. IPC_ASSERT(server_config.server_id >= 0, "call fork failed");
  180. if (server_config.server_id > 0) {
  181. LITE_LOG("create lite_ipc_server success pid is: %d", server_config.server_id);
  182. } else {
  183. std::string server_name = "lite_ipc_server";
  184. // TODO: __APPLE__ do not support PR_SET_NAME and PR_SET_PDEATHSIG
  185. // if caller crash, no have chance to send IPC_SERVER_EXIT
  186. #if __linux__
  187. LITE_LOG("start server with name: %s....", server_name.c_str());
  188. prctl(PR_SET_NAME, (unsigned long)server_name.c_str(), 0, 0, 0);
  189. //! auto die if father crash
  190. prctl(PR_SET_PDEATHSIG, SIGKILL);
  191. #else
  192. LITE_LOG("start server....");
  193. #endif
  194. while (1) {
  195. LITE_DEBUG("lite_ipc_server wait msg now.....");
  196. int res =
  197. select(server_config.fd_s[0] + 1, &server_config.select_s, NULL,
  198. NULL, NULL);
  199. IPC_ASSERT(
  200. res > 0,
  201. "select issue happened or timeout(but we do not support timeout)");
  202. struct MsgBody msg;
  203. size_t r_size = read(server_config.fd_s[0], &msg, sizeof(msg));
  204. IPC_ASSERT(r_size == sizeof(msg), "broken pipe msg");
  205. struct MsgBody response;
  206. response.type = IPC_SERVER_RESPONSE;
  207. switch (msg.type) {
  208. case IPC_CALL_REMOTE_API:
  209. LITE_DEBUG("handle remote call");
  210. handle_remote_call(&msg);
  211. break;
  212. case IPC_CONFIG_REMOTE_HANDLE_API:
  213. LITE_DEBUG("handle register remote cb");
  214. server_config.cb = msg.cb;
  215. break;
  216. default:
  217. IPC_ASSERT(IPC_SERVER_EXIT == msg.type, "code issue happened!!");
  218. }
  219. size_t w_size = write(server_config.fd_c[1], &response, sizeof(response));
  220. IPC_ASSERT(w_size == sizeof(response), "write pip failed");
  221. if (IPC_SERVER_EXIT == msg.type) {
  222. LITE_DEBUG("handle exit now");
  223. for (size_t i = 0; i < server_config.shm_mem_conut; i++) {
  224. ipc_munmap(server_config.shm_ptr[i], server_config.shm_size);
  225. }
  226. exit(0);
  227. }
  228. }
  229. }
  230. #else
  231. //! TODO: imp for Windows with CreateProcess
  232. server_config.server_id = 0;
  233. LITE_ERROR("lite do not support fork debug ipc on this PLATFORM");
  234. __builtin_trap();
  235. return;
  236. #endif
  237. }
  238. } // namespace
  239. //////////////////////////////////////////////// api imp /////////////////////////
  240. void register_remote_call_cb(remote_call_cb cb) {
  241. IPC_ASSERT(!server_config.cb, "already register remote_call_cb");
  242. IPC_ASSERT(cb, "invalid remote_call_cb");
  243. IPC_ASSERT(server_config.server_id, "register cb need server already up");
  244. server_config.cb = (void*)cb;
  245. static struct timeval tv = {5, 0};
  246. struct MsgBody msg;
  247. msg.type = IPC_CONFIG_REMOTE_HANDLE_API;
  248. msg.cb = (void*)cb;
  249. send_msg(&msg, &tv);
  250. }
  251. struct MsgBody send_msg(struct MsgBody* msg, struct timeval* timeout) {
  252. #ifdef _LITE_SUPPORT_IPC
  253. IPC_ASSERT(server_config.server_id > 0, "server not ready");
  254. if (IPC_CALL_REMOTE_API == msg->type) {
  255. IPC_ASSERT(
  256. server_config.cb,
  257. "can not find valid remote_call_cb, please "
  258. "call register_remote_call_cb firstly!!");
  259. }
  260. //! send msg to server
  261. size_t w_size = write(server_config.fd_s[1], msg, sizeof(struct MsgBody));
  262. IPC_ASSERT(w_size == sizeof(struct MsgBody), "write pipe failed");
  263. //! now wait server response
  264. struct MsgBody response;
  265. LITE_DEBUG("wait server response");
  266. int res = select(
  267. server_config.fd_c[0] + 1, &server_config.select_c, NULL, NULL, timeout);
  268. if (0 == res) {
  269. LITE_ERROR("wait server timeout");
  270. }
  271. IPC_ASSERT(res > 0, "select issue happened or timeout");
  272. size_t r_size = read(server_config.fd_c[0], &response, sizeof(response));
  273. IPC_ASSERT(sizeof(response) == r_size, "broken pipe msg");
  274. IPC_ASSERT(IPC_SERVER_RESPONSE == response.type, "error server response type");
  275. return response;
  276. #else
  277. struct MsgBody response;
  278. LITE_ERROR("This code should not be called");
  279. __builtin_trap();
  280. return response;
  281. #endif
  282. }
  283. bool is_server() {
  284. return !server_config.server_id;
  285. }
  286. bool is_enable_ipc() {
  287. return is_enable_debug_fork;
  288. }
  289. void join_server() {
  290. #ifdef _LITE_SUPPORT_IPC
  291. if (!is_enable_debug_fork)
  292. return;
  293. int ret;
  294. waitpid(server_config.server_id, &ret, 0);
  295. if (ret) {
  296. //! when server crash, we mark server_config.server_id to 0
  297. //! to prevent handle more msg, for example recycle_server
  298. server_config.server_id = 0;
  299. }
  300. IPC_ASSERT(
  301. ret == 0, "child process exit !zero, please check server log for detail");
  302. #endif
  303. }
  304. void* base_get_shm_ptr(size_t index) {
  305. return server_config.shm_ptr[index];
  306. }
  307. size_t base_get_shm_count() {
  308. return server_config.shm_mem_conut;
  309. }
  310. size_t base_get_shm_size() {
  311. return server_config.shm_size;
  312. }
  313. void enable_lite_ipc_debug() {
  314. create_server();
  315. }
  316. } // namespace ipc_imp