리눅스에서 지원하는 pi-futex 에 대해 질문합니다..
리눅스에서 pi-futex 에 관한 내용을 보고, priority inheritance 를 어떤 식으로
지원하는지에 대해 많이 검색해보고 있으나 정보 수집이 어려워서 질문을 올려봅니다.
기본적으로 futex_lock_pi / futex_unlock_pi 를 비롯해서 futex_wait_requeue_pi / futex_cmp_requeue_pi(이건 futex_requeue)
등의 시스템 콜이 지원되고 있는데, 여기서 여러모로 잘 이해가 안되는 부분이 몇 가지 있습니다.
이런 pi 가 붙은 시스템 콜들은 모두 priority inheritance 를 유저 모드에서 구현하기 "위한" 시스템 콜인가요?
아니면 이미 내부적으로 priority inheritance 를 지원하고 있다는 의미인가요?
구현을 유저 레벨에 맡기는 건지 아니면 내부적으로 지원하는 시스템 콜을 따로 만들어놓은건지 헷갈립니다.
가령 일반적인 futex 의 경우 userspace lock 이고 실제 구현하는 건 유저 레벨에 맡기고 있어서
실제로 glibc의 pthread(nptl) 에서는 lll_futex_wait / lll_futex_wake 등의 함수를 어셈블리로
작성해서 cmpxchg 나 xchg 등의 atomic operation 을 직접 써서 유저 레벨에서 락이 이미 다른 쓰레드가
잡고있는지 체크하고 안 잡고있으면 그냥 바로 락을 잡는 것을 xchg 계열 operation 으로 직접 처리하고 있는데
이처럼 pi-futex 역시 실제적인 priority inheritance 의 구현을 유저 레벨에 맡기는 것인지 궁금합니다.
즉 futex_wait_requeue_pi 와 futex_cmp_requeue_pi, futex_lock_pi, futex_unlock_pi 등의
시스템 콜을 이리저리 조합하고 유저 레벨 코드와 합쳐서 전체적으로 우선순위 역전을 피하는 것인지(구현은 라이브러리가 맡고)
아니면 이 시스템 콜 자체만으로 내부적으로 이미 우선순위 상속이 자동으로 되는 건가요?
사실 영어에 약해서 linux documentation 에 있는 pi-futex 등의 문서들을 읽어보려고 해도
잘 해석이 안되고 의미 파악이 분명치 않아서 여러모로 어려움을 겪고 있습니다..
또한 궁금한 점이 glibc 소스를 보면 pthread_mutex_lock 이나 pthread_mutex_unlock 등의 함수 내에서는
futex_lock_pi 와 futex_unlock_pi 를 사용하는 것으로 보이고 뒤의 requeue_pi 계열 함수는 사용을 하지 않는 것으로 보이고
그것도 처음 부분 코드에서 보면 아래와 같은 코드가 있는데..
unsigned int type = PTHREAD_MUTEX_TYPE (mutex);
if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0))
return __pthread_mutex_lock_full (mutex);
( ↑ 지금은 haswell 의 Lock Ellision 지원으로 인해 코드가 좀 더 추가되어 바뀌었지만)
위와 같은 조건에서 __pthread_mutex_lock_full 로 들어가는데, 제가 일반적으로 어플리케이션에서
사용하는 것처럼 락을 사용해서 디버깅 해보면 저 __pthread_mutex_lock_full 함수 호출은 되지 않고
아래쪽에서 그냥 바로 lll_futex_wait 로 들어가서 futex_wait / futex_wake 호출로 가버리는 것 같습니다.
PTHREAD_MUTEX_KIND_MASK_NP 가 무슨 의미의 타입인지도 검색해도 안나와서 잘 모르겠네요.
pthread_cond_~ 계열 함수에서는 requeue_pi 계열 함수를 사용하는 것으로 보이기는 하는데,
결과적으로 궁금한 것은 priority inheritance 의 구현은 pthread(nptl) 이 어느정도 역할을 맡는 건가요?
사실 우선순위가 역전되도록 예제 코드를 만들어보고 싶어도 개별 쓰레드 우선순위 설정하는 것부터 영 막혀서 잘 안되네요.
대략적으로 알려주시면 정말 감사하겠습니다.
댓글 달기