#include "GC.h"
#include "GCUtils.h"
#include "Printer.h"
+#include "Trace.h"
#ifdef THREADED_RTS
SpinLock gc_alloc_block_sync;
return bd;
}
+void
+freeChain_sync(bdescr *bd)
+{
+ ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync);
+ freeChain(bd);
+ RELEASE_SPIN_LOCK(&gc_alloc_block_sync);
+}
+
/* -----------------------------------------------------------------------------
Workspace utilities
-------------------------------------------------------------------------- */
ACQUIRE_SPIN_LOCK(&stp->sync_todo);
if (stp->todos) {
bd = stp->todos;
+ if (stp->todos == stp->todos_last) {
+ stp->todos_last = NULL;
+ }
stp->todos = bd->link;
+ stp->n_todos--;
bd->link = NULL;
}
RELEASE_SPIN_LOCK(&stp->sync_todo);
{
ASSERT(bd->link == NULL);
ACQUIRE_SPIN_LOCK(&stp->sync_todo);
- bd->link = stp->todos;
- stp->todos = bd;
+ if (stp->todos_last == NULL) {
+ stp->todos_last = bd;
+ stp->todos = bd;
+ } else {
+ stp->todos_last->link = bd;
+ stp->todos_last = bd;
+ }
+ stp->n_todos++;
+ trace(TRACE_gc|DEBUG_gc, "step %d, n_todos: %d", stp->abs_no, stp->n_todos);
RELEASE_SPIN_LOCK(&stp->sync_todo);
}
ASSERT(bd->link == NULL);
// update stats: this is a block that has been copied & scavenged
- copied += bd->free - bd->start;
+ gct->copied += bd->free - bd->start;
- // put the scan block *second* in ws->scavd_list. The first block
- // in this list is for evacuating objects that don't need to be
- // scavenged.
- bd->link = ws->scavd_list->link;
- ws->scavd_list->link = bd;
+ // put the scan block on the ws->scavd_list.
+ bd->link = ws->scavd_list;
+ ws->scavd_list = bd;
ws->n_scavd_blocks ++;
IF_DEBUG(sanity,
ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks));
}
-bdescr *
+StgPtr
gc_alloc_todo_block (step_workspace *ws)
{
bdescr *bd;
+ if (ws->todo_bd != NULL) {
+ ws->todo_bd->free = ws->todo_free;
+ }
+
// 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 (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;
+ }
+ } else {
ASSERT(ws->buffer_todo_bd->link == NULL);
push_todo_block(ws->buffer_todo_bd, ws->stp);
- }
- ws->buffer_todo_bd = ws->todo_bd;
+ ws->buffer_todo_bd = ws->todo_bd;
+ }
ws->todo_bd = NULL;
}
}
ws->todo_bd = bd;
+ ws->todo_free = bd->start;
+ ws->todo_lim = bd->start + BLOCK_SIZE_W;
- return bd;
-}
-
-bdescr *
-gc_alloc_scavd_block (step_workspace *ws)
-{
- bdescr *bd;
-
- bd = allocBlock_sync();
-
- bd->gen_no = ws->stp->gen_no;
- bd->step = ws->stp;
-
- // blocks in to-space in generations up to and including N
- // get the BF_EVACUATED flag.
- if (ws->stp->gen_no <= N) {
- bd->flags = BF_EVACUATED;
- } else {
- bd->flags = 0;
- }
-
- // update stats: this is a block that has been copied only
- if (ws->scavd_list != NULL) {
- scavd_copied += ws->scavd_list->free - ws->scavd_list->start;
- }
-
- bd->link = ws->scavd_list;
- ws->scavd_list = bd;
- ws->n_scavd_blocks++;
-
- return bd;
+ return ws->todo_free;
}
/* -----------------------------------------------------------------------------