Пример #1
0
static void FbCollReadFbi(struct fbcoll_state *state)
{
  snet_record_t *rec;

  assert( false == state->terminate );

  /* read from feedback stream */
  rec = SNetStreamRead( state->backstream);

  switch( SNetRecGetDescriptor( rec)) {

    case REC_data:
      /* relay data record */
      SNetStreamWrite( state->outstream, rec);
      /* mode switch to FB0 (there is a next iteration) */
      state->mode = FBCOLL_FB0;
      break;

    case REC_sort_end:
      assert( 0 == SNetRecGetLevel(rec) );
      switch(state->mode) {
        case FBCOLL_FB0:
          state->mode = FBCOLL_FB1;
          /* increase counter (non-functional) */
          SNetRecSetNum( rec, SNetRecGetNum(rec)+1);
          SNetStreamWrite( state->outstream, rec);
          break;
        case FBCOLL_FB1:
          state->mode = FBCOLL_IN;
          /* kill the sort record */
          SNetRecDestroy( rec);
          break;
        default: assert(0);
      }
      break;

    case REC_sync:
      SNetStreamReplace( state->backstream, SNetRecGetStream( rec));
      SNetRecDestroy( rec);
      break;

    case REC_terminate:
    case REC_collect:
    default:
      assert(0);
      /* if ignoring, at least destroy ... */
      SNetRecDestroy( rec);
      break;
  }
}
Пример #2
0
/* helper functions to handle mode the feedback collector is in */
static void FbCollReadIn(struct fbcoll_state *state)
{
  snet_record_t *rec;

  assert( false == state->terminate );

  /* read from input stream */
  rec = SNetStreamRead( state->instream);

  switch( SNetRecGetDescriptor( rec)) {

    case REC_data:
      /* relay data record */
      SNetStreamWrite( state->outstream, rec);
      /* append a sort record */
      SNetStreamWrite(
          state->outstream,
          SNetRecCreate( REC_sort_end, 0, 1 ) /*type, lvl, num*/
          );
      /* mode switch to FB1 */
      state->mode = FBCOLL_FB1;
      break;

    case REC_sort_end:
      /* increase the level and forward */
      SNetRecSetLevel( rec, SNetRecGetLevel(rec)+1);
      SNetStreamWrite( state->outstream, rec);
      break;

    case REC_terminate:
      state->terminate = true;
      SNetStreamWrite( state->outstream, rec);
      /* note that no sort record has to be appended */
      break;

    case REC_sync:
      SNetStreamReplace( state->instream, SNetRecGetStream( rec));
      SNetRecDestroy( rec);
      break;

    case REC_collect:
    default:
      assert(0);
      /* if ignoring, at least destroy ... */
      SNetRecDestroy( rec);
      break;
  }
}
Пример #3
0
/**
 * 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;
}
Пример #4
0
void *Reader( void *buf)
{
  bool terminate;
  int i, shape, *cbit_array;
  SACarg *output;
  snet_buffer_t *outbuf = (snet_buffer_t*)buf;
  snet_record_t *resrec;


  terminate = false;
  while( !terminate) {
    resrec = SNetBufGet( outbuf);
    if( SNetRecGetDescriptor( resrec) == REC_terminate) {
      terminate = true;
    }
    else {
      output = SNetRecTakeField( resrec,  F__des__Ct);
  
      shape = SACARGgetShape( output, 0);
      cbit_array = SACARGconvertToIntArray( SACARGnewReference( output));
      fprintf(stderr, "Enciphered Bits:\n");
      for( i=0; i<shape; i++) {
        fprintf(stderr, "%d ", cbit_array[i]);
      }
      fprintf(stderr, "\n");
      ToString( cbit_array);
    }
    SNetRecDestroy( resrec);
  }
  fprintf(stdout, "\n");
  return( NULL);
}
Пример #5
0
/* Read one record from the parser. */
input_state_t SNetGetNextInputRecord(landing_t *land)
{
  landing_input_t       *linp = LAND_SPEC(land, input);
  input_arg_t           *iarg = NODE_SPEC(land->node, input);
  snet_record_t         *record = NULL;

  trace(__func__);
  assert(NODE_TYPE(land->node) == NODE_input);

  if (iarg->state == INPUT_reading) {
    // Ask parser for a new input record.
    while (SNetInParserGetNextRecord(&record) == SNET_PARSE_CONTINUE) {
      if (record) {
        break;
      }
    }
    if (record) {
      if (REC_DESCR(record) == REC_terminate) {
        SNetRecDestroy(record);
        iarg->state = INPUT_terminating;
      } else {
        linp->num_inputs += 1;
        SNetWrite(&linp->outdesc, record, false);
        return INPUT_reading;
      }
    } else {
      iarg->state = INPUT_terminating;
    }
    return iarg->state;
  } else {
    return INPUT_terminated;
  }
}
Пример #6
0
/* Star component: forward record to instance or to collector. */
void SNetNodeStar(snet_stream_desc_t *desc, snet_record_t *rec)
{
  const star_arg_t      *sarg = DESC_NODE_SPEC(desc, star);
  landing_star_t        *land = DESC_LAND_SPEC(desc, star);

  trace(__func__);

  switch (REC_DESCR(rec)) {
    case REC_data:
      if (land->star_leader && (sarg->is_det | sarg->is_detsup)) {
        SNetDetEnter(rec, &land->detenter, sarg->is_det, sarg->entity);
      }
      if (MatchesExitPattern( rec, sarg->exit_patterns, sarg->guards)) {
        StarWrite(WriteCollector, rec, desc);
      } else {
        StarWrite(WriteInstance, rec, desc);
      }
      break;

    case REC_detref:
      /* Forward record */
      StarWrite(WriteCollector, rec, desc);
      break;

    case REC_sync:
      SNetRecDestroy(rec);
      break;

    case REC_star_leader:
      land->star_leader = true;
      land->detenter.counter = LEADER_REC(rec, counter);
      land->detenter.seqnr   = LEADER_REC(rec, seqnr  );
      SNetRecDestroy(rec);
      break;

    default:
      SNetRecUnknownEnt(__func__, rec, sarg->entity);
  }
}
Пример #7
0
static void FeedbackBufTask(snet_entity_t *, void *arg)
{
  fbbuf_arg_t *fbbarg = (fbbuf_arg_t *)arg;

  snet_stream_desc_t *instream;
  snet_stream_desc_t *outstream;
  snet_record_t *rec;
  int out_counter = 0;
  int out_capacity;

  instream   = SNetStreamOpen(fbbarg->in,  'r');
  outstream  = SNetStreamOpen(fbbarg->out, 'w');
  out_capacity =  fbbarg->out_capacity;
  SNetMemFree( fbbarg);


  /* MAIN LOOP */
  while(1) {

    rec = SNetStreamRead(instream);
    if( SNetRecGetDescriptor(rec) == REC_terminate ) {
      /* this means, the outstream does not exist anymore! */
      SNetRecDestroy(rec);
      break; /* exit main loop */
    }

    if (out_counter+1 >= out_capacity) {
      /* new stream */
      snet_stream_t *new_stream = SNetStreamCreate(out_capacity);
      SNetStreamWrite(outstream,
          SNetRecCreate(REC_sync, new_stream)
          );

      SNetStreamClose(outstream, false);
      outstream = SNetStreamOpen(new_stream, 'w');
      out_counter = 0;
    }
    /* write the record to the stream */
    SNetStreamWrite(outstream, rec);
    out_counter++;
  } /* END OF MAIN LOOP */

  SNetStreamClose(instream,  true);
  SNetStreamClose(outstream, false);
}
Пример #8
0
/**
 * Process a termination record
 */
