1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2016. ALL RIGHTS RESERVED.
3 * Copyright (C) ARM Ltd. 2016-2017. ALL RIGHTS RESERVED.
4 *
5 * See file LICENSE for terms.
6 */
7
8 #ifndef UCS_CALLBACKQ_H
9 #define UCS_CALLBACKQ_H
10
11 #include <ucs/datastruct/list.h>
12 #include <ucs/sys/compiler_def.h>
13 #include <ucs/type/status.h>
14 #include <stddef.h>
15 #include <stdint.h>
16
17 BEGIN_C_DECLS
18
19 /** @file callbackq.h */
20
21 /*
22 * Thread-safe callback queue:
23 * - only one thread can dispatch
24 * - any thread can add and remove
25 * - add/remove operations are O(1)
26 */
27
28 #define UCS_CALLBACKQ_FAST_COUNT 7 /* Max. number of fast-path callbacks */
29 #define UCS_CALLBACKQ_ID_NULL (-1) /* Invalid callback identifier */
30
31
32 /*
33 * Forward declarations
34 */
35 typedef struct ucs_callbackq ucs_callbackq_t;
36 typedef struct ucs_callbackq_elem ucs_callbackq_elem_t;
37
38
39 /**
40 * Callback which can be placed in a queue.
41 *
42 * @param [in] arg User-defined argument for the callback.
43 *
44 * @return Count of how much "work" was done by the callback. For example, zero
45 * means that no work was done, and any nonzero value means that something
46 * was done.
47 */
48 typedef unsigned (*ucs_callback_t)(void *arg);
49
50
51 /**
52 * Callback queue element predicate.
53 *
54 * @param [in] elem Callback queue element to check.
55 * @param [in] arg User-defined argument.
56 *
57 * @return Predicate result value - nonzero means "true", zero means "false".
58 */
59 typedef int (*ucs_callbackq_predicate_t)(const ucs_callbackq_elem_t *elem,
60 void *arg);
61
62
63 /**
64 * @ingroup UCS_RESOURCE
65 * Callback flags
66 */
67 enum ucs_callbackq_flags {
68 UCS_CALLBACKQ_FLAG_FAST = UCS_BIT(0), /**< Fast-path (best effort) */
69 UCS_CALLBACKQ_FLAG_ONESHOT = UCS_BIT(1) /**< Call the callback only once
70 (cannot be used with FAST) */
71 };
72
73
74 /**
75 * Callback queue element.
76 */
77 struct ucs_callbackq_elem {
78 ucs_callback_t cb; /**< Callback function */
79 void *arg; /**< Function argument */
80 unsigned flags; /**< Callback flags */
81 int id; /**< Callback id */
82 };
83
84
85 /**
86 * A queue of callback to execute
87 */
88 struct ucs_callbackq {
89 /**
90 * Array of fast-path element, the last is reserved as a sentinel to mark
91 * array end.
92 */
93 ucs_callbackq_elem_t fast_elems[UCS_CALLBACKQ_FAST_COUNT + 1];
94
95 /**
96 * Private data, which we don't want to expose in API to avoid pulling
97 * more header files
98 */
99 char priv[72];
100 };
101
102
103 /**
104 * Initialize the callback queue.
105 *
106 * @param [in] cbq Callback queue to initialize.
107 */
108 ucs_status_t ucs_callbackq_init(ucs_callbackq_t *cbq);
109
110
111 /**
112 * Clean up the callback queue and release associated memory.
113 *
114 * @param [in] cbq Callback queue to clean up.
115 */
116 void ucs_callbackq_cleanup(ucs_callbackq_t *cbq);
117
118
119 /**
120 * Add a callback to the queue.
121 * This is *not* safe to call while another thread might be dispatching callbacks.
122 * However, it can be used from the dispatch context (e.g a callback may use this
123 * function to add another callback).
124 *
125 * @param [in] cbq Callback queue to add the callback to.
126 * @param [in] cb Callback to add.
127 * @param [in] arg User-defined argument for the callback.
128 * @param [in] flags Flags for the callback, from @ref ucs_callbackq_flags.
129 *
130 * @return Unique identifier of the callback in the queue.
131 */
132 int ucs_callbackq_add(ucs_callbackq_t *cbq, ucs_callback_t cb, void *arg,
133 unsigned flags);
134
135
136 /**
137 * Remove a callback from the queue immediately.
138 * This is *not* safe to call while another thread might be dispatching callbacks.
139 * However, it can be used from the dispatch context (e.g a callback may use this
140 * function to remove itself or another callback). In this case, the callback may
141 * still be dispatched once after this function returned.
142 *
143 * @param [in] cbq Callback queue to remove the callback from.
144 * @param [in] id Callback identifier to remove.
145 */
146 void ucs_callbackq_remove(ucs_callbackq_t *cbq, int id);
147
148
149 /**
150 * Add a callback to the queue.
151 * This can be used from any context and any thread, including but not limited to:
152 * - A callback can add another callback.
153 * - A thread can add a callback while another thread is dispatching callbacks.
154 *
155 * @param [in] cbq Callback queue to add the callback to.
156 * @param [in] cb Callback to add.
157 * @param [in] arg User-defined argument for the callback.
158 * @param [in] flags Flags for the callback, from @ref ucs_callbackq_flags.
159 *
160 * @return Unique identifier of the callback in the queue.
161 */
162 int ucs_callbackq_add_safe(ucs_callbackq_t *cbq, ucs_callback_t cb, void *arg,
163 unsigned flags);
164
165
166 /**
167 * Remove a callback from the queue in a safe but lazy fashion. The callback will
168 * be removed at some point in the near future.
169 * This can be used from any context and any thread, including but not limited to:
170 * - A callback can remove another callback or itself.
171 * - A thread can't remove a callback while another thread is dispatching callbacks.
172 *
173 * @param [in] cbq Callback queue to remove the callback from.
174 * @param [in] id Callback identifier to remove.
175 */
176 void ucs_callbackq_remove_safe(ucs_callbackq_t *cbq, int id);
177
178
179 /**
180 * Remove all callbacks from the queue for which the given predicate returns
181 * "true" (nonzero) value.
182 * This is *not* safe to call while another thread might be dispatching callbacks.
183 * However, it can be used from the dispatch context (e.g a callback may use this
184 * function to remove itself or another callback). In this case, the callback may
185 * still be dispatched once after this function returned.
186 *
187 * @param [in] cbq Callback queue.
188 * @param [in] pred Predicate to check candidates for removal.
189 * @param [in] arg User-defined argument for the predicate.
190 */
191 void ucs_callbackq_remove_if(ucs_callbackq_t *cbq, ucs_callbackq_predicate_t pred,
192 void *arg);
193
194
195 /**
196 * Dispatch callbacks from the callback queue.
197 * Must be called from single thread only.
198 *
199 * @param [in] cbq Callback queue to dispatch callbacks from.
200
201 * @return Sum of all return values from the dispatched callbacks.
202 */
ucs_callbackq_dispatch(ucs_callbackq_t * cbq)203 static inline unsigned ucs_callbackq_dispatch(ucs_callbackq_t *cbq)
204 {
205 ucs_callbackq_elem_t *elem;
206 ucs_callback_t cb;
207 unsigned count;
208
209 count = 0;
210 for (elem = cbq->fast_elems; (cb = elem->cb) != NULL; ++elem) {
211 count += cb(elem->arg);
212 }
213 return count;
214 }
215
216 END_C_DECLS
217
218 #endif
219