server: Z21 fix race condition for power state
- Read/Write track power state only from EventLoop thread
('m_trackPowerOn' and 'm_emergencyStop' must be accessed
only from EventLoop thread, except on kernel start.)
This fixes infinite async loop power on/off at startup connecting Z21
Dieser Commit ist enthalten in:
Ursprung
5a291f0c91
Commit
e0d5375a35
@ -72,48 +72,45 @@ void ClientKernel::receive(const Message& message)
|
||||
case LAN_X_BC:
|
||||
if(message == LanXBCTrackPowerOff() || message == LanXBCTrackShortCircuit())
|
||||
{
|
||||
if(m_trackPowerOn != TriState::False)
|
||||
{
|
||||
m_trackPowerOn = TriState::False;
|
||||
|
||||
if(m_onTrackPowerOnChanged)
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
if(m_trackPowerOn != TriState::False)
|
||||
{
|
||||
m_trackPowerOn = TriState::False;
|
||||
if(m_onTrackPowerOnChanged)
|
||||
m_onTrackPowerOnChanged(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(message == LanXBCTrackPowerOn())
|
||||
{
|
||||
if(m_trackPowerOn != TriState::True)
|
||||
{
|
||||
m_trackPowerOn = TriState::True;
|
||||
|
||||
if(m_onTrackPowerOnChanged)
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
if(m_trackPowerOn != TriState::True)
|
||||
{
|
||||
m_trackPowerOn = TriState::True;
|
||||
if(m_onTrackPowerOnChanged)
|
||||
m_onTrackPowerOnChanged(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case LAN_X_BC_STOPPED:
|
||||
if(message == LanXBCStopped())
|
||||
{
|
||||
if(m_emergencyStop != TriState::True)
|
||||
{
|
||||
m_emergencyStop = TriState::True;
|
||||
|
||||
if(m_onEmergencyStop)
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
if(m_emergencyStop != TriState::True)
|
||||
{
|
||||
m_emergencyStop = TriState::True;
|
||||
if(m_onEmergencyStop)
|
||||
m_onEmergencyStop();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -246,29 +243,23 @@ void ClientKernel::receive(const Message& message)
|
||||
&& (reply.centralState & Z21_CENTRALSTATE_SHORTCIRCUIT) == 0;
|
||||
|
||||
const TriState trackPowerOn = toTriState(isTrackPowerOn);
|
||||
if(m_trackPowerOn != trackPowerOn)
|
||||
{
|
||||
m_trackPowerOn = trackPowerOn;
|
||||
const TriState stopState = toTriState(isStop);
|
||||
|
||||
if(m_onTrackPowerOnChanged)
|
||||
EventLoop::call(
|
||||
[this, isTrackPowerOn]()
|
||||
{
|
||||
m_onTrackPowerOnChanged(isTrackPowerOn);
|
||||
});
|
||||
}
|
||||
EventLoop::call([this, trackPowerOn, stopState]()
|
||||
{
|
||||
if(m_trackPowerOn != trackPowerOn)
|
||||
{
|
||||
m_trackPowerOn = trackPowerOn;
|
||||
if(m_onTrackPowerOnChanged)
|
||||
m_onTrackPowerOnChanged(trackPowerOn == TriState::True);
|
||||
}
|
||||
|
||||
if(m_emergencyStop != TriState::True && isStop)
|
||||
{
|
||||
m_emergencyStop = TriState::True;
|
||||
|
||||
if(m_onEmergencyStop)
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
m_onEmergencyStop();
|
||||
});
|
||||
}
|
||||
if(m_emergencyStop != stopState)
|
||||
{
|
||||
m_emergencyStop = stopState;
|
||||
m_onEmergencyStop();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -296,32 +287,44 @@ void ClientKernel::receive(const Message& message)
|
||||
|
||||
void ClientKernel::trackPowerOn()
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
if(m_trackPowerOn != TriState::True || m_emergencyStop != TriState::False)
|
||||
assert(isEventLoopThread());
|
||||
|
||||
if(m_trackPowerOn != TriState::True || m_emergencyStop != TriState::False)
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
send(LanXSetTrackPowerOn());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ClientKernel::trackPowerOff()
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
if(m_trackPowerOn != TriState::False)
|
||||
assert(isEventLoopThread());
|
||||
|
||||
if(m_trackPowerOn != TriState::False)
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
send(LanXSetTrackPowerOff());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ClientKernel::emergencyStop()
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
if(m_emergencyStop != TriState::True)
|
||||
assert(isEventLoopThread());
|
||||
|
||||
if(m_emergencyStop != TriState::True)
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
send(LanXSetStop());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ClientKernel::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
|
||||
|
||||
@ -81,7 +81,24 @@ class ClientKernel final : public Kernel
|
||||
uint8_t m_firmwareVersionMinor;
|
||||
std::function<void(HardwareType, uint8_t, uint8_t)> m_onHardwareInfoChanged;
|
||||
|
||||
/*!
|
||||
* \brief m_trackPowerOn caches command station track power state.
|
||||
*
|
||||
* NOTE: it must be accessed only from event loop thread or from
|
||||
* Z21::ClientKernel::onStart().
|
||||
*
|
||||
* \sa EventLoop
|
||||
*/
|
||||
TriState m_trackPowerOn;
|
||||
|
||||
/*!
|
||||
* \brief m_emergencyStop caches command station emergency stop state.
|
||||
*
|
||||
* NOTE: it must be accessed only from event loop thread or from
|
||||
* Z21::ClientKernel::onStart().
|
||||
*
|
||||
* \sa EventLoop
|
||||
*/
|
||||
TriState m_emergencyStop;
|
||||
std::function<void(bool)> m_onTrackPowerOnChanged;
|
||||
std::function<void()> m_onEmergencyStop;
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren