disclaim_test.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
  3. *
  4. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  6. *
  7. * Permission is hereby granted to use or copy this program
  8. * for any purpose, provided the above notices are retained on all copies.
  9. * Permission to modify the code and to distribute modified code is granted,
  10. * provided the above notices are retained, and a notice that the code was
  11. * modified is included with the above copyright notice.
  12. *
  13. */
  14. /* Test that objects reachable from an object allocated with */
  15. /* GC_malloc_with_finalizer is not reclaimable before the finalizer */
  16. /* is called. */
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #ifdef HAVE_CONFIG_H
  21. /* For GC_[P]THREADS */
  22. # include "config.h"
  23. #endif
  24. #undef GC_NO_THREAD_REDIRECTS
  25. #include "gc_disclaim.h"
  26. #ifdef LINT2
  27. /* Avoid include gc_priv.h. */
  28. # ifndef GC_API_PRIV
  29. # define GC_API_PRIV GC_API
  30. # endif
  31. # ifdef __cplusplus
  32. extern "C" {
  33. # endif
  34. GC_API_PRIV long GC_random(void);
  35. # ifdef __cplusplus
  36. } /* extern "C" */
  37. # endif
  38. # undef rand
  39. # define rand() (int)GC_random()
  40. #endif /* LINT2 */
  41. #define my_assert(e) \
  42. if (!(e)) { \
  43. fflush(stdout); \
  44. fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
  45. exit(-1); \
  46. }
  47. int memeq(void *s, int c, size_t len)
  48. {
  49. while (len--) {
  50. if (*(char *)s != c)
  51. return 0;
  52. s = (char *)s + 1;
  53. }
  54. return 1;
  55. }
  56. void GC_CALLBACK misc_sizes_dct(void *obj, void *cd)
  57. {
  58. unsigned log_size = *(unsigned char *)obj;
  59. size_t size;
  60. my_assert(log_size < sizeof(size_t) * 8);
  61. my_assert(cd == NULL);
  62. size = (size_t)1 << log_size;
  63. my_assert(memeq((char *)obj + 1, 0x56, size - 1));
  64. }
  65. void test_misc_sizes(void)
  66. {
  67. static const struct GC_finalizer_closure fc = { misc_sizes_dct, NULL };
  68. int i;
  69. for (i = 1; i <= 20; ++i) { /* Up to 1 MiB. */
  70. void *p = GC_finalized_malloc((size_t)1 << i, &fc);
  71. if (p == NULL) {
  72. fprintf(stderr, "Out of memory!\n");
  73. exit(3);
  74. }
  75. my_assert(memeq(p, 0, (size_t)1 << i));
  76. memset(p, 0x56, (size_t)1 << i);
  77. *(unsigned char *)p = i;
  78. }
  79. }
  80. typedef struct pair_s *pair_t;
  81. struct pair_s {
  82. char magic[16];
  83. int checksum;
  84. pair_t car;
  85. pair_t cdr;
  86. };
  87. static const char * const pair_magic = "PAIR_MAGIC_BYTES";
  88. int is_pair(pair_t p)
  89. {
  90. return memcmp(p->magic, pair_magic, sizeof(p->magic)) == 0;
  91. }
  92. void GC_CALLBACK pair_dct(void *obj, void *cd)
  93. {
  94. pair_t p = (pair_t)obj;
  95. int checksum;
  96. /* Check that obj and its car and cdr are not trashed. */
  97. # ifdef DEBUG_DISCLAIM_DESTRUCT
  98. printf("Destruct %p = (%p, %p)\n",
  99. (void *)p, (void *)p->car, (void *)p->cdr);
  100. # endif
  101. my_assert(GC_base(obj));
  102. my_assert(is_pair(p));
  103. my_assert(!p->car || is_pair(p->car));
  104. my_assert(!p->cdr || is_pair(p->cdr));
  105. checksum = 782;
  106. if (p->car) checksum += p->car->checksum;
  107. if (p->cdr) checksum += p->cdr->checksum;
  108. my_assert(p->checksum == checksum);
  109. /* Invalidate it. */
  110. memset(p->magic, '*', sizeof(p->magic));
  111. p->checksum = 0;
  112. p->car = (pair_t)cd;
  113. p->cdr = NULL;
  114. GC_end_stubborn_change(p);
  115. }
  116. pair_t
  117. pair_new(pair_t car, pair_t cdr)
  118. {
  119. pair_t p;
  120. static const struct GC_finalizer_closure fc = { pair_dct, NULL };
  121. p = (pair_t)GC_finalized_malloc(sizeof(struct pair_s), &fc);
  122. if (p == NULL) {
  123. fprintf(stderr, "Out of memory!\n");
  124. exit(3);
  125. }
  126. my_assert(!is_pair(p));
  127. my_assert(memeq(p, 0, sizeof(struct pair_s)));
  128. memcpy(p->magic, pair_magic, sizeof(p->magic));
  129. p->checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0);
  130. p->car = car;
  131. p->cdr = cdr;
  132. GC_end_stubborn_change(p);
  133. # ifdef DEBUG_DISCLAIM_DESTRUCT
  134. printf("Construct %p = (%p, %p)\n",
  135. (void *)p, (void *)p->car, (void *)p->cdr);
  136. # endif
  137. return p;
  138. }
  139. void
  140. pair_check_rec(pair_t p)
  141. {
  142. while (p) {
  143. int checksum = 782;
  144. if (p->car) checksum += p->car->checksum;
  145. if (p->cdr) checksum += p->cdr->checksum;
  146. my_assert(p->checksum == checksum);
  147. if (rand() % 2)
  148. p = p->car;
  149. else
  150. p = p->cdr;
  151. }
  152. }
  153. #ifdef GC_PTHREADS
  154. # ifndef NTHREADS
  155. # define NTHREADS 6
  156. # endif
  157. # include <pthread.h>
  158. #else
  159. # undef NTHREADS
  160. # define NTHREADS 1
  161. #endif
  162. #define POP_SIZE 1000
  163. #if NTHREADS > 1
  164. # define MUTATE_CNT (2000000/NTHREADS)
  165. #else
  166. # define MUTATE_CNT 10000000
  167. #endif
  168. #define GROW_LIMIT (MUTATE_CNT/10)
  169. void *test(void *data)
  170. {
  171. int i;
  172. pair_t pop[POP_SIZE];
  173. memset(pop, 0, sizeof(pop));
  174. for (i = 0; i < MUTATE_CNT; ++i) {
  175. int t = rand() % POP_SIZE;
  176. switch (rand() % (i > GROW_LIMIT? 5 : 3)) {
  177. case 0: case 3:
  178. if (pop[t])
  179. pop[t] = pop[t]->car;
  180. break;
  181. case 1: case 4:
  182. if (pop[t])
  183. pop[t] = pop[t]->cdr;
  184. break;
  185. case 2:
  186. pop[t] = pair_new(pop[rand() % POP_SIZE],
  187. pop[rand() % POP_SIZE]);
  188. break;
  189. }
  190. if (rand() % 8 == 1)
  191. pair_check_rec(pop[rand() % POP_SIZE]);
  192. }
  193. return data;
  194. }
  195. int main(void)
  196. {
  197. # if NTHREADS > 1
  198. pthread_t th[NTHREADS];
  199. int i;
  200. # endif
  201. GC_set_all_interior_pointers(0); /* for a stricter test */
  202. GC_INIT();
  203. GC_init_finalized_malloc();
  204. # ifndef NO_INCREMENTAL
  205. GC_enable_incremental();
  206. # endif
  207. test_misc_sizes();
  208. # if NTHREADS > 1
  209. printf("Threaded disclaim test.\n");
  210. for (i = 0; i < NTHREADS; ++i) {
  211. int err = pthread_create(&th[i], NULL, test, NULL);
  212. if (err) {
  213. fprintf(stderr, "Failed to create thread # %d: %s\n", i,
  214. strerror(err));
  215. exit(1);
  216. }
  217. }
  218. for (i = 0; i < NTHREADS; ++i) {
  219. int err = pthread_join(th[i], NULL);
  220. if (err) {
  221. fprintf(stderr, "Failed to join thread # %d: %s\n", i,
  222. strerror(err));
  223. exit(69);
  224. }
  225. }
  226. # else
  227. printf("Unthreaded disclaim test.\n");
  228. test(NULL);
  229. # endif
  230. return 0;
  231. }