- // If we already have a todo block, it must be full, so we push it
- // out: first to the buffer_todo_bd, then to the step. BUT, don't
- // push out the block out if it is already the scan block.
- if (ws->todo_bd != NULL && ws->scan_bd != ws->todo_bd) {
- ASSERT(ws->todo_bd->link == NULL);
- if (ws->buffer_todo_bd == NULL) {
- // If the global todo list is empty, push this block
- // out immediately rather than caching it in
- // buffer_todo_bd, because there might be other threads
- // waiting for work.
- if (ws->stp->todos == NULL) {
- push_todo_block(ws->todo_bd, ws->stp);
- } else {
- ws->buffer_todo_bd = ws->todo_bd;
+ // If this block is not the scan block, we want to push it out and
+ // make room for a new todo block.
+ if (bd != gct->scan_bd)
+ {
+ // If this block does not have enough space to allocate the
+ // current object, but it also doesn't have any work to push, then
+ // push it on to the scanned list. It cannot be empty, because
+ // then there would be enough room to copy the current object.
+ if (bd->u.scan == bd->free)
+ {
+ ASSERT(bd->free != bd->start);
+ push_scanned_block(bd, ws);
+ }
+ // Otherwise, push this block out to the global list.
+ else
+ {
+ step *stp;
+ stp = ws->step;
+ debugTrace(DEBUG_gc, "push todo block %p (%ld words), step %d, todo_q: %ld",
+ bd->start, (unsigned long)(bd->free - bd->u.scan),
+ stp->abs_no, dequeElements(ws->todo_q));
+
+ if (!pushWSDeque(ws->todo_q, bd)) {
+ bd->link = ws->todo_overflow;
+ ws->todo_overflow = bd;
+ ws->n_todo_overflow++;