Send a link to your students to track their progress
39 Terms
1
New cards
1. Drzewo urządzeń - definicja, zastosowanie, modyfikacje
Jest to standardowy sposób opisu połączenia między CPU a sprzętem, o hierarchicznej strukturze[cite: 12]. Służy do opisu sprzętu, którego system nie wykryje automatycznie sam. Pozwala na łatwe rozbudowywanie i dynamiczną zmianę opisu systemu podczas kompilacji lub w locie[cite: 13].
2
New cards
2. Obsługa magistral zapewniających autodetekcję (np. USB, PCIe)
Polega na ciągłym monitorowaniu magistrali przez jądro systemu operacyjnego i automatycznym wykrywaniu nowych urządzeń (w locie) poprzez wykorzystanie wbudowanych sprzętowych protokołów komunikacyjnych i deskryptorów tej magistrali[cite: 14].
3
New cards
3. Komunikacja we/wy - pamięć vs przestrzeń I/O i ich obsługa
Mapowanie w pamięć obsługujemy np. przez własny mikrosterownik korzystając z pliku /dev/mem (zaletą jest to, że sterownik pozwala uruchomić urządzenie zgodnie z drzewem urządzeń)[cite: 16, 17]. Przestrzeń I/O nie jest dostępna na wszystkich architekturach; obsługuje się ją przez instrukcje procesora (inb, outb) i funkcje uprawnień dostępu do portów (ioperm, iopl)[cite: 18].
4
New cards
4. Szeregowanie: tryby zwykłe, RT, terminowe i "błędne" procesy
Zwykłe: SCHED_OTHER (po kolei), BATCH (w tle), IDLE (bezczynne)[cite: 22]. RT: SCHED_FIFO i SCHED_RR (błędne procesy o wyższym priorytecie w tym trybie mogą zawiesić te o niższym)[cite: 25, 26]. Terminowe: SCHED_DEADLINE - błędny proces, który się nie skończy w czasie, zostaje bezpiecznie zawieszony (throttling) do następnego okresu, zwalniając procesor[cite: 27].
5
New cards
5. Jak powinno zachowywać się zadanie czasu rzeczywistego (RT)?
Musi unikać blokowania systemu przez długi czas, konfliktów z innymi procesami oraz unikać błędów i awarii[cite: 29]. Powinno być uruchamiane tylko i wyłącznie wtedy, gdy jest to konieczne, zatrzymując działanie, kiedy nie jest potrzebne[cite: 29].
6
New cards
6. Emulator QEMU - możliwości i testowanie
QEMU pozwala na emulację procesorów (m.in. ARM, x86, RISC-V)[cite: 32]. Standardowo emuluje dyski, sieć czy USB; własne modele sprzętu można dodawać przy pomocy QEMU Device Tree (QDT)[cite: 32]. QEMU może być wykorzystane do testowania kompatybilności OS i naszych aplikacji z różnymi platformami sprzętowymi bez użycia płytki fizycznej[cite: 33].
7
New cards
7. Komunikacja IPC: mechanizmy i użycie nazw dla kolejek/pamięci
Mechanizmy to m.in.: sygnały, potoki, gniazda, kolejki komunikatów, semafory, pamięć dzielona[cite: 36]. Aby nawiązać komunikację przez nazwę w kolejce komunikatów lub pamięci dzielonej, nazwa musi zaczynać się od znaku ukośnika (np. /kolejka1 przy użyciu mq_open lub shm_open)[cite: 38].
Semafory ograniczają pulę procesów (sem_init)[cite: 42, 43]. Mutexy dają wyłączny dostęp jednej zmiennej[cite: 43]. Zmienne warunkowe pozwalają zasnąć w oczekiwaniu na warunek[cite: 45, 46]. Blokady zapis/odczyt (pthread_rwlock) ułatwiają dostęp wielu czytającym[cite: 50]. Spinlocki powodują "aktywne oczekiwanie" bez usypiania procesu[cite: 51]. Bariery wymuszają zsynchronizowany start[cite: 52].
9
New cards
8. Możliwości rezerwacji rdzenia CPU (Affinity)
Rezerwacja rdzenia przydaje się dla zdarzeń wymagających szczególnie szybkiej, natychmiastowej obsługi, gdzie wykorzystujemy np. aktywne oczekiwanie na flagę z czujnika[cite: 54]. Korzystamy z tego przy pomocy języka C używając funkcji systemowych: sched_setaffinity, sched_getaffinity[cite: 55].
10
New cards
9. Oczekiwanie na zdarzenie sprzętowe (aktywne vs przerwania) i połówki sterowników
Przerwania pozwalają zwolnić system (nie czekamy na planowy przydział CPU) [cite: 58], ale aktywne oczekiwanie w pętli pozwala uniknąć opóźnień z powodu tzw. czasu przełączania kontekstu[cite: 59]. Optymalizacja polega na podzieleniu obsługi przez sterownik: "górna połówka" czyta sprzęt błyskawicznie, a "dolna połówka" odracza ciężkie obliczenia do formatu "zadanka" lub "kolejki prac"[cite: 60].
11
New cards
10. Serwer i zmienna liczba klientów (Zarządzanie buforem pamięci dzielonej)
Programy klienckie uzyskują dostęp po nazwie używając funkcji mapowania w pamięć wirtualną - mmap (z użyciem mutexów/semaforów do synchronizacji przed zapisem)[cite: 65]. Zapewnienie prawidłowego zwolnienia bufora polega na wywołaniu funkcji munmap przez klienta, a na koniec pełnego cyklu zamknięciu tego obszaru funkcją shm_close[cite: 66].
12
New cards
11. Drzewo urządzeń - konfiguracja max vs używana i rozszerzenia
"Maksymalna" opisuje absolutnie wszystkie dostępne urządzenia na PCB, a "używana" wskazuje, które są faktycznie wybudzone i aktywne w danym momencie (status="okay")[cite: 69]. Podsystemy można wybrać z użyciem menedżera lub plików konfiguracyjnych[cite: 70]. Niestandardowe rozszerzenia dodaje się przez "wgranie" odpowiednich sterowników do jądra[cite: 71].
13
New cards
12. Zapewnienie minimalnego czasu reakcji (1 rdzeń vs wiele rdzeni)
a) 1 rdzeń CPU: procesowi nadajemy najwyższy priorytet (np. SCHED_FIFO), używamy sprzętowych przerwań lub semaforów [cite: 74]. b) Wiele rdzeni CPU: rezerwujemy fizyczny rdzeń procesora na wyłączność sprzętową dla naszego oprogramowania operując w trybie odpytywania (affinity)[cite: 75]. Oba warianty wymagają silnej optymalizacji[cite: 76].
14
New cards
13. Dlaczego wykorzystanie DMA wymaga sterownika w przestrzeni jądra?
Ponieważ układ Direct Memory Access bezpośrednio operuje na strukturach krzemowych i wymaga absolutnego dostępu do zasobów takich jak RAM - do których dostęp w systemie operacyjnym przydziela tylko i wyłącznie przestrzeń chronionego jądra[cite: 78]. Sterownik przydziela mu adresy, chroniąc system przed całkowitym zniszczeniem pamięci OS-u[cite: 79].
15
New cards
14. Kolejki komunikatów vs potoki (cechy wspólne i różnice)
Cecha wspólna: Oba są kanałami jednokierunkowymi[cite: 82]. Różnice: W kolejkach dane lecą jako autonomiczne "komunikaty" (procesy nie muszą być stale i bezpośrednio połączone uściskiem dłoni)[cite: 83]. W potokach (Pipes) leci surowy strumień bajtów (dane pobierają się tylko w takiej kolejności, w jakiej weszły), co wymusza bezpośrednie połączone procesów[cite: 84].
16
New cards
15. Mapowanie rejestrów w pamięć aplikacji (mmap) - realizacja i problemy
Polega to na przypisaniu adresów fizycznych rejestrów na płycie głównej do adresów wirtualnych pamięci RAM realizowanym przez specjalne instrukcje OS-u[cite: 87, 88]. Do wykonania tego w C używamy funkcji mmap()[cite: 89]. Problemy z tym rozwiązaniem to np. konflikty dostępów z innymi procesami oraz wielkie utrudnienie w debugowaniu i testach[cite: 89].
17
New cards
16. Wstrzymanie wielu procesów do zainicjalizowania struktury (Synchronizacja)
Należy do tego użyć Bariery (Barriers) wywołując w wątkach np. funkcję pthread_barrier_wait. Bariery zapewniają synchronizację wykonania całego kodu równolegle wstrzymując każdy biegnący proces/wątek na checkpoincie i wznawiając go grupowo dopiero, gdy proces "inicjalizujący" warunek dotrze na miejsce jako ostatni[cite: 52].
Trzeba wykorzystać mechanizm Rezerwacji rdzenia (sched_setaffinity)[cite: 53, 54, 55]. Sterowniki systemu Linux pozwalają przypisywać obsługę określonych przerwań do wytypowanego rdzenia CPU[cite: 60]. W izolacji, na rdzeniu 3 podpinamy sprzęt #1, na rdzeniu 4 sprzęt #2 stosując np. odpytywanie aktywne (polling) flagi statusu, a resztę systemu "pędzimy" na rdzeniach 1-2.
19
New cards
18. Urządzenie ARM, zegar i przerwania - informowanie OS poprzez Drzewo Urządzeń (DT)
Informacje te zaszywa się w strukturze Drzewa Urządzeń (np. w pliku .dts). Aby poinformować jądro, trzeba dodać węzeł, który użyje właściwości `reg` dla wskazania fizycznych adresów rejestrów, właściwości `interrupts` określającej dedykowaną linię oraz właściwości `clocks` celującej referencyjnie we włącznik używanego kontrolera sygnału taktującego.
20
New cards
19. Usprawnienia Linuksa do pracy RT (PREEMPT_RT, Xenomai, RTAI)
1. PREEMPT_RT to nakładka implementowana bezpośrednio w standardowym jądrze (usprawnia pracę, podmieniając blokady Spinlocks na w pełni wywłaszczalne Mutexy tworząc miękki/twardy RT wprost z pudełka). 2. Architektura podwójnego jądra (Xenomai, RTAI): Standardowy (puchaty) Linux uruchamiany jest jako jedno mało ważne zadanie najniższego priorytetu uwięzione pod kontrolą mikro-jądra RT weryfikującego sprzęt w mikrosekundach.
21
New cards
20. Bufory rozproszone (Scatter-Gather - SG) w DMA
Pamięć przydzielana programom jest wirtualna - proces myśli, że jest ciągła, ale po podzieleniu przez MMU ("Stronicowanie") leży we fragmentach na chipie RAM. DMA używa czystych adresów fizycznych. Dlatego zamiast przenosić 1 bajt i wywoływać przerwania po stronach, sterownik generuje tzw. listę buforów rozproszonych - wektor wskazujący układowi logicznemu, gdzie po chrupiącym stronicowaniu szukać poszczególnych kawałków, wymuszając sklejanie sprzętowe.
22
New cards
21. Procesy: A (Czujniki-RT), B (GUI), C (Archiwum) - parametry szeregowania
Zgodnie z zasadą zadań RT: Proces A (kluczowy) dostaje najwyższy priorytet RT np. tryb SCHED_FIFO lub SCHED_DEADLINE, by natychmiastowo obsłużyć sensory. Proces B (GUI) potrzebuje płynności bez dławienia - używamy dla niego cyklicznego i klasycznego trybu SCHED_OTHER. Proces C zrzuca tony danych na dysk w tle, dostaje "niskopriorytetowy" typ wsadowy SCHED_BATCH (nie wolno mu zakłócić pracy czujnika i wizjera)[cite: 22].
23
New cards
22. Semafor utworzony przed fork() jako zmienna statyczna?
Nie wolno tak robić! Funkcja fork() wykonuje kopię stosu (Copy-On-Write), obydwa odseparowane procesy dostaną po własnym semaforze, więc nie będą synchronizować się nawzajem. Aby zrobić to poprawnie, należy powołać semafor (sem_init) wewnątrz Pamięci Współdzielonej IPC utworzonej poprzez mmap i użyć specjalnej stałej atrybutowej PTHREAD_PROCESS_SHARED.
24
New cards
23. Nakładki na Drzewo Urządzeń (Device Tree Overlays) i Raspberry Pi
Drzewo Urządzeń bywa twardo skompilowane (w plik binarny DTB). Nakładka (.dtbo) jest "plasterkiem" rozszerzającym i konfigurującym ten plik dynamicznie podczas ładowania z karty SD, dając możliwość zdefiniowania nowo podpiętych np. czujników temperatury. Na Raspberry Pi korzystamy z nich, modyfikując po prostu wpis w systemowym pliku np. "dtoverlay=i2c-rtc" oszczędzając kompilację.
25
New cards
24. OpenWRT i karta dźwiękowa USB - automatyczne uruchomienie (hotplug)
Urządzenia podłączane po interfejsie USB podlegają autodetekcji przez monitorowanie magistrali systemowej[cite: 14]. Aby sprzęt automatycznie się zarejestrował na bazowym "gołym" obrazie środowiska OpenWRT, konieczne jest dociągnięcie modułów jądra odpowiedzialnych m.in za audio (np. instalacja poprzez opkg paczek 'kmod-usb-audio' obsługujących sterowniki klasowe).
26
New cards
26. Najszybsze przetworzenie pakietu z rejestru statusu (1 CPU vs 4 CPU)
a) 1 CPU: Przydzielamy naszemu demonowi obsługującemu to gniazdo absolutnie najwyższy w OS priorytet np. SCHED_FIFO [cite: 25] i wykorzystujemy silnie zoptymalizowane "górne połówki" przerwań do zrzutu bufora. b) 4 CPU: Realizujemy natywną rezerwację wybranego rdzenia CPU przy użyciu sched_setaffinity, gdzie aplikacja stosuje niesamowicie "pazerny" tryb aktywnego oczekiwania bez zmian kontekstu na status[cite: 55, 59].
27
New cards
27. Drzewo urządzeń - włączanie i wyłączanie komponentów (status i dodawanie nowości)
W pliku konfigurującym (.dts), aktywację / deaktywację urządzenia definiuje się przypisaniem odpowiedniej wartości do flagi konfiguracyjnej - status = "okay" lub "disabled"[cite: 67, 69, 71]. Zaś dodanie modułu nieobecnego w głównej bazie struktury można zrealizować podając plik rozszerzeń Nakładki DT (Overlay), który zostanie zaczytany przez program ładujący U-Boot.
28
New cards
28. Synchronizacja 4 zleceń naraz (Semafor Liczący: wątki vs procesy)
Powołuje się na tę okoliczność klasyczny "Semafor liczący", przypisując przy użyciu funkcji sem_init mu wartość 4 (co wpuści cztery zlecenia dławiąc piąte)[cite: 42, 43]. Różnice: a) W wątkach działa od "kopa", bo dzielą wspólną przestrzeń adresową b) By udostępnić ten sam Semafor różnym Procesom, muszą one mieć zainicjalizowaną przestrzeń pamięci dzielonej (shm_open) i mieć ustawiony atrybut IPC - PTHREAD_PROCESS_SHARED.
29
New cards
29. Tryb szeregowania terminowego (SCHED_DEADLINE) - parametry i weryfikacja
Reżim parametryczny definiowany jest dla każdego procesu podając żelazne zasady: runtime (wymagany czas), deadline (ostateczny czas zakończenia) i period (okres zlecenia)[cite: 27]. Weryfikacja: jądro odpala tzw. admission test sprawdzając czy sprzęt potrafi fizycznie wykonać `runtime <= deadline <= period`. Gdy zawiedzie lub algorytm "wybuchnie", system dokonuje zamrożenia zasobu (throttling)[cite: 27].
30
New cards
30. Prymityw synchronizacji w Shared Memory (1 zapis, X czytających) - RW-LOCK
By nie mordować pętli mutexem (który odcina zasób drastycznie nawet czytającym konsumentom), stosuje się specjalne rozwiązanie - Blokady Zapis/Odczyt wywoływane w bibliotece pthreads funkcją pthread_rwlock_init[cite: 50]. Zmienną strukturalną umieszcza się w samym trzonie strefy Pamięci Dzielonej (mmap) inicjalizując ją atrybutem rozproszonym PTHREAD_PROCESS_SHARED.
31
New cards
32. Skąd system z procesorem ARM wybiera odpowiedni sterownik sprzętowy?
Uzyskuje on te dane rozpakowując przy starcie Drzewo Urządzeń (z pliku dts). Odnajduje fizyczny adres sprzętu analizując właściwość `reg`, oraz ładuje odpowiedni moduł kernela sprawdzając pole definiujące autorską nazwę czyli węzeł `compatible`. By zapewnić widoczność nowym peryferiom, administrator dorzuca do /boot/ wpisy uaktywniające Nakładkę (Overlay) bez przebudowy.
32
New cards
34. Drzewo (np. I2C) vs Autodetekcja (np. USB) - wpięcie na żywym organizmie
(Rozszerzenie pkt 2). W przypadku USB (autodetekcja), kontroler po podpięciu napięcia informuje jądro (wywołuje przerwanie na szynie PCIe), po czym udev szuka odpowiedniego modułu kmod (na bazie VID/PID)[cite: 14]. Na "głuchym" magistralnym układzie I2C podłączenie kabla nie zmieni nic. Musimy zaktualizować na siłę Drzewo Urządzeń z wykorzystaniem mechanizmu Nakładek Ładowalnych lub modułu ładującego do wymuszenia inicjalizacji w locie.
33
New cards
35. Przepływ danych bez Kopiowania z synchronizacją (Mechanizmy) IPC
W trybie potoku wszystko oparte jest u jądra na podwójnym kopiowaniu User->Kernel->User. Jedynym wyjściem na komunikację procesów typu ZERO-COPY jest Pamięć dzielona (mmap). W jej puli by nie doprowadzić do "Race Conditions" kładziemy Zmienne Warunkowe (pthread_cond_init) pozwalające masowo budzić wstrzymane wątki gdy pojawi się pełny pakiet lub Mutexy nałożone na stany blokad[cite: 43, 44, 45, 46].
34
New cards
36. Różnice Pamięć Dzielona (SHM) vs Kolejka (MQ) i oczekiwanie "bez zużycia sprzętu CPU"
Kolejki wymuszają interwencję jądra przenosząc z rąk do rąk wiadomość jako kopię [cite: 37] - przez co powiadamianie jest wbudowane (z użyciem funkcji jak mq_receive - blokujących nasłuch w tle bez rzeźbienia po cyklach). Pamięć dzielona wyklucza z tego łańcucha jądro - procesy modyfikują surowe bajty pamięci RAM bezpośrednio obok siebie[cite: 40]. Oczekiwanie bez Pożerania CPU załatwia usypianie procesów na "Zmiennych Warunkowych"[cite: 46].
35
New cards
40. Zastosowanie Wielowątkowości vs Wieloprocesowości (+ Mechanizmy Synchronizacji)
a) Wielowątkowość jest idealna do równoległych operacji i macierzy przetwarzających gigantyczny wspólny model RAMu bez narzutu na IPC (np. analiza matrycy kamer). b) Architektura Wieloprocesowa (tzw. Multipracessing) jest bezpieczniejsza. Wykorzystywana w serwerach z architekturą rozproszonych uprawnień lub tam gdzie błąd (Segmentation Fault) nie ma prawa uśmiercić reszty serwera. c) Oba rozwiązania używają Mutexów. d) Specyficzne dla Procesów: IPC Potoki (Pipes).
36
New cards
43. Wydajne przesłanie (1 producent [A] do N-konsumentów [B]) oraz wymiana flag między nimi
Stosuje się Pamięć Dzieloną (shm_open i mmap) obłożoną Blokadami Zapis/Odczyt (pthread_rwlock), umożliwiającą jednoczesny odczyt wielu konsumentom[cite: 50]. Aplikacja Procesu "A" informuje czytelników B że porcja czeka na odbiór wysyłając systemowy "Puls" przy wykorzystaniu Zmiennych Warunkowych poprzez zrzut sygnału `pthread_cond_broadcast`[cite: 46]. Konsumenci po odczycie podbijają wartość Semaforowego Licznika, powiadamiając tym zwrotnie producenta.
37
New cards
44. Stronicowanie Pamięci (MMU) - korzyści i gigantyczny problem dla I/O z chipem
Jądro systemowe podsuwa programowi "Bajt po Bajcie" ładnie ułożone ciągłe złudzenia po 4 Kilobajty ("Ramki", "Strony") adresów. Przykłady korzyści: separacja procesów jako warstwa bezpieczeństwa przed przepełnieniem na serwerach [cite: 101, 112] oraz poszerzanie fizycznego sprzętu swapem. Utrudnienie Komunikacji: sprzęt zewnętrzny i jego kontrolery (np. DMA) wymuszają operowanie na ciągłym czystym fizycznym krzemie, co psuje ten model i wymusza stosowanie np. list SG.
38
New cards
48. Trzy tryby "podstawowe" bez rygoru czasu rzeczywistego (zastosowania) [cite: 22]
Zwykłe zadania użytkownika wykorzystują podział sprzętu by zaspokoić każdego "po równo". a) SCHED_OTHER (Zwykły cykliczny Time-Sharing): np. renderowanie nakładki GUI w sterowniku (zapewnia płynność interakcji użytkownika). b) SCHED_BATCH (tryb Masowy w tle): przydzielenie obróbki potężnych i nieczułych statystyk czy logów systemowych c) SCHED_IDLE (stan oczekiwania): odpala np. aktualizatora lub kompresję zip tylko, gdy cała reszta jądra stoi pusta w oczekiwaniu, i ma obciążenie na progu zerowym.
39
New cards
50-52-6. Algorytm EDF kontra RMS (oraz Analiza Drzewa Niezdatności)
Używanie algorytmów np. Earliest Deadline First (EDF) zawsze wyciąga na papierze wyższe limity niż statyczny Rate Monotonic (RMS) (do 100% użycia vs 69%)[cite: 96, 97]. Nieskuteczność powodowana może być sprzętową niemożnością spełnienia pętli. Do badania ryzyka [cite: 102] w systemach używa się struktury Drzewa Niezdatności (FTA) określającego tolerancję na uszkodzenia w celu identyfikacji tzw. elementów krytycznych, grożących śmiercią z powodu awarii (np. blokady Inwersji Priorytetów)[cite: 100, 103, 107].