Signaler i linux. Exempel. Skickar signaler från tangentbordet. Signaler och systemsamtal

Innehållsserie:

I moderna operativsystem finns konceptet interprocesskommunikation (Inter-Process Communication - IPC) - detta är en uppsättning sätt att utbyta data mellan processer och/eller trådar. Signaler är ett av sådana utbytesmetoder. Konceptet med signaler stöds av de flesta operativsystem, men till exempel Windows har inte dem. fullt stöd för användning som en av IPC-metoderna - i sådana operativsystem implementeras signaler endast i C-standardbiblioteket.

Begreppet signaler

Signalerna är kapabla till slumpmässig tid(asynkront) avbryta processen för att hantera någon händelse. En process kan avbrytas av en signal som initieras av en annan process eller kärnan. Kärnan använder signaler för att meddela processer om olika händelser, såsom avslutande av en underordnad process.

Signaler har en definierad livscykel. Först skapas signalen - skickas av processen eller genereras av kärnan. Signalen väntar sedan på leverans till mottagningsprocessen. Det är allmänt accepterat att väntetiden för en signal är lika med tidsintervallet mellan skapandet av en signal och åtgärden som denna signal sänder. I slutet livscykel signalen fångas upp (ta emot) av processen och de åtgärder som är associerade med signalen utförs.

Enkla signaler och pålitliga signaler

Det finns en uppdelning av signaler i enkla och pålitliga.

Inledningsvis utvecklades och användes enkla (otillförlitliga) signaler. Genom sin funktionsprincip liknar de den kanoniska mekanismen för bearbetning av hårdvaruavbrott i processorn. Om en process vill hantera en viss signal på ett speciellt sätt, berättar den för kärnan om det genom att ange speciell funktion– signalhanterare. När en signal levereras till en process, anropar kärnan signalhanteraren så snart som möjligt, vilket avslutar processen. När hanteraren avslutas fortsätter processen exekveringen från den punkt där den avbröts.

Istället för att skriva din egen hanterarfunktion kan du helt enkelt tala om för kärnan att signalen orsakar dess standardåtgärd, eller att signalen helt enkelt ignoreras.

Hela det här konceptet med att arbeta med signaler ser tillräckligt bra ut, så länge signalen inte kommer till processen vid en tidpunkt då den redan är upptagen med att bearbeta en annan signal. Det är här problemen dyker upp - en återanropad signalhanterare kan förstöra de delade resurserna ( allmänna strukturer data och variabler) som den använder. Dessutom vid ankomsten ett stort antal signaler kan processstacken växa i det oändliga, vilket kan leda till programfel.

I processen att lösa problemet utvecklades tillförlitliga signaler, som är standardiserade i POSIX och används än idag. Längre fram i artikeln övervägs tillförlitliga signaler.

Signaler och systemsamtal

En signal kan komma till en process medan processen är inne i något systemanrop, som att vänta på input i read(). I det här fallet kan utvecklingen av händelser gå på följande sätt: applikationen försöker inte fånga upp signalen och avbryts av kärnan (till exempel ankomsten av SIGTERM-signalen) - då förblir terminalen i en icke-standardiserad konfiguration, vilket kan hindra användarens arbete. Naturligtvis är det möjligt att fånga en signal, rensa terminalen i en signalhanterare och sedan avsluta, men det är svårt nog att skriva en signalhanterare som vet vad programmet gjorde vid tidpunkten för avbrottet för att bestämma om man ska rensa terminalen eller inte.

För tillfället pågår en implementering av signaler som är fri från dessa brister. Lösningen är att endast sätta en flagga i signalhanteraren för att indikera att signalen togs emot, och sedan se till att systemanropet återkommer med en felkod som indikerar att samtalet avbröts av signalen. Därefter bör programmet kontrollera flaggan som satts av signalhanteraren och köra lämpliga åtgärder, till exempel, rensa terminalen och avsluta.

Den moderna implementeringen av signaler tvingar långsamma systemsamtal returnera en EINTR-felkod när de avbryts av en inkommande signal. Snabba systemanrop måste slutföras innan signalen levereras. Ett långsamt systemanrop är ett systemanrop som kräver obestämt belopp tid att slutföra, till exempel read(), wait(), write(). Alla systemanrop som är beroende av oförutsägbara resurser som mänskliga handlingar, nätverksdata etc. är långsamma. Naturligtvis är alla andra systemsamtal snabba.

Normalt hanterar programmet EINTR-felkoden och, om inget allvarligt har hänt, startar om systemanropet. De flesta Unix-liknande operativsystem gör för närvarande detta som standard - du behöver bara hantera signalen i en hanterare och systemanropet kommer att startas om automatiskt. På Linux startas inte systemanrop om som standard, men för varje signal kan en process ställa in en flagga för att tala om för systemet att starta om långsamma systemanrop som avbryts av den signalen.

Skickar signaler

Att skicka signaler från en process till en annan görs vanligtvis med systemanropet kill(). Dess första parameter är PID för processen till vilken signalen skickas; den andra parametern är signalnumret. Om vi ​​vill skicka en SIGTERM-signal till en process med PID 6666 använder vi systemanropet kill() så här:

kill(6666, SIGTERM);

