1 #include "test/jemalloc_test.h" 2 3 /* 4 * Under percpu_arena, binding a thread to a manual arena (an index at or above 5 * the per-CPU auto range) is one-way: percpu never reclaims it (see 6 * arena_choose_impl). Setting thread.arena back to an index in the auto range 7 * resumes per-CPU selection instead of failing with EPERM. 8 */ 9 TEST_BEGIN(test_thread_arena_resume_percpu) { 10 test_skip_if(!have_percpu_arena 11 || !PERCPU_ARENA_ENABLED(opt_percpu_arena)); 12 13 unsigned limit = percpu_arena_ind_limit(opt_percpu_arena); 14 /* Bypass the tcache so every allocation and free hits the arena. */ 15 const int flags = MALLOCX_TCACHE_NONE; 16 17 void *warm = mallocx(1, 0); 18 expect_ptr_not_null(warm, "Unexpected mallocx() failure"); 19 dallocx(warm, 0); 20 21 unsigned cur; 22 size_t sz = sizeof(cur); 23 expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0, 24 "Unexpected mallctl() failure"); 25 expect_u_lt(cur, limit, "Thread should start on a per-CPU arena"); 26 27 unsigned manual; 28 sz = sizeof(manual); 29 expect_d_eq(mallctl("arenas.create", (void *)&manual, &sz, NULL, 0), 0, 30 "Unexpected arenas.create() failure"); 31 expect_u_ge(manual, limit, "A manual arena is outside the per-CPU range"); 32 33 unsigned old; 34 sz = sizeof(old); 35 expect_d_eq(mallctl("thread.arena", (void *)&old, &sz, (void *)&manual, 36 sizeof(manual)), 0, "Binding to a manual arena should be allowed"); 37 sz = sizeof(cur); 38 expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0, 39 "Unexpected mallctl() failure"); 40 expect_u_eq(cur, manual, "Thread should be bound to the manual arena"); 41 42 void *p_manual = mallocx(1024, flags); 43 expect_ptr_not_null(p_manual, "Unexpected mallocx() failure"); 44 unsigned found; 45 sz = sizeof(found); 46 expect_d_eq(mallctl("arenas.lookup", (void *)&found, &sz, 47 (void *)&p_manual, sizeof(p_manual)), 0, 48 "Unexpected arenas.lookup() failure"); 49 expect_u_eq(found, manual, "Allocation should come from the manual arena"); 50 51 void *scratch = mallocx(1024, flags); 52 expect_ptr_not_null(scratch, "Unexpected mallocx() failure"); 53 dallocx(scratch, flags); 54 55 unsigned resume = 0; 56 expect_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&resume, 57 sizeof(resume)), 0, "Should resume per-CPU selection, not fail"); 58 sz = sizeof(cur); 59 expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0, 60 "Unexpected mallctl() failure"); 61 expect_u_lt(cur, limit, "Thread should be back on a per-CPU arena"); 62 63 void *p_percpu = mallocx(1024, flags); 64 expect_ptr_not_null(p_percpu, "Unexpected mallocx() failure"); 65 sz = sizeof(found); 66 expect_d_eq(mallctl("arenas.lookup", (void *)&found, &sz, 67 (void *)&p_percpu, sizeof(p_percpu)), 0, 68 "Unexpected arenas.lookup() failure"); 69 expect_u_lt(found, limit, "Allocation should come from a per-CPU arena"); 70 dallocx(p_percpu, flags); 71 72 /* Free the manual-arena region while bound to a different arena. */ 73 dallocx(p_manual, flags); 74 } 75 TEST_END 76 77 int 78 main(void) { 79 return test( 80 test_thread_arena_resume_percpu); 81 } 82