Sigc++ apparently takes arguments as references, so if someone reached to
a signal with null train by reserving the block again, any remaining slots
of the release emission would also get the new train pointer. This caused
the routing system to malfunction in certain cases as the router saw two
emissions for the same block reservation.
The simplest solution would be to pass t instead of train to emit(), but
then the ordering of the two emissions would be inconsistent. Thus the
additional logic to delay further emissions until the outstanding one is
completed.
#include <algorithm>
+#include <msp/core/raii.h>
#include <msp/strings/format.h>
#include <msp/time/units.h>
#include "block.h"
turnout_addr(start.get_turnout_address()),
conflict(false),
sensor(0),
- train(0)
+ train(0),
+ pending_train(0),
+ emitting_reserve(false)
{
add_track(start);
bool Block::reserve(Train *t)
{
- if(!t || !train)
+ if(!t || !(emitting_reserve ? pending_train : train))
{
- train = t;
- signal_reserved.emit(train);
+ pending_train = t;
+ if(!emitting_reserve)
+ {
+ while(pending_train!=train)
+ {
+ train = pending_train;
+ SetFlag setf(emitting_reserve);
+ signal_reserved.emit(train);
+ }
+ }
+
return true;
}
else
TrackCircuit *sensor;
std::vector<Endpoint> endpoints;
Train *train;
+ Train *pending_train;
+ bool emitting_reserve;
public:
Block(Layout &, Track &);