2012-07-04 21 views
12

Jeden z opracowywanych przeze mnie sterowników jądra Linux używa komunikacji sieciowej w jądrze (sock_create(), sock->ops->bind() itd.).Symulacja efektu select() i poll() w programowaniu gniazda jądra

Problem polega na tym, że będzie wiele gniazd do odbioru danych. Potrzebuję więc czegoś, co zasymuluje przestrzeń select() lub poll() w przestrzeni jądra. Ponieważ te funkcje używają deskryptorów plików, nie mogę używać wywołań systemowych, chyba że używam wywołań systemowych do tworzenia gniazd, ale to wydaje się niepotrzebne, ponieważ pracuję w jądrze.

Tak więc myślałem o opakowaniu domyślnego handler'a sock->sk_data_ready w mojej własnej ładowarce (custom_sk_data_ready()), która odblokowałaby semafor. Następnie mogę napisać własną funkcję kernel_select(), która próbuje zablokować semafor i blokuje oczekiwanie, aż zostanie otwarta. W ten sposób funkcja jądra przechodzi w stan uśpienia, aż semafor zostanie odblokowany przez custom_sk_data_ready(). Po uzyskaniu blokady przez kernel_select() odblokowuje się i wywołuje custom_sk_data_ready(), aby ją ponownie zarchiwizować. Tak więc jedyną dodatkową inicjalizacją jest uruchomienie custom_sk_data_ready() przed związaniem gniazda, więc pierwsze wywołanie do custom_select() nie uruchamia się fałszywie.

Widzę jeden możliwy problem. Jeśli pojawi się wiele odbierających, wiele połączeń do custom_sk_data_ready() spróbuje odblokować semafor. Aby nie zgubić wielu połączeń i śledzić używane urządzenie sock, do używanych gniazd musi być tabela lub lista wskaźników. I custom_sk_data_ready() będzie musiał oznaczać w tabeli/liście, które gniazdo zostało przekazane.

Czy ta metoda brzmi? Czy powinienem po prostu zmagać się z problemem przestrzeni użytkownika/jądra podczas korzystania ze standardowych wywołań systemowych?

Znalezienie początkowa:

Wszystkie funkcje wywołania zwrotnego w strukturze sock są nazywane w kontekście przerwania. Oznacza to, że nie mogą spać. Aby główny wątek jądra mógł spać na liście gotowych gniazd, używane są muteksy, ale custom_sk_data_ready() musi działać jak spinlock na muteksach (wywołanie mutex_trylock()). Oznacza to również, że każda alokacja dynamiczna musi używać flagi GFP_ATOMIC.


Dodatkowa możliwość:

Dla każdego otwartego gniazda, wymienić każde gniazdo na sk_data_ready() ze zwyczajem jeden (custom_sk_data_ready()) i stworzyć pracownikowi (struct work_struct) i kolejkę pracy (struct workqueue_struct). Dla każdego pracownika będzie używana wspólna funkcja process_msg(). Utwórz globalną listę modułów na poziomie jądra, w której każdy element listy ma wskaźnik do gniazda i zawiera strukturę pracującą. Gdy dane są gotowe na gnieździe, custom_sk_data_ready() wykona i znajdzie pasujący element listy z tym samym gniazdem, a następnie wywoła queue_work() z kolejką roboczą elementu elementu i pracownikiem. Następnie zostanie wywołana funkcja process_msg() i można albo znaleźć zgodny element listy poprzez zawartość parametru struct work_struct * (adres), albo użyć makra container_of(), aby uzyskać adres struktury listy, która przechowuje strukturę pracownika.

Która technika jest najbardziej brzmieniowa?

+0

Nie możesz mieć programu pomocniczego przestrzeni użytkownika wykonującego 'poll'? Multipleksowanie danych wejściowych za pomocą 'poll' lub' select' jest związane z terminarzem (ponieważ proces wstrzymywania jest bezczynny, więc inne procesy mogą działać), więc nie zrobię tego wewnątrz jądra! –

+1

@BasileStarynkevitch: Właśnie dlatego próbuję symulować blokowanie trybu uśpienia 'poll()' i 'select()'. Używanie tych dwóch wywołań systemowych z jądra jest ostatecznością. Podejrzewam, że są problemy z uruchomieniem 'poll()' i 'select()' w helperie przestrzeni użytkownika. Pomocnik musi mieć dostęp do deskryptora pliku (czego nie robi się w 'sock_create()') i ewentualnie do uzyskania dostępu do gniazda znajdującego się w przestrzeni jądra. Tak więc teraz tworzenie gniazd musi nastąpić w helperie przestrzeni użytkownika, a moduł musi znaleźć gniazdo na podstawie deskryptora pliku przestrzeni użytkownika. Teraz staje się bardziej skomplikowana. – Joshua

+0

Nie powinieneś robić tego w jądrze. – mpe

Odpowiedz

3

Twój drugi pomysł brzmi bardziej, jakby zadziałał.

Kod CEPH wygląda, jakby był podobny, patrz net/ceph/messenger.c.