選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

async.h 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #ifndef _GPXE_ASYNC_H
  2. #define _GPXE_ASYNC_H
  3. /** @file
  4. *
  5. * Asynchronous operations
  6. *
  7. */
  8. #include <gpxe/list.h>
  9. struct async;
  10. /** An asynchronous operation ID
  11. *
  12. * Only positive identifiers are valid; negative values are used to
  13. * indicate errors.
  14. */
  15. typedef long aid_t;
  16. /** Signals that can be delivered to asynchronous operations */
  17. enum signal {
  18. /** A child asynchronous operation has completed
  19. *
  20. * The parent should call async_wait() to reap the completed
  21. * child. async_wait() will return the exit status and
  22. * operation identifier of the child.
  23. *
  24. * The handler for this signal can be set to @c NULL; if it
  25. * is, then the children will accumulate as zombies until
  26. * async_wait() is called.
  27. *
  28. * The handler for this signal can also be set to @c SIG_IGN;
  29. * if it is, then the children will automatically be reaped.
  30. * Note that if you use @c SIG_IGN then you will not be able
  31. * to retrieve the return status of the children; the call to
  32. * async_wait() will simply return -ECHILD.
  33. */
  34. SIGCHLD = 0,
  35. /** Cancel asynchronous operation
  36. *
  37. * This signal should trigger the asynchronous operation to
  38. * cancel itself (including killing all its own children, if
  39. * any), and then call async_done(). The asynchronous
  40. * operation is allowed to not complete immediately.
  41. *
  42. * The handler for this signal can be set to @c NULL; if it
  43. * is, then attempts to cancel the asynchronous operation will
  44. * fail and the operation will complete normally. Anything
  45. * waiting for the operation to cancel will block.
  46. */
  47. SIGKILL,
  48. /** Update progress of asynchronous operation
  49. *
  50. * This signal should cause the asynchronous operation to
  51. * immediately update the @c completed and @c total fields.
  52. *
  53. * The handler for this signal can be set to @c NULL; if it
  54. * is, then the asynchronous operation is expected to keep its
  55. * @c completed and @c total fields up to date at all times.
  56. */
  57. SIGUPDATE,
  58. SIGMAX
  59. };
  60. /**
  61. * A signal handler
  62. *
  63. * @v async Asynchronous operation
  64. * @v signal Signal received
  65. */
  66. typedef void ( * signal_handler_t ) ( struct async *async,
  67. enum signal signal );
  68. /** Asynchronous operation operations */
  69. struct async_operations {
  70. /** Reap asynchronous operation
  71. *
  72. * @v async Asynchronous operation
  73. *
  74. * Release all resources associated with the asynchronous
  75. * operation. This will be called only after the asynchronous
  76. * operation itself calls async_done(), so the only remaining
  77. * resources will probably be the memory used by the struct
  78. * async itself.
  79. *
  80. * This method can be set to @c NULL; if it is, then no
  81. * resources will be freed. This may be suitable for
  82. * asynchronous operations that consume no dynamically
  83. * allocated memory.
  84. */
  85. void ( * reap ) ( struct async *async );
  86. /** Handle signals */
  87. signal_handler_t signal[SIGMAX];
  88. };
  89. /** An asynchronous operation */
  90. struct async {
  91. /** Other asynchronous operations with the same parent */
  92. struct list_head siblings;
  93. /** Child asynchronous operations */
  94. struct list_head children;
  95. /** Parent asynchronous operation
  96. *
  97. * This field is optional; if left to NULL then the owner must
  98. * never call async_done().
  99. */
  100. struct async *parent;
  101. /** Asynchronous operation ID */
  102. aid_t aid;
  103. /** Final return status code */
  104. int rc;
  105. /** Amount of operation completed so far
  106. *
  107. * The units for this quantity are arbitrary. @c completed
  108. * divded by @total should give something which approximately
  109. * represents the progress through the operation. For a
  110. * download operation, using byte counts would make sense.
  111. *
  112. * This progress indicator should also incorporate the status
  113. * of any child asynchronous operations.
  114. */
  115. unsigned long completed;
  116. /** Total operation size
  117. *
  118. * See @c completed. A zero value means "total size unknown"
  119. * and is explcitly permitted; users should take this into
  120. * account before calculating @c completed/total.
  121. */
  122. unsigned long total;
  123. struct async_operations *aop;
  124. };
  125. extern struct async_operations default_async_operations;
  126. extern struct async_operations orphan_async_operations;
  127. extern aid_t async_init ( struct async *async, struct async_operations *aop,
  128. struct async *parent );
  129. extern void async_uninit ( struct async *async );
  130. extern void async_ignore_signal ( struct async *async, enum signal signal );
  131. extern void async_signal ( struct async *async, enum signal signal );
  132. extern void async_signal_children ( struct async *async, enum signal signal );
  133. extern void async_done ( struct async *async, int rc );
  134. extern aid_t async_wait ( struct async *async, int *rc, int block );
  135. /** Default signal handler */
  136. #define SIG_DFL NULL
  137. /** Ignore signal */
  138. #define SIG_IGN async_ignore_signal
  139. /**
  140. * Initialise orphan asynchronous operation
  141. *
  142. * @v async Asynchronous operation
  143. * @ret aid Asynchronous operation ID
  144. *
  145. * An orphan asynchronous operation can act as a context for child
  146. * operations. However, you must not call async_done() on such an
  147. * operation, since this would attempt to send a signal to its
  148. * (non-existent) parent. Instead, simply free the structure (after
  149. * calling async_wait() to ensure that any child operations have
  150. * completed).
  151. */
  152. static inline aid_t async_init_orphan ( struct async *async ) {
  153. return async_init ( async, &orphan_async_operations, NULL );
  154. }
  155. /**
  156. * Execute and block on an asynchronous operation
  157. *
  158. * @v async_temp Temporary asynchronous operation structure to use
  159. * @v START Code used to start the asynchronous operation
  160. * @ret rc Return status code
  161. *
  162. * This is a notational shorthand for writing
  163. *
  164. * async_init_orphan ( &async_temp );
  165. * if ( ( rc = START ) == 0 )
  166. * async_wait ( &async_temp );
  167. * if ( rc != 0 ) {
  168. * ...handle failure...
  169. * }
  170. *
  171. * and allows you instead to write
  172. *
  173. * if ( ( rc = async_block ( &async_temp, START ) ) != 0 ) {
  174. * ...handle failure...
  175. * }
  176. *
  177. * The argument START is a code snippet; it should initiate an
  178. * asynchronous operation as a child of @c async_temp and return an
  179. * error status code if it failed to do so (e.g. due to malloc()
  180. * failure).
  181. */
  182. #define async_block( async_temp, START ) ( { \
  183. int rc; \
  184. \
  185. async_init_orphan ( async_temp ); \
  186. if ( ( rc = START ) == 0 ) \
  187. async_wait ( async_temp, &rc, 1 ); \
  188. rc; \
  189. } )
  190. /**
  191. * Execute and block on an asynchronous operation, with progress indicator
  192. *
  193. * @v async_temp Temporary asynchronous operation structure to use
  194. * @v START Code used to start the asynchronous operation
  195. * @ret rc Return status code
  196. *
  197. * As for async_block(), the argument START is a code snippet; it
  198. * should initiate an asynchronous operation as a child of @c
  199. * async_temp and return an error status code if it failed to do so
  200. * (e.g. due to malloc() failure).
  201. */
  202. #define async_block_progress( async_temp, START ) ( { \
  203. int rc; \
  204. \
  205. async_init_orphan ( async_temp ); \
  206. if ( ( rc = START ) == 0 ) \
  207. async_wait_progress ( async_temp, &rc );\
  208. rc; \
  209. } )
  210. #endif /* _GPXE_ASYNC_H */