Linux a czas rzeczywisty
Wprowadzenie do systemów RT: RTLinux: KURT Linux: Slajdy: |
Implementacja RTLinuksaSterownik przerwańW niezmodyfikowanym jądrze Linuksa wiele fragmentów jądra, głównie sterowniki urządzeń, chroni krytyczne obszary kodu poprzez zablokowanie przerwań instrukcją
W tym kawałku kodu przerwania zostają zablokowane w linijce 2232, i odblokowane w 2250. Jeśli jakieś przerwanie nadejdzie, kiedy wykonywana jest linijka 2232 - jego obsłużenie zostanie opóźnione aż do 2250. Rozwiązanie takie ma bardzo poważną wadę: nie da się wywłaszczyć procesu, który wyłączył przerwania. Co prawda twórcy kernela dbają o to, żeby okresy pracy z wyłączonymi przerwaniami były jak najkrótsze, i w najnowszych wersjach jądra czas ten nie przekracza 80 mikrosekund, jednak do niektórych zastosowań nawet taki czas jest zbyt długi. Co więcej, jako, że jądro jest rozwijane jednocześnie przez wiele osób, i autorem modułu może zostać każdy, istnieje ryzyko, że w wyniku beztroski jakiegoś programisty któraś kolejna wersja jądra będzie spędzać z wyłączonymi przerwaniami czas dłuższy, niż poprzednia - co może spowodować, że kernel przestanie 'nadążać' i popsuć właściwości RT systemu. RTLinux radzi sobie z tym problemem w genialnie prosty sposób - nie pozwala kernelowi Linuksa na wyłączenie przerwań, emuluje jedynie takie zachowanie. RTCore odbiera wszystkie przerwania, i decyduje, co należy z nimi zrobić. Zmiany, które muszą być wprowadzone w jądrze Linuksa, dotyczą jedynie Gdy nadchodzi przerwanie:
Gdy kernel linuksa wywołuje Gdy kernel linuksa wywołuje Podobnie blokowane / odblokowywane są poszczególne przerwania. Uwaga: wątki RT mają pełen dostęp do flagi kontrolującej blokowanie przerwań w procesorze - omijają emulator. Oznacza to, że mogą wyłączać i włączać przerwania do woli, dlatego przy pisaniu ich należy być ostrożnym! SchedulerDzięki temu, że procesy RT mają wspólną przestrzeń adresową, zmiana bieżącego procesu jest bardzo szybka. Scheduler RTLinuksa ładowany jest jako moduł, co umożliwia łatwą zamianę go na inny. Standardowy scheduler korzysta z priorytetów przydzielonych na stałe wątkom RT (Fixed Priority Scheduler). Wątek RT, który zostaje uruchomiony, nie ma przydzielonego timeslice'a - wykonuje się do momentu, kiedy sam postanowi oddać procesor, albo gdy zostanie wywłaszczony przez wątek o wyższym priorytecie. Scheduler jest uruchamiany jedynie wtedy, gdy rzeczywiście jest potrzebny, a nie co jakiś ustalony przedział czasu - prowadzi to do zmniejszenia narzutu związanego z jego działaniem. Algorytm działania schedulera jest następujący:
O ile mamy do czynienia z procesami okresowymi, dla których deadline = okres (np, coś _musi_ być wykonane co każde 50 ms), można je uporządkować korzystając z Rate Monotonic Algorithm. Algorytm jest prosty - im dany proces ma mniejszy okres, tym większy priorytet powinien mieć. Uzyskane uporządkowanie jest optymalne dla algorytmów szeregowania o stałym priorytecie. Zbiór procesów na pewno spełni wszystkie deadline'y, jeśli C1/T1 + C2/T2 + ... + Cn/Tn <= n(2(1/n) - 1) O lewej stronie można myśleć jako o 'zajętości' procesora, prawa dąży do ln 2 ~= 0.69. Oznacza to, że korzystając z tego algorytmu w pesymistycznym przypadku procesor wykorzystany jest jedynie w 69% (średnio, w 88%) Inny dostępny scheduler do RTLinuksa korzysta z algorytmu Earliest Deadline First - wybierane są te procesy, których deadline jest najbliższy. RT FIFODo komunikacji między procesami RT, albo między procesem RT i nie-RT służą kolejki FIFO czasu rzeczywistego. Są to urządzenia znakowe - Z poziomu programów RT, do obsługi kolejek służą funkcje:
Można też korzystać ze zwykłego interfejsu plików: Operacje na kolejkach w procesach RT są nieblokujące. Dzięki temu nie dochodzi do zakleszczeń. Z poziomu procesów nie-RT dostęp do kolejek jest dokładnie taki, jak do zwykłych plików. Operacje mogą być blokujące albo nieblokujące. POSIX IOJeden z modułów RTLinuksa, Oczywiście, można sobie poradzić z tym problemem w następujący sposób: otworzyć dowolny plik w procesie nie-RT, i wysłać jego zawartość do procesu RT np za pomocą RT-FIFO. ZegarDla sprawnego funkcjonowania systemu RT konieczny jest odpowiednio dokładny zegar - na przykład do uruchamiania schedulera, lub do mierzenia bardzo niewielkich odstępów czasu. W większości systemów operacyjnych, na przykład w Linuksie, zegar 'tyka' co jakiś ustalony czas (w Linuksie około 100 razy na sekundę). To zdecydowanie za mało do zastosowań RT. O ile zegar tyka często, dużo czasu procesora zostaje zmarnowane na być może niepotrzebną obsługę przerwań zegarowych; o ile tyka zbyt rzadko, zegar ma niewielką rozdzielczość i dokładne odczekanie ustalonego czasu przez proces może być niemożliwe. RTLinux radzi sobie z tym problemem poprzez całkowite zlikwidowanie okresowych przerwań zegarowych: kiedy zegar 'tyka', określa się, kiedy powinno nastąpić następne tyknięcie, po czym następuje odpowiednie przeprogramowanie zegara. Pozwala to na precyzyjne odmierzanie czasu, z dokładnością do 1 mikrosekundy - przy zachowaniu niskiego narzutu na operacje związane z zegarem (przeprogramowanie chipa zegara Intel 8354, obecnego w każdym PC, jest dość powolne. Na szczęście procesory od Pentium wzwyż mają wbudowany wewnętrzny zegar o szybkim dostępie). Na przykład, załóżmy, że proces A chce być zbudzony za 5 ms, a proces B za 23 ms.
W rozwiązaniu z zegarem takim, jak w RTLinuksie, przerwań zegarowych jest mniej a procesy budzone są sprawniej. Pamięć dzielonaObsługę pamięci dzielonej do RTLinuksa dodaje moduł |