From 1a79437888be127a1a966e20145d79e0673275d1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 29 Jan 2007 04:15:24 +0000 Subject: [PATCH] Added async_block_progress() and default SIGUPDATE handler. --- src/core/async.c | 61 ++++++++++++++++++++++++++++++++++++++-- src/include/gpxe/async.h | 21 ++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/core/async.c b/src/core/async.c index 20be7f56..d1ae0770 100644 --- a/src/core/async.c +++ b/src/core/async.c @@ -153,6 +153,28 @@ static void async_ignore_sigchld ( struct async *async, enum signal signal ) { assert ( waited_aid >= 0 ); } +/** + * SIGUPDATE 'ignore' handler + * + * @v async Asynchronous operation + * @v signal Signal received + */ +static void async_ignore_sigupdate ( struct async *async, + enum signal signal ) { + struct async *child; + + assert ( async != NULL ); + assert ( signal == SIGUPDATE ); + + async_signal_children ( async, signal ); + async->completed = 0; + async->total = 0; + list_for_each_entry ( child, &async->children, siblings ) { + async->completed += child->completed; + async->total += child->total; + } +} + /** * 'Ignore' signal handler * @@ -170,8 +192,10 @@ void async_ignore_signal ( struct async *async, enum signal signal ) { case SIGCHLD: async_ignore_sigchld ( async, signal ); break; - case SIGKILL: case SIGUPDATE: + async_ignore_sigupdate ( async, signal ); + break; + case SIGKILL: default: /* Nothing to do */ break; @@ -391,6 +415,35 @@ aid_t async_wait ( struct async *async, int *rc, int block ) { } } +/** + * Wait for any child asynchronous operation to complete, with progress bar + * + * @v child Child asynchronous operation + * @v rc Child exit status to fill in, or NULL + * @ret aid Asynchronous operation ID, or -1 on error + */ +aid_t async_wait_progress ( struct async *async, int *rc ) { + struct async *child; + long last_progress = -1; + long progress; + aid_t child_aid; + + do { + step(); + async_signal ( async, SIGUPDATE ); + if ( async->total ) { + progress = ( async->completed / (async->total / 100) ); + if ( progress != last_progress ) + printf ( "\rProgress: %d%%", progress ); + last_progress = progress; + } + child_aid = async_wait ( async, rc, 0 ); + } while ( *rc == -EINPROGRESS ); + + printf ( "\n" ); + return child_aid; +} + /** * Default asynchronous operations * @@ -400,7 +453,8 @@ aid_t async_wait ( struct async *async, int *rc, int block ) { */ struct async_operations default_async_operations = { .signal = { - [SIGCHLD] = SIG_IGN, + [SIGCHLD] = SIG_IGN, + [SIGUPDATE] = SIG_IGN, }, }; @@ -414,6 +468,7 @@ struct async_operations default_async_operations = { */ struct async_operations orphan_async_operations = { .signal = { - [SIGCHLD] = SIG_DFL, + [SIGCHLD] = SIG_DFL, + [SIGUPDATE] = SIG_IGN, }, }; diff --git a/src/include/gpxe/async.h b/src/include/gpxe/async.h index 42ee93d5..2d1d31a4 100644 --- a/src/include/gpxe/async.h +++ b/src/include/gpxe/async.h @@ -204,4 +204,25 @@ static inline aid_t async_init_orphan ( struct async *async ) { rc; \ } ) +/** + * Execute and block on an asynchronous operation, with progress indicator + * + * @v async_temp Temporary asynchronous operation structure to use + * @v START Code used to start the asynchronous operation + * @ret rc Return status code + * + * As for async_block(), the argument START is a code snippet; it + * should initiate an asynchronous operation as a child of @c + * async_temp and return an error status code if it failed to do so + * (e.g. due to malloc() failure). + */ +#define async_block_progress( async_temp, START ) ( { \ + int rc; \ + \ + async_init_orphan ( async_temp ); \ + if ( ( rc = START ) == 0 ) \ + async_wait_progress ( async_temp, &rc );\ + rc; \ + } ) + #endif /* _GPXE_ASYNC_H */