Istället för positivt PID-värden du kan skicka ett samtal lika i modulo, men negativ betydelse. Då kommer signalen att skickas till alla processer från gruppen med ett tal lika med modulen för den överförda PID "a. Om PID är 0, så skickas signalen till alla processer från gruppen som den aktuella processen tillhör. Dessa funktioner används främst av skal för att kontrollera jobb.

Om värdet -1 skickas som PID till kill () systemanropet kommer signalen att skickas till alla processer utom init "a. Denna möjlighet används för att stänga av systemet.

Mer detaljerad information på kill() systemanropet ges i man 2 kill.

En process kan skicka en signal till sig själv med hjälp av systemet raise() anrop, som tar en parameter, signalnumret. Exempel:

höja(SIGTERM);

Naturligtvis returnerar vart och ett av de övervägda systemanropen noll vid framgång och ett värde som inte är noll om något fel inträffade.

Avlyssning av signaler

Alla POSIX-kompatibla program registrerar sina signalhanterare med sigaction()-systemanropet. Detta systemanrop har tre parametrar: den första - int signum - numret på signalen som ska fångas upp. Den andra är struct sigaction * act - en pekare till en struktur som beskriver reglerna för att installera hanteraren. Den tredje parametern - struct sigaction * oact - tar redan fastställda regler signalhanterare. Antingen den andra eller tredje (men inte båda!) parametern kan ställas in på NULL om det behövs.

Struktursigaktionsstrukturen har följande beskrivning:

struct sigaction ( __sighandler_t sa_handler; sigset_t sa_mask; int sa_flags; );

sa_handler är en pekare till en signalhanterare, och hanteraren måste deklareras enligt följande:

void signal_handler(int signo);

där den enda parametern är numret på signalen som kom in i hanteraren. sa_handler kan också vara lika med SIG_IGN - signalen ignoreras av processen, och SIG_DFL - signalen orsakar en standardåtgärd, såsom att avsluta processen.

sa_mask är en uppsättning signaler som måste blockeras när signalhanteraren som anges i samma struktur anropas. Hur man installerar dem diskuteras nedan.

Alternativet sa_flags tillåter en process att modifiera signalens beteende. Parametern kan endast ta fyra värden, som dock kan kombineras med den bitvisa "ELLER"-operationen:

  1. SA_NOCLDSTOP Skicka SIGCHLD-signalen endast om den underordnade processen avbryts. Att avbryta en underordnad process leder inte till att en signal skickas.
  2. SA_NODEFER - emulering av enkla (otillförlitliga) signaler.
  3. SA_RESTHAND - efter att en signal anländer återställs dess hanterare till SIG_DFL.
  4. SA_RESTART - Starta om systemanropet efter att ha återvänt från en signalhanterare. Om flaggan inte är inställd returnerar systemanropet ett EINTR-fel.

Som vanligt returnerar sigaction() 0 vid framgång och ett negativt värde vid fel.

Processsignalmask

Lägga till signaler till sigset_t sa_mask-strukturen, rensa den, etc. implementeras med hjälp av uppsättningen funktioner sigemptyset(), sigfillset(), sigaddset(), sigdelset(). De två första funktionerna tar en parameter, en pekare till en sigset_t-struktur. Dessa funktioner rensar och fyller med allt möjliga signaler sigset_t struktur, respektive.

De två sista funktionerna lägger till respektive tar bort en specifik signal från strukturen och har två parametrar vardera. Deras första parameter är en pekare till en sigset_t-struktur, och deras andra parameter är signalnumret.

Alla ovanstående funktioner returnerar 0 vid framgång och ett nummer som inte är noll vid fel.

Dessutom finns det en annan funktion som kontrollerar om den angivna signalen finns i den angivna uppsättningen - sigismember(). Dess parametrar är desamma som för sigaddset(). Funktionen returnerar 1 om signalen finns i mängden, 0 om den inte är det, och ett negativt tal- när ett fel uppstår.

Vi kan bland annat specificera en lista över signaler, vars leverans till processen kommer att blockeras. Detta görs med hjälp av funktionen sigprocmask(int how, const sigset_t * set, sigset_t * oldset).

Dess första parameter beskriver vad som bör göras:

  1. SIG_BLOCK - signaler från uppsättningen är blockerade;
  2. SIG_UNBLOCK - signaler från uppsättningen är avblockerade;
  3. SIG_SETMASK - signaler från uppsättningen blockeras, resten avblockeras.

Den andra parametern är en pekare till samma uppsättning, vars signaler blockeras/avblockeras. Om det är NULL, ignoreras värdet på den första parametern av systemanropet.

Den tredje parametern är en pekare till signalmasken som redan används; den kan ställas in på NULL om denna data inte behövs.

För att få en lista över väntande signaler kan du använda sigpending()-funktionen, som tar en enda parameter - en pekare till sigset_t-strukturen, där uppsättningen av väntande signaler kommer att skrivas.

Principer för skrivsignalhanterare

En av de viktigaste reglerna för skrivsignalhanterare är att hanteraren måste vara återinträdande; den måste låta sig anropas igen när processen redan är i hanteraren. Man måste se till att signalhanteraren inte använder globala datastrukturer eller långsamma systemanrop. Om det tyvärr är omöjligt att undvika detta, är det värt att ta hand om skyddet mot upprepade anrop från hanteraren när du arbetar med en datastruktur eller med ett systemanrop. Detta kan uppnås genom att tillfälligt blockera leveransen av signalen vars hanterare för närvarande körs, med hjälp av sigprocmask()-systemanropet. Vi har till exempel en hanterare SIGCHLD-signal, blockerar vi i den så här:

