- Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathringbuffer.cpp
More file actions
Latest commit
142 lines (114 loc) · 3.65 KB
/
Copy pathringbuffer.cpp
File metadata and controls
142 lines (114 loc) · 3.65 KB
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
137
138
139
140
141
/*
* Block-free ringbuffer for synchronisation of producer and consumer threads.
*
* Audio callback delivers data, the other thread reads data.
*
* Size must be a multiple of the real-time buffer size (e.g. JACK buffer).
* For the non-realtime thread this is not an issue as long as it's large
* enough to hold at least two consumer frames (theoretical minimum)
*
* Caveats: if consumer threads waits too long, producer can overrun the
* buffer. This may not be a problem, for this we have resync() that puts
* the consumer readpointer right on top of the consumer writepointer.
*/
#include<iostream>
#include"ringbuffer.h"
#include<unistd.h>
#include<string.h>// memcpy
/*
* Size is specified as #items, not bytes. Item type is now float and will
* eventually be set in template form
*/
RingBuffer::RingBuffer(unsignedlong size,std::string name)
{
tail=0;
head=0;
this->size=size;
itemsize=sizeof(float);
buffer = newfloat [size]; // allocate storage
this->name=name;
blockingPush=false;
blockingPop=false;
} // RingBuffer()
RingBuffer::~RingBuffer()
{
delete [] buffer;
} // ~RingBuffer()
unsignedlongRingBuffer::items_available_for_write()
{
long pointerspace=head.load()-tail.load(); // signed
if(pointerspace > 0) return pointerspace; // NB: > 0 so NOT including 0
elsereturn pointerspace+size;
} // items_available_for_write()
unsignedlongRingBuffer::items_available_for_read()
{
long pointerspace=tail.load()-head.load(); // signed
if(pointerspace >= 0) return pointerspace; // NB: >= 0 so including 0
elsereturn pointerspace+size;
} // items_available_for_read()
voidRingBuffer::pushMayBlock(bool block)
{
this->blockingPush=block;
} // pushMayBlock()
voidRingBuffer::popMayBlock(bool block)
{
this->blockingPop=block;
} // popMayBlock()
voidRingBuffer::setBlockingNap(unsignedlong blockingNap)
{
this->blockingNap=blockingNap;
} // setBlockingNap()
/*
* Try to write as many items as possible and return the number actually written
*/
unsignedlongRingBuffer::push(float *data,unsignedlong n)
{
unsignedlong space=size;
if(blockingPush){
while((space=items_available_for_write())<n){ // blocking
usleep(blockingNap);
} // while
} // if
if(space==0) return0;
unsignedlong n_to_write = n<=space ? n : space; // limit
constauto current_tail = tail.load();
if(current_tail + n_to_write <= size){ // chunk fits without wrapping
memcpy(buffer+current_tail,data,n_to_write*itemsize);
}
else {
unsignedlong first_chunk=size-current_tail;
memcpy(buffer+current_tail,data,first_chunk*itemsize);
memcpy(buffer,data+first_chunk,(n_to_write-first_chunk)*itemsize);
}
tail.store((current_tail+n_to_write)%size);
return n_to_write;
} // push()
/*
* Try to read as many items as possible and return the number actually read
*/
unsignedlongRingBuffer::pop(float *data,unsignedlong n)
{
unsignedlong space=size;
if(blockingPop){
while((space=items_available_for_read())<n){ // blocking
usleep(blockingNap);
} // while
} // if
if(space==0) return0;
unsignedlong n_to_read = n<=space ? n : space; // limit
constauto current_head = head.load();
if(current_head + n_to_read <= size){ // no wrapping necessary
memcpy(data,buffer+current_head,n_to_read*itemsize);
}
else {
unsignedlong first_chunk=size-current_head;
memcpy(data,buffer+current_head,first_chunk*itemsize);
memcpy(data+first_chunk,buffer,(n_to_read-first_chunk)*itemsize);
}
head.store((current_head+n_to_read)%size); // zo ongeveer
return n_to_read;
} // pop()
boolRingBuffer::isLockFree()
{
return (tail.is_lock_free() && head.is_lock_free());
} // isLockFree()