summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/async.c109
1 files changed, 74 insertions, 35 deletions
diff --git a/src/core/async.c b/src/core/async.c
index 26b27f0b3..20be7f565 100644
--- a/src/core/async.c
+++ b/src/core/async.c
@@ -125,8 +125,15 @@ aid_t async_init ( struct async *async, struct async_operations *aop,
* async).
*/
void async_uninit ( struct async *async ) {
- if ( async->parent )
+
+ assert ( async != NULL );
+
+ if ( async->parent ) {
+ assert ( list_empty ( &async->children ) );
+
+ DBGC ( async, "ASYNC %p uninitialising\n", async );
list_del ( &async->siblings );
+ }
}
/**
@@ -238,6 +245,51 @@ void async_signal_children ( struct async *async, enum signal signal ) {
}
/**
+ * Reap default handler
+ *
+ * @v async Asynchronous operation
+ */
+static void async_reap_default ( struct async *async ) {
+
+ DBGC ( async, "ASYNC %p ignoring REAP\n", async );
+
+ assert ( async != NULL );
+
+ /* Nothing to do */
+}
+
+/**
+ * Reap asynchronous operation
+ *
+ * @v async Asynchronous operation
+ *
+ * Note that the asynchronous operation should have been freed by
+ * calling this function; you may not dereference @c async after this
+ * call.
+ */
+static void async_reap ( struct async *async ) {
+
+ DBGC ( async, "ASYNC %p being reaped, exit status %d (%s)\n",
+ async, async->rc, strerror ( async->rc ) );
+
+ assert ( async != NULL );
+ assert ( async->aop != NULL );
+ assert ( list_empty ( &async->children ) );
+
+ /* Unlink from hierarchy */
+ if ( async->parent )
+ list_del ( &async->siblings );
+ async->parent = NULL;
+
+ /* Release all resources */
+ if ( async->aop->reap ) {
+ async->aop->reap ( async );
+ } else {
+ async_reap_default ( async );
+ }
+}
+
+/**
* Mark asynchronous operation as complete
*
* @v async Asynchronous operation
@@ -248,6 +300,8 @@ void async_signal_children ( struct async *async, enum signal signal ) {
* having its reap() method called.
*/
void async_done ( struct async *async, int rc ) {
+ struct async *child;
+ struct async *tmp;
DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
async, rc, strerror ( rc ) );
@@ -259,23 +313,22 @@ void async_done ( struct async *async, int rc ) {
/* Store return status code */
async->rc = rc;
- /* Send SIGCHLD to parent. Guard against NULL pointer dereferences */
- if ( async->parent )
- async_signal ( async->parent, SIGCHLD );
-}
-
-/**
- * Reap default handler
- *
- * @v async Asynchronous operation
- */
-static void async_reap_default ( struct async *async ) {
-
- DBGC ( async, "ASYNC %p ignoring REAP\n", async );
-
- assert ( async != NULL );
+ /* Disown all of our children */
+ list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
+ DBGC ( async, "ASYNC %p disowning child ASYNC %p\n",
+ async, child );
+ list_del ( &child->siblings );
+ child->parent = NULL;
+ }
- /* Nothing to do */
+ /* Send SIGCHLD to parent. If we don't have a parent then we
+ * have to take care of our own funeral arrangements.
+ */
+ if ( async->parent ) {
+ async_signal ( async->parent, SIGCHLD );
+ } else {
+ async_reap ( async );
+ }
}
/**
@@ -319,25 +372,11 @@ aid_t async_wait ( struct async *async, int *rc, int block ) {
*rc = child->rc;
child_aid = child->aid;
- DBGC ( async, "ASYNC %p reaping child ASYNC %p (ID "
- "%ld), exit status %d (%s)\n", async, child,
- child_aid, child->rc, strerror ( child->rc ) );
-
- /* Reap the child */
- assert ( child->aop != NULL );
- assert ( list_empty ( &child->children ) );
-
- /* Unlink from operations hierarchy */
- list_del ( &child->siblings );
- child->parent = NULL;
-
- /* Release all resources */
- if ( child->aop->reap ) {
- child->aop->reap ( child );
- } else {
- async_reap_default ( child );
- }
+ DBGC ( async, "ASYNC %p reaping child ASYNC %p "
+ "(ID %ld)\n", async, child, child_aid );
+ /* Reap the child and return */
+ async_reap ( child );
return child_aid;
}