void chld_handler(int signum) ( sigset_t set; if (sigemptyset(&set)) (retur;) if (sigaddset(&set, SIGCHLD)) (retur; ) if (sigprocmask(SIG_BLOCK, &set, NULL)) (retur; ) / * gör något viktigt här */ if (sigprocmask(SIG_UNBLOCK, &set, NULL)) (retur; ) return; )

Utöver allt ovan antas det att hanteraren ska vara så enkel som möjligt - helst ska den sätta en viss flagga och sluta, och huvuddelen av programmet ska göra resten.

Slutsats

Ovanstående material är grundläggande för att förstå begreppet signaler. I princip borde det räcka för att du börjar använda signaler i dina program.

I slutet av cykeln kommer vi att prata om hur man tar emot (och skickar) ytterligare data om signalen, om du saknar den vanliga informationen om att signalen kom från någonstans i din process.

Ladda ner resurser

static.content.url=http://www.website/developerworks/js/artrating/

Artikel-ID=495997

ArticleTitle=Arbeta med signaler på Linux: Del 1: Signalgrunderna

Signaler är mjukvaruavbrott. De används för kommunikation mellan processer i UNIX och UNIX-liknande operativsystem som Linux, Mac OS.

Signaler har använts sedan Bell Labs UNIX på 1970-talet och är nu formellt definierade av POSIX-standarden. När en signal kommer till processen, operativ system avbryter det normala flödet av processexekvering och ger meddelande.

Det spelar ingen roll vilket operativsystem du använder, du kommer säkert att uppleva att dina appar blockeras och vägrar att fungera korrekt. På Unix, Linux finns det ett "kill"-kommando som du kan använda för att döda en process omedelbart, men inte bara det, utan jag ska prata om det lite senare. I den här artikeln "Kill command in Unix/Linux" kommer jag att berätta och visa vidare färdiga exempel olika kommandon för döda verktyg.

döda kommandon och signaler

När du utfärdar kommandot "döda" skickar du faktiskt en signal till systemet och instruerar det att avsluta den felaktiga applikationsroboten. Det finns totalt 60 signaler som kan användas, men allt du egentligen behöver veta är SIGTERM(15) och SIGKILL(9).

Du kan se alla signaler med kommandot:

# döda -l

På min macOS:

Jag kommer att försöka prata om alla signaler, men i början, låt oss bara prata om de viktigaste och mest använda.

Grundläggande signaler

Följande signaler är en del av POSIX-standarden. Varje signal är ett makro definierat i Systemhuvudfil. De förkortas vanligtvis utan deras SIG-prefix; till exempel kallas SIGHUP ofta helt enkelt som HUP.

SIGTERM– Denna signal begär att en process som körs avslutas. Denna signal kan ignoreras. Processen får tid att stängas av ordentligt. När ett program stängs av bra betyder det att det har fått tid att spara sina framsteg och frigöra resurser. Med andra ord, han "tvingade" inte att avsluta processen.

SIGKILL SIGKILL-signalen gör att processen slutar utföra sitt arbete omedelbart. Programmet kan inte ignorera denna signal. Osparade framsteg kommer att gå förlorade.

Syntax för "döda".

Kommandosyntaxen är:

# döda PID(s)

# döda [-s] [-l] %pid

Standardsignalen (om inte specificerad) är SIGTERM. När denna signal inte hjälper och inte fungerar kan du använda följande alternativ för "döda" för att tvinga processen att avslutas:

# döda SIGKILL PID

# döda -9 PID

där "-9" är flaggan för SIGKILL-signalen.

Om du inte vet vilken applikations-PID du ska använda för att bli av med, kör sedan kommandot:

$ ps -aux

Och om du vet specifik tillämpning(till exempel apache), då kan du filtrera bort det onödiga och visa alla processer för denna tjänst:

$ ps -aux | grep apache

Och det kommer att visa allt kör applikationer tillsammans med dess PID(er).

Till exempel, för att döda ett program, kör jag följande kommando:

# döda -9 3629

Det är också värt att notera att du kan köra flera processer samtidigt så att de kan "dödas":

# kill -9 PID1 PID2 PID 3

Ladda om konfigurationsfiler eller starta om verktyg:

# kill -1 number_of_PID

Särskilt användbara signaler inkluderar HUP, INT, kill, STOP, CONT och 0.

Alternativen är:

-s signal_name
Det symboliska namnet på en signal som specificerar signalen att skicka en icke-standardsignal till.

-l
Om operand inte anges, visa signalnamn; I annat, skriv namnet på signalen som motsvarar exit_status.

-signalnamn
Det symboliska namnet på en signal som anger signalen som ska skickas till TERM som standard.

-signal_nummer
Ett icke-negativt decimalt heltal som anger signalen som ska skickas till TERM som standard.

Följande PID är av särskild betydelse:
-1 Om superanvändare, sänd sedan signalen till alla processer; annars sänds till alla processer som tillhör-
för användaren.

