Skip to content

Commit

Permalink
add inplace io api
Browse files Browse the repository at this point in the history
  • Loading branch information
apache-hb committed Apr 20, 2024
1 parent 4c01e15 commit b917ba5
Show file tree
Hide file tree
Showing 15 changed files with 437 additions and 100 deletions.
4 changes: 4 additions & 0 deletions data/docs/contrib.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ When adding a new module consider how much of the compiler needs access to it. T
- Breaking source and ABI compatibility every commit is fine
- Once plugins are implemented maybe i'll rethink this

- If implementation details need to be leaked into headers suffix them with `_impl` and namespace them
* `io_buffer_impl_t` instead of `buffer_t`
* `os_read_impl` instead of `inner_read`

## Memory management strategy

Cthulhu aims to be usable as a library in embedded systems (read as: places without global malloc).
Expand Down
32 changes: 29 additions & 3 deletions src/common/io/include/io/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

CT_BEGIN_API

/// @defgroup io_impl io implementation details
/// @brief internal io implementation details
/// @warning these are internal structures and should not be used directly
/// @ingroup io
/// @{

Expand Down Expand Up @@ -136,9 +139,6 @@ typedef struct io_t
char data[];
} io_t;

// TODO: io_data and io_new should be private to the io module
// currently not due to the fs module

/// @brief get the user data from an io object
/// @warning does not perform any validation on the type of the user data
///
Expand All @@ -151,6 +151,8 @@ CT_IO_API void *io_data(IN_NOTNULL io_t *io);
/// @brief create a new IO object for a given interface
/// @pre @p cb must point to a valid callback set
/// @pre @p data must point to a valid memory region of @p cb->size bytes. if @p cb->size is 0, @p data may be NULL
/// @pre @p name must be a valid string
/// @pre @p arena must be a valid arena
///
/// @param cb the callback set
/// @param flags the access flags for this object
Expand All @@ -166,6 +168,30 @@ CT_IO_API io_t *io_new(
IN_READS(size) const void *data,
IN_NOTNULL arena_t *arena);

/// @brief initialize an IO object for a given interface
/// @note this initializes the object in place
/// @note if the io object does not require allocation, @p arena may be NULL
///
/// @pre @p buffer must point to a valid memory region of at least @c sizeof(io_t) + @p cb->size bytes
/// @pre @p cb must point to a valid callback set
/// @pre @p data must point to a valid memory region of @p cb->size bytes. if @p cb->size is 0, @p data may be NULL
///
/// @param buffer the buffer to initialize the io object in
/// @param cb the callback set
/// @param flags the access flags for this object
/// @param name the name of the object
/// @param data the user data, this is copied into the io object
/// @param arena the arena to allocate the io object from
///
/// @return the initialized IO interface
CT_IO_API io_t *io_init(
OUT_WRITES(sizeof(io_t) + cb->size) void *buffer,
IN_NOTNULL const io_callbacks_t *cb,
os_access_t flags,
IN_STRING const char *name,
IN_READS(size) const void *data,
arena_t *arena);

/// @}

CT_END_API
33 changes: 33 additions & 0 deletions src/common/io/include/io/impl/buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once

// for sizeof(io_t)
#include "io/impl.h" // IWYU pragma: export

CT_BEGIN_API

/// @ingroup io_impl
/// @{

/// @brief a read/write in memory file
/// @warning this is an internal structure and should not be used directly
typedef struct io_buffer_impl_t
{
/// @brief stored data
char *data;

/// @brief used data
size_t used;

/// @brief total size of data
size_t total;

/// @brief current offset in data
size_t offset;
} io_buffer_impl_t;

#define IO_BUFFER_SIZE (sizeof(io_buffer_impl_t) + sizeof(io_t))

/// @}

CT_END_API
29 changes: 29 additions & 0 deletions src/common/io/include/io/impl/file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once

// for sizeof(io_t)
#include "io/impl.h" // IWYU pragma: export

#include "os/os.h"

CT_BEGIN_API

/// @ingroup io_impl
/// @{

/// @brief a file descriptor
/// @warning this is an internal structure and should not be used directly
typedef struct io_file_impl_t
{
/// @brief native file descriptor
os_file_t file;

/// @brief memory mapping
os_mapping_t mapping;
} io_file_impl_t;

