/*
 *             	       Exemple "Group2.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 4 
#define SIZE 100 

//------------------------------------------------------------------
int main(int argc, char *argv[])
{
int mytid, mygid, info,	tid_list[NTASKS];		
int i, x, y, list[SIZE], sum, total, dist;					
int number[SIZE], total_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
   {
   info = pvm_spawn(argv[0],(char**)0,PvmTaskDefault,(char*)0,NTASKS-1,&tid_list[1]);
   // Imprime el estado de error en la última llamada PVM
   if (info<0) pvm_perror("Despues del pvm_spawn()"); 
   }

// Bloquea el proceso hasta que todos los procesos del grupo sean llamados
info = pvm_barrier(GROUPNAME, NTASKS);
if (info<0) pvm_perror("After 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 números de dá al master y este lo distribuye equitativamente a los "slaves"
if (mygid==0) // Soy el master
 	{
	printf("¿Cuantos numeros quieres añadir?");
	scanf("%d",&total);
	printf("Introduce los números\n");
      
	// Primero: el master recibe todos los números
	for (i=0;i<total;i++) scanf("%d",&list[i]);
   
    	dist=total/NTASKS;  //find out how many numbers each processor gets to add
    	x=0;

	// El master envía este número al resto de los procesos
	for (i=1;i<NTASKS;i++)
		{
   		info = pvm_initsend(PvmDataRaw);
   		if (info<0) pvm_perror("Despues MASTER pvm_initsend()");
   		info = pvm_pkint(&dist,1,1);	// empaqueta    
   		if (info<0) pvm_perror("Despues MASTER pvm_pkint()");
   		info = pvm_send(tid_list[i],i); // envía a cada slave
   		if (info<0) pvm_perror("Despues MASTER pvm_send()");
	     	}
	} 

// El resto de los procesos reciben el número
if (mygid!=0)
	{
	info = pvm_recv(tid_list[0], mygid);
	if (info<0) pvm_perror("Despues slave pvm_recv()");
	info = pvm_upkint(&dist,1,1);
	if (info<0) pvm_perror("Despues slave pvm_upkint()");
	}

if (mygid==0)
	{
	// Para cada proceso "slave":
	// - inicializa el buffer,
	// - empaqueta
	// - envia
	// cada proceso toma un array de numeros
	for (i=1;i<NTASKS;i++)
		{
	        // Primero: crea la lista
        	for (y=0;y<dist;y++)
			{
			number[y] = list[x];
		    	x++;
			}

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

		info = pvm_pkint(number, dist, 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()");
		}
	
	// El "master" tiene que calcular su porción
	// El "master" calcula todo y distribuye los 
	// numéros equitativmente a los "slaves"
	sum = 0;
	for (y=x;y<total;y++) sum+=list[y];
	}
	else
   		{
	   	// Soy uno de los procesos "slave"
	   	// Recibo y desempaqueto lo que el "master" envía
   		info = pvm_recv(tid_list[0],mygid);
   		if (info<0) pvm_perror("Despues SLAVE pvm_recv()");

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

// Cada "slave" suma valores que ha recibido y envía los resultados al "master"
// El "master" recibe la suma de todos los procesos y calcula la suma total
if (mygid!=0)
	{
	// Soy un "slave"
	// Calculo la suma y envía al "master"
	sum = 0;
	for (i=0;i<dist;i++) sum+=number[i];
	printf ("mi tid: %x: sum %d");
	}

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

// Empaqueto "mygid" para que el "master" sepa de quien es 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("After SLAVE pvm_send()");

if (mygid==0)
	{
	total_sum=0;
	// Soy el "master"
	// Recibo "sum" de cada proceso y escribo el valor
	for (i=0;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");
 
      		total_sum+=sum;
	  	printf("MASTER: Recibida suma de %d de la tarea %x\n",sum,slave_gid);
      		}
    	printf("MASTER: Suma Total = %d\n",total_sum);
	}

// Espero a todos para poder salir
info = pvm_barrier(GROUPNAME, NTASKS);
if (info<0) pvm_perror("Despues last pvm_barrier()");

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

return 0;
}

