Linux kernel - planista, przerwania

Linux kernel - planista, przerwania
0

Cześć,
kernel/softirq.c (podany przeze mnie kod obecnie może nie być już aktualny):

Kopiuj
asmlinkage void schedule(void) {

/*...*/

/*Wywołaj wolne procedury obsługi przerwań, tzw. "bottom halves". Funkcja ta zaimplementowana jest w pliku kernel/softirq.c. */
if (bh_active & bh_mask) {
		intr_count = 1;
		do_bottom_half();
		intr_count = 0;
	}
/*...*/
}

Dlaczego mamy intr_count=1, intr_count=0, a nie intr_count++, intr_count-- (mamy jakąś gwarancję, że przed do_bottom_half nie działa żadna procedura obsługi przerwań? skąd? mamy gwarancję, że bo do_bottom_half nowe procedury nie zostaną wywołane? jeżeli tak, to skąd?).

http://students.mimuw.edu.pl/SO/LabLinux/PROCESY/ZRODLA/sched.c.html

Pozdrawiam.

__krzysiek85
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 9 lat
  • Postów:1019
0

Czy to jest Linux 2.0?

http://pl.wikipedia.org/wiki/Wyw%C5%82aszczenie_%28informatyka%29

W jądrze Linuksa przed wersją 2.6 niemożliwe było wywłaszczenie procesu, który znajdował się w trybie jądra, co w pewnych sytuacjach mogło być powodem bardzo wolnej reakcji na działania użytkownika.


Registered Linux user #456405 | SCJP 6 | SCWCD 5 | SCBCD 5
0

Dzięki za odpowiedź,
tak, to jest jądro 2.0 (ew. może czasami może być mowa o 2.1), OK, rozumiem, analizowałem to chwilę i pojawiły mi się następujące wątpliwości (podaję, ponieważ może przyda się to komu innemu, chcącemu zrozumieć mechanizm pracy schedulera):
Czy schedule() jest funkcją działającą w trybie jądra?
Czy do_bottom_half() jest funkcją działającą w trybie jądra?
Na górze strony, do której podałem link czytamy:

[quote]do_bottom_half() runs at normal kernel priority: all interrupts

  • enabled. do_bottom_half() is atomic with respect to itself: a
  • bottom_half handler need not be re-entrant.[/quote]

Nie wiem, czy atomiczność jest dokładnie tym samym, co działanie w trybie jądra, ale OK, rozumiem, że w trakcie wykonywania dolnych połówek inne procedury obsługi przerwań nie mogą być wywołane. Jednakże wyobrażam sobie następującą sytuację: wykonywanie funkcji do_bottom_half jest już zakończone, ale intr_count=0 nie zostało jeszcze wykonane, zostaje zgłoszone nowe przerwanie i licznik intr_count zostaje zwiększone do 1. Następnie wykonywane jest intr_count=0 i licznik aktywnych dolnych połówek zostaje błędnie zmniejszony do zera... STOP. intr_count nie jest licznikiem aktywnych dolnych połówek, tylko AKTUALNIE URUCHOMIONYCH procedur obsługi przerwań.

Swoją drogą w tym kontekście interesujące jest, jak owa tomiczność jest realizowana (cytat z książki Becka i in., s. 207):

quote Części te mają właśność atomiczności, to znaczy, tak długo jak dolna część jest aktywna, nie można wykonywać żadnej z pozostałych, więc nie jest konieczne używanie cli() w celu zabezpieczenia ich przed przerwaniami.[/quote]

Czy zatem funkcja do_bottom_half() wywołuje cli()? Oczywiście tutaj może pomóc analiza kodu źródłowego do_bottom_half().

Jeszcze raz dzięki za odpowiedź :).

0

Może jeszcze kilka pytań:
Beck i in. podają następujący kod na str. 61 "wywołania systemowe":