Några av de mest använda signalerna är:

  • 1 HUP (lägg på) - lägg på.
  • 2 INT (avbryta) - avbryta.
  • 3 AVSLUTA (avsluta) - avsluta.
  • 6 ABRT (avbryt) - avbryter.
  • 9 DÖDA (icke-fångbart, icke-ignorerbart dödande)
  • 14 ALRM ( väckarklocka) - larm.
  • 15 TERM (programvaruavslutningssignal)

PKill

Kommandot "pkill" låter dig använda utökade reguljära uttrycksmönster och andra matchningskriterier. Istället för att använda PID kan du nu döda applikationen genom att ange processnamnet. Till exempel, för att döda webbläsaren Firefox, kör helt enkelt kommandot:

#pkillFirefox

För det matchar mönstret vanligt uttryck, kan du också ange en del av processnamnet, till exempel:

#pkillfire

För att undvika att "döda" fel processer kan du göra "pgrep -l [processname]" till listan över lämpliga processer.

Kommandot pkill har många fler alternativ, till exempel, om du anger alternativet "-u", låter det dig ange ett användarnamn eller ID. I det här exemplet skickar vi TERM-signalen till alla processer som ägs av 'ingen'-användaren:

# pkill -u ingen

Döda alla

Killall använder processnamnet istället för PID, och det "dödar" alla processinstanser med samma namn. Till exempel om du använder flera instanser Firefox webbläsare, du kan döda dem alla med kommandot:

# killall firefox

I Gnome kan du starta om Nautilus med kommandot:

# killall nautilus

xkill

xkill är grafiskt"döda" applikationen. När du skriver "XKill" i terminalen blir muspekaren omedelbart ett "kors". Allt du behöver göra är att klicka på "kryss" på den kränkande appen så dödar den appen direkt. Om du är intresserad kan du lägga till en kortkommando för att aktivera XKill-funktionen.

Andra signaler som används

SIGABRT

Denna signal skickar en signal till processen att avbryta operationen. ABRT är vanligtvis riktad mot själva processen när den anropar abort()-funktionen i programmeringsspråket C för att signalera krascha, men den kan skickas från vilken process som helst precis som vilken annan signal som helst.

SIGALRM, SIGVTALRM och SIGPROF

En ALRM-, VTALRM- och/eller PROF-signal skickas till en process när den angivna tidsgränsen för att anropa en larmfunktion (t.ex. setitimer) löper ut.

ALRM

Skickas när den aktuella tiden eller klockan har passerat.

VTALRM

Skickas när CPU-tiden som används av processen har löpt ut.

PROF

Skickas när processortiden som används av processen och systemet på uppdrag av processen löper ut.

SIGBUS

En BUS-signal skickas till en process när den resulterar i ett bussfel. Tillstånd som resulterar i denna signal, såsom felaktig minnesåtkomstjustering eller saknad fysisk adress.

SIGCHLD

CHLD-signalen skickas till en process när en underordnad process avslutas, avbryts eller återupptas efter att ha avbrutits. En vanlig användning av en signal är att signalera operativsystemet att rensa upp resurser som används av en underordnad process efter att den har avslutats utan ett explicit systemanrop.

SIGCONT

CONT-signalen instruerar operativsystemet att starta om en process som tidigare avbröts av en STOP- eller TSTP-signal. En av viktiga funktioner denna signal är till för att styra driften av Unix-skalet.

SIGFPE

FPE-signalen skickas till en process när den utför en felaktig aritmetisk operation, såsom division med noll.

SIGHUP

HUP-signalen skickas till en process när dess styrande terminal är stängd. Det var ursprungligen utformat för att meddela en process efter ett successivt radavbrott (HUP ansvarig för "avbrott"). På moderna system betyder denna signal vanligtvis att den pseudo- eller virtuella terminalkontrollen har stängts.

SIGILL

ILL-signal skickas till en process när den försöker utföra skadliga, okända eller privilegierade kommandon (instruktioner).

SIGINT

INT-signalen skickas till en process från den styrande terminalen när användaren önskar avsluta processen. Detta initieras vanligtvis genom att trycka på Control-C, men på vissa system "radera" eller "bryta".

SIGKILL

DÖDA-signalen skickas till en process för att avslutas omedelbart. Till skillnad från SIGTERM och SIGINT kan denna signal inte fångas eller ignoreras, och mottagningsprocessen kan inte utföra någon rengöring efter att ha tagit emot denna signal.

SIGPIPE

PIPE-signalen skickas till en process när den försöker skriva till ett rör utan en process kopplad till den andra änden.

SIGQUIT

AVSLUTA-signalen skickas till en process från dess styrande terminal när användaren begär att processen ska dumpas.

SIGSEGV

SEGV-signalen skickas till en process när den gör en ogiltig referens virtuellt minne eller segmenteringsfel, det vill säga när det utför en segmenteringsöverträdelse.

SIGSTOPPA

STOPP-signalen talar om för operativsystemet att stoppa processen för att senare återupptas.

SIGTERM

TERM-signalen skickas till en process för att begära att den avslutas. Till skillnad från dödningssignalen kan den tolkas eller ignoreras av processen. Detta gör att processen kan utföra "trevlig" exekvering för att sluta frigöra resurser och spara tillstånd om det behövs. Det bör noteras att SIGINT är nästan identisk med SIGTERM.

