Not logged in. · Lost password · Register

Page:  1  2  next 
macsurfer
Member since Feb 2013
7 posts
Subject: Aufgabe 8
Hallo,

ich habe mir jetzt viel zur Syntax von Signalen durchgelesen, aber wie ich das Programm aufbauen soll, ist mir noch völlig unklar.
Bei diesem Thema gibt es vieles, was doppelt beschrieben ist bzw. man kann es so oder auch anders schreiben. Deshalb hier meine Fragen:

Um mir eine Signalmaske zu erstellen kann ich entweder mit sigset_t sa_mask arbeiten ODER ich arbeite mit dem struct sigaction. sigaction enthält auch einen Eintrag sa_mask.
sigaction ist besser? weil?

Um mir einen Signalhandler zu bauen benutze ich entweder signal(SIGALRM, my_handler) ODER ich benutze die Funktion mysigactionstruct.sa_handler = my_handler. Zweites ist besser? weil?

Wenn ich z.B. nach 2 Sekunden das SIGALRM bekomme löse ich damit den Aufruf der Handlerfunktion aus.

An welcher Stelle im Code, soll ich jetzt das SIGALRM blockieren? Und wo wieder freigeben?

Das Erzeugen eines neuen Prozesses mit fork() und execvop() habe ich erstmal weggelassen.


#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void my_handler(int signum) {

    fprintf(stdout, "My handler text message\n");   
}

int main() {

    // Create a struct variable
    struct sigaction new_action, old_action;

    // Assign the handler for new_action
    new_action.sa_handler = my_handler;

    // Initialize the struct new_action with empty values
    sigemptyset(&new_action.sa_mask);

    // Define the behaviour of the sa_flags
    new_action.sa_flags = SA_RESTART;
    old_action.sa_flags = SA_RESTART;

    // Add signal SIGALRM to the new_action struct
    // sigaction( Signalnummer, neue maske, alte maske)
    sigaction(SIGALRM, &new_action, NULL);


    int myalarm = alarm(2);

    // To block the SIGALRM use the following 2 lines
    sigaddset(&old_action.sa_mask, SIGALRM);
    sigprocmask(SIG_BLOCK, &new_action.sa_mask, &old_action.sa_mask);

    while(myalarm == 0) {
        sigsuspend(&old_action.sa_mask);
    }
    sigprocmask(SIG_UNBLOCK, &new_action.sa_mask, NULL);
}
Raim
GSPiC-Guru
Member since May 2011
79 posts
Quote by macsurfer:
Um mir eine Signalmaske zu erstellen kann ich entweder mit sigset_t sa_mask arbeiten ODER ich arbeite mit dem struct sigaction. sigaction enthält auch einen Eintrag sa_mask.
sigaction ist besser? weil?

Das sind unterschiedliche Dinge. Im struct sigaction gibt es eine Signalmaske, die angibt welche Signale während der Ausführung einer Behandlungsfunktion zusätzlich zu dem gerade behandelten blockiert werden sollen. Siehe auch die entsprechende Man-Page.

Um mir einen Signalhandler zu bauen benutze ich entweder signal(SIGALRM, my_handler) ODER ich benutze die Funktion mysigactionstruct.sa_handler = my_handler. Zweites ist besser? weil?

Die Schnittstelle signal(2) ist nicht einheitlich implementiert und sollte nicht benutzt werden. Siehe auch hier die entsprechenden Man-Pages, der erste Satz aus man 2 signal: "The  behavior  of  signal() varies across Unix versions, and has also varied historically across different versions of Linux.  Avoid its use: use sigaction(2) instead.".
macsurfer
Member since Feb 2013
7 posts
Hallo,

danke für die Antwort.

Ich benutze also eine normale Maske z.B. sigset_t MaskeNormal und initialisiere sie mit sigemptyset(&MaskeNormal). In dieser Maske ist kein Signal geblockt.

Durch diese beiden Zeilen konnte ich das SIGALRM allgemein sperren:

sigaddset(&old_action.sa_mask, SIGALRM);
sigprocmask(SIG_BLOCK, &new_action.sa_mask, &old_action.sa_mask);

Wie kann ich es erreichen, das nur während der Handler-Fkt gesperrt wird?

Die alarm-Fkt löst ein SIGALRM aus, ich möchte während der Ausführung meiner Handler-Fkt das SIGALRM sperren.
Das erreiche ich mit sigaction(SIGALRM, &MaskeBlocken, &MaskeNormal) oder? Wo muss ich die sigaction(...) aufrufen?
Raim
GSPiC-Guru
Member since May 2011
79 posts
Quote by macsurfer:
Wie kann ich es erreichen, das nur während der Handler-Fkt gesperrt wird?

