diff -urN autovacuum.c autovacuum.c.new
--- autovacuum.c	2015-06-20 15:36:49.520565000 +0530
+++ autovacuum.c.new	2015-06-20 17:14:15.454835000 +0530
@@ -839,16 +839,22 @@
 	}
 
 	/*
-	 * If the result is exactly zero, it means a database had an entry with
-	 * time in the past.  Rebuild the list so that the databases are evenly
-	 * distributed again, and recalculate the time to sleep.  This can happen
-	 * if there are more tables needing vacuum than workers, and they all take
-	 * longer to vacuum than autovacuum_naptime.
+	 * In an ideal situation sleep time is always greater than zero and less 
+	 * than autovacuum_naptime. Any other value indicates a possible time shift.
+	 * If the result is greater than autovacuum_naptime, it means system time
+	 * has shifted back, specifically more than autovacuum_naptime. If the 
+	 * result is exactly zero, it means a database had an entry with time in
+	 * the past. This can happen either if there are more tables needing vacuum
+	 * then workers, and they all take longer to vacuum than autovacuum_naptime
+	 * or if system time is shifted to future.
+	 *
+	 * In such cases, rebuild the list so that the databases are evenly
+	 * distributed again, and recalculate the time to sleep.
 	 *
 	 * We only recurse once.  rebuild_database_list should always return times
 	 * in the future, but it seems best not to trust too much on that.
 	 */
-	if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing)
+	if (((nap->tv_sec == 0 && nap->tv_usec == 0) || nap->tv_sec > autovacuum_naptime) && !recursing)
 	{
 		rebuild_database_list(InvalidOid);
 		launcher_determine_sleep(canlaunch, true, nap);
@@ -861,6 +867,14 @@
 		nap->tv_sec = 0;
 		nap->tv_usec = MIN_AUTOVAC_SLEEPTIME * 1000;
 	}
+
+	/*
+	 * If the sleep time is too large, clamp it to autovacuum_naptime.
+	 * This avoids an essentially infinite sleep in strange cases like
+	 * clocks going backwards a few years.
+	 */
+	if (nap->tv_sec > autovacuum_naptime)
+		nap->tv_sec = autovacuum_naptime;
 }
 
 /*
diff -urN unix_latch.c unix_latch.c.new
--- unix_latch.c	2015-06-20 17:22:44.749235000 +0530
+++ unix_latch.c.new	2015-06-20 17:49:29.901562000 +0530
@@ -465,14 +465,28 @@
 		{
 			INSTR_TIME_SET_CURRENT(cur_time);
 			INSTR_TIME_SUBTRACT(cur_time, start_time);
-			cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
-			if (cur_timeout < 0)
-				cur_timeout = 0;
+
+			/*
+			 * In normal situations the difference is always positive.
+			 * The difference can be negative only if current_time is
+			 * greater than start_time i.e. system time shifted to past
+			 * time. We treat this situation as timeout.
+			 */
+			if ((long) INSTR_TIME_GET_MILLISEC(cur_time) < 0)
+			{
+				result |= WL_TIMEOUT;
+			}
+			else
+			{
+				cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
+				if (cur_timeout < 0)
+					cur_timeout = 0;
 
 #ifndef HAVE_POLL
-			tv.tv_sec = cur_timeout / 1000L;
-			tv.tv_usec = (cur_timeout % 1000L) * 1000L;
+				tv.tv_sec = cur_timeout / 1000L;
+				tv.tv_usec = (cur_timeout % 1000L) * 1000L;
 #endif
+			}
 		}
 	} while (result == 0);
 	waiting = false;
