~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to stubborn.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
#include "private/gc_priv.h"
18
18
 
19
 
# ifdef STUBBORN_ALLOC
 
19
#if defined(MANUAL_VDB)
20
20
/* Stubborn object (hard to change, nearly immutable) allocation. */
21
 
 
22
 
extern ptr_t GC_clear_stack();  /* in misc.c, behaves like identity */
23
 
 
24
 
#define GENERAL_MALLOC(lb,k) \
25
 
    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
26
 
 
27
 
/* Data structure representing immutable objects that   */
28
 
/* are still being initialized.                         */
29
 
/* This is a bit baroque in order to avoid acquiring    */
30
 
/* the lock twice for a typical allocation.             */
31
 
 
32
 
GC_PTR * GC_changing_list_start;
33
 
 
34
 
void GC_push_stubborn_structures GC_PROTO((void))
35
 
{
36
 
    GC_push_all((ptr_t)(&GC_changing_list_start),
37
 
                (ptr_t)(&GC_changing_list_start) + sizeof(GC_PTR *));
38
 
}
39
 
 
40
 
# ifdef THREADS
41
 
  VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
42
 
# else
43
 
  GC_PTR * GC_changing_list_current;
44
 
# endif
45
 
        /* Points at last added element.  Also (ab)used for             */
46
 
        /* synchronization.  Updates and reads are assumed atomic.      */
47
 
 
48
 
GC_PTR * GC_changing_list_limit;
49
 
        /* Points at the last word of the buffer, which is always 0     */
50
 
        /* All entries in (GC_changing_list_current,                    */
51
 
        /* GC_changing_list_limit] are 0                                */
52
 
 
53
 
 
54
 
void GC_stubborn_init()
55
 
{
56
 
#   define INIT_SIZE 10
57
 
 
58
 
    GC_changing_list_start = (GC_PTR *)
59
 
                        GC_INTERNAL_MALLOC(
60
 
                                (word)(INIT_SIZE * sizeof(GC_PTR)),
61
 
                                PTRFREE);
62
 
    BZERO(GC_changing_list_start,
63
 
          INIT_SIZE * sizeof(GC_PTR));
64
 
    if (GC_changing_list_start == 0) {
65
 
        GC_err_printf0("Insufficient space to start up\n");
66
 
        ABORT("GC_stubborn_init: put of space");
67
 
    }
68
 
    GC_changing_list_current = GC_changing_list_start;
69
 
    GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1;
70
 
    * GC_changing_list_limit = 0;
71
 
}
72
 
 
73
 
/* Compact and possibly grow GC_uninit_list.  The old copy is           */
74
 
/* left alone.  Lock must be held.                                      */
75
 
/* When called GC_changing_list_current == GC_changing_list_limit       */
76
 
/* which is one past the current element.                               */
77
 
/* When we finish GC_changing_list_current again points one past last   */
78
 
/* element.                                                             */
79
 
/* Invariant while this is running: GC_changing_list_current            */
80
 
/* points at a word containing 0.                                       */
81
 
/* Returns FALSE on failure.                                            */
82
 
GC_bool GC_compact_changing_list()
83
 
{
84
 
    register GC_PTR *p, *q;
85
 
    register word count = 0;
86
 
    word old_size = (char **)GC_changing_list_limit
87
 
                    - (char **)GC_changing_list_start+1;
88
 
                    /* The casts are needed as a workaround for an Amiga bug */
89
 
    register word new_size = old_size;
90
 
    GC_PTR * new_list;
91
 
    
92
 
    for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
93
 
        if (*p != 0) count++;
94
 
    }
95
 
    if (2 * count > old_size) new_size = 2 * count;
96
 
    new_list = (GC_PTR *)
97
 
                GC_INTERNAL_MALLOC(
98
 
                                new_size * sizeof(GC_PTR), PTRFREE);
99
 
                /* PTRFREE is a lie.  But we don't want the collector to  */
100
 
                /* consider these.  We do want the list itself to be      */
101
 
                /* collectable.                                           */
102
 
    if (new_list == 0) return(FALSE);
103
 
    BZERO(new_list, new_size * sizeof(GC_PTR));
104
 
    q = new_list;
105
 
    for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
106
 
        if (*p != 0) *q++ = *p;
107
 
    }
108
 
    GC_changing_list_start = new_list;
109
 
    GC_changing_list_limit = new_list + new_size - 1;
110
 
    GC_changing_list_current = q;
111
 
    return(TRUE);
112
 
}
113
 
 
114
 
/* Add p to changing list.  Clear p on failure. */
115
 
