C: Workaround für Problem



  • Hallo zusammen,

    ich habe ein kleines Problem in C und frage mich, ob jemand die Lösung dafür weiss:

    Folgendes Programm simuliert das Problem:

    #include <stdio.h>
    #include <signal.h>
    #include <fcntl.h>
    #include <stdlib.h>
    
    int main(void)
    {
       int fd;
       FILE *f;
       char *befehl;
    
       void alrmHndlr(int sig)
       {
          signal(SIGALRM, SIG_DFL);
          printf(" :-( \n");
          free(befehl);
    
          /*Kritischer Punkt*/
          fclose (f);
          close(fd);
    
          exit(0);
       } /* of Handler */
    
       fd = 0;
       f = fdopen (fd, "r+");
    
       printf(" :-) \n");
    
       befehl = malloc(1024);
       signal(SIGALRM, alrmHndlr);
    
       alarm(2);
    
       while(fgets(befehl, 1024, f) != 0)
       {
    
          printf("Befehl:%s\n", befehl);
    
       } /* of while */
    }/* of main */
    

    Die while-Schleife wartet auf die Standardeingabe.
    Währenddessen wird aber alarm() ausgeführt und der Stream f soll geschlossen werden. Dieser scheint aber vom System nicht als bereit zum Schließen markiert zu sein, so dass Valgrind folgenden Fehler anzeigt:

    valgrind: the `impossible' happened:
    poll_for_ready_fds: select failed?!
    Basic block ctr is approximately 150000

    sched status:

    Thread 1: status = Runnable, associated_mx = 0x0, associated_cv = 0x0
    ==3190== at 0x4017DF64: vgPlain___libc_freeres_wrapper (vg_intercept.c:870)
    ==3190== by 0x804A10D: alrmHndlr.0 (command.c:141)
    ==3190== by 0x4017C7EF: ??? (vg_hashtable.c:213)
    ==3190== by 0x402BEFE7: _IO_file_underflow@@GLIBC_2.1 (in /lib/libc-2.3.2.so)

    Was ich bräuchte währe als entweder eine Möglichkeit, die while-Schleife zu verlassen oder zu signalisieren, dass das Programm nicht mehr auf fgets warten soll.

    Danke im Vorraus,
    Gwar



  • Du darfst im Signalhandler nur bestimmte Funktionen aufrufen. Siehe die NOTES in der manpage zu signal.

    Also mach ein Flag was du im Handler setzt und in der Schleife überprüfst.



  • Hi,

    erst einmal vielen Dank für die Antwort.

    Meine Manpage sagt leider nichts über verbotene Methoden innerhalb eines Signal-Handlers aus.

    Der Signalhandler wird auf handler gesetzt, die eine benutzerdefinierte Funktion (...) sein darf

    Zu Deinem Lösungsvorschlag:

    Du meinst mit Flag z.B. so etwas:

    #include <stdio.h>
    #include <signal.h>
    #include <fcntl.h>
    #include <stdlib.h> 
    #include <errno.h>
    
    int main(void)
    {
    	int fd;
    	FILE *f;
    	char *befehl;
    	int test=0;
    
    	void alrmHndlr(int sig)
    	{
    		signal(SIGALRM, SIG_DFL);
    		printf(" :-( \n");
    		test=1;
    
    	} /* of Handler */
    
    	fd = 0;
    	f = fdopen (fd, "r+");
    
    	printf(" :-) \n");
    
    	befehl = malloc(1024);
    	signal(SIGALRM, alrmHndlr);
    
    	alarm(2);
    
    	while(test==0)
    	{
    		fgets(befehl, 1024, f);
    		printf("Befehl:%s\n", befehl);
    
    	} /* of while */
    	free(befehl);
    	if (fclose(f) != 0){
    		perror("fclose\n");
    	}/* of if*/
    	exit(0);
    }/* of main */
    

    An sich würde das ja gehen - allerdings wartet fgets nach dem Signal noch auf eine Eingabe, so dass man erst noch irgendetwas eingeben muss, damit das Programm beendet... gibt es dafür eine Lösung?

    Dank und Gruß,
    Gwar



  • Gwar schrieb:

    An sich würde das ja gehen - allerdings wartet fgets nach dem Signal noch auf eine Eingabe, so dass man erst noch irgendetwas eingeben muss, damit das Programm beendet... gibt es dafür eine Lösung?

    Das ist hier auch so. Keine Ahnung warum.

    Wegen dem Handler:

    The routine handler must be very careful, since processing elsewhere
    was interrupted at some arbitrary point. POSIX has the concept of "safe
    function". If a signal interrupts an unsafe function, and handler
    calls an unsafe function, then the behavior is undefined. Safe func-
    tions are listed explicitly in the various standards. The POSIX
    1003.1-2003 list is

    _Exit() _exit() abort() accept() access() aio_error() aio_return()
    aio_suspend() alarm() bind() cfgetispeed() cfgetospeed() cfsetispeed()
    cfsetospeed() chdir() chmod() chown() clock_gettime() close() connect()
    creat() dup() dup2() execle() execve() fchmod() fchown() fcntl() fdata-
    sync() fork() fpathconf() fstat() fsync() ftruncate() getegid()
    geteuid() getgid() getgroups() getpeername() getpgrp() getpid() getp-
    pid() getsockname() getsockopt() getuid() kill() link() listen()
    lseek() lstat() mkdir() mkfifo() open() pathconf() pause() pipe()
    poll() posix_trace_event() pselect() raise() read() readlink() recv()
    recvfrom() recvmsg() rename() rmdir() select() sem_post() send()
    sendmsg() sendto() setgid() setpgid() setsid() setsockopt() setuid()
    shutdown() sigaction() sigaddset() sigdelset() sigemptyset() sig-
    fillset() sigismember() signal() sigpause() sigpending() sigprocmask()
    sigqueue() sigset() sigsuspend() sleep() socket() socketpair() stat()
    symlink() sysconf() tcdrain() tcflow() tcflush() tcgetattr() tcgetp-
    grp() tcsendbreak() tcsetattr() tcsetpgrp() time() timer_getoverrun()
    timer_gettime() timer_settime() times() umask() uname() unlink()
    utime() wait() waitpid() write().



  • Vielen Dank schon mal. Falls ich ne Lösung finde werde ich sie hier posten.

    Gruß,
    Gwar



  • Vielleicht könnte das jemand nach Unix/Linux schieben. Dachte erst, dass wäre noch Standard-C aber alarm() ist wohl doch nur POSIX.



  • DrGreenthumb schrieb:

    Vielleicht könnte das jemand nach Unix/Linux schieben.

    Kein Problem.



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum Linux/Unix verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Erst mal sorry für's Posten ins falsche Forum.

    Ich habe das Problem mit select (siehe manpage, man select) gelöst.
    Klappt wunderbar.

    Gruß,
    Gwar



  • Aber ich frage mich, wieso sich ein read() nicht durch ein Signal abbrechen lässt, wo es doch extra dafür einen ERROR-Code gibt.



  • Mein Professor meinte, es wäre meistens, aber eben nicht immer, erwünscht, dass die Leseoperation nach einem alarm wieder aufgenommen wird (z.B. wenn der Prozess nur an etwas erinnert werden soll). Wahrscheinlich liegt es daran?

    Gruß,
    Gwar



  • es gibt ja eine neuere POSIX Signal API, da kann man auch einstellen, ob ein Signal unterbrechend wirkt

    man: sigaction(2)



  • nur ma so ne frage... aber seit wann kann man in c funktionen in einer funktion definieren?



  • gar nicht. Ich nehm an, dass das ein AbTipp Fehler war.



  • nein, kein Abtippfehler. Ich muss zugeben, dass ich erst seit ein paar Wochen C programmiere und mir dieser Beschränkung nicht bewusst war. Bei mir kompiliert das Programm auch ohne Probleme und funktioniert, daher habe ich mir auch nichts weiter bei gedacht. Hab schon in nem anderen Forum gelesen, dass das eigentlich nicht der Fall sein dürfte... ist es aber bei mir 😕

    Gruß,
    Gwar



  • das ist eine gcc-Erweiterung, die leider aber auch nur dort funktioniert. Kann man nur hoffen, das sich dass irgendwann mal ändert.



  • ... dass es auch von anderen Compilern unterstützt wird oder dass gcc es nicht mehr macht weil es kein Standard ist?

    Übrigens: wie könnte man denn ohne lokale Funktionsdeklarationen realisieren, dass ein Signalhandler (dem man ja AFAIK keine Werte mit übergeben kann) auf eine Variable zugreift? Eigentlich dann ja nur durch globale Variablendefinitionen, oder?

    Gruß,
    Gwar



  • ich meine hoffen, dass es irgendwann mal Standard ist und überall funktioniert.

    Jo, ohne der Erweiterung musst du es global machen. Nicht wirklich im ganzen Programm global, aber immerhin in dem Modul.


Anmelden zum Antworten