A jelfeldolgozás (signal processing) a számítástechnikában a folyamatközi kommunikáció egyik formája, amit a POSIX-szabványú operációs rendszerek alkalmaznak.

A jelek (signal) szabványosított üzenetek, amelyeket egy futó programnak küldenek, hogy adott viselkedést, például kilépést vagy hibakezelést indítsanak el. Ezek a folyamatok közötti kommunikáció (IPC) korlátozott formáját jelentik, amelyeket jellemzően Unix, Unix-szerű és más POSIX-kompatibilis operációs rendszerekben használnak.

A jel (szignál) egy aszinkron értesítés, amelyet egy folyamatnak vagy ugyanazon a folyamaton belüli adott szálnak (thread) küldenek, hogy értesítsék egy eseményről. A jelek gyakori felhasználási módjai egy folyamat megszakítása, felfüggesztése, leállítása vagy „megölése”. A jelek az 1970-es évekbeli Bell Labs Unixból származnak, majd később a POSIX szabványban is specifikálták őket.

Amikor egy jel elküldésre kerül, az operációs rendszer megszakítja a célfolyamat normál végrehajtási folyamatát a jel kézbesítése érdekében. A végrehajtás bármely nem atomi utasítás során megszakítható. Ha a folyamat korábban regisztrált egy jelkezelőt (signal handler), akkor az a rutin végrehajtódik. Ellenkező esetben az alapértelmezett jelkezelő kerül végrehajtásra.

A beágyazott programok hasznosnak találhatják a jeleket a folyamatok közötti kommunikációhoz, mivel a jelek algoritmikus hatékonyságukról ismertek.A számítástechnikában az algoritmikus hatékonyság az algoritmusok azon tulajdonsága, amely az általuk felhasznált számítási erőforrások mennyiségéhez kapcsolódik.

A jelek hasonlóak a megszakításokhoz, a különbség az, hogy a megszakításokat a CPU közvetíti és a kernel kezeli, míg a jeleket a kernel közvetíti (esetleg rendszerhívásokon keresztül) és az egyes folyamatok kezelik. A kernel átadhat egy megszakítást jelként annak a folyamatnak, amely azt okozta (tipikus példák a SIGSEGV, SIGBUS, SIGILL és SIGFPE).

Története Az Unix 1-es verziójában (1971) külön rendszerhívások voltak a megszakítások, kilépések és gépi csapdák elkapására. A kill a 2. verzióban (1972) jelent meg. A 4. verzió (1973) az összes csapdát egyetlen hívássá, jelzéssé egyesítette. Az 5-ös verzió (1974) tetszőleges jeleket küldhetett. A 7. verzióban (1979) minden számozott csapda szimbolikus nevet kapott. A Plan 9 a Bell Labs-tól (80-as évek vége) a jeleket jegyzetekkel helyettesítette, amelyek lehetővé tették rövid, tetszőleges karakterláncok küldését.

Jelek küldése A kill(2) rendszerhívás egy megadott jelet küld egy megadott folyamatnak, ha a jogosultságok megengedik. Hasonlóképpen, a kill(1) parancs lehetővé teszi a felhasználó számára, hogy jeleket küldjön a folyamatoknak. A raise(3)raise(3) — Linux manual page könyvtárfüggvény elküldi a megadott jelet az aktuális folyamatnak.

Az olyan kivételek, mint a nullával való osztás, a szegmentálási hiba (SIGSEGV) és a lebegőpontos kivétel (SIGFPE), memóriakiírást okoznak és leállítják a programot.

A kernel jeleket generálhat a folyamatok eseményekről való értesítésére. Például a SIGPIPE akkor generálódik, amikor egy folyamat egy olyan pipe-ra ír, amelyet az olvasó lezárt; alapértelmezés szerint ez a folyamat leállítását okozza, ami kényelmes a shell pipeline-ok létrehozásakor.A Unix-szerű operációs rendszerekben a pipeline egy mechanizmus a folyamatok közötti kommunikációra üzenetküldés segítségével. A pipeline olyan Folyamat (számítástechnika)folyamatok halmaza, amelyeket szabványos adatfolyamaik láncolnak össze, így minden folyamat kimeneti szövege (stdout) közvetlenül bemenetként (stdin) kerül a következő folyamatba. A második folyamat akkor indul el, amikor az első folyamat még fut, és a folyamatokat egyidejűleg hajtják végre.

