diff options
author | sanine <sanine.not@pm.me> | 2022-08-27 23:52:56 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-08-27 23:52:56 -0500 |
commit | a4dd0ad63c00f4dee3b86dfd3075d1d61b2b3180 (patch) | |
tree | 13bd5bfa15e6fea2a12f176bae79adf9c6fd0933 /3rdparty/plibsys/src/pshmbuffer.c | |
parent | bde3e4f1bb7b8f8abca0884a7d994ee1c17a66b1 (diff) |
add plibsys
Diffstat (limited to '3rdparty/plibsys/src/pshmbuffer.c')
-rw-r--r-- | 3rdparty/plibsys/src/pshmbuffer.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/3rdparty/plibsys/src/pshmbuffer.c b/3rdparty/plibsys/src/pshmbuffer.c new file mode 100644 index 0000000..7bdbbd3 --- /dev/null +++ b/3rdparty/plibsys/src/pshmbuffer.c @@ -0,0 +1,334 @@ +/* + * The MIT License + * + * Copyright (C) 2010-2020 Alexander Saprykin <saprykin.spb@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pmem.h" +#include "pshm.h" +#include "pshmbuffer.h" + +#include <stdlib.h> +#include <string.h> + +#define P_SHM_BUFFER_READ_OFFSET 0 +#define P_SHM_BUFFER_WRITE_OFFSET sizeof (psize) +#define P_SHM_BUFFER_DATA_OFFSET sizeof (psize) * 2 + +struct PShmBuffer_ { + PShm *shm; + psize size; +}; + +static psize pp_shm_buffer_get_free_space (PShmBuffer *buf); +static psize pp_shm_buffer_get_used_space (PShmBuffer *buf); + +/* Warning: this function is not thread-safe, only for internal usage */ +static psize +pp_shm_buffer_get_free_space (PShmBuffer *buf) +{ + psize read_pos, write_pos; + ppointer addr; + + addr = p_shm_get_address (buf->shm); + + memcpy (&read_pos, (pchar *) addr + P_SHM_BUFFER_READ_OFFSET, sizeof (read_pos)); + memcpy (&write_pos, (pchar *) addr + P_SHM_BUFFER_WRITE_OFFSET, sizeof (write_pos)); + + if (write_pos < read_pos) + return read_pos - write_pos - 1; + else if (write_pos > read_pos) + return buf->size - (write_pos - read_pos) - 1; + else + return buf->size - 1; +} + +static psize +pp_shm_buffer_get_used_space (PShmBuffer *buf) +{ + psize read_pos, write_pos; + ppointer addr; + + addr = p_shm_get_address (buf->shm); + + memcpy (&read_pos, (pchar *) addr + P_SHM_BUFFER_READ_OFFSET, sizeof (read_pos)); + memcpy (&write_pos, (pchar *) addr + P_SHM_BUFFER_WRITE_OFFSET, sizeof (write_pos)); + + if (write_pos > read_pos) + return write_pos - read_pos; + else if (write_pos < read_pos) + return (buf->size - (read_pos - write_pos)); + else + return 0; +} + +P_LIB_API PShmBuffer * +p_shm_buffer_new (const pchar *name, + psize size, + PError **error) +{ + PShmBuffer *ret; + PShm *shm; + + if (P_UNLIKELY (name == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Invalid input argument"); + return NULL; + } + + if (P_UNLIKELY ((shm = p_shm_new (name, + (size != 0) ? size + P_SHM_BUFFER_DATA_OFFSET + 1 : 0, + P_SHM_ACCESS_READWRITE, + error)) == NULL)) + return NULL; + + if (P_UNLIKELY (p_shm_get_size (shm) <= P_SHM_BUFFER_DATA_OFFSET + 1)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Too small memory segment to hold required data"); + p_shm_free (shm); + return NULL; + } + + if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PShmBuffer))) == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_NO_RESOURCES, + 0, + "Failed to allocate memory for shared buffer"); + p_shm_free (shm); + return NULL; + } + + ret->shm = shm; + ret->size = p_shm_get_size (shm) - P_SHM_BUFFER_DATA_OFFSET; + + return ret; +} + +P_LIB_API void +p_shm_buffer_free (PShmBuffer *buf) +{ + if (P_UNLIKELY (buf == NULL)) + return; + + p_shm_free (buf->shm); + p_free (buf); +} + +P_LIB_API void +p_shm_buffer_take_ownership (PShmBuffer *buf) +{ + if (P_UNLIKELY (buf == NULL)) + return; + + p_shm_take_ownership (buf->shm); +} + +P_LIB_API pint +p_shm_buffer_read (PShmBuffer *buf, + ppointer storage, + psize len, + PError **error) +{ + psize read_pos, write_pos; + psize data_aval, to_copy; + puint i; + ppointer addr; + + if (P_UNLIKELY (buf == NULL || storage == NULL || len == 0)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Invalid input argument"); + return -1; + } + + if (P_UNLIKELY ((addr = p_shm_get_address (buf->shm)) == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Unable to get shared memory address"); + return -1; + } + + if (P_UNLIKELY (p_shm_lock (buf->shm, error) == FALSE)) + return -1; + + memcpy (&read_pos, (pchar *) addr + P_SHM_BUFFER_READ_OFFSET, sizeof (read_pos)); + memcpy (&write_pos, (pchar *) addr + P_SHM_BUFFER_WRITE_OFFSET, sizeof (write_pos)); + + if (read_pos == write_pos) { + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return 0; + } + + data_aval = pp_shm_buffer_get_used_space (buf); + to_copy = (data_aval <= len) ? data_aval : len; + + for (i = 0; i < to_copy; ++i) + memcpy ((pchar *) storage + i, + (pchar *) addr + P_SHM_BUFFER_DATA_OFFSET + ((read_pos + i) % buf->size), + 1); + + read_pos = (read_pos + to_copy) % buf->size; + memcpy ((pchar *) addr + P_SHM_BUFFER_READ_OFFSET, &read_pos, sizeof (read_pos)); + + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return (pint) to_copy; +} + +P_LIB_API pssize +p_shm_buffer_write (PShmBuffer *buf, + ppointer data, + psize len, + PError **error) +{ + psize read_pos, write_pos; + puint i; + ppointer addr; + + if (P_UNLIKELY (buf == NULL || data == NULL || len == 0)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Invalid input argument"); + return -1; + } + + if (P_UNLIKELY ((addr = p_shm_get_address (buf->shm)) == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Unable to get shared memory address"); + return -1; + } + + if (P_UNLIKELY (p_shm_lock (buf->shm, error) == FALSE)) + return -1; + + memcpy (&read_pos, (pchar *) addr + P_SHM_BUFFER_READ_OFFSET, sizeof (read_pos)); + memcpy (&write_pos, (pchar *) addr + P_SHM_BUFFER_WRITE_OFFSET, sizeof (write_pos)); + + if (pp_shm_buffer_get_free_space (buf) < len) { + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return 0; + } + + for (i = 0; i < len; ++i) + memcpy ((pchar *) addr + P_SHM_BUFFER_DATA_OFFSET + ((write_pos + i) % buf->size), + (pchar *) data + i, + 1); + + write_pos = (write_pos + len) % buf->size; + memcpy ((pchar *) addr + P_SHM_BUFFER_WRITE_OFFSET, &write_pos, sizeof (write_pos)); + + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return (pssize) len; +} + +P_LIB_API pssize +p_shm_buffer_get_free_space (PShmBuffer *buf, + PError **error) +{ + psize space; + + if (P_UNLIKELY (buf == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Invalid input argument"); + return -1; + } + + if (P_UNLIKELY (p_shm_lock (buf->shm, error) == FALSE)) + return -1; + + space = pp_shm_buffer_get_free_space (buf); + + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return (pssize) space; +} + +P_LIB_API pssize +p_shm_buffer_get_used_space (PShmBuffer *buf, + PError **error) +{ + psize space; + + if (P_UNLIKELY (buf == NULL)) { + p_error_set_error_p (error, + (pint) P_ERROR_IPC_INVALID_ARGUMENT, + 0, + "Invalid input argument"); + return -1; + } + + if (P_UNLIKELY (p_shm_lock (buf->shm, error) == FALSE)) + return -1; + + space = pp_shm_buffer_get_used_space (buf); + + if (P_UNLIKELY (p_shm_unlock (buf->shm, error) == FALSE)) + return -1; + + return (pssize) space; +} + +P_LIB_API void +p_shm_buffer_clear (PShmBuffer *buf) +{ + ppointer addr; + psize size; + + if (P_UNLIKELY (buf == NULL)) + return; + + if (P_UNLIKELY ((addr = p_shm_get_address (buf->shm)) == NULL)) { + P_ERROR ("PShmBuffer::p_shm_buffer_clear: p_shm_get_address() failed"); + return; + } + + size = p_shm_get_size (buf->shm); + + if (P_UNLIKELY (p_shm_lock (buf->shm, NULL) == FALSE)) { + P_ERROR ("PShmBuffer::p_shm_buffer_clear: p_shm_lock() failed"); + return; + } + + memset (addr, 0, size); + + if (P_UNLIKELY (p_shm_unlock (buf->shm, NULL) == FALSE)) + P_ERROR ("PShmBuffer::p_shm_buffer_clear: p_shm_unlock() failed"); +} |