ARGOBOTS
key.c
Go to the documentation of this file.
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  * See COPYRIGHT in top-level directory.
4  */
5 
6 #include "abti.h"
7 
13 static inline void ABTI_ktable_set(ABTI_ktable *p_ktable, ABTI_key *p_key,
14  void *value);
15 static inline void *ABTI_ktable_get(ABTI_ktable *p_ktable, ABTI_key *p_key);
16 void ABTI_ktable_delete(ABTI_ktable *p_ktable, ABTI_key *p_key);
17 
18 static ABTD_atomic_uint32 g_key_id = ABTD_ATOMIC_UINT32_STATIC_INITIALIZER(0);
19 
46 int ABT_key_create(void (*destructor)(void *value), ABT_key *newkey)
47 {
48  int abt_errno = ABT_SUCCESS;
49  ABTI_key *p_newkey;
50 
51  p_newkey = (ABTI_key *)ABTU_malloc(sizeof(ABTI_key));
52  p_newkey->f_destructor = destructor;
53  p_newkey->id = ABTD_atomic_fetch_add_uint32(&g_key_id, 1);
54  ABTD_atomic_relaxed_store_uint32(&p_newkey->refcount, 1);
55  p_newkey->freed = ABT_FALSE;
56 
57  /* Return value */
58  *newkey = ABTI_key_get_handle(p_newkey);
59 
60  return abt_errno;
61 }
62 
77 {
78  int abt_errno = ABT_SUCCESS;
79  ABT_key h_key = *key;
80  ABTI_key *p_key = ABTI_key_get_ptr(h_key);
81  ABTI_CHECK_NULL_KEY_PTR(p_key);
82 
83  uint32_t refcount;
84 
85  p_key->freed = ABT_TRUE;
86  refcount = ABTD_atomic_fetch_sub_uint32(&p_key->refcount, 1);
87  if (refcount == 1) {
88  ABTU_free(p_key);
89  }
90 
91  /* Return value */
92  *key = ABT_KEY_NULL;
93 
94 fn_exit:
95  return abt_errno;
96 
97 fn_fail:
98  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
99  goto fn_exit;
100 }
101 
114 int ABT_key_set(ABT_key key, void *value)
115 {
116  int abt_errno = ABT_SUCCESS;
117  ABTI_local *p_local = ABTI_local_get_local();
118  ABTI_thread *p_thread;
119  ABTI_task *p_task;
120  ABTI_ktable *p_ktable;
121 
122  ABTI_key *p_key = ABTI_key_get_ptr(key);
123  ABTI_CHECK_NULL_KEY_PTR(p_key);
124 
125  /* We don't allow an external thread to call this routine. */
126  ABTI_CHECK_INITIALIZED();
127  ABTI_CHECK_TRUE(p_local != NULL, ABT_ERR_INV_XSTREAM);
128 
129  /* Obtain the key-value table pointer. */
130  p_thread = p_local->p_thread;
131  if (p_thread) {
132  if (p_thread->p_keytable == NULL) {
133  int key_table_size = gp_ABTI_global->key_table_size;
134  p_thread->p_keytable = ABTI_ktable_alloc(key_table_size);
135  }
136  p_ktable = p_thread->p_keytable;
137  } else {
138  p_task = p_local->p_task;
139  ABTI_CHECK_TRUE(p_task != NULL, ABT_ERR_INV_TASK);
140  if (p_task->p_keytable == NULL) {
141  int key_table_size = gp_ABTI_global->key_table_size;
142  p_task->p_keytable = ABTI_ktable_alloc(key_table_size);
143  }
144  p_ktable = p_task->p_keytable;
145  }
146 
147  /* Save the value in the key-value table */
148  ABTI_ktable_set(p_ktable, p_key, value);
149 
150 fn_exit:
151  return abt_errno;
152 
153 fn_fail:
154  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
155  goto fn_exit;
156 }
157 
173 int ABT_key_get(ABT_key key, void **value)
174 {
175  int abt_errno = ABT_SUCCESS;
176  ABTI_local *p_local = ABTI_local_get_local();
177  ABTI_thread *p_thread;
178  ABTI_task *p_task;
179  ABTI_ktable *p_ktable = NULL;
180  void *keyval = NULL;
181 
182  ABTI_key *p_key = ABTI_key_get_ptr(key);
183  ABTI_CHECK_NULL_KEY_PTR(p_key);
184 
185  /* We don't allow an external thread to call this routine. */
186  ABTI_CHECK_INITIALIZED();
187  ABTI_CHECK_TRUE(p_local != NULL, ABT_ERR_INV_XSTREAM);
188 
189  /* Obtain the key-value table pointer */
190  p_thread = p_local->p_thread;
191  if (p_thread) {
192  p_ktable = p_thread->p_keytable;
193  if (p_ktable) {
194  /* Retrieve the value from the key-value table */
195  keyval = ABTI_ktable_get(p_ktable, p_key);
196  }
197  } else {
198  p_task = p_local->p_task;
199  ABTI_CHECK_TRUE(p_task != NULL, ABT_ERR_INV_TASK);
200  p_ktable = p_task->p_keytable;
201  if (p_ktable) {
202  /* Retrieve the value from the key-value table */
203  keyval = ABTI_ktable_get(p_ktable, p_key);
204  }
205  }
206 
207  *value = keyval;
208 
209 fn_exit:
210  return abt_errno;
211 
212 fn_fail:
213  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
214  goto fn_exit;
215 }
216 
217 ABTI_ktable *ABTI_ktable_alloc(int size)
218 {
219  ABTI_ktable *p_ktable;
220 
221  p_ktable = (ABTI_ktable *)ABTU_malloc(sizeof(ABTI_ktable));
222  p_ktable->size = size;
223  p_ktable->num = 0;
224  p_ktable->p_elems =
225  (ABTI_ktelem **)ABTU_calloc(size, sizeof(ABTI_ktelem *));
226 
227  return p_ktable;
228 }
229 
230 void ABTI_ktable_free(ABTI_ktable *p_ktable)
231 {
232  ABTI_ktelem *p_elem, *p_next;
233  ABTI_key *p_key;
234  int i;
235  uint32_t refcount;
236 
237  for (i = 0; i < p_ktable->size; i++) {
238  p_elem = p_ktable->p_elems[i];
239  while (p_elem) {
240  /* Call the destructor if it exists and the value is not null. */
241  p_key = p_elem->p_key;
242  if (p_key->f_destructor && p_elem->value) {
243  p_key->f_destructor(p_elem->value);
244  }
245  refcount = ABTD_atomic_fetch_sub_uint32(&p_key->refcount, 1);
246  if (refcount == 1 && p_key->freed == ABT_TRUE) {
247  ABTU_free(p_key);
248  }
249 
250  p_next = p_elem->p_next;
251  ABTU_free(p_elem);
252  p_elem = p_next;
253  }
254  }
255 
256  ABTU_free(p_ktable->p_elems);
257  ABTU_free(p_ktable);
258 }
259 
260 static inline uint32_t ABTI_ktable_get_idx(ABTI_key *p_key, int size)
261 {
262  return p_key->id % size;
263 }
264 
265 static inline void ABTI_ktable_set(ABTI_ktable *p_ktable, ABTI_key *p_key,
266  void *value)
267 {
268  uint32_t idx;
269  ABTI_ktelem *p_elem;
270 
271  /* Look for the same key */
272  idx = ABTI_ktable_get_idx(p_key, p_ktable->size);
273  p_elem = p_ktable->p_elems[idx];
274  while (p_elem) {
275  if (p_elem->p_key == p_key) {
276  p_elem->value = value;
277  return;
278  }
279  p_elem = p_elem->p_next;
280  }
281 
282  /* The table does not have the same key */
283  p_elem = (ABTI_ktelem *)ABTU_malloc(sizeof(ABTI_ktelem));
284  p_elem->p_key = p_key;
285  p_elem->value = value;
286  p_elem->p_next = p_ktable->p_elems[idx];
287  ABTD_atomic_fetch_add_uint32(&p_key->refcount, 1);
288  p_ktable->p_elems[idx] = p_elem;
289 
290  p_ktable->num++;
291 }
292 
293 static inline void *ABTI_ktable_get(ABTI_ktable *p_ktable, ABTI_key *p_key)
294 {
295  uint32_t idx;
296  ABTI_ktelem *p_elem;
297 
298  idx = ABTI_ktable_get_idx(p_key, p_ktable->size);
299  p_elem = p_ktable->p_elems[idx];
300  while (p_elem) {
301  if (p_elem->p_key == p_key) {
302  return p_elem->value;
303  }
304  p_elem = p_elem->p_next;
305  }
306 
307  return NULL;
308 }
309 
310 void ABTI_ktable_delete(ABTI_ktable *p_ktable, ABTI_key *p_key)
311 {
312  uint32_t idx;
313  ABTI_ktelem *p_prev = NULL;
314  ABTI_ktelem *p_elem;
315 
316  idx = ABTI_ktable_get_idx(p_key, p_ktable->size);
317  p_elem = p_ktable->p_elems[idx];
318  while (p_elem) {
319  if (p_elem->p_key == p_key) {
320  if (p_prev) {
321  p_prev->p_next = p_elem->p_next;
322  } else {
323  p_ktable->p_elems[idx] = p_elem->p_next;
324  }
325  p_ktable->num--;
326 
327  ABTU_free(p_elem);
328  return;
329  }
330 
331  p_prev = p_elem;
332  p_elem = p_elem->p_next;
333  }
334 }
static ABTD_atomic_uint32 g_key_id
Definition: key.c:18
static void * ABTU_malloc(size_t size)
Definition: abtu.h:39
#define ABT_KEY_NULL
Definition: abt.h:347
int ABT_key_get(ABT_key key, void **value)
Get the value associated with the key.
Definition: key.c:173
#define ABT_ERR_INV_TASK
Definition: abt.h:82
int ABT_key_free(ABT_key *key)
Free an WU-specific data key.
Definition: key.c:76
struct ABT_key_opaque * ABT_key
Definition: abt.h:291
#define ABT_FALSE
Definition: abt.h:224
#define HANDLE_ERROR_FUNC_WITH_CODE(n)
Definition: abti_error.h:241
ABTI_global * gp_ABTI_global
Definition: global.c:14
#define ABT_SUCCESS
Definition: abt.h:64
#define ABT_TRUE
Definition: abt.h:223
int ABT_key_create(void(*destructor)(void *value), ABT_key *newkey)
Create an WU-specific data key.
Definition: key.c:46
#define ABT_ERR_INV_XSTREAM
Definition: abt.h:68
static void ABTU_free(void *ptr)
Definition: abtu.h:32
int ABT_key_set(ABT_key key, void *value)
Associate a value with the key.
Definition: key.c:114
static void * ABTU_calloc(size_t num, size_t size)
Definition: abtu.h:49