Bizonyos billentyűkombinációk begépelése egy futó folyamat vezérlőterminálján azt eredményezi, hogy a rendszer bizonyos jeleket küld neki: A Ctrl-CCtrl-C (régebbi Unixokban DEL) egy INT jelet küld ("interrupt", SIGINT); alapértelmezés szerint ez a folyamat leállítását okozza. A Ctrl+Z billentyűkombináció egy TSTP jelet küld ("terminal stop", SIGTSTP); alapértelmezés szerint ez a folyamat végrehajtásának felfüggesztését okozza. A Ctrl-\ billentyűkombináció egy QUIT jelet (SIGQUIT) küld; alapértelmezés szerint ez a folyamat leállítását és core dump kiíratást okoz. A Ctrl-T billentyűkombináció (nem minden UNIX rendszeren támogatott) egy INFO jelet (SIGINFO) küld; alapértelmezés szerint, és ha a parancs támogatja, ez azt eredményezi, hogy az operációs rendszer információkat jelenít meg a futó parancsról.

Ezek az alapértelmezett billentyűkombinációk a modern operációs rendszerekkel az stty paranccsal módosíthatók.A Unix stty parancs egy Unix terminál beállításainak módosítására szolgál. (Version 2 AT&T UNIX )

Jelek kezelése A jelkezelők a signal(2) vagy a sigaction(2) rendszerhívással telepíthetők.A számítástechnikában a sigaction egy POSIX által definiált függvény API, amely hozzáférést biztosít a programozónak ahhoz, hogy hogyan kell viselkednie egy programnak adott operációs rendszer-jelek fogadásakor. Ha egy adott jelhez nincs telepítve jelkezelő, akkor az alapértelmezett kezelőt használja a rendszer. Ellenkező esetben a jel elfogásra kerül, és a jelkezelő meghívódik. A folyamat két alapértelmezett viselkedést is megadhat kezelő létrehozása nélkül: a jel figyelmen kívül hagyása (SIG_IGN) és az alapértelmezett jelkezelő (SIG_DFL) használata. Két jel van, amelyet nem lehet elfogni és kezelni: a SIGKILL és a SIGSTOP.

Kockázatok A jelkezelés érzékeny a versenyhelyzetekre. Mivel a jelek aszinkronok, egy másik jel (akár azonos típusú is) a jelkezelő rutin végrehajtása során is eljuthat a folyamathoz.

A sigprocmask(2) hívás használható a jelek kézbesítésének blokkolására és feloldására.sigprocmask(2) — Linux manual page A blokkolt jelek nem kerülnek kézbesítésre a folyamathoz, amíg a blokkolást fel nem oldják. A nem figyelmen kívül hagyható jeleket (SIGKILL és SIGSTOP) nem lehet blokkolni.

A jelek megszakíthatják a folyamatban lévő rendszerhívást, így az alkalmazásra marad a nem transzparens újraindítás kezelése.A PCLSRing (más néven Program Counter Lusering) az ITS operációs rendszerben használt kifejezés, amely a konzisztencia elvét jelöli, ahogyan az egyik folyamat egy másik folyamat állapotához fér hozzá.

A jelkezelőket úgy kell megírni, hogy ne okozzanak semmilyen nem kívánt mellékhatást, pl. hibakód (errno) megváltozását, jelmaszk megváltozását, jelelrendezés megváltozását és egyéb globális folyamatattribútum-változásokat. A nem-reentráns függvények,A reentráns egy olyan programozási koncepció, ahol egy függvény vagy alprogram (eljárás) megszakítható, majd folytatható a végrehajtás befejezése előtt. Ez azt jelenti, hogy a függvény újra meghívható, mielőtt befejezné az előző végrehajtását. A reentráns kód rekurzívan hívható anélkül, hogy a változók kezelése hibát okozna. Ezért nem használhat statikus változókat megfelelő zárolás vagy egyéb adminisztráció nélkül. például a malloc vagy a printf használata a jelkezelő rutinokon belül szintén nem biztonságos. A POSIX specifikáció és a Linux man page signal(7) előírja,signal(7) — Linux manual page hogy a jelfüggvényből közvetlenül vagy közvetve meghívott összes rendszerfüggvény aszinkronjel-biztos legyen. A signal-safety(7) man oldalsignal-safety(7) — Linux manual page felsorolja az ilyen aszinkronjel-biztos rendszerfüggvényeket (gyakorlatilag a rendszerhívásokat), egyébként ez egy nem definiált viselkedés. Javasolt egyszerűen beállítani valamilyen volatile sig_atomic_t változót egy jelkezelőben, és máshol tesztelni.

