• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ivmai / bdwgc / 1451

10 Mar 2023 05:47PM UTC coverage: 76.182% (-0.5%) from 76.638%
1451

push

travis-ci-com

ivmai
Change enable_threads default to off if threads are unsupported (CMake)

PR #535 (bdwgc).

In case of an absent multi-threading support for the target platform,
like for Emscripten or WASI, cmake build should not fail by default
(i.e. threads support should not be on by default).  This matches the
relevant behavior of configure one.

* CMakeLists.txt (default_enable_threads): New variable (ON by
default).
* CMakeLists.txt: Call find_package(Threads) quietly regardless of
enable_threads.
* CMakeLists.txt [EMSCRIPTEN || WASI || !(CMAKE_USE_PTHREADS_INIT ||
CMAKE_USE_WIN32_THREADS_INIT)] (default_enable_threads): Set to OFF.
* CMakeLists.txt (enable_threads): Specify the default value to
default_enable_threads.
* CMakeLists.txt: Check CMAKE_USE_PTHREADS_INIT and
CMAKE_USE_WIN32_THREADS_INIT only if enable_threads.

Co-authored-by: Ivan Maidanski <ivmai@mail.ru>

7734 of 10152 relevant lines covered (76.18%)

8264643.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.82
/headers.c
1
/*
2
 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4
 * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
5
 * Copyright (c) 2008-2022 Ivan Maidanski
6
 *
7
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9
 *
10
 * Permission is hereby granted to use or copy this program
11
 * for any purpose, provided the above notices are retained on all copies.
12
 * Permission to modify the code and to distribute modified code is granted,
13
 * provided the above notices are retained, and a notice that the code was
14
 * modified is included with the above copyright notice.
15
 */
16

17
#include "private/gc_priv.h"
18

19
/*
20
 * This implements:
21
 * 1. allocation of heap block headers
22
 * 2. A map from addresses to heap block addresses to heap block headers
23
 *
24
 * Access speed is crucial.  We implement an index structure based on a 2
25
 * level tree.
26
 */
27

28
/* Non-macro version of header location routine */
29
GC_INNER hdr * GC_find_header(ptr_t h)
1,175,243,417✔
30
{
31
#   ifdef HASH_TL
32
        hdr * result;
33
        GET_HDR(h, result);
1,175,243,417✔
34
        return result;
1,175,243,417✔
35
#   else
36
        return HDR_INNER(h);
37
#   endif
38
}
39

40
/* Handle a header cache miss.  Returns a pointer to the        */
41
/* header corresponding to p, if p can possibly be a valid      */
42
/* object pointer, and 0 otherwise.                             */
43
/* GUARANTEED to return 0 for a pointer past the first page     */
44
/* of an object unless both GC_all_interior_pointers is set     */
45
/* and p is in fact a valid object pointer.                     */
46
/* Never returns a pointer to a free hblk.                      */
47
GC_INNER hdr *
48
#ifdef PRINT_BLACK_LIST
49
  GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source)
50
#else
51
  GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce)
114,553,749✔
52
#endif
53
{
54
  hdr *hhdr;
55
  HC_MISS();
56
  GET_HDR(p, hhdr);
114,553,749✔
57
  if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
114,553,749✔
58
    if (GC_all_interior_pointers) {
11,789,395✔
59
      if (hhdr != 0) {
8,966,268✔
60
        ptr_t current = p;
620✔
61

62
        current = (ptr_t)HBLKPTR(current);
620✔
63
        do {
64
            current = current - HBLKSIZE*(word)hhdr;
620✔
65
            hhdr = HDR(current);
620✔
66
        } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
620✔
67
        /* current points to near the start of the large object */
68
        if (hhdr -> hb_flags & IGNORE_OFF_PAGE)
620✔
69
            return 0;
×
70
        if (HBLK_IS_FREE(hhdr)
620✔
71
            || p - current >= (ptrdiff_t)(hhdr->hb_sz)) {
620✔
72
            GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
206✔
73
            /* Pointer past the end of the block */
74
            return 0;
206✔
75
        }
76
      } else {
77
        GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
8,965,648✔
78
        /* And return zero: */
79
      }
80
      GC_ASSERT(hhdr == 0 || !HBLK_IS_FREE(hhdr));
8,965,956✔
81
      return hhdr;
8,965,956✔
82
      /* Pointers past the first page are probably too rare     */
83
      /* to add them to the cache.  We don't.                   */
84
      /* And correctness relies on the fact that we don't.      */
85
    } else {
86
      if (hhdr == 0) {
2,823,127✔
87
        GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
2,823,135✔
88
      }
89
      return 0;
2,822,800✔
90
    }
91
  } else {
92
    if (HBLK_IS_FREE(hhdr)) {
102,764,354✔
93
      GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
200,419✔
94
      return 0;
200,419✔
95
    } else {
96
      hce -> block_addr = (word)(p) >> LOG_HBLKSIZE;
102,563,935✔
97
      hce -> hce_hdr = hhdr;
102,563,935✔
98
      return hhdr;
102,563,935✔
99
    }
100
  }
