shim_async.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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 OSCAR lab, 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 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 General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * shim_async.c
  17. *
  18. * This file contains functions to add asyncronous events triggered by timer.
  19. */
  20. #include <shim_internal.h>
  21. #include <shim_utils.h>
  22. #include <shim_thread.h>
  23. #include <pal.h>
  24. #include <linux_list.h>
  25. struct async_event {
  26. IDTYPE caller;
  27. struct list_head list;
  28. void (*callback) (IDTYPE caller, void * arg);
  29. void * arg;
  30. unsigned long install_time;
  31. unsigned long expire_time;
  32. };
  33. static LIST_HEAD(async_list);
  34. enum { HELPER_NOTALIVE, HELPER_ALIVE };
  35. static struct shim_atomic async_helper_state;
  36. static struct shim_thread * async_helper_thread;
  37. static PAL_HANDLE async_helper_event;
  38. static LOCKTYPE async_helper_lock;
  39. int install_async_event (unsigned long time,
  40. void (*callback) (IDTYPE caller, void * arg),
  41. void * arg)
  42. {
  43. struct async_event * event =
  44. malloc(sizeof(struct async_event));
  45. unsigned long install_time = DkSystemTimeQuery();
  46. debug("install async event at %llu\n", install_time);
  47. event->callback = callback;
  48. event->arg = arg;
  49. event->caller = get_cur_tid();
  50. event->install_time = install_time;
  51. event->expire_time = install_time + time;
  52. lock(async_helper_lock);
  53. struct async_event * tmp;
  54. struct list_head * prev = &async_list;
  55. list_for_each_entry(tmp, &async_list, list) {
  56. if (tmp->expire_time > event->expire_time)
  57. break;
  58. prev = &tmp->list;
  59. }
  60. INIT_LIST_HEAD(&event->list);
  61. list_add(&event->list, prev);
  62. unlock(async_helper_lock);
  63. if (atomic_read(&async_helper_state) == HELPER_NOTALIVE)
  64. create_async_helper();
  65. DkEventSet(async_helper_event);
  66. return 0;
  67. }
  68. int init_async (void)
  69. {
  70. atomic_set(&async_helper_state, HELPER_NOTALIVE);
  71. create_lock(async_helper_lock);
  72. async_helper_event = DkSynchronizationEventCreate(0);
  73. return 0;
  74. }
  75. #define IDLE_SLEEP_TIME 1000
  76. #define MAX_IDLE_CYCLES 100
  77. static void shim_async_helper (void * arg)
  78. {
  79. struct shim_thread * self = (struct shim_thread *) arg;
  80. if (!arg)
  81. return;
  82. __libc_tcb_t tcb;
  83. allocate_tls(&tcb, self);
  84. debug_setbuf(&tcb.shim_tcb, true);
  85. debug("set tcb to %p\n", &tcb);
  86. lock(async_helper_lock);
  87. if (self != async_helper_thread) {
  88. put_thread(self);
  89. DkThreadExit();
  90. return;
  91. }
  92. debug("async helper thread started\n");
  93. /* TSAI: we assume async helper thread will not drain the
  94. stack that PAL provides, so for efficiency, we don't
  95. swap any stack */
  96. unsigned long idle_cycles = 0;
  97. unsigned long latest_time;
  98. struct async_event * next_event, * finished_event = NULL;
  99. goto update;
  100. while (atomic_read(&async_helper_state) == HELPER_ALIVE) {
  101. lock(async_helper_lock);
  102. update:
  103. latest_time = DkSystemTimeQuery();
  104. next_event = NULL;
  105. if (!list_empty(&async_list)) {
  106. if (finished_event) {
  107. list_del(&finished_event->list);
  108. free(finished_event);
  109. finished_event = NULL;
  110. }
  111. struct async_event * tmp, * n;
  112. list_for_each_entry_safe(tmp, n, &async_list, list) {
  113. if (tmp->expire_time > latest_time) {
  114. next_event = tmp;
  115. break;
  116. }
  117. debug("async event trigger at %llu (expect expiring at %llu)\n",
  118. latest_time, tmp->expire_time);
  119. list_del(&tmp->list);
  120. tmp->callback(tmp->caller, tmp->arg);
  121. free(tmp);
  122. }
  123. idle_cycles = 0;
  124. }
  125. unlock(async_helper_lock);
  126. if (!next_event && idle_cycles++ == MAX_IDLE_CYCLES) {
  127. debug("async helper thread reach helper cycle\n");
  128. /* walking away, if someone is issueing an event,
  129. they have to create another thread */
  130. break;
  131. }
  132. unsigned long sleep_time = next_event ?
  133. next_event->expire_time - latest_time :
  134. IDLE_SLEEP_TIME;
  135. PAL_HANDLE notify = DkObjectsWaitAny(1, &async_helper_event,
  136. sleep_time);
  137. /* if we are not waken up by someone, the waiting has finished */
  138. if (!notify && next_event) {
  139. debug("async event trigger at %llu\n", next_event->expire_time);
  140. finished_event = next_event;
  141. next_event->callback(next_event->caller, next_event->arg);
  142. }
  143. }
  144. atomic_set(&async_helper_state, HELPER_NOTALIVE);
  145. lock(async_helper_lock);
  146. async_helper_thread = NULL;
  147. unlock(async_helper_lock);
  148. put_thread(self);
  149. debug("async helper thread terminated\n");
  150. DkThreadExit();
  151. }
  152. int create_async_helper (void)
  153. {
  154. int ret = 0;
  155. if (atomic_read(&async_helper_state) == HELPER_ALIVE)
  156. return 0;
  157. enable_locking();
  158. struct shim_thread * new = get_new_internal_thread();
  159. if (!new)
  160. return -ENOMEM;
  161. lock(async_helper_lock);
  162. if (atomic_read(&async_helper_state) == HELPER_ALIVE) {
  163. unlock(async_helper_lock);
  164. put_thread(new);
  165. return 0;
  166. }
  167. async_helper_thread = new;
  168. atomic_xchg(&async_helper_state, HELPER_ALIVE);
  169. unlock(async_helper_lock);
  170. PAL_HANDLE handle = thread_create(shim_async_helper, new, 0);
  171. if (!handle) {
  172. ret = -PAL_ERRNO;
  173. lock(async_helper_lock);
  174. async_helper_thread = NULL;
  175. atomic_xchg(&async_helper_state, HELPER_NOTALIVE);
  176. unlock(async_helper_lock);
  177. put_thread(new);
  178. return ret;
  179. }
  180. new->pal_handle = handle;
  181. return 0;
  182. }
  183. int terminate_async_helper (void)
  184. {
  185. if (atomic_read(&async_helper_state) != HELPER_ALIVE)
  186. return 0;
  187. lock(async_helper_lock);
  188. atomic_xchg(&async_helper_state, HELPER_NOTALIVE);
  189. unlock(async_helper_lock);
  190. DkEventSet(async_helper_event);
  191. return 0;
  192. }