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.
Das Projekt verwendet Redhat Enterprise Linux 7, diesmal wird es jedoch in Cent OS 7 beschrieben.
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. ~~
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. ~~
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.
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