Kopiuj
 PSEUDO_CODE system_call(int sys_call_num, sys_call_args) {

/*...*/

I teraz przed poniższym fragmentem komentarz autorów:

[quote]Rzeczywiste zadanie wywołania systemowego jest w tym miejscu zakończone. Jednak zanim będzie można kontynuować wykonywanie procesu, trzeba jeszcze uporać się z pewnymi zadaniami administracyjnymi. W rzeczywistości poniższy kod wykonywany jest nie tylko po każdym wywołaniu systemowym, ale również po każdym "wolnym" przerwaniu i z tego powodu zawiera pewne instrukcje, które mają znaczenie tylko dla procedur obsługi przerwań. [/quote]

Wcześniej zastanawiałem się jak to możliwe, iż po wolnym przerwaniu jest wykonywana część kodu funkcji system_call, ale zacząłem się domyślać (nie wiem czy słusznie), iż musi być to realizowane przez skok goto. Jednak nasuwa się mi pytanie: dlaczego w takim razie ret_from_sys_call jest umieszczone w funkcji system_call? Czy nie lepiej umieścić tę część kodu w całkiem innej funkcji i nadać jej jakąś nazwę, która lepiej oddawałaby jej przeznaczenie?

[quote]Ponieważ całkiem prawdopodobne jest zagnieżdżenie jednej procedury obsługi przerwania w drugiej, zmienna intr_count zarządza głębokością zagnieżdżeń procedur obsługi przerwań. Jeśli nie ma ona wartości zero, oznacza to, że została przerwana kolejna procedura obsługi przerwań i funkcja ret_from_sys_call natychmiast zwraca sterowanie.[/quote]

Kopiuj
ret_from_sys_call:
   if (intr_count) goto exit_now;
   if (bh_mask & bh_active) {
       handle_bottom_half:
           ++intr_count;
           sti();
           do_bottom_half();
           --intr_count;
   }
   sti();[/code]

Czy tutaj ++intr_count, --intr_count jest równoważne intr_count=1, intr_count=0? Jeżeli nie, to jestem nieco zmieszany - przecież przed chwilą sprawdzaliśmy, czy intr_count nie jest równe zero! Jeżeli istotnie może się zdarzyć taka sytuacja, że inkrementacja intr_count może dać wartość różną od jedynki, to widzę tutaj tylko jedną możliwość - mianowicie musiało dojść do przełączenia zadań przez scheduler. W związku z tym pytanie: czy powyższy kod jest wywoływany w sposób atomowy? Jeżeli tak nie jest, to IMO przetwarzanie powyższego kodu może się zakończyć fatalnie - tzn. po inkrementacji intr_count (ale jeszcze przed sti()) scheduler może przekazać procesorowi do wykonywania inne zadanie, to zadanie spowoduje zwiększenie intr_count, tuż po tej instrukcji scheduler przełączy się znowu na powyższy kod i w efekcie otrzymamy błędne wartości intr_count. 
Dalej, mamy tu instrukcję sti(), ale nie do końca rozumiem celowości jej zamieszczenia tutaj - powoduje ona odblokowanie przerwań, ale z jakiego powodu przerwania wcześniej miałyby być zablokowane? Wyżej nigdzie nie ma instrukcji cli() (w kodzie w /*...*/ też nie).
Ponadto, na samym początku mamy instrukcję: if (bh_mask & bh_active) - czyli w masce możemy wyłączyć wykonywanie niektórych dolnych połówek (po prostu ustawiając odpowiednie bity na zera). Jaki jest konkretny, uchwytny przykład sytuacji, w której ma to zastosowanie?

[quote]Od tego momentu przerwania są na ogół odblokowywane.[/quote]

Jak to na ogół? Chyba sti() wymusza odblokowanie przerwań, nie widzę wyżej jakiego powodu do używania trybu warunkowego.

[quote]Jeśli do bieżącego procesu zostały wysłane sygnały i nie zablokował on ich odbierania, są teraz przetwarzane. (...) [/quote]

```c
if (current->signal & ~current->blocked) {
0
Kopiuj
if (current->signal & ~current->blocked) {
   signal_return: do_signal();
}

OK, ale nasuwa mi się tutaj kolejne pytanie - w którym momencie, są obsługiwane sygnały, których odbieranie zostało zablokowane przez proces?


> (...)


```c
exit_now: RESTORE_ALL;<code>

Tutaj jeszcze mam pytanie do wcześniejszej wypowiedzi autorów:


> Ponieważ całkiem prawdopodobne jest zagnieżdżenie jednej procedury obsługi przerwania w drugiej, zmienna intr_count zarządza głębokością zagnieżdżeń procedur obsługi przerwań. Jeśli nie ma ona wartości zero, oznacza to, że została przerwana kolejna procedura obsługi przerwań i funkcja ret_from_sys_call natychmiast zwraca sterowanie.


Z tonu tego zdania rozumiem, że jest to absolutnie konieczne. Dlaczego?

Będę wdzięczny za rozwianie powyższych wątpliwości.

Pozdrawiam.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)