-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathfifo.h
136 lines (111 loc) · 4.24 KB
/
fifo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_FIFO_H
#define CBOX_FIFO_H
#include <assert.h>
#include <stdint.h>
#include <glib.h>
#include <string.h>
struct cbox_fifo
{
uint8_t *data;
uint32_t size;
uint64_t pad; // ensure the write-related and read-related structs are on 64 bit boundary
uint32_t write_count;
uint32_t write_offset;
uint32_t read_count;
uint32_t read_offset;
};
extern struct cbox_fifo *cbox_fifo_new(uint32_t size);
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo);
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo);
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes);
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes);
extern void cbox_fifo_destroy(struct cbox_fifo *fifo);
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo)
{
return fifo->write_count - fifo->read_count;
}
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo)
{
return fifo->size - (fifo->write_count - fifo->read_count);
}
static inline gboolean cbox_fifo_read_impl(struct cbox_fifo *fifo, void *dest, uint32_t bytes, gboolean advance)
{
__sync_synchronize();
if (fifo->write_count - fifo->read_count < bytes)
return FALSE;
if (dest)
{
uint32_t ofs = fifo->read_count - fifo->read_offset;
assert(ofs >= 0 && ofs < fifo->size);
if (ofs + bytes > fifo->size)
{
uint8_t *dstb = (uint8_t *)dest;
uint32_t firstpart = fifo->size - ofs;
memcpy(dstb, fifo->data + ofs, firstpart);
memcpy(dstb + firstpart, fifo->data, bytes - firstpart);
}
else
memcpy(dest, fifo->data + ofs, bytes);
}
if (advance)
{
__sync_synchronize();
// Make sure data are copied before signalling that they can be overwritten
fifo->read_count += bytes;
if (fifo->read_count - fifo->read_offset >= fifo->size)
fifo->read_offset += fifo->size;
}
__sync_synchronize();
return TRUE;
}
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, dest, bytes, TRUE);
}
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, dest, bytes, FALSE);
}
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, NULL, bytes, TRUE);
}
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes)
{
if (fifo->size - (fifo->write_count - fifo->read_count) < bytes)
return FALSE;
uint32_t ofs = fifo->write_count - fifo->write_offset;
assert(ofs >= 0 && ofs < fifo->size);
if (ofs + bytes > fifo->size)
{
const uint8_t *srcb = (const uint8_t *)src;
uint32_t firstpart = fifo->size - ofs;
memcpy(fifo->data + ofs, srcb, firstpart);
memcpy(fifo->data, srcb + firstpart, bytes - firstpart);
}
else
memcpy(fifo->data + ofs, src, bytes);
// Make sure data are in the buffer before announcing the availability
__sync_synchronize();
fifo->write_count += bytes;
if (fifo->write_count - fifo->write_offset >= fifo->size)
fifo->write_offset += fifo->size;
return TRUE;
}
#endif