[LINUX] Verarbeiten Sie Signale in C-Sprache

Einführung

Ich werde die Geschichte beschreiben, bis ich das Abbruch-Signal als Anfänger in der C-Sprache (Newcomer Training Level) behandle.

Ich wäre Ihnen dankbar, wenn Sie auf Punkte in der Beschreibung oder im Code hinweisen könnten.

Umgebung

Das Projekt verwendet Redhat Enterprise Linux 7, diesmal wird es jedoch in Cent OS 7 beschrieben.

Über Signale

Signale sind eine der Interprozesskommunikationen, die unter UNIX und Linux verwendet werden. Es ist schwer vorstellbar, wenn Sie es auf einen Blick hören, aber es wird verwendet, wenn Sie ein Programm oder einen Befehl auf dem Terminal stoppen oder ein bestimmtes Ereignis generieren möchten. Dies gilt auch für den Versuch, einen laufenden Befehl oder ein laufendes Programm mit ** Strg + C ** zu stoppen.

Es gibt zwei Arten von Signalen, die von Linux verarbeitet werden: ** Standardsignale ** und ** Echtzeitsignale **. Zusätzlich gibt es jeweils 32 Signale, was bedeutet, dass insgesamt 64 Signale vorhanden sind. Zu diesem Zeitpunkt werden den Standardsignalen die Nummern 1 bis 32 und den Echtzeitsignalen die Nummern 33 bis 64 zugewiesen. Ich denke, dass die Signale, die Sie oft über Linux hören, die Standardsignale ** SIGINT ** und ** SIGKILL ** sind.

Einzelheiten zu Signalen finden Sie unter Manpage von SIGNAL.

Dieses Mal möchte ich basierend auf ~~ SIGABRT ~~ SIGINT beschreiben.

Weitere Informationen zu ~~ SIGABRT finden Sie unter Manpage von ABORT. ~~

Tatsächlich Abbruch behandeln

Es gibt zwei Möglichkeiten, Signale in der Sprache C abzufangen: die Funktion "Signal" und die Funktion "Sigaction". Zunächst möchte ich mit "Signal" bestätigen.

Der tatsächlich geschriebene Code lautet wie folgt.

test_signal.c


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

volatile sig_atomic_t e_flag = 0;

void abrt_handler(int sig);

int main() {
  printf("start %s\n", __func__);

  if ( signal(SIGINT, abrt_handler) == SIG_ERR ) {
    exit(1);
  }

  while (!e_flag) {}

  printf("end %s\n", __func__);

  return 0;
}

void abrt_handler(int sig) {
  e_flag = 1;
}

Ausführungsergebnis


[root@ca035c198d1f work]# ./signal_test.o
start main
^Chandle signal : 2
end main

Das Folgende ist der NG-Code, bevor Sie Ihre Anzeige erhalten. Ich werde die Beschreibung als NG-Beispiel hinterlassen.

test_signal.c(NG)


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

jmp_buf buf;

void abrt_handler(int sig);

int main() {
  printf("start %s\n", __func__);

  // SIG_Stellen Sie den Griff von ABRT ein.
  //Wenn das Handle fehlschlägt, wird der Prozess beendet.
  if ( signal(SIGABRT, abrt_handler) == SIG_ERR ) {
    exit(1);
  }

  //Stellen Sie den Rückgabepunkt nach dem Signalgriff ein.
  //Verhindern Sie, dass der Abbruch nach der Rückkehr erneut aufgerufen wird.
  if ( setjmp(buf) == 0 ) {
    printf("publish abort\n");
    abort();
  }

  printf("end %s\n", __func__);

  return 0;
}

//Signalgrifffunktion
void abrt_handler(int sig) {
  printf("handle signal : %d\n", sig);
  //Nach dem Anzeigen der Nachricht kehrt sie zu setjmp zurück.
  longjmp(buf, 1);
}

Das Ausführungsergebnis ist wie folgt.

Ausführungsergebnis


[root@ca035c198d1f work]# ./signal_test.o
start main
publish abort
handle signal : 6
end main

Wie Sie im Code sehen können, ist es nicht so schwierig. Definieren Sie das Signal, das Sie in der Funktion signal verarbeiten möchten, und geben Sie die Funktion im zweiten Argument an. Auf diese Weise wird "abrt_handler" ausgeführt, wenn SIGABRT auftritt. Außerdem wird die generierte Signalnummer im ersten Argument eingegeben, wenn "abrt_handler" aufgerufen wird. Dieses Mal wird "6" eingegeben.