SIGTSTP

En TSTP-signal skickas till dess styrande terminalprocess och uppmanar den att avbryta tillfälligt. Detta initieras vanligtvis av användaren genom att trycka på Control-Z. Till skillnad från SIGSTOP kan denna process registrera en signalhanterare eller ignorera en signal.

SIGTTIN och SIGTTOU

I TTIN och TTOU skickas signaler till en process när den försöker läsa respektive skriva från en (tty) terminal i bakgrunden. Som regel kan denna signal endast tas emot av processer under kontroll. arbetspanel; demoner har inga kontrollterminaler och bör aldrig ta emot denna signal.

SIGUSR1 och SIGUSR2

USR1- och USR2-signalerna skickas till en process och indikerar användardefinierade villkor.

SIGPOLL

POLL-signalen skickas till en process när en asynkron I/O-händelse inträffar.

SIGSYS

SYS-signalen skickas till en process när den skickar ett dåligt argument till ett systemanrop.

SIGTRAP

En TRAP-signal skickas till en process när ett tillstånd inträffar som felsökaren bad att bli informerad - till exempel när specifik funktion exekveras eller när ett visst värde på en variabel ändras.

SIGURG

En URG-signal skickas till en process när uttaget har brådskande eller utom räckviddsdata tillgänglig för läsning.

SIGXCPU

XCPU-signalen skickas till en process när den används CPU under en tid som överstiger ett visst inställt värde, ange användare. Ankomsten av XCPU-signalen säkerställer att processen snabbt sparar allt mellanresultat och avslutas långt innan det avslutar operativsystemet med en SIGKILL-signal.

SIGXFSZ

XFSZ-signalen skickas till en process när en fil växer sig större (större än det angivna värdet) än det maximalt tillåtna värdet.

SIGRTMIN till SIGRTMAX

RTMIN - RTMAX-signalerna är för specialanvändning. De är realtidssignaler.

Diverse signaler

Följande signaler är inte standardiserade av POSIX, men används ibland på vissa system.

SIGEMT

EMT-signalen skickas i processen när ett emulatoravbrott inträffar.

SIGINFO

INFO-signalen sänds i processen när en statusbegäran tas emot från den styrande terminalen.

SIGPWR

PWR-signalen skickas i processen när systemet råkar ut för ett strömavbrott.

SIGLOST

LOST-signalen skickas till en process när ett "fillås" tappas.

SIGWINCH

WINCH-signalen skickas till en process när dess styrande terminal ändrar storlek.

Skickar signaler från tangentbordet

Signaler kan skickas från tangentbordet. Några standardinställningar listas nedan. Standardgenvägarna för att skicka avbrottssignaler kan definieras med kommandot stty.

CTRL-C

Skicka SIGINT (avbryt). Som standard gör detta att processen avslutas.

CTRL-Z

Skicka SIGTSTP (Stäng av). Som standard gör detta att processen avbryter alla operationer.

CTRL-\

Skicka SIGQUIT (Avsluta). Som standard gör detta att processen avslutas omedelbart och återställer kärnan.

CTRL-T

Skicka SIGINFO (INFO). Som standard gör detta att operativsystemet visar information om kommandot. Stöds inte på alla system.

produktion

När applikationer inte beter sig och får systemet att frysa, är det mycket frestande att starta om datorn och starta om sessionen igen. Med dessa "döda"-kommandon kan du bättre hantera felbeteenden hos applikationer som orsakar eller kan orsaka en systemkrasch. Med detta avslutar jag det här ämnet"Dödkommandot i Unix/Linux".

Signaler är avbrottsbegäranden som implementeras på processnivå. Över trettio identifierade olika signaler och de hittar en mängd olika användningsområden.

  • Signaler kan skickas mellan processer som ett kommunikationsmedel.
  • Signaler kan skickas av terminaldrivrutinen för att avbryta eller avbryta processer när användaren trycker speciella kombinationer nycklar som t.ex eller .
  • Signaler kan skickas för en mängd olika ändamål av användaren eller administratören med hjälp av kommandot kill.
  • Signaler kan skickas av kärnan när en process exekverar en olaglig instruktion, som att dividera med noll.
  • Signaler kan skickas av kärnan för att meddela en process om en "intressant" händelse, såsom avslutandet av en underordnad process eller tillgängligheten av data i en I/O-kanal.
  • En minnesdump är en fil som innehåller en bild av en processs minne. Den kan användas för felsökning.
