Clarify that the reader MUST track the last sequence number read and that the 'start' offset is not involved in that. Some pre-conceptions + the sentence "the current state of the stream" threw me off for a while. Thanks Andy for explaining this to me. Signed-off-by: Marc Herbert <marc.herbert@intel.com>
96 lines
3.9 KiB
C
96 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2021 Intel Corporation
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#ifndef ZEPHYR_INCLUDE_SYS_WINSTREAM_H_
|
|
#define ZEPHYR_INCLUDE_SYS_WINSTREAM_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
/** @brief Lockless shared memory byte stream IPC
|
|
*
|
|
* The sys_winstream utility implements a unidirectional byte stream
|
|
* with simple read/write semantics on top of a memory region shared
|
|
* by the writer and reader. It requires no locking or
|
|
* synchronization mechanisms beyond reliable ordering of memory
|
|
* operations, and so is a good fit for use with heterogenous shared
|
|
* memory environments (for example, where Zephyr needs to talk to
|
|
* other CPUs in the system running their own software).
|
|
*
|
|
* This object does not keep track of the last sequence number read: the
|
|
* reader must keep that state and provide it on every read
|
|
* operation. After reaching "steady state", 'end' and 'start' are one
|
|
* byte apart because the buffer is always full.
|
|
*/
|
|
struct sys_winstream {
|
|
uint32_t len; /* Length of data[] in bytes */
|
|
uint32_t start; /* Index of first valid byte in data[] */
|
|
uint32_t end; /* Index of next byte in data[] to write */
|
|
uint32_t seq; /* Mod-2^32 index of 'end' since stream init */
|
|
uint8_t data[];
|
|
};
|
|
|
|
/** @brief Construct a sys_winstream from a region of memory
|
|
*
|
|
* This function initializes a sys_winstream in an arbitrarily-sized
|
|
* region of memory, returning the resulting object (which is
|
|
* guaranteed to be at the same address as the buffer). The memory
|
|
* must (obviously) be shared between the reader and writer, and all
|
|
* operations to it must be coherent and consistently ordered.
|
|
*
|
|
* @param buf Pointer to a region of memory to contain the stream
|
|
* @param buflen Length of the buffer, must be large enough to contain
|
|
* the struct sys_winstream and at least one byte of
|
|
* data.
|
|
* @return A pointer to an initialized sys_winstream (same address as
|
|
* the buf parameter).
|
|
*/
|
|
static inline struct sys_winstream *sys_winstream_init(void *buf, int buflen)
|
|
{
|
|
struct sys_winstream *ws = buf, tmp = { .len = buflen - sizeof(*ws) };
|
|
|
|
*ws = tmp;
|
|
return ws;
|
|
}
|
|
|
|
/** @brief Write bytes to a sys_winstream
|
|
*
|
|
* This function writes the specified number of bytes into the stream.
|
|
* It will always return synchronously, it does not block or engage in
|
|
* any kind of synchronization beyond memory write ordering. Any
|
|
* bytes passed beyond what can be stored in the buffer will be
|
|
* silently dropped, but readers can detect their presence via the
|
|
* sequence number.
|
|
*
|
|
* @param ws A sys_winstream to which to write
|
|
* @param data Pointer to bytes to be written
|
|
* @param len Number of bytes to write
|
|
*/
|
|
void sys_winstream_write(struct sys_winstream *ws,
|
|
const char *data, uint32_t len);
|
|
|
|
/** @brief Read bytes from a sys_winstream
|
|
*
|
|
* This function will read bytes from a sys_winstream into a specified
|
|
* buffer. It will always return in constant time, it does not block
|
|
* or engage in any kind of synchronization beyond memory ordering.
|
|
* The number of bytes read into the buffer will be returned, but note
|
|
* that it is possible that an underflow can occur if the writer gets
|
|
* ahead of our context. That situation can be detected via the
|
|
* sequence number returned via a pointer (i.e. if "*seq != old_seq +
|
|
* return_value", an underflow occurred and bytes were dropped).
|
|
*
|
|
* @param ws A sys_winstream from which to read
|
|
* @param seq A pointer to an integer containing the last sequence
|
|
* number read from the stream, or zero to indicate "start
|
|
* of stream". It is updated in place and returned for
|
|
* future calls and for detecting underflows.
|
|
* @param buf A buffer into which to store the data read
|
|
* @param buflen The length of buf in bytes
|
|
* @return The number of bytes written into the buffer
|
|
*/
|
|
uint32_t sys_winstream_read(struct sys_winstream *ws,
|
|
uint32_t *seq, char *buf, uint32_t buflen);
|
|
|
|
#endif /* ZEPHYR_INCLUDE_SYS_WINSTREAM_H_ */
|