Dołącz do grona twórców popularności Linuksa
Fenomen Linuksa polega na tym, że jest on dziełem programistów z całego świata. Każdy może dopisać do niego nową funkcję lub udoskonalić istniejące. Jeśli Linux nie obsługuje urządzenia zainstalowanego w Twoim komputerze -- możesz zaimplementować jego obsługę, pisząc własny moduł jądra.
Programowanie jądra systemu Linux nie wymaga żadnych niezwykłych zdolności. Choć jest ono rozległym projektem informatycznym, w żaden sposób nie różni się od innych projektów tego typu. Oczywiście, samodzielne napisanie choćby kawałka kodu jądra wymaga nauki, ale napisany dotychczas kod nie jest w żaden sposób wyjątkowy ani niezrozumiały. Podstawowym materiałem pomocniczym, niezwykle przydatnym przy opanowywaniu tajników programowania jądra, jest istniejący już kod źródłowy, dostępny dla wszystkich. Jednakże samo poznawanie kodu nie wystarczy -- należy również zdobyć wiedzę dotyczącą zasad funkcjonowania systemu operacyjnego i pełnionych przez niego funkcji.
Książka "Linux Kernel. Przewodnik programisty" została napisana po to, aby pomóc programistom w poznaniu zasad tworzenia kodu modułów jądra. Szczegółowo omawia podsystemy i funkcje jądra Linuksa, ich projekt i implementację. Autor książki porusza również zagadnienia związane z projektowaniem systemów operacyjnych.
Książka opiera się na wersji 2.6 jądra systemu Linux i zawiera informacje dotyczące następujących tematów:
-
Podstawowe zasady programowania jądra
-
Zarządzanie procesami
-
Algorytmy szeregowania zadań
-
Wywołania systemowe
-
Przerwania
-
Metody synchronizacji jądra
-
Zarządzanie czasem i pamięcią
-
Operacje wejścia -- wyjścia
-
Diagnostyka kodu jądra
-
Przenośność kodu
Stwórz poprawne funkcje jądra Linuksa i zaimplementuj je w odpowiedni sposób.
SPIS TREŚCI:
O Autorze (13)
Przedmowa (15)
Wstęp (17)
Słowo od Autora (19)
Rozdział 1. Jądro systemu Linux - wprowadzenie (23)
-
Wprowadzenie do systemu Linux (25)
-
Przegląd systemów operacyjnych (26)
-
Jądro Linuksa a jądro klasycznego systemu uniksowego (28)
-
Oznaczenia wersji jądra Linuksa (29)
-
Społeczność programistów jądra systemu Linux (31)
-
Odmienność jądra (31)
-
Brak biblioteki libc (32)
-
GNU C (32)
-
Brak mechanizmu ochrony pamięci (34)
-
Niemożność (łatwego) korzystania z operacji zmiennoprzecinkowych (35)
-
Ograniczony co do rozmiaru i stały stos (35)
-
Synchronizacja i współbieżność (35)
-
Znaczenie przenośności (36)
-
Kompilowanie jądra (36)
-
Zanim zaczniemy (38)
Rozdział 2. Zarządzanie procesami (39)
-
Deskryptor procesu i struktura zadania (40)
-
Alokacja deskryptora procesu (41)
-
Przechowywanie deskryptora procesu (42)
-
Stan procesu (43)
-
Manipulowanie bieżącym stanem procesu (44)
-
Kontekst procesu (45)
-
Tworzenie procesu (46)
-
Kopiowanie przy zapisie (47)
-
Wywołanie fork() (47)
-
Wywołanie vfork() (49)
-
Wątki w systemie Linux (49)
-
Zakończenie procesu (52)
-
Usuwanie deskryptora procesu (53)
-
Problem zadań osieroconych (54)
Rozdział 3. Szeregowanie zadań (57)
-
Strategia postępowania (58)
-
Procesy ograniczone wejściem-wyjściem a procesy ograniczone procesorem (58)
-
Priorytet procesu (59)
-
Kwant czasu (60)
-
Wywłaszczanie procesu (61)
-
Strategia szeregowania w działaniu (61)
-
Algorytm szeregujący (62)
-
Kolejka procesów gotowych do uruchomienia (62)
-
Tablice priorytetów (65)
-
Przeliczanie kwantów czasu (66)
-
Wywołanie schedule() (67)
-
Wyznaczanie nowego priorytetu i kwantu czasu (68)
-
Zawieszanie i pobudzanie procesów (71)
-
Równoważenie obciążenia (73)
-
Wywłaszczanie i przełączanie kontekstu (75)
-
Wywłaszczanie procesu użytkownika (76)
-
Wywłaszczenie jądra (76)
-
Czas rzeczywisty (77)
-
Wywołania systemowe związane z szeregowaniem (78)
-
Wywołania wpływające na strategię szeregowania i wartości priorytetów (79)
-
Wywołania systemowe sterujące kojarzeniem procesów z procesorami (80)
-
Odstąpienie procesora (80)
Rozdział 4. Wywołania systemowe (81)
-
API, POSIX i biblioteka C (82)
-
Wywołania systemowe (83)
-
Numery wywołań systemowych (84)
-
Wydajność wywołania systemowego (85)
-
Procedura obsługi wywołań systemowych (85)
-
Oznaczanie właściwego wywołania systemowego (86)
-
Przekazywanie argumentów (86)
-
Implementacja wywołania systemowego (87)
-
Weryfikacja argumentów (87)
-
Kontekst wywołania systemowego (89)
-
Wiązanie wywołania systemowego (90)
-
Inicjowanie wywołania systemowego z przestrzeni użytkownika (92)
-
Cztery powody, aby nie implementować wywołań systemowych (93)
Rozdział 5. Przerwania i procedury obsługi przerwań (95)
-
Przerwania (95)
-
Procedury obsługi przerwań (96)
-
Połówki górne i dolne (97)
-
Rejestrowanie procedury obsługi przerwania (98)
-
Zwalnianie procedury obsługi przerwania (100)
-
Tworzenie procedury obsługi przerwań (100)
-
Procedury obsługi przerwań współużytkowanych (102)
-
Prawdziwa procedura obsługi przerwania (103)
-
Kontekst przerwania (104)
-
Implementacja obsługi przerwań (105)
-
/proc/interrupts (108)
-
Kontrola przerwań (109)
-
Wyłączanie i włączanie przerwań (110)
-
Blokowanie konkretnej linii przerwania (111)
-
Stan systemu przerwań (112)
Rozdział 6. Dolne połówki i czynności odroczone (115)
-
Połówki dolne (116)
-
Po co dolne połówki? (117)
-
Świat dolnych połówek (117)
-
Przerwania programowe (120)
-
Implementacja przerwań programowych (120)
-
Korzystanie z przerwań programowych (123)
-
Tasklety (125)
-
Implementacja taskletów (125)
-
Korzystanie z taskletów (128)
-
Wątek jądra ksoftirqd (130)
-
Dawny mechanizm BH (132)
-
Kolejki robót (133)
-
Implementacja kolejek robót (133)
-
Korzystanie z kolejek robót (137)
-
Dawny mechanizm kolejkowania zadań (140)
-
Jak wybrać implementację dolnej połówki? (140)
-
Blokowanie pomiędzy dolnymi połówkami (142)
-
Wyłączanie dolnych połówek (142)
Rozdział 7. Wprowadzenie do synchronizacji jądra (145)
-
Sekcje krytyczne i przeplot operacji (146)
-
Blokowanie (147)
-
Skąd się bierze współbieżność? (149)
-
Co wymaga zabezpieczania? (150)
-
Zakleszczenia (151)
-
Rywalizacja a skalowalność (154)
-
Blokowanie we własnym kodzie (155)
Rozdział 8. Metody synchronizacji jądra (157)
-
Operacje niepodzielne (157)
-
Niepodzielne operacje na liczbach całkowitych (158)
-
Niepodzielne operacje bitowe (160)
-
Rygle pętlowe (162)
-
Inne metody blokowania ryglami pętlowymi (165)
-
Rygle pętlowe a dolne połówki (166)
-
Rygle pętlowe R-W (166)
-
Semafory (168)
-
Tworzenie i inicjalizowanie semaforów (170)
-
Korzystanie z semaforów (171)
-
Semafory R-W (172)
-
Zmienne sygnałowe (174)
-
Blokada BKL (Big Kernel Lock) (174)
-
Blokady sekwencyjne (176)
-
Blokowanie wywłaszczania (177)
-
Bariery (178)
Rozdział 9. Liczniki i zarządzanie czasem (183)
-
Czas z punktu widzenia jądra (184)
-
Częstotliwość taktowania - HZ (185)
-
Optymalna wartość HZ (186)
-
Chwilki (188)
-
Wewnętrzna reprezentacja zmiennej jiffies (190)
-
Zawijanie zmiennej jiffies (191)
-
HZ a przestrzeń użytkownika (192)
-
Zegary i liczniki sprzętowe (193)
-
Zegar czasu rzeczywistego (193)
-
Zegar systemowy (193)
-
Procedura obsługi przerwania zegarowego (194)
-
Data i godzina (196)
-
Liczniki (198)
-
Korzystanie z liczników (199)
-
Liczniki i sytuacje hazardowe (201)
-
Implementacja licznika (201)
-
Opóźnianie wykonania (202)
-
Oczekiwanie w pętli aktywnej (202)
-
Krótkie opóźnienia (204)
-
Funkcja schedule_timeout() (205)
Rozdział 10. Zarządzanie pamięcią (209)
-
Strony (209)
-
Strefy (211)
-
Pozyskiwanie stron pamięci (213)
-
Pozyskiwanie czystych stron pamięci (214)
-
Zwalnianie stron (215)
-
Funkcja kmalloc () (216)
-
Funkcja kfree() (221)
-
Funkcja vmalloc () (222)
-
Alokator plastrowy (223)
-
Zadania alokatora plastrowego (224)
-
Interfejs alokatora plastrowego (227)
-
Statyczne przydziały na stosie (230)
-
Odwzorowanie pamięci wysokiej (231)
-
Odwzorowanie trwałe (231)
-
Odwzorowania czasowe (232)
-
Jak metodę przydziału wybrać? (233)
Rozdział 11. Wirtualny system plików (235)
-
Wspólny interfejs systemu plików (235)
-
Warstwa abstrakcji systemu plików (236)
-
Uniksowy system plików (237)
-
Obiekty VFS i ich struktury danych (238)
-
Inne obiekty warstwy VFS (239)
-
Obiekt bloku głównego (240)
-
Operacje bloku głównego (241)
-
Obiekt i-węzła (243)
-
Obiekt wpisu katalogowego (247)
-
Stan wpisu katalogowego (249)
-
Bufor wpisów katalogowych (249)
-
Operacje na wpisach katalogowych (251)
-
Obiekt pliku (252)
-
Operacje na plikach (253)
-
Struktury danych systemu plików (256)
-
Struktury danych procesu (257)
-
Systemy plików w Linuksie (259)
Rozdział 12. Blokowe urządzenia wejścia-wyjścia (261)
-
Anatomia urządzenia blokowego (262)
-
Bufory i nagłówki buforów (263)
-
Struktura bio (266)
-
Kolejki zleceń (269)
-
Zawiadywanie operacjami wejścia-wyjścia (269)
-
Zadania planisty operacji wejścia-wyjścia (270)
-
Winda Linusa (271)
-
Terminowy planista operacji wejścia-wyjścia (272)
-
Przewidujący planista operacji wejścia-wyjścia (274)
Rozdział 13. Przestrzeń adresowa procesu (277)
-
Deskryptor pamięci (279)
-
Przydział deskryptora pamięci (280)
-
Zwalnianie deskryptora pamięci (281)
-
Struktura mm_struct i wątki jądra (281)
-
Obszary pamięci (282)
-
Znaczniki VMA (283)
-
Operacje VMA (284)
-
Obszary pamięci na listach i w drzewach (285)
-
Obszary pamięci w praktyce (286)
-
Manipulowanie obszarami pamięci (288)
-
Funkcja find_vma() (288)
-
Funkcja find_vma_prev() (289)
-
Funkcja find_vma_intersection() (289)
-
Tworzenie interwału adresów - wywołania mmap() i do_mmap() (290)
-
Wywołanie systemowe mmap() (292)
-
Usuwanie interwału adresów - wywołania munmap() i do_munmap() (292)
-
Wywołanie systemowe munmap() (292)
-
Tablice stron (293)
Rozdział 14. Pamięć podręczna stron i opóźniony zapis stron w tle (295)
-
Pamięć podręczna stron (296)
-
Obiekt address_space (297)
-
Drzewo pozycyjne (300)
-
Tablica skrótów stron (300)
-
Pamięć podręczna buforów (301)
-
Demon pdflush (301)
-
bdflush i kupdated (303)
-
Eliminowanie przeciążenia, czyli po co w jądrze wiele wątków? (303)
Rozdział 15. Diagnostyka (305)
-
Od czego zacząć? (305)
-
Błędy w jądrze (306)
-
Funkcja printk() (307)
-
Wszechstronność funkcji printk() (307)
-
Ograniczenia funkcji printk() (307)
-
Poziomy rejestrowania (308)
-
Bufor komunikatów (309)
-
Demony syslogd i klogd (310)
-
Funkcja printk() a hakerzy jądra (310)
-
Błąd oops (310)
-
Polecenie ksymoops (312)
-
kallsyms (313)
-
Opcje diagnostyczne jądra (313)
-
Diagnostyka niepodzielności operacji (313)
-
Prowokowanie błędów i wyprowadzanie informacji (314)
-
Funkcja Magic SysRq Key (315)
-
Saga debugera jądra (315)
-
gdb (316)
-
kgdb (317)
-
kdb (318)
-
Stymulowanie i sondowanie systemu (318)
-
Uzależnianie wykonania kodu od identyfikatora UID (318)
-
Korzystanie ze zmiennych warunkowych (319)
-
Korzystanie ze statystyk (319)
-
Ograniczanie częstotliwości komunikatów diagnostycznych (319)
-
Szukanie winowajcy - wyszukiwanie binarne (321)
-
Koledzy - kiedy wszystko inne zawiedzie (322)
Rozdział 16. Przenośność (323)
-
Historia przenośności systemu Linux (325)
-
Rozmiar słowa i typy danych (326)
-
Typy nieprzejrzyste (328)
-
Typy specjalne (329)
-
Typy o zadanych rozmiarach (329)
-
Znak typu char (330)
-
Wyrównanie danych (331)
-
Unikanie problemów wyrównywania (331)
-
Wyrównanie typów niestandardowych (332)
-
Dopełnienie struktury (332)
-
Wzajemny porządek bajtów (333)
-
Typy wzajemnego porządku bajtów - rys historyczny (335)
-
Wzajemny porządek bajtów w jądrze (335)
-
Pomiar upływu czasu (336)
-
Rozmiar strony (336)
-
Kolejność wykonywania instrukcji (337)
-
Tryb SMP, wywłaszczanie jądra i pamięć wysoka (338)
-
Przenośność to wyzwanie (338)
Rozdział 17. Łaty, haking i społeczność (339)
-
Społeczność (339)
-
Obowiązujący styl kodowania (340)
-
Wcięcia (341)
-
Nawiasy klamrowe (341)
-
Nazewnictwo (342)
-
Funkcje (342)
-
Komentarze (343)
-
Definicje typów (344)
-
Korzystanie z zastanego (344)
-
Unikanie definicji ifdef w kodzie źródłowym (344)
-
Inicjalizacja struktur (345)
-
Poprawianie złego stylu (345)
-
Łańcuch poleceń (346)
-
Przesyłanie raportów o błędach (346)
-
Generowanie łat (347)
-
Rozsyłanie łat (348)
Dodatek A Korzystanie z list (351)
-
Listy cykliczne (351)
-
Poruszanie się pomiędzy elementami listy (352)
-
Implementacja listy w jądrze Linuksa (353)
-
Manipulowanie listami (354)
-
Przeglądanie list (356)
Dodatek B Interfejs procesora (359)
-
Nowy interfejs procesora (360)
-
Statyczne dane procesora (360)
-
Dynamiczne dane procesora (361)
-
Po co korzystać z danych procesora? (362)
Dodatek C Generator liczb losowych jądra (365)
-
Projekt i implementacja puli entropii (366)
-
Problem rozruchu programu (368)
-
Interfejs wejściowy puli entropii (368)
-
Interfejs wyjściowy puli entropii (369)
Dodatek D Złożoność obliczeniowa (371)
-
Algorytmy (371)
-
Zapis złożoności O(x) (372)
-
Notacja duże theta (372)
-
Co z tego wynika? (373)
-
Pułapki złożoności czasowej (373)
Dodatek E Bibliografia i lektury dodatkowe (375)
-
Książki o projektowaniu systemów operacyjnych (375)
-
Książki o jądrze systemu Unix (376)
-
Książki o jądrze systemu Linux (377)
-
Książki o jądrach innych systemów operacyjnych (377)
-
Książki o interfejsie programowym Uniksa (377)
-
Inne książki (378)
-
Witryny WWW (378)
Skorowidz (381)