chiark / gitweb /
realtime: avoid needless signalling problems related to interference
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Mon, 3 Jan 2011 23:23:41 +0000 (23:23 +0000)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Mon, 3 Jan 2011 23:23:41 +0000 (23:23 +0000)
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
hostside/safety.c
hostside/safety.h
hostside/trackloc.c

index c9a42665db3a442573cf2a3f5d36d7f281c4d709..656c02523ff7e884bc6e529c69d126739fae4e5d 100644 (file)
@@ -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
index 9214599824af17ed352a7eca6ea99849418c4618..94d477832fabce5c2a7df882db1b5c948be49346 100644 (file)
@@ -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)
index d61e88a3b215e8c39c62917f9e9f7251fd80c214..46ef44fce90894a024f8bd6a8e19691d9e928348 100644 (file)
@@ -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
index e9125cb5e2c43f41af1db9de8de12665f2f6f5ca..6c8d59f0012adedfc7230234f96e630a59e0da28 100644 (file)
@@ -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) {