static void ProcessTermRecord(
    snet_record_t *rec,
    snet_record_t **term_rec,
    snet_stream_desc_t *cur_stream,
    snet_streamset_t *readyset,
    int *incount)
{
  assert( REC_terminate == SNetRecGetDescriptor( rec) );
  int res = SNetStreamsetRemove( readyset, cur_stream);
  assert(res == 0);
  SNetStreamClose( cur_stream, true);
  /* update incoming counter */
  *incount -= 1;

  if (*term_rec == NULL) {
    *term_rec = rec;
  } else {
    /* destroy record */
    SNetRecDestroy( rec);
  }
}
Пример #9
0
/**
 * Restore the streams from the waitingset into
 * the readyset and send sort record if required
 */
static void RestoreFromWaitingset(
    snet_streamset_t *waitingset,
    snet_streamset_t *readyset,
    snet_record_t **sort_rec,
    snet_stream_desc_t *outstream)
{
  int level;
  assert( *sort_rec != NULL);
  /* waiting set contains all streams,
     ready set is empty => "swap" sets */
  *readyset = *waitingset;
  *waitingset = NULL;
  /* check sort record: if level > 0,
     decrement and forward to outstream */
  level = SNetRecGetLevel( *sort_rec);
  if( level > 0) {
    SNetRecSetLevel( *sort_rec, level-1);
    SNetStreamWrite( outstream, *sort_rec);
  } else {
    SNetRecDestroy( *sort_rec);
  }
  *sort_rec = NULL;
}
Пример #10
0
/**
 * Process a sort record
 */
