Signály Roury D-Bus Další možnosti Závěr Meziprocesová komunikace (IPC) Tématicky zaměřený vývoj aplikací v jazyce C skupina Systémové programování – Linux Petr Velan Fakulta informatiky Masarykova univerzita velan@ics.muni.cz Brno, 15. října 2013 P. Velan IPC 15. 10. 2013, Brno 1 / 23 Signály Roury D-Bus Další možnosti Závěr Signály principy a práce se signály P. Velan IPC 15. 10. 2013, Brno 2 / 23 Signály Roury D-Bus Další možnosti Závěr Signály #include princip přerušení – událostmi řízený program příchod signálu → přerušení činnosti → obsloužení signálu → návrat k předchozí práci (nebo také ne) některé signály lze ignorovat, některé blokovat, pro většinu lze měnit reakce na ně – výjimkami jsou SIGKILL a SIGSTOP obyčejné signály vs. real-time (spolehlivé) signály nikdy nepoužívejte přímo hodnoty, u real-time signálů SIGRTMIN+n seznam signálů: man 7 signal, např.: SIGTERM "Termination" - signál ukončení SIGKILL "Kill" - signál pro nepodmíněné ukončení SIGSEGV Odkaz na nepřípustnou adresu v paměti SIGUSR1 Signál definovaný uživatelem ... P. Velan IPC 15. 10. 2013, Brno 3 / 23 Signály Roury D-Bus Další možnosti Závěr Posílání signálů #include #include int kill(pid_t pid, int sig); signály lze posílat nejen konkrétnímu procesu, ale i skupině procesů, nebo všem běžícím procesům zaslání signálu je omezeno oprávněním uživatele int raise(int sig); signály může proces posílat i sám sobě – mechanismus výjimek int sigqueue(pid_t pid, int sig, const union sigval value); pro real-time signály indikuje, zda se podařilo vložit signál do fronty navíc u všech signálů umožňuje zaslat procesu i data (int nebo ukazatel) P. Velan IPC 15. 10. 2013, Brno 4 / 23 Signály Roury D-Bus Další možnosti Závěr Reakce na signály #include sighandler_t signal(int signum, sighandler_t handler); int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); funkci signal() používejte jen pro nastavení handleru na SIG_IGN nebo SIG_DFL pro vlastní handlery používejte výhradně funkci sigaction() handler musí být co nejjednodušší pokud už měníte globální proměnnou, deklarujte ji jako volatile i handler může být přerušen signálem – pokud je to nutné, blokujte signály (viz. dále) P. Velan IPC 15. 10. 2013, Brno 5 / 23 Signály Roury D-Bus Další možnosti Závěr Příklad – sigaction() volatile int done = 0; void my_handler(int sig) { done = 1; } int main () { struct sigaction action; /* action structure for specific signal */ /* establish the signal handler */ sigemptyset(&action.sa_mask); action.sa_flags = 0; action.sa_handler = my_handler; sigaction(SIGTERM, &action, NULL); sigaction(SIGINT, &action, NULL); while (!done) { /* do some work */ sleep(1); } printf("cleaning up\n"); /* close files, free memory, write output, ... */ return 0; } P. Velan IPC 15. 10. 2013, Brno 6 / 23 Signály Roury D-Bus Další možnosti Závěr Blokování signálů Umožňuje zajistit přijetí signálu až v určitý okamžik (odložení příjmu signálu). sigprocmask(SIG_BLOCK,...) sigprocmask(SIG_UNBLOCK,...) signál obsluha signálu SIGKILL a SIGSTOP nelze blokovat. #include int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int sigpending(sigset_t *set); Operace s maskou signálů viz. man 3 sigsetops P. Velan IPC 15. 10. 2013, Brno 7 / 23 Signály Roury D-Bus Další možnosti Závěr Synchronní doručení signálů Pokud je třeba signály používat intenzivněji, stojí za zvážení jejich synchronní použítí. Funkce sigwait(), sigwaitinfo(), sigsuspend() Pro skutečně synchronní chování, by signály, na které se čeká, měly být nejříve vymaskovány. P. Velan IPC 15. 10. 2013, Brno 8 / 23 Signály Roury D-Bus Další možnosti Závěr Poznámky k signálům Signály jsou drahé (asynchronní přerušení) → přemýšlejte zda je signál nejvhodnějším řešením. Kvůli optimalizaci kompilátoru deklarujte globální proměnné jako volatile. V obslužné rutině provádějte jen to nejnutnější (žádné zapisování do souborů, alokace paměti apod.). Pozor na errno – signály jsou asynchronní!. I obslužná rutina může být přerušena signálem. P. Velan IPC 15. 10. 2013, Brno 9 / 23 Signály Roury D-Bus Další možnosti Závěr úkol Napište program, který po doručení (konkrétního, výběr je na vás) signálu zapíše do syslogu informaci o zpracování signálu P. Velan IPC 15. 10. 2013, Brno 10 / 23 Signály Roury D-Bus Další možnosti Závěr Roury anonymní a pojmenované roury P. Velan IPC 15. 10. 2013, Brno 11 / 23 Signály Roury D-Bus Další možnosti Závěr Roury $ ls | less někdy se setkáte i s pojmem datová kolona jednosměrný proud bajtů mezi dvěma konci roury roura je dvojice file deskriptorů (int pipefd[2]) – pipefd[0] pro čtení a pipefd[1] pro zápis velikost roury je omezená (65536 bajtů) nepojmenované roury jsou určeny pouze pro příbuzné procesy #include int pipe(int pipefd[2]); P. Velan IPC 15. 10. 2013, Brno 12 / 23 Signály Roury D-Bus Další možnosti Závěr Roury $ ls | less někdy se setkáte i s pojmem datová kolona jednosměrný proud bajtů mezi dvěma konci roury roura je dvojice file deskriptorů (int pipefd[2]) – pipefd[0] pro čtení a pipefd[1] pro zápis velikost roury je omezená (65536 bajtů) nepojmenované roury jsou určeny pouze pro příbuzné procesy #include int pipe(int pipefd[2]); často používáno v kombinaci s funkcí dup2() #include int dup2(int oldfd, int newfd); P. Velan IPC 15. 10. 2013, Brno 12 / 23 Signály Roury D-Bus Další možnosti Závěr Roury $ ls | less někdy se setkáte i s pojmem datová kolona jednosměrný proud bajtů mezi dvěma konci roury roura je dvojice file deskriptorů (int pipefd[2]) – pipefd[0] pro čtení a pipefd[1] pro zápis velikost roury je omezená (65536 bajtů) nepojmenované roury jsou určeny pouze pro příbuzné procesy #include int pipe(int pipefd[2]); často používáno v kombinaci s funkcí dup2() #include int dup2(int oldfd, int newfd); zjednodušené použití nepojmenovaných rour – funkce popen() a pclose(), cílový proces je spouštěn pomocí shellu → značná režie navíc P. Velan IPC 15. 10. 2013, Brno 12 / 23 Signály Roury D-Bus Další možnosti Závěr Příklad – pipe() I int main(int argc, char *argv[]) { int pfd[2]; /* pipe */ pid_t child; /* child’s PID */ char buf; /* char buffer */ if (pipe(pfd) == -1) { perror("creating pipe failed"); return 1; } child = fork(); if (child == -1) { perror("fork() failed"); return 1; } else if (child == 0) { /* child process - reader */ close(pfd[1]); /* Close unused write end */ while (read(pfd[0], &buf, 1) > 0) { write(STDOUT_FILENO, &buf, 1); } write(STDOUT_FILENO, "\n", 1); close(pfd[0]); } else { /* Parent writes string to pipe */ close(pfd[0]); /* Close unused read end */ write(pfd[1], "Ahoj!", strlen("Ahoj!")); close(pfd[1]); /* Reader will see EOF */ wait(NULL); /* Wait for child */ } return 0; } P. Velan IPC 15. 10. 2013, Brno 13 / 23 Signály Roury D-Bus Další možnosti Závěr úkol Napodobte chování shellu při řetězení aplikací pomocí datových kolon (|) Aplikace dostane jako parametry 2 řetezce představující příkazy ke spuštění – nezapoměňte, že součástí příkazu mohou být parametry spouštěného programu Vaše aplikace pak zařídí spuštění zadaných příkazů a propojení standardního výstupu první aplikace se standardním vstupem druhé. Nápověda: dup2() P. Velan IPC 15. 10. 2013, Brno 14 / 23 Signály Roury D-Bus Další možnosti Závěr Pojmenované roury (FIFO) nepojmenované roury jsou určeny pouze pro příbuzné procesy co když ale potřebujeme propojit nepříbuzné procesy? P. Velan IPC 15. 10. 2013, Brno 15 / 23 Signály Roury D-Bus Další možnosti Závěr Pojmenované roury (FIFO) nepojmenované roury jsou určeny pouze pro příbuzné procesy co když ale potřebujeme propojit nepříbuzné procesy? FIFO alias pojmenovaná roura součást souborového systému – pouze jako referenční bod pro přístup procesů, do souborového systému se nic nezapisuje je možné nastavit přístupová práva jako kterémukoliv jinému souboru pro komunikaci je nutné, aby oba konce roury byly otevřené s rourou se pak pracuje jako se souborem – open(), read(), write(), close(), unlink() #include #include int mkfifo(const char *pathname, mode_t mode); P. Velan IPC 15. 10. 2013, Brno 15 / 23 Signály Roury D-Bus Další možnosti Závěr úkol stejnou úlohu jako pro nepojmenované roury implementujte pomocí mkfifo() P. Velan IPC 15. 10. 2013, Brno 16 / 23 Signály Roury D-Bus Další možnosti Závěr D-Bus jemný úvod D-Busu P. Velan IPC 15. 10. 2013, Brno 17 / 23 Signály Roury D-Bus Další možnosti Závěr D-Bus D-Bus http://www.freedesktop.org/wiki/Software/dbus systém pro komunikaci procesů pomocí rozesílání zpráv základem knihovna libdbus, pro různé jazyky/frameworky (Python, Qt, Glib, . . . ) existují obalové knihovny dva typy zpráv volání metod (RPC) - zprávy s definovaným adresátem, obvykle vás zajímá i odpověď na zprávu signály - "veřejné"oznámení bez adresáta součástí zprávy může být cokoli – čísla, pole, řetězce, struktury, . . . další vychytávky v podobě startování služeb na vyžádání nebo vlastního systému oprávnění (obdoba UNIXových uživatelských práv) P. Velan IPC 15. 10. 2013, Brno 18 / 23 Signály Roury D-Bus Další možnosti Závěr Další možnost další možnosti IPC, kterým se budeme věnovat v příštích cvičeních P. Velan IPC 15. 10. 2013, Brno 19 / 23 Signály Roury D-Bus Další možnosti Závěr Další možnosti IPC sdílená paměť dva či více procesů přistupuje ke sdílenému paměťovému místu žádné kopírování dat, synchronizaci přístupu zajišťují procesy jeden z procesů paměť alokuje, ostatní se k alokovanému segmentu připojují P. Velan IPC 15. 10. 2013, Brno 20 / 23 Signály Roury D-Bus Další možnosti Závěr Další možnosti IPC sdílená paměť dva či více procesů přistupuje ke sdílenému paměťovému místu žádné kopírování dat, synchronizaci přístupu zajišťují procesy jeden z procesů paměť alokuje, ostatní se k alokovanému segmentu připojují sockety – síťová rozhraní obousměrný komunikační kanál komunikace mezi procesy běžícími na stejném počítači, ale i pro komunikaci s procesem na jiném počítači spojovaná komunikace (model klient-server) vs. datagramová komunikace P. Velan IPC 15. 10. 2013, Brno 20 / 23 Signály Roury D-Bus Další možnosti Závěr Závěr domácí úkoly a zdroje P. Velan IPC 15. 10. 2013, Brno 21 / 23 Signály Roury D-Bus Další možnosti Závěr Domácí úkol vytvořte systémového daemona1 jako jednoduchou náhradu za syslog daemon přijímá data z pojmenované roury /tmp/pb173_syslog, zapisovat do tohoto souboru smí kdokoliv prvním parametrem daemona je název souboru, do kterého bude zapisovat události ve tvaru