Die alarm-Fkt löst ein SIGALRM aus, ich möchte während der Ausführung meiner Handler-Fkt das SIGALRM sperren.

Dafür musst du nichts besonderes tun, das ist schon das normale Verhalten.
ingonör
Member since May 2013
67 posts
Das bedeutet also, wenn ein Signal eine Handler-Funktion auslöst, dann ist dieses Signal während der Handler-Funktionsbearbeitung automatisch gesperrt?
Raim
GSPiC-Guru
Member since May 2011
79 posts
Ja.
ingonör
Member since May 2013
67 posts
Ist es eigentlich so gedacht, dass im Signal-Handler von SIGALRM der Kindprozess erzeugt, sprich fork() und execvp() verwendet wird?
Falls ja, wie kann ich denn dem Signal-Handler Argumente übergeben? Irgendwo habe ich aufgeschnappt, dass das nur mit globalen Variablen ginge. Aber ist das hier wirklich so gedacht?

Falls nicht, was soll denn dann im Signal-Handler für SIGALRM geschehen?

Edit: Und noch eine Zwischenfrage:
Laut Aufgabenstellung soll nach Ablauf der vorgegebenen Zeit der neue Prozess ausgeführt werden und nach dessen Ausführung soll auf das ALARM Signal gewartet werden.
Ist das nicht irgendwie doppelt gemoppelt? Ich hätte es so verstanden, dass nach dem Setzen des Alarms der neue Prozess ausgeführt werden soll und nach dessen Ausführung wird mit sigsuspend(2) auf das nächste Alarm-Signal gewartet.

Edit 2: Also meine Intuition hat sich nun gegen ein forken im Signal-Handler entschieden.
Mein Programm läuft vom Prinzip so ab:

  1. int main(int argc, char **argv) {
  2.         alarm(alrmTime);
  3.  
  4.         //struct sigaction setzen
  5.         //Bitmaske leeren
  6.         //Funktion "alrm_handler" als sa_handler setzen
  7.         //sigaction mit SIGALRM setzen
  8.  
  9.        while(1){
  10.                /*** fork() und execvp() ähnlich wie in der lish ***/
  11.                
  12.  
  13.                 sigsuspend(&action.sa_mask);
  14.                 alarm(alrmTime);
  15.         }
  16. }
  17.  
  18. void alrm_handler(int sig_nr){
  19. }

Wie man sieht ist der alrm_handler leer. Anders kriege ich es aber nicht hin, dass immer wieder der Prozess aufgerufen wird. Setze ich z.B. den sa_handler auf SIG_DFL (was mir logischer erscheinen würde), dann wird das Programm mit der Meldung 'Alarm Clock 0' beendet. Seltsam, dass es nicht in der Endlosschleife verweilt.
Ist dieses Vorgehen nun korrekt?
This post was edited 2 times, last on 2013-07-05, 19:18 by ingonör.
Hase
Member since May 2013
13 posts
Das sieht doch schonmal garnicht so schlecht aus, so ähnlich ist eine Möglichkeit, sowas zu implementieren. Im Signalhandler solltest du noch was einbauen, das dir "verlorene" Alarme anzeigen kannst, ansonsten wirds schwer, die entsprechende Meldung auszugeben (siehe Aufgabenstellung). Ausserdem achte darauf, dass die Alarme immer alle n Sekunden nacheinander ausgelöst werden, ansonsten hälst du dich nicht an die Aufgabenstellung.
ingonör
Member since May 2013
67 posts
Quote by Hase on 2013-07-06, 01:46:
Im Signalhandler solltest du noch was einbauen, das dir "verlorene" Alarme anzeigen kannst, ansonsten wirds schwer, die entsprechende Meldung auszugeben (siehe Aufgabenstellung).

Damit habe ich noch so meine Problemchen. In der Übung sagtest du, dass es nicht funktionieren wird, wenn man z.B.
./spite 1 sleep 2
ausführt. So ist es bei mir momentan.
Vor dem beenden des sleep Prozesses wird einmal der alarm-Handler aufgerufen. Danach beendet er noch sleep und bleibt dann in der Zeile
sigsuspend(&action.sa_mask);
hängen.
Wie komme ich da weiter? Welche Funktion sollte ich mir dazu nochmal genauer ansehen?