Funktionerna förknippade med dessa tangentkombinationer kan tilldelas andra tangenter med hjälp av kommandot stty, men i praktiken är detta mycket sällsynt. Vi antar att dessa nycklar har sina standardfunktioner kopplade till dem. När en signal kommer fram är ett av två scenarier möjligt. Om en process har tilldelat en bearbetningsrutin till en signal, förses den med information om det sammanhang i vilket signalen genererades när den anropas. Annars utför kärnan standardåtgärderna på uppdrag av processen. Dessa åtgärder beror på signalen. Många signaler gör att processen avslutas, och i vissa fall genereras även en minnesdump. Proceduren för att anropa hanteraren kallas signalavlyssning. När hanteraren avslutas återupptas processen från den punkt där signalen togs emot. För att vissa signaler inte ska komma in i programmet måste du ställa in dem på att ignorera eller blockera. En ignorerad signal skickas helt enkelt igenom och påverkar inte processens funktion. Den blockerade signalen ställs i kö för bearbetning, men kärnan kräver inte att processen vidtar någon åtgärd förrän signalen explicit har avblockerats. Hanteraren anropas för en olåst signal endast en gång, även om flera liknande signaler tas emot under spärrperioden. Följande är signaler som bör vara kända för alla systemadministratör. Traditionellt skrivs signalnamn stora bokstäver. Ibland föregår namnen SIG (till exempel SIGHUP). namn Beskrivning Reaktion Intercepts - Blocks - Default Dump 1 HUP Release Uppsägning Ja Ja Nej 2 INT Avbrott Uppsägning Ja Ja Nej 3 AVSLUTA Exit Uppsägning Ja Ja Ja 9 KILL Uppsägning Uppsägning Nej Nej Nej 10 BUS Fel Uppsägning Ja Ja Ja 11 SEGV Segmentering Fel Uppsägning Ja Ja Ja 12 TERM Uppsägning Begäran slut Ja Ja Nej 13 STOPP Stopp Stopp Nej Nej Nej 14 TSTP Stoppsignal skickad av Stopp Ja Ja Nej från tangentbordet 15 FORTS Fortsätt efter stopp Ignorerad Ja Nej Nej 16 VINCH Ändra fönster Ignorerad Ja Ja Nej 17 USR1 Användardefinierad Slut Ja Ja Nej 18 USR2 Användardefinierad Uppsägning Ja Ja Nej Det finns andra signaler som inte visas i tabellen. 5,1; de flesta av dem rapporterar alla möjliga kryptiska fel, som "ogiltig instruktion". Som standard avslutar sådana signaler vanligtvis programmet och genererar en minnesdump. Avlyssning och blockering av signaler är vanligtvis tillåtet, eftersom det finns tillräckligt "smarta" program som eliminerar konsekvenserna av fel. BUS- och segv-signalerna skickas också när fel uppstår. Vi har tagit med dem i tabellen eftersom de är extremt vanliga: de orsakar vanligtvis program att krascha. Dessa signaler har i sig inget diagnostiskt värde. De indikerar bara faktumet av felaktig åtkomst till minnet6. KILL- och STOP-signalerna kan inte fångas upp, blockeras eller ignoreras. KILL-signalen dödar processen till vilken den skickas, medan STOP-signalen avbryter processen tills CONT-signalen tas emot. CONT-signalen kan fångas upp och ignoreras, men kan inte blockeras. tstp-signalen är en mer "flexibel" version av STOP-signalen. Det enklaste sättet att beskriva det är som en begäran att sluta. Den genereras av terminaldrivrutinen när användaren trycker på en tangentkombination . Program som fångar denna signal utför vanligtvis saneringsoperationer och skickar sedan en STOPP-signal till sig själva. Å andra sidan kan program ignorera TSTP-signalen så att de inte kan stoppas av ett tangentbordskommando. Terminalemulatorer skickar WINCH-signalen när deras konfigurationsparametrar (som antalet linjer på en virtuell terminal) ändras. Detta tillåter program som interagerar med emulatorer som t.ex textredigerare, automatiskt omkonfigurera sig själv som svar på ändringar. Om fönstret inte kan ändras korrekt, kontrollera att WINCH-signalen genereras och hanteras korrekt. Även om syftet med KILL, INT, TERM, HUP och QUIT-signalerna kan verka likadana, är de faktiskt ganska olika.
  • KILL-signalen är icke-blockerande och gör att processen avslutas ovillkorligt på kärnnivån. Faktum är att processen inte ens hinner ta emot denna signal.
  • INT-signalen skickas av terminalföraren när användaren trycker på en tangentkombination och fungerar som en begäran att slutföra den aktuella operationen. När den här signalen fångas måste enkla program avslutas eller låta standardsignalhanteraren förstöra sig själv. Program som har ett interaktivt kommandoradsläge bör avbryta den aktuella operationen, rensa upp och gå tillbaka till standbyläge.
  • TERM-signalen är en begäran om att avsluta programmet. Det antas att processen som tar emot denna signal städar upp och avslutas.
  • HUP-signalen har två vanliga tolkningar. För det första behandlar många demoner det som ett återställningskommando. Om demonen kan bevisa sin ära på nytt konfigurationsfil och anpassa sig till förändringar utan att starta om, låter HUP-signalen dig ändra dess beteende.
  • För det andra genereras denna signal ibland av terminaldrivrutinen när man försöker döda processer som är associerade med terminalen. I grund och botten har detta beteende bevarats sedan användningen av trådanslutningar terminaler och modem. Därav namnet "retreat".
  • Det brukar csh-familjen av tolkar (tcsh och andra) göra bakgrundsprocesser immuna mot HUP-signalen så att de kan fortsätta sitt arbete även när användaren loggar ut. Användare av sh-familjen av tolkar (ksh, bash, och så vidare) kan emulera detta beteende med nohup-kommandot.
  • QUIT-signalen liknar TERM-signalen, förutom att standardhanteraren dumpar minnet som standard.
