IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

POSIX C Discussion :

Appeler une autre fonction depuis un signal


Sujet :

POSIX C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 88
    Points : 53
    Points
    53
    Par défaut Appeler une autre fonction depuis un signal
    Bonsoir,

    Je cherche désespérement comment je peux passer un parametre depuis une fonction appelée par un signal ?
    En fait, à partir du moment ou je suis dans la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    void sig_chld(int signo) 
    {
        int status, child_val;
     
        switch(signo) {
            case SIGCHLD :
     
                if (waitpid(-1, &status, WNOHANG | WUNTRACED)<0)
                {
                    printf("Erreur dans l'appel du wait : %s\n", strerror(errno));
                    return;  
                }
     
                if (WIFEXITED(status))                /* did child exit normally? */
                {
                    child_val = WEXITSTATUS(status); /* get child's exit status */
                    printf("child's exited normally with status %d\n", child_val);
     
     
                }
                break;
     
     
            case SIGINT :
                printf("\nSIGINT reçu\n");
                break;
     
            case SIGTSTP :
                printf("\nSIGSTOP reçu\n");
                break;
     
        }
    }
    J'aimerais pouvoir appeler une autre fonction en lui passant un paramétre qui est un pointeur. Le problème c'est que je ne sais pas comment passer ce pointeur puisque je ne peux déjà pas le passer en entrée dans sig_chld ?

    Merci de m'aider, je craaaaaaaaaaque

  2. #2
    Membre expérimenté
    Avatar de zekey
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 036
    Points : 1 403
    Points
    1 403
    Par défaut
    Je suis pas sure d'avoir compris mais... et une variable globale ?
    Steve Hostettler
    est ton ami(e) et le tag aussi.

  3. #3
    Membre éprouvé
    Avatar de Pouic
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    669
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 669
    Points : 977
    Points
    977
    Par défaut
    Il faut que tu te tournes vers les extensions Posix1.b de gestion des signaux.
    Lorsque tu installes ton handler à l'aide de la fonction sigaction, il suffit que tu lui passe en parametre le flag SA_SIGINFO, pour que ton handler de signaux ait le prototype suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void     (* sa_sigaction) (int, siginfo_t *, void *);
    Elle ne prend donc plus un seul argument mais trois.

    Avec la structure siginfo_t définie comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    siginfo_t {
                          int     si_signo;       /* Numéro de signal         */
                          int     si_errno;       /* Numéro d'erreur          */
                          int     si_code;        /* Code du signal           */
                          pid_t   si_pid;         /* PID de l'émetteur        */
                          uid_t   si_uid;         /* UID réel de l'émetteur   */
                          int     si_status;      /* Valeur de sortie         */
                          clock_t si_utime;       /* Temps utilisateur écoulé */
                          clock_t si_stime;       /* Temps système écoulé     */
                          sigval_t si_value;      /* Valeur de signal         */
                          int     si_int;         /* Signal Posix.1b          */
                          void *  si_ptr;         /* Signal Posix.1b          */
                          void *  si_addr;        /* Emplacement d'erreur     */
                          int     si_band;        /* Band event               */
                          int     si_fd;          /* Descripteur de fichier   */
                  }
    Tu noteras que le troisieme parametre est un void*, tu peux donc en plus passer de l'information utile lorsque tu envoies ton signal avec la fonction sigqueue (plutôt que kill).

    Le champs de type siginfo_t est rempli automatiquement.

    man sigaction et man sigqueue pour plus de détails
    Software becomes slower faster than hardware becomes faster
    [size=1]
    http://xrenault.developpez.com

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 88
    Points : 53
    Points
    53
    Par défaut
    Bah, la variable globale, je ne préfère pas.

    Pour être plus clair, du main() je déclare une variable du type de la structure suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    typedef struct processus {
        char *cde;
        pid_t PID;
        int num;
        struct processus *precedent;  
    } processus;
    ...
    processus *proc=NULL;
    puis j'appele une autre fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    execution(inst,&proc);
    qui contient ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    void
    execution(instruction inst,processus **proc)
    {
        pid_t pid;
        int wait_status;
     
        if (inst==NULL) return;
     
        pid=fork();
        if (pid==-1) {
            printf("Erreur dans la creation du fils : %s",strerror(errno));
            return;  
        } 
     
        // FILS 
        if (pid==0) {
     
            printf("\nPid pere : %d\n",getppid());
            if(strcmp(inst->cde,"cd")==0) {
                printf("CD A CODER\n");
            }
            else if(strcmp(inst->cde,"jobs")==0) {
                afficher_jobs(*proc);
            }
            else {
                    execvp(inst->cde,inst->argument);
                    printf("Erreur dans l'execution de la commande %s\n",strerror(errno));
                    exit(EXIT_FAILURE);  
            }
            exit(EXIT_SUCCESS);
        // PERE
        } else {
            printf("\nPid fils: %d\n",pid);
     
            // Execution avec un & (en tache de fond)
            if(inst->continuer) {
                ajouter_job(inst,proc,pid);
                execution(inst->suivant,proc);
            } else {
                ajouter_job(inst,proc,pid);
     
    LA -> while(estpresent_job(pid)) { }; // En attente que sig_chld retire le jobd de la liste
     
            }
        }
        execution(inst->suivant,proc);
    }
    Cette fonction execute des commandes en rendant la main ou non au systeme.
    Quand elle rend la main, pas de problème.
    Quand elle ne rend pas la main, elle vérifie en permanence que le job est toujours dans la liste des jobs, et ce tant qu'il y est.
    Quand le job/commande ce termine : un signal est déclenché est sig_chld est exécuté.
    J'aimerais que sig_chld enlève le job de la liste des jobs.
    Est mon problème : le job est stocké dans une liste (proc) dont la référence a été passée à la fonction execution. Quand sig_chld est déclenché, il ne voit pas cette référence ? Et je ne sais pas comment lui transmettre.

    Merci de m'avoir lu, et surtout merci de me répondre et...

    Joyeux noël

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 88
    Points : 53
    Points
    53
    Par défaut
    Merci Pouic d'avoir répondu.

    Je ne vois pas comment utiliser sigaction autrement, je l'ai déclaré dans le main comme ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
        struct sigaction act;
     
        // Assign sig_chld as our SIGCHLD handler
        act.sa_handler = sig_chld;
     
        //Concerne les processus qui se terminent normalement
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_NOCLDSTOP;
        if (sigaction(SIGCHLD, &act, NULL) < 0) 
        {
            fprintf(stderr, "sigaction failed\n");
            return 1;
        }
     
        //Concerne les processus que l'on stop CTRL-C
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_RESTART | SA_RESETHAND;
        if (sigaction(SIGINT, &act, NULL) < 0) 
        {
            fprintf(stderr, "sigaction failed\n");
            return 1;
        }
     
        //Concerne les processus que l'on stop CTRL-Z
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_RESTART | SA_RESETHAND;
        if (sigaction(SIGTSTP, &act, NULL) < 0) 
        {
            fprintf(stderr, "sigaction failed\n");
            return 1;
        }
    Ensuite le système est en attente de la fin normal du processus, je ne lui envoie donc pas un kill ?

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut Re: Appeler une autre fonction depuis un signal
    Citation Envoyé par laurent_ifips
    Je cherche désespérement comment je peux passer un parametre depuis une fonction appelée par un signal ?
    Variable globale de type sig_atomic_t.
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Si tu commences à faire ce genre de chose, je te conseille d'avoir une bonne référence sur le système que tu utilises. Dans le cas de Unix, disons "Advanced Programming in the UNIX Environment", par W.R. Stevens et S.A. Rago chez Addison-Wesley.

    En restant dans le cadre du C standard, il y a très peu de chose qu'on peut faire dans une fonction appelée par un signal... Tellement peu que je me demande si ça ne se limite pas pratiquement à modifier une variable globale volatile de type sig_atomic_t (si j'ai bonne mémoire, même appeler exit() et abort() n'ont pas de comportement défini, je ne sais plus si appeler longjmp est permis).

    Unix permet plus de choses, mais appeler printf comme tu le fais n'en fait pas partie (toujours de mémoire, tu peux utiliser directement write par contre).

    Un signal ne peut traiter que des données qu'il trouve dans des variables globales. Modifier une structure du genre liste chainée dans un signal, c'est quand très délicat. On a tous les problèmes de la programmation multi-thread, et quelques uns en plus (par exemple malloc et free ne sont pas appelables par un signal).

    J'ai pas le temps ni l'envie d'écrire un cours sur la gestion des signaux, mais heuresement dans ton cas, il y a une forme de wait qui attends qu'un enfant spécifique se termine (waitpid). L'utiliser à la place de ta boucle devrait résoudre le fond de ton problème.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

Discussions similaires

  1. Fonction javascript qui appelle une autre fonction javascript
    Par leara500 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 09/10/2012, 21h15
  2. Réponses: 4
    Dernier message: 29/04/2012, 00h09
  3. [XQUERY] fonction appel une autre fonction
    Par julie_lab dans le forum XQUERY/SGBD
    Réponses: 3
    Dernier message: 07/07/2010, 15h26
  4. Nom de la fonction appelant une autre
    Par eliek_9 dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 26/07/2006, 17h20
  5. Réponses: 21
    Dernier message: 20/06/2006, 16h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo