| /* Copyright (c) 2015 Google Inc. | 
 |  * Barret Rhoden <brho@cs.berkeley.edu> | 
 |  * See LICENSE for details. | 
 |  * | 
 |  * Coalescing Event Queue: encapuslates the essence of epoll/kqueue in shared | 
 |  * memory: a dense array of sticky status bits. | 
 |  * | 
 |  * Like all event mailboxes, CEQs are multi-producer, multi-consumer, with the | 
 |  * producer not trusting the consumer. | 
 |  * | 
 |  * The producer sends ceq_events with a certain ID (the ev_type).  Events of a | 
 |  * particular ID are coalesced in one spot, such that N events can occur and the | 
 |  * consumer only receives them as one event.  These are the "sticky status | 
 |  * bits".  For example, setting flags in an int coalesce (you can set the same | 
 |  * flag repeatedly, and it's still set), and an atomic counter coalesces small | 
 |  * increments into a larger value.  The nature of the operation (atomic_or, | 
 |  * atomic_add) depends on a field in the CEQ.  There is also a data blob field, | 
 |  * last-write-wins.  There aren't a lot of guarantees associated with it, but | 
 |  * it's still useful for some apps. | 
 |  * | 
 |  * Internally, a CEQ maintains an array of ceq_event structs for every possible | 
 |  * ID, so the maximum ID should be known at ceq creation time.  These structs | 
 |  * coalesce the events.  To keep the consumer from needing to scan the array for | 
 |  * activity, there is a separate ring buffer that contains the indices of | 
 |  * ceq_events with activity.  This is the "dense array." | 
 |  * | 
 |  * The ring buffer is actually an optimization.  If anything goes wrong, we can | 
 |  * tell the consumer to scan the entire array.  Likewise, spurious entries in | 
 |  * the ring are safe; the consumer just does an extra check. | 
 |  * | 
 |  * In general, every time we have an event, we make sure there's a pointer in | 
 |  * the ring.  That's the purposed of 'idx_posted' - whether or not we think our | 
 |  * index is posted in the ring. */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <ros/bits/event.h> | 
 | #include <ros/atomic.h> | 
 | #include <ros/ring_buffer.h> | 
 |  | 
 | #define CEQ_OR			1 | 
 | #define CEQ_ADD			2 | 
 |  | 
 | struct ceq_event { | 
 | 	atomic_t			coalesce;	/* ev_arg2 */ | 
 | 	uint64_t			blob_data;	/* ev_arg3 */ | 
 | 	bool				idx_posted;	/* syncing with cons */ | 
 | 	uint64_t			user_data; | 
 | }; | 
 |  | 
 | /* The events array and the ring buffer are provided by the consumer. | 
 |  * | 
 |  * Ring values are -1 for "unconsumed" and an index into *events otherwise. | 
 |  * | 
 |  * Similar to BCQs, the ring buffer must be a power of two and is managed with | 
 |  * three index variables: | 
 |  * | 
 |  * prod_idx:     the next slot to be produced | 
 |  * cons_pvt_idx: the next slot a consumer can claim | 
 |  * cons_pub_idx: the last slot (farthest left / oldest) that hasn't been | 
 |  *               consumed/made ready to be produced by the producer (it is | 
 |  *               what the consumer produces). | 
 |  * | 
 |  * The ring is has no new entries that need consumed when prod == pvt.   The | 
 |  * number of entries filled is prod - pub.  The number of available entries | 
 |  * (nr_empty) is the size - (prod - pub). */ | 
 |  | 
 | struct ceq { | 
 | 	struct ceq_event		*events;	/* consumer pointer */ | 
 | 	unsigned int			nr_events; | 
 | 	unsigned int			last_recovered; | 
 | 	atomic_t			max_event_ever; | 
 | 	int32_t				*ring;		/* consumer pointer */ | 
 | 	uint32_t			ring_sz;	/* size (power of 2) */ | 
 | 	uint8_t				operation;	/* e.g. CEQ_OR */ | 
 | 	bool				ring_overflowed; | 
 | 	bool				overflow_recovery; | 
 | 	atomic_t			prod_idx;	/* next slot to fill */ | 
 | 	atomic_t			cons_pub_idx;	/* consumed so far */ | 
 | 	atomic_t			cons_pvt_idx;	/* next slot to get */ | 
 | 	uint32_t			u_lock[2];	/* user space lock */ | 
 | }; |