int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)
{
MPI_Status status;
IMPI_Uint8 newcid, maxcid;
MPI_Group group;
MPI_Comm localcomm, tmpcomm;
int myrank, rgsize;
MPI_Comm_rank(comm, &myrank);
/* create a new context ID */
if (comm is an intra-communicator) {
MPI_Allreduce(&IMPI_max_cid, &maxcid, 1, IMPI_UINT8, MPI_MAX, comm);
} else {
/* 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). 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_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(&newcid, 1, IMPI_UINT8, i, IMPI_DUP_TAG, comm, &status);
if (newcid > maxcid) maxcid = newcid;
}
/* swap context ID with remote leader */
MPI_Sendrecv(&maxcid, 1, IMPI_UINT8, 0, IMPI_DUP_TAG,
&newcid, 1, IMPI_UINT8, 0, IMPI_DUP_TAG,
comm, &status);
if (newcid > maxcid) maxcid = newcid;
/* broadcast context ID to remote non-leader processes */
for (i = 1; i < rgsize; i++) {
MPI_Send(&maxcid, 1, IMPI_UINT8, i, IMPI_DUP_TAG, comm);
}
}
else {
/* non-leader */
MPI_Send(&maxcid, 1, IMPI_UINT8, 0, MPI_DUP_TAG, comm);
MPI_Recv(&maxcid, 1, IMPI_UINT8, 0, MPI_DUP_TAG, comm, &status);
}
}
if (maxcid == IMPI_UINT8_MAX) {
error out of contexts;
}
newcid = maxcid + 1;
IMPI_max_cid = maxcid + 1;
build a new communicator newcomm with the same groups as comm and
with context newcid;
return(MPI_SUCCESS);
}