/*
** FIFO Order and Matching Rules, Part 3
** Copyright Rolf Riesen 2008
** 
** 
*/
#include <stdio.h>
#include <mpi.h>



int
main(int argc, char *argv[])
{

int my_rank, nproc;
int tag1, tag2;
int count;
int dest;
int rbuf1, rbuf2;
int rbuf3, rbuf4;
int sbuf;
MPI_Status status1, status2;
MPI_Status status3, status4;


    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    if (nproc != 3)   {
        if (my_rank == 0)   {
            printf("Please run this program on 3 nodes\n");
        }
        MPI_Finalize();
        return 0;
    }

    /* Initialize some variables */
    tag1= 100;          /* Fixed tag 1 */
    tag2= 200;          /* Fixed tag 2 */
    dest= 0;            /* Send to rank 0 */
    sbuf= my_rank;      /* Initialize send buffer */
    count= 1;           /* Send and receive 1 integer */


    if (my_rank == 0)   {
        /* I am a receiver */
	MPI_Recv(&rbuf1, count, MPI_INT, MPI_ANY_SOURCE, tag1,
            MPI_COMM_WORLD, &status1);

	MPI_Recv(&rbuf2, count, MPI_INT, MPI_ANY_SOURCE, tag1,
            MPI_COMM_WORLD, &status2);

	MPI_Recv(&rbuf3, count, MPI_INT, MPI_ANY_SOURCE, tag2,
            MPI_COMM_WORLD, &status3);

	MPI_Recv(&rbuf4, count, MPI_INT, MPI_ANY_SOURCE, tag2,
            MPI_COMM_WORLD, &status4);

        printf("Received the message from rank %d with tag %d first\n",
            rbuf1, status1.MPI_TAG);
        printf("Received the message from rank %d with tag %d second\n",
            rbuf2, status2.MPI_TAG);
        printf("Received the message from rank %d with tag %d third\n",
            rbuf3, status3.MPI_TAG);
        printf("Received the message from rank %d with tag %d fourth\n",
            rbuf4, status4.MPI_TAG);

    } else if (my_rank == 1)   {
        /* I am a sender */
	MPI_Send(&sbuf, count, MPI_INT, dest, tag2, MPI_COMM_WORLD);
	MPI_Send(&sbuf, count, MPI_INT, dest, tag1, MPI_COMM_WORLD);

    } else if (my_rank == 2)   {
        /* I am a sender */
	MPI_Send(&sbuf, count, MPI_INT, dest, tag2, MPI_COMM_WORLD);
	MPI_Send(&sbuf, count, MPI_INT, dest, tag1, MPI_COMM_WORLD);
    }

    /*
        Sending tag2 first but receiving tag1 first may not work on all
        systems. It assumes that MPI will buffer the first send and
        progress to the second one. Most implementations can buffer a
        single integer and this will work. However, the standard does
        not guarantee the working of this program.
    */

    MPI_Finalize();
    return 0;

}  /* end of main() */
