Audacity 3.2.0
ring.cpp
Go to the documentation of this file.
1/*
2 Copyright 2011 David Robillard <http://drobilla.net>
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted, provided that the above
6 copyright notice and this permission notice appear in all copies.
7
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17#include <stdint.h>
18#include <stdlib.h>
19#include <string.h>
20
21#ifdef HAVE_MLOCK
22# include <sys/mman.h>
23# define ZIX_MLOCK(ptr, size) mlock((ptr), (size))
24#elif defined(_WIN32)
25# include <windows.h>
26# define ZIX_MLOCK(ptr, size) VirtualLock((ptr), (size))
27#else
28# pragma message("warning: No memory locking, possible RT violations")
29# define ZIX_MLOCK(ptr, size)
30#endif
31
32#if defined(__APPLE__)
33# include <libkern/OSAtomic.h>
34# define ZIX_FULL_BARRIER() OSMemoryBarrier()
35#elif defined(_WIN32)
36# include <windows.h>
37# define ZIX_FULL_BARRIER() MemoryBarrier()
38#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
39# define ZIX_FULL_BARRIER() __sync_synchronize()
40#else
41# pragma message("warning: No memory barriers, possible SMP bugs")
42# define ZIX_FULL_BARRIER()
43#endif
44
45/* No support for any systems with separate read and write barriers */
46#define ZIX_READ_BARRIER() ZIX_FULL_BARRIER()
47#define ZIX_WRITE_BARRIER() ZIX_FULL_BARRIER()
48
49#include "ring.h"
50
52 uint32_t write_head;
53 uint32_t read_head;
54 uint32_t size;
55 uint32_t size_mask;
56 char* buf;
57};
58
59static inline uint32_t
61{
62 // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
63 size--;
64 size |= size >> 1;
65 size |= size >> 2;
66 size |= size >> 4;
67 size |= size >> 8;
68 size |= size >> 16;
69 size++;
70 return size;
71}
72
75{
76 ZixRing* ring = (ZixRing*)malloc(sizeof(ZixRing));
77 ring->write_head = 0;
78 ring->read_head = 0;
80 ring->size_mask = ring->size - 1;
81 ring->buf = (char*)malloc(ring->size);
82 return ring;
83}
84
85void
87{
88 free(ring->buf);
89 free(ring);
90}
91
92void
94{
95 ZIX_MLOCK(ring, sizeof(ZixRing));
96 ZIX_MLOCK(ring->buf, ring->size);
97}
98
99void
101{
102 ring->write_head = 0;
103 ring->read_head = 0;
104}
105
106static inline uint32_t
107read_space_internal(const ZixRing* ring, uint32_t r, uint32_t w)
108{
109 if (r < w) {
110 return w - r;
111 } else {
112 return (w - r + ring->size) & ring->size_mask;
113 }
114}
115
116uint32_t
118{
119 return read_space_internal(ring, ring->read_head, ring->write_head);
120}
121
122static inline uint32_t
123write_space_internal(const ZixRing* ring, uint32_t r, uint32_t w)
124{
125 if (r == w) {
126 return ring->size - 1;
127 } else if (r < w) {
128 return ((r - w + ring->size) & ring->size_mask) - 1;
129 } else {
130 return (r - w) - 1;
131 }
132}
133
134uint32_t
136{
137 return write_space_internal(ring, ring->read_head, ring->write_head);
138}
139
140uint32_t
142{
143 return ring->size - 1;
144}
145
146static inline uint32_t
147peek_internal(const ZixRing* ring, uint32_t r, uint32_t w,
148 uint32_t size, void* dst)
149{
150 if (read_space_internal(ring, r, w) < size) {
151 return 0;
152 }
153
154 if (r + size < ring->size) {
155 memcpy(dst, &ring->buf[r], size);
156 } else {
157 const uint32_t first_size = ring->size - r;
158 memcpy(dst, &ring->buf[r], first_size);
159 memcpy((char*)dst + first_size, &ring->buf[0], size - first_size);
160 }
161
162 return size;
163}
164
165uint32_t
166zix_ring_peek(ZixRing* ring, void* dst, uint32_t size)
167{
168 return peek_internal(ring, ring->read_head, ring->write_head, size, dst);
169}
170
171uint32_t
172zix_ring_read(ZixRing* ring, void* dst, uint32_t size)
173{
174 const uint32_t r = ring->read_head;
175 const uint32_t w = ring->write_head;
176
177 if (peek_internal(ring, r, w, size, dst)) {
179 ring->read_head = (r + size) & ring->size_mask;
180 return size;
181 } else {
182 return 0;
183 }
184}
185
186uint32_t
187zix_ring_skip(ZixRing* ring, uint32_t size)
188{
189 const uint32_t r = ring->read_head;
190 const uint32_t w = ring->write_head;
191 if (read_space_internal(ring, r, w) < size) {
192 return 0;
193 }
194
196 ring->read_head = (r + size) & ring->size_mask;
197 return size;
198}
199
200uint32_t
201zix_ring_write(ZixRing* ring, const void* src, uint32_t size)
202{
203 const uint32_t r = ring->read_head;
204 const uint32_t w = ring->write_head;
205 if (write_space_internal(ring, r, w) < size) {
206 return 0;
207 }
208
209 if (w + size <= ring->size) {
210 memcpy(&ring->buf[w], src, size);
212 ring->write_head = (w + size) & ring->size_mask;
213 } else {
214 const uint32_t this_size = ring->size - w;
215 memcpy(&ring->buf[w], src, this_size);
216 memcpy(&ring->buf[0], (const char*)src + this_size, size - this_size);
218 ring->write_head = size - this_size;
219 }
220
221 return size;
222}
void zix_ring_reset(ZixRing *ring)
Definition: ring.cpp:100
uint32_t zix_ring_read(ZixRing *ring, void *dst, uint32_t size)
Definition: ring.cpp:172
void zix_ring_free(ZixRing *ring)
Definition: ring.cpp:86
ZixRing * zix_ring_new(uint32_t size)
Definition: ring.cpp:74
uint32_t zix_ring_read_space(const ZixRing *ring)
Definition: ring.cpp:117
uint32_t zix_ring_capacity(const ZixRing *ring)
Definition: ring.cpp:141
uint32_t zix_ring_write_space(const ZixRing *ring)
Definition: ring.cpp:135
uint32_t zix_ring_peek(ZixRing *ring, void *dst, uint32_t size)
Definition: ring.cpp:166
uint32_t zix_ring_write(ZixRing *ring, const void *src, uint32_t size)
Definition: ring.cpp:201
uint32_t zix_ring_skip(ZixRing *ring, uint32_t size)
Definition: ring.cpp:187
void zix_ring_mlock(ZixRing *ring)
Definition: ring.cpp:93
void free(void *ptr)
Definition: VectorOps.h:34
static uint32_t read_space_internal(const ZixRing *ring, uint32_t r, uint32_t w)
Definition: ring.cpp:107
#define ZIX_WRITE_BARRIER()
Definition: ring.cpp:47
#define ZIX_READ_BARRIER()
Definition: ring.cpp:46
#define ZIX_MLOCK(ptr, size)
Definition: ring.cpp:29
static uint32_t next_power_of_two(uint32_t size)
Definition: ring.cpp:60
static uint32_t peek_internal(const ZixRing *ring, uint32_t r, uint32_t w, uint32_t size, void *dst)
Definition: ring.cpp:147
static uint32_t write_space_internal(const ZixRing *ring, uint32_t r, uint32_t w)
Definition: ring.cpp:123
uint32_t read_head
Write index into buf.
Definition: ring.cpp:53
uint32_t size_mask
Mask for fast modulo.
Definition: ring.cpp:55
uint32_t size
Size (capacity) in bytes.
Definition: ring.cpp:54
uint32_t write_head
Read index into buf.
Definition: ring.cpp:52
char * buf
Contents.
Definition: ring.cpp:56