Komunikacja międzyprocesowa w QNX
3 lutego 2009
Na desktopach oraz serwerach niewątpliwie królują jądra monolityczne. Kernele systemów takich jak *BSD, (Open)Solaris czy Linux z grubsza opierają się na tej samej architekturze. Podobnie rzecz się ma w stosunku do Windowsa, mimo że w jego budowie jest już parę ciekawych różnic. Właściwie jedynym popularnym na tego typu maszynach systemem bazującym na mikrojądrze jest Mac OS X korzystający z jądra Mach.
Zupełnie inaczej rzecz się ma w przypadku systemów wbudowanych, a także wielu systemów czasu rzeczywistego. Tam mikrojądra odgrywają znacznie większą rolę. Jednym z popularniejszych systemów opartych na mikrojądrze jest QNX korzystający z jądra QNX Neutrino. Jego wewnętrzna architektura jest zupełnie inna od tej znanej z Linuksa czy też Uniksów. Wynika to głównie z tego, że nacisk jest położony na zupełnie elementy systemu. Jedną z najistotniejszych kwestii we wszystkich mikrojądrach jest komunikacja międzyprocesowa.
Wiadomości (messages)
Podobnie jak w innych systemach opartych na mikrojądrach, także w QNX tym co łączy wszystkie elementy systemu w jedną całość jest IPC. Podstawowym mechanizmem IPC udostępnianym przez QNX Neutrino są wiadomości (messages). Są to synchroniczne komunikaty na które adresat zawsze odpowiada. Warto przyjrzeć się sposobowi w jaki Neutrino przekazuje wiadomości.
- Wątek będący klientem wykonuje procedurę MsgSend(). Przechodzi on w stan SEND blocked, co jest równoważne jego wstrzymaniu. Jeżeli wątek będący adresatem czeka na wiadomość, jest on wznawiany automatycznie, bez udziału planisty.
- W momencie w którym wątek będący serwerem wywoła procedurę MsgReceive() dostanie on informację o otrzymanej wiadomości, a nadawca przejdzie w stan REPLY blocked. Jeżeli procedura MsgReceive() zostanie wywołana w sytuacji, kiedy nie ma żadnych wiadomości w kolejce do przetworzenia, wątek przejdzie w stan RECEIVE blocked i zostanie wstrzymany do momentu otrzymania wiadomości.
- Po wykonaniu operacji związanych z obsługą otrzymanego komunikatu, serwer wykonuję procedurę MsgReply(), która przekazuje klientowi odpowiedź lub MsgError(), która przekazuje informacje o błędzie. Obie te funkcje powodują przejście klienta w stan READY, a więc wznowienie jego działania.
Przesyłanie danych
Obok synchronizacji działania realizowanej przez przechodzenie wątków w różne stany drugą kwestią jest sam sposób przesłania danych. Jeżeli ilość przesyłanych danych jest niewielka (najczęściej poniżej 256 bajtów) są one buforowane w przestrzeni jądra i w ten sposób przenoszone między przestrzeniami adresowymi dwóch wątków. W przeciwnym razie Neutrino tymczasowo mapuje fragment przestrzeni adresowej serwera w przestrzeni klienta co pozwala na przeniesienie danych między nimi w bardzo wydajny sposób. Dzięki temu prędkość kopiowania wiadomości jest zależna jedynie od przepustowości pamięci operacyjnej urządzenia. Neutrino pozwala także na wysyłanie wiadomości złożonych z bloków o różnych rozmiarach rozmieszczonych w różnych obszarach przestrzeni adresowej.
Kanały (channels) i połączenia
W QNX Neutrino wątek, który chce otrzymywać wiadomości musi utworzyć kanał (channel). Nadawca, przed wysłaniem danych nawiązuje połączenie z tym kanałem. W przestrzeni użytkownika zarówno kanały jak i połączenia są reprezentowane przez liczby całkowite. Dodatkowo liczby identyfikujące połączenia używa się zamiennie z deskryptorami plików. Do każdego kanału przyporządkowane są trzy struktury danych przechowujące informacje o klientach.
- receive - bufor LIFO wątków oczekujących na wiadomość
- send - kolejka (FIFO) wątków, które wysłały jeszcze nieodebrane wiadomości
- reply - nieuporządkowana lista wątków, które wysłały wiadomość na którą nie udzielono jeszcze odpowiedzi
Podsumowanie
Oprócz wyżej wymienionych messages QNX wspiera także wiele innych rodzajów komunikacji międzyprocesowej. Są to sygnały, kolejki, pipes, pamięć dzielona, itp. Ich implementacja opiera się jednak głównie na messages, które to w najbardziej dobitny sposób przedstawiają cechy charakterystyczne QNX jeżeli chodzi o przesyłanie komunikatów. Wykorzystany został w nich przemyślany system synchronizacji, pozwalający uniknąć opóźnienia związanego z wywołaniem planisty CPU oraz mechanizm kopiowania danych wybierający optymalną metodę dla określonej ich ilości. Nie dziwi nacisk jaki położono właśnie na IPC, skoro jest to jeden z najważniejszych elementów mikrojądra QNX Neutrino.
Komentarze do wpisu "Komunikacja międzyprocesowa w QNX":
1.
mh napisał(a):
3 lutego 2009, 23:29:47
chyba lepiej:
s/kolejka FIFO/kolejka/
s/kolejka LIFO/stos/
2.
Paweł Dziepak napisał(a):
3 lutego 2009, 23:35:06
Rzeczywiście "kolejka LIFO" mimo że czasami używana, jest dość niefortunną nazwą tej struktury danych.
3.
sprae napisał(a):
4 lutego 2009, 04:40:34
Bardzo fajne. Lubię czytać takie architektoniczne rzeczy dziękuję.
Dodaj komentarz: