2010-01-25 1 views
4

우리는 ARM 코어 (임베디드 시스템)에서 시스템을 빌드하는 데 C를 사용하고 있습니다. 문제는 공식적인 방식으로 재진입 문제를 피하면서 어떻게 모든 재진입 버그가 제거되었는지 확신 할 수있는 방법입니다. 이것은 실제적인 희망은 아니지만 모든 시스템에서 반드시 중요 할 수 있습니다."재진입"문제를 피할 수있는 체계적인 방법? (임베디드 시스템)

그냥 논의를 위해, 나는 UML 다이어그램을 그리는 것 같아요 또는 완전한 상태 기계가 좋은 시작이 될 것 같아요 (그러나 어떻게 전체 시스템이 개발 된 후 그것을 생성 할 수 있습니까?). 상태 머신/UML 다이어그램을 사용하여 분석을 수행하는 방법에 대한 제안 사항은 무엇입니까?

답변

4

저는 여러분이 해결하고자하는 문제에 대해서는 정확히 알지 못하지만, 교육 된 추측을하도록하겠습니다.

첫 번째 요점은 문제가 될 수있는 기능을 식별하는 것입니다. 재진입은 재귀 호출에 의해 발생합니다. 재귀 호출은 여러 개의 중첩 호출을 거쳐 콜백/종속성 삽입이나 여러 스레드에서 사용되는 함수에 의해 숨겨 질 수 있습니다.

다이렉트 콜 그래프를 그릴 수 있습니다. 함수 A가 B와 C를 호출하고, 함수 B가 D, E와 F를 호출하며, 함수 C는 아무 것도 호출하지 않는다는 식으로 말합니다. 멀티 스레드 할 때 각 스레드에 대해 이것을 그립니다. 그래프에 사이클이있는 경우이 사이클을 만드는 모든 함수는 재진입 가능해야합니다. 이 경우 하위 분기를 무시할 수 있습니다. 여러 스레드에서 사용되는 함수는 안전해야하지만 모든 스레드가 현재 어디에 있는지 정확히 알지 못하므로 모든 하위 분기를 포함해야합니다. 잠금 장치를 사용할 때 상황이 복잡해지고 복잡해 지므로 지금 당장이를 무시하겠습니다.

이 단계는 코드 분석 도구로 반드시 자동화 할 수 있습니다. 이제 기능이 식별되는지

, 그들의 기능 - 로컬 데이터에 의존

  • 기능은 일반적으로 안전합니다. 이것은 함수형 프로그래밍의 훌륭한 특성 중 하나입니다.
  • (기능 범위가 아닌) 외부 데이터에 의존하는 기능을 면밀히 검토해야하며 외부 데이터가 언제 어디서 변경되는지를 아는 것이 특히 중요합니다.
  • 외부 데이터를 변경하는 기능은 특히 멀티 스레딩시 빨간색 플래그를 발생시키고 시끄러운 알람 사이렌을 활성화해야합니다.
+1

내가 이런 종류의 코드 검사를 할 때 내가 본 첫 번째 장소는 내 전역에있다. 전역 변수에 직접 액세스/조작하는 함수는 일반적으로 가장 많은 재진입 문제가있는 함수입니다. Secure가 언급했듯이 함수 인수 나 내부 데이터 만 수정하는 함수는 대개 OK입니다. 호출하는 라이브러리 함수 (표준 라이브러리 함수 포함)가 스레드로부터 안전하다는 것을 확인하는 것을 잊지 마십시오! – bta

+0

알았습니다. 보안을 위해 & bta에게 조언 해 주셔서 감사합니다. –

+0

"콜백/종속성 삽입으로 숨김"또는 시그널 핸들러. –

4

빠른 수정, 당신이 뭔가 의심되는 경우 :

int some_func(int x, int y) 
{ 
    static volatile int do_not_enter_twice = 0; 
    assert(!(do_not_enter_twice++)); 

    /* some_func continued */ 

    do_not_enter_twice--; 
    return whatever; 
} 

