#define _GNU_SOURCE   // Pour sched_setaffinty
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>


static void * T1 (void * unused);
static void * T2 (void * unused);
static void * T3 (void * unused);

static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;

int main(void)
{
	cpu_set_t cpu_set;
	pthread_t t1, t2, t3;

	pthread_mutexattr_t attr;
	pthread_mutexattr_init(& attr);
	pthread_mutexattr_setprotocol(& attr, PTHREAD_PRIO_INHERIT);
	pthread_mutex_init(& mutex, & attr);

	// Fixer l'execution sur un seul coeur
	CPU_ZERO(& cpu_set);
	CPU_SET(0, & cpu_set); // Coeur 0
	if (sched_setaffinity(0, sizeof(cpu_set), & cpu_set) != 0) {
		perror("sched_setaffinity");
		exit(EXIT_FAILURE);
	}

	// Creer les trois threads
	if ((pthread_create(& t1, NULL, T1, NULL) != 0)
	 || (pthread_create(& t2, NULL, T2, NULL) != 0)
	 || (pthread_create(& t3, NULL, T3, NULL) != 0)) {
		fprintf(stderr, "Erreur de creation des threads");
		exit(EXIT_FAILURE);
	}
	// Terminer le thread main
	pthread_exit(NULL);
}

#define BOUCLE_1  50000
#define BOUCLE_2  50000

static void * T1 (void * unused)
{
	int i;
	int j;
	struct sched_param param;

	fprintf(stderr, "T1 : Creation\n");

	// passer en temps reel faible priorite
	param.sched_priority = 5;
	if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) {
		perror("pthread_setschedparam");
		exit(EXIT_FAILURE);
	}

	// verrouiller le mutex
	pthread_mutex_lock(& mutex);

	// travail actif
	fprintf(stderr, "T1 : Debut boucle\n");
	for (i = 0; i < BOUCLE_1; i ++)
		for (j = 0; j < BOUCLE_2; j ++)
			;
	fprintf(stderr, "T1 : Fin Boucle\n");

	// liberer le mutex
	pthread_mutex_unlock(& mutex);
	return NULL;
}



static void * T2 (void * unused)
{
	int i;
	int j;
	struct sched_param param;

	fprintf(stderr, "T2 : Creation\n");

	// passer en temps reel moyenne priorite
	param.sched_priority = 15;
	if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) {
		perror("pthread_setschedparam");
		exit(EXIT_FAILURE);
	}
	// attendre deux secondes
	sleep(2);
	// travail actif
	fprintf(stderr, "T2 : Debut boucle\n");
	for (i = 0; i < BOUCLE_1; i ++)
		for (j = 0; j < BOUCLE_2; j ++)
			;
	fprintf(stderr, "T2 : Fin boucle\n");
	return NULL;	
}



static void * T3 (void * unused)
{
	int i;
	int j;
	struct sched_param param;

	fprintf(stderr, "T3 : Creation\n");

	// passer en temps reel haute priorite
	param.sched_priority = 45;
	if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) {
		perror("pthread_setschedparam");
		exit(EXIT_FAILURE);
	}
	// attendre une seconde
	sleep(1);
	// prendre le mutex
	pthread_mutex_lock(& mutex);
	// travail actif
	fprintf(stderr, "T3 : Debut boucle\n");
	for (i = 0; i < BOUCLE_1; i ++)
		for (j = 0; j < BOUCLE_2; j ++)
			;
	fprintf(stderr, "T3 : Fin boucle\n");
	// liberer le mutex
	pthread_mutex_unlock(&mutex);

	return NULL;	
}

