13
0

Fix some disk-buffer threading issues

Make _pending_overwrite atomic (butler + process thread).
This also addresses a potential seek before override race.

Seeking will fill the buffers and by the time overwrite_existing_buffers()
is called from there is no space to overwrite anymore.
This commit is contained in:
Robin Gareus 2019-02-08 17:42:14 +01:00
parent b5587e5e43
commit 796ac29cf2
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 17 additions and 9 deletions

View File

@ -76,7 +76,7 @@ public:
return _do_refill_with_alloc (partial_fill);
}
bool pending_overwrite () const { return _pending_overwrite; }
bool pending_overwrite () const;
// Working buffers for do_refill (butler thread)
static void allocate_working_buffers();
@ -146,7 +146,7 @@ private:
with respect to the transport sample. This is used for latency compensation.
*/
samplepos_t overwrite_sample;
bool _pending_overwrite;
mutable gint _pending_overwrite;
bool overwrite_queued;
IOChange input_change_pending;
samplepos_t file_sample[DataType::num_types];

View File

@ -56,13 +56,13 @@ bool DiskReader::_no_disk_output = false;
DiskReader::DiskReader (Session& s, string const & str, DiskIOProcessor::Flag f)
: DiskIOProcessor (s, str, f)
, overwrite_sample (0)
, _pending_overwrite (false)
, overwrite_queued (false)
, _declick_amp (s.nominal_sample_rate ())
, _declick_offs (0)
{
file_sample[DataType::AUDIO] = 0;
file_sample[DataType::MIDI] = 0;
g_atomic_int_set (&_pending_overwrite, 0);
}
DiskReader::~DiskReader ()
@ -463,31 +463,36 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
// DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 reader run, needs butler = %2\n", name(), _need_butler));
}
bool
DiskReader::pending_overwrite () const {
return g_atomic_int_get (&_pending_overwrite) != 0;
}
void
DiskReader::set_pending_overwrite ()
{
/* called from audio thread, so we can use the read ptr and playback sample as we wish */
assert (!_pending_overwrite);
_pending_overwrite = true;
assert (!pending_overwrite ());
overwrite_sample = playback_sample;
boost::shared_ptr<ChannelList> c = channels.reader ();
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
(*chan)->rbuf->read_flush ();
}
g_atomic_int_set (&_pending_overwrite, 1);
}
bool
DiskReader::overwrite_existing_buffers ()
{
boost::shared_ptr<ChannelList> c = channels.reader();
/* called from butler thread */
assert (pending_overwrite ());
overwrite_queued = false;
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 overwriting existing buffers at %2\n", overwrite_sample));
boost::shared_ptr<ChannelList> c = channels.reader();
if (!c->empty ()) {
/* AUDIO */
@ -495,6 +500,7 @@ DiskReader::overwrite_existing_buffers ()
/* assume all are the same size */
samplecnt_t size = c->front()->rbuf->write_space ();
assert (size > 0);
boost::scoped_array<Sample> sum_buffer (new Sample[size]);
boost::scoped_array<Sample> mixdown_buffer (new Sample[size]);
@ -545,7 +551,7 @@ DiskReader::overwrite_existing_buffers ()
file_sample[DataType::MIDI] = overwrite_sample; // overwrite_sample was adjusted by ::midi_read() to the new position
}
_pending_overwrite = false;
g_atomic_int_set (&_pending_overwrite, 0);
return true;
}
@ -558,6 +564,8 @@ DiskReader::seek (samplepos_t sample, bool complete_refill)
ChannelList::iterator chan;
boost::shared_ptr<ChannelList> c = channels.reader();
g_atomic_int_set (&_pending_overwrite, 0);
//sample = std::max ((samplecnt_t)0, sample -_session.worst_output_latency ());
for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {