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"); +} | 
