- ASSERT(get_itbl(t)->type == TSO);
- switch (t->what_next) {
- case ThreadRelocated:
- next = t->_link;
- *prev = next;
- continue;
- case ThreadKilled:
- case ThreadComplete:
- // finshed or died. The thread might still be alive, but we
- // don't keep it on the all_threads list. Don't forget to
- // stub out its global_link field.
- next = t->global_link;
- t->global_link = END_TSO_QUEUE;
- *prev = next;
- continue;
- default:
- ;
- }
-
- if (tmp == NULL) {
- // not alive (yet): leave this thread on the
- // old_all_threads list.
- prev = &(t->global_link);
- next = t->global_link;
- }
- else {
- // alive: move this thread onto the all_threads list.
- next = t->global_link;
- t->global_link = all_threads;
- all_threads = t;
- *prev = next;
- }
- }
+ if (tmp != NULL) {
+ t = tmp;
+ }
+
+ ASSERT(get_itbl(t)->type == TSO);
+ if (t->what_next == ThreadRelocated) {
+ next = t->_link;
+ *prev = next;
+ continue;
+ }
+
+ next = t->global_link;
+
+ // This is a good place to check for blocked
+ // exceptions. It might be the case that a thread is
+ // blocked on delivering an exception to a thread that
+ // is also blocked - we try to ensure that this
+ // doesn't happen in throwTo(), but it's too hard (or
+ // impossible) to close all the race holes, so we
+ // accept that some might get through and deal with
+ // them here. A GC will always happen at some point,
+ // even if the system is otherwise deadlocked.
+ //
+ // If an unreachable thread has blocked
+ // exceptions, we really want to perform the
+ // blocked exceptions rather than throwing
+ // BlockedIndefinitely exceptions. This is the
+ // only place we can discover such threads.
+ // The target thread might even be
+ // ThreadFinished or ThreadKilled. Bugs here
+ // will only be seen when running on a
+ // multiprocessor.
+ if (t->blocked_exceptions != END_TSO_QUEUE) {
+ if (tmp == NULL) {
+ evacuate((StgClosure **)&t);
+ flag = rtsTrue;
+ }
+ t->global_link = exception_threads;
+ exception_threads = t;
+ *prev = next;
+ continue;
+ }
+
+ if (tmp == NULL) {
+ // not alive (yet): leave this thread on the
+ // old_all_threads list.
+ prev = &(t->global_link);
+ }
+ else {
+ // alive
+ *prev = next;
+
+ // move this thread onto the correct threads list.
+ step *new_step;
+ new_step = Bdescr((P_)t)->step;
+ t->global_link = new_step->threads;
+ new_step->threads = t;
+ }
+ }
+ }
+ }