int MPI_Intercomm_merge(MPI_Comm comm, int high, MPI_Comm *newcomm)
{
MPI_Status status;
MPI_Group g1, g2, newgroup;
IMPI_Uint8 newcid, maxcid;
IMPI_Uint8 inmsg[2], outmsg[2];
int myrank, rgsize;
/* Create the new context ID. Rank 0 processes are the leaders of their
* local group. Each leader finds the max context ID of all remote group
* processes (excluding their leader) and their "high" setting.
* The leaders then swap the information and broadcast to the remote group.
* Note: this is a criss-cross effect, processes talk to the remote
* leader. */
MPI_Comm_rank(comm, &myrank);
MPI_Comm_remote_size(comm, &rgsize);
if (myrank == 0) {
maxcid = IMPI_max_cid;
/* find max context ID of remote non-leader processes */
for (i = 1; i < rgsize; i++) {
MPI_Recv(inmsg, 1, IMPI_UINT8, i, IMPI_MERGE_TAG, comm, &status);
if (inmsg[0] > maxcid) maxcid = inmsg[0];
}
/* swap context ID and high value with remote leader */
outmsg[0] = maxcid;
outmsg[1] = high;
MPI_Sendrecv(outmsg, 2, IMPI_UINT8, 0, IMPI_MERGE_TAG,
inmsg, 2, IMPI_UINT8, 0, IMPI_MERGE_TAG, comm, &status);
if (inmsg[0] > maxcid) maxcid = inmsg[0];
rhigh = inmsg[1];
/* broadcast context ID and local high to remote non-leader processes */
outmsg[0] = maxcid;
outmsg[1] = high;
for (i = 1; i < rgsize; i++) {
MPI_Send(outmsg, 2, IMPI_UINT8, i, IMPI_MERGE_TAG, comm);
}
}
else {
/* non-leader */
MPI_Send(&maxcid, 1, IMPI_UINT8, 0, MPI_MERGE_TAG, comm);
MPI_Recv(inmsg, 2, IMPI_UINT8, 0, MPI_MERGE_TAG, comm, &status);
maxcid = inmsg[0];
rhigh = inmsg[1];
}
if (maxcid == IMPI_UINT8_MAX) {
error out of contexts;
}
newcid = maxcid + 1;
IMPI_max_cid = maxcid + 1;
/* All procs know the "high" for local and remote groups and
* the context ID. Create the properly ordered union group.
* In case of equal high values, the group that has the leader
* with the lowest rank in MPI_COMM_WORLD goes first.
*/
if (high && (!rhigh)) {
MPI_Comm_remote_group(comm, &g1);
MPI_Comm_group(comm, &g2);
} else if ((!high) && rhigh) {
MPI_Comm_group(comm, &g1);
MPI_Comm_remote_group(comm, &g2);
} else if ((rank in MPI_COMM_WORLD of rank 0 in local group)
< (rank in MPI_COMM_WORLD of rank 0 in remote group)) {
MPI_Comm_group(comm, &g1);
MPI_Comm_remote_group(comm, &g2);
} else {
MPI_Comm_remote_group(comm, &g1);
MPI_Comm_group(comm, &g2);
}
MPI_Group_union(g1, g2, &newgroup);
create a new intra-communicator newcomm with context ID newcid and
group newgroup;
return(MPI_SUCCESS);
}