Emitting events
Emitting an event is two steps: build a MessagePack payload, then hand it and an event type to the kernel. This guide shows both; event.h and msgpack.h are the full references. Emitting requires SeAuditPrivilege.
Build the payload #
Use the MessagePack writer to encode a single top-level value — typically a map of fields:
peios_mp_writer *w = ;
; /* {"user":…, "ok":…} */
; ;
; ;
const void *payload;
ssize_t plen = ; /* validates as it borrows */
if
peios_mp_writer_bytes validates that what you built is exactly one well-formed value, so a non-negative return means the payload is emit-ready. (Remember a map of n needs 2*n values — one per key and value.)
Emit it #
int rc = ;
;
if
The event type is length-counted UTF-8 and must be non-zero length ("my.app.login" is 12 bytes — not NUL-terminated on the wire). On success the kernel stamps the trusted metadata (timestamp, sequence, identity GUIDs) and sets origin_class = userspace; you don't provide any of that.
Validating untrusted payloads first #
If a payload's shape comes from dynamic or untrusted input, validate it in userspace before emitting so you handle the failure on your terms rather than as an EINVAL from the kernel:
if
The validator's acceptance matches the kernel's emit-time check at that depth bound.
Emitting in batches #
A high-rate producer should batch. peios_event_emit_batch emits many events in one call, so a single timestamp capture, identity capture, and consumer wake cover the whole set:
struct peios_event_entry entries = ;
uint32_t emitted = 0;
int rc = ;
if
count must be in [1, KMES_BATCH_MAX_ENTRIES]. On failure, errno is the reason the first failing entry failed and emitted tells you how many succeeded before it, so you know exactly where to resume. One caveat: rate-limiting is all-or-nothing for a batch — an EAGAIN emits none of it, so on EAGAIN back off and retry the whole batch.
Next #
- Consuming events — the other side of the pipe.
msgpack.hreference — the full encoder, including containers, extensions, and raw splicing.