Home | History | Annotate | Line # | Download | only in unit
      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