static void ProcessSortRecord(
    snet_entity_t *ent,
    snet_record_t *rec,
    snet_record_t **sort_rec,
    snet_stream_desc_t *cur_stream,
    snet_streamset_t *readyset,
    snet_streamset_t *waitingset)
{
  int res;
  assert( REC_sort_end == SNetRecGetDescriptor( rec) );

  /* sort record: place node in waitingset */
  /* remove node */
  res = SNetStreamsetRemove( readyset, cur_stream);
  assert(res == 0);
  /* put in waiting set */
  SNetStreamsetPut( waitingset, cur_stream);

  if (*sort_rec!=NULL) {
    /*
     * check that level & counter match
     */
    if( !SortRecEqual(rec, *sort_rec) ) {
      SNetUtilDebugNoticeEnt( ent,
          "[COLL] Warning: Received sort records do not match! "
          "expected (l%d,c%d) got (l%d,c%d) on %p", /* *trollface* PROBLEM? */
          SNetRecGetLevel(*sort_rec), SNetRecGetNum(*sort_rec),
          SNetRecGetLevel(rec),       SNetRecGetNum(rec),
          cur_stream
          );
    }
    /* destroy record */
    SNetRecDestroy( rec);
  } else {
    *sort_rec = rec;
  }
}
Пример #11
0
/**
 * 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 */
