From 81f8e77d5c49868c538e6145149d183b25ea2362 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 14 Aug 2016 16:54:15 -0400 Subject: [PATCH] Initial code drop --- README.md | 39 ++++++++++++++++++++++++ queue.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ queue.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 README.md create mode 100644 queue.c create mode 100644 queue.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdcdd1c --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Lock-free Single-Producer Single-consumer (SPSC) queue + +## Design decissions + + - Static indexed ring buffer or dynamically linked-lists? + +## Some reading material + +- http://moodycamel.com/blog/2013/a-fast-lock-free-queue-for-c++ +- https://github.com/cameron314/readerwriterqueue +- http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue + +## Credits + +- Umar Farooq +- Steffen Vogel + +## License + +#### BSD 2-Clause License + +All rights reserved. + + - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +``` +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` \ No newline at end of file diff --git a/queue.c b/queue.c new file mode 100644 index 0000000..85ccb46 --- /dev/null +++ b/queue.c @@ -0,0 +1,80 @@ +/** Lock-free Single-Producer Single-consumer (SPSC) queue. + * + * @author Steffen Vogel + * @copyright 2016 Steffen Vogel + * @license BSD 2-Clause License + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "queue.h" + +int queue_init(struct queue *q, size_t size) +{ + q->size = size; + + q->pointers = malloc(size * sizeof(void *)); + if (q->pointers == NULL) + return -1; + + q->tail = atomic_init(0); + q->head = atomic_init(0); + + return 0; +} + +void queue_destroy(struct queue *q) +{ + free(q->pointers); +} + +int queue_get(struct queue *q, void **ptr) +{ + +} + +int queue_push(struct queue *q, void *ptr) +{ + +} + +int queue_pull(struct queue *q, void **ptr, qptr_t *head) +{ + +} + +int queue_get_many(struct queue *q, void *ptrs[], size_t cnt, qptr_t head) +{ + +} + +int queue_push_many(struct queue *q, void **ptrs, size_t cnt) +{ + +} + +int queue_pull_many(struct queue *q, void **ptrs, size_t cnt, qptr_t *head) +{ + +} \ No newline at end of file diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..ba1c37e --- /dev/null +++ b/queue.h @@ -0,0 +1,89 @@ +/** Lock-free Single-Producer Single-consumer (SPSC) queue. + * + * @author Steffen Vogel + * @copyright 2016 Steffen Vogel + * @license BSD 2-Clause License + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#include +#include +#include + +struct queue { + size_t size; /**< Number of pointers in queue::array */ + + void **pointers; /**< Circular buffer. */ + + _Atomic int head; /**< */ + _Atomic int tail; /**< Tail pointer of queue*/ +}; + +/** Initiliaze a new queue and allocate memory. */ +int queue_init(struct queue *q, size_t size); + +/** Release memory of queue. */ +void queue_destroy(struct queue *q); + +/** Enqueue up to \p cnt elements from \p ptrs[] at the queue tail pointed by \p tail. + * + * It may happen that the queue is (nearly) full and there is no more + * space to enqueue more elments. + * In this case a call to this function will return a value which is smaller than \p cnt + * or even zero if the queue was already full. + * + * @param q A pointer to the queue datastructure. + * @param[in] ptrs An array of void-pointers which should be enqueued. + * @param cnt The length of the pointer array \p ptrs. + * @return The function returns the number of successfully enqueued elements from \p ptrs. + */ +int queue_push_many(struct queue *q, void *ptrs[], size_t cnt); + +/** Dequeue up to \p cnt elements from the queue and place them into the array \p ptrs[]. + * + * @param q A pointer to the queue datastructure. + * @param[out] ptrs An array with space at least \cnt elements which will receive pointers to the released elements. + * @param cnt The maximum number of elements which should be dequeued. It defines the size of \p ptrs. + * @param[in,out] head A pointer to a queue head. The value will be updated to reflect the new head. + * @return The number of elements which have been dequeued and whose reference counts have reached zero. + */ +int queue_pull_many(struct queue *q, void *ptrs[], size_t cnt); + +/** Fill \p ptrs with \p cnt elements of the queue starting at entry \p pos. */ +int queue_get_many(struct queue *q, void *ptrs[], size_t cnt); + +/** Get the first element in the queue */ +int queue_get(struct queue *q, void **ptr); + +/** Enqueue a new block at the tail of the queue. */ +int queue_push(struct queue *q, void *ptr); + +/** Dequeue the first block at the head of the queue. */ +int queue_pull(struct queue *q, void **ptr); + +#endif /* _QUEUE_H_ */ \ No newline at end of file