101
}
102

103
/* Routines to dynamically allocate collector data structures that will */
104
/* never be freed.                                                      */
105

106
GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
191,098✔
107
{
108
    ptr_t result = GC_scratch_free_ptr;
191,098✔
109
    size_t bytes_to_get;
110

111
    GC_ASSERT(I_HOLD_LOCK());
191,098✔
112
    bytes = ROUNDUP_GRANULE_SIZE(bytes);
191,098✔
113
    for (;;) {
114
        GC_ASSERT((word)GC_scratch_end_ptr >= (word)result);
192,198✔
115
        if (bytes <= (word)GC_scratch_end_ptr - (word)result) {
192,198✔
116
            /* Unallocated space of scratch buffer has enough size. */
117
            GC_scratch_free_ptr = result + bytes;
190,846✔
118
            return result;
190,846✔
119
        }
120

121
        GC_ASSERT(GC_page_size != 0);
1,352✔
122
        if (bytes >= MINHINCR * HBLKSIZE) {
1,352✔
123
            bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes);
252✔
124
            result = (ptr_t)GET_MEM(bytes_to_get);
252✔
125
            if (result != NULL) {
252✔
126
              GC_add_to_our_memory(result, bytes_to_get);
252✔
127
              /* No update of scratch free area pointer;        */
128
              /* get memory directly.                           */
129
#             ifdef USE_SCRATCH_LAST_END_PTR
130
                /* Update end point of last obtained area (needed only  */
131
                /* by GC_register_dynamic_libraries for some targets).  */
132
                GC_scratch_last_end_ptr = result + bytes;
133
#             endif
134
            }
135
            return result;
252✔
136
        }
137

138
        bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MINHINCR * HBLKSIZE);
1,100✔
139
                                                /* round up for safety */
140
        result = (ptr_t)GET_MEM(bytes_to_get);
1,100✔
141
        if (EXPECT(NULL == result, FALSE)) {
1,100✔
142
            WARN("Out of memory - trying to allocate requested amount"
×
143
                 " (%" WARN_PRIuPTR " bytes)...\n", bytes);
144
            bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes);
×
145
            result = (ptr_t)GET_MEM(bytes_to_get);
×
146
            if (result != NULL) {
×
147
              GC_add_to_our_memory(result, bytes_to_get);
×
148
#             ifdef USE_SCRATCH_LAST_END_PTR
149
                GC_scratch_last_end_ptr = result + bytes;
150
#             endif
151
            }
152
            return result;
×
153
        }
154

155
        GC_add_to_our_memory(result, bytes_to_get);
1,100✔
156
        /* TODO: some amount of unallocated space may remain unused forever */
157
        /* Update scratch area pointers and retry.      */
158
        GC_scratch_free_ptr = result;
1,100✔
159
        GC_scratch_end_ptr = GC_scratch_free_ptr + bytes_to_get;
1,100✔
160
#       ifdef USE_SCRATCH_LAST_END_PTR
161
          GC_scratch_last_end_ptr = GC_scratch_end_ptr;
162
#       endif
163
    }
1,100✔
164
}
165

166
/* Return an uninitialized header */
167
static hdr * alloc_hdr(void)
1,659,613✔
168
{
169
    hdr * result;
170

171
    GC_ASSERT(I_HOLD_LOCK());
1,659,613✔
172
    if (NULL == GC_hdr_free_list) {
1,659,613✔
173
        result = (hdr *)GC_scratch_alloc(sizeof(hdr));
189,195✔
174
    } else {
175
        result = GC_hdr_free_list;
1,470,418✔
176
        GC_hdr_free_list = (hdr *) result -> hb_next;
1,470,418✔
177
    }
178
    return result;
1,659,613✔
179
}
180

181
GC_INLINE void free_hdr(hdr * hhdr)
1,582,192✔
182
{
183
    hhdr -> hb_next = (struct hblk *) GC_hdr_free_list;
1,582,192✔
184
    GC_hdr_free_list = hhdr;
1,582,192✔
185
}
1,582,192✔
186

187
#ifdef COUNT_HDR_CACHE_HITS
188
  /* Used for debugging/profiling (the symbols are externally visible). */
189
  word GC_hdr_cache_hits = 0;
190
  word GC_hdr_cache_misses = 0;
191
#endif
192