#define IO_FILE_SIZE (sizeof(io_file_impl_t) + sizeof(io_t))

/// @}

CT_END_API
30 changes: 30 additions & 0 deletions src/common/io/include/io/impl/view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once

// for sizeof(io_t)
#include "io/impl.h" // IWYU pragma: export

CT_BEGIN_API

/// @ingroup io_impl
/// @{

/// @brief a non-owning, readonly view of a buffer
/// @warning this is an internal structure and should not be used directly
typedef struct io_view_impl_t
{
/// @brief pointer to data
const char *data;

/// @brief size of data
size_t size;

/// @brief current offset in data
size_t offset;
} io_view_impl_t;

#define IO_VIEW_SIZE (sizeof(io_view_impl_t) + sizeof(io_t))

/// @}

CT_END_API
108 changes: 103 additions & 5 deletions src/common/io/include/io/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,21 @@ typedef struct io_t io_t;
/// @brief an io error code
typedef os_error_t io_error_t;

/// @brief destroy an IO object and free its memory
///
/// @param io the io object
///
/// @return an error code if the io object could not be closed
CT_IO_API io_error_t io_free(OUT_PTR_INVALID io_t *io);

/// @brief destroy an IO object
/// @warning this does not free the memory of the object itself
/// This should only be used when the io object is allocated on the stack and initialized
/// with an io_*_init function.
///
/// @param io the io object
///
/// @return an error code if the object could not be destroyed
CT_IO_API io_error_t io_close(OUT_PTR_INVALID io_t *io);

/// @brief create an IO object from a file
Expand All @@ -33,7 +45,7 @@ CT_IO_API io_error_t io_close(OUT_PTR_INVALID io_t *io);
/// @param arena the arena to allocate from
///
/// @return the io object, or NULL on error
CT_NODISCARD CT_ALLOC(io_close)
CT_NODISCARD CT_ALLOC(io_free)
CT_IO_API io_t *io_file(IN_STRING const char *path, os_access_t mode, IN_NOTNULL arena_t *arena);

