C Language
Signaalbehandeling
Zoeken…
Syntaxis
- void (* signaal (int sig, void (* func) (int))) (int);
parameters
Parameter | Details |
---|---|
sig | Het signaal om de signaalhandler in te stellen op, een van SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV of een door de implementatie gedefinieerde waarde |
func | De signaalhandler, die een van de volgende is: SIG_DFL , voor de standaardhandler, SIG_IGN om het signaal te negeren, of een functiepointer met de handtekening void foo(int sig); . |
Opmerkingen
Het gebruik van signaalbehandelaars met alleen de garanties van de C-norm legt verschillende beperkingen op wat wel of niet kan worden gedaan in de door de gebruiker gedefinieerde signaalbehandelaar.
Als de door de gebruiker gedefinieerde functie terugkeert tijdens het gebruik van
SIGSEGV
,SIGFPE
,SIGILL
of een andere door de implementatie gedefinieerde hardware-interrupt, wordt het gedrag niet bepaald door de C-standaard. Dit komt omdat de interface van C geen middelen geeft om de defecte status te wijzigen (bijv. Na een deling door0
) en dus bij het retourneren van het programma exact dezelfde foutieve status heeft als voordat de hardware-onderbreking plaatsvond.Als de door de gebruiker gedefinieerde functie werd aangeroepen als resultaat van een oproep om
abort
teabort
of op teraise
, mag de signaalhandler niet opnieuwraise
.Signalen kunnen midden in elke bewerking aankomen, en daarom kan de ondeelbaarheid van bewerkingen in het algemeen niet worden gegarandeerd, noch werkt signaalverwerking goed met optimalisatie. Daarom moeten alle wijzigingen in gegevens in een signaalhandler variabelen zijn
- van het type
sig_atomic_t
(alle versies) of eensig_atomic_t
slot (sinds C11, optioneel) - die
volatile
gekwalificeerd zijn.
- van het type
Andere functies van de C-standaardbibliotheek zullen deze beperkingen meestal niet respecteren, omdat ze variabelen in de algemene status van het programma kunnen veranderen. De C-standaard biedt alleen garanties voor
abort
,_Exit
(sinds C99),quick_exit
(sinds C11),signal
(voor hetzelfde signaalnummer) en enkele atomaire bewerkingen (sinds C11).
Gedrag wordt niet gedefinieerd door de C-norm als een van de bovenstaande regels wordt overtreden. Platforms kunnen specifieke extensies hebben, maar deze zijn over het algemeen niet draagbaar buiten dat platform.
Gewoonlijk hebben systemen hun eigen lijst met functies die asynchroon signaalveilig zijn , dat wil zeggen met C-bibliotheekfuncties die kunnen worden gebruikt vanuit een signaalhandler. Bijvoorbeeld, vaak is
printf
een van deze functies.In het bijzonder definieert de C-norm niet veel over de interactie met zijn threads-interface (sinds C11) of platformspecifieke threadbibliotheken zoals POSIX-threads. Dergelijke platforms moeten zelf de interactie van dergelijke threadbibliotheken met signalen specificeren.
Signaalverwerking met "signal ()"
Signaalnummers kunnen synchroon zijn (zoals SIGSEGV
- segmentatiefout) wanneer ze worden geactiveerd door een storing in het programma zelf of asynchroon (zoals SIGINT
- interactieve aandacht) wanneer ze van buiten het programma worden gestart, bijvoorbeeld door een toetsdruk als Cntrl-C
.
De functie signal()
maakt deel uit van de ISO C-standaard en kan worden gebruikt om een functie toe te wijzen om een specifiek signaal af te handelen
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abort() */
#include <signal.h> /* signal() */
void handler_nonportable(int sig)
{
/* undefined behavior, maybe fine on specific platform */
printf("Catched: %d\n", sig);
/* abort is safe to call */
abort();
}
sig_atomic_t volatile finished = 0;
void handler(int sig)
{
switch (sig) {
/* hardware interrupts should not return */
case SIGSEGV:
case SIGFPE:
case SIGILL:
/* quick_exit is safe to call */
quick_exit(EXIT_FAILURE);
/* use _Exit in pre-C11 */
_Exit(EXIT_FAILURE);
default:
/* Reset the signal to the default handler,
so we will not be called again if things go
wrong on return. */
signal(sig, SIG_DFL);
/* let everybody know that we are finished */
finished = sig;
return;
}
}
int main(void)
{
/* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
if (signal(SIGSEGV, &handler) == SIG_ERR) {
perror("could not establish handler for SIGSEGV");
return EXIT_FAILURE;
}
/* Catch the SIGTERM signal, termination request */
if (signal(SIGTERM, &handler) == SIG_ERR) {
perror("could not establish handler for SIGTERM");
return EXIT_FAILURE;
}
/* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
signal(SIGINT, SIG_IGN);
/* Do something that takes some time here, and leaves
the time to terminate the program from the keyboard. */
/* Then: */
if (finished) {
fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
return EXIT_FAILURE;
}
/* Try to force a segmentation fault, and raise a SIGSEGV */
{
char* ptr = 0;
*ptr = 0;
}
/* This should never be executed */
return EXIT_SUCCESS;
}
Het gebruik van signal()
legt belangrijke beperkingen op wat u binnen de signaalhandlers mag doen, zie de opmerkingen voor meer informatie.
POSIX beveelt het gebruik van sigaction()
plaats van signal()
, vanwege het niet-gespecificeerde gedrag en aanzienlijke implementatievariaties. POSIX definieert ook veel meer signalen dan de ISO C-standaard, inclusief SIGUSR1
en SIGUSR2
, die door de programmeur voor elk doel vrij kunnen worden gebruikt.