2626#include "utils_log.h"
2727#include "utlist.h"
2828
29+ // Handle UTHash memory allocation failures without aborting the process.
30+ #define HASH_NONFATAL_OOM 1
31+ static bool uthash_oom = false;
32+ #define uthash_nonfatal_oom (obj ) \
33+ do { \
34+ (void)(obj); \
35+ uthash_oom = true; \
36+ } while (0)
37+
38+ #include "uthash.h"
39+
2940typedef struct ctl_default_entry_t {
3041 char * name ;
3142 void * value ;
@@ -43,6 +54,104 @@ static struct ctl umf_pool_ctl_root;
4354
4455static void pool_ctl_init (void );
4556
57+ typedef struct pool_name_list_entry_t {
58+ umf_memory_pool_handle_t pool ;
59+ struct pool_name_list_entry_t * next ;
60+ } pool_name_list_entry_t ;
61+
62+ typedef struct pool_name_dict_entry_t {
63+ char * name ; /* key */
64+ pool_name_list_entry_t * pools ;
65+ UT_hash_handle hh ;
66+ } pool_name_dict_entry_t ;
67+
68+ static pool_name_dict_entry_t * pools_by_name = NULL ;
69+ static utils_rwlock_t pools_by_name_lock ;
70+ static UTIL_ONCE_FLAG pools_by_name_init_once = UTIL_ONCE_FLAG_INIT ;
71+
72+ static void pools_by_name_init (void ) { utils_rwlock_init (& pools_by_name_lock ); }
73+
74+ static umf_result_t pools_by_name_add (umf_memory_pool_handle_t pool ) {
75+ const char * name = NULL ;
76+ umf_result_t ret = pool -> ops .get_name (pool -> pool_priv , & name );
77+ if (ret != UMF_RESULT_SUCCESS || !name ) {
78+ return ret ;
79+ }
80+
81+ utils_init_once (& pools_by_name_init_once , pools_by_name_init );
82+ utils_write_lock (& pools_by_name_lock );
83+
84+ pool_name_dict_entry_t * entry = NULL ;
85+ HASH_FIND_STR (pools_by_name , name , entry );
86+ if (!entry ) {
87+ entry = umf_ba_global_alloc (sizeof (* entry ));
88+ if (!entry ) {
89+ utils_write_unlock (& pools_by_name_lock );
90+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
91+ }
92+ entry -> name = umf_ba_global_strdup (name );
93+ if (!entry -> name ) {
94+ umf_ba_global_free (entry );
95+ utils_write_unlock (& pools_by_name_lock );
96+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
97+ }
98+
99+ entry -> pools = NULL ;
100+ uthash_oom = false;
101+ HASH_ADD_KEYPTR (hh , pools_by_name , entry -> name , strlen (entry -> name ),
102+ entry );
103+ if (uthash_oom ) {
104+ umf_ba_global_free (entry -> name );
105+ umf_ba_global_free (entry );
106+ utils_write_unlock (& pools_by_name_lock );
107+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
108+ }
109+ }
110+
111+ pool_name_list_entry_t * node = umf_ba_global_alloc (sizeof (* node ));
112+ if (!node ) {
113+ utils_write_unlock (& pools_by_name_lock );
114+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
115+ }
116+ node -> pool = pool ;
117+ node -> next = NULL ;
118+ LL_APPEND (entry -> pools , node );
119+
120+ utils_write_unlock (& pools_by_name_lock );
121+ return UMF_RESULT_SUCCESS ;
122+ }
123+
124+ static void pools_by_name_remove (umf_memory_pool_handle_t pool ) {
125+ const char * name = NULL ;
126+ if (pool -> ops .get_name (pool -> pool_priv , & name ) != UMF_RESULT_SUCCESS ||
127+ !name ) {
128+ return ;
129+ }
130+
131+ utils_init_once (& pools_by_name_init_once , pools_by_name_init );
132+ utils_write_lock (& pools_by_name_lock );
133+
134+ pool_name_dict_entry_t * entry = NULL ;
135+ HASH_FIND_STR (pools_by_name , name , entry );
136+ if (entry ) {
137+ pool_name_list_entry_t * it = NULL , * tmp = NULL ;
138+ LL_FOREACH_SAFE (entry -> pools , it , tmp ) {
139+ if (it -> pool == pool ) {
140+ LL_DELETE (entry -> pools , it );
141+ umf_ba_global_free (it );
142+ break ;
143+ }
144+ }
145+ if (entry -> pools == NULL ) {
146+ HASH_DEL (pools_by_name , entry );
147+ umf_ba_global_free (entry -> name );
148+ umf_ba_global_free (entry );
149+ }
150+ }
151+
152+ utils_write_unlock (& pools_by_name_lock );
153+ }
154+
46155static umf_result_t CTL_SUBTREE_HANDLER (CTL_NONAME , by_handle )(
47156 void * ctx , umf_ctl_query_source_t source , void * arg , size_t size ,
48157 umf_ctl_index_utlist_t * indexes , const char * extra_name ,
@@ -190,7 +299,69 @@ static umf_ctl_node_t CTL_NODE(by_handle)[] = {
190299
191300static const struct ctl_argument CTL_ARG (by_handle ) = CTL_ARG_PTR ;
192301
302+ static umf_result_t CTL_SUBTREE_HANDLER (CTL_NONAME , by_name )(
303+ void * ctx , umf_ctl_query_source_t source , void * arg , size_t size ,
304+ umf_ctl_index_utlist_t * indexes , const char * extra_name ,
305+ umf_ctl_query_type_t queryType , va_list args ) {
306+ (void )ctx ;
307+
308+ utils_init_once (& pools_by_name_init_once , pools_by_name_init );
309+
310+ const char * name = (const char * )indexes -> arg ;
311+
312+ utils_read_lock (& pools_by_name_lock );
313+ pool_name_dict_entry_t * entry = NULL ;
314+ HASH_FIND_STR (pools_by_name , name , entry );
315+ if (!entry ) {
316+ utils_read_unlock (& pools_by_name_lock );
317+ LOG_ERR ("Pool %s not found" , name );
318+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
319+ }
320+
321+ size_t count = 0 ;
322+ pool_name_list_entry_t * it = NULL ;
323+ LL_COUNT (entry -> pools , it , count );
324+ if (queryType == CTL_QUERY_READ && count > 1 ) {
325+ LOG_ERR ("CTL 'by_name' read operation requires exactly one pool with "
326+ "the specified name. "
327+ "Actual number of pools with name '%s' is %zu." ,
328+ name , count );
329+ utils_read_unlock (& pools_by_name_lock );
330+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
331+ }
332+
333+ umf_result_t ret = UMF_RESULT_SUCCESS ;
334+ LL_FOREACH (entry -> pools , it ) {
335+ va_list args2 ;
336+ va_copy (args2 , args );
337+ umf_result_t r = ctl_query (& umf_pool_ctl_root , it -> pool , source ,
338+ extra_name , queryType , arg , size , args2 );
339+ va_end (args2 );
340+
341+ if (r == UMF_RESULT_ERROR_INVALID_ARGUMENT ) {
342+ va_copy (args2 , args );
343+ r = it -> pool -> ops .ext_ctl (it -> pool -> pool_priv , source , extra_name ,
344+ arg , size , queryType , args2 );
345+ va_end (args2 );
346+ }
347+ if (r != UMF_RESULT_SUCCESS && ret == UMF_RESULT_SUCCESS ) {
348+ ret = r ;
349+ }
350+ }
351+ utils_read_unlock (& pools_by_name_lock );
352+
353+ return ret ;
354+ }
355+
356+ static umf_ctl_node_t CTL_NODE (by_name )[] = {
357+ CTL_LEAF_SUBTREE (CTL_NONAME , by_name ),
358+ CTL_NODE_END ,
359+ };
360+
361+ static const struct ctl_argument CTL_ARG (by_name ) = CTL_ARG_STRING (255 );
362+
193363umf_ctl_node_t CTL_NODE (pool )[] = {CTL_CHILD_WITH_ARG (by_handle ),
364+ CTL_CHILD_WITH_ARG (by_name ),
194365 CTL_LEAF_SUBTREE (default ), CTL_NODE_END };
195366
196367static void pool_ctl_init (void ) {
@@ -311,6 +482,7 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
311482 }
312483
313484 * hPool = pool ;
485+ pools_by_name_add (pool );
314486 LOG_INFO ("Memory pool created: %p" , (void * )pool );
315487 return UMF_RESULT_SUCCESS ;
316488
@@ -330,6 +502,8 @@ umf_result_t umfPoolDestroy(umf_memory_pool_handle_t hPool) {
330502 return UMF_RESULT_ERROR_UNKNOWN ;
331503 }
332504
505+ pools_by_name_remove (hPool );
506+
333507 umf_result_t ret = hPool -> ops .finalize (hPool -> pool_priv );
334508
335509 umf_memory_provider_handle_t hUpstreamProvider = NULL ;
0 commit comments