1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2015 Intel Corporation
18 #include <rte_malloc.h>
21 #include <rte_atomic_64.h>
23 #include "lthread_tls.h"
24 #include "lthread_queue.h"
25 #include "lthread_objcache.h"
26 #include "lthread_sched.h"
28 static struct rte_ring *key_pool;
29 static uint64_t key_pool_init;
31 /* needed to cause section start and end to be defined */
32 RTE_DEFINE_PER_LTHREAD(void *, dummy);
34 static struct lthread_key key_table[LTHREAD_MAX_KEYS];
36 RTE_INIT(thread_tls_ctor)
43 * Initialize a pool of keys
44 * These are unique tokens that can be obtained by threads
45 * calling lthread_key_create()
47 void _lthread_key_pool_init(void)
49 static struct rte_ring *pool;
50 struct lthread_key *new_key;
51 char name[MAX_LTHREAD_NAME_SIZE];
53 bzero(key_table, sizeof(key_table));
55 /* only one lcore should do this */
56 if (rte_atomic64_cmpset(&key_pool_init, 0, 1)) {
59 MAX_LTHREAD_NAME_SIZE,
60 "lthread_key_pool_%d",
63 pool = rte_ring_create(name,
64 LTHREAD_MAX_KEYS, 0, 0);
69 for (i = 1; i < LTHREAD_MAX_KEYS; i++) {
70 new_key = &key_table[i];
71 rte_ring_mp_enqueue((struct rte_ring *)pool,
76 /* other lcores wait here till done */
77 while (key_pool == NULL) {
78 rte_compiler_barrier();
85 * this means getting a key from the pool
87 int lthread_key_create(unsigned int *key, tls_destructor_func destructor)
90 return POSIX_ERRNO(EINVAL);
92 struct lthread_key *new_key;
94 if (rte_ring_mc_dequeue((struct rte_ring *)key_pool, (void **)&new_key)
96 new_key->destructor = destructor;
97 *key = (new_key - key_table);
101 return POSIX_ERRNO(EAGAIN);
108 int lthread_key_delete(unsigned int k)
110 struct lthread_key *key;
112 key = (struct lthread_key *) &key_table[k];
114 if (k > LTHREAD_MAX_KEYS)
115 return POSIX_ERRNO(EINVAL);
117 key->destructor = NULL;
118 rte_ring_mp_enqueue((struct rte_ring *)key_pool,
126 * Break association for all keys in use by this thread
127 * invoke the destructor if available.
128 * Since a destructor can create keys we could enter an infinite loop
129 * therefore we give up after LTHREAD_DESTRUCTOR_ITERATIONS
130 * the behavior is modelled on pthread
132 void _lthread_tls_destroy(struct lthread *lt)
138 for (i = 0; i < LTHREAD_DESTRUCTOR_ITERATIONS; i++) {
140 for (k = 1; k < LTHREAD_MAX_KEYS; k++) {
142 /* no keys in use ? */
143 nb_keys = lt->tls->nb_keys_inuse;
147 /* this key not in use ? */
148 if (lt->tls->data[k] == NULL)
151 /* remove this key */
152 data = lt->tls->data[k];
153 lt->tls->data[k] = NULL;
154 lt->tls->nb_keys_inuse = nb_keys-1;
156 /* invoke destructor */
157 if (key_table[k].destructor != NULL)
158 key_table[k].destructor(data);
164 * Return the pointer associated with a key
165 * If the key is no longer valid return NULL
168 *lthread_getspecific(unsigned int k)
172 if (k < LTHREAD_MAX_KEYS)
173 res = THIS_LTHREAD->tls->data[k];
179 * Set a value against a key
180 * If the key is no longer valid return an error
183 int lthread_setspecific(unsigned int k, const void *data)
185 if (k >= LTHREAD_MAX_KEYS)
186 return POSIX_ERRNO(EINVAL);
188 int n = THIS_LTHREAD->tls->nb_keys_inuse;
190 /* discard const qualifier */
191 char *p = (char *) (uintptr_t) data;
195 if (THIS_LTHREAD->tls->data[k] == NULL)
196 THIS_LTHREAD->tls->nb_keys_inuse = n+1;
199 THIS_LTHREAD->tls->data[k] = (void *) p;
204 * Allocate data for TLS cache
206 void _lthread_tls_alloc(struct lthread *lt)
208 struct lthread_tls *tls;
210 tls = _lthread_objcache_alloc((THIS_SCHED)->tls_cache);
212 RTE_ASSERT(tls != NULL);
214 tls->root_sched = (THIS_SCHED);
217 /* allocate data for TLS varaiables using RTE_PER_LTHREAD macros */
218 if (sizeof(void *) < (uint64_t)RTE_PER_LTHREAD_SECTION_SIZE) {
219 lt->per_lthread_data =
220 _lthread_objcache_alloc((THIS_SCHED)->per_lthread_cache);