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
);