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 stp->todos = bd->link;
72 RELEASE_SPIN_LOCK(&stp->sync_todo);
77 push_todo_block (bdescr *bd, step *stp)
79 ASSERT(bd->link == NULL);
80 ACQUIRE_SPIN_LOCK(&stp->sync_todo);
81 bd->link = stp->todos;
84 trace(TRACE_gc, "step %d, n_todos: %d", stp->abs_no, stp->n_todos);
85 RELEASE_SPIN_LOCK(&stp->sync_todo);
89 push_scan_block (bdescr *bd, step_workspace *ws)
92 ASSERT(bd->link == NULL);
94 // update stats: this is a block that has been copied & scavenged
95 copied += bd->free - bd->start;
97 // put the scan block on the ws->scavd_list.
98 bd->link = ws->scavd_list;
100 ws->n_scavd_blocks ++;
103 ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks));
107 gc_alloc_todo_block (step_workspace *ws)
111 if (ws->todo_bd != NULL) {
112 ws->todo_bd->free = ws->todo_free;
115 // If we already have a todo block, it must be full, so we push it
116 // out: first to the buffer_todo_bd, then to the step. BUT, don't
117 // push out the block out if it is already the scan block.
118 if (ws->todo_bd != NULL && ws->scan_bd != ws->todo_bd) {
119 ASSERT(ws->todo_bd->link == NULL);
120 if (ws->buffer_todo_bd == NULL) {
121 // If the global todo list is empty, push this block
122 // out immediately rather than caching it in
123 // buffer_todo_bd, because there might be other threads
125 if (ws->stp->todos == NULL) {
126 push_todo_block(ws->todo_bd, ws->stp);
128 ws->buffer_todo_bd = ws->todo_bd;
131 ASSERT(ws->buffer_todo_bd->link == NULL);
132 push_todo_block(ws->buffer_todo_bd, ws->stp);
133 ws->buffer_todo_bd = ws->todo_bd;
138 bd = allocBlock_sync();
140 bd->gen_no = ws->stp->gen_no;
144 // blocks in to-space in generations up to and including N
145 // get the BF_EVACUATED flag.
146 if (ws->stp->gen_no <= N) {
147 bd->flags = BF_EVACUATED;
153 ws->todo_free = bd->start;
154 ws->todo_lim = bd->start + BLOCK_SIZE_W;
156 return ws->todo_free;
159 /* -----------------------------------------------------------------------------
161 * -------------------------------------------------------------------------- */
165 printMutableList(generation *gen)
170 debugBelch("mutable list %p: ", gen->mut_list);
172 for (bd = gen->mut_list; bd != NULL; bd = bd->link) {
173 for (p = bd->start; p < bd->free; p++) {
174 debugBelch("%p (%s), ", (void *)*p, info_type((StgClosure *)*p));