/*
 *              	 Exemple "Group1.c" PVM versio 3.3
 *		 Susana Maria Bajo Sanchez (ei05646@salleURL.edu)
 *	 	Josep Maria Garrell i Guiu (josepmg@salleURL.edu)
 *			       Software Paral.lel
 *		        Departament d'Informatica (DI)
 *   	               Enginyeria i Arquitectura La Salle
 *		          Universitat Ramon Llull (URL)
 * 			        Curs 1999/2000
*/

#include <stdio.h>
#include <string.h>
#include "pvm3.h"

#define GROUPNAME "alltasks"
#define NTASKS 6
#define SIZE  5

//-------------------------------------------------------------------
int main(int argc, char *argv[])
{
int mytid, mygid, info,tid_list[NTASKS],i, list[SIZE], sum, slave_gid;            

mytid = pvm_mytid();
mygid = pvm_joingroup(GROUPNAME);

printf("MI TID: %x\t MI GID: %x\n",mytid,mygid);

if (mygid==0)  // Soy el "master"
	{
	// creo NTASKS-1 copias
	info = pvm_spawn(argv[0],(char**)0,PvmTaskDefault,(char*)0,NTASKS-1,&tid_list[1]);
	if (info<0) 
		{
		pvm_perror("Despues pvm_spawn()");
		pvm_kill(tid_list[1]);
		}
	}

// Bloquea el proceso hasta que todos los procesos del grupo sean llamados
info = pvm_barrier(GROUPNAME, NTASKS);
if (info<0) pvm_perror("Despues first pvm_barrier()");

// Retorna el tid del proceso identificado en el grupo
for (i=0;i<NTASKS;i++) tid_list[i] = pvm_gettid(GROUPNAME, i);

// Cada proceso escribe su numero de PE y el TID
printf("MI TID: %x\t MI TID LIST: %x\n",mytid);
printf("PE     TID\n");

for (i=0;i<NTASKS;i++) printf("%x      %x\n",tid_list[i]); 

// Una lista de numeros de da al master y este lo distribuye equitativamente a los "slaves"
if (mygid==0)
	{
        // El proceso "master" envia una lista de numeros a los otros procesos
        // Primero, crea la lista
	for (i=0;i<SIZE;i++) list[i] = i;

        // Para cada proceso "slave"
        // - inicializa el buffer
        // - empaquetar
        // - envia
	for (i=1;i<NTASKS;i++)
		{
		info = pvm_initsend(PvmDataRaw);
		if (info<0) pvm_perror("Despues MASTER pvm_initsend()");

		info = pvm_pkint(list,SIZE,1);
		if (info<0) pvm_perror("Despues MASTER pvm_pkint()");

		info = pvm_send(tid_list[i],i);
		if (info<0) pvm_perror("Despues MASTER pvm_send()");
		}
	}
	else
		{
	        // Soy uno de los procesos "slave"
	        // Recibo y desempaqueto lo que el "master" me ha enviado
		info = pvm_recv(tid_list[0],mygid);
		if (info<0) pvm_perror("Depues SLAVE pvm_recv()");

		info = pvm_upkint(list, SIZE, 1);
		if (info<0) pvm_perror("Despues SLAVE pvm_upkint()");
		}

// Cada "slave" suma valores en su lista y envia el resultado al "master
// El "master" escribe el valor retornado por cada "slave".
if (mygid!=0)
	{
        // Soy un "slave"
        // Calculo sum y lo envio al "master"
	sum = 0;
	for (i=0;i<SIZE;i++) sum+=list[i];

	info = pvm_initsend(PvmDataRaw);
	if (info<0) pvm_perror("Despues SLAVE pvm_initsend()");

        // Empaqueto mygid para que el "master" sepa quien le envio el mensaje
	info = pvm_pkint(&mygid,1,1);
	if (info<0) pvm_perror("Despues SLAVE pvm_pkint() for mygid");

	info = pvm_pkint(&sum,1,1);
	if (info<0) pvm_perror("Despues SLAVE pvm_pkint() for sum");

	info = pvm_send(tid_list[0],mygid);
	if (info<0) pvm_perror("Despues SLAVE pvm_send()");
	}
	else
		{
	        // Soy el "master"
	        // Recibo sum de cada proceso y escribo su valor
		for (i=1;i<NTASKS;i++)
			{
			info = pvm_recv(-1,-1);
			if (info<0) pvm_perror("Despues MASTER pvm_recv()");

			info = pvm_upkint(&slave_gid,1,1);
			if (info<0) pvm_perror("Despues MASTER pvm_upkint() for slave_gid");

			info = pvm_upkint(&sum,1,1);
			if (info<0) pvm_perror("Despues MASTER pvm_upkint() for sum");

			printf("MASTER: Recibida la suma de %d de la tarea %d\n",sum,slave_gid);
			}
		}
	
// Espero a todos para poder salir
info = pvm_barrier(GROUPNAME, NTASKS);
if (info<0) pvm_perror("Despues del ultimo pvm_barrier()");

printf("MI TID: %x saliendo de PVM...\n",mytid);
pvm_exit();

return 0;
}

