/* * Copyright (c) 2018-2019 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Upstream site with license notes : * http://git.sceen.net/rbraun/librbraun.git/ * * * FIFO message buffer. */ #ifndef KERN_MBUF_H #define KERN_MBUF_H #include #include #include /* * Message buffer. * * Message buffers are built on top of circular byte buffers. They provide * discrete message transfer from a producer to a consumer. * * The order is computed from the maximum message size, and is used to * determine a header size that can represent up to 2^order - 1 bytes. */ struct mbuf { struct cbuf cbuf; size_t max_msg_size; unsigned int order; }; static inline size_t mbuf_start(const struct mbuf *mbuf) { return cbuf_start(&mbuf->cbuf); } static inline size_t mbuf_end(const struct mbuf *mbuf) { return cbuf_end(&mbuf->cbuf); } /* * Initialize a message buffer. * * The descriptor is set to use the given buffer for storage. Capacity * must be a power-of-two. */ void mbuf_init(struct mbuf *mbuf, void *buf, size_t capacity, size_t max_msg_size); /* * Clear a message buffer. */ void mbuf_clear(struct mbuf *mbuf); /* * Push a message to a message buffer. * * If the message doesn't fit in the message buffer, either because it is * larger than the capacity, or because the function isn't allowed to erase * old messages and the message buffer doesn't have enough available memory * for the new message, EMSGSIZE is returned. If the message is larger than * the maximum message size, EINVAL is returned. */ int mbuf_push(struct mbuf *mbuf, const void *buf, size_t size, bool erase); /* * Pop a message from a message buffer. * * On entry, the sizep argument points to the size of the output buffer. * On return, it is updated to the size of the message. If the message * doesn't fit in the output buffer, it is not popped, EMSGSIZE is * returned, but the sizep argument is updated nonetheless to let the * user know the message size, to potentially retry with a larger buffer. * * If the buffer is empty, EAGAIN is returned, and the size of the output * buffer is unmodified. * * The output buffer may be NULL, in which case this function acts as if * it wasn't, but without writing output data. */ int mbuf_pop(struct mbuf *mbuf, void *buf, size_t *sizep); /* * Read a message from a message buffer. * * On entry, the indexp argument points to the index of the message to * read in the message buffer, and the sizep argument points to the size * of the output buffer. On return, if successful, indexp is updated * to the index of the next message, and sizep to the size of the * message read. * * If the message doesn't fit in the output buffer, it is not read, * EMSGSIZE is returned, and the sizep argument is updated nonetheless * to let the user know the message size, to potentially retry with a * larger buffer. * * If the given index refers to the end of the buffer, then EAGAIN is * returned. If it's outside buffer boundaries, EINVAL is returned. * Otherwise, if it doesn't point to the beginning of a message, the * behavior is undefined. * * The message buffer isn't changed by this operation. */ int mbuf_read(const struct mbuf *mbuf, size_t *indexp, void *buf, size_t *sizep); #endif /* KERN_MBUF_H */