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

« back to all changes in this revision

Viewing changes to misc.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:
17
17
 
18
18
#include <stdio.h>
19
19
#include <limits.h>
 
20
#include <stdarg.h>
20
21
#ifndef _WIN32_WCE
21
22
#include <signal.h>
22
23
#endif
34
35
# include <tchar.h>
35
36
#endif
36
37
 
 
38
#ifdef UNIX_LIKE
 
39
# include <fcntl.h>
 
40
# include <sys/types.h>
 
41
# include <sys/stat.h>
 
42
 
 
43
  int GC_log;  /* Forward decl, so we can set it.       */
 
44
#endif
 
45
 
37
46
#ifdef NONSTOP
38
47
# include <floss.h>
39
48
#endif
40
49
 
41
 
# ifdef THREADS
42
 
#   ifdef PCR
43
 
#     include "il/PCR_IL.h"
44
 
      PCR_Th_ML GC_allocate_ml;
45
 
#   else
46
 
#     ifdef SRC_M3
47
 
        /* Critical section counter is defined in the M3 runtime        */
48
 
        /* That's all we use.                                           */
49
 
#     else
50
 
#       ifdef GC_SOLARIS_THREADS
51
 
          mutex_t GC_allocate_ml;       /* Implicitly initialized.      */
52
 
#       else
53
 
#          if defined(GC_WIN32_THREADS) 
54
 
#             if defined(GC_PTHREADS)
55
 
                  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
56
 
#             elif defined(GC_DLL)
57
 
                 __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
58
 
#             else
59
 
                 CRITICAL_SECTION GC_allocate_ml;
60
 
#             endif
61
 
#          else
62
 
#             if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
63
 
#               if defined(USE_SPIN_LOCK)
64
 
                  pthread_t GC_lock_holder = NO_THREAD;
65
 
#               else
66
 
                  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
67
 
                  pthread_t GC_lock_holder = NO_THREAD;
68
 
                        /* Used only for assertions, and to prevent      */
69
 
                        /* recursive reentry in the system call wrapper. */
70
 
#               endif 
71
 
#             else
72
 
                  --> declare allocator lock here
73
 
#             endif
74
 
#          endif
75
 
#       endif
76
 
#     endif
77
 
#   endif
78
 
# endif
 
50
#if defined(THREADS) && defined(PCR)
 
51
# include "il/PCR_IL.h"
 
52
  PCR_Th_ML GC_allocate_ml;
 
53
#endif
 
54
/* For other platforms with threads, the lock and possibly              */
 
55
/* GC_lock_holder variables are defined in the thread support code.     */
79
56
 
80
57
#if defined(NOSYS) || defined(ECOS)
81
58
#undef STACKBASE
95
72
GC_bool GC_debugging_started = FALSE;
96
73
        /* defined here so we don't have to load debug_malloc.o */
97
74
 
98
 
void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
99
 
void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
 
75
void (*GC_check_heap) (void) = (void (*) (void))0;
 
76
void (*GC_print_all_smashed) (void) = (void (*) (void))0;
100
77
 
101
 
void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
 
78
void (*GC_start_call_back) (void) = (void (*) (void))0;
102
79
 
103
80
ptr_t GC_stackbottom = 0;
104
81
 
112
89
 
113
90
GC_bool GC_quiet = 0;
114
91
 
115
 
GC_bool GC_print_stats = 0;
 
92
#ifndef SMALL_CONFIG
 
93
  GC_bool GC_print_stats = 0;
 
94
#endif
116
95
 
117
96
GC_bool GC_print_back_height = 0;
118
97
 
144
123
        /* Number of warnings suppressed so far.        */
145
124
 
146
125
/*ARGSUSED*/
147
 
GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
 
126
void * GC_default_oom_fn(size_t bytes_requested)
148
127
{
149
128
    return(0);
150
129
}
151
130
 
152
 
GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
153
 
 
154
 
extern signed_word GC_mem_found;
155
 
 
156
 
void * GC_project2(arg1, arg2)
157
 
void *arg1;
158
 
void *arg2;
 
131
void * (*GC_oom_fn) (size_t bytes_requested) = GC_default_oom_fn;
 
132
 
 
133
void * GC_project2(void *arg1, void *arg2)
159
134
{
160
135
  return arg2;
161
136
}
162
137
 
163
 
# ifdef MERGE_SIZES
164
 
    /* Set things up so that GC_size_map[i] >= words(i),                */
165
 
    /* but not too much bigger                                          */
166
 
    /* and so that size_map contains relatively few distinct entries    */
167
 
    /* This is stolen from Russ Atkinson's Cedar quantization           */
168
 
    /* alogrithm (but we precompute it).                                */
169
 
 
170
 
 
171
 
    void GC_init_size_map()
172
 
    {
173
 
        register unsigned i;
174
 
 
175
 
        /* Map size 0 to something bigger.                      */
176
 
        /* This avoids problems at lower levels.                */
177
 
        /* One word objects don't have to be 2 word aligned,    */
178
 
        /* unless we're using mark bytes.                       */
179
 
          for (i = 0; i < sizeof(word); i++) {
180
 
              GC_size_map[i] = MIN_WORDS;
181
 
          }
182
 
#         if MIN_WORDS > 1
183
 
            GC_size_map[sizeof(word)] = MIN_WORDS;
184
 
#         else
185
 
            GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word));
186
 
#         endif
187
 
        for (i = sizeof(word) + 1; i <= 8 * sizeof(word); i++) {
188
 
            GC_size_map[i] = ALIGNED_WORDS(i);
189
 
        }
190
 
        for (i = 8*sizeof(word) + 1; i <= 16 * sizeof(word); i++) {
191
 
              GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 1) & (~1);
192
 
        }
193
 
#       ifdef GC_GCJ_SUPPORT
194
 
           /* Make all sizes up to 32 words predictable, so that a      */
195
 
           /* compiler can statically perform the same computation,     */
196
 
           /* or at least a computation that results in similar size    */
197
 
           /* classes.                                                  */
198
 
           for (i = 16*sizeof(word) + 1; i <= 32 * sizeof(word); i++) {
199
 
              GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 3) & (~3);
200
 
           }
201
 
#       endif
202
 
        /* We leave the rest of the array to be filled in on demand. */
 
138
/* Set things up so that GC_size_map[i] >= granules(i),         */
 
139
/* but not too much bigger                                              */
 
140
/* and so that size_map contains relatively few distinct entries        */
 
141
/* This was originally stolen from Russ Atkinson's Cedar                */
 
142
/* quantization alogrithm (but we precompute it).                       */ 
 
143
void GC_init_size_map(void)
 
