/*
 * Dieses Programm dient als Testumgebung für preemptive Scheduling-Verfahren.
 * Es werden 6 Prozesse simuliert, die unterschiedlich lange Laufzeiten haben.
 * Bei jedem Aufruf eines dieser Prozesse arbeitet dieser ein Zeitpensum von
 * maximal 4 ab. Der gerade aktive Prozess erhöht die Wartezeit der anderen
 * wartenden Prozesse und gibt jede Zeiteinheit ein Lebenszeichen (Ziffer 0
 * bis 6) aus. Anhand dessen kann man wie auf einem Zeitstrahl die Abarbeitungs-
 * reihenfolge der Schedulingverfahren beobachten.
 */
#include <stdio.h>
#include <stdlib.h>

/* Struktur zur Darstellung einer Funktion als Listenelement */
typedef struct function_pointer{
	void (*function)();			/* Pointer auf Funktion definieren */
	int iID;
	int iRestzeit;
	int iPriority;
	struct function_pointer *next_entry;
	} entry;

const int iPROZESS_ANZAHL = 6;

int iProzessWartezeiten[6] = {0,0,0,0,0,0};
					/* Bisherige Wartezeiten der einzelnen Prozesse */
int iZeit = 0;		/* Gesamte verstrichene Zeit */

/***************************************************************************/
/****				Die 6 ``Prozesse''									****/
/***************************************************************************/

void function_0() {				/* Beispielfunktion */
	printf("0");
}

void function_1() {				/* Beispielfunktion */
	printf("1");
}

void function_2() {				/* Beispielfunktion */
	printf("2");
}

void function_3() {				/* Beispielfunktion */
	printf("3");
}

void function_4() {				/* Beispielfunktion */
	printf("4");
}

void function_5() {				/* Beispielfunktion */
	printf("5");
}

/***************************************************************************/
/****				Ende der 6 ``Prozesse''								****/
/***************************************************************************/

/****************************************************************/
/* Errechnet die verbleibende Gesamtrechenzeit aller Funktionen */
/****************************************************************/
int iGesamtiRestzeit(entry *anfang)
{
	int tmp=0;
	entry *zeiger;

	zeiger=anfang;

	while (zeiger != NULL) {
		tmp += zeiger->iRestzeit;
		zeiger=zeiger->next_entry;
	}
	return tmp;
}

/****************************************************************/
/* Errechnet die verbleibende Rechenzeit der Funktion <iID>     */
/****************************************************************/
int iiRestzeit(int iID, entry *anfang)
{
	entry *zeiger;

	zeiger=anfang;
	while (zeiger != NULL) {
		if (zeiger->iID == iID)
			return zeiger->iRestzeit;
		zeiger = zeiger->next_entry;
	}
	return -1;
}

/***************************************************************************/
/****				Beispiel: Round Robin Verfahren						****/
/***************************************************************************/
void RR(entry *anfang)
{
	const int iPENSUM = 4;
	entry *zeiger;
	int i,i2;

	zeiger=anfang;
	while (iGesamtiRestzeit(anfang) > 0)
	{						/* Solange ein Prozess noch rechnen muß */
		for (i=0;i<iPENSUM;i++)
		{
			if (zeiger->iRestzeit>0)	/* Prüfe ob noch Zeit benötigt wird */
			{
				zeiger->function();	/* Fkt. ueber Pointer rufen */
				iZeit++;		/* inkrement. Gesamtzähler */
				zeiger->iRestzeit--;	/* iRestzeit dekrementieren */
				for (i2=0;i2<=iPROZESS_ANZAHL-1;i2++)
					if ((i2!=zeiger->iID) && iiRestzeit(i2, anfang) > 0 )
						iProzessWartezeiten[i2]++;
						/* Alle anderen warten, falls noch nicht beendet */
			}
		}

		if(zeiger->next_entry == NULL)
			zeiger = anfang;		/* Nächste Fkt. */
		else
			zeiger=zeiger->next_entry;
	}
}

