Build bochs with ne2000 support, and add sample lines in bochsrc.txt
[gpxe.git] / src / core / async.c
blobd1ae0770a52bbf8bbe613890be57815d39363559
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 #include <string.h>
20 #include <errno.h>
21 #include <assert.h>
22 #include <gpxe/process.h>
23 #include <gpxe/async.h>
25 /** @file
27 * Asynchronous operations
31 /**
32 * Name signal
34 * @v signal Signal number
35 * @ret name Name of signal
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>";
47 /**
48 * Initialise an asynchronous operation
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
55 * It is valid to create an asynchronous operation with no parent
56 * operation; see async_init_orphan().
58 aid_t async_init ( struct async *async, struct async_operations *aop,
59 struct async *parent ) {
60 static aid_t aid = 1;
62 /* Assign identifier. Negative IDs are used to indicate
63 * errors, so avoid assigning them.
65 ++aid;
66 aid &= ( ( ~( ( aid_t ) 0 ) ) >> 1 );
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" );
74 DBGC ( async, " with ID %ld\n", aid );
76 assert ( async != NULL );
77 assert ( aop != NULL );
79 /* Add to hierarchy */
80 if ( parent ) {
81 async->parent = parent;
82 list_add ( &async->siblings, &parent->children );
84 INIT_LIST_HEAD ( &async->children );
86 /* Initialise fields */
87 async->rc = -EINPROGRESS;
88 async->completed = 0;
89 async->total = 0;
90 async->aop = aop;
91 async->aid = aid;
93 return async->aid;
96 /**
97 * Uninitialise an asynchronous operation
99 * @v async Asynchronous operation
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.
107 * An example may help:
109 * int start_something ( ..., struct async *parent ) {
110 * struct my_data_structure *myself;
112 * ... allocate memory for myself ...
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;
120 * return 0;
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).
127 void async_uninit ( struct async *async ) {
129 assert ( async != NULL );
131 if ( async->parent ) {
132 assert ( list_empty ( &async->children ) );
134 DBGC ( async, "ASYNC %p uninitialising\n", async );
135 list_del ( &async->siblings );
140 * SIGCHLD 'ignore' handler
142 * @v async Asynchronous operation
143 * @v signal Signal received
145 static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
146 aid_t waited_aid;
148 assert ( async != NULL );
149 assert ( signal == SIGCHLD );
151 /* Reap the child */
152 waited_aid = async_wait ( async, NULL, 0 );
153 assert ( waited_aid >= 0 );
157 * SIGUPDATE 'ignore' handler
159 * @v async Asynchronous operation
160 * @v signal Signal received
162 static void async_ignore_sigupdate ( struct async *async,
163 enum signal signal ) {
164 struct async *child;
166 assert ( async != NULL );
167 assert ( signal == SIGUPDATE );
169 async_signal_children ( async, signal );
170 async->completed = 0;
171 async->total = 0;
172 list_for_each_entry ( child, &async->children, siblings ) {
173 async->completed += child->completed;
174 async->total += child->total;
179 * 'Ignore' signal handler
181 * @v async Asynchronous operation
182 * @v signal Signal received
184 void async_ignore_signal ( struct async *async, enum signal signal ) {
186 DBGC ( async, "ASYNC %p using ignore handler for %s\n",
187 async, signal_name ( signal ) );
189 assert ( async != NULL );
191 switch ( signal ) {
192 case SIGCHLD:
193 async_ignore_sigchld ( async, signal );
194 break;
195 case SIGUPDATE:
196 async_ignore_sigupdate ( async, signal );
197 break;
198 case SIGKILL:
199 default:
200 /* Nothing to do */
201 break;
206 * Default signal handler
208 * @v async Asynchronous operation
209 * @v signal Signal received
211 static void async_default_signal ( struct async *async, enum signal signal ) {
213 DBGC ( async, "ASYNC %p using default handler for %s\n",
214 async, signal_name ( signal ) );
216 assert ( async != NULL );
218 switch ( signal ) {
219 case SIGCHLD:
220 case SIGKILL:
221 case SIGUPDATE:
222 default:
223 /* Nothing to do */
224 break;
229 * Send signal to asynchronous operation
231 * @v async Asynchronous operation
232 * @v signal Signal to send
234 void async_signal ( struct async *async, enum signal signal ) {
235 signal_handler_t handler;
237 DBGC ( async, "ASYNC %p receiving %s\n",
238 async, signal_name ( signal ) );
240 assert ( async != NULL );
241 assert ( async->aop != NULL );
242 assert ( signal < SIGMAX );
244 handler = async->aop->signal[signal];
245 if ( handler ) {
246 /* Use the asynchronous operation's signal handler */
247 handler ( async, signal );
248 } else {
249 /* Use the default handler */
250 async_default_signal ( async, signal );
255 * Send signal to all child asynchronous operations
257 * @v async Asynchronous operation
258 * @v signal Signal to send
260 void async_signal_children ( struct async *async, enum signal signal ) {
261 struct async *child;
262 struct async *tmp;
264 assert ( async != NULL );
266 list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
267 async_signal ( child, signal );
272 * Reap default handler
274 * @v async Asynchronous operation
276 static void async_reap_default ( struct async *async ) {
278 DBGC ( async, "ASYNC %p ignoring REAP\n", async );
280 assert ( async != NULL );
282 /* Nothing to do */
286 * Reap asynchronous operation
288 * @v async Asynchronous operation
290 * Note that the asynchronous operation should have been freed by
291 * calling this function; you may not dereference @c async after this
292 * call.
294 static void async_reap ( struct async *async ) {
296 DBGC ( async, "ASYNC %p being reaped, exit status %d (%s)\n",
297 async, async->rc, strerror ( async->rc ) );
299 assert ( async != NULL );
300 assert ( async->aop != NULL );
301 assert ( list_empty ( &async->children ) );
303 /* Unlink from hierarchy */
304 if ( async->parent )
305 list_del ( &async->siblings );
306 async->parent = NULL;
308 /* Release all resources */
309 if ( async->aop->reap ) {
310 async->aop->reap ( async );
311 } else {
312 async_reap_default ( async );
317 * Mark asynchronous operation as complete
319 * @v async Asynchronous operation
320 * @v rc Return status code
322 * An asynchronous operation should call this once it has completed.
323 * After calling async_done(), it must be prepared to be reaped by
324 * having its reap() method called.
326 void async_done ( struct async *async, int rc ) {
327 struct async *child;
328 struct async *tmp;
330 DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
331 async, rc, strerror ( rc ) );
333 assert ( async != NULL );
334 assert ( async->parent != NULL );
335 assert ( rc != -EINPROGRESS );
337 /* Store return status code */
338 async->rc = rc;
340 /* Disown all of our children */
341 list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
342 DBGC ( async, "ASYNC %p disowning child ASYNC %p\n",
343 async, child );
344 list_del ( &child->siblings );
345 child->parent = NULL;
348 /* Send SIGCHLD to parent. If we don't have a parent then we
349 * have to take care of our own funeral arrangements.
351 if ( async->parent ) {
352 async_signal ( async->parent, SIGCHLD );
353 } else {
354 async_reap ( async );
359 * Wait for any child asynchronous operation to complete
361 * @v child Child asynchronous operation
362 * @v rc Child exit status to fill in, or NULL
363 * @v block Block waiting for child operation to complete
364 * @ret aid Asynchronous operation ID, or -1 on error
366 aid_t async_wait ( struct async *async, int *rc, int block ) {
367 struct async *child;
368 aid_t child_aid;
369 int dummy_rc;
371 DBGC ( async, "ASYNC %p performing %sblocking wait%s\n", async,
372 ( block ? "" : "non-" ), ( rc ? "" : " (ignoring status)" ) );
374 assert ( async != NULL );
376 /* Avoid multiple tests for "if ( rc )" */
377 if ( ! rc )
378 rc = &dummy_rc;
380 while ( 1 ) {
382 /* Return immediately if we have no children */
383 if ( list_empty ( &async->children ) ) {
384 DBGC ( async, "ASYNC %p has no more children\n",
385 async );
386 *rc = -ECHILD;
387 return -1;
390 /* Look for a completed child */
391 list_for_each_entry ( child, &async->children, siblings ) {
392 if ( child->rc == -EINPROGRESS )
393 continue;
395 /* Found a completed child */
396 *rc = child->rc;
397 child_aid = child->aid;
399 DBGC ( async, "ASYNC %p reaping child ASYNC %p "
400 "(ID %ld)\n", async, child, child_aid );
402 /* Reap the child and return */
403 async_reap ( child );
404 return child_aid;
407 /* Return immediately if non-blocking */
408 if ( ! block ) {
409 *rc = -EINPROGRESS;
410 return -1;
413 /* Allow processes to run */
414 step();
419 * Wait for any child asynchronous operation to complete, with progress bar
421 * @v child Child asynchronous operation
422 * @v rc Child exit status to fill in, or NULL
423 * @ret aid Asynchronous operation ID, or -1 on error
425 aid_t async_wait_progress ( struct async *async, int *rc ) {
426 struct async *child;
427 long last_progress = -1;
428 long progress;
429 aid_t child_aid;
431 do {
432 step();
433 async_signal ( async, SIGUPDATE );
434 if ( async->total ) {
435 progress = ( async->completed / (async->total / 100) );
436 if ( progress != last_progress )
437 printf ( "\rProgress: %d%%", progress );
438 last_progress = progress;
440 child_aid = async_wait ( async, rc, 0 );
441 } while ( *rc == -EINPROGRESS );
443 printf ( "\n" );
444 return child_aid;
448 * Default asynchronous operations
450 * The default is to ignore SIGCHLD (i.e. to automatically reap
451 * children) and to use the default handler (i.e. do nothing) for all
452 * other signals.
454 struct async_operations default_async_operations = {
455 .signal = {
456 [SIGCHLD] = SIG_IGN,
457 [SIGUPDATE] = SIG_IGN,
462 * Default asynchronous operations for orphan asynchronous operations
464 * The default for orphan asynchronous operations is to do nothing for
465 * SIGCHLD (i.e. to not automatically reap children), on the
466 * assumption that you're probably creating the orphan solely in order
467 * to async_wait() on it.
469 struct async_operations orphan_async_operations = {
470 .signal = {
471 [SIGCHLD] = SIG_DFL,
472 [SIGUPDATE] = SIG_IGN,