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