c/linux: signal.h geht nicht



  • Basisfrage (wiedermal): warum kompiliert das Ding nich!?

    Hallo, ich versuche mit Signalen herumzuexperimentieren und es scheint mir als fehlt mir da irgendeine Library. Vielleicht fehlt auch nur ein include, eine Einstellung im Makefile, ein deb-Paket, eine Kerneleinstellung, ...kA, meinem System scheinen Signale gaenzlich unbekannt - ich arbeite auf einem Debian/Linux mit gebackenem 2.6.18er Kernel.

    Ach ja, und mich wuerde auch mal interessieren in welchen deb Paketen sich die Dokumentainen zu den C Funktionen (also 2, 3 oder Posix 😎 verbergen, da ich diese auch nicht installiert habe, dies aber gern tun wuerde.

    Danke im voraus und hier der Code:
    Makefile

    # Makefile (simple)
    #
    # use -O, -O1, -O2 for optimization 
    
    SOURCE = sigmask.c
    OBJECTS = ${SOURCE:.c=.o}
    
    .PREFIXES = .c .o
    CC = gcc
    CFLAGS = -g -Wall -std=c99 -pedantic
    RM = rm -f
    
    .c.o:
    	${CC} -c ${CFLAGS} $<
    
    sigmask: ${OBJECTS}
    	${CC} -o $@ ${OBJECTS} -lm
    
    all: sigmask
    
    clean: 
    	${RM} $(OBJECTS) sigmask *~ core
    

    sigmask.c

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #include <unistd.h>
    #include <sys/types.h>
    #include <signal.h>
    
    int ctrl_c_count = 0;
    
    #define CTRL_C_THRESHOLD 5
    #define SIG_SETMASK SIG_BLOCK
    
    void catch_int(int sig)
    {
      sigset_t mask_set;  // used to set a signal masking set
      sigset_t old_set;  // used to store the old mask set
    
      signal(SIGINT, catch_int);
    
      sigfillset(&mask_set);
      sigprocmask(SIG_SETMASK, &mask_set, &old_set);
    
      ++ctrl_c_count;
      if(ctrl_c_count >= CTRL_C_THRESHOLD){
        char answer[30];
    
        printf("\nReally Exit? [y/n]: ");
        fflush(stdout);
        gets(answer);
    
        if(answer[0] == 'y' || answer[0] == 'Y'){
          printf("\nExiting...\n");
          fflush(stdout);
          exit(0);
    
        }else{
          printf("\nContinuing\n");
          fflush(stdout);
          ctrl_c_count = 0;
        }
      }
    }
    
    void catch_suspend(int sig)   
    {
      sigset_t mask_set; // sig mask
      sigset_t old_set; // restore
      signal(SIGTSPT, catch_suspend);
      sigfillset(&mask_set);
      sigprocmask(SIG_SETMASK, &mask_set, &old_set);
      printf("\n\nso far, '%d' CTRL+C presses were counted\n\n", ctrl_c_count);
      fflush(stdout);
    }
    
    int main(int argc, char** argv)
    {
      signal(SIGINT, catch_int);
      signal(SIGTSTP, catch_syspend);
      while(1) pause();
      exit(0);
    }
    

    der Output:

    gcc -c -g -Wall -std=c99 -pedantic sigmask.c
    sigmask.c: In function "catch_int":
    sigmask.c:63: error: "sigset_t" undeclared (first use in this function)
    sigmask.c:63: error: (Each undeclared identifier is reported only once
    sigmask.c:63: error: for each function it appears in.)
    sigmask.c:63: error: expected ";" before "mask_set"
    sigmask.c:64: error: expected ";" before "old_set"
    sigmask.c:71: warning: implicit declaration of function "sigfillset"
    sigmask.c:71: error: "mask_set" undeclared (first use in this function)
    sigmask.c:72: warning: implicit declaration of function "sigprocmask"
    sigmask.c:72: error: "SIG_BLOCK" undeclared (first use in this function)
    sigmask.c:72: error: "old_set" undeclared (first use in this function)
    sigmask.c: In function "catch_suspend":
    sigmask.c:106: error: "sigset_t" undeclared (first use in this function)
    sigmask.c:106: error: expected ";" before "mask_set"
    sigmask.c:107: error: expected ";" before "old_set"
    sigmask.c:110: error: "SIGTSPT" undeclared (first use in this function)
    sigmask.c:113: error: "mask_set" undeclared (first use in this function)
    sigmask.c:114: error: "SIG_BLOCK" undeclared (first use in this function)
    sigmask.c:114: error: "old_set" undeclared (first use in this function)
    sigmask.c: In function "main":
    sigmask.c:130: error: "catch_syspend" undeclared (first use in this function)
    make: ** [sigmask.o] Erro 1
    


  • Ich denke (könnte mich irren!), dass es keine gute Idee ist, ein SIG_SETMASK als SIG_BLOCK zu definieren. Weshalb schreibst Du nicht gleich SIG_BLOCK? SIG_SETMASK ist dazu da, die Signale entsprechend der Angabe zu setzen.
    Danebst existieren mit dem Befehl signal() einige Probleme:
    - Anders als bei sigaction() kann beim Auftreten eines Signals die Standardbehandlung dies Signals wieder aktiviert werden, noch bevor die mit singal() gesetzte Behandlungsroutine aufgerufen wird.
    - Die derzeit für ein bestimmtes Signal aktive Signalbehandlung kann mit signal() nicht abgefragt werden, ohne gleichzeitig die Signalbehandlung für dieses Signal zu ändern.
    Verzichte daher lieber auf signal() und verwende stattdessen sigaction().
    Ich würde an Deiner Stelle eher so vorgehen, mit sigemptyset Dein sigset zu initialisieren, hernach mit sigaddset das gewünschte Signal (in Deinem Fall SIGINT) dem sigset hinzuzufügen und schliesslich mit sigprocmask( SIG_BLOCK, &sigset, &oldset ) neu zu setzen. Wenn Du nicht an dem vorhergehenden sigset interessiert bist, kannst Du anstelle des &oldset auch einen Nullzeiger übergeben.
    Sobald das Signal blockiert wurde, kannst Du mit sigwait auf das Signal warten. Du kannst natürlich auch gleich einen Signalhandler mit sigaction registrieren, dann müsstest Du das Signal gar nicht erst blockieren.

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h> /* für die error nummern */
    #include <string.h> /* für strerror */
    #include <unistd.h> /* für sleep */
    
    void my_signal_handler( int sig )
    {
      printf( "Signal Handler bekam das Signal: %d (SIGINT=%d)\n", sig, SIGINT );
    }
    
    int main()
    {
      struct sigaction newaction;
      newaction.sa_handler = &my_signal_handler; /* Signalhandler */
      sigemptyset( &newaction.sa_mask );
      newaction.sa_flags = 0;
    
      if( 0 > sigaction( SIGINT, &newaction, NULL ) )
      {
        printf( "Konnte handler nicht installieren: %s\n", strerror( errno ) );
        exit( EXIT_FAILURE );
      }
      /* usw. */
      sleep( 20 );
    
      exit( EXIT_SUCCESS );
    }
    

    So wird allerdings das Signal bloss über den Signalhandler "geschlauft". Nach dem Drücken der Abbruchtaste beendet sich das Programm.
    Ich schweife mal wieder ab... So wie es aussieht, fehlt Dir der header signal.h, da dort sigset_t definiert wird. Ich arbeite mit Gentoo, daher hab ich ohnehin von Beginn an alle Entwicklerwerkzeuge an Board. Unter Debian sollte meines Wissens ein Paket namens build-essential existieren, welches mindestens die Grundwerkzeuge mitbringen sollten. Die Dokumentationen sind eventuell in {blah}-doc Paketen enthalten. Suche doch einfach mal nach den docs:

    $ dpkg -l \* | grep "-doc"
    

    oderso. Danebst sind noch typos vorhanden:

    sigmask.c:130: error: "catch_syspend" undeclared (first use in this function)
    

    Sollte wohl heissen "catch_suspend".
    Grüsse



  • Noch was! Der Hammer-Editor vim liefert viele nützliche Nebeneffekte! Wenn Du mit vim in einem Quellcode bist, kannst Du auf einer Zeile wie:

    #include <signal.h>
    

    bist, einfach "gf" tippen (wenn der cursor auf dem Dateinamen steht, also auf dem "wort" "signal.h"), vim springt dann gleich in diese Datei! Wenn Du dabei einen Fehler erhältst, die Datei könne nicht gefunden werden, weisst Du, dass die Datei nicht existiert, resp. der header nicht da ist.



  • fidel schrieb:

    Ich denke (könnte mich irren!), dass es keine gute Idee ist, ein SIG_SETMASK als SIG_BLOCK zu definieren. Weshalb schreibst Du nicht gleich SIG_BLOCK? SIG_SETMASK ist dazu da, die Signale entsprechend der Angabe zu setzen.
    Danebst existieren mit dem Befehl signal() einige Probleme:
    - Anders als bei sigaction() kann beim Auftreten eines Signals die Standardbehandlung dies Signals wieder aktiviert werden, noch bevor die mit singal() gesetzte Behandlungsroutine aufgerufen wird.
    - Die derzeit für ein bestimmtes Signal aktive Signalbehandlung kann mit signal() nicht abgefragt werden, ohne gleichzeitig die Signalbehandlung für dieses Signal zu ändern.
    Verzichte daher lieber auf signal() und verwende stattdessen sigaction().
    Ich würde an Deiner Stelle eher so vorgehen, mit sigemptyset Dein sigset zu initialisieren, hernach mit sigaddset das gewünschte Signal (in Deinem Fall SIGINT) dem sigset hinzuzufügen und schliesslich mit sigprocmask( SIG_BLOCK, &sigset, &oldset ) neu zu setzen. Wenn Du nicht an dem vorhergehenden sigset interessiert bist, kannst Du anstelle des &oldset auch einen Nullzeiger übergeben.
    Sobald das Signal blockiert wurde, kannst Du mit sigwait auf das Signal warten. Du kannst natürlich auch gleich einen Signalhandler mit sigaction registrieren, dann müsstest Du das Signal gar nicht erst blockieren.

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h> /* für die error nummern */
    #include <string.h> /* für strerror */
    #include <unistd.h> /* für sleep */
    
    void my_signal_handler( int sig )
    {
      printf( "Signal Handler bekam das Signal: %d (SIGINT=%d)\n", sig, SIGINT );
    }
    
    int main()
    {
      struct sigaction newaction;
      newaction.sa_handler = &my_signal_handler; /* Signalhandler */
      sigemptyset( &newaction.sa_mask );
      newaction.sa_flags = 0;
      
      if( 0 > sigaction( SIGINT, &newaction, NULL ) )
      {
        printf( "Konnte handler nicht installieren: %s\n", strerror( errno ) );
        exit( EXIT_FAILURE );
      }
      /* usw. */
      sleep( 20 );
    
      exit( EXIT_SUCCESS );
    }
    

    So wird allerdings das Signal bloss über den Signalhandler "geschlauft". Nach dem Drücken der Abbruchtaste beendet sich das Programm.
    Ich schweife mal wieder ab... So wie es aussieht, fehlt Dir der header signal.h, da dort sigset_t definiert wird. Ich arbeite mit Gentoo, daher hab ich ohnehin von Beginn an alle Entwicklerwerkzeuge an Board. Unter Debian sollte meines Wissens ein Paket namens build-essential existieren, welches mindestens die Grundwerkzeuge mitbringen sollten. Die Dokumentationen sind eventuell in {blah}-doc Paketen enthalten. Suche doch einfach mal nach den docs:

    $ dpkg -l \* | grep "-doc"
    

    oderso. Danebst sind noch typos vorhanden:

    sigmask.c:130: error: "catch_syspend" undeclared (first use in this function)
    

    Sollte wohl heissen "catch_suspend".
    Grüsse

    Hallo,
    Wie schon gesagt kompiliert der Code bei mir nicht! Das ist mein eigentliches Problem, und eben genau nicht "abschweifen"!!! 😉

    Desweiteren ist mir auch klar, dass sigaction einiges an Vorteilen mit sich bringt, zB auch zur Signalsynchronisation - die ich aber eben auch nicht nutzen kann, wenn ein "sigaction" bei mir eben nicht kompiliert. Deshalb habe ich erstmal v.a. mit signal() herumexperimentiert. Das seltsame ist ja gerade, dass ein Teil der Signalfunktionen, zB signal() kompiliert wird, wohingegen andere, wie zB sigaction() aber nicht kompiliert werden.

    Wenn Du den Code durchdiskutieren willst, gut, ich habe bei den Signalhandlern (also bei dem der das Ding nicht abwuergt), einen Aufruf auf sich selber. Der soll eben genau das verhindern. Angeblich hat man das frueher so gemacht und es scheint zu funktionieren. Das Problem, was ich eher sehe, ist dass es eben ohne sigaction() schwer wird Signale sinnvoll zu blocken bzw zu synchronisieren.
    Das Problem mit dem abfragen und aendern muessen von signal() ist ein weiteres Uebel von signal().

    Wenn Du mich also von sigaction() und seinen Vorteilen ueberzeugen willst, rennst Du bei mir offene Tueren ein, nur dass es eben (noch) nicht kompiliert!!! 😉

    Ist denn das Makefile so ok? ich weiss bspw von Messagequeues dass man da evtl eine option -D _SVID_SOURCE und _XOPEN_SOURCE setzen sollte, bei Pthreads etwa die pthread als -lm dem Linker uebergeben muss, etc.. ?



  • Sorry! Ich quassle manchmal zuviel! Betreffend Makefiles verhält es sich bei mir ebenfalls so, dass ich das nicht mehr mache. Ich arbeite nur noch mit autoconf, das übernimmt mir so manches und macht danebst meine projekte auch portabel (nur als Tipp, nicht dass ich schon wieder abschweife 😉
    Betreffend den Compiler- und Linkerflags, für die Signalfunktionen brauchst Du keine lib, daher braucht es kein -l{irgendwas}. Die Signalfunktionen sind verfügbar, nachdem die header eingebunden wurden. Die Fehlermeldung:

    sigmask.c:63: error: "sigset_t" undeclared (first use in this function)
    

    deutet unweigerlich darauf hin, dass der header signal.h nicht gefunden wird:

    $ man sigaction
    SIGACTION(2)                                      Systemaufrufe                                     SIGACTION(2)
    
    BEZEICHNUNG
           sigaction, sigprocmask, sigpending, sigsuspend - POSIX Funktionen zur Signalbenutzung.
    
    UBERSICHT
           #include <signal.h>
    
           int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
    
           int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    
           int sigpending(sigset_t *set);
    
           int sigsuspend(const sigset_t *mask);
    

    #include <signal.h>
    muss reichen!

    $ ll /usr/include/signal.h
    -rw-r--r-- 1 root root 13K 15. Feb 16:08 /usr/include/signal.h
    

    Bei Dir könnte der Pfad evtl. anders lauten. Prüfe doch mal, ob Du den header überhaupt hast.
    Probier doch mal, die Datei mal von hand zu kompilieren, lass mal das pedantic und das std=.. weg:

    $ gcc -W -Wall -o sigmask sigmask.c
    

    So findest Du schnell raus, ob die flags Probleme bereiten.



  • SIG_SETMASK wird redefiniert -> schlecht
    SIGTSPT gibts nicht

    Und c99 ist halt _nur_ der c99 standard... nimms raus, nimm gnu99 oder was auch immer 😉



  • lagalopex schrieb:

    SIG_SETMASK wird redefiniert -> schlecht
    SIGTSPT gibts nicht

    Und c99 ist halt _nur_ der c99 standard... nimms raus, nimm gnu99 oder was auch immer 😉

    OH MANNN!!!! Klar, c99 das wars!!! 👍 👍 👍
    Danke, ich hab das daemliche c99 und pendantic jetz aus dem Makefile gehauen und schon kompilierts.

    Also fuer Euch Code-Fanatiker 😉
    das #define macht gar keinen Sinn und war ein Ueberbleibsel von irgendwas, weil's halt nicht kompiliert hatte, ein SIG_BLOCK wird jedoch gar nicht verwendet im Code.
    Nebenbei hab ich nun gets() in fgets() umgewandelt, SIGTSPT sollte SIGTSTP heissen, der Aufruf von catch_syspend() heisst nun catch_suspend(), usw usw..
    Brav? 😉

    Ich hatte das Beispiel ja auch nur aus einem der vielen Tutorials, noch ein paar zusaetzliche Typos eingebaut und fertig war's


Anmelden zum Antworten