2011-04-19 7 views
6

Piszę kod programu działającego w czasie rzeczywistym w osadzonym systemie Linux. Ponieważ krytyczne jest to, że nie utkniemy nieprzewidywalnie na błędach stron, chciałbym przedostać się do stosu, aby region, którego używamy, był objęty rozmową mlockall().Jaki jest najlepszy sposób na przedostanie się do stosu w wątku pthreads?

Dla głównego wątku jest to dość proste; po prostu zrób kilka dużych alloca() s i pamiętaj, aby pisać co kilka stron. Działa to, ponieważ przy uruchamianiu programu limit stosu jest znacznie większy niż potrzebna; w końcu przydzielamy dokładnie ile mamy naprzód.

Jednak w przypadku stosów pthread, czy będą one również przydzielane za pomocą MAP_GROWSDOWN? Jeśli tak, to jaki jest najlepszy sposób na prefault je, biorąc pod uwagę, że:

  1. Nie wiemy, jaka część (znany) rozmiar stosu jest zużywana przez libc starcie
  2. Nie chcemy przeznaczyć więcej pamięci na stosie, niż jest to konieczne

Zdaję sobie sprawę, że mogę używać pthread_attr_setstack przejść w ręcznie przydzielone stosie, ale to komplikuje sprzątania po wątku i tak wolałbym tego uniknąć Jeśli to możliwe.

Jaki jest najlepszy sposób wykonania tego uzupełnienia? Byłoby wystarczające, gdyby istniał łatwy sposób na sprawdzenie dolnej granicy stosu (tuż nad stroną strażnika); w tym momencie mógłbym po prostu napisać do każdej strony stamtąd do bieżącego wskaźnika stosu.

Należy pamiętać, że przenoszenie nie jest problemem; chcielibyśmy mieć rozwiązanie, które działa tylko pod x86-32 i Linux.

Odpowiedz

3

Jeśli używasz pthread_attr_setstacksize, nadal możesz mieć automatyczne przydzielanie o znanym rozmiarze.

glibc nptl pozostawia strony ochronne między stosami, więc możesz również ustawić obsługę SEGV i po prostu pisać, dopóki nie popełnisz błędu, a następnie longjmp z pętli. To byłoby brzydkie!

Edytuj: Naprawdę nieprzenośny sposób polega na otwarciu /proc/self/maps, aby znaleźć stosy!

+0

Czy w umowie dotyczącej API istnieje gwarancja, że ​​'pthread_attr_setstacksize' nie użyje rzeczy podobnych do' GROWSDOWN', tj. Że 'mlockall()' natychmiast zastosuje się do całego stosu w czasie przydzielania bez dodatkowego wstępnego ? – bdonlan

+0

Stosy wątków są ograniczone do glibc nptl. Nie wiem od ręki, czy to część specyfikacji, ale podejrzewam, że tak jest. Szybki rzut oka pokazuje, że nptl również używa puli stosów, więc jeśli tworzysz/niszczycie wątki, twój kod nie powinien zawieść, jeśli otrzymasz "ciepły" stos. –

+0

Dobrze, myślę, że to na razie wystarczająco dobre dla nas - mam nadzieję, że nie wejdziemy w sytuację, w której strony blokują i tak :) – bdonlan

1

tak. jeśli wywołałeś mlockall (MCL_CURRENT | MCL_FUTURE) przed pthread_create, wystąpi błąd strony dla stosu wątków podczas uruchamiania wątku. i po tym nie będzie już błędu strony podczas uzyskiwania dostępu do stosu w wątku. , więc ludzie zawsze ustawiają odpowiedni rozmiar nici dla nowo utworzonego wątku, aby uniknąć zablokowania zbyt dużej ilości pamięci dla przyszłych nadchodzących wątków. przyjrzeć: https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example

jeśli zmienisz rozmiar gwintu stosu 7MB, widać: początkowa licznika: Pagefaults, kierunek: 0 (dozwolone> = 0), Minor: 190 (dozwolone> = 0) mlockall() generowane: Pagefaults, Major: 0 (dozwolone> = 0), mniejsze: 393 (dozwolone> = 0) malloc() i generowane dotyku: Pagefaults, Major: 0 (dozwolone> = 0), mniejsze: 25633 (Allowed> = 0) 2nd malloc() i generowane użycie: Pagefaults, Major: 0 (dozwolone 0), mniejsze: 0 (dozwolone 0)

Obejrzyj wyjście ps -leyf i zobacz, czy RSS ma teraz około 100 [MB] Naciśnij, aby wyjść Jestem gwintem RT z stosem, który nie generuje błędów stron podczas używania, stack = 7340032 Powodowany przez utworzenie wątku: Pagepliki, Major: 0 (dozwolone> = 0), Minor: 1797 (dozwolone> = 0) Spowodowane użyciem stosu wątków: Pagefaults, Major: 0 (dozwolone 0), mniejsze: 0 (dozwolone 0)

1797 błędów stron podczas tworzenia wątku, około 7 MB. -barry

Powiązane problemy