2011-04-19 1 views
6

저는 임베디드 리눅스 시스템에서 실행되는 실시간 프로그램을위한 코드를 작성하고 있습니다. 우리가 페이지 폴트에 예측할 수 없게 멈추지 않도록하는 것이 중요하므로, 우리가 사용하는 영역이 mlockall() 호출로 보장 될 수 있도록 스택에서 미리 오류를 내고 싶습니다.pthreads 스레드에 대해 스택에서 사전 오류를 방지하는 가장 좋은 방법은 무엇입니까?

주 스레드의 경우 이것은 간단합니다. 단순히 약간 큰 alloca()을하고 몇 페이지마다 쓰기를해야합니다. 이것은 프로그램 시작시 스택 제한이 필요한 양보다 훨씬 크기 때문에 작동합니다. 우리는 정확히 얼마나 많은 프리 퍼트를 할당 할까?

그러나 pthread 스택의 경우 MAP_GROWSDOWN을 사용하여 할당됩니까? 그렇다면, 점을 감안, 그들을 prefault하는 가장 좋은 방법은 무엇 :

  1. 우리는 libc의 시작에 의해 소비되는 방법 (알려진) 스택 크기의 많은 모른다는
  2. 우리는 할당하지 않으 보다 스택에 더 많은 메모리가 필요하다

내가 수동으로 할당 스택에 전달하는 pthread_attr_setstack을 사용할 수 있습니다 알고 있어요,하지만이 스레드 후 청소 복잡하고, 그래서이를 방지하기 원합니다 가능하다면.

이와 같이,이 prefaulting을 수행하는 가장 좋은 방법은 무엇입니까? 스택의 하한 (가드 페이지 바로 위)을 쉽게 찾을 수 있다면 충분할 것입니다. 이 시점에서 나는 모든 페이지를 현재 스택 포인터로 쓸 수 있습니다.

이식성은 문제가되지 않습니다. 우리는 x86-32 및 Linux에서만 작동하는 솔루션을 갖게되어 기쁩니다.

답변

3

pthread_attr_setstacksize을 사용하는 경우에도 알려진 크기의 자동 할당을 사용할 수 있습니다.

glibc nptl은 스택 사이에 가드 페이지를 남기므로 SEGV 핸들러를 설정하고 오류가 발생할 때까지 간단히 낙서 한 후 longjmp을 루프 밖으로 빠져 나올 수 있습니다. 그게 못생긴거야!

편집 : 실제로 이동할 수없는 방법은 /proc/self/maps을 열어 스택을 찾는 것입니다.

+0

'pthread_attr_setstacksize'는'GROWDDOWN'과 유사한 것을 사용하지 않는다는 보증이 있습니다. 즉,'mlockall()'은 추가적인 prefaulting없이 즉시 할당 할 때 전체 스택에 적용됩니다 ? – bdonlan

+0

스레드 스택은 모두 glibc nptl에 묶여 있습니다. 그것이 스펙의 일부라면 나는 알지 못한다. 그러나 나는 그것이 의심 스럽다. 빠른보기는 nptl이 스택 풀을 사용한다는 것을 보여줍니다. 따라서 스레드를 생성/파괴하고 있다면 "웜"스택을 얻으면 코드가 실패하지 않아야합니다. –

+0

괜찮아, 지금은 우리에게 충분하다고 생각해. 아마 우린 페이지가 어쨌든 차단되는 상황에 빠지지 않을거야. :) – bdonlan

1

예. pthread_create 전에 mlockall (MCL_CURRENT | MCL_FUTURE)을 호출했다면 스레드를 시작할 때 스레드 스택의 페이지 오류가 발생합니다. 그 후에 스레드의 스택에 액세스하는 동안 페이지 폴트가 다시 발생하지 않습니다. 그래서 사람들은 앞으로 생성 될 스레드에 대해 너무 많은 메모리를 잠그지 않도록 항상 새로 생성 된 스레드에 적합한 스레드 크기를 설정합니다.당신이 7메가바이트에 스레드 스택의 크기를 변경하는 경우 가 https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example

, 당신은 볼 수 있습니다 : 을 살펴 초기 횟수 : 주요 Pagefaults : 190 (허용> = 0 : 0, 마이너가 (> = 0 허용) 0f (허용됨 = 0) mlockall() 생성 : Pagefaults, Major : 0 (허용됨 = 0), Minor : 393 (허용됨 = 0) malloc 25633 (허용> = 0) 두 번째 malloc() 및 생성 사용 : Pagefaults, Major : 0 (허용됨 0), Minor : 0 (허용됨 0)

ps -leyf의 출력을보고 RSS는 이제 약 100 [MB]입니다. 종료하려면 누릅니다. 사용하는 동안 페이지 폴트를 생성하지 않는 스택이있는 RT 스레드입니다. stacksize = 7340032 페이지 폴트, 메이저 : 0 (허용 된 값 = 0), 마이너 : 1797 (허용 된 값 = 0) 스레드를 사용하여 발생합니다. 페이지 폴트, 메이저 : 0 (허용됨 0), 마이너 : 0 (허용됨 0)

1797 스레드를 생성하는 동안 페이지 폴트가 발생하면 약 7MB입니다. -barry

관련 문제