Skip to content

Commit

Permalink
kernel: Rewrite k_pipe_* API
Browse files Browse the repository at this point in the history
The `k_pipe_*` API has been reworked to provide a more consistent and
intuitive interface. The new API aims to provide a simple to use byte
stream interface that is more in line with the POSIX pipe API.
The previous API has been deprecated and will be removed in a future
release.

Signed-off-by: Måns Ansgariusson <[email protected]>
  • Loading branch information
Mattemagikern committed Dec 21, 2024
1 parent 088afe9 commit 1357469
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 17 deletions.
131 changes: 130 additions & 1 deletion include/zephyr/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <zephyr/tracing/tracing_macros.h>
#include <zephyr/sys/mem_stats.h>
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/sys/ring_buffer.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -4971,6 +4972,7 @@ void k_mbox_data_get(struct k_mbox_msg *rx_msg, void *buffer);
* @{
*/

#ifdef CONFIG_PIPES
/** Pipe Structure */
struct k_pipe {
unsigned char *buffer; /**< Pipe buffer: may be NULL */
Expand Down Expand Up @@ -5041,6 +5043,7 @@ struct k_pipe {
Z_PIPE_INITIALIZER(name, _k_pipe_buf_##name, pipe_buffer_size)

/**
* @deprecated
* @brief Initialize a pipe.
*
* This routine initializes a pipe object, prior to its first use.
Expand All @@ -5054,6 +5057,7 @@ struct k_pipe {
void k_pipe_init(struct k_pipe *pipe, unsigned char *buffer, size_t size);

/**
* @deprecated
* @brief Release a pipe's allocated buffer
*
* If a pipe object was given a dynamically allocated buffer via
Expand All @@ -5067,6 +5071,7 @@ void k_pipe_init(struct k_pipe *pipe, unsigned char *buffer, size_t size);
int k_pipe_cleanup(struct k_pipe *pipe);

/**
* @deprecated
* @brief Initialize a pipe and allocate a buffer for it
*
* Storage for the buffer region will be allocated from the calling thread's
Expand All @@ -5084,6 +5089,7 @@ int k_pipe_cleanup(struct k_pipe *pipe);
__syscall int k_pipe_alloc_init(struct k_pipe *pipe, size_t size);

/**
* @deprecated
* @brief Write data to a pipe.
*
* This routine writes up to @a bytes_to_write bytes of data to @a pipe.
Expand All @@ -5106,6 +5112,7 @@ __syscall int k_pipe_put(struct k_pipe *pipe, const void *data,
size_t min_xfer, k_timeout_t timeout);

/**
* @deprecated
* @brief Read data from a pipe.
*
* This routine reads up to @a bytes_to_read bytes of data from @a pipe.
Expand All @@ -5129,6 +5136,7 @@ __syscall int k_pipe_get(struct k_pipe *pipe, void *data,
size_t min_xfer, k_timeout_t timeout);

/**
* @deprecated
* @brief Query the number of bytes that may be read from @a pipe.
*
* @param pipe Address of the pipe.
Expand All @@ -5139,6 +5147,7 @@ __syscall int k_pipe_get(struct k_pipe *pipe, void *data,
__syscall size_t k_pipe_read_avail(struct k_pipe *pipe);

/**
* @deprecated
* @brief Query the number of bytes that may be written to @a pipe
*
* @param pipe Address of the pipe.
Expand All @@ -5149,6 +5158,7 @@ __syscall size_t k_pipe_read_avail(struct k_pipe *pipe);
__syscall size_t k_pipe_write_avail(struct k_pipe *pipe);

/**
* @deprecated
* @brief Flush the pipe of write data
*
* This routine flushes the pipe. Flushing the pipe is equivalent to reading
Expand All @@ -5161,6 +5171,7 @@ __syscall size_t k_pipe_write_avail(struct k_pipe *pipe);
__syscall void k_pipe_flush(struct k_pipe *pipe);

/**
* @deprecated
* @brief Flush the pipe's internal buffer
*
* This routine flushes the pipe's internal buffer. This is equivalent to
Expand All @@ -5175,10 +5186,128 @@ __syscall void k_pipe_buffer_flush(struct k_pipe *pipe);

/** @} */

#else /* CONFIG_PIPES */

enum pipe_flags {
PIPE_FLAG_OPEN = BIT(0),
PIPE_FLAG_RESET = BIT(1),
PIPE_FLAG_FULL = BIT(2),
};

struct k_pipe {
size_t waiting;
struct ring_buf buf;
struct k_spinlock lock;
_wait_q_t data;
_wait_q_t space;
uint8_t flags;
};

#define Z_PIPE_INITIALIZER(obj, pipe_buffer, pipe_buffer_size) \
{ \
.flags = 0, \
.waiting = 0, \
.buf = RING_BUF_INIT(pipe_buffer, pipe_buffer_size), \
.lock = {}, \
.data = Z_WAIT_Q_INIT(&obj.data), \
.space = Z_WAIT_Q_INIT(&obj.space), \
}

/**
* @cond INTERNAL_HIDDEN
* INTERNAL_HIDDEN @endcond
*/

/**
* @brief Statically define and initialize a pipe.
*
* The pipe can be accessed outside the module where it is defined using:
*
* @code extern struct k_pipe <name>; @endcode
*
* @param name Name of the pipe.
* @param pipe_buffer_size Size of the pipe's ring buffer (in bytes).
* @param pipe_align Alignment of the pipe's ring buffer (power of 2).
*
*/
#define K_PIPE_DEFINE(name, pipe_buffer_size, pipe_align) \
static unsigned char __noinit __aligned(pipe_align) \
_k_pipe_buf_##name[pipe_buffer_size]; \
STRUCT_SECTION_ITERABLE(k_pipe, name) = \
Z_PIPE_INITIALIZER(name, _k_pipe_buf_##name, pipe_buffer_size)

/**
* @brief initialize a pipe
*
* This routine initializes a pipe object, prior to its first use.
*
* @param pipe Address of the pipe.
* @param buffer Address of the pipe's buffer.
* @param buffer_size Size of the pipe's buffer.
*/
__syscall void k_pipe_init(struct k_pipe *pipe, uint8_t *buffer, size_t buffer_size);

/**
* @brief Write data to a pipe
*
* This routine writes up to @a len bytes of data to @a pipe.
* If the pipe is full, the routine will block until the data can be written or the timeout expires.
*
* @param pipe Address of the pipe.
* @param data Address of data to write.
* @param len Size of data (in bytes).
* @param timeout Waiting period to wait for the data to be written.
*
* @retval 0 on success
* @retval -EAGAIN if the data could not be written before the timeout expired
* @retval -ECANCELED if the write was interrupted by eg. k_pipe_flush(..)
* @retval -EPIPE if the pipe was closed
*/
__syscall int k_pipe_write(struct k_pipe *pipe, const uint8_t *data, size_t len,
k_timeout_t timeout);

/**
* @brief Read data from a pipe
* This routine reads up to @a len bytes of data from @a pipe.
* If the pipe is empty, the routine will block until the data can be read or the timeout expires.
*
* @param pipe Address of the pipe.
* @param data Address to place the data read from pipe.
* @param len Requested number of bytes to read.
* @param timeout Waiting period to wait for the data to be read.
*
* @retval number of bytes read on success
* @retval -EAGAIN if the data could not be read before the timeout expired
* @retval -ECANCELED if the read was interrupted by eg. k_pipe_flush(..)
* @retval -EPIPE if the pipe was closed
*/
__syscall int k_pipe_read(struct k_pipe *pipe, uint8_t *data, size_t len,
k_timeout_t timeout);

/**
* @brief Reset the pipe
*
* This routine resets the internal state of the pipe and any
* writers or readers that were previously pended become unpended.
*
* @param pipe Address of the pipe.
*/
__syscall int k_pipe_reset(struct k_pipe *pipe);

/**
* @brief Close a pipe
*
* This routine closes a pipe. Any threads that were blocked on the pipe
* will be unblocked and receive an error code.
*
* @param pipe Address of the pipe.
* @retval 0 on success
*/
__syscall int k_pipe_close(struct k_pipe *pipe);
#endif /* CONFIG_PIPES */

/**
* @cond INTERNAL_HIDDEN
*/
struct k_mem_slab_info {
uint32_t num_blocks;
size_t block_size;
Expand Down
19 changes: 12 additions & 7 deletions include/zephyr/sys/ring_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

#ifndef ZEPHYR_INCLUDE_SYS_RING_BUFFER_H_
#define ZEPHYR_INCLUDE_SYS_RING_BUFFER_H_

#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <errno.h>

Expand Down Expand Up @@ -61,7 +59,17 @@ static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
buf->put_head = buf->put_tail = buf->put_base = value;
buf->get_head = buf->get_tail = buf->get_base = value;
}

#define RING_BUF_INIT(buf, size8) \
{ \
.buffer = buf, \
.size = size8, \
.put_head = 0, \
.put_tail = 0, \
.put_base = 0, \
.get_head = 0, \
.get_tail = 0, \
.get_base = 0 \
}
/**
* @brief Define and initialize a ring buffer for byte data.
*
Expand All @@ -80,10 +88,7 @@ static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
BUILD_ASSERT(size8 < RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint8_t __noinit _ring_buffer_data_##name[size8]; \
struct ring_buf name = { \
.buffer = _ring_buffer_data_##name, \
.size = size8 \
}
struct ring_buf name = RING_BUF_INIT(_ring_buffer_data_##name, size8)

/**
* @brief Define and initialize an "item based" ring buffer.
Expand Down
4 changes: 4 additions & 0 deletions kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ list(APPEND kernel_files
thread.c
sched.c
)
# FIXME: Once the prior pipe implementation is removed, this should be included in the above list
if(NOT CONFIG_PIPES)
list(APPEND kernel_files pipe.c)
endif() # NOT CONFIG_PIPES
if(CONFIG_SMP)
list(APPEND kernel_files
smp.c
Expand Down
Loading

0 comments on commit 1357469

Please sign in to comment.