/// @brief create an IO object from an initial view of memory
Expand All @@ -46,7 +58,7 @@ CT_IO_API io_t *io_file(IN_STRING const char *path, os_access_t mode, IN_NOTNULL
/// @param arena the arena to allocate from
///
/// @return the io object
CT_NODISCARD CT_ALLOC(io_close)
CT_NODISCARD CT_ALLOC(io_free)
CT_IO_API io_t *io_memory(IN_STRING const char *name, const void *data, size_t size, os_access_t flags, IN_NOTNULL arena_t *arena);

/// @brief create an IO object in memory of a given size
Expand All @@ -58,7 +70,7 @@ CT_IO_API io_t *io_memory(IN_STRING const char *name, const void *data, size_t s
/// @param arena the arena to allocate from
///
/// @return the io object
CT_NODISCARD CT_ALLOC(io_close)
CT_NODISCARD CT_ALLOC(io_free)
CT_IO_API io_t *io_blob(IN_STRING const char *name, size_t size, os_access_t flags, IN_NOTNULL arena_t *arena);

/// @brief create a readonly IO object for a given view of memory
Expand All @@ -70,7 +82,7 @@ CT_IO_API io_t *io_blob(IN_STRING const char *name, size_t size, os_access_t fla
/// @param arena the arena to allocate from
///
/// @return the IO view
CT_NODISCARD CT_ALLOC(io_close)
CT_NODISCARD CT_ALLOC(io_free)
CT_IO_API io_t *io_view(IN_STRING const char *name, IN_NOTNULL const void *data, size_t size, IN_NOTNULL arena_t *arena);

/// @brief create an IO view of a string
Expand All @@ -81,9 +93,95 @@ CT_IO_API io_t *io_view(IN_STRING const char *name, IN_NOTNULL const void *data,
/// @param arena the arena to allocate from
///
/// @return the io object
CT_NODISCARD CT_ALLOC(io_close)
CT_NODISCARD CT_ALLOC(io_free)
CT_IO_API io_t *io_string(IN_STRING const char *name, IN_STRING const char *string, IN_NOTNULL arena_t *arena);

/// @brief create an io object from a file
/// initializes an io object using a preallocated buffer.
/// @note the buffer must be available for the lifetime of the io object.
/// ending the lifetime of the buffer before the io object will result in undefined behavior.
///
/// @pre @p buffer must be at least @ref IO_FILE_SIZE bytes large
/// @pre @p buffer must be aligned to @c alignof(io_t)
///
/// @param buffer the buffer to use for the io object
/// @param path the path to the file
/// @param mode the access mode of the file
///
/// @return the initialized io object
CT_NODISCARD CT_ALLOC(io_close)
CT_IO_API io_t *io_file_init(OUT_WRITES(IO_FILE_SIZE) void *buffer, IN_STRING const char *path, os_access_t mode);

/// @brief create an io object from a memory buffer
/// initializes an io object using a preallocated buffer.
/// @note the buffer must be available for the lifetime of the io object.
/// ending the lifetime of the buffer before the io object will result in undefined behavior.
///
/// @pre @p buffer must be at least @ref IO_MEMORY_SIZE bytes large
/// @pre @p buffer must be aligned to @c alignof(io_t)
///
/// @param buffer the buffer to use for the io object
/// @param name the name of the io block
/// @param data the data to copy into the initial buffer
/// @param size the size of the data
/// @param flags the access mode of the file
/// @param arena the arena to allocate from
///
/// @return the initialized io object
CT_NODISCARD CT_ALLOC(io_close)
CT_IO_API io_t *io_memory_init(OUT_WRITES(IO_MEMORY_SIZE) void *buffer, IN_STRING const char *name, const void *data, size_t size, os_access_t flags, IN_NOTNULL arena_t *arena);

/// @brief create an io object from a memory buffer
/// initializes an io object using a preallocated buffer.
/// @note the buffer must be available for the lifetime of the io object.
/// ending the lifetime of the buffer before the io object will result in undefined behavior.
///
/// @pre @p buffer must be at least @ref IO_MEMORY_SIZE bytes large
/// @pre @p buffer must be aligned to @c alignof(io_t)
///
/// @param buffer the buffer to use for the io object
/// @param name the name of the io object
/// @param size the starting size of the buffer
/// @param flags the access mode
/// @param arena the arena to allocate from
///
/// @return the initialized io object
CT_NODISCARD CT_ALLOC(io_close)
CT_IO_API io_t *io_blob_init(OUT_WRITES(IO_MEMORY_SIZE) void *buffer, IN_STRING const char *name, size_t size, os_access_t flags, IN_NOTNULL arena_t *arena);

/// @brief create an io object from a memory buffer
/// initializes an io object using a preallocated buffer.
/// @note the buffer must be available for the lifetime of the io object.
/// ending the lifetime of the buffer before the io object will result in undefined behavior.
///
/// @pre @p buffer must be at least @ref IO_VIEW_SIZE bytes large
/// @pre @p buffer must be aligned to @c alignof(io_t)
///
/// @param buffer the buffer to use for the io object
/// @param name the name of the IO view
/// @param data the data to provide in the view
/// @param size the size of the data
///
/// @return the initialized io object
CT_NODISCARD CT_ALLOC(io_close)
CT_IO_API io_t *io_view_init(OUT_WRITES(IO_VIEW_SIZE) void *buffer, IN_STRING const char *name, IN_NOTNULL const void *data, size_t size);

/// @brief create an io object from a memory buffer
/// initializes an io object using a preallocated buffer.
/// @note the buffer must be available for the lifetime of the io object.
/// ending the lifetime of the buffer before the io object will result in undefined behavior.
///
/// @pre @p buffer must be at least @ref IO_VIEW_SIZE bytes large
/// @pre @p buffer must be aligned to @c alignof(io_t)
///
/// @param buffer the buffer to use for the io object
/// @param name the name of the IO view
/// @param string the backing string view
///
/// @return the initialized io object
CT_NODISCARD CT_ALLOC(io_close)
CT_IO_API io_t *io_string_init(OUT_WRITES(IO_VIEW_SIZE) void *buffer, IN_STRING const char *name, IN_STRING const char *string);

/// @brief read from an io object
/// @pre the io object must have been created with the @a eOsAccessRead flag
///
Expand Down
Loading

0 comments on commit b917ba5

Please sign in to comment.