144
{
 
145
    int i;
 
146
 
 
147
    /* Map size 0 to something bigger.                  */
 
148
    /* This avoids problems at lower levels.            */
 
149
      GC_size_map[0] = 1;
 
150
    for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
 
151
        GC_size_map[i] = ROUNDED_UP_GRANULES(i);
 
152
        GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
203
153
    }
 
154
    /* We leave the rest of the array to be filled in on demand. */
 
155
}
 
156
 
 
157
/* Fill in additional entries in GC_size_map, including the ith one */
 
158
/* We assume the ith entry is currently 0.                              */
 
159
/* Note that a filled in section of the array ending at n always    */
 
160
/* has length at least n/4.                                             */
 
161
void GC_extend_size_map(size_t i)
 
162
{
 
163
    size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
 
164
    size_t granule_sz = orig_granule_sz;
 
165
    size_t byte_sz = GRANULES_TO_BYTES(granule_sz);
 
166
                        /* The size we try to preserve.         */
 
167
                        /* Close to i, unless this would        */
 
168
                        /* introduce too many distinct sizes.   */
 
169
    size_t smaller_than_i = byte_sz - (byte_sz >> 3);
 
170
    size_t much_smaller_than_i = byte_sz - (byte_sz >> 2);
 
171
    size_t low_limit;   /* The lowest indexed entry we  */
 
172
                        /* initialize.                  */
 
173
    size_t j;
204
174
    
205
 
    /* Fill in additional entries in GC_size_map, including the ith one */
206
 
    /* We assume the ith entry is currently 0.                          */
207
 
    /* Note that a filled in section of the array ending at n always    */
208
 
    /* has length at least n/4.                                         */
209
 
    void GC_extend_size_map(i)
210
 
    word i;
 
175
    if (GC_size_map[smaller_than_i] == 0) {
 
176
        low_limit = much_smaller_than_i;
 
177
        while (GC_size_map[low_limit] != 0) low_limit++;
 
178
    } else {
 
179
        low_limit = smaller_than_i + 1;
 
180
        while (GC_size_map[low_limit] != 0) low_limit++;
 
181
        granule_sz = ROUNDED_UP_GRANULES(low_limit);
 
182
        granule_sz += granule_sz >> 3;
 
183
        if (granule_sz < orig_granule_sz) granule_sz = orig_granule_sz;
 
184
    }
 
185
    /* For these larger sizes, we use an even number of granules.       */
 
186
    /* This makes it easier to, for example, construct a 16byte-aligned */
 
187
    /* allocator even if GRANULE_BYTES is 8.                            */
 
188
        granule_sz += 1;
 
189
        granule_sz &= ~1;
 
190
    if (granule_sz > MAXOBJGRANULES) {
 
191
        granule_sz = MAXOBJGRANULES;
 
192
    }
 
193
    /* If we can fit the same number of larger objects in a block,      */
 
194
    /* do so.                                                   */ 
211
195
    {
212
 
        word orig_word_sz = ROUNDED_UP_WORDS(i);
213
 
        word word_sz = orig_word_sz;
214
 
        register word byte_sz = WORDS_TO_BYTES(word_sz);
215
 
                                /* The size we try to preserve.         */
216
 
                                /* Close to to i, unless this would     */
217
 
                                /* introduce too many distinct sizes.   */
218
 
        word smaller_than_i = byte_sz - (byte_sz >> 3);
219
 
        word much_smaller_than_i = byte_sz - (byte_sz >> 2);
220
 
        register word low_limit;        /* The lowest indexed entry we  */
221
 
                                        /* initialize.                  */
222
 
        register word j;
223
 
        
224
 
        if (GC_size_map[smaller_than_i] == 0) {
225
 
            low_limit = much_smaller_than_i;
226
 
            while (GC_size_map[low_limit] != 0) low_limit++;
227
 
        } else {
228
 
            low_limit = smaller_than_i + 1;
229
 
            while (GC_size_map[low_limit] != 0) low_limit++;
230
 
            word_sz = ROUNDED_UP_WORDS(low_limit);
231
 
            word_sz += word_sz >> 3;
232
 
            if (word_sz < orig_word_sz) word_sz = orig_word_sz;
233
 
        }
234
 
#       ifdef ALIGN_DOUBLE
235
 
            word_sz += 1;
236
 
            word_sz &= ~1;
237
 
#       endif
238
 
        if (word_sz > MAXOBJSZ) {
239
 
            word_sz = MAXOBJSZ;
240
 
        }
241
 
        /* If we can fit the same number of larger objects in a block,  */
242
 
        /* do so.                                                       */ 
243
 
        {
244
 
            size_t number_of_objs = BODY_SZ/word_sz;
245
 
            word_sz = BODY_SZ/number_of_objs;
246
 
#           ifdef ALIGN_DOUBLE
247
 
                word_sz &= ~1;
248
 
#           endif
249
 
        }
250
 
        byte_sz = WORDS_TO_BYTES(word_sz);
251
 
        if (GC_all_interior_pointers) {
252
 
            /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
253
 
            byte_sz -= EXTRA_BYTES;
254
 
        }
255
 
 
256
 
        for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;  
 
196
        size_t number_of_objs = HBLK_GRANULES/granule_sz;
 
197
        granule_sz = HBLK_GRANULES/number_of_objs;
 
198
        granule_sz &= ~1;
257
199
    }
258
 
# endif
 
200
    byte_sz = GRANULES_TO_BYTES(granule_sz);
 
201
    /* We may need one extra byte;                      */
 
202
    /* don't always fill in GC_size_map[byte_sz]        */
 
203
    byte_sz -= EXTRA_BYTES;
 
204
 
 
205
    for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = granule_sz;  
 
206
}
259
207
 
260
208
 
261
209
/*
274
222
# define CLEAR_SIZE 213  /* Granularity for GC_clear_stack_inner */
275
223
# define DEGRADE_RATE 50
276
224
 
277
 
word GC_min_sp;         /* Coolest stack pointer value from which we've */
 
225
ptr_t GC_min_sp;        /* Coolest stack pointer value from which we've */
278
226
                        /* already cleared the stack.                   */
279
227
                        
280
 
word GC_high_water;
 
228
ptr_t GC_high_water;
281
229
                        /* "hottest" stack pointer value we have seen   */
282
230
                        /* recently.  Degrades over time.               */
283
231
 
284
 
word GC_words_allocd_at_reset;
 
232
word GC_bytes_allocd_at_reset;
285
233
 
286
234
#if defined(ASM_CLEAR_CODE)
287
 
  extern ptr_t GC_clear_stack_inner();
 
235
  extern void *GC_clear_stack_inner(void *, ptr_t);
