I'm writing an embedded control system in C that consists of multiple tasks that send messages to each other (a fairly common idiom, I believe!), but I'm having a hard time designing a mechanism which:
- is neat
- is generic
- is relatively efficient
- most importantly: is platform independent (specifically, doesn't violate strict-aliasing or alignment issues)
Conceptually, I'd like to represent each message type as a separate struct definition, and I'd like a system with the following functions (simplified):
void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
void *dequeueMsg(queue_t *pQueue);
where a queue_t
comprises a linked list of nodes, each with a char buf[MAX_SIZE]
field. The system I'm on doesn't have a malloc()
implementation, so there'll need to be a global pool of free nodes, and then one of the following (perceived issues in bold):
sendMsg()
does amemcpy
of the incoming message into the buffer of a free node.
My understanding is that this will have alignment issues unless the caller ofdequeueMsg()
does a furthermemcpy
on the return value.- or there'll be a
void *getFreeBuffer()
function which returns thebuf[]
of the next free node, which the caller (the sender) will cast to the appropriate pointer-to-type.
My understanding is that this will now have alignment issues on the way in, and still requires amemcpy
afterdequeueMsg()
to avoid alignment issues on the way out. - or redefine the buffer in
queue_t
nodes as (e.g.)uint32_t buf[MAX_SIZE]
.
My understanding is that this violates strict aliasing, and isn't platform-independent.
The only other option I can see is to create a union of all the message types along with char buf[MAX_SIZE]
, but I don't count this as "neat"!
So my question is, how does one do this properly?