diff --git a/rts/GC.c b/rts/GC.c
index a13cd33afadd346ed79e20ac72235ea4e62887eb..d71eaee2e30b710545063e2b5f310de4b3df30f3 100644
--- a/rts/GC.c
+++ b/rts/GC.c
@@ -172,6 +172,7 @@ static void         zero_static_object_list ( StgClosure* first_static );
 
 static rtsBool      traverse_weak_ptr_list  ( void );
 static void         mark_weak_ptr_list      ( StgWeak **list );
+static rtsBool      traverse_blackhole_queue ( void );
 
 static StgClosure * eval_thunk_selector     ( nat field, StgSelector * p );
 
@@ -723,6 +724,11 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
       }
     }
 
+    // if any blackholes are alive, make the threads that wait on
+    // them alive too.
+    if (traverse_blackhole_queue())
+	flag = rtsTrue;
+
     if (flag) { goto loop; }
 
     // must be last...  invariant is that everything is fully
@@ -1366,16 +1372,6 @@ traverse_weak_ptr_list(void)
 		  ;
 	      }
 	      
-	      // Threads blocked on black holes: if the black hole
-	      // is alive, then the thread is alive too.
-	      if (tmp == NULL && t->why_blocked == BlockedOnBlackHole) {
-		  if (isAlive(t->block_info.closure)) {
-		      t = (StgTSO *)evacuate((StgClosure *)t);
-		      tmp = t;
-		      flag = rtsTrue;
-		  }
-	      }
-
 	      if (tmp == NULL) {
 		  // not alive (yet): leave this thread on the
 		  // old_all_threads list.
@@ -1433,6 +1429,34 @@ traverse_weak_ptr_list(void)
 
 }
 
+/* -----------------------------------------------------------------------------
+   The blackhole queue
+   
+   Threads on this list behave like weak pointers during the normal
+   phase of garbage collection: if the blackhole is reachable, then
+   the thread is reachable too.
+   -------------------------------------------------------------------------- */
+static rtsBool
+traverse_blackhole_queue (void)
+{
+    StgTSO *prev, *t, *tmp;
+    rtsBool flag;
+
+    flag = rtsFalse;
+    prev = NULL;
+
+    for (t = blackhole_queue; t != END_TSO_QUEUE; prev=t, t = t->link) {
+	if (! (tmp = (StgTSO *)isAlive((StgClosure*)t))) {
+	    if (isAlive(t->block_info.closure)) {
+		t = (StgTSO *)evacuate((StgClosure *)t);
+		if (prev) prev->link = t;
+		flag = rtsTrue;
+	    }
+	}
+    }
+    return flag;
+}
+
 /* -----------------------------------------------------------------------------
    After GC, the live weak pointer list may have forwarding pointers
    on it, because a weak pointer object was evacuated after being