~~ Da wir dieses Mal einen Abbruch ausgeben, endet der Vorgang so, wie er ist, wenn Sie nach der Verarbeitung des Signals an denselben Ort zurückkehren. Daher verwenden wir "longjmp", um zu verhindern, dass der Prozess beendet wird, indem wir nicht denselben Ort durchlaufen. ~~

Nachtrag

Da Sie auf das im Signalhandler laufende longjmp hingewiesen haben, haben wir es korrigiert. In Bezug auf longjmp im Signalhandler enthält JPCERT CC die folgende Beschreibung.

Das Aufrufen der Funktion longjmp () aus dem Signalhandler heraus kann zu undefiniertem Verhalten führen und die Programmintegrität beeinträchtigen. Daher sollten weder longjmp () noch POSIX siglongjmp () aus dem Signalhandler heraus aufgerufen werden.

Ich habe festgestellt, dass der obige Code Signale verarbeiten kann, aber Signalbehandlungen mit der Funktion "Singal" werden nicht empfohlen. Wie auf der Manpage von SIGNAL erwähnt, heißt es, dass Sie das weniger tragbare "Signal" vermeiden und "Sigaction" verwenden sollten. Details finden Sie unter Manpage von SIGNAL.

Versuchen wir nun die Implementierung mit sigaction.

Der tatsächlich geschriebene Code lautet wie folgt.

sigaction_test.c


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

void abrt_handler(int sig, siginfo_t *info, void *ctx);
volatile sig_atomic_t eflag = 0;

int main() {
  printf("start %s\n", __func__);

  struct sigaction sa_sigabrt;
  memset(&sa_sigabrt, 0, sizeof(sa_sigabrt));
  sa_sigabrt.sa_sigaction = abrt_handler;
  sa_sigabrt.sa_flags = SA_SIGINFO;

  if ( sigaction(SIGINT, &sa_sigabrt, NULL) < 0 ) {
    exit(1);
  }

  while ( !eflag ) {}

  printf("end %s\n", __func__);
  return 0;
}

void abrt_handler(int sig, siginfo_t *info, void *ctx) {
  // siginfo_Es wird von printf angezeigt, um zu überprüfen, ob der Wert von t erfasst wurde.
  //Ursprünglich ist printf nicht asynchron sicher und sollte hier nicht verwendet werden.
  printf("si_signo:%d\nsi_code:%d\n", info->si_signo, info->si_code);
  printf("si_pid:%d\nsi_uid:%d\n", (int)info->si_pid, (int)info->si_uid);
  eflag = 1;
}

Das Ausführungsergebnis ist wie folgt.

Ausführungsergebnis


[root@ca035c198d1f work]# ./sigaction_test.o
start main
^Csi_signo:2
si_code:128
si_pid:0
si_uid:0
end main

Das Folgende ist der NG-Code, bevor Sie Ihre Anzeige erhalten. Ich werde die Beschreibung als NG-Beispiel hinterlassen.

sigaction_test.c(NG)


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

jmp_buf buf;

void abrt_handler(int sig, siginfo_t *info, void *ctx);

int main() {
  printf("start %s\n", __func__);

  //Einstellungen für die Sigaction
  struct sigaction sa_sigabrt;
  memset(&sa_sigabrt, 0, sizeof(sa_sigabrt));
  sa_sigabrt.sa_sigaction = abrt_handler;
  sa_sigabrt.sa_flags = SA_SIGINFO;

  // SIG_Stellen Sie den Griff von ABRT ein.
  //Wenn das Handle fehlschlägt, wird der Prozess beendet.
  if ( sigaction(SIGABRT, &sa_sigabrt, NULL) < 0 ) {
    exit(1);
  }

  //Stellen Sie den Rückgabepunkt nach dem Signalgriff ein.
  //Verhindern Sie, dass der Abbruch nach der Rückkehr erneut aufgerufen wird.
  if ( setjmp(buf) == 0 ) {
    printf("publish abort\n");
    abort();
  }

  printf("end %s\n", __func__);
  return 0;
}

void abrt_handler(int sig, siginfo_t *info, void *ctx) {
  printf("si_signo:%d\nsi_code:%d\n", info->si_signo, info->si_code);
  printf("si_pid:%d\nsi_uid:%d\n", (int)info->si_pid, (int)info->si_uid);
  //Nach dem Anzeigen der Nachricht kehrt sie zu setjmp zurück.
  longjmp(buf, 1);
}

Das Ausführungsergebnis ist wie folgt.

