Linux kernel - planista, przerwania

0

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

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.

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.

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":

 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]

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
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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1