# define ADD_CHANGING(p) \
116
 
        {       \
117
 
            register struct hblk * h = HBLKPTR(p);      \
118
 
            register word index = PHT_HASH(h);  \
119
 
            \
120
 
            set_pht_entry_from_index(GC_changed_pages, index);  \
121
 
        }       \
122
 
        if (*GC_changing_list_current != 0 \
123
 
            && ++GC_changing_list_current == GC_changing_list_limit) { \
124
 
            if (!GC_compact_changing_list()) (p) = 0; \
125
 
        } \
126
 
        *GC_changing_list_current = p;
127
 
 
128
 
void GC_change_stubborn(p)
129
 
GC_PTR p;
130
 
{
131
 
    DCL_LOCK_STATE;
132
 
    
133
 
    DISABLE_SIGNALS();
134
 
    LOCK();
135
 
    ADD_CHANGING(p);
136
 
    UNLOCK();
137
 
    ENABLE_SIGNALS();
138
 
}
139
 
 
140
 
void GC_end_stubborn_change(p)
141
 
GC_PTR p;
142
 
{
143
 
#   ifdef THREADS
144
 
      register VOLATILE GC_PTR * my_current = GC_changing_list_current;
145
 
#   else
146
 
      register GC_PTR * my_current = GC_changing_list_current;
147
 
#   endif
148
 
    register GC_bool tried_quick;
149
 
    DCL_LOCK_STATE;
150
 
    
151
 
    if (*my_current == p) {
152
 
        /* Hopefully the normal case.                                   */
153
 
        /* Compaction could not have been running when we started.      */
154
 
        *my_current = 0;
155
 
#       ifdef THREADS
156
 
          if (my_current == GC_changing_list_current) {
157
 
            /* Compaction can't have run in the interim.        */
158
 
            /* We got away with the quick and dirty approach.   */
159
 
            return;
160
 
          }
161
 
          tried_quick = TRUE;
162
 
#       else
163
 
          return;
164
 
#       endif
165
 
    } else {
166
 
        tried_quick = FALSE;
167
 
    }
168
 
    DISABLE_SIGNALS();
169
 
    LOCK();
170
 
    my_current = GC_changing_list_current;
171
 
    for (; my_current >= GC_changing_list_start; my_current--) {
172
 
        if (*my_current == p) {
173
 
            *my_current = 0;
174
 
            UNLOCK();
175
 
            ENABLE_SIGNALS();
176
 
            return;
177
 
        }
178
 
    }
179
 
    if (!tried_quick) {
180
 
        GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n",
181
 
                       (unsigned long)p);
182
 
        ABORT("Bad arg to GC_end_stubborn_change");
183
 
    }
184
 
    UNLOCK();
185
 
    ENABLE_SIGNALS();
186
 
}
187
 
 
188
 
/* Allocate lb bytes of composite (pointerful) data     */
189
 
/* No pointer fields may be changed after a call to     */
190
 
/* GC_end_stubborn_change(p) where p is the value       */
191
 
/* returned by GC_malloc_stubborn.                      */
192
 
# ifdef __STDC__
193
 
    GC_PTR GC_malloc_stubborn(size_t lb)
194
 
# else
195
 
    GC_PTR GC_malloc_stubborn(lb)
196
 
    size_t lb;
197
 
# endif
198
 
{
199
 
register ptr_t op;
200
 
register ptr_t *opp;
201
 
register word lw;
202
 
ptr_t result;
203
 
DCL_LOCK_STATE;
204
 
 
205
 
    if( SMALL_OBJ(lb) ) {
206
 
#       ifdef MERGE_SIZES
207
 
          lw = GC_size_map[lb];
208
 
#       else
209
 
          lw = ALIGNED_WORDS(lb);
210
 
#       endif
211
 
        opp = &(GC_sobjfreelist[lw]);
212
 
        FASTLOCK();
213
 
        if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
214
 
            FASTUNLOCK();
215
 
            result = GC_generic_malloc((word)lb, STUBBORN);
216
 
            goto record;
217
 
        }
218
 
        *opp = obj_link(op);
219
 
        obj_link(op) = 0;
220
 
        GC_words_allocd += lw;
221
 
        result = (GC_PTR) op;
222
 
        ADD_CHANGING(result);
223
 
        FASTUNLOCK();
224
 
        return((GC_PTR)result);
225
 
   } else {
226
 
       result = (GC_PTR)
227
 
                GC_generic_malloc((word)lb, STUBBORN);
228
 
   }
229
 
record:
230
 
   DISABLE_SIGNALS();
231
 
   LOCK();
232
 
   ADD_CHANGING(result);
233
 
   UNLOCK();
234
 
   ENABLE_SIGNALS();
235
 
   return((GC_PTR)GC_clear_stack(result));
