//----------------------------------------------------------------------
//----------------------------------------------------------------------
//
//		--------------------------------
//		 Utilisation des I.P.C. (linux)
//		--------------------------------
//
//----------------------------------------------------------------------
//----------------------------------------------------------------------

#include	<stdio.h>
#include	<unistd.h>
#include	<stdlib.h>
#include	<string.h>
#include	<errno.h>

#include	<signal.h>
#include	<sys/types.h>
#include	<sys/ipc.h>
#include	<sys/sem.h>
#include	<sys/shm.h>
#include	<sys/msg.h>

//----------------------------------------------------------------------
//----------------------------------------------------------------------

#define		a(b)	printf("%s\n", b)

#define		tellProcess				\
	theProcId	= getpid();			\
	printf("%d: pid du processus\n", theProcId);	\
	theProcId	= getppid();			\
	printf("%d: pid de son pere\n", theProcId);
	
int		debug	= 0;
int		environ	= 0;

//----------------------------------------------------------------------
//----------------------------------------------------------------------

/**
 *	A tout moment, on peut consulter la derniere erreur 
 *	vue par le systeme.
 */
extern
int		errno;

//----------------------------------------------------------------------
//----------------------------------------------------------------------

/**
 *	Une fonction de traitement pour un/des signal/aux
 *	a toujours cette signature.
 */ 
void		trtSignal		(int s)
	{
	printf	("traitement du signal %d\n", s);
	sleep(3);
	}

//----------------------------------------------------------------------
//----------------------------------------------------------------------

/**
 * 	Le point d'entree 'main' recoit 
 * 	en parametres:
 * 	-)	le nombre de mots de la ligne de commande
 * 		(avant '<' ou  '>' ou '&')
 * 	-)	le tableau des mots de cette ligne de commande
 * 	-)	le tableau des variables d'environnement
 */