Пример #12
0
/**
 * 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);
}
Пример #13
0
static void BoxTask(snet_entity_t *ent, void *arg)
{
#ifdef DBG_RT_TRACE_BOX_TIMINGS
  static struct timeval tv_in;
  static struct timeval tv_out;
#endif

#ifdef SNET_DEBUG_COUNTERS
  snet_time_t time_in;
  snet_time_t time_out;
  long mseconds;
#endif /* SNET_DEBUG_COUNTERS */

  box_arg_t *barg = (box_arg_t *)arg;
  snet_record_t *rec;
  snet_stream_desc_t *instream, *outstream;
  bool terminate = false;

  instream = SNetStreamOpen(barg->input, 'r');
  outstream =  SNetStreamOpen(barg->output, 'w');
  /* set out descriptor */
  barg->hnd.out_sd = outstream;
  /* set entity */
  barg->hnd.ent = ent;

  /* MAIN LOOP */
  while(!terminate) {
    /* read from input stream */
    rec = SNetStreamRead(instream);

    switch(SNetRecGetDescriptor(rec)) {
      case REC_trigger_initialiser:
      case REC_data:
      	barg->hnd.rec = rec;

#ifdef DBG_RT_TRACE_BOX_TIMINGS
        gettimeofday(&tv_in, NULL);
        SNetUtilDebugNoticeEnt(ent,
            "[BOX] Firing box function at %lf.",
            tv_in.tv_sec + tv_in.tv_usec / 1000000.0
            );
#endif
#ifdef SNET_DEBUG_COUNTERS
        SNetDebugTimeGetTime(&time_in);
#endif /* SNET_DEBUG_COUNTERS */

#ifdef USE_USER_EVENT_LOGGING
        /* Emit a monitoring message of a record read to be processed by a box */
        if (SNetRecGetDescriptor(rec) == REC_data) {
          SNetThreadingEventSignal(ent,
              SNetMonInfoCreate(EV_MESSAGE_IN, MON_RECORD, rec)
              );
        }
#endif

        /* execute box function and update execution realm */
        barg->hnd = *barg->boxfun(&barg->hnd);
        barg->hnd = *barg->exerealm_update(&barg->hnd);

        /*
         * Emit an event here?
         * SNetMonInfoEvent(EV_BOX_???, MON_RECORD, rec);
         */

#ifdef DBG_RT_TRACE_BOX_TIMINGS
        gettimeofday(&tv_out, NULL);
        SNetUtilDebugNoticeEnt(ent,
            "[BOX] Return from box function after %lf sec.",
            (tv_out.tv_sec - tv_in.tv_sec) + (tv_out.tv_usec - tv_in.tv_usec) / 1000000.0
            );
#endif


#ifdef SNET_DEBUG_COUNTERS
        SNetDebugTimeGetTime(&time_out);
        mseconds = SNetDebugTimeDifferenceInMilliseconds(&time_in, &time_out);
        SNetDebugCountersIncreaseCounter(mseconds, SNET_COUNTER_TIME_BOX);
#endif /* SNET_DEBUG_COUNTERS */

        SNetRecDestroy(rec);

        /* restrict to one data record per execution */
        //SNetThreadingYield();

        /* check the box task should be migrated after one record execution */
        SNetThreadingCheckMigrate();
        break;

      case REC_sync:
        {
          snet_stream_t *newstream = SNetRecGetStream(rec);
          SNetStreamReplace(instream, newstream);
          SNetRecDestroy(rec);
        }
        break;

      case REC_sort_end:
        /* forward the sort record */
        SNetStreamWrite(outstream, rec);
        break;

      case REC_terminate:
      	barg->hnd = *barg->exerealm_destroy(&barg->hnd);
        SNetStreamWrite(outstream, rec);
        terminate = true;
        break;

      case REC_collect:
      default:
        assert(0);
    }
  } /* MAIN LOOP END */
  barg->hnd = *barg->exerealm_destroy(&barg->hnd);
  SNetStreamClose(instream, true);
  SNetStreamClose(outstream, false);
 
  /* destroy box arg */
  SNetVariantListDestroy(barg->hnd.vars);
  SNetIntListListDestroy(barg->hnd.sign);
  SNetMemFree( barg);
}
Пример #14
0
/**
 * The feedback dispatcher, at the end of the
 * feedback combinator loop
 */