236
 
}
237
 
 
238
 
 
239
 
/* Functions analogous to GC_read_dirty and GC_page_was_dirty.  */
240
 
/* Report pages on which stubborn objects were changed.         */
241
 
void GC_read_changed()
242
 
{
243
 
    register GC_PTR * p = GC_changing_list_start;
244
 
    register GC_PTR q;
245
 
    register struct hblk * h;
246
 
    register word index;
247
 
    
248
 
    if (p == 0) /* initializing */ return;
249
 
    BCOPY(GC_changed_pages, GC_prev_changed_pages,
250
 
          (sizeof GC_changed_pages));
251
 
    BZERO(GC_changed_pages, (sizeof GC_changed_pages));
252
 
    for (; p <= GC_changing_list_current; p++) {
253
 
        if ((q = *p) != 0) {
254
 
            h = HBLKPTR(q);
255
 
            index = PHT_HASH(h);
256
 
            set_pht_entry_from_index(GC_changed_pages, index);
257
 
        }
258
 
    }
259
 
}
260
 
 
261
 
GC_bool GC_page_was_changed(h)
262
 
struct hblk * h;
263
 
{
264
 
    register word index = PHT_HASH(h);
265
 
    
266
 
    return(get_pht_entry_from_index(GC_prev_changed_pages, index));
267
 
}
268
 
 
269
 
/* Remove unreachable entries from changed list. Should only be */
270
 
/* called with mark bits consistent and lock held.              */
271
 
void GC_clean_changing_list()
272
 
{
273
 
    register GC_PTR * p = GC_changing_list_start;
274
 
    register GC_PTR q;
275
 
    register ptr_t r;
276
 
    register unsigned long count = 0;
277
 
    register unsigned long dropped_count = 0;
278
 
    
279
 
    if (p == 0) /* initializing */ return;
280
 
    for (; p <= GC_changing_list_current; p++) {
281
 
        if ((q = *p) != 0) {
282
 
            count++;
283
 
            r = (ptr_t)GC_base(q);
284
 
            if (r == 0 || !GC_is_marked(r)) {
285
 
                *p = 0;
286
 
                dropped_count++;
287
 
            }
288
 
        }
289
 
    }
290
 
#   ifdef PRINTSTATS
291
 
      if (count > 0) {
292
 
        GC_printf2("%lu entries in changing list: reclaimed %lu\n",
293
 
                  (unsigned long)count, (unsigned long)dropped_count);
294
 
      }
295
 
#   endif
296
 
}
297
 
 
298
 
#else /* !STUBBORN_ALLOC */
299
 
 
300
 
# ifdef __STDC__
301
 
    GC_PTR GC_malloc_stubborn(size_t lb)
302
 
# else
303
 
    GC_PTR GC_malloc_stubborn(lb)
304
 
    size_t lb;
305
 
# endif
306
 
{
307
 
    return(GC_malloc(lb));
308
 
}
309
 
 
310
 
/*ARGSUSED*/
311
 
void GC_end_stubborn_change(p)
312
 
GC_PTR p;
313
 
{
314
 
}
315
 
 
316
 
/*ARGSUSED*/
317
 
void GC_change_stubborn(p)
318
 
GC_PTR p;
319
 
{
320
 
}
321
 
 
322
 
void GC_push_stubborn_structures GC_PROTO((void))
323
 
{
324
 
}
325
 
 
326
 
#endif
 
21
/* This interface is deprecated.  We mostly emulate it using      */
 
22
/* MANUAL_VDB.  But that imposes the additional constraint that   */
 
23
/* written, but not yet GC_dirty()ed objects must be referenced   */
 
24
/* by a stack.                                                    */
 
25
void * GC_malloc_stubborn(size_t lb)
 
26
{
 
27
    return(GC_malloc(lb));
 
28
}
 
29
 
 
30
/*ARGSUSED*/
 
31
void GC_end_stubborn_change(void *p)
 
32
{
 
33
    GC_dirty(p);
 
34
}
 
35
 
 
36
/*ARGSUSED*/
 
37
void GC_change_stubborn(void *p)
 
38
{
 
39
}
 
40
 
 
41
#else /* !MANUAL_VDB */
 
42
 
 
43
void * GC_malloc_stubborn(size_t lb)
 
44
{
 
45
    return(GC_malloc(lb));
 
46
}
 
47
 
 
48
/*ARGSUSED*/
 
49
void GC_end_stubborn_change(void *p)
 
50
{
 
51
}
 
52
 
 
53
/*ARGSUSED*/
 
54
void GC_change_stubborn(void *p)
 
55
{
 
56
}
 
57
 
 
58
#endif /* !MANUAL_VDB */