int		main			(int argc, char * argv[], char * envp[])
	{
	int		w, rc, id, s;

	printf	("\n");
	printf	("----------------------------\n");
	printf	(" Qq manipulations d'I.P.C.: \n");
	printf	("----------------------------\n");
	printf	("\nB.M.G. version Automne 2010 \n");
	printf	("\nligne de commande \n");
	for	(w = 0; w < argc; w++)
		{
		printf	("\n%d\t%s\n", w, argv[w]);
		if	(! strcmp(argv[w], "-debug"))	debug	= 1;
		if	(! strcmp(argv[w], "-environ"))	environ	= 1;
		}
	if	(environ)
		{
		printf	("\nenvironnement");
		for	(w = 0; envp[w]; w++)
			{
			printf	("\n%d\t%s\n", w, envp[w]);
			}
		}

	a("manipulation de l'environnement");
	//-----------------------------------
	
	setenv	("aaa", "AAAAAAAA", 1);
	printf	("<%s>\n", getenv("aaa"));
	
	a("'system' lance une commande, et l'attend");
	//--------------------------------------------
	
	printf	("\n");
	system("date");
	printf	("\n");
	
	a("manipulation des semaphores");
	//-------------------------------

        typedef	union semun
		{
		int val;                  /* valeur pour SETVAL */
		struct semid_ds *buf;     /* buffer pour IPC_STAT, IPC_SET */
		unsigned short *array;    /* table  pour GETALL, SETALL */
		                          /* Sp�cificit� Linux : */
		struct seminfo *__buf;    /* buffer pour IPC_INFO */
		}
	itsSemun;
       
	itsSemun	arg;

	typedef	struct sembuf
		{
		short sem_num;  /* Num�ro du s�maphore (0=premier) */
                short sem_op;   /* Op�ration sur le s�maphore      */
		short sem_flg;  /* Options pour l'op�ration        */
		}
	itsSembuf;

	itsSembuf	act[1];
			
	a("interception de tous les signaux");
	//------------------------------------
	
	for	(w = 0; w < 32; w++)
		{
		signal	(w, trtSignal);
		}

	a("mise en place d'un segment de memoire partagee");
	//--------------------------------------------------

	void *		m;
	
	/* '666' est une valeur convenue; cf 'ftok()' a la place */
	id = shmget	(666, 1000, IPC_CREAT);
	if	(id < 0)perror("shmdt: ");
	printf	("shmget id=%d\n", id);

	m = shmat	(id, NULL, 0);
	printf	("shmat rc=%d\n", (int)m);
	if	(! m)	perror("shmat: ");

	rc= shmdt	(m);
	printf	("shmdt rc=%d\n", rc);
	if	(rc < 0)perror("shmdt: ");
	
	m = shmat	(id, NULL, 0);
	if	(! m)	perror("shmat: ");
	strcpy	((char *)m, "1234567890");

	a("mise en place d'un semaphore");
	//--------------------------------

	s = semget	(555, 1, 512);
	if	(s < 0)	perror("semget: ");
	printf	("semget id=%d\n", s);

	rc = semctl	(s, 0, GETVAL);
	printf	("semop-GETVAL=%d\n", rc);

	arg.val = 5;
	rc = semctl	(s, 0, SETVAL, arg);
	printf	("semop-SETVAL=%d\n", rc);
	rc = semctl	(s, 0, GETVAL);
	printf	("semop-GETVAL=%d\n", rc);

	a("mise en place d'une file de messages");
	//----------------------------------------

	// (en boucle du pgm au pgm: totalement inutile sous cette forme !)
	
	int	f = msgget	(444, IPC_CREAT);
	if	(f < 0)	perror("msgget: ");
	printf	("msgget id=%d\n", f);

	struct	msgbuf
		{
		long	mtype;
		char	mtext[10];
		}
		theMsg;

	theMsg.mtype	= 5;
	strcpy	(&(theMsg.mtext[0]), "111");
	rc	= msgsnd	(f, (struct msgbuf *)&theMsg, 10,
						 IPC_NOWAIT);
	if	(rc < 0)perror("msgsnd: ");
	printf	("rc <%d>\n", rc);
	
	strcpy	(&(theMsg.mtext[0]), "222");
	rc	= msgrcv	(f, (struct msgbuf *)&theMsg, 10,
					(long)0, IPC_NOWAIT);
	if	(rc < 0)perror("msgrcv: ");
	printf	("rc <%d>\n", rc);

	printf	("MSG: <%s>\n", &(theMsg.mtext[0]));

	a("multi-processing");
	//--------------------
	
	pid_t	theProcId;
	tellProcess;
	
	pid_t	theProc	= fork();
	switch	(theProc)
		{
		case	-1:
			{
			printf	("le fork a echoue; errno=%d\n", errno);
			}
		break;
		case	0:
			{
			printf	("debut d'un fils \n");
			tellProcess;

			printf	("memoire partagee vu du fils <%s>\n",
					(char *)m);
			
			m = shmat	(id, NULL, 0);
			printf	("shmat rc=%d (fils)\n", (int)m);
			if	(! m)	perror("shmat: ");
			sleep	(2);

			printf	("le fils decide d'attendre le pere...\n");
			act[0].sem_num	=	0;
			act[0].sem_op	=	0;
			act[0].sem_flg	=	0;
			rc = semop	(s, act, 1);
			printf	("semop: %d %d\n", rc, errno);
			if	(rc < 0)	perror	("semop: ");
			printf	("le fils a fini d'attendre\n");
			
			printf	("fin d'un fils \n");
			exit	(0);
			}
		break;
		default	:
			{
			printf	("suite du pere \n");
			tellProcess;
			
			printf	("le pere commence a ne rien faire...\n");
			sleep	(10);
			printf	("...le pere a fini de ne rien faire\n");
			printf	("memoire partagee vue du pere <%s>\n",
					(char *)m);
	
			printf	("le pere decide de liberer le fils\n");
			arg.val = 0;
			rc = semctl	(s, 0, SETVAL, arg);
			printf	("semop-SETVAL=%d\n", rc);
			sleep	(4);
			printf	("fin du pere \n");
			}
		break;
		}
	
	printf	("fin\n");
	return	0;
	}

//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------

