Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » signa() & longjmp()

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
14.11.2009, 20:17 Uhr
~Sne11ius
Gast


Hallo zusammen!

ich muss als Aufgabe für die Uni ein Programm schreiben, dass empfangene Signale auf der Konsole ausgibt.
Ich bin damit auch recht erfolgreich... Allerdings macht die letzte while-Schleife nicht das, was ich von ihr erwarte: nach der dritten Benutzung von CTRL+C das Programm auf jeden Fall beenden.
Auch wenn er etwas lang ist zeig euch besser den Kompletten Quelltext, sonst lass ich noch aus versehen was wichtiges weg.

Vielen Dank natürlich im Vorraus!


C++:
#include <iostream> // für cout

#include <cstdio>   // für getchar()
#include <cstdlib>  // für exit()
#include <csignal>  // für signal(), SIGABRT, SIGFPE...
#include <csetjmp>  // für setjmp() und longjmp()

using namespace std;

// Diese Variable wird abgefragt, befor eine Anweisung ausgeführt wird,
// die zum Senden eines Signales führt.
volatile bool do_Bad_Things(false);

// In diese Struktur wird mittels setjmp() die aktuelle 'Programmumgebung'
// gespeichert (z. B. Werte von Registern, Program-Counter)
jmp_buf save_Env;

// Diese Funktion gibt eine zum jeweiligen Signal passende Meldung aus.
// Außerdem setzt sie 'do_Bad_Things' auf false.
// Die Funktion wird in main() mittels signal() als Signal-Handler für hier
// aufgeführten Signale gesetzt.
void signal_Handler(int SIG)
{
    // Meldung machen:
    switch (SIG)
    {
        case (SIGABRT) :
      cout << "SIGABRT";
        break;
        case (SIGFPE) :
            cout << "SIGFPE";
            break;
        case (SIGILL) :
            cout << "SIGILL";
            break;
        case (SIGSEGV) :
            cout << "SIGSEGV";
            break;
        case (SIGTERM) :
        cout << "SIGTERM";
            break;
        default :
        cout << "unknown signal";
    }

    cout << "(" << SIG << ") received." << endl;

    // Dafür sorgen, dass nicht das gleiche Signal sofort wieder ausgelöst
    // wird
    do_Bad_Things = false;

    signal(SIG, &signal_Handler);
    // Zu 'sicherer' Position springen
    longjmp(save_Env, 1);
}

volatile int repeat(3);

void INT_Handler(int SIG)
{
    --repeat;
    cout << endl << "SIGINT(" << SIG << ") receieved." << endl;
    cout.flush();
    cout << "Wirklich beenden? [j/n] " << endl;
    char c(getchar());
    if ('j' == c || 'J' == c)
    exit(0);
    else
    longjmp(save_Env, 1);
}

// Aktuellen Status sichern und Auslösen eines Signals erlauben
int save_State()
{
    do_Bad_Things = true;
    return setjmp(save_Env);
}