288
236
#else  
289
237
/* Clear the stack up to about limit.  Return arg. */
290
238
/*ARGSUSED*/
291
 
ptr_t GC_clear_stack_inner(arg, limit)
292
 
ptr_t arg;
293
 
word limit;
 
239
void * GC_clear_stack_inner(void *arg, ptr_t limit)
294
240
{
295
241
    word dummy[CLEAR_SIZE];
296
242
    
297
243
    BZERO(dummy, CLEAR_SIZE*sizeof(word));
298
 
    if ((word)(dummy) COOLER_THAN limit) {
 
244
    if ((ptr_t)(dummy) COOLER_THAN limit) {
299
245
        (void) GC_clear_stack_inner(arg, limit);
300
246
    }
301
247
    /* Make sure the recursive call is not a tail call, and the bzero   */
308
254
/* Clear some of the inaccessible part of the stack.  Returns its       */
309
255
/* argument, so it can be used in a tail call position, hence clearing  */
310
256
/* another frame.                                                       */
311
 
ptr_t GC_clear_stack(arg)
312
 
ptr_t arg;
 
257
void * GC_clear_stack(void *arg)
313
258
{
314
 
    register word sp = (word)GC_approx_sp();  /* Hotter than actual sp */
 
259
    ptr_t sp = GC_approx_sp();  /* Hotter than actual sp */
315
260
#   ifdef THREADS
316
261
        word dummy[SMALL_CLEAR_SIZE];
317
262
        static unsigned random_no = 0;
319
264
                                 /* Used to occasionally clear a bigger  */
320
265
                                 /* chunk.                               */
321
266
#   endif
322
 
    register word limit;
 
267
    ptr_t limit;
323
268
    
324
269
#   define SLOP 400
325
270
        /* Extra bytes we clear every time.  This clears our own        */
340
285
    if (++random_no % 13 == 0) {
341
286
        limit = sp;
342
287
        MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
343
 
        limit &= ~0xf;  /* Make it sufficiently aligned for assembly    */
 
288
        limit = (ptr_t)((word)limit & ~0xf);
 
289
                        /* Make it sufficiently aligned for assembly    */
344
290
                        /* implementations of GC_clear_stack_inner.     */
345
291
        return GC_clear_stack_inner(arg, limit);
346
292
    } else {
350
296
# else
351
297
    if (GC_gc_no > GC_stack_last_cleared) {
352
298
        /* Start things over, so we clear the entire stack again */
353
 
        if (GC_stack_last_cleared == 0) GC_high_water = (word) GC_stackbottom;
 
299
        if (GC_stack_last_cleared == 0) GC_high_water = (ptr_t)GC_stackbottom;
354
300
        GC_min_sp = GC_high_water;
355
301
        GC_stack_last_cleared = GC_gc_no;
356
 
        GC_words_allocd_at_reset = GC_words_allocd;
 
302
        GC_bytes_allocd_at_reset = GC_bytes_allocd;
357
303
    }
358
304
    /* Adjust GC_high_water */
359
305
        MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
364
310
    limit = GC_min_sp;
365
311
    MAKE_HOTTER(limit, SLOP);
366
312
    if (sp COOLER_THAN limit) {
367
 
        limit &= ~0xf;  /* Make it sufficiently aligned for assembly    */
 
313
        limit = (ptr_t)((word)limit & ~0xf);
 
314
                        /* Make it sufficiently aligned for assembly    */
368
315
                        /* implementations of GC_clear_stack_inner.     */
369
316
        GC_min_sp = sp;
370
317
        return(GC_clear_stack_inner(arg, limit));
371
 
    } else if (WORDS_TO_BYTES(GC_words_allocd - GC_words_allocd_at_reset)
372
 
               > CLEAR_THRESHOLD) {
 
318
    } else if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
373
319
        /* Restart clearing process, but limit how much clearing we do. */
374
320
        GC_min_sp = sp;
375
321
        MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
376
322
        if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
377
 
        GC_words_allocd_at_reset = GC_words_allocd;
 
323
        GC_bytes_allocd_at_reset = GC_bytes_allocd;
378
324
    }  
379
325
    return(arg);
380
326
# endif
383
329
 
384
330
/* Return a pointer to the base address of p, given a pointer to a      */
385
331
/* an address within an object.  Return 0 o.w.                          */
386
 
# ifdef __STDC__
387
 
    GC_PTR GC_base(GC_PTR p)
388
 
# else
389
 
    GC_PTR GC_base(p)
390
 
    GC_PTR p;
391
 
# endif
 
332
void * GC_base(void * p)
392
333
{
393
 
    register word r;
394
 
    register struct hblk *h;
395
 
    register bottom_index *bi;
396
 
    register hdr *candidate_hdr;
397
 
    register word limit;
 
334
    ptr_t r;
 
335
    struct hblk *h;
 
336
    bottom_index *bi;
 
337
    hdr *candidate_hdr;
 
338
    ptr_t limit;
398
339
    
399
 
    r = (word)p;
 
340
    r = p;
400
341
    if (!GC_is_initialized) return 0;
401
342
    h = HBLKPTR(r);
402
343
    GET_BI(r, bi);
406
347
    /* to the beginning.                                                */
407
348
        while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
408
349
           h = FORWARDED_ADDR(h,candidate_hdr);
409
 
           r = (word)h;
 
350
           r = (ptr_t)h;
410
351
           candidate_hdr = HDR(h);
411
352
        }
412
 
    if (candidate_hdr -> hb_map == GC_invalid_map) return(0);
 
353
    if (HBLK_IS_FREE(candidate_hdr)) return(0);
413
354
    /* Make sure r points to the beginning of the object */
414
 
        r &= ~(WORDS_TO_BYTES(1) - 1);
 
355
        r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
415
356
        {
416
 
            register int offset = HBLKDISPL(r);
417
 
            register signed_word sz = candidate_hdr -> hb_sz;
418
 
            register signed_word map_entry;
419
 
              
420
 
            map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
421
 
            if (map_entry > CPP_MAX_OFFSET) {
422
 
                map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz;
423
 
            }
424
 
            r -= WORDS_TO_BYTES(map_entry);
425
 
            limit = r + WORDS_TO_BYTES(sz);
426
 
            if (limit > (word)(h + 1)
427
 
                && sz <= BYTES_TO_WORDS(HBLKSIZE)) {
 
357
            size_t offset = HBLKDISPL(r);
 
358
            signed_word sz = candidate_hdr -> hb_sz;
 
359
            size_t obj_displ = offset % sz;
 
360
 
 
361
            r -= obj_displ;
 
362
            limit = r + sz;
 
363
            if (limit > (ptr_t)(h + 1) && sz <= HBLKSIZE) {
428
364
                return(0);
429
365
            }
430
 
            if ((word)p >= limit) return(0);
 
366
            if ((ptr_t)p >= limit) return(0);
431
367
        }
432
 
    return((GC_PTR)r);
 
368
    return((void *)r);
433
369
}
434
370
 
435
371
 
436
372
/* Return the size of an object, given a pointer to its base.           */
437
373
/* (For small obects this also happens to work from interior pointers,  */
438
374
/* but that shouldn't be relied upon.)                                  */
439
 
# ifdef __STDC__
440
 
    size_t GC_size(GC_PTR p)
441
 
# else
442
 
    size_t GC_size(p)
443
 
    GC_PTR p;
444
 
# endif
 
375
size_t GC_size(void * p)
445
376
{
446
 
    register int sz;
447
 
    register hdr * hhdr = HDR(p);
 
377
    hdr * hhdr = HDR(p);
448
378
    
449
 
    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
450
 
    return(sz);
451
 
}
452
 
 
453
 
size_t GC_get_heap_size GC_PROTO(())
454
 
{
455
 
    return ((size_t) GC_heapsize);
456
 
}
457
 
 
458
 
size_t GC_get_free_bytes GC_PROTO(())
459
 
{
460
 
    return ((size_t) GC_large_free_bytes);
461
 
}
462
 
 
463
 
size_t GC_get_bytes_since_gc GC_PROTO(())
464
 
{
465
 
    return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
466
 
}
467
 
 
468
 
size_t GC_get_total_bytes GC_PROTO(())
469
 
{
470
 
    return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc));
 
379
    return hhdr -> hb_sz;
 
380
}
 
381
 
 
382
size_t GC_get_heap_size(void)
 
383
{
 
384
    return GC_heapsize;
 
385
}
 
386
 
 
387
size_t GC_get_free_bytes(void)
 
388
{
 
389
    return GC_large_free_bytes;
 
390
}
 
391
 
 
392
size_t GC_get_bytes_since_gc(void)
 
393
{
 
394
    return GC_bytes_allocd;
 
395
}
 
396
 
 
397
size_t GC_get_total_bytes(void)
 
398
{
 
399
    return GC_bytes_allocd+GC_bytes_allocd_before_gc;
471
400
}
472
401
 
473
402
GC_bool GC_is_initialized = FALSE;
474
403
 
475
 
void GC_init()
 
404
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
 
405
  extern void GC_init_parallel(void);
 
406
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
 
407
 
 
408
/* FIXME: The GC_init/GC_init_inner distinction should go away. */
 
409
void GC_init(void)
476
410
{
477
 
    DCL_LOCK_STATE;
478
 
    
479
 
    DISABLE_SIGNALS();
480
 
 
481
 
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
482
 
    if (!GC_is_initialized) {
483
 
      BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
484
 
      HMODULE hK32 = GetModuleHandleA("kernel32.dll");
485
 
      if (hK32)
486
 
          pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
487
 
                GetProcAddress (hK32,
488
 
                                "InitializeCriticalSectionAndSpinCount");
489
 
      if (pfn)
490
 
          pfn(&GC_allocate_ml, 4000);
491
 
      else
492
 
          InitializeCriticalSection (&GC_allocate_ml);
493
 
    }
494
 
#endif /* MSWIN32 */
495
 
 
496
 
    LOCK();
 
411
    /* LOCK(); -- no longer does anything this early. */
497
412
    GC_init_inner();
498
 
    UNLOCK();
499
 
    ENABLE_SIGNALS();
500
 
 
501
 
#   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
502
 
        /* Make sure marker threads and started and thread local */
503
 
        /* allocation is initialized, in case we didn't get      */
504
 
        /* called from GC_init_parallel();                       */
505
 
        {
506
 
          extern void GC_init_parallel(void);
507
 
          GC_init_parallel();
508
 
        }
509
 
#   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
510
 
 
511
 
#   if defined(DYNAMIC_LOADING) && defined(DARWIN)
512
 
    {
513
 
        /* This must be called WITHOUT the allocation lock held
514
 
        and before any threads are created */
515
 
        extern void GC_init_dyld();
516
 
        GC_init_dyld();
517
 
    }
518
 
#   endif
 
413
    /* UNLOCK(); */
519
414
}
520
415
 
521
416
#if defined(MSWIN32) || defined(MSWINCE)
523
418
#endif
524
419
 
525
420
#ifdef MSWIN32
526
 
    extern void GC_init_win32 GC_PROTO((void));
 
421
    extern void GC_init_win32(void);
527
422
#endif
528
423
 
529
424
extern void GC_setpagesize();
530
425
 
531
 
 
532
426
#ifdef MSWIN32
533
427
extern GC_bool GC_no_win32_dlls;
534
428
#else
535
429
# define GC_no_win32_dlls FALSE
536
430
#endif
537
431
 
538
 
void GC_exit_check GC_PROTO((void))
 
432
void GC_exit_check(void)
539
433
{
540
434
   GC_gcollect();
541
435
}
542
436
 
543
437
#ifdef SEARCH_FOR_DATA_START
544
 
  extern void GC_init_linux_data_start GC_PROTO((void));
 
438
  extern void GC_init_linux_data_start(void);
545
439
#endif
546
440
 
547
441
#ifdef UNIX_LIKE
548
442
 
549
 
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
 
443
extern void GC_set_and_save_fault_handler(void (*handler)(int));
550
444
 
551
445
static void looping_handler(sig)
552
446
int sig;
553
447
{
554
 
    GC_err_printf1("Caught signal %d: looping in handler\n", sig);
 
448
    GC_err_printf("Caught signal %d: looping in handler\n", sig);
555
449
    for(;;);
556
450
}
557
451
 
573
467
 
574
468
#endif
575
469
 
 
470
#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
 
471
  void GC_thr_init(void);
 
472
#endif
 
473
 
576
474
void GC_init_inner()
577
475
{
578
476
#   if !defined(THREADS) && defined(GC_ASSERTIONS)
581
479
    word initial_heap_sz = (word)MINHINCR;
582
480
    
583
481
    if (GC_is_initialized) return;
584
 
#   ifdef PRINTSTATS
585
 
      GC_print_stats = 1;
 
482
 
 
483
    /* Note that although we are nominally called with the */
 
484
    /* allocation lock held, the allocation lock is now    */
 
485
    /* only really acquired once a second thread is forked.*/
 
486
    /* And the initialization code needs to run before     */
 
487
    /* then.  Thus we really don't hold any locks, and can */
 
488
    /* in fact safely initialize them here.                */
 
489
#   ifdef THREADS
 
490
      GC_ASSERT(!GC_need_to_lock);
586
491
#   endif
 
492
#   if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
 
493
      if (!GC_is_initialized) {
 
494
        BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
 
495
        HMODULE hK32 = GetModuleHandleA("kernel32.dll");
 
496
        if (hK32)
 
497
          pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
 
498
                GetProcAddress (hK32,
 
499
                                "InitializeCriticalSectionAndSpinCount");
 
500
        if (pfn)
 
501
            pfn(&GC_allocate_ml, 4000);
 
502
        else
 
503
          InitializeCriticalSection (&GC_allocate_ml);
 
504
      }
 
505
#endif /* MSWIN32 */
587
506
#   if defined(MSWIN32) || defined(MSWINCE)
588
507
      InitializeCriticalSection(&GC_write_cs);
589
508
#   endif
590
 
    if (0 != GETENV("GC_PRINT_STATS")) {
591
 
      GC_print_stats = 1;
592
 
    } 
 
509
#   if (!defined(SMALL_CONFIG))
 
510
      if (0 != GETENV("GC_PRINT_STATS")) {
 
511
        GC_print_stats = 1;
 
512
      } 
 
513
      if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
 
514
        GC_print_stats = VERBOSE;
 
515
      } 
 
516
#     if defined(UNIX_LIKE)
 
517
        {
 
518
          char * file_name = GETENV("GC_LOG_FILE");
 
519
          if (0 != file_name) {
 
520
            int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666);
 
521
            if (log_d < 0) {
 
522
              GC_log_printf("Failed to open %s as log file\n", file_name);
 
523
            } else {
 
524
              GC_log = log_d;
 
525
            }
 
526
          }
 
527
        }
 
