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