net/enic: avoid error message when no advanced filtering
[dpdk.git] / examples / performance-thread / common / lthread_tls.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <limits.h>
10 #include <inttypes.h>
11 #include <unistd.h>
12 #include <pthread.h>
13 #include <fcntl.h>
14 #include <sys/time.h>
15 #include <sys/mman.h>
16 #include <sched.h>
17
18 #include <rte_malloc.h>
19 #include <rte_log.h>
20 #include <rte_ring.h>
21
22 #include "lthread_tls.h"
23 #include "lthread_queue.h"
24 #include "lthread_objcache.h"
25 #include "lthread_sched.h"
26
27 static struct rte_ring *key_pool;
28 static uint64_t key_pool_init;
29
30 /* needed to cause section start and end to be defined */
31 RTE_DEFINE_PER_LTHREAD(void *, dummy);
32
33 static struct lthread_key key_table[LTHREAD_MAX_KEYS];
34
35 RTE_INIT(thread_tls_ctor)
36 {
37         key_pool = NULL;
38         key_pool_init = 0;
39 }
40
41 /*
42  * Initialize a pool of keys
43  * These are unique tokens that can be obtained by threads
44  * calling lthread_key_create()
45  */
46 void _lthread_key_pool_init(void)
47 {
48         static struct rte_ring *pool;
49         struct lthread_key *new_key;
50         char name[MAX_LTHREAD_NAME_SIZE];
51
52         bzero(key_table, sizeof(key_table));
53
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)) {
58
59                 snprintf(name,
60                         MAX_LTHREAD_NAME_SIZE,
61                         "lthread_key_pool_%d",
62                         getpid());
63
64                 pool = rte_ring_create(name,
65                                         LTHREAD_MAX_KEYS, 0, 0);
66                 RTE_ASSERT(pool);
67
68                 int i;
69
70                 for (i = 1; i < LTHREAD_MAX_KEYS; i++) {
71                         new_key = &key_table[i];
72                         rte_ring_mp_enqueue((struct rte_ring *)pool,
73                                                 (void *)new_key);
74                 }
75                 key_pool = pool;
76         }
77         /* other lcores wait here till done */
78         while (key_pool == NULL) {
79                 rte_compiler_barrier();
80                 sched_yield();
81         };
82 }
83
84 /*
85  * Create a key
86  * this means getting a key from the pool
87  */
88 int lthread_key_create(unsigned int *key, tls_destructor_func destructor)
89 {
90         if (key == NULL)
91                 return POSIX_ERRNO(EINVAL);
92
93         struct lthread_key *new_key;
94
95         if (rte_ring_mc_dequeue((struct rte_ring *)key_pool, (void **)&new_key)
96             == 0) {
97                 new_key->destructor = destructor;
98                 *key = (new_key - key_table);
99
100                 return 0;
101         }
102         return POSIX_ERRNO(EAGAIN);
103 }
104
105
106 /*
107  * Delete a key
108  */
109 int lthread_key_delete(unsigned int k)
110 {
111         struct lthread_key *key;
112
113         key = (struct lthread_key *) &key_table[k];
114
115         if (k > LTHREAD_MAX_KEYS)
116                 return POSIX_ERRNO(EINVAL);
117
118         key->destructor = NULL;
119         rte_ring_mp_enqueue((struct rte_ring *)key_pool,
120                                         (void *)key);
121         return 0;
122 }
123
124
125
126 /*
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
132  */
133 void _lthread_tls_destroy(struct lthread *lt)
134 {
135         int i, k;
136         int nb_keys;
137         void *data;
138
139         for (i = 0; i < LTHREAD_DESTRUCTOR_ITERATIONS; i++) {
140
141                 for (k = 1; k < LTHREAD_MAX_KEYS; k++) {
142
143                         /* no keys in use ? */
144                         nb_keys = lt->tls->nb_keys_inuse;
145                         if (nb_keys == 0)
146                                 return;
147
148                         /* this key not in use ? */
149                         if (lt->tls->data[k] == NULL)
150                                 continue;
151
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;
156
157                         /* invoke destructor */
158                         if (key_table[k].destructor != NULL)
159                                 key_table[k].destructor(data);
160                 }
161         }
162 }
163
164 /*
165  * Return the pointer associated with a key
166  * If the key is no longer valid return NULL
167  */
168 void
169 *lthread_getspecific(unsigned int k)
170 {
171         void *res = NULL;
172
173         if (k < LTHREAD_MAX_KEYS)
174                 res = THIS_LTHREAD->tls->data[k];
175
176         return res;
177 }
178
179 /*
180  * Set a value against a key
181  * If the key is no longer valid return an error
182  * when storing value
183  */
184 int lthread_setspecific(unsigned int k, const void *data)
185 {
186         if (k >= LTHREAD_MAX_KEYS)
187                 return POSIX_ERRNO(EINVAL);
188
189         int n = THIS_LTHREAD->tls->nb_keys_inuse;
190
191         /* discard const qualifier */
192         char *p = (char *) (uintptr_t) data;
193
194
195         if (data != NULL) {
196                 if (THIS_LTHREAD->tls->data[k] == NULL)
197                         THIS_LTHREAD->tls->nb_keys_inuse = n+1;
198         }
199
200         THIS_LTHREAD->tls->data[k] = (void *) p;
201         return 0;
202 }
203
204 /*
205  * Allocate data for TLS cache
206 */
207 void _lthread_tls_alloc(struct lthread *lt)
208 {
209         struct lthread_tls *tls;
210
211         tls = _lthread_objcache_alloc((THIS_SCHED)->tls_cache);
212
213         RTE_ASSERT(tls != NULL);
214
215         tls->root_sched = (THIS_SCHED);
216         lt->tls = tls;
217
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);
222         }
223 }