int main(int argc, char** argv)
{
    // Persönlichen Handler für Signale registrieren
    signal(SIGABRT, signal_Handler);
    signal(SIGABRT, signal_Handler);
    signal(SIGFPE,  signal_Handler);
    signal(SIGILL,  signal_Handler);
    signal(SIGSEGV, signal_Handler);
    signal(SIGTERM, signal_Handler);
    signal(SIGKILL, signal_Handler);
    signal(SIGINT,  INT_Handler);

    // Status sichern
    save_State();
    if (do_Bad_Things)
        int i(0/0); // Division durch 0 => SIGFPE

    save_State();
    if (do_Bad_Things)
    {
        int* p(0); // Pointer zeigt auf Adresse 0
        *p = 0;    // In Adresse 0 schreiben => SIGSEGV
    }

    while(true)
    {
        save_State();
        cout << "Druecke CTRL-C zum Beenden des Programms." << endl;
        if (repeat == 0)
            exit(0);
        pause();
    }
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
14.11.2009, 21:22 Uhr
Hans
Library Walker
(Operator)


Hi,

das hier

C++:
volatile int repeat(3);



sieht mir wie eine Funktionsdeklaration aus, bei der eine Funktion namens repeat deklariert wird, die den Wert 3 als konstanten Parameter erhält und einen int-Wert zurück gibt. Das volatile ergibt dabei m.E. nicht viel Sinn.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 14.11.2009 um 21:23 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
14.11.2009, 21:39 Uhr
~Sne11ius
Gast


Durch

C++:
volatile int repeat(3);


wird eine Variable vom Typ int deklariert und sofort mit 3 initialisiert. Das macht man mit Objekten dauernd, aber es geht auch mit allen Standarddatentypen - man ruft quasi den 'Konstruktor' von int auf...


Zitat von Hans:

Das volatile ergibt dabei m.E. nicht viel Sinn.
Hans


Da könntest du trotzdem recht haben, es ändert aber nichts an meinem Problem - es besteht mit oder ohne 'volatile'

Vielen Dank schonmal für die Antwort.

Snellius
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
14.11.2009, 21:44 Uhr
0xdeadbeef
Gott
(Operator)


Ne, das ist eine zwar etwas ungewöhnlich geschriebene, aber gültige Variablendefinition. volatile ist notwendig, um die Variable im Speicher zu halten - sonst erzeugt longjmp sehr schnell undefiniertes Verhalten.

Zwei(einhalb) Probleme sehe ich: Erstens setzt INT_Handler den SIGINT-Handler nicht neu, zweitens benutzt du setjmp und longjmp statt sigsetjmp und siglongjmp - bei ersteren ist in POSIX nicht definiert, ob sie den Signal-Kontext speichern, und sie sind deshalb zur Signalbehandlung denkbar ungeeignet. Zweieinhalbtens ist getchar() in INT_Handler nicht die beste Wahl zum Auslesen der Auswahl, weil du dabei mit ziemlicher Sicherheit mindestens ein Newline-Zeichen aus dem Stream fischen wirst.

Ansonsten solltest du in C++ mit longjmp und exit äußerst vorsichtig sein - sie sind ein großartiger Weg, sich den Stack zu zerhauen.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
14.11.2009, 22:07 Uhr
~Sne11ius
Gast


Hi!

Hab die Verbesserungen direkt eingebaut und jetzt funktioniert es wie geplant. sigsetjmp & siglongjmp haben den Pokal nach Hause geholt.
Und das getchar() mit dem Ja/Nein-Zeug schmeiss ich einfach auf den Müll, dann hab ich das Problem nicht mehr
Also alles in Butter.
Aber eins ist mir noch nicht ganz klar: warum muss man eigentlich den Signal-Handler neu setzen?

Viele Grüße & Dank:

Sne11ius
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
14.11.2009, 22:31 Uhr
0xdeadbeef
Gott
(Operator)


Das Verhalten an der Stelle ist im Standard nicht eindeutig definiert, aber einige Unices (und Linux) betrachten Signal-Handler als Einwegfunktionen - einmal benutzt, danach praktisch weggeschmissen. Auf beispielsweise BSD-Systemen wäre das nicht nötig, aber für portablen Code wirst du dir die Mühe machen müssen.

Übrigens ist das ganze Unterfangen standardtechnisch betrachtet ziemlich wackelig.

Zitat von ISO/IEC 9899:1999 (C99) 7.14.1.1 (5):

If the signal occurs other than as the result of calling the abort or raise function, the
behavior is undefined if the signal handler refers to any object with static storage duration
other than by assigning a value to an object declared as volatile sig_atomic_t, or
the signal handler calls any function in the standard library other than the abort
function, the _Exit function, or the signal function with the first argument equal to
the signal number corresponding to the signal that caused the invocation of the handler.
Furthermore, if such a call to the signal function results in a SIG_ERR return, the
value of errno is indeterminate.


Ich müsste jetzt nachschlagen, was POSIX, BSD, SUS etc. darüber zu sagen haben, prinzipiell solltest du dich aber darauf einstellen, dass deine Möglichkeiten in einem Signal-Handler sehr beschränkt sind, zumindest, sofern du zuverlässigen Code schreiben willst.

Nachtrag: POSIX:2008 hat dazu noch eine Menge zu sagen, nachlesbar hier: www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04 - insbesondere Sektion 2.4.3.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 14.11.2009 um 22:51 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
14.11.2009, 22:51 Uhr
~Sne11ius
Gast



Zitat von 0xdeadbeef:

Nachtrag: POSIX:2004 hat dazu noch eine Menge zu sagen, nachlesbar hier: www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04 - insbesondere Sektion 2.4.3.


Vielen Dank, lese gerade darin. Kommentare kommen vll. später nach ein paar Experimenten.

Grüße: Sne11ius
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
14.11.2009, 22:51 Uhr
0xdeadbeef
Gott
(Operator)


Hab den Link gerade noch auf POSIX:2008 aktualisiert.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
14.11.2009, 23:29 Uhr
Hans
Library Walker
(Operator)


Hi,


Zitat von 0xdeadbeef:
Ne, das ist eine zwar etwas ungewöhnlich geschriebene, aber gültige Variablendefinition. volatile ist notwendig, um die Variable im Speicher zu halten - sonst erzeugt longjmp sehr schnell undefiniertes Verhalten.


das ist wirklich 'ne ungewöhnliche Definition! - Volatile hab ich mir bisher immer als nötigen Zusatz für Variablennamen, die Hardwareregister bezeichnen erklärt. Ansonsten hab noch nicht viel Aufschlussreiches dazu gefunden, - vor allem keine sinnvollen Beispiele, die nichts mit Registern zu tun haben.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
14.11.2009, 23:41 Uhr
0xdeadbeef
Gott
(Operator)


Äh...ich glaube, du meinst das register-Schlüsselwort.

volatile sagt im Wesentlichen, dass damit gerechnet werden muss, dass die Variable sich aus nicht sofort ersichtlichen Gründen mal ändern kann. Das bewirkt üblicherweise, dass der Compiler die Variable nicht als Registervariable behandeln kann und dass der Compiler Code, der die Variable benutzt, nicht in einer Form optimiert, die das außer Acht lässt. Siehe http://en.wikipedia.org/wiki/Volatile_variable
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: