/** * Peeks the top record of all streams in waitingset, * if there is a terminate record, the stream is closed * and removed from the waitingset */ static int DestroyTermInWaitingSet(snet_stream_iter_t *wait_iter, snet_streamset_t *waitingset) { int destroy_cnt=0; if ( !SNetStreamsetIsEmpty( waitingset)) { SNetStreamIterReset( wait_iter, waitingset); while( SNetStreamIterHasNext( wait_iter)) { snet_stream_desc_t *sd = SNetStreamIterNext( wait_iter); snet_record_t *wait_rec = SNetStreamPeek( sd); /* for this stream, check if there is a termination record next */ if ( wait_rec != NULL && SNetRecGetDescriptor( wait_rec) == REC_terminate ) { /* consume, remove from waiting set and free the stream */ (void) SNetStreamRead( sd); SNetStreamIterRemove( wait_iter); SNetStreamClose( sd, true); /* update destroyed counter */ destroy_cnt++; /* destroy record */ SNetRecDestroy( wait_rec); } /* else do nothing */ } } return destroy_cnt; }
/** * 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 */
snet_stream_desc_t *SNetStreamPoll(snet_streamset_t *set) { assert( *set != NULL); snet_stream_desc_t *result = NULL; /* get 'self', i.e. the task calling SNetStreamPoll() * the set is a simple pointer to the last element */ snet_thread_t *self = SNetThreadingSelf(); snet_stream_iter_t *iter; int cnt = 0; //self = (*set)->thr; iter = SNetStreamIterCreate(set); /* fast path: there is something anywhere */ { while( SNetStreamIterHasNext(iter)) { snet_stream_desc_t *sd = SNetStreamIterNext( iter); snet_stream_t *s = sd->stream; pthread_mutex_lock(&s->lock); if (s->count > 0) result = sd; pthread_mutex_unlock(&s->lock); } if (result != NULL) { goto poll_fastpath; } } /* reset wakeup_sd */ pthread_mutex_lock( &self->lock ); self->wakeup_sd = NULL; pthread_mutex_unlock( &self->lock ); /* for each stream in the set */ SNetStreamIterReset(iter, set); while( SNetStreamIterHasNext(iter)) { snet_stream_desc_t *sd = SNetStreamIterNext( iter); snet_stream_t *s = sd->stream; /* lock stream (prod-side) */ pthread_mutex_lock( &s->lock); { /* CS BEGIN */ /* check if there is something in the buffer */ if ( s->count > 0 ) { /* yes, we can stop iterating through streams. */ pthread_mutex_lock( &self->lock ); if (self->wakeup_sd == NULL) { self->wakeup_sd = sd; } /* unlock self */ pthread_mutex_unlock( &self->lock ); /* unlock stream */ pthread_mutex_unlock( &s->lock); /* exit loop */ break; } else { /* nothing in the buffer, register stream as activator */ s->is_poll = 1; cnt++; } } /* CS END */ /* unlock stream */ pthread_mutex_unlock( &s->lock); } /* end for each stream */ /* wait until wakeup_sd is set */ pthread_mutex_lock( &self->lock ); while( self->wakeup_sd == NULL ) { pthread_cond_wait(&self->pollcond, &self->lock); } result = self->wakeup_sd; self->wakeup_sd = NULL; pthread_mutex_unlock( &self->lock ); SNetStreamIterReset(iter, set); while( SNetStreamIterHasNext(iter)) { snet_stream_t *s = (SNetStreamIterNext(iter))->stream; pthread_mutex_lock(&s->lock); s->is_poll = 0; pthread_mutex_unlock(&s->lock); if (--cnt == 0) break; } poll_fastpath: SNetStreamIterDestroy(iter); /* 'rotate' list to stream descriptor for non-empty buffer */ *set = result; return result; }