긴 답변 :
사용하는 일부 도구는 call graph을하고 거기에서 수동으로 계속합니다.

+0

오! 내가 참조. 우리는 이미 콜 그래프를 만들었지 만 재진입 - 문제 해결을 위해 콜 그래프를 사용하지 못했습니다. 그리고 예, 우리는 재진입 점검을했는데, 어떤 기능이이 점검을 통과해야하는지 확신 할 수 없습니다 (지금 알고 있습니다). 그건 그렇고, 우리가 거대하기 때문에 콜 그래프를 분석 할 수있는 도구가 있습니까? –

+0

거대한 콜 그래프를 계산하려면 DMS 대답을 참조하십시오. –

0

코드를 확인하기 위해 2 가지 작업을 수행합니다. 철저한 그룹 코드 검토 (재 착오 실수 만 찾거나 스타일이나 다른 오류를 찾기 위해) 둘째, 문제에 대한 실질적인 공격. 예를 들어

:

int myfunction(int x, int y) { 
    REENTRANCE_CHECK; 
    ... body of function 
} 

지금 당신이 할 수 중 하나를 (생산) 비어있는 REENTRANCE_CHECK를 #define한다하거나 기능을 검사하는 코드를 다시 입력하지 않습니다. 테스트를 실행 한 다음 (테스트가없는 경우 디버거가 연결된 상태에서 장치에서 실행) 이러한 검사가 활성화되어 있고 어떤 것이 떨어지는지 확인하십시오.

마찬가지로 디버그 논리를 추가하여 전역 상태에 대한 잘못된 업데이트를 검색 할 수 있습니다.이미 보유 할 때 취득하는 경우 주장 잠금 (사용하는 코드를 작성 같은

뭔가 :.

int my_global; 
DEFINE_GLOBAL_LOCK(my_global); 

void my_dangerous_function() { 
    ... 
    LOCK_GLOBAL(my_global); 
    .. some critical section of code that uses my_global. 
    UNLOCK_GLOBAL(my_global); 
    ... 
} 

다시를 DECLARE_GLOBAL_LOCK, LOCK_GLOBAL 및 UNLOCK_GLOBAL는 하나 (실제 잠금 코드로 #define에 의해 정의 할 수 있습니다 테스트 용으로 작성해야합니다).

이 접근법은 전역 상태에 대한 모든 액세스를 찾아서 랩핑하는 경우에만 작동하지만 검색은 쉽습니다 .

2

거대한 콜 그래프를 계산할 수있는 도구는 DMS Software Reengineering Toolkit이고 C 프런트 엔드입니다. C 프런트 엔드는 C 코드를 구문 분석하는 데 사용됩니다. DMS는 제어 및 데이터 흐름 분석, 포인트 - 투 - 분석 및 호출 직접 및 콜 간접 통과 포인터 사실을 추출하기 위해 내장 된 기계를 가지고 있습니다. 의 C 소스 코드 시스템 용 콜 그래프를 작성하는 데 DMS가 사용되었습니다. 3500 만 줄의 C 코드 (= 250,000 함수)를 호출 한 다음 해당 호출 그래프에서 정보를 추출합니다. 이와 같이 큰 그래프를 작성할 때 중요한 문제는 간접 함수 호출이 최소한의 가양 성 목표를 보수적으로 목표로 삼을 수 있도록 실제와 똑같은 점으로 정보를 완벽하게 계산하는 것입니다.

귀하의 경우, 추출 할 정보는 다른 저자가 지적한대로 "주기가 있습니까?" 이 콜 그래프에서.

이 척도에서는 수동으로 수행하고 싶지 않으므로 프로덕션 빌드를 준비 할 때마다 다시 수행해야합니다. 수표를 기계화하는 것은 많은 의미가 있습니다.

관련 문제