Ausführungsergebnis


[root@ca035c198d1f work]# start main
publish abort
si_signo:6
si_code:-6
si_pid:79
si_uid:0
end main
^C
[1]+  Done                    ./sigaction_test.o

Wie Sie im Code sehen können, wird er häufiger als die Funktion "Signal" eingestellt. Für sigaction werden die zum Zeitpunkt der Behandlung auszuführende Funktion und sa_flags gesetzt. Die Funktionseinstellungen sind ungefähr die gleichen wie "Signal", aber "sa_flags" kann auf verschiedene Werte eingestellt werden. Dieses Mal habe ich "SA_SIGINFO" eingestellt, damit ich die Informationen erhalten kann, wenn das Signal gesendet wurde.

Ich denke, dass sich das Argument der Funktion, die zum Zeitpunkt des Signalhandles ausgeführt werden soll, von dem zum Zeitpunkt des "Signals" unterscheidet. Dieses Mal setzen wir "SA_SIGINFO" auf "sa_flags", also wird "siginfo_t", das die Informationen speichert, das Argument sein. Zum Zeitpunkt der Bearbeitung können Sie sehen, dass die Prozess-ID zum Zeitpunkt der Ausführung von * info von siginfo_t abgerufen werden kann.

Es gibt auch "ctx", aber diesmal habe ich es noch nicht untersucht.

Zusammenfassung

Es war rau, aber jetzt kann ich mit dem Signal umgehen. Dieses Mal machen wir es nur für den Abbruch, aber wir können das gleiche für andere Signale tun.

In Bezug auf den diesmal beschriebenen Inhalt bin ich ehrlich gesagt nicht sicher, wie das Signal aussehen soll. Wenn Sie also Vorschläge oder Ratschläge haben, wie ich dies schreibe, lassen Sie es mich bitte wissen.

Recommended Posts

Verarbeiten Sie Signale in C-Sprache
Greifen Sie auf MongoDB in C zu
Weiter Python in C-Sprache
Markdown mit Python behandeln
C-API in Python 3
Erweitern Sie Python in C ++ (Boost.NumPy)
Einbettung der Maschinensprache in die Sprache C.
Behandeln Sie Konstanten in Django-Vorlagen
Heap-Sortierung in C-Sprache
Verwenden Sie reguläre Ausdrücke in C.
Behandeln Sie Umgebungsvariablen in Python
Nachahmung von Pythons Numpy in C #
Binäre Suche in Python / C ++
Minimaler Gesamtflächenbaum in C #
Behandeln Sie komplexe Zahlen in Python
Signale in Java erkennen und verarbeiten.
Umgang mit Sitzungen in SQLAlchemy
Schreiben Sie einen tabellengesteuerten Test in C.
Modultest mit mehreren Instanzen in C-Sprache
Realisieren Sie die Schnittstellenklasse in der Sprache C.
ABC166 in Python A ~ C Problem
Behandeln Sie Daten in Linux-Bash-Befehlen
Behandeln Sie Posix-Nachrichtenwarteschlangen in Python
Behandeln Sie Daten im NetCDF-Format mit Python
Behandeln Sie das GDS II-Format mit Python
Behandeln Sie Anfragen in einem separaten Prozess
Beim Lesen der C ++ - Struktur mit Cython
Löse ABC036 A ~ C mit Python
So verpacken Sie C in Python
Löse ABC037 A ~ C mit Python
Segfo mit 16 Zeichen in C-Sprache
Schreiben Sie einen C-Sprach-Unit-Test in Python
Umgang mit Japanisch mit Python
Behandeln Sie mehrere Python-Versionen in einem Jupyter
Linkliste (list_head / queue) in C-Sprache
Löse ABC175 A, B, C mit Python
Algorithmus in Python (ABC 146 C Dichotomie
Implementieren Sie einen Teil des Prozesses in C ++
Implementieren Sie den FIR-Filter in Python und C.
Verwendung von Google Test in C-Sprache
Beispielskript zum Überfüllen von Signalen in Python
Schreiben Sie die O_SYNC-Datei in C und Python
Schriftliche Auswahlsortierung in C.
Umgang mit aufeinanderfolgenden Werten in MySQL
Generieren Sie mit Python eine C-Sprache aus dem S-Ausdruck
Verwenden Sie libxlsxwriter, um xlsx-Dateien in C ++ zu exportieren.
Führen Sie Python in C ++ unter Visual Studio 2017 aus
Kommunizieren Sie mit I2C-Geräten unter Linux C.