528
#     endif
 
529
#   endif
593
530
#   ifndef NO_DEBUGGING
594
531
      if (0 != GETENV("GC_DUMP_REGULARLY")) {
595
532
        GC_dump_regularly = 1;
606
543
#   endif
607
544
    if (0 != GETENV("GC_FIND_LEAK")) {
608
545
      GC_find_leak = 1;
609
 
#     ifdef __STDC__
610
 
        atexit(GC_exit_check);
611
 
#     endif
 
546
      atexit(GC_exit_check);
612
547
    }
613
548
    if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
614
549
      GC_all_interior_pointers = 1;
623
558
      GC_large_alloc_warn_interval = LONG_MAX;
624
559
    }
625
560
    {
 
561
      char * addr_string = GETENV("GC_TRACE");
 
562
      if (0 != addr_string) {
 
563
#       ifndef ENABLE_TRACE
 
564
          WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
 
565
#       else
 
566
#         ifdef STRTOULL
 
567
            long long addr = strtoull(addr_string, NULL, 16);
 
568
#         else
 
569
            long addr = strtoul(addr_string, NULL, 16);
 
570
#         endif
 
571
          if (addr < 0x1000)
 
572
              WARN("Unlikely trace address: 0x%lx\n", (GC_word)addr);
 
573
          GC_trace_addr = (ptr_t)addr;
 
574
#       endif
 
575
      }
 
576
    }
 
