|
@@ -125,8 +125,15 @@ aid_t async_init ( struct async *async, struct async_operations *aop,
|
125
|
125
|
* async).
|
126
|
126
|
*/
|
127
|
127
|
void async_uninit ( struct async *async ) {
|
128
|
|
- if ( async->parent )
|
|
128
|
+
|
|
129
|
+ assert ( async != NULL );
|
|
130
|
+
|
|
131
|
+ if ( async->parent ) {
|
|
132
|
+ assert ( list_empty ( &async->children ) );
|
|
133
|
+
|
|
134
|
+ DBGC ( async, "ASYNC %p uninitialising\n", async );
|
129
|
135
|
list_del ( &async->siblings );
|
|
136
|
+ }
|
130
|
137
|
}
|
131
|
138
|
|
132
|
139
|
/**
|
|
@@ -237,6 +244,51 @@ void async_signal_children ( struct async *async, enum signal signal ) {
|
237
|
244
|
}
|
238
|
245
|
}
|
239
|
246
|
|
|
247
|
+/**
|
|
248
|
+ * Reap default handler
|
|
249
|
+ *
|
|
250
|
+ * @v async Asynchronous operation
|
|
251
|
+ */
|
|
252
|
+static void async_reap_default ( struct async *async ) {
|
|
253
|
+
|
|
254
|
+ DBGC ( async, "ASYNC %p ignoring REAP\n", async );
|
|
255
|
+
|
|
256
|
+ assert ( async != NULL );
|
|
257
|
+
|
|
258
|
+ /* Nothing to do */
|
|
259
|
+}
|
|
260
|
+
|
|
261
|
+/**
|
|
262
|
+ * Reap asynchronous operation
|
|
263
|
+ *
|
|
264
|
+ * @v async Asynchronous operation
|
|
265
|
+ *
|
|
266
|
+ * Note that the asynchronous operation should have been freed by
|
|
267
|
+ * calling this function; you may not dereference @c async after this
|
|
268
|
+ * call.
|
|
269
|
+ */
|
|
270
|
+static void async_reap ( struct async *async ) {
|
|
271
|
+
|
|
272
|
+ DBGC ( async, "ASYNC %p being reaped, exit status %d (%s)\n",
|
|
273
|
+ async, async->rc, strerror ( async->rc ) );
|
|
274
|
+
|
|
275
|
+ assert ( async != NULL );
|
|
276
|
+ assert ( async->aop != NULL );
|
|
277
|
+ assert ( list_empty ( &async->children ) );
|
|
278
|
+
|
|
279
|
+ /* Unlink from hierarchy */
|
|
280
|
+ if ( async->parent )
|
|
281
|
+ list_del ( &async->siblings );
|
|
282
|
+ async->parent = NULL;
|
|
283
|
+
|
|
284
|
+ /* Release all resources */
|
|
285
|
+ if ( async->aop->reap ) {
|
|
286
|
+ async->aop->reap ( async );
|
|
287
|
+ } else {
|
|
288
|
+ async_reap_default ( async );
|
|
289
|
+ }
|
|
290
|
+}
|
|
291
|
+
|
240
|
292
|
/**
|
241
|
293
|
* Mark asynchronous operation as complete
|
242
|
294
|
*
|
|
@@ -248,6 +300,8 @@ void async_signal_children ( struct async *async, enum signal signal ) {
|
248
|
300
|
* having its reap() method called.
|
249
|
301
|
*/
|
250
|
302
|
void async_done ( struct async *async, int rc ) {
|
|
303
|
+ struct async *child;
|
|
304
|
+ struct async *tmp;
|
251
|
305
|
|
252
|
306
|
DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
|
253
|
307
|
async, rc, strerror ( rc ) );
|
|
@@ -259,23 +313,22 @@ void async_done ( struct async *async, int rc ) {
|
259
|
313
|
/* Store return status code */
|
260
|
314
|
async->rc = rc;
|
261
|
315
|
|
262
|
|
- /* Send SIGCHLD to parent. Guard against NULL pointer dereferences */
|
263
|
|
- if ( async->parent )
|
264
|
|
- async_signal ( async->parent, SIGCHLD );
|
265
|
|
-}
|
266
|
|
-
|
267
|
|
-/**
|
268
|
|
- * Reap default handler
|
269
|
|
- *
|
270
|
|
- * @v async Asynchronous operation
|
271
|
|
- */
|
272
|
|
-static void async_reap_default ( struct async *async ) {
|
273
|
|
-
|
274
|
|
- DBGC ( async, "ASYNC %p ignoring REAP\n", async );
|
275
|
|
-
|
276
|
|
- assert ( async != NULL );
|
|
316
|
+ /* Disown all of our children */
|
|
317
|
+ list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
|
|
318
|
+ DBGC ( async, "ASYNC %p disowning child ASYNC %p\n",
|
|
319
|
+ async, child );
|
|
320
|
+ list_del ( &child->siblings );
|
|
321
|
+ child->parent = NULL;
|
|
322
|
+ }
|
277
|
323
|
|
278
|
|
- /* Nothing to do */
|
|
324
|
+ /* Send SIGCHLD to parent. If we don't have a parent then we
|
|
325
|
+ * have to take care of our own funeral arrangements.
|
|
326
|
+ */
|
|
327
|
+ if ( async->parent ) {
|
|
328
|
+ async_signal ( async->parent, SIGCHLD );
|
|
329
|
+ } else {
|
|
330
|
+ async_reap ( async );
|
|
331
|
+ }
|
279
|
332
|
}
|
280
|
333
|
|
281
|
334
|
/**
|
|
@@ -319,25 +372,11 @@ aid_t async_wait ( struct async *async, int *rc, int block ) {
|
319
|
372
|
*rc = child->rc;
|
320
|
373
|
child_aid = child->aid;
|
321
|
374
|
|
322
|
|
- DBGC ( async, "ASYNC %p reaping child ASYNC %p (ID "
|
323
|
|
- "%ld), exit status %d (%s)\n", async, child,
|
324
|
|
- child_aid, child->rc, strerror ( child->rc ) );
|
325
|
|
-
|
326
|
|
- /* Reap the child */
|
327
|
|
- assert ( child->aop != NULL );
|
328
|
|
- assert ( list_empty ( &child->children ) );
|
329
|
|
-
|
330
|
|
- /* Unlink from operations hierarchy */
|
331
|
|
- list_del ( &child->siblings );
|
332
|
|
- child->parent = NULL;
|
333
|
|
-
|
334
|
|
- /* Release all resources */
|
335
|
|
- if ( child->aop->reap ) {
|
336
|
|
- child->aop->reap ( child );
|
337
|
|
- } else {
|
338
|
|
- async_reap_default ( child );
|
339
|
|
- }
|
|
375
|
+ DBGC ( async, "ASYNC %p reaping child ASYNC %p "
|
|
376
|
+ "(ID %ld)\n", async, child, child_aid );
|
340
|
377
|
|
|
378
|
+ /* Reap the child and return */
|
|
379
|
+ async_reap ( child );
|
341
|
380
|
return child_aid;
|
342
|
381
|
}
|
343
|
382
|
|