* 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
*
typedef struct Change Change;
struct Change { /* valid in: filled in by and when: */
- Method *meth; /* PQ indep after prepare() */
- MovPosChange *indep; /* PQ 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 */
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) {
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) {
/*========== 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
};
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
/*---------- 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;
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++)
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");
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,
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);
+ }
}
}
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;
}
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;
}
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) {