Mon cast (int)(long) ci-dessus n'était pas une bonne idée : en 64 bits, je pouvais tomber sur des pointeurs valides avec les 32 bits de poids faible équivalents à -1.
Je ne libérais pas convenablement ma mémoire partagée : il faut appeler shmctl avec IPC_RMID pour que la libération se fasse.
Voilà une version qui fonctionne (En même temps, je reste sur des opérations simples sur la liste chaînée : insertion en fin et parcourt). Elle découpe la mémoire partagée en blocs qui sont ensuites alloués à la liste chaînée.
/* Accès aux fonctions non ansi sous gcc */
#undef __STRICT_ANSI__
/* Accès aux fonctions systèmes sous HP-UX */
#define _INCLUDE_POSIX_SOURCE
#define _INCLUDE_XOPEN_SOURCE
#include "stdio.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/wait.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include "unistd.h"
#include "string.h"
#include "errno.h"
/* La clé ne doit pas être déjà utilisée par un autre processus du système */
#define SHM_KEY 32
#define MAX_LIST_SIZE 20
#define NO_MORE_CELL -1
#ifdef _LP64
#define POINTER_TO_INT long
#else
#define POINTER_TO_INT int
#endif /* _LP64 */
typedef struct _CELL
{
int nVal; /* Dans le cas du root, contient la prochaine clé libre */
int nNext; /* Id de la prochaine cellule, ou NO_NEXT_ID */
}
CELL;
/* Le champ cell doit rester le premier de cette structure pour que l'adresse
de la cellule corresponde à l'adresse du bloc. */
typedef struct _CELL_BLOCK
{
CELL cell;
int bUsed;
}
CELL_BLOCK;
int PrintLastError()
{
perror(strerror(errno));
return errno;
}
int AllocMemory(CELL_BLOCK* lpShM)
{
int nI;
/* On parcourt la mémoire à la recherche d'un bloc non utilisé */
for (nI = 0; nI < sizeof(CELL_BLOCK) * MAX_LIST_SIZE; nI++)
{
if (! lpShM[nI].bUsed)
break;
}
/* Vérification que l'on est pas arrivé au bout de la mémoire */
if (nI != sizeof(CELL_BLOCK) * MAX_LIST_SIZE)
lpShM[nI].bUsed = 1;
else
nI = 0;
return nI;
}
void FreeMemory(CELL* lpBlock)
{
((CELL_BLOCK*)lpBlock)->bUsed = 0;
}
CELL_BLOCK* MapMemory(int nShMId)
{
CELL_BLOCK* lpResult;
printf("%d map la mémoire\n", getpid());
lpResult = shmat(nShMId, NULL, 0);
if ((POINTER_TO_INT)lpResult == -1)
exit(PrintLastError());
return lpResult;
}
void InitMemory(CELL_BLOCK* lpShM)
{
/* On met la mémoire à zéro pour la définir comme non utilisée */
memset(lpShM, 0, sizeof(CELL_BLOCK) * MAX_LIST_SIZE);
}
void UnMapMemory(CELL_BLOCK* lpShM)
{
printf("%d démap la mémoire\n", getpid());
if (shmdt(lpShM) == -1)
PrintLastError();
}
CELL* InsertAfter(CELL_BLOCK* lpShM, CELL* lpCurrent, int nVal)
{
int nNew; /* Indice du bloc alloué dans la mémoire */
CELL* lpResult;
nNew = AllocMemory(lpShM);
if (nNew == 0)
{
UnMapMemory(lpShM);
exit(ENOMEM);
}
lpResult = (CELL*)&lpShM[nNew];
lpResult->nVal = nVal;
lpResult->nNext = lpCurrent->nNext;
lpCurrent->nNext= nNew;
return lpResult;
}
CELL* GetNext(CELL_BLOCK* lpShM, CELL* lpCurrent)
{
CELL* lpResult;
if (lpCurrent->nNext != NO_MORE_CELL)
lpResult = &lpShM[lpCurrent->nNext].cell;
else
lpResult = NULL;
return lpResult;
}
int ChildMain(int nShMId)
{
CELL_BLOCK* lpShM; /* Pointeur sur la mémoire partagée */
CELL* lpCurrent; /* Pointeur sur la cellule courante */
int nVal; /* Valeur de la cellule entrée par l'utilisateur */
lpShM = MapMemory(nShMId);
printf("Je suis le processus fils pid=%d\n", getpid());
InitMemory(lpShM);
/* Initialisation de la racine comme première case */
lpShM->bUsed = 1;
lpShM->cell.nNext = NO_MORE_CELL;
lpCurrent = &lpShM->cell;
scanf("%d", &nVal);
while (nVal != 0)
{
lpCurrent = InsertAfter(lpShM, lpCurrent, nVal);
scanf("%d", &nVal);
}
UnMapMemory(lpShM);
return 0;
}
int FatherMain(int nChildPid, int nShMId)
{
CELL_BLOCK* lpShM; /* Pointeur sur la mémoire partagée */
CELL* lpCurrent; /* Pointeur sur la cellule courante */
int status; /* Valeur de retour du processus fils */
int result;
result = 0;
lpShM = MapMemory(nShMId);
printf("Je suis le père pid=%d et j'ai créé un fils pid=%d\n",
getpid(), nChildPid);
/* Attente de la fin du fils */
if (waitpid(nChildPid, &status, 0) != -1)
{
/* Vérification que le processus fils s'est terminé normalement */
if (WIFEXITED(status) && (! WEXITSTATUS(status)))
{
printf("Fin normale du fils\n");
lpCurrent = GetNext(lpShM, &lpShM->cell);
while (lpCurrent != NULL)
{
printf("%d\n", lpCurrent->nVal);
lpCurrent = GetNext(lpShM, lpCurrent);
}
}
else
printf("Fils terminé avec erreurs\n");
}
else
result = PrintLastError();
/* Demande de libérer la mémoire lors du dernier démappage */
shmctl(nShMId, IPC_RMID, NULL);
UnMapMemory(lpShM);
return result;
}
int main(int argc, char **argv)
{
int nPid; /* Récupération du retour de fork */
int nShMId; /* Id de la mémoire partagée */
int result;
result = 0;
/* Allocation de la racine */
nShMId = shmget(SHM_KEY, sizeof(CELL_BLOCK) * MAX_LIST_SIZE,
IPC_CREAT | IPC_EXCL | 0666);
if (nShMId == -1)
{
result = PrintLastError();
goto the_end;
}
/* Création du fils */
nPid = fork();
if (nPid == -1)
result = PrintLastError();
else if (nPid == 0)
result = ChildMain(nShMId);
else
result = FatherMain(nPid, nShMId);
the_end:
return result;
}