Edit: Bisher habe ich die Funktion sigprocmask() ignoriert. Die scheint ja der Schlüssel zu meinem Problem zu sein. Ich habe das Programm nun folgendermaßen geändert:

  1.        
  2.         //Folgender Teil war so schon implementiert
  3.                 //sigaction struct erzeugen
  4.         //sigaction den alarm-Handler zuweisen
  5.         //sigaction flag = SA_RESTART setzen
  6.         //sigaction maske leeren
  7.         sigaction(SIGALRM, &action, NULL);
  8.        
  9.         //Dieser Teil ist neu hinzu gekommen
  10.         sigset_t mask;
  11.                 sigemptyset(&mask);
  12.                 sigaddset(&mask, SIGALRM);
  13.                 sigprocmask(SIG_BLOCK, &mask, &action.sa_mask);
  14.        
  15.         //...
  16.  
  17.         while(1){
  18.                 //fork() und execvp() aehnlich wie in der lish   
  19.                
  20.                 sigsuspend(&action.sa_mask);               
  21.                 alarm(alrmTime);
  22.         }

Jetzt funktioniert es auch mit
./spite 1 sleep 2
aber so ganz richtig ist das Ganze ja noch nicht oder?
Denn ich weiß noch nicht, wie ich mir "verlorene" Alarme speichern soll. Natürlich geht das mit einer volatile-Variable, die irgendwie im alarm-Handler verwendet/geändert werden soll.
Aber so, wie mein Code momentan steht, wird der alarm-Handler nur alle 2 Sekunden aufgerufen und nicht nach 1 Sekunde, da SIGALARM ja blockiert ist.
Wo ist der Fehler?
This post was edited on 2013-07-07, 09:39 by ingonör.
morty
SPiC-Meister
(Moderator)
Member since May 2011
331 posts
Naja das Problem ist, dass du _genau ein_ SIGALRM bekommst. Du muss also dafür sorgen, dass sobald du einen Alarm bekommen hast ein neuer aufgesetzt wird. Gleichzeitig (Achtung Schlüsselwort!) wartest du auf die Beendigung des Kindes.
ingonör
Member since May 2013
67 posts
Quote by morty:
Naja das Problem ist, dass du _genau ein_ SIGALRM bekommst. Du muss also dafür sorgen, dass sobald du einen Alarm bekommen hast ein neuer aufgesetzt wird.

Das stimmt doch gar nicht. Am Ende meiner Endlos-while Schleife wird doch immer ein neuer Alarm aufgesetzt. Oder wie ist das zu verstehen?
Treak
Member since Apr 2012
3 posts
Ja am Ende deiner Schleife, also nachdem du bereits das Kind wieder eingesammelt hast, was je nachdem wie lange das Kind braucht sehr lange sein kann.

Durch das blockieren von SIGALRM (mit sigprocmask) veschiebst du das Problem nur. Dein programm wacht wider auf weil das Signal verspätet zugestellt wird. Es  ist vorher geblockt und wird währende dem sigsuspend unblocked, wo dann sofort ankommt und wieder aufwacht. So wachst du zwar garantiert wieder auf, aber du kannst niemals erkennen wann das SIGALRM kam.
Auch behebst du damit nicht das Problem, dass du den alarm nicht regelmässig bekommst, sonder zusätzlich noch abhängig von der berechenzeit des Kindes.

Wie morty gesagt hat, muss der Alarm gesetzt werden sofort nachdem der letzte Alarm kam, damit du gewährleisten kannt, dass die Alarme in regelmässigem Abstand kommen.
FanFan
FSI EEI & FSI Mechatronik
(Moderator)
Member since Oct 2010
76 posts
Quote by Treak:
[...]muss der Alarm gesetzt werden sofort nachdem der letzte Alarm kam[...]

Das heist am besten gleich im Signalhandler?
Fufu der Radiergummi
Member since Apr 2012
25 posts
Quote by FanFan:
Das heist am besten gleich im Signalhandler?

Dacht ich mir auch grad, aber wie übergeb ich der Handlerfunktion die Alarmzeit?

Edith: Globale Variablen sind ja wieder verpöhnt nehm ich an
This post was edited on 2013-07-09, 14:29 by Fufu der Radiergummi.
morty
SPiC-Meister
(Moderator)
Member since May 2011
331 posts
Quote by Fufu der Radiergummi:
Quote by FanFan:
Das heist am besten gleich im Signalhandler?

Dacht ich mir auch grad, aber wie übergeb ich der Handlerfunktion die Alarmzeit?

Edith: Globale Variablen sind ja wieder verpöhnt nehm ich an

?!?!? Wie mit volatile: So wenig wie Möglich so viel wie nötig. Sie sollen vermieden werden, wenn's geht. Es macht aber keinen Sinn auf sie zu verzichten, wenn man dann Code-technisch einen Handstand machen und mit den Ohren wackeln muss.
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O :troll:
Special characters:
Page:  1  2  next 
Go to forum
Powered by the Unclassified NewsBoard software, 20110527-dev, © 2003-8 by Yves Goergen