/* Terminate any kind of feedback landing. */ void SNetTermFeedback(landing_t *land, fifo_t *fifo) { trace(__func__); if (land->type == LAND_feedback1) { landing_feedback1_t *fb1 = LAND_SPEC(land, feedback1); landing_feedback3_t *fb3 = LAND_SPEC(fb1->feedback3, feedback3); assert(fb3->terminate == FeedbackInitial); if (fb1->outdesc) { SNetFifoPut(fifo, fb1->outdesc); } if (fb1->instdesc) { snet_record_t *recdet = SNetRecCreate(REC_detref, -1L, fb1->feedback3, NULL); land->worker = SNetThreadGetSelf(); SNetWrite(&fb1->instdesc, recdet, false); SNetFifoPut(fifo, fb1->instdesc); } SNetLandingDone(fb1->feedback2); SNetLandingDone(fb1->feedback4); SNetLandingDone(fb1->feedback3); SNetFreeLanding(land); } else if (land->type == LAND_feedback2) { landing_feedback2_t *fb2 = LAND_SPEC(land, feedback2); if (fb2->instdesc) { SNetFifoPut(fifo, fb2->instdesc); } SNetLandingDone(fb2->feedback3); SNetFreeLanding(land); } else if (land->type == LAND_feedback3) { landing_feedback3_t *fb3 = LAND_SPEC(land, feedback3); SNetLandingDone(fb3->feedback4); SNetFreeLanding(land); } else if (land->type == LAND_feedback4) { landing_feedback4_t *fb4 = LAND_SPEC(land, feedback4); if (fb4->outdesc) { SNetFifoPut(fifo, fb4->outdesc); } SNetFreeLanding(land); } else { assert(0); } }
/* Terminate any kind of dripback landing. */ void SNetTermDripBack(landing_t *land, fifo_t *fifo) { trace(__func__); if (land->type == LAND_dripback1) { landing_dripback1_t *db1 = LAND_SPEC(land, dripback1); if (db1->controldesc) { snet_record_t *rec = SNetRecCreate(REC_terminate); land->worker = SNetThreadGetSelf(); SNetWrite(&db1->controldesc, rec, false); SNetFifoPut(fifo, db1->controldesc); } else { SNetLandingDone(db1->dripback2); } SNetFreeLanding(land); } else if (land->type == LAND_dripback2) { landing_dripback2_t *db2 = LAND_SPEC(land, dripback2); if (db2->instdesc) { fprintf(stderr, "%s: Premature termination of dripback2\n", __func__); SNetFifoPut(fifo, db2->instdesc); db2->instdesc = NULL; } if (db2->outdesc) { SNetFifoPut(fifo, db2->outdesc); db2->outdesc = NULL; } SNetFreeLanding(land); } else { assert(0); } }
/* Let go of multiple references to a stream descriptor. */ void SNetDescRelease(snet_stream_desc_t *desc, int count) { trace(__func__); assert(desc->refs >= count); if (DESC_DECR_MULTI(desc, count) == 0) { landing_t *land = desc->landing; SNetStreamClose(desc); SNetLandingDone(land); } }
/* Decrease the reference count of a stream descriptor by one. */ void SNetDescDone(snet_stream_desc_t *desc) { trace(__func__); assert(desc->refs > 0); if (DESC_DECR(desc) == 0) { landing_t *land = desc->landing; SNetStreamClose(desc); SNetLandingDone(land); } }
/* Terminate a garbage landing: decrease references to subsequent resources. */ void SNetTermGarbage(landing_t *land, fifo_t *fifo) { snet_stream_desc_t *desc = LAND_SPEC(land, siso)->outdesc; trace(__func__); assert(desc); assert(desc->refs > 0); SNetLandingDone(desc->landing); SNetFifoPut(fifo, desc); SNetFreeLanding(land); }
/* Terminate a star landing. */ void SNetTermStar(landing_t *land, fifo_t *fifo) { landing_star_t *lstar = LAND_SPEC(land, star); trace(__func__); if (lstar->instdesc) { SNetFifoPut(fifo, lstar->instdesc); } if (lstar->colldesc) { SNetFifoPut(fifo, lstar->colldesc); } if (lstar->instland) { SNetLandingDone(lstar->instland); } SNetLandingDone(lstar->collland); SNetFreeLanding(land); }
/* DripBack process a record. */ void SNetNodeDripBack(snet_stream_desc_t *desc, snet_record_t *rec) { landing_t *land = desc->landing; dripback_arg_t *darg = LAND_NODE_SPEC(land, dripback); trace(__func__); if (land->type == LAND_dripback1) { landing_dripback1_t *db1 = LAND_SPEC(land, dripback1); landing_dripback2_t *db2 = LAND_SPEC(db1->dripback2, dripback2); SNetFifoPut(db1->recfifo, rec); if (FAA(&db2->queued, 1) == 0) { if (db1->controldesc == NULL) { SNetPushLanding(desc, db1->dripback2); db1->controldesc = SNetStreamOpen(darg->selfref, desc); } rec = SNetRecCreate(REC_wakeup); SNetWrite(&db1->controldesc, rec, true); } } else if (land->type == LAND_dripback2) { landing_dripback2_t *db2 = LAND_SPEC(land, dripback2); bool via_access = (DESC_STREAM(desc) == darg->selfref); assert(via_access || DESC_STREAM(desc) == darg->dripback); while (rec) { switch (REC_DESCR( rec)) { case REC_data: /* Test if record should go to the instance. */ if (SNetFeedbackMatch( rec, darg->back_patterns, darg->guards)) { if (via_access) { /* Because record came from outside add a detref counter. */ assert(db2->detfifo.head->next == NULL); SNetRecDetrefAdd(rec, ++(db2->entered), land, &db2->detfifo); } else { /* Record came from the instance. */ assert(DATA_REC(rec, detref)); } if (db2->instdesc == NULL) { /* Instance should come back to this landing. */ if (SNetTopLanding(desc) != land) { SNetPushLanding(desc, land); } db2->instdesc = SNetStreamOpen(darg->instance, desc); if (SNetTopLanding(desc) == land) { SNetPopLanding(desc); SNetLandingDone(land); } } SNetWrite(&db2->instdesc, rec, false); } else { if (!via_access) { /* Record leaves the dripback loop. */ assert(DATA_REC(rec, detref)); SNetFeedbackLeave(rec, land, &db2->detfifo); } if (db2->outdesc == NULL) { db2->outdesc = SNetStreamOpen(darg->output, desc); } SNetWrite(&db2->outdesc, rec, false); } break; case REC_wakeup: assert(via_access); SNetRecDestroy(rec); break; case REC_terminate: assert(via_access); assert(db2->terminate == DripBackInitial); db2->terminate = DripBackDraining; SNetRecDestroy(rec); break; case REC_detref: if (DETREF_REC( rec, leave) == land && DETREF_REC( rec, location) == SNetDistribGetNodeId()) { assert(!via_access); SNetDetLeaveCheckDetref(rec, &db2->detfifo); if (DETREF_REC( rec, detref) == SNetFifoPeekFirst(&db2->detfifo)) { DripBackCheckBusy(db2); } SNetRecDestroy(rec); } else { assert(via_access); if (db2->outdesc == NULL) { db2->outdesc = SNetStreamOpen(darg->output, desc); } SNetWrite(&db2->outdesc, rec, false); } break; case REC_sync: SNetRecDestroy(rec); break; default: SNetRecUnknownEnt(__func__, rec, darg->entity); } rec = NULL; if (db2->state == DripBackBusy) { if (DripBackCheckBusy(db2) == false) { assert(db2->queued > 0); if (SAF(&db2->queued, 1) == 0) { db2->state = DripBackIdle; } else { rec = SNetFifoGet(&db2->recfifo); assert(rec); via_access = true; } } } else { assert(db2->state == DripBackIdle); assert(SNetFifoPeekFirst(&db2->detfifo) == NULL); if (db2->queued > 0) { rec = SNetFifoGet(&db2->recfifo); assert(rec); via_access = true; db2->state = DripBackBusy; } } } if (db2->terminate == DripBackDraining) { if (db2->state == DripBackIdle) { assert(db2->queued == 0 && DripBackCheckBusy(db2) == false); db2->terminate = DripBackTerminated; } } if (db2->terminate == DripBackTerminated) { if (db2->instdesc) { snet_stream_desc_t *desc = db2->instdesc; db2->instdesc = NULL; SNetDescDone(desc); SNetLandingDone(land); } } } else { assert(0); } }
/* Feedback forward a record. */ void SNetNodeFeedback(snet_stream_desc_t *desc, snet_record_t *rec) { landing_t *land = desc->landing; feedback_arg_t *farg = LAND_NODE_SPEC(land, feedback); trace(__func__); if (land->type == LAND_feedback1) { landing_feedback1_t *fb1 = LAND_SPEC(land, feedback1); switch (REC_DESCR( rec)) { case REC_data: /* Test if record should go into the feedback loop. */ if (SNetFeedbackMatch( rec, farg->back_patterns, farg->guards)) { /* Because record came from outside add a detref counter. */ SNetRecDetrefAdd(rec, ++(fb1->counter), fb1->feedback3, fb1->detfifo); if (fb1->instdesc == NULL) { SNetPushLanding(desc, fb1->feedback2); fb1->instdesc = SNetStreamOpen(farg->selfref2, desc); } SNetWrite(&fb1->instdesc, rec, true); } else { if (fb1->outdesc == NULL) { SNetPushLanding(desc, fb1->feedback4); fb1->outdesc = SNetStreamOpen(farg->selfref4, desc); } SNetWrite(&fb1->outdesc, rec, true); } break; case REC_detref: if (fb1->outdesc == NULL) { SNetPushLanding(desc, fb1->feedback4); fb1->outdesc = SNetStreamOpen(farg->selfref4, desc); } SNetWrite(&fb1->outdesc, rec, true); break; case REC_sync: SNetRecDestroy(rec); break; default: SNetRecUnknownEnt(__func__, rec, farg->entity); } } else if (land->type == LAND_feedback2) { landing_feedback2_t *fb2 = LAND_SPEC(land, feedback2); if (fb2->instdesc == NULL) { SNetPushLanding(desc, fb2->feedback3); fb2->instdesc = SNetStreamOpen(farg->instance, desc); } switch (REC_DESCR( rec)) { case REC_data: case REC_detref: SNetWrite(&fb2->instdesc, rec, true); break; default: SNetRecUnknownEnt(__func__, rec, farg->entity); } } else if (land->type == LAND_feedback4) { landing_feedback4_t *fb4 = LAND_SPEC(land, feedback4); if (fb4->outdesc == NULL) { fb4->outdesc = SNetStreamOpen(farg->output, desc); } switch (REC_DESCR( rec)) { case REC_data: case REC_detref: SNetWrite(&fb4->outdesc, rec, true); break; default: SNetRecUnknownEnt(__func__, rec, farg->entity); } } else if (land->type == LAND_feedback3) { landing_feedback3_t *fb3 = LAND_SPEC(land, feedback3); if (fb3->terminate == FeedbackTerminated) { assert(REC_DESCR( rec) != REC_data); SNetRecDestroy(rec); } else { switch (REC_DESCR( rec)) { case REC_data: /* Test if record should go into the feedback loop. */ if (SNetFeedbackMatch( rec, farg->back_patterns, farg->guards)) { if (fb3->instdesc == NULL) { SNetPushLanding(desc, fb3->feedback2); fb3->instdesc = SNetStreamOpen(farg->selfref2, desc); } /* send the record to the instance */ SNetWrite(&fb3->instdesc, rec, false); } else { /* record leaves the feedback loop. */ SNetFeedbackLeave(rec, land, &fb3->detfifo); if (fb3->outdesc == NULL) { SNetPushLanding(desc, fb3->feedback4); fb3->outdesc = SNetStreamOpen(farg->selfref4, desc); } /* forward record outwards */ SNetWrite(&fb3->outdesc, rec, false); if (fb3->terminate) { assert(fb3->terminate == FeedbackDraining); FeedbackCheckBusy(fb3); } } break; case REC_detref: if (DETREF_REC( rec, leave) == land) { if (DETREF_REC( rec, seqnr) == -1L) { assert(fb3->terminate == FeedbackInitial); fb3->terminate = FeedbackDraining; } SNetRecDestroy(rec); FeedbackCheckBusy(fb3); } break; case REC_sync: SNetRecDestroy(rec); break; default: SNetRecUnknownEnt(__func__, rec, farg->entity); } if (fb3->terminate == FeedbackTerminating) { if (fb3->outdesc) { SNetDescDone(fb3->outdesc); } if (fb3->instdesc) { SNetDescDone(fb3->instdesc); } SNetLandingDone(fb3->feedback2); fb3->terminate = FeedbackTerminated; } } } else { assert(0); } }
/* Send a record to a stream which may need to be opened */ static void StarWrite(star_write_t kind, snet_record_t *rec, snet_stream_desc_t *desc) { const star_arg_t *sarg = DESC_NODE_SPEC(desc, star); landing_star_t *land = DESC_LAND_SPEC(desc, star); switch (kind) { case WriteCollector: /* check if open */ if (!land->colldesc) { /* first landing must be collector */ if (SNetTopLanding(desc) != land->collland) { SNetPushLanding(desc, land->collland); } land->colldesc = SNetStreamOpen(sarg->collector, desc); } SNetWrite(&land->colldesc, rec, true); break; case WriteInstance: /* check if open */ if (!land->instdesc) { /* first landing must be instance */ if (SNetTopLanding(desc) != land->instland) { SNetPushLanding(desc, land->instland); } land->instdesc = SNetStreamOpen(sarg->instance, desc); /* remove instance landing */ if (SNetTopLanding(desc) == land->instland) { SNetPopLanding(desc); SNetLandingDone(land->instland); } /* prevent double deallocation */ land->instland = NULL; /* emit output record to instance */ SNetWrite(&land->instdesc, rec, true); } else { /* A star is superfluous when the next landing is its incarnation. */ bool superfluous = (desc->landing->node == land->instdesc->landing->node); /* emit output record to instance */ SNetWrite(&land->instdesc, rec, (superfluous == false)); /* If instance has been garbage collected then dissolve. */ if (superfluous) { /* Possibly forward leader status to next incarnation. */ rec = (land->star_leader && (sarg->is_det | sarg->is_detsup)) ? SNetRecCreate(REC_star_leader, land->detenter.counter, land->detenter.seqnr) : NULL; land->star_leader = false; /* Discard stream towards collector. */ if (land->colldesc) { SNetDescDone(land->colldesc); } /* Discard collector landing. */ SNetLandingDone(land->collland); /* Change landing into identity, which can be garbage collected. */ SNetBecomeIdentity(desc->landing, land->instdesc); /* Finally, notify incarnation of new leader status. */ if (rec) { SNetWrite(&(DESC_LAND_SPEC(desc, identity)->outdesc), rec, true); } } } break; default: assert(0); } }