USR1- och USR2-signalerna har ingen standardtilldelning. De kan användas för olika ändamål. Till exempel tolkar Apache-webbservern USR1-signalen som en begäran om omstart. Skickar signaler: kill-kommando Kill-kommandot används oftast för att döda processer. Detta kommando kan skicka vilken signal som helst till processen, men standard är TERM. Kill-kommandot kan köras av både vanliga användare (för deras egna processer) och superanvändare (för alla processer). Den har följande syntax: kill [-signal] identifierare, där signal är numret eller symboliskt namn på signalen som ska skickas, och identifierare är numret på processen som ska slås upp. Ett kill-kommando utan ett signalnummer garanterar inte att processen kommer att dödas, eftersom TERM-signalen kan fångas upp, blockeras och ignoreras. Kommando döda -9 identifierare"garanterat" att döda processen, eftersom signal nummer 9 (KILL) inte fångas upp. Använd bara kommandot kill -9 om en "artig" begäran om att avsluta programmet har misslyckats. Vi sätter ordet "garanterad" inom citattecken, eftersom processer ibland går in i ett tillstånd där de inte kan avslutas ens på detta sätt (vanligtvis beror detta på att till exempel I/O blockeras när de stoppas hårddisk). Den enda utvägen i den här situationen är att starta om. Killall-kommandot körs olika funktioner i UNIX-system och Linux. I Linux kommando killall dödar de processer som namnet ger. Till exempel dödar följande kommando alla processer Apache webbserver. ubuntu$ sudo killall httpd Standard UNIX- killall kommando, som tillhandahålls på Solaris-, HP-UX- och AIX-distributionerna, tar inga parametrar och dödar helt enkelt alla processer nuvarande användaren. Att köra det som superanvändare kommer att döda init-processen och stänga av datorn. Wow! kommandona pgrep och pkill solarissystem, HP-UX och Linux (men inte i AEX) letar efter processer som givna namn(eller andra attribut). Kommandot pgrep skriver ut ID:n för processer som matchar kriterierna som anges på kommandoraden, och kommandot pkill skickar en signal till de hittade processerna. Till exempel skickar följande kommando en TERM-signal till alla processer som körs som användaren ben. $ sudo pkill -u ben

Många Unix-program accepterar signaler som USR1 och USR2. Till exempel för att uppdatera körbar fil för Nginx on the fly skickar du kill -USR2 .

Jag förstår att USR1 är en "användardefinierad" signal, vilket betyder att den som skapat programmet kan använda det för att betyda "stäng av" eller "avlasta dina loggar" eller "skriv ut foo tusen gånger" eller vad som helst. Men jag förstår inte varför de måste använda detta godtyckliga namn. Varför inte döda -UPGRADE, eller döda -GRACEFUL_SHUTDOWN? Har Unix bara vissa signaler?

Medan vi håller på, använder Nginx också följande signaler (se dokumentation):

  • TERM, INT: snabb avstängning
  • SLUTA: graciös avstängning
  • HUP:
    • Starta om konfiguration
    • Starta nya arbetsflöden med ny konfiguration
    • Graciös avstängning av gamla arbetsprocesser
  • USR1: öppna loggfiler
  • USR2: uppdatera körbara filer i farten
  • VINSCH: avslutar graciöst arbetsflöden

HUP? Vinsch? Vad är anledningen till dessa namn? Var kan jag få reda på mer om detta?

6 svar

Signaler som är tillgängliga på operativsystemet definieras av operativsystemet (vanligtvis efter POSIX) - de är inte "strängar" utan heltalskonstanter med standardnamn. USR1 och USR2 är två signaler som inte har en specifik betydelse, avsedda för vilken godtycklig användning som helst som en utvecklare vill ha.

På din linux maskin läs man 7-signal för en översikt över signal- och signalhantering.

Du kan åsidosätta betydelsen av andra signaler, om du är redo att arbeta med operativsystemet, genom att utfärda dessa signaler som svar på händelser. Du kan till exempel göra att HUP betyder "ladda om konfiguration" - om du antingen är säker på att processen aldrig kommer att hänga (terminalförlust) eller om du är beredd att hantera fall där OS, inte användaren, skickar en HUP-signal .

HUP är inte lämplig att "hänga". Denna signal skickas till en process om dess styrande terminal når slutet av filen. Förr i tiden var manöverterminaler oftast kopplade till seriella portar, eventuellt via en modemlinje via telefonlinje. Om telefonanslutningen har vänts, lokalt modem kommer att sänka Carrier Detect-raden, vilket kommer att göra att kärnfilens slutföranderapport skickas, och överförd signal SIGHUP .

WINCH är inte lämplig för att "byta fönster". Den skickas till en process om dess styrande terminal ändrar storlek. Av uppenbara skäl är terminaler som kan ändra storlek vanligtvis pseudoterminaler som i slutändan representeras av en terminalemulator som körs i en fönstermiljö (som xterm).

Eftersom signalnamn är standardiserade (POSIX). Du kan skriva din egen körbara kill-typ för att ta -UPGRADE om du vill och leverera USR1-signalen, men standardkillen som följer med UNIX kommer inte att känna igen den.

Alternativt kan du skapa ett alias, en funktion eller ett skalskript för att göra översättningen åt dig, till exempel med ett bash-alias:

Alias ​​​​upgrade="kill -USR1"

Signal.h-huvudfilen mappar signalnamn till deras faktiska implementeringsberoende betydelser.

