Exemplo n.º 1
0
Arquivo: join.c Projeto: xyuan/ug
static void JoinSetMode (int mode)
{
  joinGlobals.joinMode = mode;

#       if DebugJoin<=8
  sprintf(cBuffer, "%4d: JoinMode=%s.\n",
          me, JoinModeName(joinGlobals.joinMode));
  DDD_PrintDebug(cBuffer);
#       endif
}
Exemplo n.º 2
0
Arquivo: jcmds.c Projeto: rolk/ug
void DDD_JoinObj (DDD_HDR hdr, DDD_PROC dest, DDD_GID new_gid)
{
    JIJoin *ji;

    if (!ddd_JoinActive())
    {
        DDD_PrintError('E', 7012, "Missing DDD_JoinBegin(). aborted");
        HARD_EXIT;
    }

    if (dest>=procs)
    {
        sprintf(cBuffer, "cannot join %08x with %08x on processor %d (procs=%d)",
                OBJ_GID(hdr), new_gid, dest, procs);
        DDD_PrintError('E', 7003, cBuffer);
        HARD_EXIT;
    }

    if (dest==me)
    {
        sprintf(cBuffer, "cannot join %08x with myself", OBJ_GID(hdr));
        DDD_PrintError('E', 7004, cBuffer);
        HARD_EXIT;
    }

    if (ObjHasCpl(hdr))
    {
        sprintf(cBuffer, "cannot join %08x, object already distributed",
                OBJ_GID(hdr));
        DDD_PrintError('E', 7005, cBuffer);
        HARD_EXIT;
    }



    ji = JIJoinSet_NewItem(joinGlobals.setJIJoin);
    ji->hdr     = hdr;
    ji->dest    = dest;
    ji->new_gid = new_gid;

    if (! JIJoinSet_ItemOK(joinGlobals.setJIJoin))
        return;

#       if DebugJoin<=2
    sprintf(cBuffer, "%4d: DDD_JoinObj %08x, dest=%d, new_gid=%08x\n",
            me, OBJ_GID(hdr), dest, new_gid);
    DDD_PrintDebug(cBuffer);
#       endif
}
Exemplo n.º 3
0
Arquivo: pack.c Projeto: rolk/ug
RETCODE XferPackMsgs (XFERMSG *theMsgs)
{
  XFERMSG      *xm;

#if     DebugPack<=3
  sprintf(cBuffer, "%d: XferPackMsgs\n", me);
  DDD_PrintDebug(cBuffer);
  fflush(stdout);
#endif

  /* sort messages according to decreasing size. i.e., send
     biggest message first. LowComm will use this to handle
     situations with little memory ressources. */
  {
    int i, n;
    XFERMSG **xm_array;

    /* count number of messages */
    for(n=0, xm=theMsgs; xm!=NULL; xm=xm->next) n++;

    if (n>0)
    {
      /* alloc array of pointers to messages */
      xm_array = (XFERMSG **) OO_Allocate (sizeof(XFERMSG *) * n);
      if (xm_array!=NULL)
      {
        for(i=0, xm=theMsgs; i<n; xm=xm->next, i++) xm_array[i] = xm;

        /* sort array and relink list */
        qsort(xm_array, n, sizeof(XFERMSG *), sort_MsgSize);
        theMsgs = xm_array[0];
        for(i=0; i<n-1; i++) xm_array[i]->next = xm_array[i+1];
        if (n>1) xm_array[n-1]->next = NULL;

        /* free array */
        OO_Free (xm_array /*,0*/);
      }
      /* else
         {
              resorting msg-list is not possible due to memory shortage.
              simply don't do it.
         }
       */
    }
  }



  /* allocate buffer, pack messages and send away */
  for(xm=theMsgs; xm!=NULL; xm=xm->next)
  {
    if (! LC_MsgAlloc(xm->msg_h))
    {
      sprintf(cBuffer, STR_NOMEM " in XferPackMsgs (size=%ld)",
              (unsigned long) LC_GetBufferSize(xm->msg_h));
      DDD_PrintError('E', 6522, cBuffer);
      RET_ON_ERROR;
    }
    XferPackSingleMsg(xm);
    LC_MsgSend(xm->msg_h);
  }

  RET_ON_OK;
}
Exemplo n.º 4
0
Arquivo: pack.c Projeto: rolk/ug
static void XferPackSingleMsg (XFERMSG *msg)
{
  SYMTAB_ENTRY *theSymTab;
  OBJTAB_ENTRY *theObjTab;
  TENewCpl     *theNewCpl;
  TEOldCpl     *theOldCpl;
  char         *theObjects, *currObj;
  int i, actSym, actNewCpl, actOldCpl, actObj, recvProc;
  INT mi;


  /* recipient of this message */
  recvProc = msg->proc;

  /* get table addresses inside message */
  theSymTab = (SYMTAB_ENTRY *)LC_GetPtr(msg->msg_h, xferGlobals.symtab_id);
  theObjTab = (OBJTAB_ENTRY *)LC_GetPtr(msg->msg_h, xferGlobals.objtab_id);
  theNewCpl = (TENewCpl *)    LC_GetPtr(msg->msg_h, xferGlobals.newcpl_id);
  theOldCpl = (TEOldCpl *)    LC_GetPtr(msg->msg_h, xferGlobals.oldcpl_id);
  theObjects= (char *)LC_GetPtr(msg->msg_h, xferGlobals.objmem_id);


  /* build several tables inside message */
  actSym = actNewCpl = actOldCpl = actObj = 0;
  currObj = theObjects;
  for(i=0; i<msg->nObjItems; i++)          /* for all XICopyObj-items */
  {
    REGISTER XICopyObj *xi = msg->xferObjArray[i];
    REGISTER DDD_HDR hdr   = xi->hdr;
    TYPE_DESC *desc = &theTypeDefs[OBJ_TYPE(hdr)];
    DDD_OBJ obj   = HDR2OBJ(hdr,desc);
    /*COUPLING  *cpl;*/
    DDD_HDR copyhdr;

    /* build coupling table */
    /* skip cpl which describes object itself (receive proc) */
    /*
                    for(cpl=THECOUPLING(hdr); cpl!=NULL; cpl=cpl->next)
                    {
                            if (cpl->proc!=recvProc)
                            {
                                    theNewCpl[actNewCpl].gid  = OBJ_GID(hdr);
                                    theNewCpl[actNewCpl].proc = cpl->proc;
                                    theNewCpl[actNewCpl].prio = cpl->prio;
                                    actNewCpl++;
                            }
                    }
     */

    /* one coupling for object itself (send proc) */
    /*
                    theNewCpl[actNewCpl].gid  = OBJ_GID(hdr);
                    theNewCpl[actNewCpl].proc = me;
                    theNewCpl[actNewCpl].prio = OBJ_PRIO(hdr);
                    actNewCpl++;
     */


#if defined(C_FRONTEND) || defined(CPP_FRONTEND)
    copyhdr = OBJ2HDR(currObj,desc);
#else
    copyhdr = (DDD_HDR) currObj;
#endif

    /* update object table */
#if defined(C_FRONTEND) || defined(CPP_FRONTEND)
    theObjTab[actObj].h_offset = (int)(((char *)copyhdr)-theObjects);
#else
    theObjTab[actObj].o_offset = (int)(currObj-theObjects);
    theObjTab[actObj].typ    = OBJ_TYPE(hdr);
    theObjTab[actObj].gid    = OBJ_GID(hdr);
    theObjTab[actObj].attr   = OBJ_ATTR(hdr);
    theObjTab[actObj].prio   = xi->prio;
#endif
    theObjTab[actObj].hdr      = NULL;
    theObjTab[actObj].addLen   = xi->addLen;
    theObjTab[actObj].size     = xi->size;              /* needed for variable-sized objects */
    actObj++;



    /*
            copy object into message. in the following xi->size
            equals desc->len for fixed-size objects.
     */
    /*STAT_RESET3;*/
#if defined(C_FRONTEND) || defined(CPP_FRONTEND)
    /* NOTE: object memory is copied _completely_, i.e., also LDATA-
       components are copied into message and sent to destination.
       then, on the receiving processor the data is sorted out... */
    memcpy(currObj, obj, xi->size);
#else
    ObjToMsg (obj, desc, currObj);
#endif
    /*STAT_INCTIMER3(32);*/

    /* insert priority into copy */
    OBJ_PRIO(copyhdr) = xi->prio;


    /* call application handler for direct manipulation */
    /* KB 941110:  moved from objmgr.c                  */
    /*
            Caution: this is a very, very dirty situation.
            HANDLER_XFERCOPYMANIP is able to manipulate the
            obj-copy inside the message. this handler should
            be removed in future DDD versions.
     */
                #if defined(C_FRONTEND)
    if (desc->handlerXFERCOPYMANIP)
    {
      /*
              NOTE: OBJ_TYPE could change during the
              execution of HANDLER_XFERCOPYMANIP. however,
              the position of DDD_HEADER inside the object
              should not change. therefore, we can remember
              the offsetHeader here and use it afterwards
              to adjust the desc.
       */
      int offset = desc->offsetHeader;

      /* now call handler */
      desc->handlerXFERCOPYMANIP(currObj);

      /* adjust new description according to new type */
      desc = &(theTypeDefs[OBJ_TYPE((DDD_HDR)(currObj+offset))]);
    }
                #endif

    /* build symbol table portion from object copy */
    actSym += BuildSymTab(desc, obj, (char *)currObj, &(theSymTab[actSym]));


    /* advance to next free object slot in message, c.f. alignment */
    currObj += CEIL(xi->size);


    /* gather additional data */
    if (xi->addLen>0)
    {
      actSym += GetDepData(currObj,
                           desc, obj, &(theSymTab[actSym]), xi);
      currObj += xi->addLen;
    }
  }


  /* for all XINewCpl items in this message */
  for(i=0; i<msg->nNewCpl; i++)
  {
    theNewCpl[actNewCpl]  = msg->xferNewCpl[i]->te;
    actNewCpl++;
  }

  /* for all XIOldCpl items in this message */
  for(i=0; i<msg->nOldCpl; i++)
  {
    theOldCpl[actOldCpl]  = msg->xferOldCpl[i]->te;
    actOldCpl++;
  }



  /* sort SymTab, ObjTab and CplTab */
  /*STAT_RESET3;*/
  qsort(theSymTab, actSym, sizeof(SYMTAB_ENTRY), sort_SymTabEntries);
  /*STAT_INCTIMER3(34); STAT_RESET3;*/

  /* sorting of objtab is necessary!! (see AcceptObjFromMsg) KB 960812 */
  currentObjectMem = theObjects;
  qsort(theObjTab, msg->nObjects, sizeof(OBJTAB_ENTRY), sort_ObjTabEntries);
  /*STAT_INCTIMER3(35); STAT_RESET3;*/


#ifdef SORT_STATISTIK
  sprintf(cBuffer, "ITEMS 34=%d, 35=%d, 36=%d\n", actSym,  msg->nObjects,  actNewCpl);
  DDD_PrintDebug(cBuffer);
  sprintf(cBuffer, "COMPS 34=%d, 35=%d, 36=%d\n", n34,  n35,  n36);
  DDD_PrintDebug(cBuffer);
#endif


  /* substitute all pointers by index into SymTab */
  /*TAT_RESET3;*/
  for(mi=0; mi<actSym; mi++)
  {
    /* patch SymTab index into reference location inside message */
#if defined(C_FRONTEND) || defined(CPP_FRONTEND)
    *(theSymTab[mi].adr.ref) = (DDD_OBJ)(mi+1);
#endif
#ifdef F_FRONTEND
    *(theSymTab[mi].adr.ref) = (mi+1);
#endif
  }
  /*STAT_INCTIMER3(37);*/


  /* TODO: theSymtab[].ref wird ab hier nicht mehr verwendet und muss nicht uebertragen werden! */


  /* set valid table entries */
  LC_SetTableLen(msg->msg_h, xferGlobals.symtab_id, actSym);
  LC_SetTableLen(msg->msg_h, xferGlobals.objtab_id, msg->nObjects);
  LC_SetTableLen(msg->msg_h, xferGlobals.newcpl_id, actNewCpl);
  LC_SetTableLen(msg->msg_h, xferGlobals.oldcpl_id, actOldCpl);


#if DebugXfer>1
  if (DDD_GetOption(OPT_DEBUG_XFERMESGS)==OPT_ON)
#endif
  XferDisplayMsg("OS", msg->msg_h);
}
Exemplo n.º 5
0
Arquivo: typemgr.c Projeto: xyuan/ug
void DDD_Library::TypeDefine (DDD_TYPE typ, ...)
#endif

