Když proces hlídá proces
... Neznámá předtucha mě nutí otevřít Task Manager. Spěšně ho prohlížím. V záplavě nejrůznějších procesů upoutá mou pozornost jeden s názvem kernel64.exe. Co to je za nesmysl? Proces vypnu a jdu si nalít trochu čaje. Když se znovu podívám do Task Managera, proces kernel64.exe je zpět. WTF?...
Cílem následujícího článku je ukázat, jak jednoduše lze hlídat běh procesu a v případě potřeby ho znovu nastartovat. Před pár dny jsem si při sledování filmu Robin Hood vzpomněl, jak jsem před mnoha lety četl článek o vtipném pokusu jedné společnosti, která konkurenci (XEROX nebo IBM?) do tiskárny nasadila dvě binárky, které se ve formě procesů neustále hlídaly a pokud byl jeden z procesů zabit, druhý ho okamžitě znovu spustil. Tento vtip nadělal administrátorům hodně vrásek na čele. Paradoxně dal také vzniknout jedné z technik, s níž jsme se mohli, můžeme a pravděpodobně i budeme moci setkávat u malware. Z dnešního pohledu už se nejedná o nijak závažný problém. Ale před třemi čtyřmi desítkami let se odstranění tohoto žertíku opravdu rovnalo neřešitelnému úkolu. Možná se teď leckdo z vás ptá, proč jsem si na tohle vzpomněl zrovna u filmu Robin Hood. Odpověď je jednoduchá: Ty dva procesy se totiž jmenovaly Robin a Big John :)
Oč se tedy jedná? Princip je velice jednoduchý. Máme dva procesy, které se vzájemně hlídají. Pokud jeden z nich zjistí, že ten druhý "umřel", okamžitě ho znovu nastartuje. Způsobů, jak tento úkol realizovat je mnoho. Pokusím se obecně popsat tři nejzákladnější a navrch přidám popis čtvrtého, trošku komplikovanějšího řešení.
První a úplně nejjednodušší řešení napadlo snad každého. Každý program bude procházet cyklicky procesy a hledat v nich název svého souputníka. Pokud ho najde, pokračuje dál. Pokud ho nenajde, spustí ho znovu a pokračuje dál. Mezi obecně nejpoužívanější Windows API pro tento účel je sada funkcí z knihovny Tool Help. Konkrétně CreateToolhelp32Snapshot, Process32First a Process32Next. Windows API funkce CreateToolhelp32Snapshot s prvním argumentem TH32CS_SNAPPROCESS, jenž říká, že budeme pracovat s procesy, vytvoří handle. Tento handle se dále předá do API funkce Process32First jako první argument. Jako druhý je pak pointer na strukturu PROCESSENTRY32. Tuto strukturu API funkce Process32Fist naplní informacemi o prvním běžícím procesu. Pro nás je nejdůležitější pole szExeFile udávající název souboru, z kterého byl daný proces vytvořen. Pro vylistování dalších procesů použijeme API funkci Process32Next. Tato API funkce přebírá stejné argumenty jako předchozí. Jednoduchý kód pro ověření, zda daný proces v paměti existuje, může vypadat následovně:
Jak je vidět, kód je velice jednoduchý a prakticky nepotřebuje dalšího vysvětlování. Druhou možností je využití takzvaného mutexu. Mutex je synchronizační objekt, který může, ale nemusí mít jméno/pojmenování. Využívá signalizaci, aby dal procesům nebo vláknům, která se mají synchronizovat, echo, jak celý proces synchronizace probíhá (ještě se stále synchronizuje nebo už můžeme pokračovat?). Z těch několika málo API funkcí sloužících pro práci s mutexy si vystačíme s jednou, maximálně se dvěma (v závislosti na chutích jedinců ;)). První je CreateMutex a případná druhá OpenMutex. API funkce CreateMutex přebírá tři argumenty. První nastavuje bezpečnostní atributy pro práci s mutexem, druhým si může tvůrce mutexu zajistit počáteční vlastnictví mutexu a konečně třetí argument tvoří název mutexu. Důležitou vlastnostní mutexu je pro nás fakt, že jméno mutexu je v rámci systému unikátní, a proto existuje vždy pouze v jediném exempláři. Pokusíme-li se vytvořit mutex se jménem, které již existuje, systém nastaví funkci GetLastError na hodnotu ERROR_ALREADY_EXISTS. Díky tomu jsme schopni zjistit, zda náš spřízněný proces stále běží. Vyjádřeno programovacím jazykem:
Opět se jedná o velice jednoduchý kód. Stejným způsobem můžeme využít i semafor. Semafor je 'inteligentnější' verze mutexu. 'Inteligentnější' je o schopnost počítat maximální počet procesů nebo vláken přistupujících k mutexu. Ostatní se holt musí hezky seřadit do řady a tiše čekat, až na ně přijde řada. Pro práci se semafory se nejčastěji setkáte s API funkcemi CreateSemaphore pro vytvoření semaforu, OpenSemaphore pro otevření existujícího semaforu a ReleaseSemaphore pro navýšení počítadla semaforu.
Tři nejjednodušší řešení máme za sebou. Na začátku jsem slíbil ještě jedno trochu složitější řešení. Ve skutečnosti se opět jedná o velice jednoduché řešení ;) Myšlenka je jednoduchá: Aplikace si vytvoří klienta a server. Server slouží přípojný bod pro druhý proces, aby byl schopný zjistit existenci prvního procesu. Klientem se pokusí připojit na server spolubojovníka. Pokud se mu to povede, čeká dokud nedostane zprávu o chybě. Pak se znovu pokusí připojit. Pokud se mu to nepodaří, spustí kamarádský proces a pokračuje s připojováním. Vytvoření tohoto kódu již nechám jako cvičení na každém ze čtenářů :)
- Pro psaní komentářů se přihlašte




