#---------------8<---[snip]---------------------------------------------------------------------------------
# create a permanent sleeping beauty process that sleeps 1/18.2th of second
# every four times it gets scheduled, unless the do_not_sleep flag is set.
# the do_not_sleep flag is meant to be set when a download is in progress,
# so that the download throughput is not affected.
#---------------8<---[snip]---------------------------------------------------------------------------------
--- a/src/usr/sleeping_beauty.c	1969-12-31 16:00:00.000000000 -0800
+++ b/src/usr/sleeping_beauty.c	2012-06-25 15:27:46.607097999 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 Embrane, Inc. <alessandro.salvatori@embrane.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/process.h>
+#include <ipxe/nap.h>
+#include <usr/sleeping_beauty.h>
+
+
+
+#define SLEEPING_FACTOR 4
+
+static int do_not_sleep = 0;
+
+void prince_kisses_sleeping_beauty(void) {
+	do_not_sleep = 1; 
+}
+
+void sleeping_beauty_bites_the_apple(void) {
+	do_not_sleep = 0;
+}
+
+/**
+ * Sleep every SLEEPING_FACTOR times
+ *
+ * @v process		Network stack process
+ */
+static void sleeping_step ( struct process *process __unused ) {
+	static int countdown = 0;
+
+	if ( 0 == countdown ) {
+		countdown = SLEEPING_FACTOR;
+	}
+
+	if ( do_not_sleep || --countdown ) {
+		return;
+	}
+
+	cpu_nap();
+}
+
+/* Sleeping beauty process */
+PERMANENT_PROCESS ( sleeping_beauty, sleeping_step );
#---------------8<---[snip]---------------------------------------------------------------------------------
# make two methods available to toggle the aggressive polling on and off: 
#
# - prince_kisses_sleeping_beauty()   <-- the beauty wakes up and polls agressively
#
# - sleeping_beauty_bites_the_apple() <-- the beauty falls asleep again and uses very little CPU
#
#---------------8<---[snip]---------------------------------------------------------------------------------
--- a/src/usr/sleeping_beauty.h	1969-12-31 16:00:00.000000000 -0800
+++ b/src/usr/sleeping_beauty.h	2012-06-25 15:27:17.118098360 -0700
@@ -0,0 +1,3 @@
+extern void prince_kisses_sleeping_beauty(void);
+
+extern void sleeping_beauty_bites_the_apple(void);
#---------------8<---[snip]---------------------------------------------------------------------------------
# Detect when TCP connections stall, and fail the download, else from there
# on we would be sucking the host CPU forever.
#---------------8<---[snip]---------------------------------------------------------------------------------
diff --git a/src/core/monojob.c b/src/core/monojob.c
index d2161b3..9bcb943 100644
--- a/src/core/monojob.c
+++ b/src/core/monojob.c
@@ -67,6 +67,8 @@ int monojob_wait ( const char *string ) {
 	unsigned long completed;
 	unsigned long total;
 	unsigned int percentage;
+	unsigned long last_completed = 0;
+	unsigned int stalled_seconds = 0;
 	int shown_percentage = 0;
 
 	if ( string )
@@ -102,6 +104,15 @@ int monojob_wait ( const char *string ) {
 			if ( shown_percentage )
 				printf ( "\b\b\b\b    \b\b\b\b" );
 			job_progress ( &monojob, &progress );
+			if ( last_completed == progress.completed ) {
+				++stalled_seconds;
+			} else {
+				stalled_seconds=0;
+			}
+			if ( stalled_seconds >= 30 ) {
+				monojob_close ( &monojob, -ETIME );
+				break;
+			}
 			/* Normalise progress figures to avoid overflow */
 			completed = ( progress.completed / 128 );
 			total = ( progress.total / 128 );
@@ -113,6 +124,7 @@ int monojob_wait ( const char *string ) {
 				printf ( "." );
 				shown_percentage = 0;
 			}
+			last_completed = progress.completed;
 			last_progress = now;
 		}
 	}
#---------------8<---[snip]---------------------------------------------------------------------------------
# Avoid using 100% CPU at all times (bad for virtualized environments).
# When a download making progress, go back to aggressive polling
#---------------8<---[snip]---------------------------------------------------------------------------------
diff -u b/src/core/monojob.c b/src/core/monojob.c
--- a/src/core/monojob.c
+++ b/src/core/monojob.c
@@ -27,6 +27,7 @@
 #include <ipxe/job.h>
 #include <ipxe/monojob.h>
 #include <ipxe/timer.h>
+#include <usr/sleeping_beauty.h>
 
 /** @file
  *
@@ -104,6 +105,9 @@
 			if ( shown_percentage )
 				printf ( "\b\b\b\b    \b\b\b\b" );
 			job_progress ( &monojob, &progress );
+			if ( progress.completed && !last_completed ) {
+				prince_kisses_sleeping_beauty();
+			}
 			if ( last_completed == progress.completed ) {
 				++stalled_seconds;
 			} else {
#---------------8<---[snip]---------------------------------------------------------------------------------
# Avoid using 100% CPU at all times (bad for virtualized environments).
# When a download fails, go back to moderate polling
#---------------8<---[snip]---------------------------------------------------------------------------------
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <usr/dhcpmgmt.h>
 #include <usr/imgmgmt.h>
 #include <usr/autoboot.h>
+#include <usr/sleeping_beauty.h>
 
 /** @file
  *
@@ -396,6 +397,9 @@ int netboot ( struct net_device *netdev ) {
  err_pxe_menu_boot:
  err_dhcp:
  err_ifopen:
+
+	sleeping_beauty_bites_the_apple();
+
 	return rc;
 }
 
#---------------8<---[snip]---------------------------------------------------------------------------------
