1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team 1998-2006
5 * Generational garbage collector: utilities
7 * Documentation on the architecture of the Garbage Collector can be
8 * found in the online commentary:
10 * http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/GC
12 * ---------------------------------------------------------------------------*/
23 SpinLock gc_alloc_block_sync;
30 ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync);
32 RELEASE_SPIN_LOCK(&gc_alloc_block_sync);
37 freeChain_sync(bdescr *bd)
39 ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync);
41 RELEASE_SPIN_LOCK(&gc_alloc_block_sync);
44 /* -----------------------------------------------------------------------------
46 -------------------------------------------------------------------------- */
49 grab_todo_block (step_workspace *ws)
57 if (ws->buffer_todo_bd)
59 bd = ws->buffer_todo_bd;
60 ASSERT(bd->link == NULL);
61 ws->buffer_todo_bd = NULL;
65 ACQUIRE_SPIN_LOCK(&stp->sync_todo);
68 if (stp->todos == stp->todos_last) {
69 stp->todos_last = NULL;
71 stp->todos = bd->link;
75 RELEASE_SPIN_LOCK(&stp->sync_todo);
80 push_todo_block (bdescr *bd, step *stp)
82 ASSERT(bd->link == NULL);
83 ACQUIRE_SPIN_LOCK(&stp->sync_todo);
84 if (stp->todos_last == NULL) {
88 stp->todos_last->link = bd;
92 trace(TRACE_gc|DEBUG_gc, "step %d, n_todos: %d", stp->abs_no, stp->n_todos);
93 RELEASE_SPIN_LOCK(&stp->sync_todo);
97 push_scan_block (bdescr *bd, step_workspace *ws)
100 ASSERT(bd->link == NULL);
102 // update stats: this is a block that has been copied & scavenged
103 gct->copied += bd->free - bd->start;
105 // put the scan block on the ws->scavd_list.
106 bd->link = ws->scavd_list;
108 ws->n_scavd_blocks ++;
111 ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks));
115 gc_alloc_todo_block (step_workspace *ws)
119 if (ws->todo_bd != NULL) {
120 ws->todo_bd->free = ws->todo_free;
123 // If we already have a todo block, it must be full, so we push it
124 // out: first to the buffer_todo_bd, then to the step. BUT, don't
125 // push out the block out if it is already the scan block.
126 if (ws->todo_bd != NULL && ws->scan_bd != ws->todo_bd) {
127 ASSERT(ws->todo_bd->link == NULL);
128 if (ws->buffer_todo_bd == NULL) {
129 // If the global todo list is empty, push this block
130 // out immediately rather than caching it in
131 // buffer_todo_bd, because there might be other threads
133 if (ws->stp->todos == NULL) {
134 push_todo_block(ws->todo_bd, ws->stp);
136 ws->buffer_todo_bd = ws->todo_bd;
139 ASSERT(ws->buffer_todo_bd->link == NULL);
140 push_todo_block(ws->buffer_todo_bd, ws->stp);
141 ws->buffer_todo_bd = ws->todo_bd;
146 bd = allocBlock_sync();
148 bd->gen_no = ws->stp->gen_no;
152 // blocks in to-space in generations up to and including N
153 // get the BF_EVACUATED flag.
154 if (ws->stp->gen_no <= N) {
155 bd->flags = BF_EVACUATED;
161 ws->todo_free = bd->start;
162 ws->todo_lim = bd->start + BLOCK_SIZE_W;
164 return ws->todo_free;
167 /* -----------------------------------------------------------------------------
169 * -------------------------------------------------------------------------- */
173 printMutableList(generation *gen)
178 debugBelch("mutable list %p: ", gen->mut_list);
180 for (bd = gen->mut_list; bd != NULL; bd = bd->link) {
181 for (p = bd->start; p < bd->free; p++) {
182 debugBelch("%p (%s), ", (void *)*p, info_type((StgClosure *)*p));