577
    {
626
578
      char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
627
579
      if (0 != time_limit_string) {
628
580
        long time_limit = atol(time_limit_string);
661
613
#   ifdef MSWIN32
662
614
        GC_init_win32();
663
615
#   endif
 
616
#   if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
 
617
        WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
 
618
        /* If thread stacks are cached, they tend to be scanned in      */
 
619
        /* entirety as part of the root set.  This wil grow them to     */
 
620
        /* maximum size, and is generally not desirable.                */
 
621
#   endif
664
622
#   if defined(SEARCH_FOR_DATA_START)
665
623
        GC_init_linux_data_start();
666
624
#   endif
667
625
#   if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
668
626
        GC_init_netbsd_elf();
669
627
#   endif
670
 
#   if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
671
 
       || defined(GC_WIN32_THREADS)
672
 
        GC_thr_init();
673
 
#   endif
674
 
#   ifdef GC_SOLARIS_THREADS
675
 
        /* We need dirty bits in order to find live stack sections.     */
676
 
        GC_dirty_init();
677
 
#   endif
678
628
#   if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
679
629
        || defined(GC_SOLARIS_THREADS)
680
630
      if (GC_stackbottom == 0) {
681
 
        GC_stackbottom = GC_get_stack_base();
 
631
        GC_stackbottom = GC_get_main_stack_base();
682
632
#       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
683
633
          GC_register_stackbottom = GC_get_register_stack_base();
684
634
#       endif
685
635
      } else {
686
636
#       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
687
637
          if (GC_register_stackbottom == 0) {
688
 
            WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
 
638
            WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
689
639
            /* The following may fail, since we may rely on             */
690
640
            /* alignment properties that may not hold with a user set   */
691
641
            /* GC_stackbottom.                                          */
694
644
#       endif
695
645
      }
696
646
#   endif
 
647
    /* Ignore gcc -Wall warnings on the following. */
697
648
    GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
698
649
    GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
699
650
    GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
700
651
#   ifndef THREADS
701
 
#     if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
702
 
        ABORT(
703
 
          "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
704
 
#     endif
705
 
#     if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
706
 
        ABORT(
707
 
          "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
708
 
#     endif
709
652
#     ifdef STACK_GROWS_DOWN
710
653
        GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
711
654
#     else
716
659
      GC_ASSERT((word)(-1) > (word)0);
717
660
      /* word should be unsigned */
718
661
#   endif
 
662
    GC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
 
663
        /* Ptr_t comparisons should behave as unsigned comparisons.     */
719
664
    GC_ASSERT((signed_word)(-1) < (signed_word)0);
 
665
#   if !defined(SMALL_CONFIG)
 
666
      if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
 
667
        /* This used to test for !GC_no_win32_dlls.  Why? */
 
668
        GC_setpagesize();
 
669
        /* For GWW_MPROTECT on Win32, this needs to happen before any   */
 
670
        /* heap memory is allocated.                                    */
 
671
        GC_dirty_init();
 
672
        GC_ASSERT(GC_bytes_allocd == 0)
 
673
        GC_incremental = TRUE;
 
674
      }
 
675
#   endif /* !SMALL_CONFIG */
720
676
    
721
677
    /* Add initial guess of root sets.  Do this first, since sbrk(0)    */
722
678
    /* might be used.                                                   */
748
704
        }
749
705
    }
750
706
    if (!GC_expand_hp_inner(initial_heap_sz)) {
751
 
        GC_err_printf0("Can't start up: not enough memory\n");
 
707
        GC_err_printf("Can't start up: not enough memory\n");
752
708
        EXIT();
753
709
    }
754
 
    /* Preallocate large object map.  It's otherwise inconvenient to    */
755
 
    /* deal with failure.                                               */
756
 
      if (!GC_add_map_entry((word)0)) {
757
 
        GC_err_printf0("Can't start up: not enough memory\n");
758
 
        EXIT();
759
 
      }
 
710
    GC_initialize_offsets();
760
711
    GC_register_displacement_inner(0L);
761
 
#   ifdef MERGE_SIZES
762
 
      GC_init_size_map();
 
712
#   if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
 
713
      if (!GC_all_interior_pointers) {
 
714
        /* TLS ABI uses pointer-sized offsets for dtv. */
 
715
        GC_register_displacement_inner(sizeof(void *));
 
716
      }
763
717
#   endif
 
718
    GC_init_size_map();
764
719
#   ifdef PCR
765
720
      if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
766
721
          != PCR_ERes_okay) {
771
726
      PCR_IL_Unlock();
772
727
      GC_pcr_install();
773
728
#   endif
774
 
#   if !defined(SMALL_CONFIG)
775
 
      if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
776
 
        GC_ASSERT(!GC_incremental);
777
 
        GC_setpagesize();
778
 
#       ifndef GC_SOLARIS_THREADS
779
 
          GC_dirty_init();
780
 
#       endif
781
 
        GC_ASSERT(GC_words_allocd == 0)
782
 
        GC_incremental = TRUE;
783
 
      }
784
 
#   endif /* !SMALL_CONFIG */
 
729
    GC_is_initialized = TRUE;
 
730
#   if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
 
731
        GC_thr_init();
 
732
#   endif
785
733
    COND_DUMP;
786
734
    /* Get black list set up and/or incremental GC started */
787
735
      if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
788
 
    GC_is_initialized = TRUE;
789
736
#   ifdef STUBBORN_ALLOC
790
737
        GC_stubborn_init();
791
738
#   endif
805
752
                  GC_register_finalizer_no_order);
