2010-01-25 1 views
4

Мы используем C для создания системы на ядре ARM (т. е. встроенной системы). Возникает вопрос: как мы можем избежать проблемы с повторным запуском формально, чтобы мы были уверены, что все ошибки повторного входа удалены. Это, возможно, не практическое желание, но, безусловно, важно для любой системы.Любой систематический способ избежать проблемы «повторного входа»? (встроенная система)

Как раз для обсуждения, я думаю, что рисование диаграммы UML или полное состояние машины было бы хорошим началом (но как сгенерировать его ПОСЛЕ развития всей системы?). Любые предложения по использованию диаграммы состояния/UML для анализа?

ответ

4

Я не совсем уверен в проблеме, которую вы хотите решить, но позвольте мне сделать обоснованное предположение.

Первым моментом является определение функций, которые могут быть проблематичными. Повторное включение происходит либо с помощью рекурсивных вызовов, которые могут проходить несколько вложенных вызовов и даже быть скрыты при помощи обратных вызовов/зависимостей или функциями, которые используются в нескольких потоках.

Вы можете нарисовать диаграмму направленного вызова. Скажем, функция A вызывает B и C, функция B вызывает D, E и F, функция C ничего не называет и так далее. Нарисуйте это для каждого потока при многопоточности. Если на графике есть циклы, то все функции, выполняющие этот цикл, должны быть безопасны для повторного ввода. В этом случае вы можете игнорировать дочерние элементы. Функции, которые используются в нескольких потоках, также должны быть безопасными, но теперь они включают все дочерние элементы, потому что вы точно не знаете, где находится каждый поток. Все будет сложным и сложным, когда будут использоваться блокировки, поэтому пока не будем игнорировать это.

Этот шаг, безусловно, может быть автоматизирован с помощью инструментов анализа кода.

Теперь, когда функции определены,

  • Функции, которые зависят только от их функции локального данных, как правило, безопасны. Это один из приятных свойств функционального программирования.
  • Функции, зависящие от внешних данных (не в пределах области действия), должны быть тщательно изучены, особенно важно знать, когда и где внешние данные будут изменены.
  • Функции, которые изменяют внешние данные, должны поднять красный флаг и активировать громкую сиреную сирену, особенно при многопоточности.
+1

Когда я делаю такого рода экспертизу кода, первое, что я смотрю, это мои глобальные перемены. Функции, которые непосредственно получают доступ к глобальным переменным или управляют ими, обычно являются функциями с большинством проблем с повторным подключением. Как упоминалось выше, функции, которые изменяют только аргументы функции или внутренние данные, как правило, хорошо. Не забудьте проверить, что любые функции библиотеки, которые вы вызываете (включая стандартные функции библиотеки), являются потокобезопасными! – bta

+0

Понял. Спасибо Secure & bta за консультацию. – 2010-01-26 01:42:27

+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

О! Понимаю. Мы уже сделали график вызовов, но не смогли использовать его для решения проблем с повторным подключением. И да, мы сделали повторную проверку, просто не уверен, какая функция должна пройти эту проверку (теперь я знаю). Кстати, есть ли инструмент для анализа графика вызовов, так как наш огромный ... – 2010-01-26 01:38:32

+0

См. Ответ DMS для вычисления огромных графов вызовов. –

0

Я бы сделал 2 вещи, чтобы проверить ваш код. Тщательный групповой обзор кода (с целью поиска ошибок повторного входа, а не стиля или других ошибок). Во-вторых, практическая атака на проблемы.

Например:

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

Теперь вы можете #define REENTRANCE_CHECK быть либо пустым (для производства) или некоторый код, который проверяет функцию никогда не введен заново. Запустите тесты (если у вас нет тестов, а затем запустите их на своем устройстве с прикрепленным отладчиком), если эти проверки включены, и посмотрите, что-то не происходит.

Аналогичным образом вы можете добавить логику отладки, чтобы обнаружить неверные обновления в глобальном состоянии.Написать код, который использует блокировки (которые утверждающие, если они приобрели, когда уже провели

Что-то вроде этого:.

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); 
    ... 
} 

Again, DECLARE_GLOBAL_LOCK, LOCK_GLOBAL и UNLOCK_GLOBAL можно либо с помощью #define, чтобы быть реальным код блокировки (которые, конечно же, вам придется писать) для тестирования, а для производства они могут быть # неопределенными ни в чем.

Этот подход работает только в том случае, если вы обнаружите и завершите все обращения к вашему глобальному состоянию, но это легко с поиском

2

Инструмент, который может вычислять огромные графы вызовов - это DMS Software Reengineering Toolkit и его передний конец C. Передняя часть C используется для анализа кода C; DMS имеет встроенные механизмы для расчета контроля и анализа потока данных, анализа точек и анализа вызовов и прямого вызова и вызова-косвенного указателя.

DMS был использован для построения графиков вызовов для систем исходного кода C от 35 миллионов строк кода C (= 250 000 функций), а затем для извлечения информации из этого графика вызовов. Ключевая проблема при построении больших графиков, подобных этому, заключается в том, чтобы точно вычислить точки-информацию как практические (существуют жесткие ограничения теории при этом идеально), так что вызовы косвенных функций консервативно нацелены на минимальное количество ложноположительных целей.

В вашем случае информация для извлечения, как указывают другие авторы, «есть ли цикл?». в этом графе вызовов.

В этом масштабе вы не хотите делать это вручную, и вам нужно повторно делать это каждый раз, когда вы готовитесь к сборке продукции. Таким образом, механизация проверки будет иметь большой смысл.

Смежные вопросы