Forum Programmation.autre les sémaphores nommés

Posté par  .
Étiquettes : aucune
0
23
fév.
2006
je voudrais savoir si c'est possible d'utiliser des sémaphores nommés sur linux (suse 8.1).
lorsque je tape sur le terminal : man sem_open j'ai ceci en résultat :
linux:/ # man sem_open
Aucune entrée de manuel pour sem_open
le programme ci-dessous tourne bien sur Tru64 UNIX V5.0A mais sur linux (suse 8.1) la compilation se passe bien mais à l'éxecution j'ai comme erreur le message suivant :
Erreur de segmentation !
je compile avec la ligne suivante : gcc -v -g -lrt shmsem.c
la bibliothèque semaphore.h existe bien dans le dossier /usr/include/
voici le programme:
/*shmsem.c*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>

#define gotoxy(x,y)printf("\033[%d;%dH",y,x);

caddr_t pg_addr,pg_addr2;
sem_t *mysemp;
sem_t *mycpt;
int fd,fd2;

typedef struct p{
char nom[20];
char prenom[20];
int age;
}FICHE;

void Menu(void);
void Ecrire(void);
void shmsem(void);
void Lire(void);
void Quitter(void);

void Menu(void)
{
gotoxy(30,1);
printf("***** M E N U *****\n");
gotoxy(20,3);
printf("Tapez (1) Ecrire:?\n");
gotoxy(20,5);
printf("Tapez (2) Lire:?\n");
gotoxy(20,7);
printf("Tapez (3) Quitter:?\n");
gotoxy(20,9);
printf("Votre choix : ");
}
/*
prendre le sémaphore encoder puis libérer le sémaphore.
pendant que le processus écrit les autres sont bloqués
*/

void shmsem(void)
{
int size = 5*sizeof(FICHE);
int size2 =sizeof(int);
/*
int semid, nsems, semflg, CLE;
key_t key;
/*création de la première mémoire partagée*/
/************************************************/
fd = shm_open("example", O_RDWR|O_CREAT,S_IRWXO|S_IRWXG|S_IRWXU);
if (fd < 0)
{
perror("open error ");
exit(0);
}
if ((ftruncate(fd, size)) == -1)
{
perror("ftruncate failure");
exit(0);
}
/*Allocation de la mémoire partagée*/
pg_addr = (caddr_t) mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED,fd, 0);
if (pg_addr == (caddr_t) -1)
{
perror("mmap failure");
exit(0);
}
/**************************************************/
/*création de la deuxième mémoire partagée*/
fd2 = shm_open("example2", O_RDWR|O_CREAT,S_IRWXO|S_IRWXG|S_IRWXU);
if (fd2 < 0)
{
perror("open error");
exit(0);
}
if ((ftruncate(fd2, size2)) == -1)
{
perror("ftruncate failure");
exit(0);
}
/*Allocation de la mémoire partagée*/
pg_addr2 = (caddr_t) mmap(0, size2, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED,fd2, 0);
if (pg_addr2 == (caddr_t) -1)
{
perror("mmap failure");
exit(0);
}
/*le sémaphore initial*/

mysemp = sem_open("mysemp", O_CREAT | O_RDWR, 0644, 1);
if (mysemp == (void *)-1)
{
perror("sem_open() failed ");
}
/*le sémaphore compteur*/

mycpt = sem_open("mycpt", O_CREAT | O_RDWR, 0644, 0);
if (mycpt == (void *)-1)
{
perror("sem_open() failed ");
}
sem_post(mycpt);/*incrémentation du sémaphore compteur*/
}
void Ecrire(void)
{
FICHE nouveau;
int a,val;
char n[20], p[20];
/* ATTENTE DU SEMA : SEM_WAIT */
printf ("En attente.....\n");
sem_wait(mysemp);
fflush(stdout);
fflush(stdin);
printf ("ECRITURE\n");
fflush(stdin);
printf("Nom:");
scanf("%s",&n);
fflush(stdin);
printf("Prenom:");
scanf("%s",&p);
printf("Age:");
scanf("%d",&a);

strcpy(nouveau.nom, n);
strcpy(nouveau.prenom, p);
nouveau.age=a;
val=*pg_addr2;
memcpy(pg_addr+(val*sizeof(FICHE)), &nouveau, sizeof(FICHE));
if(val==5)
{
val=0;
*pg_addr2=val;
}
else
{
val++;
*pg_addr2=val;
}
/* LIBERATION DU SEMA : SEM_POST */
sem_post(mysemp);
}
/*
prendre le sémaphore, lire, afficher et libérer le sémaphore.
pendant que le processus lit les autres sont bloqués
*/
void Lire(void)
{
FICHE pers;
int i;
printf ("LECTURE\n");
/* ATTENTE DU SEMA : SEM_WAIT */
printf ("En attente......\n");
sem_wait(mysemp);
for(i=0;i<5;i++)
{
memcpy(&pers, pg_addr+(i*sizeof(FICHE)), sizeof(FICHE));
printf ("Nom : %s\t Prenom : %s\t Age : %d\n",pers.nom,pers.prenom,pers.age);
}
/* LIBERATION DU SEMA : SEM_POST */
sem_post(mysemp);
fflush(stdin);
getchar();
}
/*
le dernier processus qui reste doit détruire toutes les ressources :
mémoire partagée et sémaphore.
*/
void Quitter(void)
{
int val;
sem_wait(mycpt);
sem_getvalue(mycpt,&val);
if(val==0)
{
sem_unlink ("mysemp");
sem_unlink("mycpt");
shm_unlink("example");
shm_unlink("example2");
sem_close(mysemp);
sem_close(mycpt);
close(fd);
close(fd2);
}

}

