shim_ipc_child.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. /* Copyright (C) 2014 Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * shim_ipc_helper.c
  17. *
  18. * This file contains functions and callbacks to handle IPC between parent
  19. * processes and their children.
  20. */
  21. #include <shim_internal.h>
  22. #include <shim_thread.h>
  23. #include <shim_handle.h>
  24. #include <shim_ipc.h>
  25. #include <shim_utils.h>
  26. #include <shim_profile.h>
  27. #include <pal.h>
  28. #include <pal_error.h>
  29. #include <errno.h>
  30. static int ipc_thread_exit (IDTYPE vmid, IDTYPE ppid, IDTYPE tid,
  31. unsigned int exitcode, unsigned int term_signal, unsigned long exit_time)
  32. {
  33. assert(vmid != cur_process.vmid);
  34. #ifdef PROFILE
  35. if (!exit_time)
  36. exit_time = GET_PROFILE_INTERVAL();
  37. #endif
  38. struct shim_thread * thread = __lookup_thread(tid);
  39. if (thread) {
  40. int ret = 0;
  41. //assert(thread->vmid == vmid && !thread->in_vm);
  42. thread->exit_code = -exitcode;
  43. thread->term_signal = term_signal;
  44. #ifdef PROFILE
  45. thread->exit_time = exit_time;
  46. #endif
  47. ret = thread_exit(thread, false);
  48. put_thread(thread);
  49. return ret;
  50. }
  51. struct shim_simple_thread * sthread = __lookup_simple_thread(tid);
  52. if (!sthread) {
  53. sthread = get_new_simple_thread();
  54. sthread->vmid = vmid;
  55. sthread->tid = tid;
  56. add_simple_thread(sthread);
  57. }
  58. sthread->is_alive = 0;
  59. sthread->exit_code = -exitcode;
  60. sthread->term_signal = term_signal;
  61. #ifdef PROFILE
  62. sthread->exit_time = exit_time;
  63. #endif
  64. DkEventSet(sthread->exit_event);
  65. put_simple_thread(sthread);
  66. return 0;
  67. }
  68. void ipc_parent_exit (struct shim_ipc_port * port, IDTYPE vmid,
  69. unsigned int exitcode)
  70. {
  71. debug("ipc port %p of process %u closed suggests parent exiting\n",
  72. port, vmid);
  73. struct shim_ipc_info * parent = NULL;
  74. lock(cur_process.lock);
  75. if (parent && vmid == cur_process.parent->vmid) {
  76. parent = cur_process.parent;
  77. cur_process.parent = NULL;
  78. }
  79. unlock(cur_process.lock);
  80. if (parent)
  81. put_ipc_info(parent);
  82. }
  83. struct thread_info {
  84. IDTYPE vmid;
  85. unsigned int exitcode;
  86. unsigned int term_signal;
  87. };
  88. static int child_sthread_exit (struct shim_simple_thread * thread, void * arg,
  89. bool * unlocked)
  90. {
  91. struct thread_info * info = (struct thread_info *) arg;
  92. if (thread->vmid == info->vmid) {
  93. if (thread->is_alive) {
  94. thread->exit_code = -info->exitcode;
  95. thread->term_signal = info->term_signal;
  96. thread->is_alive = false;
  97. DkEventSet(thread->exit_event);
  98. }
  99. return 1;
  100. }
  101. return 0;
  102. }
  103. static int child_thread_exit (struct shim_thread * thread, void * arg,
  104. bool * unlocked)
  105. {
  106. struct thread_info * info = (struct thread_info *) arg;
  107. if (thread->vmid == info->vmid) {
  108. if (thread->is_alive) {
  109. thread->exit_code = -info->exitcode;
  110. thread->term_signal = info->term_signal;
  111. thread_exit(thread, false);
  112. }
  113. return 1;
  114. }
  115. return 0;
  116. }
  117. int remove_child_thread (IDTYPE vmid, unsigned int exitcode, unsigned int term_signal)
  118. {
  119. struct thread_info info = { .vmid = vmid, .exitcode = exitcode, .term_signal = term_signal };
  120. int nkilled = 0, ret;
  121. assert(vmid != cur_process.vmid);
  122. if ((ret = walk_thread_list(&child_thread_exit, &info, false)) > 0)
  123. nkilled += ret;
  124. if ((ret = walk_simple_thread_list(&child_sthread_exit, &info, false)) > 0)
  125. nkilled += ret;
  126. if (!nkilled)
  127. debug("child port closed, no thread exited\n");
  128. return 0;
  129. }
  130. void ipc_child_exit (struct shim_ipc_port * port, IDTYPE vmid,
  131. unsigned int exitcode)
  132. {
  133. debug("ipc port %p of process %u closed suggests child exiting\n",
  134. port, vmid);
  135. /*
  136. * Chia-Che 12/12/2017:
  137. * Can't assume there is a termination signal. this callback
  138. * is only called when the child process is not responding, and
  139. * under this circumstance can only assume the child process
  140. * has encountered severe failure, hence SIGKILL.
  141. */
  142. remove_child_thread(vmid, exitcode, SIGKILL);
  143. }
  144. static struct shim_ipc_port * get_parent_port (IDTYPE * dest)
  145. {
  146. struct shim_ipc_port * port = NULL;
  147. lock(cur_process.lock);
  148. if (cur_process.parent && (port = cur_process.parent->port)) {
  149. get_ipc_port(port);
  150. *dest = cur_process.parent->vmid;
  151. }
  152. unlock(cur_process.lock);
  153. return port;
  154. }
  155. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_turnaround, ipc);
  156. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_send, ipc);
  157. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_callback, ipc);
  158. int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode, unsigned int term_signal)
  159. {
  160. unsigned long send_time = GET_PROFILE_INTERVAL();
  161. BEGIN_PROFILE_INTERVAL_SET(send_time);
  162. int ret = 0;
  163. struct shim_ipc_msg * msg =
  164. create_ipc_msg_on_stack(IPC_CLD_EXIT,
  165. sizeof(struct shim_ipc_cld_exit), 0);
  166. struct shim_ipc_cld_exit * msgin =
  167. (struct shim_ipc_cld_exit *) &msg->msg;
  168. msgin->ppid = ppid;
  169. msgin->tid = tid;
  170. msgin->exitcode = exitcode;
  171. msgin->term_signal = term_signal;
  172. #ifdef PROFILE
  173. msgin->time = send_time;
  174. #endif
  175. debug("ipc broadcast: IPC_CLD_EXIT(%u, %u, %d)\n", ppid, tid, exitcode);
  176. ret = broadcast_ipc(msg, NULL, 0, IPC_PORT_DIRPRT|IPC_PORT_DIRCLD);
  177. SAVE_PROFILE_INTERVAL(ipc_cld_exit_send);
  178. return ret;
  179. }
  180. int ipc_cld_exit_callback (IPC_CALLBACK_ARGS)
  181. {
  182. struct shim_ipc_cld_exit * msgin =
  183. (struct shim_ipc_cld_exit *) &msg->msg;
  184. #ifdef PROFILE
  185. unsigned long time = msgin->time;
  186. #else
  187. unsigned long time = 0;
  188. #endif
  189. BEGIN_PROFILE_INTERVAL_SET(time);
  190. SAVE_PROFILE_INTERVAL(ipc_cld_exit_turnaround);
  191. debug("ipc callback from %u: IPC_CLD_EXIT(%u, %u, %d)\n",
  192. msg->src, msgin->ppid, msgin->tid, msgin->exitcode);
  193. int ret = ipc_thread_exit(msg->src, msgin->ppid, msgin->tid,
  194. msgin->exitcode, msgin->term_signal,
  195. time);
  196. SAVE_PROFILE_INTERVAL(ipc_cld_exit_callback);
  197. return ret;
  198. }
  199. DEFINE_PROFILE_INTERVAL(ipc_cld_join_send, ipc);
  200. DEFINE_PROFILE_INTERVAL(ipc_cld_join_callback, ipc);
  201. int ipc_cld_join_send (IDTYPE dest)
  202. {
  203. BEGIN_PROFILE_INTERVAL();
  204. struct shim_ipc_port * port = dest ?
  205. lookup_ipc_port(dest, IPC_PORT_DIRPRT) :
  206. get_parent_port(&dest);
  207. if (!port)
  208. return -ESRCH;
  209. struct shim_ipc_msg * msg =
  210. create_ipc_msg_on_stack(IPC_CLD_JOIN, 0, dest);
  211. debug("ipc send to %u: IPC_CLD_JOIN\n", dest);
  212. int ret = send_ipc_message(msg, port);
  213. add_ipc_port(port, dest, IPC_PORT_DIRPRT, NULL);
  214. put_ipc_port(port);
  215. SAVE_PROFILE_INTERVAL(ipc_cld_join_send);
  216. return ret;
  217. }
  218. int ipc_cld_join_callback (IPC_CALLBACK_ARGS)
  219. {
  220. BEGIN_PROFILE_INTERVAL();
  221. debug("ipc callback from %u: IPC_CLD_JOIN\n", msg->src);
  222. add_ipc_port(port, msg->src, IPC_PORT_DIRCLD, NULL);
  223. SAVE_PROFILE_INTERVAL(ipc_cld_join_callback);
  224. return 0;
  225. }
  226. DEFINE_PROFILE_INTERVAL(ipc_send_profile, ipc);
  227. #ifdef PROFILE
  228. int ipc_cld_profile_send (void)
  229. {
  230. IDTYPE dest;
  231. struct shim_ipc_port * port = get_parent_port(&dest);
  232. if (!port)
  233. return -ESRCH;
  234. unsigned long time = GET_PROFILE_INTERVAL();
  235. int nsending = 0;
  236. for (int i = 0 ; i < N_PROFILE ; i++)
  237. switch (PROFILES[i].type) {
  238. case OCCURENCE:
  239. if (atomic_read(&PROFILES[i].val.occurence.count))
  240. nsending++;
  241. break;
  242. case INTERVAL:
  243. if (atomic_read(&PROFILES[i].val.interval.count))
  244. nsending++;
  245. break;
  246. case CATAGORY:
  247. break;
  248. }
  249. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  250. IPC_CLD_PROFILE,
  251. sizeof(struct shim_ipc_cld_profile) +
  252. sizeof(struct profile_val) *
  253. nsending, dest);
  254. struct shim_ipc_cld_profile * msgin =
  255. (struct shim_ipc_cld_profile *) &msg->msg;
  256. int nsent = 0;
  257. for (int i = 0 ; i < N_PROFILE && nsent < nsending ; i++)
  258. switch (PROFILES[i].type) {
  259. case OCCURENCE: {
  260. unsigned long count =
  261. atomic_read(&PROFILES[i].val.occurence.count);
  262. if (count) {
  263. msgin->profile[nsent].idx = i + 1;
  264. msgin->profile[nsent].val.occurence.count = count;
  265. debug("send %s: %lu times\n", PROFILES[i].name, count);
  266. nsent++;
  267. }
  268. break;
  269. }
  270. case INTERVAL: {
  271. unsigned long count =
  272. atomic_read(&PROFILES[i].val.interval.count);
  273. if (count) {
  274. msgin->profile[nsent].idx = i + 1;
  275. msgin->profile[nsent].val.interval.count = count;
  276. msgin->profile[nsent].val.interval.time =
  277. atomic_read(&PROFILES[i].val.interval.time);
  278. debug("send %s: %lu times, %lu msec\n", PROFILES[i].name,
  279. count, msgin->profile[nsent].val.interval.time);
  280. nsent++;
  281. }
  282. break;
  283. }
  284. case CATAGORY:
  285. break;
  286. }
  287. msgin->time = time;
  288. msgin->nprofile = nsent;
  289. debug("ipc send to %u: IPC_CLD_PROFILE\n", dest);
  290. int ret = send_ipc_message(msg, port);
  291. put_ipc_port(port);
  292. return ret;
  293. }
  294. int ipc_cld_profile_callback (IPC_CALLBACK_ARGS)
  295. {
  296. struct shim_ipc_cld_profile * msgin =
  297. (struct shim_ipc_cld_profile *) &msg->msg;
  298. debug("ipc callback from %u: IPC_CLD_PROFILE\n", msg->src);
  299. for (int i = 0 ; i < msgin->nprofile ; i++) {
  300. int idx = msgin->profile[i].idx;
  301. if (idx == 0)
  302. break;
  303. idx--;
  304. switch (PROFILES[idx].type) {
  305. case OCCURENCE:
  306. debug("receive %s: %u times\n", PROFILES[idx].name,
  307. msgin->profile[i].val.occurence.count);
  308. atomic_add(msgin->profile[i].val.occurence.count,
  309. &PROFILES[idx].val.occurence.count);
  310. break;
  311. case INTERVAL:
  312. debug("receive %s: %u times, %lu msec\n", PROFILES[idx].name,
  313. msgin->profile[i].val.interval.count,
  314. msgin->profile[i].val.interval.time);
  315. atomic_add(msgin->profile[i].val.interval.count,
  316. &PROFILES[idx].val.interval.count);
  317. atomic_add(msgin->profile[i].val.interval.time,
  318. &PROFILES[idx].val.interval.time);
  319. break;
  320. case CATAGORY:
  321. break;
  322. }
  323. }
  324. SAVE_PROFILE_INTERVAL_SINCE(ipc_send_profile, msgin->time);
  325. return 0;
  326. }
  327. #endif