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 Sebastian . Évalué à 2.
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 nas . Évalué à 1.
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 JaguarWan . Évalué à 1.
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 alf . Évalué à 2.
[ 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 Sebastian . Évalué à 1.
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 JaguarWan . Évalué à 1.
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 Sebastian . Évalué à 2.
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 nas . Évalué à 1.
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 alf . Évalué à 4.
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).
Pas seulement. 7.19.5.2p2:
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.