1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2023 Ericsson AB 3 */ 4 5 #ifndef RTE_DISPATCHER_H 6 #define RTE_DISPATCHER_H 7 8 /** 9 * @file 10 * 11 * RTE Dispatcher 12 * 13 * @warning 14 * @b EXPERIMENTAL: 15 * All functions in this file may be changed or removed without prior notice. 16 * 17 * The purpose of the dispatcher is to help decouple different parts 18 * of an application (e.g., modules), sharing the same underlying 19 * event device. 20 */ 21 22 #include <stdbool.h> 23 #include <stdint.h> 24 25 #include <rte_compat.h> 26 #include <rte_eventdev.h> 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 /** 33 * Function prototype for match callbacks. 34 * 35 * Match callbacks are used by an application to decide how the 36 * dispatcher distributes events to different parts of the 37 * application. 38 * 39 * The application is not expected to process the event at the point 40 * of the match call. Such matters should be deferred to the process 41 * callback invocation. 42 * 43 * The match callback may be used as an opportunity to prefetch data. 44 * 45 * @param event 46 * Pointer to event 47 * 48 * @param cb_data 49 * The pointer supplied by the application in 50 * rte_dispatcher_register(). 51 * 52 * @return 53 * Returns true in case this event should be delivered (via 54 * the process callback), and false otherwise. 55 */ 56 typedef bool (*rte_dispatcher_match_t)(const struct rte_event *event, 57 void *cb_data); 58 59 /** 60 * Function prototype for process callbacks. 61 * 62 * The process callbacks are used by the dispatcher to deliver 63 * events for processing. 64 * 65 * @param event_dev_id 66 * The originating event device id. 67 * 68 * @param event_port_id 69 * The originating event port. 70 * 71 * @param events 72 * Pointer to an array of events. 73 * 74 * @param num 75 * The number of events in the @p events array. 76 * 77 * @param cb_data 78 * The pointer supplied by the application in 79 * rte_dispatcher_register(). 80 */ 81 typedef void (*rte_dispatcher_process_t)(uint8_t event_dev_id, 82 uint8_t event_port_id, struct rte_event *events, uint16_t num, 83 void *cb_data); 84 85 /** 86 * Function prototype for finalize callbacks. 87 * 88 * The finalize callbacks are used by the dispatcher to notify the 89 * application it has delivered all events from a particular batch 90 * dequeued from the event device. 91 * 92 * @param event_dev_id 93 * The originating event device id. 94 * 95 * @param event_port_id 96 * The originating event port. 97 * 98 * @param cb_data 99 * The pointer supplied by the application in 100 * rte_dispatcher_finalize_register(). 101 */ 102 typedef void (*rte_dispatcher_finalize_t)(uint8_t event_dev_id, 103 uint8_t event_port_id, void *cb_data); 104 105 /** 106 * Dispatcher statistics 107 */ 108 struct rte_dispatcher_stats { 109 /** Number of event dequeue calls made toward the event device. */ 110 uint64_t poll_count; 111 /** Number of non-empty event batches dequeued from event device.*/ 112 uint64_t ev_batch_count; 113 /** Number of events dispatched to a handler.*/ 114 uint64_t ev_dispatch_count; 115 /** Number of events dropped because no handler was found. */ 116 uint64_t ev_drop_count; 117 }; 118 119 /** 120 * Create a dispatcher with the specified id. 121 * 122 * @param event_dev_id 123 * The identifier of the event device from which this dispatcher 124 * will dequeue events. 125 * 126 * @return 127 * A pointer to a new dispatcher instance, or NULL on failure, in which 128 * case rte_errno is set. 129 */ 130 __rte_experimental 131 struct rte_dispatcher * 132 rte_dispatcher_create(uint8_t event_dev_id); 133 134 /** 135 * Free a dispatcher. 136 * 137 * @param dispatcher 138 * The dispatcher instance. 139 * 140 * @return 141 * - 0: Success 142 * - <0: Error code on failure 143 */ 144 __rte_experimental 145 int 146 rte_dispatcher_free(struct rte_dispatcher *dispatcher); 147 148 /** 149 * Retrieve the service identifier of a dispatcher. 150 * 151 * @param dispatcher 152 * The dispatcher instance. 153 * 154 * @return 155 * The dispatcher service's id. 156 */ 157 __rte_experimental 158 uint32_t 159 rte_dispatcher_service_id_get(const struct rte_dispatcher *dispatcher); 160 161 /** 162 * Binds an event device port to a specific lcore on the specified 163 * dispatcher. 164 * 165 * This function configures the event port id to be used by the event 166 * dispatcher service, if run on the specified lcore. 167 * 168 * Multiple event device ports may be bound to the same lcore. A 169 * particular port must not be bound to more than one lcore. 170 * 171 * If the dispatcher service is mapped (with rte_service_map_lcore_set()) 172 * to a lcore to which no ports are bound, the service function will be a 173 * no-operation. 174 * 175 * This function may be called by any thread (including unregistered 176 * non-EAL threads), but not while the dispatcher is running on lcore 177 * specified by @c lcore_id. 178 * 179 * @param dispatcher 180 * The dispatcher instance. 181 * 182 * @param event_port_id 183 * The event device port identifier. 184 * 185 * @param batch_size 186 * The batch size to use in rte_event_dequeue_burst(), for the 187 * configured event device port and lcore. 188 * 189 * @param timeout 190 * The timeout parameter to use in rte_event_dequeue_burst(), for the 191 * configured event device port and lcore. 192 * 193 * @param lcore_id 194 * The lcore by which this event port will be used. 195 * 196 * @return 197 * - 0: Success 198 * - -ENOMEM: Unable to allocate sufficient resources. 199 * - -EEXISTS: Event port is already configured. 200 * - -EINVAL: Invalid arguments. 201 */ 202 __rte_experimental 203 int 204 rte_dispatcher_bind_port_to_lcore(struct rte_dispatcher *dispatcher, 205 uint8_t event_port_id, uint16_t batch_size, uint64_t timeout, 206 unsigned int lcore_id); 207 208 /** 209 * Unbind an event device port from a specific lcore. 210 * 211 * This function may be called by any thread (including unregistered 212 * non-EAL threads), but not while the dispatcher is running on 213 * lcore specified by @c lcore_id. 214 * 215 * @param dispatcher 216 * The dispatcher instance. 217 * 218 * @param event_port_id 219 * The event device port identifier. 220 * 221 * @param lcore_id 222 * The lcore which was using this event port. 223 * 224 * @return 225 * - 0: Success 226 * - -ENOENT: Event port id not bound to this @c lcore_id. 227 */ 228 __rte_experimental 229 int 230 rte_dispatcher_unbind_port_from_lcore(struct rte_dispatcher *dispatcher, 231 uint8_t event_port_id, unsigned int lcore_id); 232 233 /** 234 * Register an event handler. 235 * 236 * The match callback function is used to select if a particular event 237 * should be delivered, using the corresponding process callback 238 * function. 239 * 240 * The reason for having two distinct steps is to allow the dispatcher 241 * to deliver all events as a batch. This in turn will cause 242 * processing of a particular kind of events to happen in a 243 * back-to-back manner, improving cache locality. 244 * 245 * The list of handler callback functions is shared among all lcores, 246 * but will only be executed on lcores which has an eventdev port 247 * bound to them, and which are running the dispatcher service. 248 * 249 * An event is delivered to at most one handler. Events where no 250 * handler is found are dropped. 251 * 252 * The application must not depend on the order of which the match 253 * functions are invoked. 254 * 255 * Ordering of events is not guaranteed to be maintained between 256 * different deliver callbacks. For example, suppose there are two 257 * callbacks registered, matching different subsets of events arriving 258 * on an atomic queue. A batch of events [ev0, ev1, ev2] are dequeued 259 * on a particular port, all pertaining to the same flow. The match 260 * callback for registration A returns true for ev0 and ev2, and the 261 * matching function for registration B for ev1. In that scenario, the 262 * dispatcher may choose to deliver first [ev0, ev2] using A's deliver 263 * function, and then [ev1] to B - or vice versa. 264 * 265 * rte_dispatcher_register() may be called by any thread 266 * (including unregistered non-EAL threads), but not while the event 267 * dispatcher is running on any service lcore. 268 * 269 * @param dispatcher 270 * The dispatcher instance. 271 * 272 * @param match_fun 273 * The match callback function. 274 * 275 * @param match_cb_data 276 * A pointer to some application-specific opaque data (or NULL), 277 * which is supplied back to the application when match_fun is 278 * called. 279 * 280 * @param process_fun 281 * The process callback function. 282 * 283 * @param process_cb_data 284 * A pointer to some application-specific opaque data (or NULL), 285 * which is supplied back to the application when process_fun is 286 * called. 287 * 288 * @return 289 * - >= 0: The identifier for this registration. 290 * - -ENOMEM: Unable to allocate sufficient resources. 291 */ 292 __rte_experimental 293 int 294 rte_dispatcher_register(struct rte_dispatcher *dispatcher, 295 rte_dispatcher_match_t match_fun, void *match_cb_data, 296 rte_dispatcher_process_t process_fun, void *process_cb_data); 297 298 /** 299 * Unregister an event handler. 300 * 301 * This function may be called by any thread (including unregistered 302 * non-EAL threads), but not while the dispatcher is running on 303 * any service lcore. 304 * 305 * @param dispatcher 306 * The dispatcher instance. 307 * 308 * @param handler_id 309 * The handler registration id returned by the original 310 * rte_dispatcher_register() call. 311 * 312 * @return 313 * - 0: Success 314 * - -EINVAL: The @c handler_id parameter was invalid. 315 */ 316 __rte_experimental 317 int 318 rte_dispatcher_unregister(struct rte_dispatcher *dispatcher, int handler_id); 319 320 /** 321 * Register a finalize callback function. 322 * 323 * An application may optionally install one or more finalize 324 * callbacks. 325 * 326 * All finalize callbacks are invoked by the dispatcher when a 327 * complete batch of events (retrieve using rte_event_dequeue_burst()) 328 * have been delivered to the application (or have been dropped). 329 * 330 * The finalize callback is not tied to any particular handler. 331 * 332 * The finalize callback provides an opportunity for the application 333 * to do per-batch processing. One case where this may be useful is if 334 * an event output buffer is used, and is shared among several 335 * handlers. In such a case, proper output buffer flushing may be 336 * assured using a finalize callback. 337 * 338 * rte_dispatcher_finalize_register() may be called by any thread 339 * (including unregistered non-EAL threads), but not while the 340 * dispatcher is running on any service lcore. 341 * 342 * @param dispatcher 343 * The dispatcher instance. 344 * 345 * @param finalize_fun 346 * The function called after completing the processing of a 347 * dequeue batch. 348 * 349 * @param finalize_data 350 * A pointer to some application-specific opaque data (or NULL), 351 * which is supplied back to the application when @c finalize_fun is 352 * called. 353 * 354 * @return 355 * - >= 0: The identifier for this registration. 356 * - -ENOMEM: Unable to allocate sufficient resources. 357 */ 358 __rte_experimental 359 int 360 rte_dispatcher_finalize_register(struct rte_dispatcher *dispatcher, 361 rte_dispatcher_finalize_t finalize_fun, void *finalize_data); 362 363 /** 364 * Unregister a finalize callback. 365 * 366 * This function may be called by any thread (including unregistered 367 * non-EAL threads), but not while the dispatcher is running on 368 * any service lcore. 369 * 370 * @param dispatcher 371 * The dispatcher instance. 372 * 373 * @param reg_id 374 * The finalize registration id returned by the original 375 * rte_dispatcher_finalize_register() call. 376 * 377 * @return 378 * - 0: Success 379 * - -EINVAL: The @c reg_id parameter was invalid. 380 */ 381 __rte_experimental 382 int 383 rte_dispatcher_finalize_unregister(struct rte_dispatcher *dispatcher, int reg_id); 384 385 /** 386 * Start a dispatcher instance. 387 * 388 * Enables the dispatcher service. 389 * 390 * The underlying event device must have been started prior to calling 391 * rte_dispatcher_start(). 392 * 393 * For the dispatcher to actually perform work (i.e., dispatch 394 * events), its service must have been mapped to one or more service 395 * lcores, and its service run state set to '1'. A dispatcher's 396 * service is retrieved using rte_dispatcher_service_id_get(). 397 * 398 * Each service lcore to which the dispatcher is mapped should 399 * have at least one event port configured. Such configuration is 400 * performed by calling rte_dispatcher_bind_port_to_lcore(), prior to 401 * starting the dispatcher. 402 * 403 * @param dispatcher 404 * The dispatcher instance. 405 */ 406 __rte_experimental 407 void 408 rte_dispatcher_start(struct rte_dispatcher *dispatcher); 409 410 /** 411 * Stop a running dispatcher instance. 412 * 413 * Disables the dispatcher service. 414 * 415 * @param dispatcher 416 * The dispatcher instance. 417 */ 418 __rte_experimental 419 void 420 rte_dispatcher_stop(struct rte_dispatcher *dispatcher); 421 422 /** 423 * Retrieve statistics for a dispatcher instance. 424 * 425 * This function is MT safe and may be called by any thread 426 * (including unregistered non-EAL threads). 427 * 428 * @param dispatcher 429 * The dispatcher instance. 430 * @param[out] stats 431 * A pointer to a structure to fill with statistics. 432 */ 433 __rte_experimental 434 void 435 rte_dispatcher_stats_get(const struct rte_dispatcher *dispatcher, 436 struct rte_dispatcher_stats *stats); 437 438 /** 439 * Reset statistics for a dispatcher instance. 440 * 441 * This function may be called by any thread (including unregistered 442 * non-EAL threads), but may not produce the correct result if the 443 * dispatcher is running on any service lcore. 444 * 445 * @param dispatcher 446 * The dispatcher instance. 447 */ 448 __rte_experimental 449 void 450 rte_dispatcher_stats_reset(struct rte_dispatcher *dispatcher); 451 452 #ifdef __cplusplus 453 } 454 #endif 455 456 #endif /* RTE_DISPATCHER_H */ 457