/** * A custom creation function for instances of star operands * - having a separate function here allows for distinction * of an "ordinary" serial combinator and * another replica of the serial replicator (star) */ static snet_stream_t *SNetSerialStarchild(snet_stream_t *input, snet_info_t *info, int location, snet_startup_fun_t box_a, snet_startup_fun_t box_b) { snet_stream_t *internal_stream; snet_stream_t *output; snet_locvec_t *locvec; locvec = SNetLocvecGet(info); (void) SNetLocvecStarSpawn(locvec); /* create operand A */ SNetRouteDynamicEnter(info, SNetLocvecTopval(SNetLocvecGet(info)), location, box_a); internal_stream = (*box_a)(input, info, location); internal_stream = SNetRouteUpdate(info, internal_stream, location); SNetRouteDynamicExit(info, SNetLocvecTopval(SNetLocvecGet(info)), location, box_a); assert( SNetLocvecStarWithin(SNetLocvecGet(info)) ); /* create operand B */ output = (*box_b)(internal_stream, info, location); (void) SNetLocvecStarSpawnRet(locvec); return(output); }
/** * Convenience function for creating * Split, DetSplit, LocSplit or LocSplitDet, * dependent on parameters is_byloc and is_det */ snet_stream_t *CreateSplit( snet_stream_t *input, snet_info_t *info, snet_locvec_t *locvec, int location, snet_ast_t *box_a, int ltag, int utag, bool is_byloc, bool is_det ) { snet_info_t *newInfo = SNetInfoCopy(info); snet_stream_t *initial, *output; split_arg_t *sarg; snet_locvec_t *locvec; locvec = SNetLocvecGet(info); SNetLocvecSplitEnter(locvec); SNetLocvecSet(newInfo, SNetLocvecCopy(locvec)); input = SNetRouteUpdate(newInfo, input, location); if(SNetDistribIsNodeLocation(location)) { initial = SNetStreamCreate(0); sarg = (split_arg_t *) SNetMemAlloc( sizeof( split_arg_t)); sarg->input = input; sarg->output = initial; sarg->boxfun = box_a; sarg->info = newInfo; sarg->ltag = ltag; sarg->utag = utag; sarg->is_det = is_det; sarg->is_byloc = is_byloc; sarg->location = location; SNetThreadingSpawn( SNetEntityCreate( ENTITY_split, location, locvec, "<split>", SplitBoxTask, (void*)sarg) ); output = CollectorCreateDynamic( initial, location, info); } else { SNetLocvecDestroy(SNetLocvecGet(newInfo)); SNetInfoDestroy(newInfo); output = input; } SNetLocvecSplitLeave(locvec); return output; }
/** * Create the instance of the operand network, including * routing component (star incarnate) at the end */ static void CreateOperandNetwork(snet_stream_desc_t **next, star_arg_t *sarg, snet_stream_desc_t *to_coll) { /* info structure for network creation */ /* The outstream to the collector from a newly created incarnate. Nothing is written to this stream, but it has to be registered at the collector. */ snet_stream_t *starstream, *nextstream_addr; /* Create the stream to the instance */ nextstream_addr = SNetStreamCreate(0); /* Set the source of the stream to support garbage collection */ SNetStreamSetSource(nextstream_addr, SNetLocvecGet(sarg->info)); /* open the stream for the caller */ *next = SNetStreamOpen(nextstream_addr, 'w'); /* use custom creation function for proper/easier update of locvec */ starstream = SNetSerialStarchild( nextstream_addr, sarg->info, sarg->location, sarg->box, sarg->selffun ); /* notify collector about the new instance */ SNetStreamWrite( to_coll, SNetRecCreate(REC_collect, starstream)); }
/** * Collector creation function * @pre num >= 1 */ snet_stream_t *CollectorCreateStatic( int num, snet_stream_t **instreams, int location, snet_info_t *info) { snet_stream_t *outstream; coll_arg_t *carg; int i; assert(num >= 1); /* create outstream */ outstream = SNetStreamCreate(0); /* create collector handle */ carg = (coll_arg_t *) SNetMemAlloc( sizeof( coll_arg_t)); carg->output = outstream; carg->is_static = true; CARG_ST(carg, num) = num; /* copy instreams */ CARG_ST(carg, inputs) = SNetMemAlloc(num * sizeof(snet_stream_t *)); for(i=0; i<num; i++) { CARG_ST(carg, inputs[i]) = instreams[i]; } /* spawn collector task */ SNetThreadingSpawn( SNetEntityCreate( ENTITY_collect, location, SNetLocvecGet(info), "<collect>", CollectorTask, (void*)carg) ); return outstream; }
/* DripBack creation function */ snet_stream_t *SNetDripBack( snet_stream_t *input, snet_info_t *info, int location, snet_variant_list_t *back_patterns, snet_expr_list_t *guards, snet_startup_fun_t box_a) { snet_stream_t *output; node_t *node; dripback_arg_t *darg; snet_locvec_t *locvec; int detlevel; trace(__func__); detlevel = SNetDetSwapLevel(0); locvec = SNetLocvecGet(info); SNetLocvecFeedbackEnter(locvec); output = SNetStreamCreate(0); node = SNetNodeNew(NODE_dripback, location, &input, 1, &output, 1, SNetNodeDripBack, SNetStopDripBack, SNetTermDripBack); darg = NODE_SPEC(node, dripback); /* fill in the node argument */ darg->input = input; darg->output = output; darg->back_patterns = back_patterns; darg->guards = guards; darg->stopping = 0; /* Create the instance network */ darg->instance = SNetNodeStreamCreate(node); SNetSubnetIncrLevel(); darg->dripback = (*box_a)(darg->instance, info, location); SNetSubnetDecrLevel(); STREAM_DEST(darg->dripback) = node; SNetNodeTableAdd(darg->dripback); /* Create one self-referencing stream. */ darg->selfref = SNetNodeStreamCreate(node); STREAM_DEST(darg->selfref) = node; SNetNodeTableAdd(darg->selfref); darg->entity = SNetEntityCreate( ENTITY_fbdisp, location, locvec, "<feedback>", NULL, (void*)darg); SNetLocvecFeedbackLeave(locvec); SNetDetSwapLevel(detlevel); return output; }
static void TerminateStarBoxTask(snet_stream_desc_t *outstream, star_arg_t *sarg) { /* close streams */ SNetStreamClose( outstream, false); /* destroy the task argument */ SNetExprListDestroy( sarg->guards); SNetLocvecDestroy(SNetLocvecGet(sarg->info)); SNetInfoDestroy(sarg->info); SNetVariantListDestroy( sarg->exit_patterns); SNetMemFree( sarg); }
/** * Collector creation function */ snet_stream_t *CollectorCreateDynamic( snet_stream_t *instream, int location, snet_info_t *info) { snet_stream_t *outstream; coll_arg_t *carg; /* create outstream */ outstream = SNetStreamCreate(0); /* create collector handle */ carg = (coll_arg_t *) SNetMemAlloc( sizeof( coll_arg_t)); carg->output = outstream; carg->is_static = false; CARG_DYN(carg, input) = instream; /* spawn collector task */ SNetThreadingSpawn( SNetEntityCreate( ENTITY_collect, location, SNetLocvecGet(info), "<collect>", CollectorTask, (void*)carg) ); return outstream; }
/** * Split box task. * * Implements both the non-deterministic and deterministic variants. */ static void SplitBoxTask(snet_entity_t *ent, void *arg) { int i; split_arg_t *sarg = (split_arg_t *)arg; snet_stream_desc_t *initial, *instream; int ltag_val, utag_val; snet_info_t *info; snet_record_t *rec; snet_locvec_t *locvec; bool terminate = false; /* a list of all outstreams for all yet created instances */ snet_streamset_t repos_set = NULL; snet_stream_iter_t *iter = SNetStreamIterCreate( &repos_set); /* a hashtable for fast lookup, initial capacity = 2^4 = 16 */ hashtab_t *repos_tab = HashtabCreate( 4); (void) ent; /* NOT USED */ /* for deterministic variant: */ int counter = 0; initial = SNetStreamOpen(sarg->output, 'w'); instream = SNetStreamOpen(sarg->input, 'r'); /* MAIN LOOP START */ while( !terminate) { /* read from input stream */ rec = SNetStreamRead( instream); switch( SNetRecGetDescriptor( rec)) { case REC_data: /* get lower and upper tag values */ ltag_val = SNetRecGetTag( rec, sarg->ltag); utag_val = SNetRecGetTag( rec, sarg->utag); /* for all tag values */ for( i = ltag_val; i <= utag_val; i++) { snet_stream_desc_t *outstream = HashtabGet( repos_tab, i); if( outstream == NULL) { snet_stream_t *temp_stream; snet_stream_t *newstream_addr = SNetStreamCreate(0); /* instance does not exist yet, create it */ outstream = SNetStreamOpen(newstream_addr, 'w'); /* add to lookup table */ HashtabPut( repos_tab, i, outstream); /* add to list */ SNetStreamsetPut( &repos_set, outstream); /* create info and location vector for creation of this replica */ info = SNetInfoCopy(sarg->info); locvec = SNetLocvecSplitSpawn(SNetLocvecGet(sarg->info), i); SNetLocvecSet(info, locvec); if( sarg->is_byloc) { SNetRouteDynamicEnter(info, i, i, sarg->boxfun); temp_stream = sarg->boxfun(newstream_addr, info, i); temp_stream = SNetRouteUpdate(info, temp_stream, sarg->location); SNetRouteDynamicExit(info, i, i, sarg->boxfun); } else { SNetRouteDynamicEnter(info, i, sarg->location, sarg->boxfun); temp_stream = sarg->boxfun(newstream_addr, info, sarg->location); temp_stream = SNetRouteUpdate(info, temp_stream, sarg->location); SNetRouteDynamicExit(info, i, sarg->location, sarg->boxfun); } /* destroy info and location vector */ SNetLocvecDestroy(locvec); SNetInfoDestroy(info); if(temp_stream != NULL) { /* notify collector about the new instance via initial */ SNetStreamWrite( initial, SNetRecCreate( REC_collect, temp_stream)); } } /* end if (outstream==NULL) */ /* multicast the record */ SNetStreamWrite( outstream, /* copy record for all but the last tag value */ (i!=utag_val) ? SNetRecCopy( rec) : rec ); } /* end for all tags ltag_val <= i <= utag_val */ /* If deterministic, append a sort record to *all* registered * instances and the initial stream. */ if( sarg->is_det ) { /* reset iterator */ SNetStreamIterReset( iter, &repos_set); while( SNetStreamIterHasNext( iter)) { snet_stream_desc_t *cur_stream = SNetStreamIterNext( iter); SNetStreamWrite( cur_stream, SNetRecCreate( REC_sort_end, 0, counter)); } /* Now also send a sort record to initial, after the collect records for new instances have been sent */ SNetStreamWrite( initial, SNetRecCreate( REC_sort_end, 0, counter)); } /* increment counter for deterministic variant */ counter += 1; break; case REC_sync: { snet_stream_t *newstream = SNetRecGetStream( rec); SNetStreamReplace( instream, newstream); SNetRecDestroy( rec); } break; case REC_sort_end: /* broadcast the sort record */ SNetStreamIterReset( iter, &repos_set); /* all instances receive copies of the record */ while( SNetStreamIterHasNext( iter)) { snet_stream_desc_t *cur_stream = SNetStreamIterNext( iter); SNetStreamWrite( cur_stream, SNetRecCreate( REC_sort_end, /* we have to increase level */ SNetRecGetLevel( rec)+1, SNetRecGetNum( rec)) ); } /* send the original record to the initial stream, but with increased level */ SNetRecSetLevel( rec, SNetRecGetLevel( rec) + 1); SNetStreamWrite( initial, rec); break; case REC_terminate: SNetStreamIterReset( iter, &repos_set); /* all instances receive copies of the record */ while( SNetStreamIterHasNext( iter)) { snet_stream_desc_t *cur_stream = SNetStreamIterNext( iter); SNetStreamWrite( cur_stream, SNetRecCopy( rec)); SNetStreamIterRemove( iter); /* close the stream to the instance */ SNetStreamClose( cur_stream, false); } /* send the original record to the initial stream */ SNetStreamWrite( initial, rec); /* note that no sort record has to be appended */ terminate = true; break; case REC_collect: /* invalid control record */ default: assert( 0); /* if ignore, at least destroy it */ SNetRecDestroy( rec); } } /* MAIN LOOP END */ /* destroy repository */ HashtabDestroy( repos_tab); SNetStreamIterDestroy( iter); /* close and destroy initial stream */ SNetStreamClose( initial, false); /* close instream */ SNetStreamClose( instream, true); SNetLocvecDestroy(SNetLocvecGet(sarg->info)); SNetInfoDestroy(sarg->info); /* destroy the argument */ SNetMemFree( sarg); } /* END of SPLIT BOX TASK */
/** * Convenience function for creating * Star, DetStar, StarIncarnate or DetStarIncarnate, * dependent on parameters is_incarnate and is_det */ static snet_stream_t *CreateStar( snet_stream_t *input, snet_info_t *info, int location, snet_variant_list_t *exit_patterns, snet_expr_list_t *guards, snet_startup_fun_t box_a, snet_startup_fun_t box_b, bool is_incarnate, bool is_det ) { snet_stream_t *output; star_arg_t *sarg; snet_stream_t *newstream; snet_locvec_t *locvec; locvec = SNetLocvecGet(info); if (!is_incarnate) { SNetLocvecStarEnter(locvec); input = SNetRouteUpdate(info, input, location); } else { input = SNetRouteUpdate(info, input, location); } if(SNetDistribIsNodeLocation(location)) { /* create the task argument */ sarg = SNetMemAlloc( sizeof(star_arg_t)); newstream = SNetStreamCreate(0); sarg->instream = SNetStreamOpen(input, 'r'); sarg->outstream = SNetStreamOpen(newstream, 'w'); sarg->nextstream = NULL; sarg->box = box_a; sarg->selffun = box_b; sarg->exit_patterns = exit_patterns; sarg->guards = guards; sarg->info = SNetInfoCopy(info); SNetLocvecSet(sarg->info, SNetLocvecCopy(locvec)); sarg->is_incarnate = is_incarnate; sarg->is_det = is_det; sarg->location = location; sarg->sync_cleanup = false; sarg->counter = 0; SNetThreadingSpawn( ENTITY_star, location, locvec, "<star>", &StarBoxTask, sarg); /* creation function of top level star will return output stream * of its collector, the incarnates return their outstream */ if (!is_incarnate) { /* the "top-level" star also creates a collector */ output = CollectorCreateDynamic(newstream, location, info); } else { output = newstream; } } else { SNetExprListDestroy( guards); SNetVariantListDestroy(exit_patterns); output = input; } if (!is_incarnate) SNetLocvecStarLeave(SNetLocvecGet(info)); return( output); }
/** * Star component task */ static void StarBoxTask(void *arg) { star_arg_t *sarg = arg; snet_record_t *rec; /* read from input stream */ rec = SNetStreamRead( sarg->instream); switch( SNetRecGetDescriptor( rec)) { case REC_data: if( MatchesExitPattern( rec, sarg->exit_patterns, sarg->guards)) { assert(!sarg->sync_cleanup); #ifdef DEBUG_PRINT_GC SNetUtilDebugNoticeEnt( ent, "[STAR] Notice: Data leaves replication network."); #endif /* send rec to collector */ SNetStreamWrite( sarg->outstream, rec); } else { /* if instance has not been created yet, create it */ if( sarg->nextstream == NULL) { CreateOperandNetwork(&sarg->nextstream, sarg, sarg->outstream); } /* send the record to the instance */ SNetStreamWrite( sarg->nextstream, rec); } /* end if not matches exit pattern */ /* deterministic non-incarnate has to append control records */ if (sarg->is_det && !sarg->is_incarnate) { /* send new sort record to collector level=0, counter=0*/ SNetStreamWrite( sarg->outstream, SNetRecCreate( REC_sort_end, 0, sarg->counter) ); /* if has next instance, send new sort record */ if (sarg->nextstream != NULL) { SNetStreamWrite( sarg->nextstream, SNetRecCreate( REC_sort_end, 0, sarg->counter) ); } /* increment counter */ sarg->counter++; } #ifdef ENABLE_GC else if (sarg->sync_cleanup) { snet_record_t *term_rec; /* * If sync_cleanup is set, we decided to postpone termination * due to garbage collection triggered by a sync record until now. * Postponing was done in order not to create the operand network unnecessarily * only to be able to forward the sync record. */ assert( sarg->nextstream != NULL); /* first send a sync record to the next instance */ SNetStreamWrite( sarg->nextstream, SNetRecCreate( REC_sync, SNetStreamGet(sarg->instream)) ); /* send a terminate record to collector, it will close and destroy the stream */ term_rec = SNetRecCreate(REC_terminate); SNetRecSetFlag(term_rec); SNetStreamWrite( sarg->outstream, term_rec); #ifdef DEBUG_PRINT_GC /* terminating due to GC */ SNetUtilDebugNoticeEnt( ent, "[STAR] Notice: Destroying star dispatcher due to GC, " "delayed until new data record!" ); #endif SNetStreamClose(sarg->nextstream, false); SNetStreamClose(sarg->instream, false); TerminateStarBoxTask(sarg->outstream,sarg); return; } #endif /* ENABLE_GC */ break; case REC_sync: { snet_stream_t *newstream = SNetRecGetStream( rec); #ifdef ENABLE_GC snet_locvec_t *loc = SNetStreamGetSource( newstream); #ifdef DEBUG_PRINT_GC if (loc != NULL) { int size = SNetLocvecPrintSize(loc) + 1; char srecloc[size]; srecloc[size - 1] = '\0'; SNetLocvecPrint(srecloc, loc); SNetUtilDebugNoticeTask( "[STAR] Notice: Received sync record with a stream with source %s.", srecloc ); } #endif /* TODO * It is not necessary to carry the whole location vector in the * next stream of a star-entity, only a flag. As a prerequisite, * non_incarnates must not clean themselves up! */ /* * Only incarnates are eligible for cleanup! * check if the source (location) of the stream and the own location are * (subsequent) star dispatcher entities of the same star combinator network * -> if so, we can clean-up ourselves */ if ( sarg->is_incarnate && loc != NULL ) { assert( true == SNetLocvecEqualParent(loc, SNetLocvecGet(sarg->info)) ); /* If the next instance is already created, we can forward the sync-record * immediately and terminate. * Otherwise we postpone termination to the point when a next data record * is received, as we create the operand network then. */ if (sarg->nextstream != NULL) { snet_record_t *term_rec; /* forward the sync record */ SNetStreamWrite( sarg->nextstream, rec); /* send a terminate record to collector, it will close and destroy the stream */ term_rec = SNetRecCreate(REC_terminate); SNetRecSetFlag(term_rec); SNetStreamWrite( sarg->outstream, term_rec); #ifdef DEBUG_PRINT_GC /* terminating due to GC */ SNetUtilDebugNoticeEnt( ent, "[STAR] Notice: Destroying star dispatcher due to GC, " "immediately on sync!" ); #endif SNetStreamClose(sarg->nextstream, false); SNetStreamClose(sarg->instream, true); TerminateStarBoxTask(sarg->outstream,sarg); return; } else { sarg->sync_cleanup = true; #ifdef DEBUG_PRINT_GC SNetUtilDebugNoticeEnt( ent, "[STAR] Notice: Remembering delayed destruction."); #endif /* handle sync record as usual */ SNetStreamReplace( sarg->instream, newstream); SNetRecDestroy( rec); } } else #endif /* ENABLE_GC */ { /* handle sync record as usual */ SNetStreamReplace( sarg->instream, newstream); SNetRecDestroy( rec); } } break; case REC_sort_end: { int rec_lvl = SNetRecGetLevel(rec); /* send a copy to the box, if exists */ if( sarg->nextstream != NULL) { SNetStreamWrite( sarg->nextstream, SNetRecCreate( REC_sort_end, (!sarg->is_incarnate)? rec_lvl+1 : rec_lvl, SNetRecGetNum(rec) ) ); } /* send the original one to the collector */ if (!sarg->is_incarnate) { /* if non-incarnate, we have to increase level */ SNetRecSetLevel( rec, rec_lvl+1); } SNetStreamWrite( sarg->outstream, rec); } break; case REC_terminate: if( sarg->nextstream != NULL) { SNetStreamWrite( sarg->nextstream, SNetRecCopy( rec)); SNetStreamClose( sarg->nextstream, false); } SNetStreamWrite( sarg->outstream, rec); /* note that no sort record has to be appended */ SNetStreamClose(sarg->instream, true); TerminateStarBoxTask(sarg->outstream,sarg); return; case REC_collect: default: SNetUtilDebugFatal("Unknown record type!"); /* if ignore, at least destroy ... */ SNetRecDestroy( rec); } SNetThreadingRespawn(NULL); }
/** * Box creation function */ snet_stream_t *SNetBox(snet_stream_t *input, snet_info_t *info, int location, const char *boxname, snet_box_fun_t boxfun, snet_exerealm_create_fun_t er_create, snet_exerealm_update_fun_t er_update, snet_exerealm_destroy_fun_t er_destroy, snet_int_list_list_t *output_variants) { int i,j; snet_stream_t *output; box_arg_t *barg; snet_variant_list_t *vlist; input = SNetRouteUpdate(info, input, location); if(SNetDistribIsNodeLocation(location)) { output = SNetStreamCreate(0); vlist = SNetVariantListCreate(0); for(i=0; i<SNetIntListListLength(output_variants); i++) { snet_int_list_t *l = SNetIntListListGet(output_variants, i); snet_variant_t *v = SNetVariantCreateEmpty(); for(j=0; j<SNetIntListLength(l); j+=2) { switch(SNetIntListGet(l, j)) { case field: SNetVariantAddField(v, SNetIntListGet(l, j+1)); break; case tag: SNetVariantAddTag(v, SNetIntListGet(l, j+1)); break; case btag: SNetVariantAddBTag(v, SNetIntListGet(l, j+1)); break; default: assert(0); } } SNetVariantListAppendEnd(vlist, v); } barg = (box_arg_t *) SNetMemAlloc(sizeof(box_arg_t)); barg->input = input; barg->output = output; barg->boxfun = boxfun; barg->exerealm_create = er_create; barg->exerealm_update = er_update; barg->exerealm_destroy = er_destroy; /* set out signs */ barg->hnd.sign = output_variants; /* mapping */ barg->hnd.mapping = NULL; /* set variants */ barg->hnd.vars = vlist; barg->hnd = *barg->exerealm_create(&barg->hnd); SNetThreadingSpawn( SNetEntityCreate(ENTITY_box, location, SNetLocvecGet(info), boxname, BoxTask, (void*)barg) ); } else { SNetIntListListDestroy(output_variants); output = input; } return output; }
snet_stream_t *SNetFeedbackDet( snet_stream_t *input, snet_info_t *info, int location, snet_variant_list_t *back_patterns, snet_expr_list_t *guards, snet_startup_fun_t box_a ) { snet_stream_t *output; snet_locvec_t *locvec; locvec = SNetLocvecGet(info); SNetLocvecFeedbackEnter(locvec); input = SNetRouteUpdate(info, input, location); if(SNetDistribIsNodeLocation(location)) { snet_stream_t *into_op, *from_op; snet_stream_t *back_bufin, *back_bufout; fbbuf_arg_t *fbbarg; fbcoll_arg_t *fbcarg; fbdisp_arg_t *fbdarg; /* create streams */ into_op = SNetStreamCreate(0); output = SNetStreamCreate(0); back_bufout = SNetStreamCreate(FEEDBACK_BACKCHAN_CAPACITY); #ifndef FEEDBACK_OMIT_BUFFER back_bufin = SNetStreamCreate(0); /* create the feedback buffer */ fbbarg = SNetMemAlloc( sizeof( fbbuf_arg_t)); fbbarg->in = back_bufin; fbbarg->out = back_bufout; fbbarg->out_capacity = FEEDBACK_BACKCHAN_CAPACITY; SNetThreadingSpawn( SNetEntityCreate( ENTITY_fbbuf, location, locvec, "<fbbuf>", FeedbackBufTask, (void*)fbbarg) ); #else back_bufin = back_bufout; #endif /* create the feedback collector */ fbcarg = SNetMemAlloc( sizeof( fbcoll_arg_t)); fbcarg->in = input; fbcarg->fbi = back_bufout; fbcarg->out = into_op; SNetThreadingSpawn( SNetEntityCreate( ENTITY_fbcoll, location, locvec, "<fbcoll>", FeedbackCollTask, (void*)fbcarg) ); /* create the instance network */ from_op = box_a(into_op, info, location); from_op = SNetRouteUpdate(info, from_op, location); /* create the feedback dispatcher */ fbdarg = SNetMemAlloc( sizeof( fbdisp_arg_t)); fbdarg->in = from_op; fbdarg->fbo = back_bufin; fbdarg->out = output; fbdarg->back_patterns = back_patterns; fbdarg->guards = guards; SNetThreadingSpawn( SNetEntityCreate( ENTITY_fbdisp, location, locvec, "<fbdisp>", FeedbackDispTask, (void*)fbdarg) ); } else { SNetVariantListDestroy(back_patterns); SNetExprListDestroy(guards); output = box_a(input, info, location); output = SNetRouteUpdate(info, output, location); } SNetLocvecFeedbackLeave(locvec); return( output); }
/* Feedback creation function */ snet_stream_t *SNetFeedback( snet_stream_t *input, snet_info_t *info, int location, snet_variant_list_t *back_patterns, snet_expr_list_t *guards, snet_startup_fun_t box_a) { snet_stream_t *output; node_t *node; feedback_arg_t *farg; snet_locvec_t *locvec; int detlevel; trace(__func__); if (SNetFeedbackDeterministic()) { return SNetDripBack(input, info, location, back_patterns, guards, box_a); } detlevel = SNetDetSwapLevel(0); locvec = SNetLocvecGet(info); SNetLocvecFeedbackEnter(locvec); input = SNetRouteUpdate(info, input, location); if (SNetDistribIsNodeLocation(location)) { output = SNetStreamCreate(0); node = SNetNodeNew(NODE_feedback, &input, 1, &output, 1, SNetNodeFeedback, SNetStopFeedback, SNetTermFeedback); farg = NODE_SPEC(node, feedback); /* fill in the node argument */ farg->input = input; farg->output = output; farg->back_patterns = back_patterns; farg->guards = guards; farg->stopping = 0; /* Create the instance network */ farg->instance = SNetNodeStreamCreate(node); farg->feedback = (*box_a)(farg->instance, info, location); farg->feedback = SNetRouteUpdate(info, farg->feedback, location); /* Feedback loop should end at this node. */ assert(STREAM_DEST(farg->feedback) == NULL); STREAM_DEST(farg->feedback) = node; /* Create two self-referencing streams. */ farg->selfref2 = SNetNodeStreamCreate(node); STREAM_DEST(farg->selfref2) = node; farg->selfref4 = SNetNodeStreamCreate(node); STREAM_DEST(farg->selfref4) = node; farg->entity = SNetEntityCreate( ENTITY_fbdisp, location, locvec, "<feedback>", NULL, (void*)farg); } else { SNetExprListDestroy( guards); SNetVariantListDestroy(back_patterns); output = input; } SNetLocvecFeedbackLeave(locvec); SNetDetSwapLevel(detlevel); return output; }
/** * Convenience function for creating * Star, DetStar, StarIncarnate or DetStarIncarnate, * dependent on parameters is_incarnate and is_det. */ static snet_stream_t *CreateStar( snet_stream_t *input, snet_info_t *info, int location, snet_variant_list_t *exit_patterns, snet_expr_list_t *guards, snet_startup_fun_t box_a, snet_startup_fun_t box_b, bool is_incarnate, bool is_det) { snet_stream_t *output; node_t *node; star_arg_t *sarg; snet_locvec_t *locvec; locvec = SNetLocvecGet(info); if (!is_incarnate) { SNetLocvecStarEnter(locvec); } else { assert(false); } output = SNetStreamCreate(0); node = SNetNodeNew(NODE_star, location, &input, 1, &output, 1, SNetNodeStar, SNetStopStar, SNetTermStar); sarg = NODE_SPEC(node, star); sarg->input = input; sarg->collector = output; sarg->exit_patterns = exit_patterns; sarg->guards = guards; sarg->is_incarnate = is_incarnate; sarg->is_det = is_det; sarg->is_detsup = (SNetDetGetLevel() > 0); sarg->stopping = 0; /* create operand A */ sarg->instance = SNetNodeStreamCreate(node); (void) SNetLocvecStarSpawn(locvec); SNetSubnetIncrLevel(); sarg->internal = (*box_a)(sarg->instance, info, location); SNetSubnetDecrLevel(); (void) SNetLocvecStarSpawnRet(locvec); /* direct destination of operand back to this node */ STREAM_DEST(sarg->internal) = node; /* Is this a Star followed by only a Sync? */ if (SNetZipperEnabled() && NODE_TYPE(STREAM_DEST(sarg->instance)) == NODE_sync && STREAM_FROM(sarg->internal) == STREAM_DEST(sarg->instance)) { /* Replace the combination of star + sync with a fused sync-star. */ sync_arg_t *sync = NODE_SPEC(STREAM_DEST(sarg->instance), sync); /* if (SNetVerbose()) { printf("Replacing a star + sync with a fused sync-star.\n"); } */ output = SNetZipper(input, info, location, exit_patterns, guards, sync->patterns, sync->guard_exprs); SNetEntityDestroy(sync->entity); SNetVariantDestroy(sync->merged_pattern); SNetDelete(STREAM_DEST(sarg->instance)); SNetStreamDestroy(sarg->instance); SNetStreamDestroy(sarg->internal); SNetStreamDestroy(sarg->collector); SNetMemFree(node); } else { sarg->entity = SNetEntityCreate( ENTITY_star, location, locvec, "<star>", NULL, (void *) sarg); if (!is_incarnate) { /* the "top-level" star also creates a collector */ output = SNetCollectorDynamic(sarg->collector, location, info, is_det, node); SNetNodeTableAdd(sarg->internal); } } if (!is_incarnate) { SNetLocvecStarLeave(locvec); } return output; }