806
753
      }
807
754
#   endif
 
755
 
 
756
    /* The rest of this again assumes we don't really hold      */
 
757
    /* the allocation lock.                                     */
 
758
#   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
 
759
        /* Make sure marker threads and started and thread local */
 
760
        /* allocation is initialized, in case we didn't get      */
 
761
        /* called from GC_init_parallel();                       */
 
762
        {
 
763
          GC_init_parallel();
 
764
        }
 
765
#   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
 
766
 
 
767
#   if defined(DYNAMIC_LOADING) && defined(DARWIN)
 
768
    {
 
769
        /* This must be called WITHOUT the allocation lock held
 
770
        and before any threads are created */
 
771
        extern void GC_init_dyld();
 
772
        GC_init_dyld();
 
773
    }
 
774
#   endif
808
775
}
809
776
 
810
 
void GC_enable_incremental GC_PROTO(())
 
777
void GC_enable_incremental(void)
811
778
{
812
779
# if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS)
813
780
  /* If we are keeping back pointers, the GC itself dirties all */
816
783
  if (!GC_find_leak) {
817
784
    DCL_LOCK_STATE;
818
785
    
819
 
    DISABLE_SIGNALS();
820
786
    LOCK();
821
787
    if (GC_incremental) goto out;
822
788
    GC_setpagesize();
823
 
    if (GC_no_win32_dlls) goto out;
824
 
#   ifndef GC_SOLARIS_THREADS 
825
 
      maybe_install_looping_handler();  /* Before write fault handler! */
826
 
      GC_dirty_init();
827
 
#   endif
 
789
    /* if (GC_no_win32_dlls) goto out; Should be win32S test? */
 
790
    maybe_install_looping_handler();  /* Before write fault handler! */
 
791
    GC_incremental = TRUE;
828
792
    if (!GC_is_initialized) {
829
793
        GC_init_inner();
 
794
    } else {
 
795
        GC_dirty_init();
830
796
    }
831
 
    if (GC_incremental) goto out;
 
797
    if (!GC_dirty_maintained) goto out;
832
798
    if (GC_dont_gc) {
833
799
        /* Can't easily do it. */
834
800
        UNLOCK();
835
 
        ENABLE_SIGNALS();
836
801
        return;
837
802
    }
838
 
    if (GC_words_allocd > 0) {
 
803
    if (GC_bytes_allocd > 0) {
839
804
        /* There may be unmarked reachable objects      */
840
805
        GC_gcollect_inner();
841
806
    }   /* else we're OK in assuming everything's       */
842
807
        /* clean since nothing can point to an          */
843
808
        /* unmarked object.                             */
844
809
    GC_read_dirty();
845
 
    GC_incremental = TRUE;
846
810
out:
847
811
    UNLOCK();
848
 
    ENABLE_SIGNALS();
 
812
  } else {
 
813
    GC_init();
849
814
  }
 
815
# else
 
816
    GC_init();
850
817
# endif
851
818
}
852
819
 
853
820
 
854
821
#if defined(MSWIN32) || defined(MSWINCE)
855
 
# define LOG_FILE _T("gc.log")
 
822
# if defined(_MSC_VER) && defined(_DEBUG)
 
823
#  include <crtdbg.h>
 
824
# endif
 
825
# ifdef OLD_WIN32_LOG_FILE
 
826
#   define LOG_FILE _T("gc.log")
 
827
# endif
856
828
 
857
829
  HANDLE GC_stdout = 0;
858
830
 
863
835
      }
864
836
  }
865
837
 
866
 
  int GC_write(buf, len)
867
 
  GC_CONST char * buf;
868
 
  size_t len;
 
838
# ifndef THREADS
 
839
#   define GC_need_to_lock 0  /* Not defined without threads */
 
840
# endif
 
841
  int GC_write(const char *buf, size_t len)
869
842
  {
870
843
      BOOL tmp;
871
844
      DWORD written;
872
845
      if (len == 0)
873
846
          return 0;
874
 
      EnterCriticalSection(&GC_write_cs);
 
847
      if (GC_need_to_lock) EnterCriticalSection(&GC_write_cs);
875
848
      if (GC_stdout == INVALID_HANDLE_VALUE) {
 
849
          if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
876
850
          return -1;
877
851
      } else if (GC_stdout == 0) {
878
 
          GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
879
 
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
880
 
                                 NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
881
 
                                 NULL); 
882
 
          if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed");
 
852
        char * file_name = GETENV("GC_LOG_FILE");
 
853
        char logPath[_MAX_PATH + 5];
 
854
 
 
855
        if (0 == file_name) {
 
856
#         ifdef OLD_WIN32_LOG_FILE
 
857
            strcpy(logPath, LOG_FILE);
 
858
#         else
 
859
            GetModuleFileName(NULL, logPath, _MAX_PATH);
 
860
            strcat(logPath, ".log");
 
861
#         endif
 
862
          file_name = logPath;
 
863
        }
 
864
        GC_stdout = CreateFile(logPath, GENERIC_WRITE,
 
865
                               FILE_SHARE_READ,
 
866
                               NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
 
867
                               NULL); 
 
868
        if (GC_stdout == INVALID_HANDLE_VALUE)
 
869
            ABORT("Open of log file failed");
883
870
      }
