1313#include "base_alloc_global.h"
1414#include "utils_common.h"
1515#include "utils_concurrency.h"
16+ #include "utils_load_library.h"
1617#include "utils_log.h"
1718#include "utils_sanitizers.h"
1819
3435
3536#define MALLOCX_ARENA_MAX (MALLCTL_ARENAS_ALL - 1)
3637
38+ typedef struct je_callbacks_t {
39+ void * (* pool_mallocx )(size_t size , int flags );
40+ void * (* pool_rallocx )(void * ptr , size_t size , int flags );
41+ void (* pool_dallocx )(void * ptr , int flags );
42+ int (* pool_mallctl )(const char * name , void * oldp , size_t * oldlenp ,
43+ void * newp , size_t newlen );
44+ #ifdef _WIN32
45+ HMODULE lib_handle ;
46+ #else
47+ void * lib_handle ;
48+ #endif
49+ } je_callbacks_t ;
50+
3751typedef struct jemalloc_memory_pool_t {
52+ je_callbacks_t je_callbacks ; // jemalloc callbacks
3853 umf_memory_provider_handle_t provider ;
3954 unsigned int arena_index ; // index of jemalloc arena
4055 // set to true if umfMemoryProviderFree() should never be called
@@ -51,6 +66,55 @@ static __TLS umf_result_t TLS_last_allocation_error;
5166
5267static jemalloc_memory_pool_t * pool_by_arena_index [MALLCTL_ARENAS_ALL ];
5368
69+ typedef enum je_enums_t {
70+ JE_LIB_NAME = 0 ,
71+ JE_MALLOCX ,
72+ JE_RALLOCX ,
73+ JE_DALLOCX ,
74+ JE_MALLCTL ,
75+ JE_SYMBOLS_MAX // it has to be the last one
76+ } je_enums_t ;
77+
78+ static const char * je_symbol [JE_SYMBOLS_MAX ] = {
79+ #ifdef _WIN32
80+ "libjemalloc.dll" , "je_mallocx" , "je_rallocx" , "je_dallocx" , "je_mallctl" ,
81+ #else
82+ "libjemalloc.so.2" , "mallocx" , "rallocx" , "dallocx" , "mallctl" ,
83+ #endif
84+ };
85+
86+ static int init_je_callbacks (je_callbacks_t * je_callbacks ) {
87+ assert (je_callbacks );
88+
89+ const char * lib_name = je_symbol [JE_LIB_NAME ];
90+ je_callbacks -> lib_handle = utils_open_library (lib_name , 0 );
91+ if (!je_callbacks -> lib_handle ) {
92+ LOG_FATAL (
93+ "opening the %s library (required by jemalloc pool) failed - make "
94+ "sure jemalloc is installed and it is in the default search paths" ,
95+ lib_name );
96+ return -1 ;
97+ }
98+
99+ * (void * * )& je_callbacks -> pool_mallocx = utils_get_symbol_addr (
100+ je_callbacks -> lib_handle , je_symbol [JE_MALLOCX ], lib_name );
101+ * (void * * )& je_callbacks -> pool_rallocx = utils_get_symbol_addr (
102+ je_callbacks -> lib_handle , je_symbol [JE_RALLOCX ], lib_name );
103+ * (void * * )& je_callbacks -> pool_dallocx = utils_get_symbol_addr (
104+ je_callbacks -> lib_handle , je_symbol [JE_DALLOCX ], lib_name );
105+ * (void * * )& je_callbacks -> pool_mallctl = utils_get_symbol_addr (
106+ je_callbacks -> lib_handle , je_symbol [JE_MALLCTL ], lib_name );
107+
108+ if (!je_callbacks -> pool_mallocx || !je_callbacks -> pool_rallocx ||
109+ !je_callbacks -> pool_dallocx || !je_callbacks -> pool_mallctl ) {
110+ LOG_ERR ("cannot find symbols in %s" , lib_name );
111+ utils_close_library (je_callbacks -> lib_handle );
112+ return -1 ;
113+ }
114+
115+ return 0 ;
116+ }
117+
54118static jemalloc_memory_pool_t * get_pool_by_arena_index (unsigned arena_ind ) {
55119 // there is no way to obtain MALLOCX_ARENA_MAX from jemalloc
56120 // so this checks if arena_ind does not exceed assumed range
@@ -359,7 +423,7 @@ static void *op_malloc(void *pool, size_t size) {
359423 // MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
360424 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
361425 int flags = MALLOCX_ARENA (je_pool -> arena_index ) | MALLOCX_TCACHE_NONE ;
362- void * ptr = je_mallocx (size , flags );
426+ void * ptr = ( * je_pool -> je_callbacks . pool_mallocx ) (size , flags );
363427 if (ptr == NULL ) {
364428 TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
365429 return NULL ;
@@ -371,12 +435,12 @@ static void *op_malloc(void *pool, size_t size) {
371435}
372436
373437static umf_result_t op_free (void * pool , void * ptr ) {
374- (void )pool ; // unused
375438 assert (pool );
439+ jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
376440
377441 if (ptr != NULL ) {
378442 VALGRIND_DO_MEMPOOL_FREE (pool , ptr );
379- je_dallocx (ptr , MALLOCX_TCACHE_NONE );
443+ ( * je_pool -> je_callbacks . pool_dallocx ) (ptr , MALLOCX_TCACHE_NONE );
380444 }
381445
382446 return UMF_RESULT_SUCCESS ;
@@ -399,20 +463,21 @@ static void *op_calloc(void *pool, size_t num, size_t size) {
399463
400464static void * op_realloc (void * pool , void * ptr , size_t size ) {
401465 assert (pool );
466+ jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
467+
402468 if (size == 0 && ptr != NULL ) {
403- je_dallocx (ptr , MALLOCX_TCACHE_NONE );
469+ ( * je_pool -> je_callbacks . pool_dallocx ) (ptr , MALLOCX_TCACHE_NONE );
404470 TLS_last_allocation_error = UMF_RESULT_SUCCESS ;
405471 VALGRIND_DO_MEMPOOL_FREE (pool , ptr );
406472 return NULL ;
407473 } else if (ptr == NULL ) {
408474 return op_malloc (pool , size );
409475 }
410476
411- jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
412477 // MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
413478 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
414479 int flags = MALLOCX_ARENA (je_pool -> arena_index ) | MALLOCX_TCACHE_NONE ;
415- void * new_ptr = je_rallocx (ptr , size , flags );
480+ void * new_ptr = ( * je_pool -> je_callbacks . pool_rallocx ) (ptr , size , flags );
416481 if (new_ptr == NULL ) {
417482 TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
418483 return NULL ;
@@ -437,7 +502,7 @@ static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) {
437502 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
438503 int flags =
439504 MALLOCX_ALIGN (alignment ) | MALLOCX_ARENA (arena ) | MALLOCX_TCACHE_NONE ;
440- void * ptr = je_mallocx (size , flags );
505+ void * ptr = ( * je_pool -> je_callbacks . pool_mallocx ) (size , flags );
441506 if (ptr == NULL ) {
442507 TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
443508 return NULL ;
@@ -453,6 +518,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
453518 assert (provider );
454519 assert (out_pool );
455520
521+ umf_result_t umf_result = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
522+
456523 umf_jemalloc_pool_params_handle_t je_params =
457524 (umf_jemalloc_pool_params_handle_t )params ;
458525
@@ -466,6 +533,13 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
466533 return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
467534 }
468535
536+ int ret = init_je_callbacks (& pool -> je_callbacks );
537+ if (ret != 0 ) {
538+ LOG_ERR ("loading jemalloc symbols failed" );
539+ umf_result = UMF_RESULT_ERROR_UNKNOWN ;
540+ goto err_free_pool ;
541+ }
542+
469543 pool -> provider = provider ;
470544
471545 if (je_params ) {
@@ -475,8 +549,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
475549 }
476550
477551 unsigned arena_index ;
478- err = je_mallctl ( "arenas.create" , ( void * ) & arena_index , & unsigned_size ,
479- NULL , 0 );
552+ err = ( * pool -> je_callbacks . pool_mallctl )(
553+ "arenas.create" , ( void * ) & arena_index , & unsigned_size , NULL , 0 );
480554 if (err ) {
481555 LOG_ERR ("Could not create arena." );
482556 goto err_free_pool ;
@@ -485,10 +559,11 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
485559 // setup extent_hooks for newly created arena
486560 char cmd [64 ];
487561 snprintf (cmd , sizeof (cmd ), "arena.%u.extent_hooks" , arena_index );
488- err = je_mallctl (cmd , NULL , NULL , (void * )& pHooks , sizeof (void * ));
562+ err = (* pool -> je_callbacks .pool_mallctl )(cmd , NULL , NULL , (void * )& pHooks ,
563+ sizeof (void * ));
489564 if (err ) {
490565 snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena_index );
491- je_mallctl (cmd , NULL , 0 , NULL , 0 );
566+ ( * pool -> je_callbacks . pool_mallctl ) (cmd , NULL , 0 , NULL , 0 );
492567 LOG_ERR ("Could not setup extent_hooks for newly created arena." );
493568 goto err_free_pool ;
494569 }
@@ -504,15 +579,15 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
504579
505580err_free_pool :
506581 umf_ba_global_free (pool );
507- return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
582+ return umf_result ;
508583}
509584
510585static void op_finalize (void * pool ) {
511586 assert (pool );
512587 jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
513588 char cmd [64 ];
514589 snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , je_pool -> arena_index );
515- je_mallctl (cmd , NULL , 0 , NULL , 0 );
590+ ( * je_pool -> je_callbacks . pool_mallctl ) (cmd , NULL , 0 , NULL , 0 );
516591 pool_by_arena_index [je_pool -> arena_index ] = NULL ;
517592 umf_ba_global_free (je_pool );
518593
0 commit comments