aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown <mcb30@etherboot.org>2007-01-29 04:15:24 +0000
committerMichael Brown <mcb30@etherboot.org>2007-01-29 04:15:24 +0000
commit1a79437888be127a1a966e20145d79e0673275d1 (patch)
tree1a6bbbf47d83af7908a15f7a9dfbcc2ab4da3582
parentc42a38470992c70716b683968bc8479df90ad984 (diff)
downloadipxe-1a79437888be127a1a966e20145d79e0673275d1.tar.gz
Added async_block_progress() and default SIGUPDATE handler.
-rw-r--r--src/core/async.c61
-rw-r--r--src/include/gpxe/async.h21
2 files changed, 79 insertions, 3 deletions
diff --git a/src/core/async.c b/src/core/async.c
index 20be7f565..d1ae0770a 100644
--- a/src/core/async.c
+++ b/src/core/async.c
@@ -154,6 +154,28 @@ static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
}
/**
+ * 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
*
* @v async Asynchronous operation
@@ -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;
@@ -392,6 +416,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
*
* The default is to ignore SIGCHLD (i.e. to automatically reap
@@ -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 42ee93d59..2d1d31a4a 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 */