A jelkezelők ehelyett elhelyezhetik a jelet egy várakozási sorba, és azonnal visszatérhetnek. A fő szál ezután „megszakítás nélkül” folytatódik, amíg a jeleket el nem veszik a várakozási sorból, például egy eseményhurokban.A számítástechnikában az eseményciklus egy programozási konstrukció, vagy programtervezési minta, amely eseményekre vagy üzenetekre vár és azokat kiküldi egy programban. A „megszakítás nélküli” itt azt jelenti, hogy a blokkoló műveletek idő előtt visszatérhetnek, és a fent említett módon folytatni kell őket. A jeleket a fő szálon lévő várakozási sorból kell feldolgozni, nem pedig a munkavégző készletekből, mivel ez újra bevezeti az aszinkronitás problémáját. Egy várakozási sor kezelése azonban nem lehetséges aszinkronjel-biztonságos módon, kizárólag a sig_atomic_t változóval, mivel az ilyen változókba történő írások és olvasások garantáltan atomiak, nem pedig növelések vagy (lehívások és) csökkentések, ahogyan az egy várakozási sor esetében megkövetelhető lenne. Így gyakorlatilag kezelőnként csak egy jel kerülhet biztonságosan sorba a sig_atomic_t segítségével, amíg azt fel nem dolgozza.

Kapcsolat hardveres kivételekkel Egy folyamat végrehajtása hardveres kivétel generálódását eredményezheti, például, ha a folyamat nullával próbál osztani, vagy laphiba keletkezik.A számítástechnikában a laphiba egy kivétel, amelyet a memóriakezelő egység (MMU) generál, amikor egy folyamat megfelelő előkészületek nélkül fér hozzá egy memórialaphoz.

Unix-szerű operációs rendszerekben ez az esemény automatikusan megváltoztatja a processzor kontextusát,A számítástechnikában a feladatkontextus (task context) a feladat (ami lehet egy folyamat, egy szál vagy egy rost) által használt minimális adathalmaz, amelyet menteni kell ahhoz, hogy a feladat megszakítható, majd később ugyanonnan folytatható legyen. hogy elindítsa a kernel kivételkezelőjének végrehajtását. Bizonyos kivételek, például egy laphiba esetén a kernel elegendő információval rendelkezik ahhoz, hogy teljes mértékben kezelje az eseményt, és folytassa a folyamat végrehajtását.

Más kivételek esetén azonban a kernel nem képes intelligensen feldolgozni a hibákat, és ehelyett a kivételkezelési műveletet a hibás folyamatra kell halasztania. Ez a halasztás a jelzés mechanizmusán keresztül valósul meg, ahol a kernel az aktuális kivételnek megfelelő jelet küld a folyamatnak. Például, ha egy folyamat egész számot próbál nullával osztani egy x86 CPU-n, akkor egy osztási hiba (divide error) kivétel keletkezik, és a kernel elküldi az SIGFPE jelet a folyamatnak.

Hasonlóképpen, ha a folyamat a virtuális címtartományán kívül eső memóriacímet próbálna elérni, a kernel egy SIGSEGV (szegmentációs hiba jel) segítségével értesítené a folyamatot erről a megsértésről. A jelnevek és a kivételek közötti pontos megfeleltetés nyilvánvalóan a CPU-tól függ, mivel a kivételtípusok architektúránként eltérőek.

POSIX jelek Az alábbi lista a Single Unix Specification 5. verziójában meghatározott jeleket (signal) dokumentálja.POSIX.1-2024 Minden jel makró konstansként van definiálva a <signal.h> fejlécfájlban. A makró konstans neve egy "SIG" előtagból áll, amelyet a jel mnemonikus neve követ.

Egy folyamat meghatározhatja, hogyan kezelje a bejövő POSIX jeleket. Ha egy folyamat nem definiál viselkedést egy jelhez, akkor az adott jel alapértelmezett kezelőjét (default handler) használja. Az alábbi táblázat néhány alapértelmezett műveletet sorol fel POSIX-kompatibilis UNIX rendszereken, például a FreeBSD-n, az OpenBSD-n és a Linuxon.