static void FeedbackDispTask(snet_entity_t *ent, void *arg)
{
  fbdisp_arg_t *fbdarg = (fbdisp_arg_t *)arg;

  snet_stream_desc_t *instream;
  snet_stream_desc_t *outstream;
  snet_stream_desc_t *backstream;
  bool terminate = false;
  snet_record_t *rec;
  (void) ent; /* NOT USED */

  instream   = SNetStreamOpen(fbdarg->in,  'r');
  outstream  = SNetStreamOpen(fbdarg->out, 'w');
  backstream = SNetStreamOpen(fbdarg->fbo, 'w');

  /* MAIN LOOP */
  while( !terminate) {

    /* read from input stream */
    rec = SNetStreamRead( instream);

    switch( SNetRecGetDescriptor( rec)) {

      case REC_data:
        /* route data record */
        if( MatchesBackPattern( rec, fbdarg->back_patterns, fbdarg->guards)) {
          /* send rec back into the loop */
          SNetStreamWrite( backstream, rec);
        } else {
          /* send to output */
          SNetStreamWrite( outstream, rec);
        }
        break;

      case REC_sort_end:
        {
          int lvl = SNetRecGetLevel(rec);
          if ( 0 == lvl ) {
            SNetStreamWrite( backstream, rec);
          } else {
            assert( lvl > 0 );
            SNetRecSetLevel( rec, lvl-1);
            SNetStreamWrite( outstream, rec);
          }
        }
        break;

      case REC_terminate:
        terminate = true;
#ifndef FEEDBACK_OMIT_BUFFER
        /* a terminate record is sent in the backloop for the buffer */
        SNetStreamWrite( backstream, SNetRecCopy( rec));
#endif
        SNetStreamWrite( outstream, rec);
        break;

      case REC_sync:
        SNetStreamReplace( instream, SNetRecGetStream( rec));
        SNetRecDestroy( rec);
        break;

      case REC_collect:
      default:
        assert(0);
        /* if ignoring, at least destroy ... */
        SNetRecDestroy( rec);
        break;
    }

  } /* END OF MAIN LOOP */

  SNetStreamClose(instream,   true);
  SNetStreamClose(outstream,  false);
  SNetStreamClose(backstream, false);

  SNetVariantListDestroy( fbdarg->back_patterns);
  SNetExprListDestroy( fbdarg->guards);
  SNetMemFree( fbdarg);
}
Пример #15
0
/**
 * Collector task for dynamic combinators (star/split)
 * and the static parallel combinator
 */
