chiark / gitweb /
movpos: wip multiple movfeatkinds: new indep/meth protocol, is good. wip
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Wed, 29 Dec 2010 17:04:41 +0000 (17:04 +0000)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sat, 8 Jan 2011 22:44:47 +0000 (22:44 +0000)
hostside/movpos.c

index d6692864f5fc97b270f1c1237d5b109e8c9a0cf1..fc09eb3320e360eeaa01e9fa6a388032dba16680 100644 (file)
@@ -29,7 +29,7 @@ typedef struct Method Method;
  * at points when control flow  passes between kind and indep:
  *   U  Unallocated  no memory allocated (Change does not exist)
  *   P  Prepared     memory allocation done, basics filled in
- *   Q  Queued       reservation or confirmation successful
+ *   I  Installed    reservation or confirmation successful
  *   D  Done         motion is complete and callback is being entered
  *   G  Garbage      motion is complete and callback is being exited
  *
@@ -43,27 +43,31 @@ typedef struct Method Method;
 typedef struct Change Change;
 
 struct Change {                    /* valid in:  filled in by and when:      */
-  Method *meth;                    /*  PQ         indep after prepare()      */
-  MovPosChange *indep;             /*  P        indep after prepare()      */
+  Method *meth;                    /*  PIDG       indep after prepare()      */
+  MovPosChange *indep;             /*  PID        indep after prepare()      */
   /* kind-specific data follows */ /*  varies     kind-specific code, varies */
 } Change;
 
 struct Method {
   const char *pname;
-  MovFeatKind kind;
+  unsigned needcheck, needexec; /* used by indep to track T/Y/E */
+
   ErrorCode (*prepare)(Method *m,                                 /* TYE->T */
                       Segment *move,
                       int n_motions, const Motion *motions,
                       int ms, int confirming,
                       Change *chg_r,           /* 0->P; err: 0->0; may be 0 */
                       int *cost_r /* may be 0 */);
-  ErrorCode (*consider)(Method *m,                                 /* TYE->T */
-                       Change *remove,                   /* Q->P; err: Q->Q */
-                       Change *install);                 /* P->Q; err: P->P */
-      /* error: ET->T, no change to Changes */
   void (*dispose)(Method *m,                                       /* TY->TY */
                  Change*);                                          /* P->U */
 
+  ErrorCode (*install)(Method *m,                   /* TYE->T; err: TYE->TYY */
+                      Change *inst);                     /* P->I; err: P->P */
+      /* error: ET->T, no change to Changes */
+  void (*remove)(Method *m,                                      /* TYE->TYY */
+                Change *remove);                                    /* I->P */
+      /* error: ET->T, no change to Changes */
+
   ErrorCode (*check)(Method *m);                    /* TYE->Y; err: TYE->TYE */
   void (*execute)(Method *m);                                       /* EY->E */
   void (*all_abandon)(Method *m);                                       /* I */
@@ -346,21 +350,24 @@ static ErrorCode fsq_prepare(Method *mm, Segment *move,
   return 0;
 }
 
-static ErrorCode fsq_consider(Method *mm, Change *remove, Change *install) {
+static void fsq_dispose(Method *mm, Change *chg) {
   FsqMethod *m= (void*)mm;
-  FsqReq *remv= (FsqReq*)remove;
-  FsqReq *inst= (FsqReq*)install;
+  FsqReq *r= (FsqReq*)chg;
+  free(r);
+}
 
-  DPRINTF1(movpos,fsq, "%s consider ", m->m.pname);
+static void fsq_remove(Method *mm, Change *instchg) {
+  FsqMethod *m= (void*)mm;
+  FsqReq *remv= (FsqReq*)remvchg;
 
   fsq_dequeue(m, remv);
-  ErrorCode ec= fsq_enqueue(m, inst);
-  if (ec) {
-    ErrorCode ec2= fsq_enqueue(m, remv);
-    assert(!ec2);
-  }
-  DPRINTF1(movpos,fsq, " %s\n", ec2str(ec));
-  return ec;
+}
+
+static ErrorCode fsq_install(Method *mm, Change *instchg) {
+  FsqMethod *m= (void*)mm;
+  FsqReq *inst= (FsqReq*)instchg;
+
+  return fsq_enqueue(m, inst);
 }
 
 static ErrorCode fsq_check(Method *mm) { 
@@ -376,12 +383,6 @@ static void fsq_execute(Method *mm) {
   fsq_check_action(m);
 }
 
-static void fsq_dispose(Method *mm, Change *chg) {
-  FsqMethod *m= (void*)mm;
-  FsqReq *r= (FsqReq*)chg;
-  free(r);
-}
-
 /*---------- something to do ? ----------*/
 
 static void fsq_check_action(FsqMethod *m) {
@@ -587,32 +588,78 @@ static FsqMethod waggle= {
 
 /*========== dummy `nomove' kind ==========*/
 
-static ErrorCode nomove_prepare(Method *m, Segment *move,
+typedef struct NomoveChange {
+  Change h;
+  DLIST_NODE inqueue;
+  int n_motions;
+  Motion motions[];
+};
+
+typedef struct {
+  Method m;
+  unsigned eventqueued:1;
+  NomoveChange *queuehead;
+} NomoveMethod;
+
+static ErrorCode nomove_prepare(Method *meth_in, Segment *move,
                                int n_motions, const Motion *motions,
                                int ms, int confirming,
                                Change *chg_r, int *cost_r) {
   if (chg_r) {
-    *chg= mmalloc(sizeof(Change));
-    fixme
+    NomoveChange *chg;
+    chg= mmalloc(sizeof(*chg) + sizeof(Motion)*n_motions);
+    chg->n_motions= n_motions;
+    memcpy(chg->motions, motions, sizeof(Motion)*n_motions);
   }
   if (cost_r) {
     *cost_r= 0;
   }
   return 0;
 }
+static void nomove_dispose(Method *mm, Change *remvchg) {
+  NomoveChange *remv= (void*)remvchg;
+  free(remv);
+}
 
-static ErrorCode nomove_consider(Method *m, Change *remove, Change *install)
-  { return 0; }
+static ErrorCode nomove_install(Method *mm, Change *instchg) {
+  NomoveMethod *meth= (void*)mm;
+  NomoveChange *inst= (void*)instchg;
+  DLIST1_PREPEND(meth->queuehead, inst, inqueue);
+  return 0;
+}
+static void nomove_remove(Method *mm, Change *remvchg) {
+  NomoveMethod *meth= (void*)mm;
+  NomoveChange *remv= (void*)remvchg;
+  DLIST1_REMOVE(meth->queuehead, remv, inqueue);
+}
 
-static void nomove_dispose(Method *m, Change *chg) { }
-static ErrorCode nomove_check(Method *m) { return 0; }
-static ErrorCode nomove_execute(Method *m) {
-  fixme
+static ErrorCode nomove_check(Method *mm) { return 0; }
+
+static void (*nomove_execute_now)(oop_source *source, struct timeval tv,
+                                 void *meth_v) {
+  NomoveMethod *meth= meth_v;
+  meth->eventqueued= 0;
+  NomoveChange *done;
+  while ((done= meth->queuehead)) {
+    for (i=0; i<done->n_motions; i++)
+      method_update_feature(&meth->m, done->indep, &done->motions[i]);
+    method_change_done(&meth->m, &done->h);
+    DLIST1_REMOVE(meth->queuehead, done, inqueue);
+    nomove_dispose(&meth->m, &done->h);
+  }
 }
+static void nomove_execute(Method *mm) {
+  NomoveMethod *meth= (void*)mm;
+  if (!meth->eventqueued) {
+    meth->eventqueued= 1;
+    events->on_time(events, OOP_TIME_NOW, nomove_execute_now, meth);
+  }
+}
+
 static Method nomove_method= {
   "nomove", mfk_none,
-  nomove_prepare, nomove_consider, nomove_dispose,
+  nomove_prepare, nomove_dispose,
+  nomove_install, nomove_remove,
   nomove_check, nomove_execute, ignore_all_abandon
 };
 
@@ -621,22 +668,21 @@ static Method nomove_method= {
 struct MovPosChange {
   Segment *move;
   MovPosComb actual, target;
+  unsigned installed:1;
   int n_changes;
   Change *changes[];
 };
 
-
 static Method *methods[]= {
-  &nomove_method,
-  (Method*)&points_method,
-  (Method*)&waggle,
-  0
+  [mfk_none] = (Method*)&nomove_method,
+  [mfk_point] = (Method*)&points_method,
+  [mfk_relay] = (Method*)&waggle,
 };
 
 /*---------- entrypoints from methods ----------*/
 
 static void method_update_feature(Method *m, MovPosChange *indep,
-                                const Motion *mo) {
+                                 const Motion *mo) {
   /* Called from methods' execution logic when an individual feature
    * has been moved.  This is used by the method-independent code to
    * compute the correct delta set of movements from the current
@@ -684,13 +730,21 @@ static void method_change_done(Method *m, Change *chg) {
 
 /*---------- internal core machinery ----------*/
 
+static Method *feature_method(MovFeatInfo *feati) {
+  assert(feati->kind >= 0);
+  assert(feati->kind < ARRAY_SIZE(methods));
+  Method *meth= methods[feati->kind];
+  assert(meth);
+  return meth;
+}
+
 static int change_needed(const MovFeatInfo *feati,
                         MovPosComb startpoint, MovPosComb target) {
   int r;
   r= !SOMEP(startpoint) ||
     (target - startpoint) / feati->weight % feati->posns;
   DPRINTF(movpos,changeneeded, "%s:%s(%d*%d) %d..%d => %d\n",
-         methods[feati->kind]->pname, feati->pname,
+         feature_method(feati)->pname, feati->pname,
          feati->posns, feati->weight,
          startpoint, target, r);
   return r;
@@ -731,7 +785,7 @@ static ErrorCode indep_prepare(Segment *move, MovPosComb target,
        feat++, feati++) {
     if (!change_needed(feati,startpoint,target)) continue;
     MovPosComb posn= target / feati->weight % feati->posns;
-    Method *meth= methods[kind];
+    Method *meth= feature_method(feati);
 
     int methi;
     for (methi=0; methi<n_meths; methi++)
@@ -757,8 +811,9 @@ static ErrorCode indep_prepare(Segment *move, MovPosComb target,
     indep= mmalloc(sizeof(*indep) + sizeof(Change*) * n_meths);
     memset(indep->changes, 0, sizeof(Change*) * n_meths);
     indep->move= move;
-    indep->start= startpoint;
+    indep->actual= startpoint;
     indep->target= target;
+    indep->considering= 0;
   }
   DPRINTF(movpos,eval, "\n");
 
@@ -767,6 +822,8 @@ static ErrorCode indep_prepare(Segment *move, MovPosComb target,
   for (int changei=0; changei<n_meths; changei++) {
     Method *meth= meths[changei];
     int thiscost= 0;
+    meth->needcheck= 1;
+    meth->needexec= 1;
     ec= meth->prepare(meth,move,
                      n_motions[changei],motions[changei],
                      ms, confirming,
@@ -794,66 +851,58 @@ static ErrorCode indep_prepare(Segment *move, MovPosComb target,
   return ec;
 }
 
+static void indep_remove(MovPosChange *remv) {
+  if (!remv) return;
+  
+  for (i=0; i<remv->n_changes; i++) {
+    Change *chg= inst->changes[i];
+    if (!chg->installed) continue;
+    Method *meth= chg->meth;
+    meth->needexec= 1;
+    meth->remove(meth, chg);
+  }
+}
+
 static ErrorCode
-indep_consider(MovPosChange *remv, MovPosChange *inst) {
-  /* does consider and check; on failure, it does consider on remv
-   * and check (which is guaranteed to always succeed) */
-  assert(inst->n_changes <= 32);
-  assert(remv->n_changes <= 32);
-  uint32_t inst_done, remv_done;
-  int inst2remv[inst->n_changes]; /* valid only if inst_done; -ve => none */
-
-  int ii, jj;
+indep_install(MovPosChange *inst, int needcheck) {
+  /* if this fails, inst may be left partially installed */
+  if (!inst) return 0;
   
-  for (ii=0; ii<inst->n_changes; ii++) {
-    Method *meth= inst->changes[ii].meth;
-    for (jj=remv->n_changes-1; jj>=0; jj++)
-      if (remv->changes[jj].meth == meth) break;
-    ec= meth->consider(meth,
-                      jj>=0 ? remv->changes[jj] : 0,
-                      inst->changes[ii]);
+  for (i=0; i<inst->n_changes; i++) {
+    Change *chg= inst->changes[n_installed];
+    assert(!chg->installed);
+    Method *meth= chg->meth;
+    meth->needexec= 1;
+    ec= meth->install(meth, chg);
     if (ec) goto x;
+    chg->installed= 1;
 
-    inst_done |= (1UL << ii);
-    inst2remv[ii]= jj;
-    if (jj>=0) remv_done |= (1UL << jj);
-
-    ec= meth->check(meth);
-    if (ec) goto x;
-  }
-  for (jj=0; jj<remv->n_changes; jj++) {
-    if (remv_done & (1UL << jj)) continue;
-    ec= meth->consider(meth, remv->changes[jj], 0);
-    assert(!ec);
-    ec= meth->check(meth);
-    assert(!ec);
-    /* remv_done |= (1UL << jj);
-       not needed because we never roll back from here */
+    if (needcheck) {
+      meth->needcheck= 1;
+      ec= meth->check(meth);
+      if (ec) goto x;
+      meth->needcheck= 0;
+    }
   }
-  return 0;
+  inst->installed= 1;
 
  x:
-  for (ii=0; ii<inst->n_changes; ii++) {
-    if (!(inst_done & (1UL << ii))) continue;
-    Method *meth= inst->changes[ii].meth;
-    jj= inst2remv[ii];
-    ec= meth->consider(meth,
-                      inst->changes[ii],
-                      jj>=0 ? remv->changes[jj] : 0);
-    assert(!ec);
-    ec= meth->check(meth);
-    assert(!ec);
-  }
-  /* we do not need to unwind methods for which we are only removing
-   * since we never roll back after starting those */
   return ec;
 }
 
-static void indep_execute(void) {
+static void indep_check_execute(void) {
   for (Method **methwalk= methods;
        (meth= *methwalk);
        methwalk++) {
-    meth->execute(meth);
+    if (meth->needcheck) {
+      ec= meth->check(meth);
+      assert(!ec);
+      meth->needcheck= 0;
+    }
+    if (meth->needexec) {
+      meth->needexec= 0;
+      meth->execute(meth);
+    }
   }
 }
 
@@ -882,19 +931,20 @@ movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
          maxdelay_ms, movpos_pname(move,startpoint));
 
   ec= indep_prepare(move,target, startpoint,
-                     ms,0,
-                     &indep, 0);
+                   ms,0,
+                   &indep, 0);
   if (ec) return ec;
 
-  ec= indep_consider(0, indep);
+  ec= indep_install(indep, 1);
   if (ec) goto x;
 
-  indep_execute();
+  indep_check_execute();
   return 0;
 
  x:
+  indep_remove(indep);
   indep_dispose(indep);
-  indep_execute();
+  indep_check_execute();
   return ec;
 }
 
@@ -951,23 +1001,33 @@ ErrorCode movpos_change(Segment *move, MovPosComb target,
                    chg->meth->pname, chg->move->i->pname,
                    movpos_pname(chg->move, chg->intent));
 
-  MovPosChange *indep= 0;
+  MovPosChange *inst= 0;
 
   ec= indep_prepare(move,target, actual,
                    maxdelay_ms,1,
-                   &indep, 0);
+                   &inst, 0);
   if (ec) goto x;
 
-  ec= indep_consider(resv, indep);
+  indep_remove(resv);
+  indep_remove(move->motion);;
+
+  ec= indep_install(inst, 1);
   if (ec) goto x;
 
   indep_dispose(resv);
-  indep_execute();
+  indep_dispose(move->motion);
+
+  move->motion= inst;
+
+  indep_check_execute();
   return 0;
 
  x:
-  indep_dispose(indep);
-  indep_execute();
+  indep_remove(inst);
+  indep_dispose(inst);
+  ec= indep_install(move->motion, 0);  assert(!ec);
+  ec= indep_install(resv, 0);          assert(!ec);
+  indep_check_execute();
   return ec;
 }
 
@@ -976,10 +1036,9 @@ void movpos_unreserve(MovPosChange *resv) {
   DPRINTF(movpos,unreserve, "%s:%s/%s\n",
          res->meth->pname, res->move->i->pname,
          movpos_pname(res->move, res->intent));
-  ErrorCode ec= indep_consider(resv, 0);
-  assert(!ec);
+  indep_remove(resv);
   indep_dispose(resv);
-  indep_execute();
+  indep_check_execute();
 }
 
 MovPosComb movpos_change_intent(MovPosChange *indep) {