/***************************************************************************/
/**** Statistische Auswertung der Wartezeiten mit Ankunftszeiten		****/
/***************************************************************************/
void Statistik2 ()
{
	int i,iGes;
	iGes=0;
	printf("\n\n Die Wartezeiten jeweils: \n");
	for (i=0;i<=5;i++) {
		printf("   Prozess %d: %3d\n",i,(iProzessWartezeiten[i] - iProzessWartezeiten[i]));
		iGes += (iProzessWartezeiten[i] - iProzessWartezeiten[i]);
	}
	printf(" Der Durchschnitt:   %6.2f\n",(float)iGes / 6.0);
	printf(" Die Summe:          %3d\n",iGes);
	printf(" Die Gesamtlaufzeit: %3d\n",iZeit);
}

/***************************************************************************/
/****				Statistische Auswertung der Wartezeiten				****/
/***************************************************************************/
void Statistik ()
{
	int i,iGes;
	iGes=0;
	printf("\n\n Die Wartezeiten jeweils: \n");
	for (i=0;i<=5;i++) {
		printf("   Prozess %d: %3d\n",i,iProzessWartezeiten[i]);
		iGes += iProzessWartezeiten[i];
	}
	printf(" Der Durchschnitt:   %6.2f\n",(float)iGes / 6.0);
	printf(" Die Summe:          %3d\n",iGes);
	printf(" Die Gesamtlaufzeit: %3d\n",iZeit);
}

/***************************************************************************/

main() {
	int iProzessZeiten[6]={12,16,10,3,3,6}; /* benötigte Zeiten der Prozesse */
	int iProzessPrioritaeten[6]={2,1,3,2,1,3}; /* Prioritäten für Aufgabe 4.2b */
	int iAnkuenfte[6] = {0,1,5,10,3,25};     /* Ankunftzeiten für Aufgabe 4.2b */

/***************************************************************************/
/****				Hier wird eine Liste aller Prozesse angelegt		****/
/***************************************************************************/
	entry *anfang;
	entry *Zeiger;

	anfang=malloc(sizeof(entry));
	anfang->function=function_0;
	anfang->iID=0;
	anfang->iRestzeit=iProzessZeiten[0];
	anfang->next_entry=malloc(sizeof(entry));	
	anfang->iPriority=iProzessPrioritaeten[0];
	Zeiger=anfang->next_entry;

	Zeiger->function=function_1;
	Zeiger->iID=1;
	Zeiger->iRestzeit=iProzessZeiten[1];
	Zeiger->next_entry=malloc(sizeof(entry));
	Zeiger->iPriority=iProzessPrioritaeten[1];
	Zeiger=Zeiger->next_entry;

	Zeiger->function=function_2;
	Zeiger->iID=2;
	Zeiger->iRestzeit=iProzessZeiten[2];
	Zeiger->iPriority=iProzessPrioritaeten[2];
	Zeiger->next_entry=malloc(sizeof(entry));
	Zeiger=Zeiger->next_entry;

	Zeiger->function=function_3;
	Zeiger->iID=3;
	Zeiger->iRestzeit=iProzessZeiten[3];
	Zeiger->iPriority=iProzessPrioritaeten[3];
	Zeiger->next_entry=malloc(sizeof(entry));
	Zeiger=Zeiger->next_entry;

	Zeiger->function=function_4;
	Zeiger->iID=4;
	Zeiger->iRestzeit=iProzessZeiten[4];
	Zeiger->iPriority=iProzessPrioritaeten[4];
	Zeiger->next_entry=malloc(sizeof(entry));
	Zeiger=Zeiger->next_entry;

	Zeiger->function=function_5;
	Zeiger->iID=5;
	Zeiger->iRestzeit=iProzessZeiten[5];
	Zeiger->iPriority=iProzessPrioritaeten[5];
	Zeiger->next_entry=NULL; /* Pointer initialisieren */
	Zeiger = anfang;
/***************************************************************************/
	RR(Zeiger);
	Statistik();
	return 0;
}