{
  TYPE_DESC *desc;
  size_t argsize;
  char      *argp;
  int argtyp, argno;
  DDD_TYPE argrefs;
  int i, nPtr;
  char      *errtxt;
  va_list ap;
  char      *adr;
  char      *gbits;
#if defined(CPP_FRONTEND)
  int size;
  int offset;
#endif

  /* TODO: only master should be able to define types, other
          procs should receive the correct definition from master.
          (with the current implementation inconsistencies might occur)
   */

  /* test whether typ is valid */
  if (typ>=nDescr)
  {
    DDD_PrintError('E', 2414,
                   "invalid DDD_TYPE in DDD_TypeDefine");
    HARD_EXIT;             /*return;*/
  }

  /* get object description */
  desc = &(theTypeDefs[typ]);
  desc->currTypeDefCall++;

  if (desc->mode!=DDD_TYPE_DECLARED && desc->mode!=DDD_TYPE_CONTDEF)
  {
    if (desc->mode==DDD_TYPE_DEFINED)
    {
      DDD_PrintError('E', 2415,
                     RegisterError(desc, 0, "DDD_TYPE already defined"));
    }
    else
    {
      DDD_PrintError('E', 2416,
                     RegisterError(desc, 0, "undeclared DDD_TYPE"));
    }
    HARD_EXIT;             /*return;*/
  }


  /* initialize TYPE_DESC struct, only on first call */
  if (desc->currTypeDefCall==1)
    ConstructDesc(desc);


  if (typ==0)        /* i.e. typ==EL_DDDHDR */
  {
    /* DDD_HDR also contains a DDD_HDR (sic!) */
    desc->hasHeader = TRUE;
  }

#       ifdef DebugTypeDefine
  sprintf(cBuffer,"   DDD_TypeDefine(%s/%d)\n",
          desc->name, desc->currTypeDefCall);
  DDD_PrintDebug(cBuffer);
#       endif


  /* start variable arguments after "typ"-parameter */
  va_start(ap, typ);

#ifdef C_FRONTEND
  adr = va_arg(ap, char *);
  argno = 2;
#endif

#ifdef CPP_FRONTEND
  if (CPP_STRUCT(desc))
  {
    adr = va_arg(ap, char *);
    argno = 2;
  }
  else
  {
Exemplo n.º 6
0
Arquivo: jcmds.c Projeto: rolk/ug
DDD_RET DDD_JoinEnd (void)
#endif
{
    JIJoinPtrArray   *arrayJIJoin    = NULL;
    JIAddCplPtrArray *arrayJIAddCpl2 = NULL;
    JIAddCplPtrArray *arrayJIAddCpl3 = NULL;
    int obsolete, nRecvMsgs1, nRecvMsgs2, nRecvMsgs3, nSendMsgs;
    JOINMSG1    *sendMsgs1=NULL, *sm1=NULL;
    JOINMSG2    *sendMsgs2=NULL, *sm2=NULL;
    JOINMSG3    *sendMsgs3=NULL, *sm3=NULL;
    LC_MSGHANDLE *recvMsgs1=NULL, *recvMsgs2=NULL, *recvMsgs3=NULL;
    DDD_HDR     *localCplObjs=NULL;
    size_t sendMem=0, recvMem=0;
    JIPartner   *joinObjs = NULL;
    int nJoinObjs;



#ifdef JoinMemFromHeap
    MarkHeap();
    LC_SetMemMgr(memmgr_AllocTMEM, memmgr_FreeTMEM,
                 memmgr_AllocHMEM, NULL);
#endif

    STAT_SET_MODULE(DDD_MODULE_JOIN);
    STAT_ZEROALL;

    /* step mode and check whether call to JoinEnd is valid */
    if (!JoinStepMode(JMODE_CMDS))
    {
        DDD_PrintError('E', 7011, "DDD_JoinEnd() aborted");
        HARD_EXIT;
    }


    /*
            PREPARATION PHASE
     */
    /* get sorted array of JIJoin-items */
    arrayJIJoin = JIJoinSet_GetArray(joinGlobals.setJIJoin);
    obsolete = JIJoinSet_GetNDiscarded(joinGlobals.setJIJoin);


    /*
            COMMUNICATION PHASE 1
            all processors, where JoinObj-commands have been issued,
            send information about these commands to the target
            processors together with the GID of the objects on the
            target procs and the local priority.
     */
    STAT_RESET;
    /* prepare msgs for JIJoin-items */
    nSendMsgs = PreparePhase1Msgs(arrayJIJoin, &sendMsgs1, &sendMem);
    /* DisplayMemResources(); */

    /* init communication topology */
    nRecvMsgs1 = LC_Connect(joinGlobals.phase1msg_t);
    STAT_TIMER(T_JOIN_PREP_MSGS);

    STAT_RESET;
    /* build phase1 msgs on sender side and start send */
    PackPhase1Msgs(sendMsgs1);
    STAT_TIMER(T_JOIN_PACK_SEND);


    /*
            now messages are in the net, use spare time
     */
    STAT_RESET;
    /* get sorted list of local objects with couplings */
    localCplObjs = LocalCoupledObjectsList();
    if (localCplObjs==NULL && ddd_nCpls>0)
    {
        DDD_PrintError('E', 7020,
                       "Cannot get list of coupled objects in DDD_JoinEnd(). Aborted");
        HARD_EXIT;
    }


    if (obsolete>0)
    {
        if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_OBSOLETE)
        {
            int all = JIJoinSet_GetNItems(joinGlobals.setJIJoin);

            sprintf(cBuffer, "DDD MESG [%03d]: %4d from %4d join-cmds obsolete.\n",
                    me, obsolete, all);
            DDD_PrintLine(cBuffer);
        }
    }
    STAT_TIMER(T_JOIN);


    /*
            nothing more to do until incoming messages arrive
     */

    /* display information about send-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase1Msg.Send\n");
        LC_PrintSendMsgs();
    }


    /* wait for communication-completion (send AND receive) */
    STAT_RESET;
    recvMsgs1 = LC_Communicate();
    STAT_TIMER(T_JOIN_WAIT_RECV);


    /* display information about message buffer sizes */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE)
    {
        int k;

        /* sum up sizes of receive mesg buffers */
        for(k=0; k<nRecvMsgs1; k++)
        {
            recvMem += LC_GetBufferSize(recvMsgs1[k]);
        }

        sprintf(cBuffer,
                "DDD MESG [%03d]: SHOW_MEM "
                "msgs  send=%010ld recv=%010ld all=%010ld\n",
                me, (long)sendMem, (long)recvMem, (long)(sendMem+recvMem));
        DDD_PrintLine(cBuffer);
    }

    /* display information about recv-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase1Msg.Recv\n");
        LC_PrintRecvMsgs();
    }

    /* unpack messages */
    STAT_RESET;
    UnpackPhase1Msgs(recvMsgs1, nRecvMsgs1, localCplObjs, NCpl_Get,
                     &joinObjs, &nJoinObjs);
    LC_Cleanup();
    STAT_TIMER(T_JOIN_UNPACK);





    /*
            COMMUNICATION PHASE 2
            all processors which received notification of JoinObj-commands
            during phase 1 send AddCpl-requests to all copies of DDD objects,
            for which Joins had been issued remotely.
     */
    /* get sorted array of JIAddCpl-items */
    arrayJIAddCpl2 = JIAddCplSet_GetArray(joinGlobals.setJIAddCpl2);

    STAT_RESET;
    /* prepare msgs for JIAddCpl-items */
    nSendMsgs = PreparePhase2Msgs(arrayJIAddCpl2, &sendMsgs2, &sendMem);
    /* DisplayMemResources(); */

    /* init communication topology */
    nRecvMsgs2 = LC_Connect(joinGlobals.phase2msg_t);
    STAT_TIMER(T_JOIN_PREP_MSGS);

    STAT_RESET;
    /* build phase2 msgs on sender side and start send */
    PackPhase2Msgs(sendMsgs2);
    STAT_TIMER(T_JOIN_PACK_SEND);

    /*
            now messages are in the net, use spare time
     */

    /* reorder Join-commands according to new_gid */
    /* this ordering is needed in UnpackPhase3 */
    if (JIJoinPtrArray_GetSize(arrayJIJoin) > 1)
    {
        qsort(
            JIJoinPtrArray_GetData(arrayJIJoin),
            JIJoinPtrArray_GetSize(arrayJIJoin),
            sizeof(JIJoin *), sort_NewGid);
    }


    /*
            nothing more to do until incoming messages arrive
     */

    /* display information about send-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase2Msg.Send\n");
        LC_PrintSendMsgs();
    }


    /* wait for communication-completion (send AND receive) */
    STAT_RESET;
    recvMsgs2 = LC_Communicate();
    STAT_TIMER(T_JOIN_WAIT_RECV);


    /* display information about message buffer sizes */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE)
    {
        int k;

        /* sum up sizes of receive mesg buffers */
        for(k=0; k<nRecvMsgs2; k++)
        {
            recvMem += LC_GetBufferSize(recvMsgs2[k]);
        }

        sprintf(cBuffer,
                "DDD MESG [%03d]: SHOW_MEM "
                "msgs  send=%010ld recv=%010ld all=%010ld\n",
                me, (long)sendMem, (long)recvMem, (long)(sendMem+recvMem));
        DDD_PrintLine(cBuffer);
    }

    /* display information about recv-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase2Msg.Recv\n");
        LC_PrintRecvMsgs();
    }

    /* unpack messages */
    STAT_RESET;
    UnpackPhase2Msgs(recvMsgs2, nRecvMsgs2, joinObjs, nJoinObjs,
                     localCplObjs, NCpl_Get);

    LC_Cleanup();
    STAT_TIMER(T_JOIN_UNPACK);

    for(; sendMsgs2!=NULL; sendMsgs2=sm2)
    {
        sm2 = sendMsgs2->next;
        FreeTmp(sendMsgs2, 0);
    }






    /*
            COMMUNICATION PHASE 3
            all processors which received notification of JoinObj-commands
            during phase 1 send AddCpl-requests to the procs where the
            JoinObj-commands have been issued. One AddCpl-request is sent
            for each cpl in the local objects coupling list. One AddCpl-request
            is sent for each AddCpl-request received during phase 2.
            (i.e., two kinds of AddCpl-requests are send to the processors
            on which the JoinObj-commands have been issued.
     */
    /* get sorted array of JIAddCpl-items */
    arrayJIAddCpl3 = JIAddCplSet_GetArray(joinGlobals.setJIAddCpl3);

    STAT_RESET;
    /* prepare msgs for JIAddCpl-items */
    nSendMsgs = PreparePhase3Msgs(arrayJIAddCpl3, &sendMsgs3, &sendMem);
    /* DisplayMemResources(); */

    /* init communication topology */
    nRecvMsgs3 = LC_Connect(joinGlobals.phase3msg_t);
    STAT_TIMER(T_JOIN_PREP_MSGS);

    STAT_RESET;
    /* build phase3 msgs on sender side and start send */
    PackPhase3Msgs(sendMsgs3);
    STAT_TIMER(T_JOIN_PACK_SEND);

    /*
            now messages are in the net, use spare time
     */
    /* ... */

    /*
            nothing more to do until incoming messages arrive
     */

    /* display information about send-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase3Msg.Send\n");
        LC_PrintSendMsgs();
    }


    /* wait for communication-completion (send AND receive) */
    STAT_RESET;
    recvMsgs3 = LC_Communicate();
    STAT_TIMER(T_JOIN_WAIT_RECV);


    /* display information about message buffer sizes */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE)
    {
        int k;

        /* sum up sizes of receive mesg buffers */
        for(k=0; k<nRecvMsgs3; k++)
        {
            recvMem += LC_GetBufferSize(recvMsgs3[k]);
        }

        sprintf(cBuffer,
                "DDD MESG [%03d]: SHOW_MEM "
                "msgs  send=%010ld recv=%010ld all=%010ld\n",
                me, (long)sendMem, (long)recvMem, (long)(sendMem+recvMem));
        DDD_PrintLine(cBuffer);
    }

    /* display information about recv-messages on lowcomm-level */
    if (DDD_GetOption(OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL)
    {
        DDD_SyncAll();
        if (me==master)
            DDD_PrintLine("DDD JOIN_SHOW_MSGSALL: Phase3Msg.Recv\n");
        LC_PrintRecvMsgs();
    }

    /* unpack messages */
    STAT_RESET;
    UnpackPhase3Msgs(recvMsgs3, nRecvMsgs3, arrayJIJoin);
    LC_Cleanup();
    STAT_TIMER(T_JOIN_UNPACK);

    for(; sendMsgs3!=NULL; sendMsgs3=sm3)
    {
        sm3 = sendMsgs3->next;
        FreeTmp(sendMsgs3, 0);
    }






    /*
            free temporary storage
     */
    JIJoinPtrArray_Free(arrayJIJoin);
    JIJoinSet_Reset(joinGlobals.setJIJoin);

    JIAddCplPtrArray_Free(arrayJIAddCpl2);
    JIAddCplSet_Reset(joinGlobals.setJIAddCpl2);

    JIAddCplPtrArray_Free(arrayJIAddCpl3);
    JIAddCplSet_Reset(joinGlobals.setJIAddCpl3);

    if (localCplObjs!=NULL) FreeTmp(localCplObjs, 0);

    if (joinObjs!=NULL) FreeTmp(joinObjs, 0);

    for(; sendMsgs1!=NULL; sendMsgs1=sm1)
    {
        sm1 = sendMsgs1->next;
        FreeTmp(sendMsgs1, 0);
    }



#ifdef JoinMemFromHeap
    ReleaseHeap();
    LC_SetMemMgr(memmgr_AllocTMEM, memmgr_FreeTMEM,
                 memmgr_AllocTMEM, memmgr_FreeTMEM);
#endif

#       if DebugJoin<=4
    sprintf(cBuffer,"%4d: JoinEnd, before IFAllFromScratch().\n", me);
    DDD_PrintDebug(cBuffer);
#       endif

    /* re-create all interfaces and step JMODE */
    STAT_RESET;
    IFAllFromScratch();
    STAT_TIMER(T_JOIN_BUILD_IF);


    JoinStepMode(JMODE_BUSY);

    return(DDD_RET_OK);
}