884
 
      tmp = WriteFile(GC_stdout, buf, len, &written, NULL);
 
871
      tmp = WriteFile(GC_stdout, buf, (DWORD)len, &written, NULL);
885
872
      if (!tmp)
886
873
          DebugBreak();
887
 
      LeaveCriticalSection(&GC_write_cs);
 
874
#     if defined(_MSC_VER) && defined(_DEBUG)
 
875
          _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
 
876
#     endif
 
877
      if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
888
878
      return tmp ? (int)written : -1;
889
879
  }
 
880
# undef GC_need_to_lock
890
881
 
891
882
#endif
892
883
 
893
884
#if defined(OS2) || defined(MACOS)
894
885
FILE * GC_stdout = NULL;
895
886
FILE * GC_stderr = NULL;
 
887
FILE * GC_log = NULL;
896
888
int GC_tmp;  /* Should really be local ... */
897
889
 
898
890
  void GC_set_files()
903
895
    if (GC_stderr == NULL) {
904
896
        GC_stderr = stderr;
905
897
    }
 
898
    if (GC_log == NULL) {
 
899
        GC_log = stderr;
 
900
    }
906
901
  }
907
902
#endif
908
903
 
909
904
#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
910
905
  int GC_stdout = 1;
911
906
  int GC_stderr = 2;
 
907
  int GC_log = 2;
912
908
# if !defined(AMIGA)
913
909
#   include <unistd.h>
914
910
# endif
918
914
    && !defined(MACOS)  && !defined(ECOS) && !defined(NOSYS)
919
915
int GC_write(fd, buf, len)
920
916
int fd;
921
 
GC_CONST char *buf;
 