193
GC_INNER void GC_init_headers(void)
32✔
194
{
195
    unsigned i;
196

197
    GC_ASSERT(I_HOLD_LOCK());
32✔
198
    GC_ASSERT(NULL == GC_all_nils);
32✔
199
    GC_all_nils = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
32✔
200
    if (GC_all_nils == NULL) {
32✔
201
      GC_err_printf("Insufficient memory for GC_all_nils\n");
×
202
      EXIT();
×
203
    }
204
    BZERO(GC_all_nils, sizeof(bottom_index));
32✔
205
    for (i = 0; i < TOP_SZ; i++) {
65,568✔
206
        GC_top_index[i] = GC_all_nils;
65,536✔
207
    }
208
}
32✔
209

210
/* Make sure that there is a bottom level index block for address addr. */
211
/* Return FALSE on failure.                                             */
212
static GC_bool get_index(word addr)
7,607,379✔
213
{
214
    word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
7,607,379✔
215
    bottom_index * r;
216
    bottom_index * p;
217
    bottom_index ** prev;
218
    bottom_index *pi; /* old_p */
219
    word i;
220

221
    GC_ASSERT(I_HOLD_LOCK());
7,607,379✔
222
#   ifdef HASH_TL
223
      i = TL_HASH(hi);
7,607,379✔
224

225
      pi = GC_top_index[i];
7,607,379✔
226
      for (p = pi; p != GC_all_nils; p = p -> hash_link) {
7,607,379✔
227
          if (p -> key == hi) return TRUE;
7,607,060✔
228
      }
229
#   else
230
      if (GC_top_index[hi] != GC_all_nils)
231
        return TRUE;
232
      i = hi;
233
#   endif
234
    r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
319✔
235
    if (EXPECT(NULL == r, FALSE))
319✔
236
      return FALSE;
×
237
    BZERO(r, sizeof(bottom_index));
319✔
238
    r -> key = hi;
319✔
239
#   ifdef HASH_TL
240
      r -> hash_link = pi;
319✔
241
#   endif
242

243
    /* Add it to the list of bottom indices */
244
      prev = &GC_all_bottom_indices;    /* pointer to p */
319✔
245
      pi = 0;                           /* bottom_index preceding p */
319✔
246
      while ((p = *prev) != 0 && p -> key < hi) {
851✔
247
        pi = p;
213✔
248
        prev = &(p -> asc_link);
213✔
249
      }
250
      r -> desc_link = pi;
319✔
251
      if (0 == p) {
319✔
252
        GC_all_bottom_indices_end = r;
34✔
253
      } else {
254
        p -> desc_link = r;
285✔
255
      }
256
      r -> asc_link = p;
319✔
257
      *prev = r;
319✔
258

259
      GC_top_index[i] = r;
319✔
260
    return TRUE;
319✔
261
}
262

263
/* Install a header for block h.        */
264
/* The header is uninitialized.         */
265
/* Returns the header or 0 on failure.  */
266
GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
1,659,613✔
267
{
268
    hdr * result;
269

270
    GC_ASSERT(I_HOLD_LOCK());
1,659,613✔
271
    if (EXPECT(!get_index((word)h), FALSE)) return NULL;
1,659,613✔
272

273
    result = alloc_hdr();
1,659,613✔
274
    if (EXPECT(result != NULL, TRUE)) {
1,659,613✔
275
      SET_HDR(h, result);
1,659,613✔
276
#     ifdef USE_MUNMAP
277
        result -> hb_last_reclaimed = (unsigned short)GC_gc_no;
1,659,613✔
278
#     endif
279
    }
280
    return result;
1,659,613✔
281
}
282

283
/* Set up forwarding counts for block h of size sz */
284
GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
2,973,883✔
285
{
286
    struct hblk * hbp;
287

288
    for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) {
5,947,766✔
289
        if (!get_index((word)hbp))
2,973,883✔
290
            return FALSE;
×
291
        if ((word)hbp > GC_WORD_MAX - (word)BOTTOM_SZ * HBLKSIZE)
2,973,883✔
292
            break; /* overflow of hbp+=BOTTOM_SZ is expected */
×
293
    }
294
    if (!get_index((word)h + sz - 1))
2,973,883✔
295
        return FALSE;
×
296
    for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) {
3,431,570✔
297
        word i = HBLK_PTR_DIFF(hbp, h);
457,687✔
298

299
        SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
457,687✔
300
    }
301
    return TRUE;
2,973,883✔
302
}
303

304
/* Remove the header for block h */
305
GC_INNER void GC_remove_header(struct hblk *h)
1,582,192✔
306
{
307
    hdr **ha;
308
    GET_HDR_ADDR(h, ha);
1,582,192✔
309
    free_hdr(*ha);
1,582,192✔
310
    *ha = 0;
1,582,192✔
311
}
1,582,192✔
312

