Added async_block_progress() and default SIGUPDATE handler.
authorMichael Brown <mcb30@etherboot.org>
Mon, 29 Jan 2007 04:15:24 +0000 (04:15 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 29 Jan 2007 04:15:24 +0000 (04:15 +0000)
src/core/async.c
src/include/gpxe/async.h

index 20be7f5..d1ae077 100644 (file)
@@ -153,6 +153,28 @@ static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
        assert ( waited_aid >= 0 );
 }
 
        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
  *
 /**
  * '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 SIGCHLD:
                async_ignore_sigchld ( async, signal );
                break;
-       case SIGKILL:
        case SIGUPDATE:
        case SIGUPDATE:
+               async_ignore_sigupdate ( async, signal );
+               break;
+       case SIGKILL:
        default:
                /* Nothing to do */
                break;
        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
  *
 /**
  * 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 = {
  */
 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 = {
  */
 struct async_operations orphan_async_operations = {
        .signal = {
-               [SIGCHLD] = SIG_DFL,
+               [SIGCHLD]       = SIG_DFL,
+               [SIGUPDATE]     = SIG_IGN,
        },
 };
        },
 };
index 42ee93d..2d1d31a 100644 (file)
@@ -204,4 +204,25 @@ static inline aid_t async_init_orphan ( struct async *async ) {
                rc;                                             \
        } )
 
                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 */
 #endif /* _GPXE_ASYNC_H */