shim_ipc_child.c 11 KB

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