20be7f5659cd2c31baf53bd4cff6e3531cf415b8
[people/xl0/gpxe.git] / src / core / async.c
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
19 #include <string.h>
20 #include <errno.h>
21 #include <assert.h>
22 #include <gpxe/process.h>
23 #include <gpxe/async.h>
24
25 /** @file
26  *
27  * Asynchronous operations
28  *
29  */
30
31 /**
32  * Name signal
33  *
34  * @v signal            Signal number
35  * @ret name            Name of signal
36  */
37 static inline __attribute__ (( always_inline )) const char *
38 signal_name ( enum signal signal ) {
39         switch ( signal ) {
40         case SIGCHLD:           return "SIGCHLD";
41         case SIGKILL:           return "SIGKILL";
42         case SIGUPDATE:         return "SIGUPDATE";
43         default:                return "SIG<UNKNOWN>";
44         }
45 }
46
47 /**
48  * Initialise an asynchronous operation
49  *
50  * @v async             Asynchronous operation
51  * @v aop               Asynchronous operation operations to use
52  * @v parent            Parent asynchronous operation, or NULL
53  * @ret aid             Asynchronous operation ID
54  *
55  * It is valid to create an asynchronous operation with no parent
56  * operation; see async_init_orphan().
57  */
58 aid_t async_init ( struct async *async, struct async_operations *aop,
59                    struct async *parent ) {
60         static aid_t aid = 1;
61
62         /* Assign identifier.  Negative IDs are used to indicate
63          * errors, so avoid assigning them.
64          */
65         ++aid;
66         aid &= ( ( ~( ( aid_t ) 0 ) ) >> 1 );
67
68         DBGC ( async, "ASYNC %p (type %p) initialising as", async, aop );
69         if ( parent ) {
70                 DBGC ( async, " child of ASYNC %p", parent );
71         } else {
72                 DBGC ( async, " orphan" );
73         }
74         DBGC ( async, " with ID %ld\n", aid );
75
76         assert ( async != NULL );
77         assert ( aop != NULL );
78
79         /* Add to hierarchy */
80         if ( parent ) {
81                 async->parent = parent;
82                 list_add ( &async->siblings, &parent->children );
83         }
84         INIT_LIST_HEAD ( &async->children );
85
86         /* Initialise fields */
87         async->rc = -EINPROGRESS;
88         async->completed = 0;
89         async->total = 0;
90         async->aop = aop;
91         async->aid = aid;
92
93         return async->aid;
94 }
95
96 /**
97  * Uninitialise an asynchronous operation
98  *
99  * @v async             Asynchronous operation
100  *
101  * Abandon an asynchronous operation without signalling the parent.
102  * You may do this only during the period between calling async_init()
103  * and returning to the parent for the first time.  It is designed to
104  * simplify the error paths of asynchronous operations that themselves
105  * spawn further asynchronous operations.
106  *
107  * An example may help:
108  *
109  *     int start_something ( ..., struct async *parent ) {
110  *         struct my_data_structure *myself;
111  *
112  *         ... allocate memory for myself ...
113  *
114  *         async_init ( &myself->async, &my_async_operations, parent );
115  *         if ( ( rc = start_child_operation ( ..., &myself->async ) ) != 0 ) {
116  *             async_uninit ( &myself->async );
117  *             return rc;
118  *         }
119  *
120  *         return 0;
121  *     }
122  *
123  * It is valid to call async_uninit() on an asynchronous operation
124  * that has not yet been initialised (i.e. a zeroed-out @c struct @c
125  * async).
126  */
127 void async_uninit ( struct async *async ) {
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 );
135                 list_del ( &async->siblings );
136         }
137 }
138
139 /**
140  * SIGCHLD 'ignore' handler
141  *
142  * @v async             Asynchronous operation
143  * @v signal            Signal received
144  */
145 static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
146         aid_t waited_aid;
147
148         assert ( async != NULL );
149         assert ( signal == SIGCHLD );
150
151         /* Reap the child */
152         waited_aid = async_wait ( async, NULL, 0 );
153         assert ( waited_aid >= 0 );
154 }
155
156 /**
157  * 'Ignore' signal handler
158  *
159  * @v async             Asynchronous operation
160  * @v signal            Signal received
161  */
162 void async_ignore_signal ( struct async *async, enum signal signal ) {
163
164         DBGC ( async, "ASYNC %p using ignore handler for %s\n",
165                async, signal_name ( signal ) );
166
167         assert ( async != NULL );
168
169         switch ( signal ) {
170         case SIGCHLD:
171                 async_ignore_sigchld ( async, signal );
172                 break;
173         case SIGKILL:
174         case SIGUPDATE:
175         default:
176                 /* Nothing to do */
177                 break;
178         }
179 }
180
181 /**
182  * Default signal handler
183  *
184  * @v async             Asynchronous operation
185  * @v signal            Signal received
186  */
187 static void async_default_signal ( struct async *async, enum signal signal ) {
188
189         DBGC ( async, "ASYNC %p using default handler for %s\n",
190                async, signal_name ( signal ) );
191
192         assert ( async != NULL );
193
194         switch ( signal ) {
195         case SIGCHLD:
196         case SIGKILL:
197         case SIGUPDATE:
198         default:
199                 /* Nothing to do */
200                 break;
201         }
202 }
203
204 /**
205  * Send signal to asynchronous operation
206  *
207  * @v async             Asynchronous operation
208  * @v signal            Signal to send
209  */
210 void async_signal ( struct async *async, enum signal signal ) {
211         signal_handler_t handler;
212
213         DBGC ( async, "ASYNC %p receiving %s\n",
214                async, signal_name ( signal ) );
215
216         assert ( async != NULL );
217         assert ( async->aop != NULL );
218         assert ( signal < SIGMAX );
219
220         handler = async->aop->signal[signal];
221         if ( handler ) {
222                 /* Use the asynchronous operation's signal handler */
223                 handler ( async, signal );
224         } else {
225                 /* Use the default handler */
226                 async_default_signal ( async, signal );
227         }
228 }
229
230 /**
231  * Send signal to all child asynchronous operations
232  *
233  * @v async             Asynchronous operation
234  * @v signal            Signal to send
235  */
236 void async_signal_children ( struct async *async, enum signal signal ) {
237         struct async *child;
238         struct async *tmp;
239
240         assert ( async != NULL );
241
242         list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
243                 async_signal ( child, signal );
244         }
245 }
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
292 /**
293  * Mark asynchronous operation as complete
294  *
295  * @v async             Asynchronous operation
296  * @v rc                Return status code
297  *
298  * An asynchronous operation should call this once it has completed.
299  * After calling async_done(), it must be prepared to be reaped by
300  * having its reap() method called.
301  */
302 void async_done ( struct async *async, int rc ) {
303         struct async *child;
304         struct async *tmp;
305
306         DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
307                async, rc, strerror ( rc ) );
308
309         assert ( async != NULL );
310         assert ( async->parent != NULL );
311         assert ( rc != -EINPROGRESS );
312
313         /* Store return status code */
314         async->rc = rc;
315
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         }
323
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         }
332 }
333
334 /**
335  * Wait for any child asynchronous operation to complete
336  * 
337  * @v child             Child asynchronous operation
338  * @v rc                Child exit status to fill in, or NULL
339  * @v block             Block waiting for child operation to complete
340  * @ret aid             Asynchronous operation ID, or -1 on error
341  */
342 aid_t async_wait ( struct async *async, int *rc, int block ) {
343         struct async *child;
344         aid_t child_aid;
345         int dummy_rc;
346
347         DBGC ( async, "ASYNC %p performing %sblocking wait%s\n", async,
348                ( block ? "" : "non-" ), ( rc ? "" : " (ignoring status)" ) );
349
350         assert ( async != NULL );
351
352         /* Avoid multiple tests for "if ( rc )" */
353         if ( ! rc )
354                 rc = &dummy_rc;
355
356         while ( 1 ) {
357
358                 /* Return immediately if we have no children */
359                 if ( list_empty ( &async->children ) ) {
360                         DBGC ( async, "ASYNC %p has no more children\n",
361                                async );
362                         *rc = -ECHILD;
363                         return -1;
364                 }
365
366                 /* Look for a completed child */
367                 list_for_each_entry ( child, &async->children, siblings ) {
368                         if ( child->rc == -EINPROGRESS )
369                                 continue;
370
371                         /* Found a completed child */
372                         *rc = child->rc;
373                         child_aid = child->aid;
374
375                         DBGC ( async, "ASYNC %p reaping child ASYNC %p "
376                                "(ID %ld)\n", async, child, child_aid );
377
378                         /* Reap the child and return */
379                         async_reap ( child );
380                         return child_aid;
381                 }
382
383                 /* Return immediately if non-blocking */
384                 if ( ! block ) {
385                         *rc = -EINPROGRESS;
386                         return -1;
387                 }
388
389                 /* Allow processes to run */
390                 step();
391         }
392 }
393
394 /**
395  * Default asynchronous operations
396  *
397  * The default is to ignore SIGCHLD (i.e. to automatically reap
398  * children) and to use the default handler (i.e. do nothing) for all
399  * other signals.
400  */
401 struct async_operations default_async_operations = {
402         .signal = {
403                 [SIGCHLD] = SIG_IGN,
404         },
405 };
406
407 /**
408  * Default asynchronous operations for orphan asynchronous operations
409  *
410  * The default for orphan asynchronous operations is to do nothing for
411  * SIGCHLD (i.e. to not automatically reap children), on the
412  * assumption that you're probably creating the orphan solely in order
413  * to async_wait() on it.
414  */
415 struct async_operations orphan_async_operations = {
416         .signal = {
417                 [SIGCHLD] = SIG_DFL,
418         },
419 };