Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

async.c 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <assert.h>
  21. #include <gpxe/process.h>
  22. #include <gpxe/async.h>
  23. /** @file
  24. *
  25. * Asynchronous operations
  26. *
  27. */
  28. /**
  29. * Name signal
  30. *
  31. * @v signal Signal number
  32. * @ret name Name of signal
  33. */
  34. static inline __attribute__ (( always_inline )) const char *
  35. signal_name ( enum signal signal ) {
  36. switch ( signal ) {
  37. case SIGCHLD: return "SIGCHLD";
  38. case SIGKILL: return "SIGKILL";
  39. case SIGUPDATE: return "SIGUPDATE";
  40. default: return "SIG<UNKNOWN>";
  41. }
  42. }
  43. /**
  44. * Initialise an asynchronous operation
  45. *
  46. * @v async Asynchronous operation
  47. * @v aop Asynchronous operation operations to use
  48. * @v parent Parent asynchronous operation, or NULL
  49. * @ret aid Asynchronous operation ID
  50. *
  51. * It is valid to create an asynchronous operation with no parent
  52. * operation; see async_init_orphan().
  53. */
  54. aid_t async_init ( struct async *async, struct async_operations *aop,
  55. struct async *parent ) {
  56. static aid_t aid = 1;
  57. /* Assign identifier. Negative IDs are used to indicate
  58. * errors, so avoid assigning them.
  59. */
  60. ++aid;
  61. aid &= ( ( ~( ( aid_t ) 0 ) ) >> 1 );
  62. DBGC ( async, "ASYNC %p (type %p) initialising as", async, aop );
  63. if ( parent ) {
  64. DBGC ( async, " child of ASYNC %p", parent );
  65. } else {
  66. DBGC ( async, " orphan" );
  67. }
  68. DBGC ( async, " with ID %ld\n", aid );
  69. assert ( async != NULL );
  70. assert ( aop != NULL );
  71. /* Add to hierarchy */
  72. if ( parent ) {
  73. async->parent = parent;
  74. list_add ( &async->siblings, &parent->children );
  75. }
  76. INIT_LIST_HEAD ( &async->children );
  77. /* Initialise fields */
  78. async->rc = -EINPROGRESS;
  79. async->completed = 0;
  80. async->total = 0;
  81. async->aop = aop;
  82. async->aid = aid;
  83. return async->aid;
  84. }
  85. /**
  86. * Uninitialise an asynchronous operation
  87. *
  88. * @v async Asynchronous operation
  89. *
  90. * Abandon an asynchronous operation without signalling the parent.
  91. * You may do this only during the period between calling async_init()
  92. * and returning to the parent for the first time. It is designed to
  93. * simplify the error paths of asynchronous operations that themselves
  94. * spawn further asynchronous operations.
  95. *
  96. * An example may help:
  97. *
  98. * int start_something ( ..., struct async *parent ) {
  99. * struct my_data_structure *myself;
  100. *
  101. * ... allocate memory for myself ...
  102. *
  103. * async_init ( &myself->async, &my_async_operations, parent );
  104. * if ( ( rc = start_child_operation ( ..., &myself->async ) ) != 0 ) {
  105. * async_uninit ( &myself->async );
  106. * return rc;
  107. * }
  108. *
  109. * return 0;
  110. * }
  111. *
  112. * It is valid to call async_uninit() on an asynchronous operation
  113. * that has not yet been initialised (i.e. a zeroed-out @c struct @c
  114. * async).
  115. */
  116. void async_uninit ( struct async *async ) {
  117. assert ( async != NULL );
  118. if ( async->parent ) {
  119. assert ( list_empty ( &async->children ) );
  120. DBGC ( async, "ASYNC %p uninitialising\n", async );
  121. list_del ( &async->siblings );
  122. }
  123. }
  124. /**
  125. * SIGCHLD 'ignore' handler
  126. *
  127. * @v async Asynchronous operation
  128. * @v signal Signal received
  129. */
  130. static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
  131. aid_t waited_aid;
  132. assert ( async != NULL );
  133. assert ( signal == SIGCHLD );
  134. /* Reap the child */
  135. waited_aid = async_wait ( async, NULL, 0 );
  136. assert ( waited_aid >= 0 );
  137. }
  138. /**
  139. * 'Ignore' signal handler
  140. *
  141. * @v async Asynchronous operation
  142. * @v signal Signal received
  143. */
  144. void async_ignore_signal ( struct async *async, enum signal signal ) {
  145. DBGC ( async, "ASYNC %p using ignore handler for %s\n",
  146. async, signal_name ( signal ) );
  147. assert ( async != NULL );
  148. switch ( signal ) {
  149. case SIGCHLD:
  150. async_ignore_sigchld ( async, signal );
  151. break;
  152. case SIGKILL:
  153. case SIGUPDATE:
  154. default:
  155. /* Nothing to do */
  156. break;
  157. }
  158. }
  159. /**
  160. * Default signal handler
  161. *
  162. * @v async Asynchronous operation
  163. * @v signal Signal received
  164. */
  165. static void async_default_signal ( struct async *async, enum signal signal ) {
  166. DBGC ( async, "ASYNC %p using default handler for %s\n",
  167. async, signal_name ( signal ) );
  168. assert ( async != NULL );
  169. switch ( signal ) {
  170. case SIGCHLD:
  171. case SIGKILL:
  172. case SIGUPDATE:
  173. default:
  174. /* Nothing to do */
  175. break;
  176. }
  177. }
  178. /**
  179. * Send signal to asynchronous operation
  180. *
  181. * @v async Asynchronous operation
  182. * @v signal Signal to send
  183. */
  184. void async_signal ( struct async *async, enum signal signal ) {
  185. signal_handler_t handler;
  186. DBGC ( async, "ASYNC %p receiving %s\n",
  187. async, signal_name ( signal ) );
  188. assert ( async != NULL );
  189. assert ( async->aop != NULL );
  190. assert ( signal < SIGMAX );
  191. handler = async->aop->signal[signal];
  192. if ( handler ) {
  193. /* Use the asynchronous operation's signal handler */
  194. handler ( async, signal );
  195. } else {
  196. /* Use the default handler */
  197. async_default_signal ( async, signal );
  198. }
  199. }
  200. /**
  201. * Send signal to all child asynchronous operations
  202. *
  203. * @v async Asynchronous operation
  204. * @v signal Signal to send
  205. */
  206. void async_signal_children ( struct async *async, enum signal signal ) {
  207. struct async *child;
  208. struct async *tmp;
  209. assert ( async != NULL );
  210. list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
  211. async_signal ( child, signal );
  212. }
  213. }
  214. /**
  215. * Reap default handler
  216. *
  217. * @v async Asynchronous operation
  218. */
  219. static void async_reap_default ( struct async *async ) {
  220. DBGC ( async, "ASYNC %p ignoring REAP\n", async );
  221. assert ( async != NULL );
  222. /* Nothing to do */
  223. }
  224. /**
  225. * Reap asynchronous operation
  226. *
  227. * @v async Asynchronous operation
  228. *
  229. * Note that the asynchronous operation should have been freed by
  230. * calling this function; you may not dereference @c async after this
  231. * call.
  232. */
  233. static void async_reap ( struct async *async ) {
  234. DBGC ( async, "ASYNC %p being reaped, exit status %d (%s)\n",
  235. async, async->rc, strerror ( async->rc ) );
  236. assert ( async != NULL );
  237. assert ( async->aop != NULL );
  238. assert ( list_empty ( &async->children ) );
  239. /* Unlink from hierarchy */
  240. if ( async->parent )
  241. list_del ( &async->siblings );
  242. async->parent = NULL;
  243. /* Release all resources */
  244. if ( async->aop->reap ) {
  245. async->aop->reap ( async );
  246. } else {
  247. async_reap_default ( async );
  248. }
  249. }
  250. /**
  251. * Mark asynchronous operation as complete
  252. *
  253. * @v async Asynchronous operation
  254. * @v rc Return status code
  255. *
  256. * An asynchronous operation should call this once it has completed.
  257. * After calling async_done(), it must be prepared to be reaped by
  258. * having its reap() method called.
  259. */
  260. void async_done ( struct async *async, int rc ) {
  261. struct async *child;
  262. struct async *tmp;
  263. DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
  264. async, rc, strerror ( rc ) );
  265. assert ( async != NULL );
  266. assert ( async->parent != NULL );
  267. assert ( rc != -EINPROGRESS );
  268. /* Store return status code */
  269. async->rc = rc;
  270. /* Disown all of our children */
  271. list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
  272. DBGC ( async, "ASYNC %p disowning child ASYNC %p\n",
  273. async, child );
  274. list_del ( &child->siblings );
  275. child->parent = NULL;
  276. }
  277. /* Send SIGCHLD to parent. If we don't have a parent then we
  278. * have to take care of our own funeral arrangements.
  279. */
  280. if ( async->parent ) {
  281. async_signal ( async->parent, SIGCHLD );
  282. } else {
  283. async_reap ( async );
  284. }
  285. }
  286. /**
  287. * Wait for any child asynchronous operation to complete
  288. *
  289. * @v child Child asynchronous operation
  290. * @v rc Child exit status to fill in, or NULL
  291. * @v block Block waiting for child operation to complete
  292. * @ret aid Asynchronous operation ID, or -1 on error
  293. */
  294. aid_t async_wait ( struct async *async, int *rc, int block ) {
  295. struct async *child;
  296. aid_t child_aid;
  297. int dummy_rc;
  298. DBGC ( async, "ASYNC %p performing %sblocking wait%s\n", async,
  299. ( block ? "" : "non-" ), ( rc ? "" : " (ignoring status)" ) );
  300. assert ( async != NULL );
  301. /* Avoid multiple tests for "if ( rc )" */
  302. if ( ! rc )
  303. rc = &dummy_rc;
  304. while ( 1 ) {
  305. /* Return immediately if we have no children */
  306. if ( list_empty ( &async->children ) ) {
  307. DBGC ( async, "ASYNC %p has no more children\n",
  308. async );
  309. *rc = -ECHILD;
  310. return -1;
  311. }
  312. /* Look for a completed child */
  313. list_for_each_entry ( child, &async->children, siblings ) {
  314. if ( child->rc == -EINPROGRESS )
  315. continue;
  316. /* Found a completed child */
  317. *rc = child->rc;
  318. child_aid = child->aid;
  319. DBGC ( async, "ASYNC %p reaping child ASYNC %p "
  320. "(ID %ld)\n", async, child, child_aid );
  321. /* Reap the child and return */
  322. async_reap ( child );
  323. return child_aid;
  324. }
  325. /* Return immediately if non-blocking */
  326. if ( ! block ) {
  327. *rc = -EINPROGRESS;
  328. return -1;
  329. }
  330. /* Allow processes to run */
  331. step();
  332. }
  333. }
  334. /**
  335. * Default asynchronous operations
  336. *
  337. * The default is to ignore SIGCHLD (i.e. to automatically reap
  338. * children) and to use the default handler (i.e. do nothing) for all
  339. * other signals.
  340. */
  341. struct async_operations default_async_operations = {
  342. .signal = {
  343. [SIGCHLD] = SIG_IGN,
  344. },
  345. };
  346. /**
  347. * Default asynchronous operations for orphan asynchronous operations
  348. *
  349. * The default for orphan asynchronous operations is to do nothing for
  350. * SIGCHLD (i.e. to not automatically reap children), on the
  351. * assumption that you're probably creating the orphan solely in order
  352. * to async_wait() on it.
  353. */
  354. struct async_operations orphan_async_operations = {
  355. .signal = {
  356. [SIGCHLD] = SIG_DFL,
  357. },
  358. };