313
/* Remove forwarding counts for h */
314
GC_INNER void GC_remove_counts(struct hblk *h, size_t sz/* bytes */)
2,935,058✔
315
{
316
    struct hblk * hbp;
317

318
    if (sz <= HBLKSIZE) return;
2,935,058✔
319
    if (HDR(h+1) == 0) {
450,134✔
320
#     ifdef GC_ASSERTIONS
321
        for (hbp = h+2; (word)hbp < (word)h + sz; hbp++)
207,169✔
322
          GC_ASSERT(HDR(hbp) == 0);
206,394✔
323
#     endif
324
      return;
775✔
325
    }
326

327
    for (hbp = h+1; (word)hbp < (word)h + sz; hbp += 1) {
906,208✔
328
        SET_HDR(hbp, 0);
456,849✔
329
    }
330
}
331

332
GC_API void GC_CALL GC_apply_to_all_blocks(GC_walk_hblk_fn fn,
33,815✔
333
                                           GC_word client_data)
334
{
335
    signed_word j;
336
    bottom_index * index_p;
337

338
    for (index_p = GC_all_bottom_indices; index_p != 0;
260,223✔
339
         index_p = index_p -> asc_link) {
192,593✔
340
        for (j = BOTTOM_SZ-1; j >= 0;) {
196,463,996✔
341
            if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])) {
196,078,810✔
342
                if (!HBLK_IS_FREE(index_p->index[j])) {
36,108,914✔
343
                    (*fn)(((struct hblk *)
29,758,626✔
344
                              (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
29,758,626✔
345
                               << LOG_HBLKSIZE)),
29,758,626✔
346
                          client_data);
347
                }
348
                j--;
36,108,914✔
349
             } else if (index_p->index[j] == 0) {
159,969,896✔
350
                j--;
157,689,416✔
351
             } else {
352
                j -= (signed_word)(index_p->index[j]);
2,280,480✔
353
             }
354
         }
355
     }
356
}
33,815✔
357

358
GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free)
2,339,388✔
359
{
360
    REGISTER bottom_index * bi;
361
    REGISTER word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
2,339,388✔
362

363
    GC_ASSERT(I_HOLD_LOCK());
2,339,388✔
364
    GET_BI(h, bi);
2,339,388✔
365
    if (bi == GC_all_nils) {
2,339,388✔
366
        REGISTER word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
24,345✔
367

368
        bi = GC_all_bottom_indices;
24,345✔
369
        while (bi != 0 && bi -> key < hi) bi = bi -> asc_link;
24,345✔
370
        j = 0;
24,345✔
371
    }
372

373
    while (bi != 0) {
4,772,392✔
374
        while (j < BOTTOM_SZ) {
64,611,895✔
375
            hdr * hhdr = bi -> index[j];
62,107,049✔
376
            if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
62,107,049✔
377
                j++;
56,040,657✔
378
            } else {
379
                if (allow_free || !HBLK_IS_FREE(hhdr)) {
6,066,392✔
380
                    return (struct hblk *)(((bi -> key << LOG_BOTTOM_SZ)
4,635,228✔
381
                                            + j) << LOG_HBLKSIZE);
2,317,614✔
382
                } else {
383
                    j += divHBLKSZ(hhdr -> hb_sz);
3,748,778✔
384
                }
385
            }
386
        }
387
        j = 0;
93,616✔
388
        bi = bi -> asc_link;
93,616✔
389
    }
390
    return NULL;
21,774✔
391
}
392

393
GC_INNER struct hblk * GC_prev_block(struct hblk *h)
215,748✔
394
{
395
    bottom_index * bi;
396
    signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
215,748✔
397

398
    GC_ASSERT(I_HOLD_LOCK());
215,748✔
399
    GET_BI(h, bi);
215,748✔
400
    if (bi == GC_all_nils) {
215,748✔
401
        word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
×
402

403
        bi = GC_all_bottom_indices_end;
×
404
        while (bi != NULL && bi -> key > hi)
×
405
            bi = bi -> desc_link;
×
406
        j = BOTTOM_SZ - 1;
×
407
    }
408
    for (; bi != NULL; bi = bi -> desc_link) {
231,910✔
409
        while (j >= 0) {
14,069,840✔
410
            hdr * hhdr = bi -> index[j];
13,831,719✔
411

412
            if (NULL == hhdr) {
13,831,719✔
413
                --j;
13,625,679✔
414
            } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
206,040✔
415
                j -= (signed_word)hhdr;
243✔
416
            } else {
417
                return (struct hblk *)(((bi -> key << LOG_BOTTOM_SZ) + j)
411,594✔
418
                                       << LOG_HBLKSIZE);
205,797✔
419
            }
420
        }
421
        j = BOTTOM_SZ - 1;
16,162✔
422
    }
423
    return NULL;
9,951✔
424
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc