FD.io VPP
v21.01.1
Vector Packet Processing
callback_data.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2020 Cisco and/or its affiliates.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at:
6
*
7
* http://www.apache.org/licenses/LICENSE-2.0
8
*
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
* See the License for the specific language governing permissions and
13
* limitations under the License.
14
*/
15
16
/** @file
17
* @brief Callback multiplex scheme
18
*/
19
20
#ifndef included_callback_data_h
21
#define included_callback_data_h
22
#include <
vppinfra/clib.h
>
23
24
/** @brief Declare and define a callback set type
25
* @param set_t_ The set type to define
26
* @param cb_t_ The callback type to use
27
*/
28
#define clib_callback_data_typedef(set_t_, cb_t_) \
29
typedef struct set_t_ \
30
{ \
31
cb_t_* curr; \
32
cb_t_* volatile next; \
33
cb_t_* spare; \
34
clib_spinlock_t* lock; \
35
} set_t_
36
37
/** @brief Initialize a callback set
38
* @param set_ The callback set to initialize
39
* @param lock_ The lock to use, if any
40
*/
41
#define clib_callback_data_init(set_,lock_) \
42
do { \
43
(set_)->lock = (lock_); \
44
(set_)->curr = 0; \
45
(set_)->next = 0; \
46
(set_)->spare = 0; \
47
} while (0)
48
49
/** @brief Add a callback to the specified callback set
50
* @param set_ The callback set
51
* @param value_ The value_ to assign the callback
52
*
53
* Add a callback from the indicated callback set. If the set is
54
* currently being iterated, then the change will be applied after the
55
* current full iteration, and prior to the next full iteration.
56
*/
57
#define clib_callback_data_add(set_,value_) \
58
do { \
59
clib_spinlock_lock_if_init ((set_)->lock); \
60
typeof ((set_)->next) next_ = (set_)->next; \
61
if (PREDICT_TRUE (next_ == 0)) \
62
{ \
63
next_ = (set_)->spare; \
64
(set_)->spare = 0; \
65
vec_append (next_, (set_)->curr); \
66
} \
67
u32 sz_ = vec_len (next_); \
68
vec_validate (next_, sz_); \
69
next_[sz_] = (value_); \
70
(set_)->next = next_; \
71
clib_spinlock_unlock_if_init ((set_)->lock); \
72
} while (0)
73
74
/** @brief Remove a callback from the specified callback set
75
* @param set_ The callback set
76
* @param fp_ The current callback function
77
* @return 1 if the function was removed, 0 if not
78
*
79
* Remove a callback from the indicated callback set. Idempotent. If
80
* the set is currently being iterated, then the change will be applied
81
* after the current full iteration, and prior to the next full
82
* iteration.
83
*/
84
#define clib_callback_data_remove(set_,fp_) \
85
({ \
86
int found_ = 0; \
87
clib_spinlock_lock_if_init ((set_)->lock); \
88
typeof ((set_)->next) next_ = (set_)->next; \
89
if (PREDICT_TRUE (next_ == 0)) \
90
{ \
91
next_ = (set_)->spare; \
92
(set_)->spare = 0; \
93
vec_append (next_, (set_)->curr); \
94
} \
95
u32 sz_ = vec_len (next_); \
96
u32 i_; \
97
for (i_ = 0; i_ < sz_; i_++) \
98
if (next_[i_].fp == (fp_)) \
99
{ \
100
vec_delete (next_, 1, i_); \
101
found_ = 1; \
102
break; \
103
} \
104
(set_)->next = next_; \
105
clib_spinlock_unlock_if_init ((set_)->lock); \
106
found_; \
107
})
108
109
/** @brief Swap a callback in the specified callback set
110
* @param set_ The callback set
111
* @param fp_ The current callback function
112
* @param value_ The value_ to assign the callback
113
* @return 1 if the function was swapped, 0 if not
114
*
115
* Swap a callback in the indicated callback set. If the callback is
116
* not found, then nothing is done. If the set is currently being
117
* iterated, then the change will be applied after the current full
118
* iteration, and prior to the next full iteration.
119
*/
120
#define clib_callback_data_swap(set_,fp_,value_) \
121
({ \
122
int found_ = 0; \
123
clib_spinlock_lock_if_init ((set_)->lock); \
124
typeof ((set_)->next) next_ = (set_)->next; \
125
if (PREDICT_TRUE (next_ == 0)) \
126
{ \
127
next_ = (set_)->spare; \
128
(set_)->spare = 0; \
129
vec_append (next_, (set_)->curr); \
130
} \
131
u32 sz_ = vec_len (next_); \
132
u32 i_; \
133
for (i_ = 0; i_ < sz_; i_++) \
134
if (next_[i_].fp == (fp_)) \
135
{ \
136
next_[i_] = (value_); \
137
found_ = 1; \
138
break; \
139
} \
140
(set_)->next = next_; \
141
clib_spinlock_unlock_if_init ((set_)->lock); \
142
found_; \
143
})
144
145
/** @brief Ensure a callback is in the specified callback set
146
* @param set_ The callback set
147
* @param value_ The value_ to assign the callback
148
* @return 1 if the function was swapped, 0 if not
149
*
150
* Add or swap a callback in the indicated callback set. If the
151
* callback is already in the set, it is replaced. If the callback is
152
* not found, then it is added. If the set is currently being
153
* iterated, then the change will be applied after the current full
154
* iteration, and prior to the next full iteration.
155
*/
156
#define clib_callback_data_ensure(set_,value_) \
157
do { \
158
int found_ = 0; \
159
clib_spinlock_lock_if_init ((set_)->lock); \
160
typeof ((set_)->next) next_ = (set_)->next; \
161
if (PREDICT_TRUE (next_ == 0)) \
162
{ \
163
next_ = (set_)->spare; \
164
(set_)->spare = 0; \
165
vec_append (next_, (set_)->curr); \
166
} \
167
u32 sz_ = vec_len (next_); \
168
u32 i_; \
169
for (i_ = 0; i_ < sz_; i_++) \
170
if (next_[i_].fp == (value_).fp) \
171
{ \
172
found_ = 1; \
173
break; \
174
} \
175
if (!found_) \
176
vec_validate (next_, i_); \
177
next_[i_] = (value_); \
178
(set_)->next = next_; \
179
clib_spinlock_unlock_if_init ((set_)->lock); \
180
} while(0)
181
182
/** @brief Enable/Disable the specified callback
183
* @param set_ The callback set
184
* @param fp_ The callback function
185
* @param ena_ 1 to enable, 0 to disable
186
*
187
* Enable or disable a callback function, with no data.
188
*/
189
#define clib_callback_data_enable_disable(set_,fp_,ena_) \
190
do { \
191
if (ena_) \
192
{ \
193
typeof ((set_)->next[0]) data_ = { .fp = (fp_) }; \
194
clib_callback_data_add ((set_), data_); \
195
} \
196
else \
197
clib_callback_data_remove ((set_), (fp_)); \
198
} while (0)
199
200
/** @brief Get the value of a callback, if set.
201
* @param set_ The callback set
202
* @param fp_ The callback function
203
* @param v_ Set to the callback's current value
204
* @return 1 if the function is in the set, 0 if not
205
*/
206
#define clib_callback_data_get_value(set_,fp_,v_) \
207
({ \
208
int found_ = 0; \
209
clib_spinlock_lock_if_init ((set_)->lock); \
210
typeof ((set_)->next) search_ = (set_)->next; \
211
if (PREDICT_TRUE (search_ == 0)) \
212
search_ = (set_)->curr; \
213
u32 sz_ = vec_len (search_); \
214
u32 i_; \
215
for (i_ = 0; i_ < sz_; i_++) \
216
if (search_[i_].fp == (fp_)) \
217
{ \
218
(v_) = search_[i]; \
219
found_ = 1; \
220
break; \
221
} \
222
clib_spinlock_unlock_if_init ((set_)->lock); \
223
found_; \
224
})
225
226
/** @brief Check if callback is set
227
* @param set_ The callback set
228
* @param fp_ The callback function
229
* @return 1 if the function is in the set, 0 if not
230
*/
231
#define clib_callback_data_is_set(set_,fp_) \
232
({ \
233
int found_ = 0; \
234
clib_spinlock_lock_if_init ((set_)->lock); \
235
typeof ((set_)->next) search_ = (set_)->next; \
236
if (PREDICT_TRUE (search_ == 0)) \
237
search_ = (set_)->curr; \
238
u32 sz_ = vec_len (search_); \
239
u32 i_; \
240
for (i_ = 0; i_ < sz_; i_++) \
241
if (search_[i_].fp == (fp_)) \
242
{ \
243
found_ = 1; \
244
break; \
245
} \
246
clib_spinlock_unlock_if_init ((set_)->lock); \
247
found_; \
248
})
249
250
/** @brief Check for and get current callback set
251
* @param set_ the callback set
252
* @param varargs additional callback parameters
253
*/
254
#define clib_callback_data_check_and_get(set_) \
255
({ \
256
typeof ((set_)->curr) curr_ = (set_)->curr; \
257
if (PREDICT_FALSE ((set_)->next != 0)) \
258
{ \
259
clib_spinlock_lock_if_init ((set_)->lock); \
260
vec_reset_length (curr_); \
261
(set_)->spare = curr_; \
262
curr_ = (set_)->next; \
263
(set_)->next = 0; \
264
if (PREDICT_FALSE (0 == vec_len (curr_))) \
265
vec_free (curr_); \
266
(set_)->curr = curr_; \
267
clib_spinlock_unlock_if_init ((set_)->lock); \
268
} \
269
curr_; \
270
})
271
272
/** @brief Iterate and call a callback vector
273
* @param vec_ the callback vector
274
* @param varargs additional callback parameters
275
*/
276
#define clib_callback_data_call_vec(vec_, ...) \
277
do { \
278
u32 sz_ = vec_len (vec_); \
279
u32 i_; \
280
for (i_ = 0; i_ < sz_; i_++) \
281
{ \
282
CLIB_PREFETCH (&vec_[i_+1], CLIB_CACHE_LINE_BYTES, STORE); \
283
(vec_[i_].fp) (&vec_[i_], __VA_ARGS__); \
284
} \
285
} while (0)
286
287
/** @brief Call the specified callback set
288
* @param set_ the callback set
289
* @param varargs additional callback parameters
290
*/
291
#define clib_callback_data_call(set_, ...) \
292
do { \
293
typeof ((set_)->curr) v_ = clib_callback_data_check_and_get(set_); \
294
clib_callback_data_iterate (v_, __VA_ARGS__); \
295
} while (0)
296
297
/** @brief prefetch the callback set
298
* @param set_ The callback set
299
*/
300
#define clib_callback_data_prefetch(set_) \
301
do { \
302
if (PREDICT_FALSE ((set_)->curr)) \
303
CLIB_PREFETCH ((set_)->curr, CLIB_CACHE_LINE_BYTES, STORE); \
304
} while (0)
305
306
307
#endif
/* included_callback_data_h */
308
309
/*
310
* fd.io coding-style-patch-verification: ON
311
*
312
* Local Variables:
313
* eval: (c-set-style "gnu")
314
* End:
315
*/
clib.h
src
vppinfra
callback_data.h
Generated on Wed Jul 14 2021 16:06:24 for FD.io VPP by
1.8.13