int main(void)
{
char car;
shmsem();
do
{
printf("\033[2J");
Menu();
/* ignore tous les caracteres non alphanumeriques */
while(!isalnum(car=getchar()));
switch (car)
{
case '1': Ecrire();
break;
case '2': Lire();
break;
case '3': Quitter();
break;
default: fprintf(stderr,"%c: commande inconnue !\n",car);
}
}while (car != '3');

getchar();
return 0;
}
Apparemment le problème est dû aux sémaphores nommés, donc ma question est de savoir comment pourrais-je procéder à la réecriture du programme pour linux merci pour votre aide !!!
  • # #include <sem.h>

    Posté par  . Évalué à 2.

    Bonsoir,

    Personnellement j'utilise les directives de précompilations suivantes pour les sémaphores et les mémoires partagées (IPC Systèmes V) :

    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <sys/shm.h>


    Mais à dire que le problème vient de là ... Je ne serais répondre ;)
    Essayes également de rajouter des arguments comme gcc -Wall -pedantic pour avoir plus d'information sur les erreurs.
    • [^] # Re: #include <sem.h>

      Posté par  . Évalué à 1.

      karimi@linux:~/Tc> gcc -g -lrt -Wall -pedantic shmsem.c
      shmsem.c: In function `Ecrire':
      shmsem.c:127: warning: char format, different type arg (arg 2)
      shmsem.c:130: warning: char format, different type arg (arg 2)
      karimi@linux:~/Tc>
      voilà ce que j'obtiens donc apparmment des warning mais pas d'erreurs !!!
      • [^] # Re: #include <sem.h>

        Posté par  . Évalué à 1.

        Tu as essayé d'utiliser les sémaphores/mémoires partagées SystemV ?

        semget(2), semctl(2) (sémaphores), shmget(2), shmctl(2), shmat(2) et shmdt(2) pourraient t'intéresser.

        D'autre part, si tu as une segfault vérifie que tu n'as pas déclenché un buffer overflow: un autre post relève un gros trou (char ** filé au scanf + pas de limite de saisie) dans ton code de saisie utilisateur, et dans ton source tu fais à plusieurs reprise des au lieu de sympathiques memcpy().

        Je n'ai pas regardé en détail mais vérifie aussi tes manipulations de pointeur, Linux n'aime pas qu'on se balade en dehors d'une map.

        Dans tous les cas, en cas de segfault étranges, valgrind et gdb sont tes meilleurs amis :)
    • [^] # Re: #include <sem.h>

      Posté par  . Évalué à 2.

      Essayes également de rajouter des arguments comme gcc -Wall -pedantic pour avoir plus d'information sur les erreurs.
      Je fais plutôt gcc -W -Wall [-std=XXX [-pedantic]]. Le -W est à remplacer par -Wextra en GCC 4; -std=XXX pour spécifier la version de C, et -pedantic sert à ajouter des warnings demandés par la norme C et à d'autres choses (c'est moi qui souligne):
      -pedantic
      Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.

      Valid ISO C and ISO C++ programs should compile properly with or without this option (though a rare few will require -ansi or a -std option specifying the required version of ISO C). However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected.

      -pedantic does not cause warning messages for use of the alternate keywords whose names begin and end with `__'. Pedantic warnings are also disabled in the expression that follows __extension__. However, only system header files should use these escape routes; application programs should avoid them. See Alternate Keywords.

      Some users try to use -pedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all—only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.
      [ source:http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/Warning-Options.(...) ]
      Donc -pedantic rejettera les programmes utilisant des extensions au C "pur ISO", dont POSIX, par exemple, ou peut-être les IPC... (j'ai pas vérifié pour les IPC, mais je me suis déjà fait jeter par -pedantic pour du POSIX)

      Et, au passage, je n'utilise -pedantic qu'avec -std=XXX, pour bien savoir quelle version/extension de C j'utilise (et aussi au cas où quelqu'un pase derrière et ne connaît pas la version C par défaut de gcc, ou s'il utilise un autre compilateur, ou quand gcc changera de version C par défaut...).
  • # chaîne de caractères

    Posté par  . Évalué à 1.


    printf("Nom:");
    scanf("%s",&n);
    fflush(stdin);
    printf("Prenom:");
    scanf("%s",&p);


    Si je ne me trompe pas, quand tu dois renvoyer l'adresse d'une chaîne c'est ainsi :


    printf("Nom:");
    scanf("%s",n);
    fflush(stdin);
    printf("Prenom:");
    scanf("%s",p);
    • [^] # Buffer overflow power

      Posté par  . Évalué à 1.

      char n[20], p[20];

      printf("Nom:"); fgets(n, sizeof(n) * sizeof(char), stdin);
      printf("Prenom:"); fgets(p, sizeof(p) * sizeof(char), stdin);

      c'est plus secure quand même.

      P.S.: fflush(stdin) a un comportement indéfini, ça n'est autorisé que sur stdout.
      • [^] # Re: Buffer overflow power

        Posté par  . Évalué à 2.

        Effectivement,
        Tu as raison !
        Mais je ne crois pas qu'il faut multiplier le sizeof(n) par sizeof(char).
        Car il connait déjà la taille de la chaîne de caractère puisque les variables sont déclarées auparavant.
        fgets(n, sizeof(n), stdin);
        Avec un petit sscanf après les fgets également pour formater le tout.
        • [^] # Re: Buffer overflow power

          Posté par  . Évalué à 1.

          en fait ce que je voudrais comprendre c'est pourquoi :

          1. sous UNIX, le programme tourne parfaitement bien
          2. je n'ai aucune entrée de manuel pour sem_open() sachant bien que la bibliothèque semaphore.h est présente dans le /usr/include/
          3. peut-on utiliser des sémaphores nommés sur linux si c'est oui à l'aide de quel ensemble de fonctions.

          en vous remerciant pour les corrections apportées aux programmes !
      • [^] # Re: Buffer overflow power

        Posté par  . Évalué à 4.

        char n[20], p[20];

        printf("Nom:"); fgets(n, sizeof(n) * sizeof(char), stdin);
        printf("Prenom:"); fgets(p, sizeof(p) * sizeof(char), stdin);

        c'est plus secure quand même.

        Presque.

        Comme n est du type char[20], on a: sizeof(n) == 20 * sizeof (char). Donc ta formule est incorrecte. Note qu'elle renvoie le bon résultat numérique, mais seulement par coïncidence: la façon dont elle est exprimée laisse croire que, pour un tableau, sizeof tab renvoie le nombre d'éléments, alors qu'elle renvoie le nombre d'éléments fois la taille de l'élément (le nombre d'éléments est obtenu par sizeof array / sizeof array[0]).
        Tu obtiens le bon résultat dans ton cas, seulement parce que sizeof (char) == sizeof (unsigned char) == sizeof (signed char) == 1. C'est garanti par la norme C (6.5.3.4p1 du n1224).
        Dans tout autre cas, sizeof MonType >= 1. Pour fgets(), ça n'a aucun impact, vu qu'il attend des char mais, pour toute autre fonction, ta formule indiquerait à la fonction que le tableau fourni en paramètre a une taille plus grande qu'en réalité, d'où des risques de buffer overflow, ou de perte mémoire (je pense aussi à malloc(), si tu demandes plus de mémoire que ce dont tu as besoin, ce sont des pertes sèches...).

        Pour en revenir à ce bout de code précis, si on suppose que tu as mis simplement sizeof n, alors ton programe est plus sûr... jusqu'à ce que l'utilisateur rentre un nom de (au moins) 19 caractères... Dans ce cas, le premier fgets() mange les 19 premiers caractères, y ajoute un '\0', et rend la main en laissant le '\n' dans stdin. Le deuxième fgets() mangera tout de suite le '\n', et retournera après y avoir ajouté le '\0'.
        Tu obtiendras donc un nom de 19 caractères, et un prénom qui vaut '\n'. Idem pour le prénom, sachant que les caractères en trop dans stdin seront lus plus tard dans le code, et pas forcément là où on s'y attendrait...

        Avec fgets(), il faut tester la présence de '\n' dans le buffer, et lire la suite s'il n'y est pas (sauf si on a rencontré la fin du flux, évidemment). La bonne réponse est donc fgets(n, sizeof n, stdin); suivi d'une boucle de vérification de la présence de '\n' (avec strchr()) ou de fin du flux, et d'une relecture si nécessaire; le tout encapsulé dans une fonction générique, pour que tu n'aies pas à la recoder 20 fois (note aussi que ça se trouve sur le vaste internet, cd. http://cbfalconer.home.att.net/download/ggets.zip par exemple, faite par un connaisseur du C et "régulier" sur comp.lang.c).

        P.S.: fflush(stdin) a un comportement indéfini, ça n'est autorisé que sur stdout.

        Pas seulement. 7.19.5.2p2:
        If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
        Donc stderr ou tout autre flux sortant est valide pour fflush().

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.