// Melita Mialjevic 0036411392
// Dekkerov algoritam:
//zajednicke varijable: PRAVO, ZASTAVICA[0..1]
//funkcija udi_u_kriticni_odsjecak(i,j) {
//   ZASTAVICA[i] = 1
//   dok je ZASTAVICA[j]<>0 cini {
//     ako je PRAVO=j onda {
//         ZASTAVICA[i] = 0
//        dok je PRAVO=j cini {
//            ništa
//         }
//
//         ZASTAVICA[i] = 1
//      }
//   }
//} kraj.
//funkcija izadi_iz_kriticnog_odsjecka(i,j) {
//   PRAVO = j
//   ZASTAVICA[i] = 0
//} kraj.

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<signal.h>

int Id;
int *ZASTAVICA, *PRAVO;						// varijablama zajedničke memorije pristupa se kazaljkama

void brisi(int sig) {						// funkcija koja brise smece koje ostanje za njemu  shmdt služi za otpuštanje segmenata
	(void) shmdt((int*) ZASTAVICA +1);
	(void) shmdt((int*) ZASTAVICA);
	(void) shmdt((int*) PRAVO);
	(void) shmctl(Id,IPC_RMID,NULL);		
	exit(0);
}
	


int udji_u_kriticni_odsjecak(int i) {	// funkcija udji u kriticni odsjecak 
	int j;
	if ( i ==1) 
		j = 2;
	else
		j = 1;
	*(ZASTAVICA + i) = 1;
	printf( "ulazak u kriticni odsjecak i =%d, j = %d, Z(j)= %d, Z(j)= %d \n", i , j, *(ZASTAVICA+i), *(ZASTAVICA +j));
	while (*( ZASTAVICA +j)!=0) {				// igra se sa zastavicama isto kao u pseudokodu gore (nisam isla  opisivati dekkerov algoritam jer je dan gore)
		printf(" Z(j) = %d\n", *(ZASTAVICA +j));
		if (*PRAVO == j) {
			printf ("PRAVO = %d\n",*PRAVO);
			*(ZASTAVICA+ i)= 0;
			while (* PRAVO == j) {
				printf ("Z(i)=0, cekamo dok je PRAVO = j\n");
				sleep(1);
			}
			*(ZASTAVICA +i) =1;
		}
		else {
			printf( "PRAVO = %d\n",*PRAVO);
			sleep(1);
		}
	}
	return 0;
}

int izadji_iz_kriticnog_odsjecka(int i) { // funkcija izlaska iz kriticnog odsjecka 
	int j;
	if (i ==1)
		j =2;
	else 
		j = 1;
	printf(" Izlazak iz kriticnog odsjecka i=%d,j= %d, Z(i)= %d, Z(j)= %d\n", i, j ,*(ZASTAVICA+i), *(ZASTAVICA +j));
	*PRAVO = j;
	*(ZASTAVICA + i) = 0;
	printf ("izlazak iz kriticnog odsjecka i=%d, j=%d, Z(i)= %d, Z(j) =%d\n", i, j, *(ZASTAVICA + i), *(ZASTAVICA + j));
	return 0;
}



int proces(int i) {
	int k,m;
	for(k =1; k<= 5; k++) {
		printf("proces %d, k= %d\n", i, k);
		udji_u_kriticni_odsjecak(i);						//proces obavi svoj ulazak  u KO isve sta treba i onda pozove izlazak iz KO
		for (m=1; m<=5; m++) {
			printf( "i= %d k= %d m=%d\n", i, k, m);
			sleep(1);
		}
	izadji_iz_kriticnog_odsjecka(i);
	}
	return(0);
}


//glavni program
int main(void) {
	int i;

	Id = shmget(IPC_PRIVATE, 100*sizeof(int), 0600); // zauzimanje zajedničke memorije  
	if (Id == -1) {
		printf( "Greska! Nema zajednicke memorije!\n"); // ako je vratio -1 znaci da nema zajednicke memorije
		exit(1);
	}
	PRAVO = (int *) shmat(Id, NULL,0);		//Proces veže segment na svoj adresni prostor sa shmat:
	ZASTAVICA = (int *) shmat(Id, NULL,0);
	sigset(SIGINT, brisi);						// ako se dogodi interrupt onda pozove funkciju brisi koja sve to pocisti
	
	for (i=1; i<=2; i++) {						// stvaramo dva procesa
		switch(fork()) {
			case 0:
				printf("iteracija %d\n",i);
				proces(i);						//ako je uspio forkati pozove funkciju proces
				exit(0);
			case -1 :
				printf(" Nemoguce stvoriti novi proces\n");
				break;	
			default:
				printf ("iteracija %d, fork uspio\n",i);
				break;
		}
	}
	while (i --) {											// jos moram cekati da djeca zavrse i da ih sredim
		printf ("Cekanje da djeca zavrse, i = %d\n",i);
		wait(NULL);
	}
		brisi(0);
	return 0;
}

	