void CollectorTask(snet_entity_t *ent, void *arg)
{
  coll_arg_t *carg = (coll_arg_t *)arg;
  snet_streamset_t readyset, waitingset;
  snet_stream_iter_t *wait_iter;
  snet_stream_desc_t *outstream;
  snet_stream_desc_t *curstream = NULL;
  snet_stream_desc_t *last = NULL;		// when the paired parallel terminate, it sends the sort_end record to the last branch
  snet_record_t *sort_rec = NULL;
  snet_record_t *term_rec = NULL;
  int incount;
  bool terminate = false;


  /* open outstream for writing */
  outstream = SNetStreamOpen(carg->output, 'w');

  readyset = waitingset = NULL;

  if (carg->is_static) {
    int i;
    incount = CARG_ST(carg, num);
    /* fill initial readyset of collector */
    for (i=0; i<incount; i++) {
      snet_stream_desc_t *tmp;
      /* open each stream in listening set for reading */
      tmp = SNetStreamOpen( CARG_ST(carg, inputs[i]), 'r');
      /* add each stream instreams[i] to listening set of collector */
      SNetStreamsetPut( &readyset, tmp);
    }
    SNetMemFree( CARG_ST(carg, inputs) );
  } else {
    incount = 1;
    /* Open initial stream and put into readyset */
    SNetStreamsetPut( &readyset,
        SNetStreamOpen(CARG_DYN(carg, input), 'r')
        );
  }

  /* create an iterator for waiting set, is reused within main loop*/
  wait_iter = SNetStreamIterCreate( &waitingset);

  /* MAIN LOOP */
  while( !terminate) {
    /* get a record */
    snet_record_t *rec = GetRecord(&readyset, incount, &curstream);
    /* process the record */
    switch( SNetRecGetDescriptor( rec)) {

      case REC_data:
        /* data record: forward to output */
        SNetStreamWrite( outstream, rec);
        break;

      case REC_sort_end:
      	/* curstream == last, this is the last branch and the paired parallel already terminates
      	 * increase the level by one because it was not increased by the paired parallel as it should be
      	 * Also later when last becomes the only waiting branch, the collector should terminate. However before terminating, it should pretend that parallel has sent the sort end from all branches
      	 */
      	if (curstream == last) {			// imply last != NULL, this will be the last branch and the paired parallel already terminates
      		SNetRecSetLevel(rec, SNetRecGetLevel(rec) + 1);			// increase the level by one because it was not increased by the paired parallel as it should be
      	}
      	if (last == NULL && SNetRecGetLevel(rec) == 0 && SNetRecGetNum(rec) == -1) {		// if last was not set, and collector receives a sort_end (l0, c-1) --> set the curstream as last
      		last = curstream;																															// from now on, any sort_end from last will be increased level by 1
      		SNetRecDestroy( rec);
      		break;			// ignore the sort_end
      	}

        ProcessSortRecord(ent, rec, &sort_rec, curstream, &readyset, &waitingset);
        /* end processing this stream */
        curstream = NULL;
        break;

      case REC_sync:
        SNetStreamReplace( curstream, SNetRecGetStream( rec));
        SNetRecDestroy( rec);
        break;

      case REC_collect:
        /* only for dynamic collectors! */
        assert( false == carg->is_static );
        /* collect: add new stream to ready set */
#ifdef DESTROY_TERM_IN_WAITING_UPON_COLLECT
        /* but first, check if we can free resources by checking the
           waiting set for arrival of termination records */
        incount -= DestroyTermInWaitingSet(wait_iter, &waitingset);
        assert(incount > 0);
#endif
        /* finally, add new stream to ready set */
        SNetStreamsetPut(
            &readyset,
            SNetStreamOpen( SNetRecGetStream( rec), 'r')
            );
        /* update incoming counter */
        incount++;
        /* destroy collect record */
        SNetRecDestroy( rec);
        break;

      case REC_terminate:
        /* termination record: close stream and remove from ready set */
        ProcessTermRecord(rec, &term_rec, curstream, &readyset, &incount);
        /* stop processing this stream */
        curstream = NULL;
        break;

      default:
        assert(0);
        /* if ignore, at least destroy ... */
        SNetRecDestroy( rec);
    } /* end switch */

    /************* termination conditions *****************/
    if ( SNetStreamsetIsEmpty( &readyset)) {
      /* the streams which had a sort record are in the waitingset */
      if ( !SNetStreamsetIsEmpty( &waitingset)) {
        if ( carg->is_static && (1 == incount) ) {		// stat
          snet_stream_desc_t *in = (waitingset != NULL) ? waitingset : readyset;

          /* if last is the only one in the waitingset --> pretends that the already-terminated paired parallel has sent the sort end to all branches
           * Therefore restore the waitingset before terminating (so that a relevant sort_end is sent out) */
          if (in == last)
          	RestoreFromWaitingset(&waitingset, &readyset, &sort_rec, outstream);

          SNetStreamWrite( outstream,
              SNetRecCreate( REC_sync, SNetStreamGet(in))
              );
          SNetStreamClose( in, false);
          terminate = true;
#ifdef DEBUG_PRINT_GC
          /* terminating due to GC */
          SNetUtilDebugNoticeEnt( ent,
              "[COLL] Terminate static collector as only one branch left!"
              );
#endif
        } else
          RestoreFromWaitingset(&waitingset, &readyset, &sort_rec, outstream);
      } else {
        /* both ready set and waitingset are empty */
#ifdef DEBUG_PRINT_GC
        if (carg->is_static) {
          SNetUtilDebugNoticeEnt( ent,
              "[COLL] Terminate static collector as no inputs left!");
        }
#endif
        assert(term_rec != NULL);
        SNetStreamWrite( outstream, term_rec);
        term_rec = NULL;
        terminate = true;
      }
    }

     
    /************* end of termination conditions **********/
  } /* MAIN LOOP END */

  if (term_rec != NULL) {
    SNetRecDestroy(term_rec);
  }
  if (sort_rec != NULL) {
    SNetRecDestroy(sort_rec);
  }
  /* close outstream */
  SNetStreamClose( outstream, false);
  /* destroy iterator */
  SNetStreamIterDestroy( wait_iter);
  /* destroy argument */
  SNetMemFree( carg);
} /* END of DYNAMIC COLLECTOR TASK */
Пример #16
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);
  }
}
Пример #17
0
/* 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);
  }
}
Пример #18
0
/**
 * The feedback buffer, in the back-loop
 */
