shim_ipc_child.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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 ppid, IDTYPE tid,
  29. unsigned int exitcode, 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. #endif
  36. struct shim_thread * thread = __lookup_thread(tid);
  37. if (thread) {
  38. int ret = 0;
  39. //assert(thread->vmid == vmid && !thread->in_vm);
  40. thread->exit_code = -exitcode;
  41. thread->term_signal = term_signal;
  42. #ifdef PROFILE
  43. thread->exit_time = exit_time;
  44. #endif
  45. ret = thread_exit(thread, false);
  46. put_thread(thread);
  47. return ret;
  48. }
  49. struct shim_simple_thread * sthread = __lookup_simple_thread(tid);
  50. if (!sthread) {
  51. sthread = get_new_simple_thread();
  52. sthread->vmid = vmid;
  53. sthread->tid = tid;
  54. add_simple_thread(sthread);
  55. }
  56. sthread->is_alive = 0;
  57. sthread->exit_code = -exitcode;
  58. sthread->term_signal = term_signal;
  59. #ifdef PROFILE
  60. sthread->exit_time = exit_time;
  61. #endif
  62. DkEventSet(sthread->exit_event);
  63. put_simple_thread(sthread);
  64. return 0;
  65. }
  66. void ipc_parent_exit (struct shim_ipc_port * port, IDTYPE vmid,
  67. unsigned int exitcode)
  68. {
  69. debug("ipc port %p of process %u closed suggests parent exiting\n",
  70. port, vmid);
  71. struct shim_ipc_info * parent = NULL;
  72. lock(&cur_process.lock);
  73. if (parent && vmid == cur_process.parent->vmid) {
  74. parent = cur_process.parent;
  75. cur_process.parent = NULL;
  76. }
  77. unlock(&cur_process.lock);
  78. if (parent)
  79. put_ipc_info(parent);
  80. }
  81. struct thread_info {
  82. IDTYPE vmid;
  83. unsigned int exitcode;
  84. unsigned int term_signal;
  85. };
  86. static int child_sthread_exit (struct shim_simple_thread * thread, void * arg,
  87. bool * unlocked)
  88. {
  89. struct thread_info * info = (struct thread_info *) arg;
  90. if (thread->vmid == info->vmid) {
  91. if (thread->is_alive) {
  92. thread->exit_code = -info->exitcode;
  93. thread->term_signal = info->term_signal;
  94. thread->is_alive = false;
  95. DkEventSet(thread->exit_event);
  96. }
  97. return 1;
  98. }
  99. return 0;
  100. }
  101. static int child_thread_exit (struct shim_thread * thread, void * arg,
  102. bool * unlocked)
  103. {
  104. struct thread_info * info = (struct thread_info *) arg;
  105. if (thread->vmid == info->vmid) {
  106. if (thread->is_alive) {
  107. thread->exit_code = -info->exitcode;
  108. thread->term_signal = info->term_signal;
  109. thread_exit(thread, false);
  110. }
  111. return 1;
  112. }
  113. return 0;
  114. }
  115. int remove_child_thread (IDTYPE vmid, unsigned int exitcode, unsigned int term_signal)
  116. {
  117. struct thread_info info = { .vmid = vmid, .exitcode = exitcode, .term_signal = term_signal };
  118. int nkilled = 0, ret;
  119. assert(vmid != cur_process.vmid);
  120. if ((ret = walk_thread_list(&child_thread_exit, &info, false)) > 0)
  121. nkilled += ret;
  122. if ((ret = walk_simple_thread_list(&child_sthread_exit, &info, false)) > 0)
  123. nkilled += ret;
  124. if (!nkilled)
  125. debug("child port closed, no thread exited\n");
  126. return 0;
  127. }
  128. void ipc_child_exit (struct shim_ipc_port * port, IDTYPE vmid,
  129. unsigned int exitcode)
  130. {
  131. debug("ipc port %p of process %u closed suggests child exiting\n",
  132. port, vmid);
  133. /*
  134. * Chia-Che 12/12/2017:
  135. * Can't assume there is a termination signal. this callback
  136. * is only called when the child process is not responding, and
  137. * under this circumstance can only assume the child process
  138. * has encountered severe failure, hence SIGKILL.
  139. */
  140. remove_child_thread(vmid, exitcode, SIGKILL);
  141. }
  142. static struct shim_ipc_port * get_parent_port (IDTYPE * dest)
  143. {
  144. struct shim_ipc_port * port = NULL;
  145. lock(&cur_process.lock);
  146. if (cur_process.parent && (port = cur_process.parent->port)) {
  147. get_ipc_port(port);
  148. *dest = cur_process.parent->vmid;
  149. }
  150. unlock(&cur_process.lock);
  151. return port;
  152. }
  153. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_turnaround, ipc);
  154. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_send, ipc);
  155. DEFINE_PROFILE_INTERVAL(ipc_cld_exit_callback, ipc);
  156. int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode, unsigned int term_signal)
  157. {
  158. __attribute__((unused)) unsigned long send_time = GET_PROFILE_INTERVAL();
  159. BEGIN_PROFILE_INTERVAL_SET(send_time);
  160. int ret = 0;
  161. struct shim_ipc_msg * msg =
  162. create_ipc_msg_on_stack(IPC_CLD_EXIT,
  163. sizeof(struct shim_ipc_cld_exit), 0);
  164. struct shim_ipc_cld_exit * msgin =
  165. (struct shim_ipc_cld_exit *) &msg->msg;
  166. msgin->ppid = ppid;
  167. msgin->tid = tid;
  168. msgin->exitcode = exitcode;
  169. msgin->term_signal = term_signal;
  170. #ifdef PROFILE
  171. msgin->time = send_time;
  172. #endif
  173. debug("ipc broadcast: IPC_CLD_EXIT(%u, %u, %d)\n", ppid, tid, exitcode);
  174. ret = broadcast_ipc(msg, NULL, 0, IPC_PORT_DIRPRT|IPC_PORT_DIRCLD);
  175. SAVE_PROFILE_INTERVAL(ipc_cld_exit_send);
  176. return ret;
  177. }
  178. int ipc_cld_exit_callback (IPC_CALLBACK_ARGS)
  179. {
  180. struct shim_ipc_cld_exit * msgin =
  181. (struct shim_ipc_cld_exit *) &msg->msg;
  182. #ifdef PROFILE
  183. unsigned long time = msgin->time;
  184. #else
  185. unsigned long time = 0;
  186. #endif
  187. BEGIN_PROFILE_INTERVAL_SET(time);
  188. SAVE_PROFILE_INTERVAL(ipc_cld_exit_turnaround);
  189. debug("ipc callback from %u: IPC_CLD_EXIT(%u, %u, %d)\n",
  190. msg->src, msgin->ppid, msgin->tid, msgin->exitcode);
  191. int ret = ipc_thread_exit(msg->src, msgin->ppid, msgin->tid,
  192. msgin->exitcode, msgin->term_signal,
  193. time);
  194. SAVE_PROFILE_INTERVAL(ipc_cld_exit_callback);
  195. return ret;
  196. }
  197. DEFINE_PROFILE_INTERVAL(ipc_cld_join_send, ipc);
  198. DEFINE_PROFILE_INTERVAL(ipc_cld_join_callback, ipc);
  199. int ipc_cld_join_send (IDTYPE dest)
  200. {
  201. BEGIN_PROFILE_INTERVAL();
  202. struct shim_ipc_port * port = dest ?
  203. lookup_ipc_port(dest, IPC_PORT_DIRPRT) :
  204. get_parent_port(&dest);
  205. if (!port)
  206. return -ESRCH;
  207. struct shim_ipc_msg * msg =
  208. create_ipc_msg_on_stack(IPC_CLD_JOIN, 0, dest);
  209. debug("ipc send to %u: IPC_CLD_JOIN\n", dest);
  210. int ret = send_ipc_message(msg, port);
  211. add_ipc_port(port, dest, IPC_PORT_DIRPRT, NULL);
  212. put_ipc_port(port);
  213. SAVE_PROFILE_INTERVAL(ipc_cld_join_send);
  214. return ret;
  215. }
  216. int ipc_cld_join_callback (IPC_CALLBACK_ARGS)
  217. {
  218. BEGIN_PROFILE_INTERVAL();
  219. debug("ipc callback from %u: IPC_CLD_JOIN\n", msg->src);
  220. add_ipc_port(port, msg->src, IPC_PORT_DIRCLD, NULL);
  221. SAVE_PROFILE_INTERVAL(ipc_cld_join_callback);
  222. return 0;
  223. }
  224. DEFINE_PROFILE_INTERVAL(ipc_send_profile, ipc);
  225. #ifdef PROFILE
  226. int ipc_cld_profile_send (void)
  227. {
  228. IDTYPE dest;
  229. struct shim_ipc_port * port = get_parent_port(&dest);
  230. if (!port)
  231. return -ESRCH;
  232. unsigned long time = GET_PROFILE_INTERVAL();
  233. int nsending = 0;
  234. for (int i = 0 ; i < N_PROFILE ; i++)
  235. switch (PROFILES[i].type) {
  236. case OCCURENCE:
  237. if (atomic_read(&PROFILES[i].val.occurence.count))
  238. nsending++;
  239. break;
  240. case INTERVAL:
  241. if (atomic_read(&PROFILES[i].val.interval.count))
  242. nsending++;
  243. break;
  244. case CATEGORY:
  245. break;
  246. }
  247. struct shim_ipc_msg * msg = create_ipc_msg_on_stack(
  248. IPC_CLD_PROFILE,
  249. sizeof(struct shim_ipc_cld_profile) +
  250. sizeof(struct profile_val) *
  251. nsending, dest);
  252. struct shim_ipc_cld_profile * msgin =
  253. (struct shim_ipc_cld_profile *) &msg->msg;
  254. int nsent = 0;
  255. for (int i = 0 ; i < N_PROFILE && nsent < nsending ; i++)
  256. switch (PROFILES[i].type) {
  257. case OCCURENCE: {
  258. unsigned long count =
  259. atomic_read(&PROFILES[i].val.occurence.count);
  260. if (count) {
  261. msgin->profile[nsent].idx = i + 1;
  262. msgin->profile[nsent].val.occurence.count = count;
  263. debug("send %s: %lu times\n", PROFILES[i].name, count);
  264. nsent++;
  265. }
  266. break;
  267. }
  268. case INTERVAL: {
  269. unsigned long count =
  270. atomic_read(&PROFILES[i].val.interval.count);
  271. if (count) {
  272. msgin->profile[nsent].idx = i + 1;
  273. msgin->profile[nsent].val.interval.count = count;
  274. msgin->profile[nsent].val.interval.time =
  275. atomic_read(&PROFILES[i].val.interval.time);
  276. debug("send %s: %lu times, %lu msec\n", PROFILES[i].name,
  277. count, msgin->profile[nsent].val.interval.time);
  278. nsent++;
  279. }
  280. break;
  281. }
  282. case CATEGORY:
  283. break;
  284. }
  285. msgin->time = time;
  286. msgin->nprofile = nsent;
  287. debug("ipc send to %u: IPC_CLD_PROFILE\n", dest);
  288. int ret = send_ipc_message(msg, port);
  289. put_ipc_port(port);
  290. return ret;
  291. }
  292. int ipc_cld_profile_callback (IPC_CALLBACK_ARGS)
  293. {
  294. struct shim_ipc_cld_profile * msgin =
  295. (struct shim_ipc_cld_profile *) &msg->msg;
  296. debug("ipc callback from %u: IPC_CLD_PROFILE\n", msg->src);
  297. for (int i = 0 ; i < msgin->nprofile ; i++) {
  298. int idx = msgin->profile[i].idx;
  299. if (idx == 0)
  300. break;
  301. idx--;
  302. switch (PROFILES[idx].type) {
  303. case OCCURENCE:
  304. debug("receive %s: %u times\n", PROFILES[idx].name,
  305. msgin->profile[i].val.occurence.count);
  306. atomic_add(msgin->profile[i].val.occurence.count,
  307. &PROFILES[idx].val.occurence.count);
  308. break;
  309. case INTERVAL:
  310. debug("receive %s: %u times, %lu msec\n", PROFILES[idx].name,
  311. msgin->profile[i].val.interval.count,
  312. msgin->profile[i].val.interval.time);
  313. atomic_add(msgin->profile[i].val.interval.count,
  314. &PROFILES[idx].val.interval.count);
  315. atomic_add(msgin->profile[i].val.interval.time,
  316. &PROFILES[idx].val.interval.time);
  317. break;
  318. case CATEGORY:
  319. break;
  320. }
  321. }
  322. SAVE_PROFILE_INTERVAL_SINCE(ipc_send_profile, msgin->time);
  323. return 0;
  324. }
  325. #endif