1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2015 Intel Corporation
18 #include <rte_malloc.h>
22 #include "lthread_tls.h"
23 #include "lthread_queue.h"
24 #include "lthread_objcache.h"
25 #include "lthread_sched.h"
27 static struct rte_ring *key_pool;
28 static uint64_t key_pool_init;
30 /* needed to cause section start and end to be defined */
31 RTE_DEFINE_PER_LTHREAD(void *, dummy);
33 static struct lthread_key key_table[LTHREAD_MAX_KEYS];
35 RTE_INIT(thread_tls_ctor)
42 * Initialize a pool of keys
43 * These are unique tokens that can be obtained by threads
44 * calling lthread_key_create()
46 void _lthread_key_pool_init(void)
48 static struct rte_ring *pool;
49 struct lthread_key *new_key;
50 char name[MAX_LTHREAD_NAME_SIZE];
52 bzero(key_table, sizeof(key_table));
54 uint64_t pool_init = 0;
55 /* only one lcore should do this */
56 if (__atomic_compare_exchange_n(&key_pool_init, &pool_init, 1, 0,
57 __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
60 MAX_LTHREAD_NAME_SIZE,
61 "lthread_key_pool_%d",
64 pool = rte_ring_create(name,
65 LTHREAD_MAX_KEYS, 0, 0);
70 for (i = 1; i < LTHREAD_MAX_KEYS; i++) {
71 new_key = &key_table[i];
72 rte_ring_mp_enqueue((struct rte_ring *)pool,
77 /* other lcores wait here till done */
78 while (key_pool == NULL) {
79 rte_compiler_barrier();
86 * this means getting a key from the pool
88 int lthread_key_create(unsigned int *key, tls_destructor_func destructor)
91 return POSIX_ERRNO(EINVAL);
93 struct lthread_key *new_key;
95 if (rte_ring_mc_dequeue((struct rte_ring *)key_pool, (void **)&new_key)
97 new_key->destructor = destructor;
98 *key = (new_key - key_table);
102 return POSIX_ERRNO(EAGAIN);
109 int lthread_key_delete(unsigned int k)
111 struct lthread_key *key;
113 key = (struct lthread_key *) &key_table[k];
115 if (k > LTHREAD_MAX_KEYS)
116 return POSIX_ERRNO(EINVAL);
118 key->destructor = NULL;
119 rte_ring_mp_enqueue((struct rte_ring *)key_pool,
127 * Break association for all keys in use by this thread
128 * invoke the destructor if available.
129 * Since a destructor can create keys we could enter an infinite loop
130 * therefore we give up after LTHREAD_DESTRUCTOR_ITERATIONS
131 * the behavior is modelled on pthread
133 void _lthread_tls_destroy(struct lthread *lt)
139 for (i = 0; i < LTHREAD_DESTRUCTOR_ITERATIONS; i++) {
141 for (k = 1; k < LTHREAD_MAX_KEYS; k++) {
143 /* no keys in use ? */
144 nb_keys = lt->tls->nb_keys_inuse;
148 /* this key not in use ? */
149 if (lt->tls->data[k] == NULL)
152 /* remove this key */
153 data = lt->tls->data[k];
154 lt->tls->data[k] = NULL;
155 lt->tls->nb_keys_inuse = nb_keys-1;
157 /* invoke destructor */
158 if (key_table[k].destructor != NULL)
159 key_table[k].destructor(data);
165 * Return the pointer associated with a key
166 * If the key is no longer valid return NULL
169 *lthread_getspecific(unsigned int k)
173 if (k < LTHREAD_MAX_KEYS)
174 res = THIS_LTHREAD->tls->data[k];
180 * Set a value against a key
181 * If the key is no longer valid return an error
184 int lthread_setspecific(unsigned int k, const void *data)
186 if (k >= LTHREAD_MAX_KEYS)
187 return POSIX_ERRNO(EINVAL);
189 int n = THIS_LTHREAD->tls->nb_keys_inuse;
191 /* discard const qualifier */
192 char *p = (char *) (uintptr_t) data;
196 if (THIS_LTHREAD->tls->data[k] == NULL)
197 THIS_LTHREAD->tls->nb_keys_inuse = n+1;
200 THIS_LTHREAD->tls->data[k] = (void *) p;
205 * Allocate data for TLS cache
207 void _lthread_tls_alloc(struct lthread *lt)
209 struct lthread_tls *tls;
211 tls = _lthread_objcache_alloc((THIS_SCHED)->tls_cache);
213 RTE_ASSERT(tls != NULL);
215 tls->root_sched = (THIS_SCHED);
218 /* allocate data for TLS varaiables using RTE_PER_LTHREAD macros */
219 if (sizeof(void *) < (uint64_t)RTE_PER_LTHREAD_SECTION_SIZE) {
220 lt->per_lthread_data =
221 _lthread_objcache_alloc((THIS_SCHED)->per_lthread_cache);