diff options
author | David Robillard <d@drobilla.net> | 2022-08-11 22:21:09 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-08-18 12:20:37 -0400 |
commit | f8020557901a30245a7bdcecd3c0586bbe8760c2 (patch) | |
tree | fdee2ffc8b9667b851ef2df575228ad98133b180 /include/zix | |
parent | b57d596a38b7d3d075a0ae48df3b3472ab6227b4 (diff) | |
download | zix-f8020557901a30245a7bdcecd3c0586bbe8760c2.tar.gz zix-f8020557901a30245a7bdcecd3c0586bbe8760c2.tar.bz2 zix-f8020557901a30245a7bdcecd3c0586bbe8760c2.zip |
Add transactional ring API
Diffstat (limited to 'include/zix')
-rw-r--r-- | include/zix/ring.h | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/include/zix/ring.h b/include/zix/ring.h index ae4b6c4..872f963 100644 --- a/include/zix/ring.h +++ b/include/zix/ring.h @@ -6,6 +6,7 @@ #include "zix/allocator.h" #include "zix/attributes.h" +#include "zix/common.h" #include <stdint.h> @@ -29,6 +30,20 @@ extern "C" { typedef struct ZixRingImpl ZixRing; /** + A transaction for writing data in multiple parts. + + The simple zix_ring_write() can be used to write an atomic message that will + immediately be visible to the reader, but transactions allow data to be + written in several chunks before being "committed" and becoming readable. + This can be useful for things like prefixing messages with a header without + needing an allocated buffer to construct the "packet". +*/ +typedef struct { + uint32_t read_head; ///< Read head at the start of the transaction + uint32_t write_head; ///< Write head if the transaction were committed +} ZixRingTransaction; + +/** Create a new ring. @param size Size in bytes (note this may be rounded up). @@ -131,6 +146,64 @@ zix_ring_write(ZixRing* ZIX_NONNULL ring, uint32_t size); /** + Begin a write. + + The returned transaction is initially empty. Data can be written to it by + calling zix_ring_amend_write() one or more times, then finishing with + zix_ring_commit_write(). + + Note that the returned "transaction" is not meant to be long-lived: a call + to this function should be (more or less) immediately followed by calls to + zix_ring_amend_write() then a call to zix_ring_commit_write(). + + @param ring The ring to write data to. + @return A new empty transaction. +*/ +ZixRingTransaction +zix_ring_begin_write(ZixRing* ZIX_NONNULL ring); + +/** + Amend the current write with some data. + + The data is written immediately after the previously amended data, as if + they were written contiguously with a single write call. This data is not + visible to the reader until zix_ring_commit_write() is called. + + If any call to this function returns an error, then the transaction is + invalid and must not be committed. No cleanup is necessary for an invalid + transaction. Any bytes written while attempting the transaction will remain + in the free portion of the buffer and be overwritten by subsequent writes. + + @param ring The ring this transaction is writing to. + @param tx The active transaction, from zix_ring_begin_write(). + @param src Pointer to the data to write. + @param size Length of data to write in bytes. + @return #ZIX_STATUS_NO_MEM or #ZIX_STATUS_SUCCESS. +*/ +ZixStatus +zix_ring_amend_write(ZixRing* ZIX_NONNULL ring, + ZixRingTransaction* ZIX_NONNULL tx, + const void* ZIX_NONNULL src, + uint32_t size); + +/** + Commit the current write. + + This atomically updates the state of the ring, so that the reader will + observe the data written during the transaction. + + This function usually shouldn't be called for any transaction which + zix_ring_amend_write() returned an error for. + + @param ring The ring this transaction is writing to. + @param tx The active transaction, from zix_ring_begin_write(). + @return #ZIX_STATUS_SUCCESS. +*/ +ZixStatus +zix_ring_commit_write(ZixRing* ZIX_NONNULL ring, + const ZixRingTransaction* ZIX_NONNULL tx); + +/** @} @} */ |