När det gäller WINCH anser jag detta som lite av en styggelse. Detta är signalen som levereras till applikationer när storleken på fönstret ändras (särskilt när deras styrande terminalfönster ändras).

Att använda detta för att graciöst stänga arbetartrådar är inte en bra idé om du inte kan garantera att processen aldrig kommer att köras i terminalen. Jag vet att det skulle vara mycket myt om jag körde en app och den bestämde sig för att avbryta allt arbete under flygning bara för att jag maximerade fönstret :-)

Testa kill -l och hitta svaret själv:

1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGUPE) SIGPIPE) 6FLIGST) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGCHLD 28) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 3SIMINIG) 4 2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+ SIGRTMIN+ 1146) 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-8-MAX) 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX

En signal eller virtuellt avbrott är ett meddelande som systemet skickar till en process, eller en process skickar till en annan. När en process tar emot en signal avbryts exekveringen av processprogrammet och kontrollen överförs till en subrutin (funktion) - signalhanteraren. Efter att signalhanteraren exekveras, återupptas exekveringen av det avbrutna programmet från den punkt vid vilken det avbröts.

Operativsystemet ger stort antal typer av signaler, men de flesta av dessa typer är reserverade för systemändamål - det är signaler som operativsystemet skickar till en process. Men det finns också signaler om att processer kan utbytas med varandra.

Som standard är reaktionen på de flesta signaler att avsluta processen som tog emot signalen, det vill säga om processen tar emot en signal som den inte har för avsikt att hantera, avslutas processen som tar emot signalen. Men för de flesta typer av signaler kan en process installera en hanterare given signal eller ställ in att ignorera denna signal.

Om processen är i ett "frivilligt" avstängt tillstånd (till exempel orsakat av att sömnsystemanropet utförs), då mottagningen av signalen "väcker processen från sömn", oavsett vilken signalhantering det var, avslutas sömnsystemanropet omedelbart.

Signalhanteraren i processen har formen av en funktion med en prototyp:

Tomhet funktionsnamn(int sigtype);

Parametern för denna funktion är signaltypen (samma hanterare kan ställas in för att hantera signaler av olika typer).

För att ställa in din egen signalhanterare, för att avbryta den eller för att ställa in signalen så att den ignoreras, använd signalsystemanropet

Signalhanterare funktioner är vanliga funktioner C, de har tillgång till alla globalt synliga variabler och funktioner. Men eftersom vi inte vet vid vilken tidpunkt i programexekveringen hanterarfunktionen kommer att kallas, måste vi vara särskilt försiktiga när vi kommer åt globala datastrukturer från denna funktion. För funktioner som bearbetar strömmar finns det en till viktigt krav- återinträde. Eftersom en signalhanterare kan anropas när som helst i programexekveringen (och under vissa förhållanden kan en annan signalhanterare anropas under behandlingen av en signal), måste hanterarna använda funktioner som uppfyller kravet på återinträde, det vill säga kan vara ringde vid den tidpunkt då de redan har blivit uppringda någon annanstans i programmet. Faktum är att kravet på återinträde beror på att funktionen inte använder några globala resurser utan att ta hand om att synkronisera åtkomsten till dessa resurser. Vissa I/O-funktioner, inklusive funktionen printf() är inte återkommande. Detta betyder att utmatningen av en printf()-funktion kan störa utmatningen av en annan funktion. Följande är en lista över återkommande funktioner som är säkra att anropa från signalhanterare.

Lista över återkommande funktioner

posix_trace_event()

timer_getoverrun()

En process kan skicka en signal till vilken annan process som helst vars PID den känner till genom att använda kill-systemanropet (trots dess formidabla namn dödar detta systemanrop inte nödvändigtvis processen som det är adresserat till). I vissa fall kan en process behöva skicka en signal till sig själv, detta kan göras med hjälp av höjningssystemet.

Vissa typer av signaler

Signaltyper identifieras med numeriska siffror, men programmering använder ofta symboliska signalnamn som definieras i systeminkluderande filer. Nedan är några av de mest använda signalnamnen:

Denna signal gör att processen som tog emot den avslutas. Detta är den enda signalen som inte kan ignoreras och som du inte kan tilldela en anpassad hanterare för.

Denna signal är en begäran om att avsluta processen. Utfärdandet av denna signal inkluderar till exempel kommandot (inte ett systemanrop!) kill . Processen som tog emot denna signal är tänkt att avslutas, men processen kan ställa in att signalen ska ignoreras eller tilldela sin egen hanterare till den.

Denna signal skickas av systemet till den överordnade processen när någon av dess underordnade processer avslutas. Standardsvaret på denna signal är ignorera. Den överordnade processen behöver inte bry sig om att hantera denna signal, såvida den inte vill använda den för att synkronisera dess exekvering med den underordnade processen.

Denna signal används för att räkna tidsintervall. En process kan ställa in ett tidsintervall med hjälp av larmet eller setitimersystemets anrop och efter specificerat intervall systemet kommer att skicka en SIGALRM-signal.

SIGUSR1 och SIGUSR2

Bakom dessa signaler finns inga reserverade systembokningar. Processer kan skicka dessa signaler till varandra och tolka dem som de tycker är lämpliga.

För mer information om typerna av signaler, se beskrivningen av funktionen