/* A record arriving via the loopback now leaves the feedback network. * Remove the detref structure and check for termination conditions. */ void SNetFeedbackLeave(snet_record_t *rec, landing_t *landing, fifo_t *detfifo) { snet_stack_t *stack; detref_t *detref, *first; trace(__func__); // record must have a stack of detrefs if ((stack = DATA_REC(rec, detref)) == NULL) { SNetUtilDebugFatal("[%s]: missing stack.", __func__); } // stack must have at least one detref if ((detref = SNetStackPop(stack)) == NULL) { SNetUtilDebugFatal("[%s]: empty stack.", __func__); } if (SNetStackIsEmpty(stack)) { SNetStackDestroy(stack); DATA_REC(rec, detref) = NULL; } // detref must refer to this DetLeave node if (detref->leave != landing) { SNetUtilDebugFatal("[%s]: leave %p != landing %p.", __func__, detref->leave, landing); } // reference counter must be at least two if (detref->refcount < 2) { SNetUtilDebugFatal("[%s]: refcnt %d < 1.", __func__, detref->refcount); } // decrease reference count if (DETREF_DECR(detref) == 1) { DETREF_DECR(detref); } assert(detref->refcount >= 0); // pop detrefs in sequence which have no more records in the loopback left. while ((first = SNetFifoPeekFirst(detfifo)) != NULL) { // stop processing if more records to come for this sequence counter if (first->refcount > 0) { break; } SNetFifoGet(detfifo); SNetFifoDone(&first->recfifo); SNetDelete(first); } }
snet_record_t *SNetRecCreate( snet_record_descr_t descr, ...) { snet_record_t *rec; va_list args; rec = SNetMemAlloc( sizeof( snet_record_t)); REC_DESCR( rec) = descr; va_start( args, descr); switch (descr) { case REC_data: RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( rec, data_rec) = SNetMemAlloc( sizeof( data_rec_t)); DATA_REC( rec, btags) = SNetIntMapCreate(0); DATA_REC( rec, tags) = SNetIntMapCreate(0); DATA_REC( rec, fields) = SNetRefMapCreate(0); DATA_REC( rec, mode) = MODE_binary; GenerateRecId( &DATA_REC( rec, rid) ); DATA_REC( rec, parent_rids) = NULL; DATA_REC( rec, interface_id) = 0; break; case REC_trigger_initialiser: RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); break; case REC_sync: { RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( rec, sync_rec) = SNetMemAlloc( sizeof( sync_rec_t)); SYNC_REC( rec, input) = va_arg( args, snet_stream_t *); SYNC_REC( rec, outtype) = NULL; } break; case REC_collect: RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( rec, coll_rec) = SNetMemAlloc( sizeof( coll_rec_t)); COLL_REC( rec, output) = va_arg( args, snet_stream_t*); break; case REC_terminate: RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( rec, terminate_rec) = SNetMemAlloc( sizeof( terminate_rec_t)); TERM_REC( rec, local) = false; break; case REC_sort_end: RECPTR( rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( rec, sort_end_rec) = SNetMemAlloc( sizeof( sort_end_rec_t)); SORT_E_REC( rec, level) = va_arg( args, int); SORT_E_REC( rec, num) = va_arg( args, int); break; default: SNetUtilDebugFatal("Unknown control record description. [%d]", descr); break; } va_end( args); return rec; }
void SNetRecDestroy( snet_record_t *rec) { int name; snet_ref_t *field; switch (REC_DESCR( rec)) { case REC_data: RECORD_FOR_EACH_FIELD(rec, name, field) { SNetRefDestroy(field); } SNetRefMapDestroy( DATA_REC( rec, fields)); SNetIntMapDestroy( DATA_REC( rec, tags)); SNetIntMapDestroy( DATA_REC( rec, btags)); if (DATA_REC( rec, parent_rids) != NULL) SNetRecIdListDestroy( DATA_REC( rec, parent_rids)); SNetMemFree( RECORD( rec, data_rec)); break; case REC_sync: { snet_variant_t *var = SYNC_REC( rec, outtype); if (var != NULL) { SNetVariantDestroy(var); } SNetMemFree( RECORD( rec, sync_rec)); } break; case REC_collect: SNetMemFree( RECORD( rec, coll_rec)); break; case REC_sort_end: SNetMemFree( RECORD( rec, sort_end_rec)); break; case REC_terminate: SNetMemFree( RECORD( rec, terminate_rec)); break; case REC_trigger_initialiser: break; default: SNetUtilDebugFatal("Unknown record description, in SNetRecDestroy"); break; }
snet_record_t *SNetRecCopy( snet_record_t *rec) { snet_record_t *new_rec; switch (REC_DESCR( rec)) { case REC_data: new_rec = SNetMemAlloc( sizeof( snet_record_t)); REC_DESCR( new_rec) = REC_data; RECPTR( new_rec) = SNetMemAlloc( sizeof( snet_record_types_t)); RECORD( new_rec, data_rec) = SNetMemAlloc( sizeof( data_rec_t)); DATA_REC( new_rec, fields) = SNetRefMapCopy(DATA_REC(rec, fields)); DATA_REC( new_rec, tags) = SNetIntMapCopy( DATA_REC( rec, tags)); DATA_REC( new_rec, btags) = SNetIntMapCopy( DATA_REC( rec, btags)); SNetRecSetInterfaceId( new_rec, SNetRecGetInterfaceId( rec)); SNetRecSetDataMode( new_rec, SNetRecGetDataMode( rec)); DATA_REC( new_rec, parent_rids) = NULL; /* (DATA_REC( rec, parent_rids)==NULL) ? NULL : SNetRecIdListCopy(DATA_REC( rec, parent_rids)); */ break; case REC_sort_end: new_rec = SNetRecCreate( REC_DESCR( rec), SORT_E_REC( rec, level), SORT_E_REC( rec, num)); break; case REC_terminate: new_rec = SNetRecCreate( REC_terminate); TERM_REC(new_rec, local) = TERM_REC(rec, local); break; default: new_rec = NULL; SNetUtilDebugFatal("Can't copy record of type %d", REC_DESCR( rec)); break; } return new_rec; }
/* 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); } }