1 // Stethoscope shared memory buffer implementation
2 // This file is part of SuperCollider
4 // Copyright (C) 2011 Jakob Leben
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; see the file COPYING. If not, write to
18 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 // Boston, MA 02111-1307, USA.
21 #ifndef SC_SCOPE_BUFFER_HPP
22 #define SC_SCOPE_BUFFER_HPP
24 #include <boost/interprocess/offset_ptr.hpp>
25 #include <boost/atomic.hpp>
31 namespace detail_server_shm
{
33 using boost::interprocess::offset_ptr
;
36 class scope_buffer_writer
;
37 class scope_buffer_reader
;
39 class scope_buffer_pool
43 void init (void * pool
, size_t size_of_pool
)
46 memset(pool_
, 0, size_of_pool
);
47 init_memory_pool(size_of_pool
, pool_
);
50 void * allocate (size_t bytes
)
52 return malloc_ex(bytes
, pool_
);
55 void deallocate (void * ptr
)
61 friend class server_shared_memory
;
67 friend class scope_buffer_writer
;
68 friend class scope_buffer_reader
;
70 typedef offset_ptr
<float> sh_float_ptr
;
81 unsigned int _channels
;
85 Reader/writer synchronization mechanism:
87 _stage, _in and _out are indexes into _state - an array of 3 equal data regions.
89 _out denotes the region where the writer writes.
90 _in denotes the region where the reader reads.
91 _stage denotes the region where data is exchanged between the writer and the reader.
93 After the writer is done writing, it sets the changed flag of the _in region,
94 and swaps _in with _stage.
96 The reader polls the changed flag of the _stage region. If it is set, it swaps _out
97 with _stage, reads the new _out region, and unsets its changed flag.
105 data_desc(): data(0), frames(0), changed(false) {}
108 atomic
<bool> changed
;
124 bool allocate( scope_buffer_pool
& pool
, unsigned int channels
, unsigned int size
)
126 bool available
= _status
.load( boost::memory_order_relaxed
) == free
;
127 if( !available
) return false;
130 _channels
= channels
;
132 unsigned int asset_size
= channels
* size
;
133 _data
= (float*)pool
.allocate( asset_size
* 3 * sizeof(float) );
137 _state
[0].data
= _data
;
138 _state
[1].data
= _data
+ asset_size
;
139 _state
[2].data
= _data
+ asset_size
+ asset_size
;
141 _status
.store( initialized
, boost::memory_order_release
);
146 void release( scope_buffer_pool
& pool
)
148 bool allocated
= _status
.load( boost::memory_order_relaxed
) != free
;
149 if( !allocated
) return;
151 pool
.deallocate( _data
.get() );
153 _status
.store( free
, boost::memory_order_release
);
156 float * write_address() { return _state
[_in
].data
.get(); }
158 void push( unsigned int frames
)
160 _state
[_in
].frames
= frames
;
161 _state
[_in
].changed
.store( true, boost::memory_order_relaxed
);
162 _in
= _stage
.exchange( _in
, boost::memory_order_release
);
169 return _status
.load( boost::memory_order_acquire
) == initialized
;
172 float * read_address() { return _state
[_out
].data
.get(); }
176 int stage
= _stage
.load( boost::memory_order_relaxed
);
177 bool changed
= _state
[stage
].changed
.load( boost::memory_order_relaxed
);
181 _state
[_out
].changed
.store( false, boost::memory_order_relaxed
);
182 _out
= _stage
.exchange( _out
, boost::memory_order_acquire
);
185 return _state
[_out
].frames
;
189 class scope_buffer_writer
193 scope_buffer
*buffer
;
195 scope_buffer_writer( scope_buffer
*buffer
= 0 ):
199 scope_buffer_writer( scope_buffer
*buf
, scope_buffer_pool
& pool
, unsigned int channels
, unsigned int size
):
202 if( !buffer
->allocate( pool
, channels
, size
) )
213 return buffer
->write_address();
216 unsigned int max_size()
218 return buffer
->_size
;
221 void push( unsigned int frames
)
223 buffer
->push( frames
);
226 void release( scope_buffer_pool
& pool
)
228 buffer
->release( pool
);
232 // FIXME: how do we ensure that scope_buffer data members used in the reader
233 // are consistent among themselves at all times???
235 class scope_buffer_reader
237 scope_buffer
*buffer
;
240 scope_buffer_reader( scope_buffer
*buffer_
= 0 ):
246 // places an acquire memory ordering fence
247 return (buffer
&& buffer
->valid());
250 bool pull( unsigned int &frames
)
252 unsigned int new_frames
= buffer
->pull();
257 return new_frames
!= 0;
262 return buffer
->read_address();
265 unsigned int max_frames()
267 return buffer
->_size
;
270 unsigned int channels()
272 return buffer
->_channels
;
276 } /* namespace detail_server_shm */