1 #include "test/jemalloc_test.h" 2 3 static int data_cleanup_count; 4 5 void 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 * 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 67 TEST_BEGIN(test_tsd_main_thread) { 68 thd_start((void *)(uintptr_t)0xa5f3e329); 69 } 70 TEST_END 71 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 * 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 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 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