From 6218b2c28eff39421d26983497bb902ffba8482f Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 3 Jan 2011 23:23:41 +0000 Subject: [PATCH] realtime: avoid needless signalling problems related to interference When we are considering an interfering segment, we want to first see whether the segment has anything in it and only if so consider its position. That avoids is calling it a problem that the interfering segment's position is not known (eg, because it has never been set). To support this, split segment_interferes into two functions: segment_interferer: simply returns the possibly-interfering segment so that we can check whether it's relevant segment_interferer_does: does the hard work, dealing appropriately with errors At all but the one call site of interest we can assert that the getmovpos callback never fails, so we provide a helper function segment_interferes_simple which does what segment_interferes used to (except that getmovpos returning an error now causes an abort). --- hostside/resolve.c | 2 +- hostside/safety.c | 32 ++++++++++++++++++------------ hostside/safety.h | 20 +++++++++++++++---- hostside/trackloc.c | 48 ++++++++++++++++++++++++++++++++------------- 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/hostside/resolve.c b/hostside/resolve.c index c9a4266..656c025 100644 --- a/hostside/resolve.c +++ b/hostside/resolve.c @@ -340,7 +340,7 @@ static int resolve_complete_main(void) { target= just_getmovpos(d,&tac); if (d->i->invertible) { - Segment *interferer= segment_interferes(&tac,d); + Segment *interferer= segment_interferes_simple(&tac,d); if (interferer) { actual_inversions_start(); d->seg_inverted= interferer->seg_inverted diff --git a/hostside/safety.c b/hostside/safety.c index 9214599..94d4778 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -447,7 +447,6 @@ static int initpresent_nextseg(TrackLocation *t, TrackAdvanceContext *c, static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, const TrackLocation *before) { PredictUserContext *u= c->u; - Segment *interferer; MovPosComb route_plan; TimeInterval max_ms; ErrorCode ec; @@ -472,14 +471,24 @@ static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, return predict_problem(u, t->seg, "will collide with itself!"); if (!u->optimistic) { - interferer= segment_interferes(c,t->seg); - if (interferer) { - if (interferer->owner && interferer->owner != u->train) - return predict_problem(u, t->seg, "impeded by %s at %s", - interferer->owner->pname, interferer->i->pname); - if (interferer->pred_present) - return predict_problem(u, t->seg, "will collide with itself at %s!", - interferer->i->pname); + Segment *interferer= segment_interferer(t->seg); + /* We want to avoid calling segment_interferer_does unless we have + * to, as it uses getmovpos which, if the movposcomb is unknown, + * will predict_problem even if the interferer is empty. */ + if (interferer && + (interferer->owner || interferer->pred_present)) { + int does; + ec= segment_interferer_does(c,t->seg,interferer, &does); + if (!ec) return ec; + + if (does) { + if (interferer->owner && interferer->owner != u->train) + return predict_problem(u, t->seg, "impeded by %s at %s", + interferer->owner->pname, interferer->i->pname); + if (interferer->pred_present) + return predict_problem(u, t->seg, "will collide with itself at %s!", + interferer->i->pname); + } } } @@ -965,7 +974,7 @@ ErrorCode predict(Train *tra, struct timeval tnow, unsigned flags, seg->seg_inverted= seg->tr_backwards ^ u.train_polarity_inverted; if (seg->i->invertible) { actual_inversions_segment(seg); - Segment *interferer= segment_interferes(0,seg); + Segment *interferer= segment_interferes_simple(0,seg); if (interferer && !interferer->will_polarise && interferer->i->invertible) { interferer->seg_inverted= seg->seg_inverted @@ -1216,7 +1225,6 @@ static void detection_report_problem(Train *tra, Segment *seg, void safety_notify_detection(Segment *seg) { Train *tra; ErrorCode ec; - Segment *interferer; int maxinto; struct timeval tnow; SpeedInfo speed_info; @@ -1226,7 +1234,7 @@ void safety_notify_detection(Segment *seg) { debug_count_event("detection"); if (!seg->det_expected) { - interferer= segment_interferes(0,seg); + Segment *interferer= segment_interferes_simple(0,seg); if (!interferer) safety_panic(0,seg, "unexpected detection"); if (interferer->det_ignore) return; if (!interferer->det_expected) diff --git a/hostside/safety.h b/hostside/safety.h index d61e88a..46ef44f 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -339,10 +339,22 @@ int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c, /* Of c, only c->getmovpos is used. t->remain is not used. * c may be 0 which works just like c->getmovpos==0. */ -Segment *segment_interferes(TrackAdvanceContext *c, Segment *base); - /* 0 means we know there is no interference; if we can't determine - * the relevant movposcombs we return the interfering segment. - * c is used as for trackloc_getlink. */ +Segment *segment_interferer(Segment *base); + /* Returns the segment which may interfere with base, if any. */ + +ErrorCode segment_interferer_does(TrackAdvanceContext *c, Segment *base, + Segment *interferer, int *does_r); + /* Checks whether it interferes with base. + * Return is 0 or the error value from c->getmovpos. + * *does_r is set (only) on successful return, + * c is used as for trackloc_getlink. If c->getmovpos is 0 + * the segments are taken to interfere if they would in any movposcomb. + * interferer may be 0 in which case succeeds, setting *does_r=0. + */ + +Segment *segment_interferes_simple(TrackAdvanceContext *c, Segment *base); + /* Combines segment_interferer and segment_interferer_does. + * c->getmovpos MUST NOT return errors; we abort if it does. */ int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c); /* Advances t by dist until distance becomes 0, some callback diff --git a/hostside/trackloc.c b/hostside/trackloc.c index e9125cb..6c8d59f 100644 --- a/hostside/trackloc.c +++ b/hostside/trackloc.c @@ -133,7 +133,14 @@ int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) { } } -static int interfering_movposcomb(TrackAdvanceContext *c, Segment *seg) { +Segment *segment_interferer(Segment *base) { + SegmentNum intern= base->i->interferes; + if (!SOMEP(intern)) return 0; + return &segments[intern]; +} + +static ErrorCode interfering_movposcomb(TrackAdvanceContext *c, Segment *seg, + int *does_r) { MovPosComb mpc; int r; @@ -145,28 +152,41 @@ static int interfering_movposcomb(TrackAdvanceContext *c, Segment *seg) { t.remain= 0; r= c->getmovpos(&t,c,&mpc); - if (r) return 1; + if (r) return r; } - if (mpc < 0) return 1; - return seg->i->interferes_movposcomb_map & (1u << mpc); + *does_r= !SOMEP(mpc) || seg->i->interferes_movposcomb_map & (1u << mpc); + return 0; } -Segment *segment_interferes(TrackAdvanceContext *c, Segment *base) { - SegmentNum intern; - Segment *inter; - - intern= base->i->interferes; +ErrorCode segment_interferer_does(TrackAdvanceContext *c, Segment *base, + Segment *inter, int *does_r) { + ErrorCode ec; + int does; - if (!SOMEP(intern)) return 0; - if (!interfering_movposcomb(c,base)) return 0; + if (!inter) goto doesnt; - inter= &segments[intern]; + ec= interfering_movposcomb(c,base, &does); if (ec) return ec; + if (!does) goto doesnt; assert(base->i == &info_segments[inter->i->interferes]); - if (!interfering_movposcomb(c,inter)) return 0; + ec= interfering_movposcomb(c,inter, &does); if (ec) return ec; + if (!does) goto doesnt; + + doesnt: + *does_r= 0; + return 0; +} + +Segment *segment_interferes_simple(TrackAdvanceContext *c, Segment *base) { + Segment *inter= segment_interferer(base); + if (!inter) return 0; + + int does; + ErrorCode ec= segment_interferer_does(c,base,inter,&does); + assert(!ec); - return inter; + return does ? inter : 0; } int trackloc_reverse_exact(TrackLocation *t, TrackAdvanceContext *c) { -- 2.30.2