static void FeedbackBufTask(snet_entity_t *ent, void *arg)
{
  fbbuf_arg_t *fbbarg = (fbbuf_arg_t *)arg;

  snet_stream_desc_t *instream;
  snet_stream_desc_t *outstream;
  snet_queue_t *internal_buffer;
  snet_record_t *rec;
  int out_capacity;
  int max_read;
  (void) ent; /* NOT USED */

  instream   = SNetStreamOpen(fbbarg->in,  'r');
  outstream  = SNetStreamOpen(fbbarg->out, 'w');
  out_capacity =  fbbarg->out_capacity;
  SNetMemFree( fbbarg);

  internal_buffer = SNetQueueCreate();
  max_read = out_capacity; /* TODO better usual stream capacity */

  /* MAIN LOOP */
  while(1) {
    int n = 0;
    rec = NULL;

    /* STEP 1: read n=min(available,max_read) records from input stream */

    /* read first record of the actual dispatch */
    if (0 == SNetQueueSize(internal_buffer)) {
      rec = SNetStreamRead(instream);
      /* only in empty mode! */
      if( REC_terminate == SNetRecGetDescriptor( rec)) {
        /* this means, the outstream does not exist anymore! */
        SNetRecDestroy(rec);
        goto feedback_buf_epilogue;
      }
    } else {
      SNetThreadingYield();
      if ( SNetStreamPeek(instream) != NULL ) {
        rec = SNetStreamRead(instream);
        assert( REC_terminate != SNetRecGetDescriptor( rec) );
      }
    }

    if (rec != NULL) {
      n = 1;
      /* put record into internal buffer */
      (void) SNetQueuePut(internal_buffer, rec);
    }


    while ( n<=max_read && SNetStreamPeek(instream)!=NULL ) {
      rec = SNetStreamRead(instream);

      /* check if we will need a larger outstream, and if so,
       * create a larger stream
       */
      if (SNetQueueSize(internal_buffer)+1 >= out_capacity) {
        snet_stream_t *new_stream;
        out_capacity *= 2;

        new_stream = SNetStreamCreate(out_capacity);
        (void) SNetQueuePut(internal_buffer, SNetRecCreate(REC_sync, new_stream));
      }

      /* put record into internal buffer */
      (void) SNetQueuePut(internal_buffer, rec);
      n++;
    }

    /* STEP 2: try to empty the internal buffer */
    rec = SNetQueuePeek(internal_buffer);

    while (rec != NULL) {
      snet_stream_t *new_stream = NULL;
      if( REC_sync == SNetRecGetDescriptor( rec)) {
        new_stream = SNetRecGetStream(rec);
      }
      if (0 == SNetStreamTryWrite(outstream, rec)) {
        snet_record_t *rem;
        /* success, also remove from queue */
        rem = SNetQueueGet(internal_buffer);
        assert( rem == rec );

        if (new_stream != NULL) {
          /* written sync record, now change stream */
          SNetStreamClose(outstream, false);
          outstream = SNetStreamOpen(new_stream, 'w');
        }
      } else {
        /* there remain elements in the buffer */
        break;
      }
      /* for the next iteration */
      rec = SNetQueuePeek(internal_buffer);
    }
  } /* END OF MAIN LOOP */

feedback_buf_epilogue:

  SNetQueueDestroy(internal_buffer);

  SNetStreamClose(instream,   true);
  SNetStreamClose(outstream,  false);
}