-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Eject crash fix #1924
Eject crash fix #1924
Conversation
This looks like a minefield, completely broken by design 🙈 |
src/engine/bpmcontrol.h
Outdated
|
||
TapFilter m_tapFilter; | ||
|
||
TrackPointer m_pTrack; | ||
BeatsPointer m_pBeats; | ||
TrackPointer m_pTrack; // is witten from an engine worker thread |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo. Use a single line comment for both elements. What about the other concurrently accessed members? We should at least group them together.
OMG, what an ugly patch for evil code! Not your fault, @daschuer ;) I didn't notice any obvious mistakes while quickly scrolling over all the changes. |
I'll be the first to say the engine needs to be rewritten from scratch due
to flawed designs around mutable shared state, but let's avoid talking
about blame b/c a culture of shaming isn't healthy. People who wrote this
code are receiving your comments :).
https://codeascraft.com/2012/05/22/blameless-postmortems/
…On Thu, Nov 29, 2018, 3:20 AM Uwe Klotz ***@***.***> wrote:
OMG, what an ugly patch for evil code! Not your fault, @daschuer
<https://github.com/daschuer> ;)
I didn't notice any obvious mistakes while quickly scrolling over all the
changes.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1924 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABnn4gLJKcwH8lrvCt40X97W0--P-E3ks5uz5i4gaJpZM4Y4nAt>
.
|
Sorry for the comment, @rryan, it was not my intention to blame anyone! Every project gets bigger with time and design decisions that were reasonable at the start might turn out as unhandy later. That's daily business, no matter how experienced you (think you) are. Primarily I struggle with the code that I have written myself in the past ;) What I actually should have expressed is that @daschuer's fixes are very brittle and I'm uncomfortable with this code or coding style. But unfortunately we have no choice other than to mitigate the issues. |
OK, improved even more, |
I vote for 2.2 instead of master, because the threat is real and the successor of 2.2 is months away. Due to the conflicts I would like to avoid a fix for 2.1 that will go out of support soon. |
Most changes in enginebuffer.cpp are white space changes due to the function extraction. Here is a eject crash report: I think the crash condition is not very likely for normal users, because you need to to use controls during ejecting the track. I can only imagine that this happens when using AUTO DJ, or some automation in scripts, |
It only conflicts with some typo fixes when merging to 2.2. The conflict is displayed that big, because of surrounding white space changes. |
m_sGroup(group) { | ||
UserSettingsPointer pConfig) | ||
: EngineControl(group, pConfig), | ||
m_tapFilter(this, kFilterLength, kMaxInterval), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't hurt to explicitly initialize the atomic values. Here they are used on a higher level of abstraction. We should not rely on the implicit default values that are pure numbers without any meaning in the context of BPM control.
@@ -834,9 +841,9 @@ void BpmControl::setInstantaneousBpm(double instantaneousBpm) { | |||
|
|||
void BpmControl::resetSyncAdjustment() { | |||
// Immediately edit the beat distance to reflect the new reality. | |||
double new_distance = m_pThisBeatDistance->get() + m_dUserOffset; | |||
double new_distance = m_pThisBeatDistance->get() + m_dUserOffset.getValue(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why getValue/setValue instead of fetchAndStore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is ControlValueAtomic, which has no fetchAndStore().
// Note: dThisBeatLength is fractional frames count * 2 (stereo samples) | ||
pGroupFeatures->beat_length_sec = dThisBeatLength / kSamplesPerFrame | ||
/ m_pTrack->getSampleRate() / calcRateRatio(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might getTrackSampleRate() return 0.0 due to race conditions if the track has just been unloaded? We better should add a check for this.
Unrelated (or maybe related): Is calcRateRatio() guaranteed to always return a value that is strictly != 0 in any situation?
src/engine/enginebuffer.cpp
Outdated
@@ -171,8 +171,7 @@ EngineBuffer::EngineBuffer(QString group, UserSettingsPointer pConfig, | |||
m_pRepeat = new ControlPushButton(ConfigKey(m_group, "repeat")); | |||
m_pRepeat->setButtonMode(ControlPushButton::TOGGLE); | |||
|
|||
// Sample rate | |||
m_pSampleRate = new ControlProxy("[Master]", "samplerate", this); | |||
m_pMasterSampleRate = new ControlProxy("[Master]", "samplerate", this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_pKeylockEngine is also bound to "[Master]" and doesn't contain a prefix in its name. Do we really need to add "Master" just for this member?
src/engine/enginebuffer.cpp
Outdated
@@ -372,7 +371,7 @@ double EngineBuffer::getLocalBpm() { | |||
} | |||
|
|||
void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { | |||
foreach (EngineControl* pControl, m_engineControls) { | |||
for (const auto& pControl: m_engineControls) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use qAsConst(m_engineControls) to avoid a copy.
src/engine/enginebuffer.cpp
Outdated
for (QList<EngineControl*>::iterator it = m_engineControls.begin(); | ||
it != m_engineControls.end(); ++it) { | ||
EngineControl *pControl = *it; | ||
for (const auto& pControl: m_engineControls) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use qAsConst(m_engineControls) to avoid a copy.
src/engine/enginebuffer.cpp
Outdated
TrackPointer pNewTrack, TrackPointer pOldTrack) { | ||
// First inform engineControls directly | ||
// Note: we are still in a worker thread. | ||
for (const auto& pControl: m_engineControls) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
qAsConst is missing
src/engine/enginecontrol.h
Outdated
double getCurrentSample() const; | ||
double getTotalSamples() const; | ||
double getTrackSampleRate() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 3 accessors should be replaced by a single function that returns the whole thing atomically. I haven't check how many callers are affected.
src/util/tapfilter.cpp
Outdated
@@ -11,6 +11,7 @@ TapFilter::~TapFilter() { | |||
} | |||
|
|||
void TapFilter::tap() { | |||
QMutexLocker locker(&m_mutex); | |||
mixxx::Duration elapsed = m_timer.restart(); | |||
if (elapsed <= m_maxInterval) { | |||
emit(tapped(m_mean.insert(elapsed.toDoubleMillis()), m_mean.size())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Emitting signals from an event loop thread while holding a lock may cause deadlocks.
TODO: Just some technical code fixes, optimizations, and clarifications. The changes in EngineBuffer are hard to review. I'm silently assuming that the implementation hasn't changed substantially and only code has been reordered, reformatted, and updated. Are we able to agree on a target? The threats are real and at least 2.2 should receive these fixes. |
69d2eea
to
c8c5883
Compare
Ready! |
LGTM. A huge change set. Should we still merge this into 2.1? |
This was getting bigger due to fixing the usefully review comments. We can go back to an earlier version with less changes. But that feels odd. 2.1 and 2.2 can considered as stable. |
Excluding some of the changes is not an option. I'm confident that we don't introduce regressions, all changes are straightforward. Only the reformatting causes some noise. Fixing 2.2 is mandatory, fixing 2.1 is optional. |
OK, so let's merge it. Thank you for review. |
This PRs should fix some crashes that may occur during switching or ejecting tracks.
https://bugs.launchpad.net/mixxx/+bug/1801874
The main fix is that we now that we obtain a strong reference to the track and beat pointers changed by the engine worker thread.
I have also included some related changes that was helpful to have a clear look on the code during development.