1 #include "test/jemalloc_test.h"
2
3 static int data_cleanup_count;
4
5 void
data_cleanup(int * data)6 data_cleanup(int *data) {
7 if (data_cleanup_count == 0) {
8 assert_x_eq(*data, MALLOC_TSD_TEST_DATA_INIT,
9 "Argument passed into cleanup function should match tsd "
10 "value");
11 }
12 ++data_cleanup_count;
13
14 /*
15 * Allocate during cleanup for two rounds, in order to assure that
16 * jemalloc's internal tsd reinitialization happens.
17 */
18 bool reincarnate = false;
19 switch (*data) {
20 case MALLOC_TSD_TEST_DATA_INIT:
21 *data = 1;
22 reincarnate = true;
23 break;
24 case 1:
25 *data = 2;
26 reincarnate = true;
27 break;
28 case 2:
29 return;
30 default:
31 not_reached();
32 }
33
34 if (reincarnate) {
35 void *p = mallocx(1, 0);
36 assert_ptr_not_null(p, "Unexpeced mallocx() failure");
37 dallocx(p, 0);
38 }
39 }
40
41 static void *
thd_start(void * arg)42 thd_start(void *arg) {
43 int d = (int)(uintptr_t)arg;
44 void *p;
45
46 tsd_t *tsd = tsd_fetch();
47 assert_x_eq(tsd_test_data_get(tsd), MALLOC_TSD_TEST_DATA_INIT,
48 "Initial tsd get should return initialization value");
49
50 p = malloc(1);
51 assert_ptr_not_null(p, "Unexpected malloc() failure");
52
53 tsd_test_data_set(tsd, d);
54 assert_x_eq(tsd_test_data_get(tsd), d,
55 "After tsd set, tsd get should return value that was set");
56
57 d = 0;
58 assert_x_eq(tsd_test_data_get(tsd), (int)(uintptr_t)arg,
59 "Resetting local data should have no effect on tsd");
60
61 tsd_test_callback_set(tsd, &data_cleanup);
62
63 free(p);
64 return NULL;
65 }
66
TEST_BEGIN(test_tsd_main_thread)67 TEST_BEGIN(test_tsd_main_thread) {
68 thd_start((void *)(uintptr_t)0xa5f3e329);
69 }
70 TEST_END
71
TEST_BEGIN(test_tsd_sub_thread)72 TEST_BEGIN(test_tsd_sub_thread) {
73 thd_t thd;
74
75 data_cleanup_count = 0;
76 thd_create(&thd, thd_start, (void *)MALLOC_TSD_TEST_DATA_INIT);
77 thd_join(thd, NULL);
78 /*
79 * We reincarnate twice in the data cleanup, so it should execute at
80 * least 3 times.
81 */
82 assert_x_ge(data_cleanup_count, 3,
83 "Cleanup function should have executed multiple times.");
84 }
85 TEST_END
86
87 static void *
thd_start_reincarnated(void * arg)88 thd_start_reincarnated(void *arg) {
89 tsd_t *tsd = tsd_fetch();
90 assert(tsd);
91
92 void *p = malloc(1);
93 assert_ptr_not_null(p, "Unexpected malloc() failure");
94
95 /* Manually trigger reincarnation. */
96 assert_ptr_not_null(tsd_arena_get(tsd),
97 "Should have tsd arena set.");
98 tsd_cleanup((void *)tsd);
99 assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
100 "TSD arena should have been cleared.");
101 assert_u_eq(tsd->state, tsd_state_purgatory,
102 "TSD state should be purgatory\n");
103
104 free(p);
105 assert_u_eq(tsd->state, tsd_state_reincarnated,
106 "TSD state should be reincarnated\n");
107 p = mallocx(1, MALLOCX_TCACHE_NONE);
108 assert_ptr_not_null(p, "Unexpected malloc() failure");
109 assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
110 "Should not have tsd arena set after reincarnation.");
111
112 free(p);
113 tsd_cleanup((void *)tsd);
114 assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
115 "TSD arena should have been cleared after 2nd cleanup.");
116
117 return NULL;
118 }
119
TEST_BEGIN(test_tsd_reincarnation)120 TEST_BEGIN(test_tsd_reincarnation) {
121 thd_t thd;
122 thd_create(&thd, thd_start_reincarnated, NULL);
123 thd_join(thd, NULL);
124 }
125 TEST_END
126
127 int
main(void)128 main(void) {
129 /* Ensure tsd bootstrapped. */
130 if (nallocx(1, 0) == 0) {
131 malloc_printf("Initialization error");
132 return test_status_fail;
133 }
134
135 return test_no_reentrancy(
136 test_tsd_main_thread,
137 test_tsd_sub_thread,
138 test_tsd_reincarnation);
139 }
140