From 98d81b5996aeb959c928406874e1c6c817012c16 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Fri, 16 Jul 2021 23:04:55 -0500 Subject: [PATCH 01/10] abtu: add ABTU_hashtable ABTU_hashtable is a simple implementation of hash table. ABTU_hashtable will be used for ABT_sched_config and ABT_pool_config. --- src/include/abtu.h | 22 +++++ src/util/Makefile.mk | 1 + src/util/hashtable.c | 195 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 src/util/hashtable.c diff --git a/src/include/abtu.h b/src/include/abtu.h index ea70d79a..5549bf89 100644 --- a/src/include/abtu.h +++ b/src/include/abtu.h @@ -336,4 +336,26 @@ ABTU_ret_err int ABTU_atoui64(const char *str, uint64_t *p_val, ABTU_ret_err int ABTU_atosz(const char *str, size_t *p_val, ABT_bool *p_overflow); +/* Simple hash table */ + +typedef struct ABTU_hashtable_element { + int key; + struct ABTU_hashtable_element *p_next; + char *data; +} ABTU_hashtable_element; + +typedef struct ABTU_hashtable { + size_t num_entries; + size_t data_size; +} ABTU_hashtable; + +ABTU_ret_err int ABTU_hashtable_create(size_t num_entries, size_t data_size, + ABTU_hashtable **pp_hashtable); +void ABTU_hashtable_free(ABTU_hashtable *p_hashtable); +void ABTU_hashtable_get(const ABTU_hashtable *p_hashtable, int key, void *data, + int *found); +ABTU_ret_err int ABTU_hashtable_set(ABTU_hashtable *p_hashtable, int key, + const void *data, int *overwritten); +void ABTU_hashtable_delete(ABTU_hashtable *p_hashtable, int key, int *deleted); + #endif /* ABTU_H_INCLUDED */ diff --git a/src/util/Makefile.mk b/src/util/Makefile.mk index f0626d44..e8b4800a 100644 --- a/src/util/Makefile.mk +++ b/src/util/Makefile.mk @@ -5,5 +5,6 @@ abt_sources += \ util/atoi.c \ + util/hashtable.c \ util/largepage.c \ util/mprotect.c diff --git a/src/util/hashtable.c b/src/util/hashtable.c new file mode 100644 index 00000000..c1323be5 --- /dev/null +++ b/src/util/hashtable.c @@ -0,0 +1,195 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ +/* + * See COPYRIGHT in top-level directory. + */ + +#include "abti.h" + +static inline ABTU_hashtable_element * +get_element(const ABTU_hashtable *p_hashtable, size_t entry_index) +{ + char *p_buffer = (char *)p_hashtable; + const size_t data_size = p_hashtable->data_size; + const size_t hashtable_size = sizeof(ABTU_hashtable); + const size_t hashtable_element_size = + ABTU_roundup_size(sizeof(ABTU_hashtable_element) + data_size, + ABT_CONFIG_STATIC_CACHELINE_SIZE); + return (ABTU_hashtable_element *)(p_buffer + hashtable_size + + hashtable_element_size * entry_index); +} + +ABTU_ret_err int ABTU_hashtable_create(size_t num_entries, size_t data_size, + ABTU_hashtable **pp_hashtable) +{ + const size_t hashtable_size = sizeof(ABTU_hashtable); + const size_t hashtable_element_size = + ABTU_roundup_size(sizeof(ABTU_hashtable_element) + data_size, + ABT_CONFIG_STATIC_CACHELINE_SIZE); + const size_t size = hashtable_size + hashtable_element_size * num_entries; + + char *p_buffer; + int ret = ABTU_calloc(1, size, (void **)&p_buffer); + ABTI_CHECK_ERROR(ret); + + ABTU_hashtable *p_hashtable = (ABTU_hashtable *)p_buffer; + p_buffer += hashtable_size; + p_hashtable->num_entries = num_entries; + p_hashtable->data_size = data_size; + *pp_hashtable = p_hashtable; + return ABT_SUCCESS; +} + +void ABTU_hashtable_free(ABTU_hashtable *p_hashtable) +{ + size_t i; + for (i = 0; i < p_hashtable->num_entries; i++) { + ABTU_hashtable_element *p_element = get_element(p_hashtable, i)->p_next; + while (p_element) { + ABTU_hashtable_element *p_next = p_element->p_next; + ABTU_free(p_element); + p_element = p_next; + } + } + ABTU_free(p_hashtable); +} + +void ABTU_hashtable_get(const ABTU_hashtable *p_hashtable, int key, void *data, + int *found) +{ + const size_t num_entries = p_hashtable->num_entries; + const size_t data_size = p_hashtable->data_size; + const ssize_t entry_index_tmp = ((ssize_t)key) % ((ssize_t)num_entries); + const size_t entry_index = entry_index_tmp < 0 + ? (ssize_t)(entry_index_tmp + num_entries) + : (ssize_t)entry_index_tmp; + ABTU_hashtable_element *p_element = get_element(p_hashtable, entry_index); + if (!p_element->data) { + /* No data */ + if (found) + *found = 0; + return; + } else { + /* Iterate the list. */ + while (p_element) { + if (p_element->key == key) { + if (data) { + memcpy(data, p_element->data, data_size); + } + if (found) + *found = 1; + return; + } else if (!p_element->p_next) { + if (found) + *found = 0; + return; + } + p_element = p_element->p_next; + } + } +} + +ABTU_ret_err int ABTU_hashtable_set(ABTU_hashtable *p_hashtable, int key, + const void *data, int *overwritten) +{ + ABTI_ASSERT(data); + const size_t num_entries = p_hashtable->num_entries; + const size_t data_size = p_hashtable->data_size; + const ssize_t entry_index_tmp = ((ssize_t)key) % ((ssize_t)num_entries); + const size_t entry_index = entry_index_tmp < 0 + ? (ssize_t)(entry_index_tmp + num_entries) + : (ssize_t)entry_index_tmp; + ABTU_hashtable_element *p_element = get_element(p_hashtable, entry_index); + if (!p_element->data) { + /* No data */ + p_element->key = key; + p_element->data = ((char *)p_element) + sizeof(ABTU_hashtable_element); + memcpy(p_element->data, data, data_size); + if (overwritten) + *overwritten = 0; + return ABT_SUCCESS; + } else { + /* Iterate the list. */ + while (p_element) { + if (p_element->key == key) { + if (data) { + memcpy(p_element->data, data, data_size); + } + if (overwritten) + *overwritten = 1; + return ABT_SUCCESS; + } else if (!p_element->p_next) { + const size_t hashtable_element_size = + ABTU_roundup_size(sizeof(ABTU_hashtable_element) + + data_size, + ABT_CONFIG_STATIC_CACHELINE_SIZE); + ABTU_hashtable_element *p_new_element; + int ret = ABTU_calloc(1, hashtable_element_size, + (void **)&p_new_element); + ABTI_CHECK_ERROR(ret); + p_new_element->key = key; + p_new_element->data = + ((char *)p_new_element) + sizeof(ABTU_hashtable_element); + memcpy(p_new_element->data, data, data_size); + p_element->p_next = p_new_element; + if (overwritten) + *overwritten = 0; + return ABT_SUCCESS; + } + p_element = p_element->p_next; + } + } + return ABT_SUCCESS; +} + +void ABTU_hashtable_delete(ABTU_hashtable *p_hashtable, int key, int *deleted) +{ + const size_t num_entries = p_hashtable->num_entries; + const size_t data_size = p_hashtable->data_size; + const ssize_t entry_index_tmp = ((ssize_t)key) % ((ssize_t)num_entries); + const size_t entry_index = entry_index_tmp < 0 + ? (ssize_t)(entry_index_tmp + num_entries) + : (ssize_t)entry_index_tmp; + ABTU_hashtable_element *p_element = get_element(p_hashtable, entry_index); + if (!p_element->data) { + /* No data */ + if (deleted) + *deleted = 0; + return; + } else if (p_element->key == key) { + ABTU_hashtable_element *p_next = p_element->p_next; + if (p_next) { + const size_t hashtable_element_size = + ABTU_roundup_size(sizeof(ABTU_hashtable_element) + data_size, + ABT_CONFIG_STATIC_CACHELINE_SIZE); + memcpy(p_element, p_next, hashtable_element_size); + /* Recalculate p_element->data. */ + p_element->data = + ((char *)p_element) + sizeof(ABTU_hashtable_element); + ABTU_free(p_next); + } else { + p_element->data = NULL; + } + if (deleted) + *deleted = 1; + return; + } else { + /* Iterate the list. */ + ABTU_hashtable_element **pp_element = &p_element->p_next; + p_element = *pp_element; + while (p_element) { + if (p_element->key == key) { + *pp_element = p_element->p_next; + ABTU_free(p_element); + if (deleted) + *deleted = 1; + return; + } else if (!p_element->p_next) { + if (deleted) + *deleted = 0; + return; + } + pp_element = &p_element->p_next; + p_element = *pp_element; + } + } +} From 590bd8459e5206d46a8722a07c8a5f58319d66d8 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 17:33:30 -0500 Subject: [PATCH 02/10] sched_config: use ABTU_hashtable ABTU_hashtable is a generic hash table implementation, which is slightly more heavyweight but simpler. Since ABT_sched_config manipulation is not performance critical, this patch introduces ABTU_hashtable for ABT_sched_config to increase the maintainability. --- src/include/abti.h | 15 +-- src/sched/config.c | 274 ++++++++++++++++++++++----------------------- 2 files changed, 135 insertions(+), 154 deletions(-) diff --git a/src/include/abti.h b/src/include/abti.h index 65c854d4..3a61f74b 100644 --- a/src/include/abti.h +++ b/src/include/abti.h @@ -57,9 +57,6 @@ #define ABTI_UNIT_HASH_TABLE_SIZE_EXP 8 /* N -> 2^N table entries */ #define ABTI_UNIT_HASH_TABLE_SIZE ((size_t)(1 << ABTI_UNIT_HASH_TABLE_SIZE_EXP)) -#define ABTI_SCHED_CONFIG_HTABLE_SIZE 8 -#define ABTI_SCHED_CONFIG_UNUSED_INDEX INT_MIN - #define ABTI_STACK_CHECK_TYPE_NONE 0 #define ABTI_STACK_CHECK_TYPE_CANARY 1 #define ABTI_STACK_CHECK_TYPE_MPROTECT 2 @@ -116,7 +113,6 @@ typedef struct ABTI_local_func ABTI_local_func; typedef struct ABTI_xstream ABTI_xstream; typedef enum ABTI_xstream_type ABTI_xstream_type; typedef struct ABTI_sched ABTI_sched; -typedef struct ABTI_sched_config_element ABTI_sched_config_element; typedef struct ABTI_sched_config ABTI_sched_config; typedef enum ABTI_sched_used ABTI_sched_used; typedef void *ABTI_sched_id; /* Scheduler id */ @@ -319,17 +315,8 @@ struct ABTI_sched { #endif }; -struct ABTI_sched_config_element { - int idx; /* Index of this element. */ - ABT_sched_config_type type; /* Element type. */ - char val[sizeof(double) > sizeof(void *) - ? sizeof(double) - : sizeof(void *)]; /* Memory for double, int, or pointer */ - ABTI_sched_config_element *p_next; /* Next element. */ -}; - struct ABTI_sched_config { - ABTI_sched_config_element elements[ABTI_SCHED_CONFIG_HTABLE_SIZE]; + ABTU_hashtable *p_table; }; struct ABTI_pool { diff --git a/src/sched/config.c b/src/sched/config.c index 68c0bd99..1ff3c3f3 100644 --- a/src/sched/config.c +++ b/src/sched/config.c @@ -9,14 +9,28 @@ #include #include -static inline size_t sched_config_type_size(ABT_sched_config_type type); -ABTU_ret_err static int sched_config_get(const ABTI_sched_config *p_config, - int idx, ABT_sched_config_type *p_type, - void *p_val); -ABTU_ret_err static int sched_config_set(ABTI_sched_config *p_config, int idx, - ABT_sched_config_type type, - const void *p_val); -static void sched_config_free(ABTI_sched_config *p_config); +#define SCHED_CONFIG_HTABLE_SIZE 8 +typedef struct { + ABT_sched_config_type type; /* Element type. */ + union { + int v_int; + double v_double; + void *v_ptr; + } val; +} sched_config_element; + +static void sched_config_create_element_int(sched_config_element *p_elem, + int val); +static void sched_config_create_element_double(sched_config_element *p_elem, + double val); +static void sched_config_create_element_ptr(sched_config_element *p_elem, + void *ptr); +ABTU_ret_err static int +sched_config_create_element_typed(sched_config_element *p_elem, + ABT_sched_config_type type, + const void *p_val); +static void sched_config_read_element(const sched_config_element *p_elem, + void *ptr); /** @defgroup SCHED_CONFIG Scheduler config * This group is for Scheduler config. @@ -107,15 +121,17 @@ int ABT_sched_config_create(ABT_sched_config *config, ...) ABTI_UB_ASSERT(ABTI_initialized()); int abt_errno; - int i = 0; ABTI_sched_config *p_config; abt_errno = ABTU_calloc(1, sizeof(ABTI_sched_config), (void **)&p_config); ABTI_CHECK_ERROR(abt_errno); - /* Initialize index. */ - for (i = 0; i < ABTI_SCHED_CONFIG_HTABLE_SIZE; i++) { - p_config->elements[i].idx = ABTI_SCHED_CONFIG_UNUSED_INDEX; + abt_errno = + ABTU_hashtable_create(SCHED_CONFIG_HTABLE_SIZE, + sizeof(sched_config_element), &p_config->p_table); + if (abt_errno != ABT_SUCCESS) { + ABTU_free(p_config); + ABTI_HANDLE_ERROR(abt_errno); } va_list varg_list; @@ -128,31 +144,31 @@ int ABT_sched_config_create(ABT_sched_config *config, ...) if (idx == ABT_sched_config_var_end.idx) break; /* Add the argument */ + sched_config_element data; switch (var.type) { case ABT_SCHED_CONFIG_INT: { - int int_val = va_arg(varg_list, int); - abt_errno = sched_config_set(p_config, idx, - ABT_SCHED_CONFIG_INT, &int_val); + sched_config_create_element_int(&data, va_arg(varg_list, int)); break; } case ABT_SCHED_CONFIG_DOUBLE: { - double double_val = va_arg(varg_list, double); - abt_errno = - sched_config_set(p_config, idx, ABT_SCHED_CONFIG_DOUBLE, - &double_val); + sched_config_create_element_double(&data, + va_arg(varg_list, double)); break; } case ABT_SCHED_CONFIG_PTR: { - void *ptr_val = va_arg(varg_list, void *); - abt_errno = sched_config_set(p_config, idx, - ABT_SCHED_CONFIG_PTR, &ptr_val); + sched_config_create_element_ptr(&data, + va_arg(varg_list, void *)); break; } default: abt_errno = ABT_ERR_INV_ARG; } + if (abt_errno == ABT_SUCCESS) { + abt_errno = ABTU_hashtable_set(p_config->p_table, idx, &data, NULL); + } if (abt_errno != ABT_SUCCESS) { - sched_config_free(p_config); + ABTU_hashtable_free(p_config->p_table); + ABTU_free(p_config); va_end(varg_list); ABTI_HANDLE_ERROR(abt_errno); } @@ -215,9 +231,12 @@ int ABT_sched_config_read(ABT_sched_config config, int num_vars, ...) for (idx = 0; idx < num_vars; idx++) { void *ptr = va_arg(varg_list, void *); if (ptr) { - int abt_errno = sched_config_get(p_config, idx, NULL, ptr); - /* It's okay even if there's no associated value. */ - (void)abt_errno; + sched_config_element data; + int found; + ABTU_hashtable_get(p_config->p_table, idx, &data, &found); + if (found) { + sched_config_read_element(&data, ptr); + } } } va_end(varg_list); @@ -254,7 +273,8 @@ int ABT_sched_config_free(ABT_sched_config *config) ABTI_sched_config *p_config = ABTI_sched_config_get_ptr(*config); ABTI_CHECK_NULL_SCHED_CONFIG_PTR(p_config); - sched_config_free(p_config); + ABTU_hashtable_free(p_config->p_table); + ABTU_free(p_config); *config = ABT_SCHED_CONFIG_NULL; @@ -312,8 +332,18 @@ int ABT_sched_config_set(ABT_sched_config config, int idx, ABTI_sched_config *p_config = ABTI_sched_config_get_ptr(config); ABTI_CHECK_NULL_SCHED_CONFIG_PTR(p_config); - int abt_errno = sched_config_set(p_config, idx, type, val); - ABTI_CHECK_ERROR(abt_errno); + if (val) { + /* Add a value. */ + sched_config_element data; + int abt_errno; + abt_errno = sched_config_create_element_typed(&data, type, val); + ABTI_CHECK_ERROR(abt_errno); + abt_errno = ABTU_hashtable_set(p_config->p_table, idx, &data, NULL); + ABTI_CHECK_ERROR(abt_errno); + } else { + /* Delete a value. */ + ABTU_hashtable_delete(p_config->p_table, idx, NULL); + } return ABT_SUCCESS; } @@ -362,8 +392,19 @@ int ABT_sched_config_get(ABT_sched_config config, int idx, ABTI_sched_config *p_config = ABTI_sched_config_get_ptr(config); ABTI_CHECK_NULL_SCHED_CONFIG_PTR(p_config); - int abt_errno = sched_config_get(p_config, idx, type, val); - ABTI_CHECK_ERROR(abt_errno); + sched_config_element data; + int found; + ABTU_hashtable_get(p_config->p_table, idx, &data, &found); + if (found) { + if (val) { + sched_config_read_element(&data, val); + } + if (type) { + *type = data.type; + } + } else { + ABTI_HANDLE_ERROR(ABT_ERR_INV_ARG); + } return ABT_SUCCESS; } @@ -374,134 +415,87 @@ int ABT_sched_config_get(ABT_sched_config config, int idx, ABTU_ret_err int ABTI_sched_config_read(const ABTI_sched_config *p_config, int idx, void *p_val) { - return sched_config_get(p_config, idx, NULL, p_val); + int found; + sched_config_element data; + ABTU_hashtable_get(p_config->p_table, idx, &data, &found); + if (found) { + if (p_val) { + sched_config_read_element(&data, p_val); + } + return ABT_SUCCESS; + } else { + return ABT_ERR_INV_ARG; + } } /*****************************************************************************/ /* Internal static functions */ /*****************************************************************************/ -ABTU_ret_err static int sched_config_get(const ABTI_sched_config *p_config, - int idx, ABT_sched_config_type *p_type, - void *p_val) +static void sched_config_create_element_int(sched_config_element *p_elem, + int val) { - int table_index = ((idx % ABTI_SCHED_CONFIG_HTABLE_SIZE) + - ABTI_SCHED_CONFIG_HTABLE_SIZE) % - ABTI_SCHED_CONFIG_HTABLE_SIZE; - if (p_config->elements[table_index].idx == ABTI_SCHED_CONFIG_UNUSED_INDEX) { - return ABT_ERR_INV_ARG; - } else { - const ABTI_sched_config_element *p_element = - &p_config->elements[table_index]; - while (p_element) { - if (p_element->idx == idx) { - if (p_val) { - memcpy(p_val, p_element->val, - sched_config_type_size(p_element->type)); - } - if (p_type) { - *p_type = p_element->type; - } - return ABT_SUCCESS; - } else { - p_element = p_element->p_next; - } - } - return ABT_ERR_INV_ARG; - } + memset(p_elem, 0, sizeof(sched_config_element)); + p_elem->type = ABT_SCHED_CONFIG_INT; + p_elem->val.v_int = val; } -ABTU_ret_err static int sched_config_set(ABTI_sched_config *p_config, int idx, - ABT_sched_config_type type, - const void *p_val) +static void sched_config_create_element_double(sched_config_element *p_elem, + double val) { - int table_index = ((idx % ABTI_SCHED_CONFIG_HTABLE_SIZE) + - ABTI_SCHED_CONFIG_HTABLE_SIZE) % - ABTI_SCHED_CONFIG_HTABLE_SIZE; - if (p_config->elements[table_index].idx == ABTI_SCHED_CONFIG_UNUSED_INDEX) { - if (p_val) { - /* Newly add. */ - p_config->elements[table_index].idx = idx; - p_config->elements[table_index].type = type; - memcpy(p_config->elements[table_index].val, p_val, - sched_config_type_size(type)); - } - } else { - ABTI_sched_config_element *p_element = &p_config->elements[table_index]; - ABTI_sched_config_element **pp_element = NULL; - while (p_element) { - if (p_element->idx == idx) { - if (p_val) { - /* Update. */ - p_element->type = type; - memcpy(p_element->val, p_val, sched_config_type_size(type)); - } else { - /* Remove the element. */ - if (pp_element) { - *pp_element = p_element->p_next; - ABTU_free(p_element); - } else { - ABTI_sched_config_element *p_next = p_element->p_next; - if (p_next) { - memcpy(p_element, p_next, - sizeof(ABTI_sched_config_element)); - ABTU_free(p_next); - } else { - p_element->idx = ABTI_SCHED_CONFIG_UNUSED_INDEX; - } - } - } - break; - } else if (!p_element->p_next) { - if (p_val) { - /* Newly add. */ - ABTI_sched_config_element *p_new_element; - int abt_errno = - ABTU_calloc(1, sizeof(ABTI_sched_config_element), - (void **)&p_new_element); - ABTI_CHECK_ERROR(abt_errno); - p_new_element->idx = idx; - p_new_element->type = type; - memcpy(p_new_element->val, p_val, - sched_config_type_size(type)); - p_element->p_next = p_new_element; - } - break; - } else { - pp_element = &p_element->p_next; - p_element = *pp_element; - } - } - } - return ABT_SUCCESS; + memset(p_elem, 0, sizeof(sched_config_element)); + p_elem->type = ABT_SCHED_CONFIG_DOUBLE; + p_elem->val.v_double = val; } -static void sched_config_free(ABTI_sched_config *p_config) +static void sched_config_create_element_ptr(sched_config_element *p_elem, + void *ptr) { - /* Check elements. */ - int i; - for (i = 0; i < ABTI_SCHED_CONFIG_HTABLE_SIZE; i++) { - ABTI_sched_config_element *p_element = p_config->elements[i].p_next; - while (p_element) { - ABTI_sched_config_element *p_next = p_element->p_next; - ABTU_free(p_element); - p_element = p_next; + memset(p_elem, 0, sizeof(sched_config_element)); + p_elem->type = ABT_SCHED_CONFIG_PTR; + p_elem->val.v_ptr = ptr; +} + +ABTU_ret_err static int +sched_config_create_element_typed(sched_config_element *p_elem, + ABT_sched_config_type type, const void *p_val) +{ + switch (type) { + case ABT_SCHED_CONFIG_INT: { + sched_config_create_element_int(p_elem, *(const int *)p_val); + break; + } + case ABT_SCHED_CONFIG_DOUBLE: { + sched_config_create_element_double(p_elem, *(const double *)p_val); + break; } + case ABT_SCHED_CONFIG_PTR: { + sched_config_create_element_ptr(p_elem, *(void *const *)p_val); + break; + } + default: + return ABT_ERR_INV_ARG; } - ABTU_free(p_config); + return ABT_SUCCESS; } -static inline size_t sched_config_type_size(ABT_sched_config_type type) +static void sched_config_read_element(const sched_config_element *p_elem, + void *ptr) { - switch (type) { - case ABT_SCHED_CONFIG_INT: - return sizeof(int); - case ABT_SCHED_CONFIG_DOUBLE: - return sizeof(double); - case ABT_SCHED_CONFIG_PTR: - return sizeof(void *); + switch (p_elem->type) { + case ABT_SCHED_CONFIG_INT: { + *((int *)ptr) = p_elem->val.v_int; + break; + } + case ABT_SCHED_CONFIG_DOUBLE: { + *((double *)ptr) = p_elem->val.v_double; + break; + } + case ABT_SCHED_CONFIG_PTR: { + *((void **)ptr) = p_elem->val.v_ptr; + break; + } default: ABTI_ASSERT(0); - ABTU_unreachable(); } } From 7779ec0dc4ba932dbfb84db737470c017bc3e896 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 17:36:41 -0500 Subject: [PATCH 03/10] sched_config: rename files from config to sched_config The next commit will add ABT_pool_config, so "config" is confusing. This patch renames related code files. --- src/include/Makefile.mk | 2 +- src/include/abti.h | 2 +- src/include/{abti_config.h => abti_sched_config.h} | 8 ++++---- src/sched/Makefile.mk | 4 ++-- src/sched/{config.c => sched_config.c} | 0 5 files changed, 8 insertions(+), 8 deletions(-) rename src/include/{abti_config.h => abti_sched_config.h} (84%) rename src/sched/{config.c => sched_config.c} (100%) diff --git a/src/include/Makefile.mk b/src/include/Makefile.mk index 778305eb..45a1b6d9 100644 --- a/src/include/Makefile.mk +++ b/src/include/Makefile.mk @@ -17,7 +17,6 @@ noinst_HEADERS = \ include/abti.h \ include/abti_barrier.h \ include/abti_cond.h \ - include/abti_config.h \ include/abti_error.h \ include/abti_event.h \ include/abti_eventual.h \ @@ -33,6 +32,7 @@ noinst_HEADERS = \ include/abti_rwlock.h \ include/abti_pool.h \ include/abti_sched.h \ + include/abti_sched_config.h \ include/abti_self.h \ include/abti_stream.h \ include/abti_stream_barrier.h \ diff --git a/src/include/abti.h b/src/include/abti.h index 3a61f74b..3bbeda0a 100644 --- a/src/include/abti.h +++ b/src/include/abti.h @@ -628,7 +628,7 @@ void ABTI_info_check_print_all_thread_stacks(void); #include "abti_self.h" #include "abti_pool.h" #include "abti_sched.h" -#include "abti_config.h" +#include "abti_sched_config.h" #include "abti_stream.h" #include "abti_thread.h" #include "abti_unit.h" diff --git a/src/include/abti_config.h b/src/include/abti_sched_config.h similarity index 84% rename from src/include/abti_config.h rename to src/include/abti_sched_config.h index 85920200..38188495 100644 --- a/src/include/abti_config.h +++ b/src/include/abti_sched_config.h @@ -3,10 +3,10 @@ * See COPYRIGHT in top-level directory. */ -#ifndef ABTI_CONFIG_H_INCLUDED -#define ABTI_CONFIG_H_INCLUDED +#ifndef ABTI_SCHED_CONFIG_H_INCLUDED +#define ABTI_SCHED_CONFIG_H_INCLUDED -/* Inlined functions for Config */ +/* Inlined functions for scheduler config */ static inline ABTI_sched_config * ABTI_sched_config_get_ptr(ABT_sched_config config) @@ -40,4 +40,4 @@ ABTI_sched_config_get_handle(ABTI_sched_config *p_config) #endif } -#endif /* ABTI_CONFIG_H_INCLUDED */ +#endif /* ABTI_SCHED_CONFIG_H_INCLUDED */ diff --git a/src/sched/Makefile.mk b/src/sched/Makefile.mk index 02f08386..f87ab1f2 100644 --- a/src/sched/Makefile.mk +++ b/src/sched/Makefile.mk @@ -6,8 +6,8 @@ abt_sources += \ sched/basic.c \ sched/basic_wait.c \ - sched/config.c \ sched/prio.c \ + sched/randws.c \ sched/sched.c \ - sched/randws.c + sched/sched_config.c diff --git a/src/sched/config.c b/src/sched/sched_config.c similarity index 100% rename from src/sched/config.c rename to src/sched/sched_config.c From 7acd21b7bec33beadf8dbd91e781478b21b8d41a Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 17:54:45 -0500 Subject: [PATCH 04/10] pool_config: implement functions for ABT_pool_config This patch introduces ABT_pool_config, which can be used like ABT_sched_config. Its main functionality is "automatic" setting for a pool created by ABT_pool_create(), which will be added by the next commit. --- Doxyfile.in | 14 +- src/include/Makefile.mk | 1 + src/include/abt.h.in | 53 ++++++ src/include/abti.h | 6 + src/include/abti_error.h | 9 + src/include/abti_pool_config.h | 42 +++++ src/pool/Makefile.mk | 4 +- src/pool/pool_config.c | 335 +++++++++++++++++++++++++++++++++ 8 files changed, 461 insertions(+), 3 deletions(-) create mode 100644 src/include/abti_pool_config.h create mode 100644 src/pool/pool_config.c diff --git a/Doxyfile.in b/Doxyfile.in index 30441f93..665e6511 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1980,6 +1980,12 @@ ALIASES += DOC_ERROR_INV_ARG_INV_TOOL_QUERY_KIND{2}="\c ABT_ERR_INV_ARG is retur ALIASES += DOC_ERROR_INV_ARG_NEG{1}="\c ABT_ERR_INV_ARG is returned if \1 is negative.\n" +ALIASES += DOC_ERROR_INV_ARG_POOL_CONFIG_INDEX{2}="\c ABT_ERR_INV_ARG is returned if \1 does not have a value associated with \2.\n" + +ALIASES += DOC_ERROR_INV_ARG_POOL_CONFIG_TYPE="\c ABT_ERR_INV_ARG is returned if \c type of the given \c ABT_pool_config_var is invalid.\n" + +ALIASES += DOC_ERROR_INV_ARG_POOL_CONFIG_TYPE{1}="\c ABT_ERR_INV_ARG is returned if \1 is invalid.\n" + ALIASES += DOC_ERROR_INV_ARG_SCHED_CONFIG_INDEX{2}="\c ABT_ERR_INV_ARG is returned if \1 does not have a value associated with \2.\n" ALIASES += DOC_ERROR_INV_ARG_SCHED_CONFIG_TYPE="\c ABT_ERR_INV_ARG is returned if \c type of the given \c ABT_sched_config_var is invalid.\n" @@ -2022,6 +2028,10 @@ ALIASES += DOC_ERROR_INV_MUTEX_PTR{1}="\c ABT_ERR_INV_MUTEX is returned if \1 po ALIASES += DOC_ERROR_INV_POOL_ACCESS{1}="\c ABT_ERR_INV_POOL_ACCESS is returned if \1 is not a valid pool access type.\n" +ALIASES += DOC_ERROR_INV_POOL_CONFIG_HANDLE{1}="\c ABT_ERR_INV_POOL_CONFIG is returned if \1 is \c ABT_SCHED_POOL_NULL.\n" + +ALIASES += DOC_ERROR_INV_POOL_CONFIG_PTR{1}="\c ABT_ERR_INV_POOL_CONFIG is returned if \1 points to \c ABT_SCHED_POOL_NULL.\n" + ALIASES += DOC_ERROR_INV_POOL_HANDLE{1}="\c ABT_ERR_INV_POOL is returned if \1 is \c ABT_POOL_NULL.\n" ALIASES += DOC_ERROR_INV_POOL_KIND{1}="\c ABT_ERR_INV_POOL_KIND is returned if \1 is not a valid pool kind.\n" @@ -2162,7 +2172,9 @@ ALIASES += DOC_NOTE_DEFAULT_MUTEX_ATTRIBUTE="To check the details of the default ALIASES += DOC_NOTE_DEFAULT_POOL="To see the details of the default pool, please check \c ABT_pool_create()." -ALIASES += DOC_NOTE_DEFAULT_POOL_CONFIG="" +ALIASES += DOC_NOTE_DEFAULT_POOL_AUTOMATIC="To see the details of whether the pool is automatically freed or not, please check \c ABT_pool_create()." + +ALIASES += DOC_NOTE_DEFAULT_POOL_CONFIG=""To see the details of the default pool configuration, please check \c ABT_pool_config_create()." ALIASES += DOC_NOTE_DEFAULT_SCHED="To see the details of the default scheduler, please check \c ABT_sched_create()." diff --git a/src/include/Makefile.mk b/src/include/Makefile.mk index 45a1b6d9..1a2c6bc9 100644 --- a/src/include/Makefile.mk +++ b/src/include/Makefile.mk @@ -31,6 +31,7 @@ noinst_HEADERS = \ include/abti_mutex_attr.h \ include/abti_rwlock.h \ include/abti_pool.h \ + include/abti_pool_config.h \ include/abti_sched.h \ include/abti_sched_config.h \ include/abti_self.h \ diff --git a/src/include/abt.h.in b/src/include/abt.h.in index 3e0ddc70..076d0562 100644 --- a/src/include/abt.h.in +++ b/src/include/abt.h.in @@ -164,6 +164,11 @@ extern "C" { * @brief Error code: invalid pool access type. */ #define ABT_ERR_INV_POOL_ACCESS 14 +/** + * @ingroup ERROR_CODE + * @brief Error code: invalid pool configuration. + */ +#define ABT_ERR_INV_POOL_CONFIG 56 /** * @ingroup ERROR_CODE * @brief Error code: invalid work unit for scheduling. @@ -1400,6 +1405,46 @@ typedef struct { ABT_sched_get_migr_pool_fn get_migr_pool; } ABT_sched_def; +/** + * @ingroup POOL_CONFIG + * @brief A struct that sets and gets a pool configuration. + */ +typedef enum { + /** Parameter of type int */ + ABT_POOL_CONFIG_INT = 0, + /** Parameter of type double */ + ABT_POOL_CONFIG_DOUBLE = 1, + /** Parameter of type pointer */ + ABT_POOL_CONFIG_PTR = 2, +} ABT_pool_config_type; + +/** + * @ingroup POOL_CONFIG + * @brief A struct that sets and gets a pool configuration. + */ +typedef struct { + /** + * A key of a configuration variable. It must be non-negative as negative + * keys are reserved for the Argobots internal use. + */ + int key; + /** Type of a configuration variable. */ + ABT_pool_config_type type; +} ABT_pool_config_var; + +/** + * @ingroup POOL_CONFIG + * @var ABT_pool_config_automatic + * @brief Predefined ABT_pool_config_var to configure whether the pool is + * freed automatically or not. + * @hideinitializer + * + * Its type is int. If the value is non-zero, the pool is freed automatically + * after its associated objects are released. If the value is zero, the pool is + * configured to be not freed automatically by the Argobots runtime. + */ +extern const ABT_pool_config_var ABT_pool_config_automatic ABT_API_PUBLIC; + /* Pool Functions */ typedef ABT_unit_type (*ABT_unit_get_type_fn)(ABT_unit); typedef ABT_thread (*ABT_unit_get_thread_fn)(ABT_unit); @@ -1782,6 +1827,14 @@ int ABT_pool_get_data(ABT_pool pool, void **data) ABT_API_PUBLIC; int ABT_pool_add_sched(ABT_pool pool, ABT_sched sched) ABT_API_PUBLIC; int ABT_pool_get_id(ABT_pool pool, int *id) ABT_API_PUBLIC; +/* Pool config */ +int ABT_pool_config_create(ABT_pool_config *config) ABT_API_PUBLIC; +int ABT_pool_config_free(ABT_pool_config *config) ABT_API_PUBLIC; +int ABT_pool_config_set(ABT_pool_config config, int key, ABT_pool_config_type type, + const void *val) ABT_API_PUBLIC; +int ABT_pool_config_get(ABT_pool_config config, int key, + ABT_pool_config_type *p_type, void *val) ABT_API_PUBLIC; + /* Work Unit */ int ABT_unit_get_thread(ABT_unit unit, ABT_thread *thread) ABT_API_PUBLIC; int ABT_unit_set_associated_pool(ABT_unit unit, ABT_pool pool) ABT_API_PUBLIC; diff --git a/src/include/abti.h b/src/include/abti.h index 3bbeda0a..f01d0055 100644 --- a/src/include/abti.h +++ b/src/include/abti.h @@ -119,6 +119,7 @@ typedef void *ABTI_sched_id; /* Scheduler id */ typedef uintptr_t ABTI_sched_kind; /* Scheduler kind */ typedef struct ABTI_pool ABTI_pool; typedef struct ABTI_pool_def ABTI_pool_def; +typedef struct ABTI_pool_config ABTI_pool_config; typedef struct ABTI_thread ABTI_thread; typedef struct ABTI_thread_attr ABTI_thread_attr; typedef struct ABTI_ythread ABTI_ythread; @@ -363,6 +364,10 @@ struct ABTI_pool_def { ABT_pool_print_all_fn p_print_all; }; +struct ABTI_pool_config { + ABTU_hashtable *p_table; +}; + struct ABTI_thread { ABTI_thread *p_prev; ABTI_thread *p_next; @@ -627,6 +632,7 @@ void ABTI_info_check_print_all_thread_stacks(void); #include "abti_global.h" #include "abti_self.h" #include "abti_pool.h" +#include "abti_pool_config.h" #include "abti_sched.h" #include "abti_sched_config.h" #include "abti_stream.h" diff --git a/src/include/abti_error.h b/src/include/abti_error.h index 5c3b4736..6aa468bd 100644 --- a/src/include/abti_error.h +++ b/src/include/abti_error.h @@ -190,6 +190,15 @@ } \ } while (0) +#define ABTI_CHECK_NULL_POOL_CONFIG_PTR(p) \ + do { \ + if (ABTI_IS_ERROR_CHECK_ENABLED && \ + ABTU_unlikely(p == (ABTI_pool_config *)NULL)) { \ + HANDLE_ERROR_FUNC_WITH_CODE(ABT_ERR_INV_POOL_CONFIG); \ + return ABT_ERR_INV_POOL_CONFIG; \ + } \ + } while (0) + #define ABTI_CHECK_NULL_SCHED_PTR(p) \ do { \ if (ABTI_IS_ERROR_CHECK_ENABLED && \ diff --git a/src/include/abti_pool_config.h b/src/include/abti_pool_config.h new file mode 100644 index 00000000..50bbb532 --- /dev/null +++ b/src/include/abti_pool_config.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ +/* + * See COPYRIGHT in top-level directory. + */ + +#ifndef ABTI_POOL_CONFIG_H_INCLUDED +#define ABTI_POOL_CONFIG_H_INCLUDED + +/* Inlined functions for pool config */ + +static inline ABTI_pool_config *ABTI_pool_config_get_ptr(ABT_pool_config config) +{ +#ifndef ABT_CONFIG_DISABLE_ERROR_CHECK + ABTI_pool_config *p_config; + if (config == ABT_POOL_CONFIG_NULL) { + p_config = NULL; + } else { + p_config = (ABTI_pool_config *)config; + } + return p_config; +#else + return (ABTI_pool_config *)config; +#endif +} + +static inline ABT_pool_config +ABTI_pool_config_get_handle(ABTI_pool_config *p_config) +{ +#ifndef ABT_CONFIG_DISABLE_ERROR_CHECK + ABT_pool_config h_config; + if (p_config == NULL) { + h_config = ABT_POOL_CONFIG_NULL; + } else { + h_config = (ABT_pool_config)p_config; + } + return h_config; +#else + return (ABT_pool_config)p_config; +#endif +} + +#endif /* ABTI_POOL_CONFIG_H_INCLUDED */ diff --git a/src/pool/Makefile.mk b/src/pool/Makefile.mk index ac5371af..5e36bb9b 100644 --- a/src/pool/Makefile.mk +++ b/src/pool/Makefile.mk @@ -6,5 +6,5 @@ abt_sources += \ pool/fifo.c \ pool/fifo_wait.c \ - pool/pool.c - + pool/pool.c \ + pool/pool_config.c diff --git a/src/pool/pool_config.c b/src/pool/pool_config.c new file mode 100644 index 00000000..70685917 --- /dev/null +++ b/src/pool/pool_config.c @@ -0,0 +1,335 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ +/* + * See COPYRIGHT in top-level directory. + */ + +#include "abti.h" + +#include +#include +#include + +#define POOL_CONFIG_HTABLE_SIZE 8 +typedef struct { + ABT_pool_config_type type; /* Element type. */ + union { + int v_int; + double v_double; + void *v_ptr; + } val; +} pool_config_element; + +static void pool_config_create_element_int(pool_config_element *p_elem, + int val); +static void pool_config_create_element_double(pool_config_element *p_elem, + double val); +static void pool_config_create_element_ptr(pool_config_element *p_elem, + void *ptr); +ABTU_ret_err static int +pool_config_create_element_typed(pool_config_element *p_elem, + ABT_pool_config_type type, const void *p_val); +static void pool_config_read_element(const pool_config_element *p_elem, + void *ptr); + +/** @defgroup POOL_CONFIG Pool config + * This group is for Pool config. + */ + +/* Global configurable parameters */ +const ABT_pool_config_var ABT_pool_config_automatic = { + .key = -2, .type = ABT_POOL_CONFIG_INT +}; + +/** + * @ingroup POOL_CONFIG + * @brief Create a new pool configuration. + * + * \c ABT_pool_config_create() creates a new empty pool configuration and + * returns its handle through \c config. + * + * Currently, Argobots supports the following hints: + * + * - \c ABT_pool_config_automatic: + * + * Whether the pool is automatically freed or not. If the value is + * \c ABT_TRUE, the pool is automatically freed when all schedulers associated + * with the pool are freed. If this hint is not specified, the default value + * of each pool creation routine is used for pool creation. + * + * @note + * \DOC_NOTE_DEFAULT_POOL_AUTOMATIC + * + * \c config must be freed by \c ABT_pool_config_free() after its use. + * + * @contexts + * \DOC_CONTEXT_INIT \DOC_CONTEXT_NOCTXSWITCH + * + * @errors + * \DOC_ERROR_SUCCESS + * \DOC_ERROR_INV_ARG_POOL_CONFIG_TYPE + * \DOC_ERROR_RESOURCE + * + * @undefined + * \DOC_UNDEFINED_UNINIT + * \DOC_UNDEFINED_NULL_PTR{\c config} + * + * @param[out] config pool configuration handle + * @return Error code + */ +int ABT_pool_config_create(ABT_pool_config *config) +{ + ABTI_UB_ASSERT(ABTI_initialized()); + + int abt_errno; + ABTI_pool_config *p_config; + + abt_errno = ABTU_calloc(1, sizeof(ABTI_pool_config), (void **)&p_config); + ABTI_CHECK_ERROR(abt_errno); + abt_errno = + ABTU_hashtable_create(POOL_CONFIG_HTABLE_SIZE, + sizeof(pool_config_element), &p_config->p_table); + if (abt_errno != ABT_SUCCESS) { + ABTU_free(p_config); + ABTI_HANDLE_ERROR(abt_errno); + } + + *config = ABTI_pool_config_get_handle(p_config); + return ABT_SUCCESS; +} + +/** + * @ingroup POOL_CONFIG + * @brief Free a pool configuration. + * + * \c ABT_pool_config_free() deallocates the resource used for the pool + * configuration \c pool_config and sets \c pool_config to + * \c ABT_POOL_CONFIG_NULL. + * + * @contexts + * \DOC_CONTEXT_INIT \DOC_CONTEXT_NOCTXSWITCH + * + * @errors + * \DOC_ERROR_SUCCESS + * \DOC_ERROR_INV_POOL_CONFIG_PTR{\c config} + * + * @undefined + * \DOC_UNDEFINED_UNINIT + * \DOC_UNDEFINED_NULL_PTR{\c config} + * \DOC_UNDEFINED_THREAD_UNSAFE_FREE{\c config} + * + * @param[in,out] config pool configuration handle + * @return Error code + */ +int ABT_pool_config_free(ABT_pool_config *config) +{ + ABTI_UB_ASSERT(ABTI_initialized()); + ABTI_UB_ASSERT(config); + + ABTI_pool_config *p_config = ABTI_pool_config_get_ptr(*config); + ABTI_CHECK_NULL_POOL_CONFIG_PTR(p_config); + + ABTU_hashtable_free(p_config->p_table); + ABTU_free(p_config); + + *config = ABT_POOL_CONFIG_NULL; + + return ABT_SUCCESS; +} + +/** + * @ingroup POOL_CONFIG + * @brief Register a value to a pool configuration. + * + * \c ABT_pool_config_set() associated a value pointed to by the value \c val + * with the index \c key in the pool configuration \c config. This routine + * overwrites a value and its type if a value has already been associated with + * \c key. + * + * @note + * For example, this routine can be called as follows to set a value that is + * corresponding to \c key = \a 1. + * @code{.c} + * const ABT_pool_config_var var = { 1, ABT_POOL_CONFIG_INT }; + * int val = 10; + * ABT_pool_config_set(&config, var.key, var.type, &val); + * @endcode + * + * If \c value is \c NULL, this routine deletes a value associated with \c key + * if such exists. + * + * @note + * This routine returns \c ABT_SUCCESS even if \c value is \c NULL but no value + * is associated with \c key. + * + * @contexts + * \DOC_CONTEXT_INIT \DOC_CONTEXT_NOCTXSWITCH + * + * @errors + * \DOC_ERROR_SUCCESS + * \DOC_ERROR_INV_ARG_POOL_CONFIG_TYPE{\c type} + * \DOC_ERROR_INV_POOL_CONFIG_HANDLE{\c config} + * \DOC_ERROR_RESOURCE + * + * @undefined + * \DOC_UNDEFINED_UNINIT + * \DOC_UNDEFINED_THREAD_UNSAFE{\c config} + * + * @param[in] config pool configuration handle + * @param[in] key index of a target value + * @param[in] type type of a target value + * @param[in] val target value + * @return Error code + */ +int ABT_pool_config_set(ABT_pool_config config, int key, + ABT_pool_config_type type, const void *val) +{ + ABTI_UB_ASSERT(ABTI_initialized()); + + ABTI_pool_config *p_config = ABTI_pool_config_get_ptr(config); + ABTI_CHECK_NULL_POOL_CONFIG_PTR(p_config); + if (val) { + /* Add a value. */ + pool_config_element data; + int abt_errno; + abt_errno = pool_config_create_element_typed(&data, type, val); + ABTI_CHECK_ERROR(abt_errno); + abt_errno = ABTU_hashtable_set(p_config->p_table, key, &data, NULL); + ABTI_CHECK_ERROR(abt_errno); + } else { + /* Delete a value. */ + ABTU_hashtable_delete(p_config->p_table, key, NULL); + } + return ABT_SUCCESS; +} + +/** + * @ingroup POOL_CONFIG + * @brief Retrieve a value from a pool configuration. + * + * \c ABT_pool_config_get() reads a value associated with the index \c key of + * \c ABT_pool_config_var from the pool configuration \c config. If \c val is + * not \c NULL, \c val is set to the value. If \c type is not \c NULL, \c type + * is set to the type of the value. + * + * @note + * For example, this routine can be called as follows to get a value that is + * corresponding to \c key = \a 1. + * @code{.c} + * const ABT_pool_config_var var = { 1, ABT_POOL_CONFIG_INT }; + * int val; + * ABT_pool_config_type type; + * ABT_pool_config_get(&config, var.key, &type, &val); + * assert(type == var.type); + * @endcode + * + * @contexts + * \DOC_CONTEXT_INIT \DOC_CONTEXT_NOCTXSWITCH + * + * @errors + * \DOC_ERROR_SUCCESS + * \DOC_ERROR_INV_ARG_POOL_CONFIG_INDEX{\c config, \c key} + * \DOC_ERROR_INV_POOL_CONFIG_HANDLE{\c config} + * + * @undefined + * \DOC_UNDEFINED_UNINIT + * \DOC_UNDEFINED_THREAD_UNSAFE{\c config} + * + * @param[in] config pool configuration handle + * @param[in] key index of a target value + * @param[out] type type of a target value + * @param[out] val target value + * @return Error code + */ +int ABT_pool_config_get(ABT_pool_config config, int key, + ABT_pool_config_type *type, void *val) +{ + ABTI_UB_ASSERT(ABTI_initialized()); + + ABTI_pool_config *p_config = ABTI_pool_config_get_ptr(config); + ABTI_CHECK_NULL_POOL_CONFIG_PTR(p_config); + pool_config_element data; + int found; + ABTU_hashtable_get(p_config->p_table, key, &data, &found); + if (found) { + if (val) { + pool_config_read_element(&data, val); + } + if (type) { + *type = data.type; + } + } else { + ABTI_HANDLE_ERROR(ABT_ERR_INV_ARG); + } + return ABT_SUCCESS; +} + +/*****************************************************************************/ +/* Internal static functions */ +/*****************************************************************************/ + +static void pool_config_create_element_int(pool_config_element *p_elem, int val) +{ + memset(p_elem, 0, sizeof(pool_config_element)); + p_elem->type = ABT_POOL_CONFIG_INT; + p_elem->val.v_int = val; +} + +static void pool_config_create_element_double(pool_config_element *p_elem, + double val) +{ + memset(p_elem, 0, sizeof(pool_config_element)); + p_elem->type = ABT_POOL_CONFIG_DOUBLE; + p_elem->val.v_double = val; +} + +static void pool_config_create_element_ptr(pool_config_element *p_elem, + void *ptr) +{ + memset(p_elem, 0, sizeof(pool_config_element)); + p_elem->type = ABT_POOL_CONFIG_PTR; + p_elem->val.v_ptr = ptr; +} + +ABTU_ret_err static int +pool_config_create_element_typed(pool_config_element *p_elem, + ABT_pool_config_type type, const void *p_val) +{ + switch (type) { + case ABT_POOL_CONFIG_INT: { + pool_config_create_element_int(p_elem, *(const int *)p_val); + break; + } + case ABT_POOL_CONFIG_DOUBLE: { + pool_config_create_element_double(p_elem, *(const double *)p_val); + break; + } + case ABT_POOL_CONFIG_PTR: { + pool_config_create_element_ptr(p_elem, *(void *const *)p_val); + break; + } + default: + return ABT_ERR_INV_ARG; + } + return ABT_SUCCESS; +} + +static void pool_config_read_element(const pool_config_element *p_elem, + void *ptr) +{ + switch (p_elem->type) { + case ABT_POOL_CONFIG_INT: { + *((int *)ptr) = p_elem->val.v_int; + break; + } + case ABT_POOL_CONFIG_DOUBLE: { + *((double *)ptr) = p_elem->val.v_double; + break; + } + case ABT_POOL_CONFIG_PTR: { + *((void **)ptr) = p_elem->val.v_ptr; + break; + } + default: + ABTI_ASSERT(0); + } +} From 3f1992a11f25baf97994a5c1afe482ab581cf7b4 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 18:37:09 -0500 Subject: [PATCH 05/10] pool: reflect ABT_pool_config in ABT_pool_create The user could not create an automatically freed pool by ABT_pool_create() (i.e., a function to create a user-defined pool). This patch updates ABT_pool_create() so that it reads configuration (including "automatic") from ABT_pool_config and reflects it. --- Doxyfile.in | 4 ++- src/include/abti.h | 4 +++ src/pool/pool.c | 55 ++++++++++++++++++++++++++++-------------- src/pool/pool_config.c | 20 +++++++++++++++ 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 665e6511..c58162f5 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1870,7 +1870,9 @@ ALIASES += DOC_DESC_ATOMICITY_XSTREAM_REQUEST="Requests for execution streams ar ALIASES += DOC_DESC_ATOMICITY_XSTREAM_STATE="Management of states of execution streams is performed atomically." -ALIASES += DOC_DESC_SCHED_AUTOMATIC{1}="If \1 is not configured to be automatically freed, it is the user's responsibility to free \1 after its use unless \c newsched is associated with the main scheduler of the primary execution stream. If \1 is configured to be automatically freed, \1 is automatically freed when a work unit associated with \1 is freed. If the user never associates \1 with a work unit (e.g., by \c ABT_pool_add_sched() or \c ABT_xstream_set_main_sched()), it is the user's responsibility to free \1." +ALIASES += DOC_DESC_POOL_AUTOMATIC{1}="If \1 is not configured to be automatically freed, it is the user's responsibility to free \1 after its use unless \c 1 is associated with the main scheduler of the primary execution stream. If \1 is configured to be automatically freed, \1 is automatically freed when all schedulers associated with \1 is freed. If the user never associates \1 with a scheduler (e.g., by \c ABT_sched_create()), it is the user's responsibility to free \1." + +ALIASES += DOC_DESC_SCHED_AUTOMATIC{1}="If \1 is not configured to be automatically freed, it is the user's responsibility to free \1 after its use unless \c 1 is associated with the main scheduler of the primary execution stream. If \1 is configured to be automatically freed, \1 is automatically freed when a work unit associated with \1 is freed. If the user never associates \1 with a work unit (e.g., by \c ABT_pool_add_sched() or \c ABT_xstream_set_main_sched()), it is the user's responsibility to free \1." ALIASES += DOC_DESC_TIMER_RESOLUTION="The resolution of elapsed time depends on the clock resolution of the system." diff --git a/src/include/abti.h b/src/include/abti.h index f01d0055..819587a6 100644 --- a/src/include/abti.h +++ b/src/include/abti.h @@ -558,6 +558,10 @@ ABTU_ret_err int ABTI_pool_get_fifo_wait_def(ABT_pool_access access, void ABTI_pool_print(ABTI_pool *p_pool, FILE *p_os, int indent); void ABTI_pool_reset_id(void); +/* Pool config */ +ABTU_ret_err int ABTI_pool_config_read(const ABTI_pool_config *p_config, + int key, void *p_val); + /* Work Unit */ void ABTI_unit_init_hash_table(ABTI_global *p_global); void ABTI_unit_finalize_hash_table(ABTI_global *p_global); diff --git a/src/pool/pool.c b/src/pool/pool.c index 9266a268..4db2e658 100644 --- a/src/pool/pool.c +++ b/src/pool/pool.c @@ -5,8 +5,9 @@ #include "abti.h" -ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, - ABT_bool automatic, ABT_bool is_builtin, +ABTU_ret_err static int pool_create(ABTI_pool_def *def, + ABTI_pool_config *p_config, + ABT_bool def_automatic, ABT_bool is_builtin, ABTI_pool **pp_newpool); /** @defgroup POOL Pool @@ -19,13 +20,7 @@ ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, * * \c ABT_pool_create() creates a new pool, given by the pool definition * (\c def) and a pool configuration (\c config), and returns its handle through - * \c newpool. If \c p_init is not \c NULL, this routine calls \c p_init() with - * \c newpool as the first argument and \c config as the second argument. This - * routine returns an error returned by \c p_init() if \c p_init() does not - * return \c ABT_SUCCESS. - * - * \c config is passed as the second argument of the initialization function of - * the pool. + * \c newpool. * * \c def must define all the non-optional functions. See \c #ABT_pool_def for * details. @@ -37,12 +32,21 @@ ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, * Specifically, any explicit or implicit context-switching operation in a pool * function may cause undefined behavior. * + * \c newpool can be configured via \c config. If the user passes + * \c ABT_POOL_CONFIG_NULL for \c config, the default configuration is used. + * If \c p_init is not \c NULL, this routine calls \c p_init() with + * \c newpool as the first argument and \c config as the second argument. This + * routine returns an error returned by \c p_init() if \c p_init() does not + * return \c ABT_SUCCESS. + * + * @note + * \DOC_NOTE_DEFAULT_POOL_CONFIG + * * This routine copies \c def and \c config, so the user can free \c def and * \c config after this routine returns. * - * The created pool is not automatically freed, so \c newpool must be freed by - * \c ABT_pool_free() after its use unless \c newpool is associated with the - * main scheduler of the primary execution stream. + * \DOC_DESC_POOL_AUTOMATIC{\c newpool} By default \c newpool created by this + * routine is not automatically freed. * * @note * \DOC_NOTE_EFFECT_ABT_FINALIZE @@ -108,8 +112,10 @@ int ABT_pool_create(ABT_pool_def *def, ABT_pool_config config, internal_def.p_print_all = def->p_print_all; ABTI_pool *p_newpool; - int abt_errno = - pool_create(&internal_def, config, ABT_FALSE, ABT_FALSE, &p_newpool); + ABTI_pool_config *p_config = ABTI_pool_config_get_ptr(config); + const ABT_bool def_automatic = ABT_FALSE; + int abt_errno = pool_create(&internal_def, p_config, def_automatic, + ABT_FALSE, &p_newpool); ABTI_CHECK_ERROR(abt_errno); *newpool = ABTI_pool_get_handle(p_newpool); @@ -935,8 +941,7 @@ ABTU_ret_err int ABTI_pool_create_basic(ABT_pool_kind kind, } ABTI_CHECK_ERROR(abt_errno); - abt_errno = pool_create(&def, ABT_POOL_CONFIG_NULL, automatic, ABT_TRUE, - pp_newpool); + abt_errno = pool_create(&def, NULL, automatic, ABT_TRUE, pp_newpool); ABTI_CHECK_ERROR(abt_errno); return ABT_SUCCESS; } @@ -1009,8 +1014,9 @@ void ABTI_pool_reset_id(void) /*****************************************************************************/ static inline uint64_t pool_get_new_id(void); -ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, - ABT_bool automatic, ABT_bool is_builtin, +ABTU_ret_err static int pool_create(ABTI_pool_def *def, + ABTI_pool_config *p_config, + ABT_bool def_automatic, ABT_bool is_builtin, ABTI_pool **pp_newpool) { int abt_errno; @@ -1018,6 +1024,18 @@ ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, abt_errno = ABTU_malloc(sizeof(ABTI_pool), (void **)&p_pool); ABTI_CHECK_ERROR(abt_errno); + /* Read the config and set the configured parameter */ + ABT_bool automatic = def_automatic; + if (p_config) { + int automatic_val = 0; + abt_errno = + ABTI_pool_config_read(p_config, ABT_pool_config_automatic.key, + &automatic_val); + if (abt_errno == ABT_SUCCESS) { + automatic = (automatic_val == 0) ? ABT_FALSE : ABT_TRUE; + } + } + p_pool->access = def->access; p_pool->automatic = automatic; p_pool->is_builtin = is_builtin; @@ -1042,6 +1060,7 @@ ABTU_ret_err static int pool_create(ABTI_pool_def *def, ABT_pool_config config, /* Configure the pool */ if (p_pool->p_init) { + ABT_pool_config config = ABTI_pool_config_get_handle(p_config); abt_errno = p_pool->p_init(ABTI_pool_get_handle(p_pool), config); if (abt_errno != ABT_SUCCESS) { ABTU_free(p_pool); diff --git a/src/pool/pool_config.c b/src/pool/pool_config.c index 70685917..423a5f5b 100644 --- a/src/pool/pool_config.c +++ b/src/pool/pool_config.c @@ -263,6 +263,26 @@ int ABT_pool_config_get(ABT_pool_config config, int key, return ABT_SUCCESS; } +/*****************************************************************************/ +/* Private APIs */ +/*****************************************************************************/ + +ABTU_ret_err int ABTI_pool_config_read(const ABTI_pool_config *p_config, + int key, void *p_val) +{ + int found; + pool_config_element data; + ABTU_hashtable_get(p_config->p_table, key, &data, &found); + if (found) { + if (p_val) { + pool_config_read_element(&data, p_val); + } + return ABT_SUCCESS; + } else { + return ABT_ERR_INV_ARG; + } +} + /*****************************************************************************/ /* Internal static functions */ /*****************************************************************************/ From 642327af19a25394c027e8f78b4e10d65e67ef95 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 22:50:38 -0500 Subject: [PATCH 06/10] error: support ABT_ERR_INV_POOL_CONFIG ABT_ERR_INV_POOL_CONFIG is a new error code. This patch updates ABT_error_get_str() to support this new error code. --- src/error.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/error.c b/src/error.c index 3c64a20c..a14acd44 100644 --- a/src/error.c +++ b/src/error.c @@ -105,7 +105,8 @@ int ABT_error_get_str(int err, char *str, size_t *len) "ABT_ERR_INV_TOOL_CONTEXT", "ABT_ERR_INV_ARG", "ABT_ERR_SYS", - "ABT_ERR_CPUID" }; + "ABT_ERR_CPUID", + "ABT_ERR_INV_POOL_CONFIG" }; #ifndef ABT_CONFIG_ENABLE_VER_20_API ABTI_CHECK_TRUE(err >= ABT_SUCCESS && From 4abaa12415425ccefbf0756a25237514380abc92 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 22:56:25 -0500 Subject: [PATCH 07/10] xstream: fix ABT_xstream_set_main_sched_basic in an error case If ABT_xstream_set_main_sched_basic() takes automatically freed pools but it failed after scheduler creation (i.e., on setting the main scheduler because of memory allocation failure in, for example, ABTI_thread_set_associated_pool()), the user-given automatically freed pools are freed when the scheduler is freed. They should be kept alive in such a case. This patch fixes it. --- src/stream.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/stream.c b/src/stream.c index 6f2fe548..b9e50086 100644 --- a/src/stream.c +++ b/src/stream.c @@ -930,20 +930,16 @@ int ABT_xstream_set_main_sched(ABT_xstream xstream, ABT_sched sched) * * \c ABT_xstream_set_main_sched() sets the predefined scheduler \c predefined * as the main scheduler of the execution stream \c xstream. The functionality - * provided by this routine is the same as the combination of + * provided by this routine when it succeeds is the same as the combination of * \c ABT_sched_create_basic() and \c ABT_xstream_set_main_sched(). * * @code{.c} * int ABT_xstream_set_main_sched_basic(...) { - * int abt_errno; - * ABT_sched sched = ABT_SCHED_NULL; - * abt_errno = ABT_sched_create_basic(predef, num_pools, pools, - * ABT_SCHED_CONFIG_NULL, sched); - * if (abt_errno == ABT_SUCCESS) - * abt_errno = ABT_xstream_set_main_sched(xstream, sched); - * if (abt_errno != ABT_SUCCESS && sched != ABT_SCHED_NULL) - * ABT_sched_free(&sched); - * return abt_errno; + * ABT_sched sched; + * ABT_sched_create_basic(predef, num_pools, pools, ABT_SCHED_CONFIG_NULL, + * &sched); + * ABT_xstream_set_main_sched(xstream, sched); + * return ABT_SUCCESS; * } * @endcode * @@ -1005,6 +1001,14 @@ int ABT_xstream_set_main_sched_basic(ABT_xstream xstream, abt_errno = xstream_update_main_sched(p_global, &p_local_xstream, p_xstream, p_sched); if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { + int i; + for (i = 0; i < num_pools; i++) { + if (pools[i] != ABT_POOL_NULL) { + /* Avoid freeing user-given pools. */ + ABTI_pool_release(ABTI_pool_get_ptr(p_sched->pools[i])); + p_sched->pools[i] = ABT_POOL_NULL; + } + } ABTI_sched_free(p_global, ABTI_local_get_local_uninlined(), p_sched, ABT_FALSE); ABTI_HANDLE_ERROR(abt_errno); From 4bc26670e521f77b5b4518ba9ca575efc09158cb Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 22:58:10 -0500 Subject: [PATCH 08/10] test/basic: create a test to check ABT_pool_config related functions --- test/.gitignore | 1 + test/basic/Makefile.am | 3 + test/basic/pool_config.c | 153 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 test/basic/pool_config.c diff --git a/test/.gitignore b/test/.gitignore index 7da67daf..37e2d18e 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -42,6 +42,7 @@ basic/sched_set_main basic/sched_stack basic/sched_config basic/sched_user_ws +basic/pool_config basic/pool_custom basic/sync_no_contention basic/main_sched diff --git a/test/basic/Makefile.am b/test/basic/Makefile.am index 7f7b7ac7..cd905a96 100644 --- a/test/basic/Makefile.am +++ b/test/basic/Makefile.am @@ -47,6 +47,7 @@ TESTS = \ sched_stack \ sched_config \ sched_user_ws \ + pool_config \ pool_custom \ sync_no_contention \ main_sched \ @@ -151,6 +152,7 @@ sched_set_main_SOURCES = sched_set_main.c sched_stack_SOURCES = sched_stack.c sched_config_SOURCES = sched_config.c sched_user_ws_SOURCES = sched_user_ws.c +pool_config_SOURCES = pool_config.c pool_custom_SOURCES = pool_custom.c sync_no_contention_SOURCES = sync_no_contention.c main_sched_SOURCES = main_sched.c @@ -241,6 +243,7 @@ testing: ./sched_stack ./sched_config ./sched_user_ws + ./pool_config ./pool_custom ./sync_no_contention ./main_sched diff --git a/test/basic/pool_config.c b/test/basic/pool_config.c new file mode 100644 index 00000000..4a34fd11 --- /dev/null +++ b/test/basic/pool_config.c @@ -0,0 +1,153 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ +/* + * See COPYRIGHT in top-level directory. + */ + +#include +#include "abt.h" +#include "abttest.h" + +ABT_pool_config_var param_a = { .key = 0, .type = ABT_POOL_CONFIG_INT }; +ABT_pool_config_var param_b = { .key = 1, .type = ABT_POOL_CONFIG_DOUBLE }; +ABT_bool g_check_error; + +void check_val(ABT_pool_config config, const int *ans_a, const double *ans_b) +{ + int ret; + if (g_check_error || ans_a) { + /* Check ABT_pool_config_get for param_a. */ + int val_a = 1; + ABT_pool_config_type type = (ABT_pool_config_type)77; + ret = ABT_pool_config_get(config, param_a.key, &type, &val_a); + if (ans_a) { + ATS_ERROR(ret, "ABT_pool_config_get"); + assert(val_a == *ans_a && type == param_a.type); + ret = ABT_pool_config_get(config, param_a.key, NULL, NULL); + ATS_ERROR(ret, "ABT_pool_config_get"); + } else { + assert(ret != ABT_SUCCESS && val_a == 1 && + type == (ABT_pool_config_type)77); + } + } + if (g_check_error || ans_b) { + /* Check ABT_pool_config_get for param_b. */ + double val_b = 1; + ABT_pool_config_type type = (ABT_pool_config_type)77; + ret = ABT_pool_config_get(config, param_b.key, &type, &val_b); + if (ans_b) { + ATS_ERROR(ret, "ABT_pool_config_get"); + assert(val_b == *ans_b && type == param_b.type); + ret = ABT_pool_config_get(config, param_b.key, NULL, NULL); + ATS_ERROR(ret, "ABT_pool_config_get"); + } else { + assert(ret != ABT_SUCCESS && val_b == 1 && + type == (ABT_pool_config_type)77); + } + } +} + +int main(int argc, char *argv[]) +{ + const int a = 5, a2 = 8; + int ret, i, param_b_key; + const double b = 3.0, b2 = 7.0; + ABT_pool_config config; + + /* Initialize */ + ATS_read_args(argc, argv); + ATS_init(argc, argv, 1); + + ret = ABT_info_query_config(ABT_INFO_QUERY_KIND_ENABLED_CHECK_ERROR, + (void *)&g_check_error); + ATS_ERROR(ret, "ABT_info_query_config"); + + for (param_b_key = 1; param_b_key <= 9; param_b_key++) { + /* Change param_b.key to check the internal hash table implementation. + */ + param_b.key = param_b_key; + + /* {x, x} */ + ret = ABT_pool_config_create(&config); + ATS_ERROR(ret, "ABT_pool_config_create"); + check_val(config, NULL, NULL); + + /* {x, x} -> {a, x} */ + ret = ABT_pool_config_set(config, param_a.key, param_a.type, &a); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a, NULL); + + /* {a, x} -> {a2, x} */ + ret = ABT_pool_config_set(config, param_a.key, param_a.type, &a2); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a2, NULL); + + /* {a2, x} -> {a2, b} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a2, &b); + + /* {a2, x} -> {a2, b2} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b2); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a2, &b2); + + /* {a2, b2} -> {x, b2} */ + ret = ABT_pool_config_set(config, param_a.key, param_a.type, NULL); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, &b2); + + /* {x, b2} -> {x, b2} */ + ret = ABT_pool_config_set(config, param_a.key, param_a.type, NULL); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, &b2); + + /* {x, b2} -> {a, b2} */ + ret = ABT_pool_config_set(config, param_a.key, param_a.type, &a); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a, &b2); + + /* {a, b2} -> {a, b} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a, &b); + + /* {a, b} -> {a, x} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, NULL); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, &a, NULL); + + ret = ABT_pool_config_free(&config); + ATS_ERROR(ret, "ABT_pool_config_free"); + + /* {x, x} */ + ret = ABT_pool_config_create(&config); + ATS_ERROR(ret, "ABT_pool_config_create"); + check_val(config, NULL, NULL); + + for (i = 0; i < 10; i++) { + /* {x, x} -> {x, b} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, &b); + + /* {x, b} -> {x, b2} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b2); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, &b2); + + /* {x, b2} -> {x, b} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, &b); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, &b); + + /* {x, b} -> {x, x} */ + ret = ABT_pool_config_set(config, param_b.key, param_b.type, NULL); + ATS_ERROR(ret, "ABT_pool_config_set"); + check_val(config, NULL, NULL); + } + ret = ABT_pool_config_free(&config); + ATS_ERROR(ret, "ABT_pool_config_free"); + } + /* Finalize */ + return ATS_finalize(0); +} From 7c4a37a8de9eeb0e2dc81ecf99665869a991bd24 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 22:58:28 -0500 Subject: [PATCH 09/10] test/basic: update error.c to check ABT_ERR_INV_POOL_CONFIG --- test/basic/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/basic/error.c b/test/basic/error.c index 1e44291f..35a48749 100644 --- a/test/basic/error.c +++ b/test/basic/error.c @@ -37,6 +37,7 @@ int main(int argc, char *argv[]) { "ABT_ERR_INV_POOL", ABT_ERR_INV_POOL }, { "ABT_ERR_INV_POOL_KIND", ABT_ERR_INV_POOL_KIND }, { "ABT_ERR_INV_POOL_ACCESS", ABT_ERR_INV_POOL_ACCESS }, + { "ABT_ERR_INV_POOL_CONFIG", ABT_ERR_INV_POOL_CONFIG }, { "ABT_ERR_INV_UNIT", ABT_ERR_INV_UNIT }, { "ABT_ERR_INV_THREAD", ABT_ERR_INV_THREAD }, { "ABT_ERR_INV_THREAD_ATTR", ABT_ERR_INV_THREAD_ATTR }, From 117bbf307c1d8bccbba4de6f4d97bb4255046880 Mon Sep 17 00:00:00 2001 From: Shintaro Iwasaki Date: Sat, 17 Jul 2021 22:59:11 -0500 Subject: [PATCH 10/10] test/leakcheck: extend pool.c to cover automatic user-defined pool --- test/leakcheck/pool.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/test/leakcheck/pool.c b/test/leakcheck/pool.c index a2a36f5e..14307a41 100644 --- a/test/leakcheck/pool.c +++ b/test/leakcheck/pool.c @@ -81,11 +81,6 @@ int pool_free(ABT_pool pool) ABT_pool create_pool(int automatic, int must_succeed) { - if (automatic) { - /* Currently there's no way to create an automatic pool using - * ABT_pool_create(). */ - return ABT_POOL_NULL; - } int ret; ABT_pool pool = (ABT_pool)RAND_PTR; @@ -110,7 +105,31 @@ ABT_pool create_pool(int automatic, int must_succeed) pool_def.p_free = pool_free; pool_def.p_print_all = NULL; - ret = ABT_pool_create(&pool_def, ABT_POOL_CONFIG_NULL, &pool); + ABT_pool_config config = (ABT_pool_config)RAND_PTR; + if (automatic) { + /* Create a configuration. */ + ret = ABT_pool_config_create(&config); + assert(!must_succeed || ret == ABT_SUCCESS); + if (ret != ABT_SUCCESS) { + assert(config == (ABT_pool_config)RAND_PTR); + return ABT_POOL_NULL; + } + const int automatic_val = 1; + ret = ABT_pool_config_set(config, ABT_pool_config_automatic.key, + ABT_pool_config_automatic.type, + (const void *)&automatic_val); + assert(!must_succeed || ret == ABT_SUCCESS); + if (ret != ABT_SUCCESS) { + ret = ABT_pool_config_free(&config); + assert(ret == ABT_SUCCESS && config == ABT_POOL_CONFIG_NULL); + return ABT_POOL_NULL; + } + } else { + /* By default, a pool created by ABT_pool_create() is not automatically + * freed. */ + config = ABT_POOL_CONFIG_NULL; + } + ret = ABT_pool_create(&pool_def, config, &pool); assert(!must_succeed || ret == ABT_SUCCESS); if (ret != ABT_SUCCESS) { #ifdef ABT_ENABLE_VER_20_API @@ -118,7 +137,11 @@ ABT_pool create_pool(int automatic, int must_succeed) #else assert(pool == ABT_POOL_NULL); #endif - return ABT_POOL_NULL; + pool = ABT_POOL_NULL; + } + if (config != ABT_POOL_CONFIG_NULL) { + ret = ABT_pool_config_free(&config); + assert(ret == ABT_SUCCESS && config == ABT_POOL_CONFIG_NULL); } return pool; }