917
const char *buf;
922
918
size_t len;
923
919
{
924
920
     register int bytes_written = 0;
956
952
 
957
953
 
958
954
#if defined(MSWIN32) || defined(MSWINCE)
 
955
    /* FIXME: This is pretty ugly ... */
959
956
#   define WRITE(f, buf, len) GC_write(buf, len)
960
957
#else
961
958
#   if defined(OS2) || defined(MACOS)
967
964
#   endif
968
965
#endif
969
966
 
 
967
#define BUFSZ 1024
 
968
#ifdef _MSC_VER
 
969
# define vsnprintf _vsnprintf
 
970
#endif
970
971
/* A version of printf that is unlikely to call malloc, and is thus safer */
971
972
/* to call from the collector in case malloc has been bound to GC_malloc. */
972
 
/* Assumes that no more than 1023 characters are written at once.         */
973
 
/* Assumes that all arguments have been converted to something of the     */
974
 
/* same size as long, and that the format conversions expect something    */
975
 
/* of that size.                                                          */
976
 
void GC_printf(format, a, b, c, d, e, f)
977
 
GC_CONST char * format;
978
 
long a, b, c, d, e, f;
 
973
/* Floating point arguments ans formats should be avoided, since fp       */
 
974
/* conversion is more likely to allocate.                                 */
 
975
/* Assumes that no more than BUFSZ-1 characters are written at once.      */
 
976
void GC_printf(const char *format, ...)
979
977
{
980
 
    char buf[1025];
 
978
    va_list args;
 
979
    char buf[BUFSZ+1];
981
980
    
 
981
    va_start(args, format);
982
982
    if (GC_quiet) return;
983
 
    buf[1024] = 0x15;
984
 
    (void) sprintf(buf, format, a, b, c, d, e, f);
985
 
    if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
 
983
    buf[BUFSZ] = 0x15;
 
984
    (void) vsnprintf(buf, BUFSZ, format, args);
 
985
    va_end(args);
 
986
    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
986
987
    if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
987
988
}
988
989
 
989
 
void GC_err_printf(format, a, b, c, d, e, f)
990
 
GC_CONST char * format;
991
 
long a, b, c, d, e, f;
 
990
void GC_err_printf(const char *format, ...)
992
991
{
993
 
    char buf[1025];
 
992
    va_list args;
 
993
    char buf[BUFSZ+1];
994
994
    
995
 
    buf[1024] = 0x15;
996
 
    (void) sprintf(buf, format, a, b, c, d, e, f);
997
 
    if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
 
995
    va_start(args, format);
 
996
    buf[BUFSZ] = 0x15;
 
997
    (void) vsnprintf(buf, BUFSZ, format, args);
 
998
    va_end(args);
 
999
    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
998
1000
    if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
999
1001
}
1000
1002
 
1001
 
void GC_err_puts(s)
1002
 
GC_CONST char *s;
 
1003
void GC_log_printf(const char *format, ...)
 
1004
{
 
1005
    va_list args;
 
1006
    char buf[BUFSZ+1];
 
1007
    
 
1008
    va_start(args, format);
 
1009
    buf[BUFSZ] = 0x15;
 
1010
    (void) vsnprintf(buf, BUFSZ, format, args);
 
1011
    va_end(args);
 
1012
    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
 
1013
    if (WRITE(GC_log, buf, strlen(buf)) < 0) ABORT("write to log failed");
 
1014
}
 
1015
 
 
1016
void GC_err_puts(const char *s)
1003
1017
{
1004
1018
    if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
1005
1019
}
1006
1020
 
1007
1021
#if defined(LINUX) && !defined(SMALL_CONFIG)
1008
1022
void GC_err_write(buf, len)
1009
 
GC_CONST char *buf;
 
1023
const char *buf;
1010
1024
size_t len;
1011
1025
{
1012
1026
    if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
1013
1027
}
1014
1028
#endif
1015
1029
 
1016
 
# if defined(__STDC__) || defined(__cplusplus)
1017
 
    void GC_default_warn_proc(char *msg, GC_word arg)
1018
 
# else
1019
 
    void GC_default_warn_proc(msg, arg)
1020
 
    char *msg;
1021
 
    GC_word arg;
1022
 
# endif
 
1030
void GC_default_warn_proc(char *msg, GC_word arg)
1023
1031
{
1024
 
    GC_err_printf1(msg, (unsigned long)arg);
 
1032
    GC_err_printf(msg, arg);
1025
1033
}
1026
1034
 
1027
1035
GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
1028
1036
 
1029
 
# if defined(__STDC__) || defined(__cplusplus)
1030
 
    GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
1031
 
# else
1032
 
    GC_warn_proc GC_set_warn_proc(p)
1033
 
    GC_warn_proc p;
1034
 
# endif
 
1037
GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
1035
1038
{
1036
1039
    GC_warn_proc result;
1037
1040
 
1045
1048
    return(result);
1046
1049
}
1047
1050
 
1048
 
# if defined(__STDC__) || defined(__cplusplus)
1049
 
    GC_word GC_set_free_space_divisor (GC_word value)
1050
 
# else
1051
 
    GC_word GC_set_free_space_divisor (value)
1052
 
    GC_word value;
1053
 
# endif
 
1051
GC_word GC_set_free_space_divisor (GC_word value)
1054
1052
{
1055
1053
    GC_word old = GC_free_space_divisor;
1056
1054
    GC_free_space_divisor = value;
1058
1056
}
1059
1057
 
1060
1058
#ifndef PCR
1061
 
void GC_abort(msg)
1062
 
GC_CONST char * msg;
 
1059
void GC_abort(const char *msg)
1063
1060
{
1064
1061
#   if defined(MSWIN32)
1065
1062
      (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
1066
1063
#   else
1067
 
      GC_err_printf1("%s\n", msg);
 
1064
      GC_err_printf("%s\n", msg);
1068
1065
#   endif
1069
1066
    if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
1070
1067
            /* In many cases it's easier to debug a running process.    */
1098
1095
/* Helper procedures for new kind creation.     */
1099
1096
void ** GC_new_free_list_inner()
1100
1097
{
1101
 
    void *result = GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
 
1098
    void *result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),
 
1099
                                      PTRFREE);
1102
1100
    if (result == 0) ABORT("Failed to allocate freelist for new kind");
1103
 
    BZERO(result, (MAXOBJSZ+1)*sizeof(ptr_t));
 
1101
    BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
1104
1102
    return result;
1105
1103
}
1106
1104
 
1107
1105
void ** GC_new_free_list()
1108
1106
{
1109
1107
    void *result;
1110
 
    LOCK(); DISABLE_SIGNALS();
 
1108
    LOCK();
1111
1109
    result = GC_new_free_list_inner();
1112
 
    UNLOCK(); ENABLE_SIGNALS();
 
1110
    UNLOCK();
1113
1111
    return result;
1114
1112
}
1115
1113
 
1116
 
int GC_new_kind_inner(fl, descr, adjust, clear)
1117
 
void **fl;
1118
 
GC_word descr;
1119
 
int adjust;
1120
 
int clear;
 
1114
unsigned GC_new_kind_inner(void **fl, GC_word descr, int adjust, int clear)
1121
1115
{
1122
 
    int result = GC_n_kinds++;
 
1116
    unsigned result = GC_n_kinds++;
1123
1117
 
1124
1118
    if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
1125
 
    GC_obj_kinds[result].ok_freelist = (ptr_t *)fl;
 
1119
    GC_obj_kinds[result].ok_freelist = fl;
1126
1120
    GC_obj_kinds[result].ok_reclaim_list = 0;
1127
1121
    GC_obj_kinds[result].ok_descriptor = descr;
1128
1122
    GC_obj_kinds[result].ok_relocate_descr = adjust;
1130
1124
    return result;
1131
1125
}
1132
1126
 
1133
 
int GC_new_kind(fl, descr, adjust, clear)
1134
 
void **fl;
1135
 
GC_word descr;
1136
 
int adjust;
1137
 
int clear;
 
1127
unsigned GC_new_kind(void **fl, GC_word descr, int adjust, int clear)
1138
1128
{
1139
 
    int result;
1140
 
    LOCK(); DISABLE_SIGNALS();
 
1129
    unsigned result;
 
1130
    LOCK();
1141
1131
    result = GC_new_kind_inner(fl, descr, adjust, clear);
1142
 
    UNLOCK(); ENABLE_SIGNALS();
 
1132
    UNLOCK();
1143
1133
    return result;
1144
1134
}
1145
1135
 
1146
 
int GC_new_proc_inner(proc)
1147
 
GC_mark_proc proc;
 
1136
unsigned GC_new_proc_inner(GC_mark_proc proc)
1148
1137
{
1149
 
    int result = GC_n_mark_procs++;
 
1138
    unsigned result = GC_n_mark_procs++;
1150
1139
 
1151
1140
    if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
1152
1141
    GC_mark_procs[result] = proc;
1153
1142
    return result;
1154
1143
}
1155
1144
 
1156
 
int GC_new_proc(proc)
1157
 
GC_mark_proc proc;
 
1145
unsigned GC_new_proc(GC_mark_proc proc)
1158
1146
{
1159
 
    int result;
1160
 
    LOCK(); DISABLE_SIGNALS();
 
1147
    unsigned result;
 
1148
    LOCK();
1161
1149
    result = GC_new_proc_inner(proc);
1162
 
    UNLOCK(); ENABLE_SIGNALS();
 
1150
    UNLOCK();
1163
1151
    return result;
1164
1152
}
1165
1153
 
 
1154
GC_API void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
 
1155
{
 
1156
    int dummy;
 
1157
    struct GC_stack_base base;
 
1158
 
 
1159
    base.mem_base = (void *)&dummy;
 
1160
#   ifdef IA64
 
1161
      base.reg_base = (void *)GC_save_regs_in_stack();
 
1162
      /* Unnecessarily flushes register stack,          */
 
1163
      /* but that probably doesn't hurt.                */
 
1164
#   endif
 
1165
    return fn(&base, arg);
 
1166
}
1166
1167
 
1167
1168
#if !defined(NO_DEBUGGING)
1168
1169
 
1169
1170
void GC_dump()
1170
1171
{
1171
 
    GC_printf0("***Static roots:\n");
 
1172
    GC_printf("***Static roots:\n");
1172
1173
    GC_print_static_roots();
1173
 
    GC_printf0("\n***Heap sections:\n");
 
1174
    GC_printf("\n***Heap sections:\n");
1174
1175
    GC_print_heap_sects();
1175
 
    GC_printf0("\n***Free blocks:\n");
 
1176
    GC_printf("\n***Free blocks:\n");
1176
1177
    GC_print_hblkfreelist();
1177
 
    GC_printf0("\n***Blocks in use:\n");
 
1178
    GC_printf("\n***Blocks in use:\n");
1178
1179
    GC_print_block_list();
1179
 
    GC_printf0("\n***Finalization statistics:\n");
 
1180
    GC_printf("\n***Finalization statistics:\n");
1180
1181
    GC_print_finalization_stats();
1181
1182
}
1182
1183