Перейти к содержанию
    

Помоги найти мой косяк. Функция Sleep перестает работать.

У меня есть в проекте ошибка. Но я ее не могу отловить, вылетает в разные моменты времени.

Проект показывать смысла нет. Кода дохрена и никто не поймет.

 

Контролер ATmega8A 16MHz. Всего два процесса.

В какой то момент времени перестает работать правильно функция Sleep(). Т.е Sleep(500) начинает работать как Sleep(1) . При этом ОС работает замечательно.

 

Вот не могу понять. Что приводит к такому дивному эффекту? Или как эту хрень отловить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот не могу понять. Что приводит к такому дивному эффекту? Или как эту хрень отловить.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все нашел.

Для меж процессорного обмена использовал глобальную одно байтовую переменную (volatile). Заменил ее на месседжи и глюк исчез.

 

Из-за одного байта угробил кучу времени((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавлю свой вопрос сюда. Есть ощущение, что из той же области.

 

Проблема следующая. Один из потоков встает на ожидание флага (Event) с большим (10000) таймаутом. И практически сразу проваливается. Флаг при этом не выставлен, таймаут не отработан.

Пробежался по шагам - при входе в Wait все вроде тормозится, но после переключения, сразу процесс просыпается. Стека вполне много (с большим запасом). Вопрос - где искать ошибку, где в теории мог накосячить ?

Порт для Cortex-M3. Использую IAR 6.10.

Раньше такого не наблюдалось :(.

Пока сам за пару дней не откопал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Если вылетает сразу, то это похоже что вы отдаете в функцию неправлиьный указатель на эвент.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В данном случаи возврат идет с результатом false, т.е. произошол таймаут ожидания события. Но реально он (таймаут) не случился.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нащупал точку проблемы. Похоже я неправильно использую средства оси. Или это такая особенность.

Есть некая очередь сообщений. По некоему сообщению проваливаемся в обработчик, и там в одном месте есть ожидание флага. Теперь пока мы ждем флага в очередь сообщений приходит новое. И система воспринимает это, как событие, по которому пора разбудить процесс. Более внимательно посмотрел в отладчике. После вынимания из очереди очередного элемента не чистится флаг в ConsumersProcessMap. Соответственно приход нового элемента будит процесс и Wait у Event проваливается сразу. Это баг или так и должно быть и сам подход использования неверен?

 

  if (SystemMsg.pop(sysmsg,100))
  {   
   switch(sysmsg.msg)
   {
   case KEY_PRESSED:
      {
    // перешли в новое     
    // здесь ожидаем некоего флага    
        Rquest_done.Wait(5000);    

      }break;

    ...
   }//switch
  } else {
        // делать что-то     

         }

 

Вот еще один момент. Такое проявляется при приходе сообщения (push элемента chanal) из более высокоприоритетного потока. В момент проверки ожидающих потоков, стоит бит, что он ready (вполне возможно просто прерван верхним потоком) и при этом ConsumersProcessMap указывает, что этот самый готовый поток ждет сообщения. Чудеса. Из менее приоритетного ConsumersProcessMap обнуляется, там таких странных вещей не наблюдается. Пробовал поймать, где застревает флаг ожидания. Не получается.

Изменено пользователем BAT

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вроде похоже отловил причину. Не знаю как назвать, багом или особенностью Scm.

 

Что получилось.

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

 

Итого:

Теперь если процесс попытается встать на ожидание какого-то другого события и в очередь сообщений придет элемент получится пролет ожидание этого события.

 

Вот думаю, что делать. Добавить чистку ConsumersProcessMap во время POP из канала? Но получится идеологически неверно влезать в сорцы оси. Но и в своем коде менять принцип не хочется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Процесс с более высоким приоритетом прерывает ожидающий сообщений из канала. ConsumersProcessMap соответственно указывает, что процесс в ожидании.

Не понял, как может быть прерван процесс, ожидающий сообщения - ведь и так находится в неактивном состоянии.

 

Вот думаю, что делать. Добавить чистку ConsumersProcessMap во время POP из канала? Но получится идеологически неверно влезать в сорцы оси. Но и в своем коде менять принцип не хочется.

Там в коде в функции pop есть такой фрагмент:

if(pool.get_count())                                                                           
{                                                                                              
    p->Timeout = 0;                                                                            
    item = pool.pop();                                                                         
    CheckWaiters(ProducersProcessMap);                                                         
    return true;                                                                               
}                                                                                              
                                                                                               
if(ConsumersProcessMap & PrioTag)             // waked up by timer when timeout expired        
{                                             // or by OS::ForceWakeUpProcess()                
                                                                                               
    p->Timeout = 0;                           // non-zero if waked up by ForceWakeUpProcess()  
    ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map      
    return false;                                                                              
}

Попробуйте поменять эти два if'а местами - должно порешать вашу проблему. Сейчас готовится новая версия, там как раз такой порядок проверки условий. Заодно узнаем, правильное это решение или нет. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понял, как может быть прерван процесс, ожидающий сообщения - ведь и так находится в неактивном состоянии.

 

Согласен, не так выразился. Не прерывает, а просто просыпается более высокоприоритетный.

 

По поводу поменять местами. В принципе проблему решит. Правда сначала вывалится с ошибкой таймаута (практически он таки имел место), а при повторном входе сразу выйдет с уже нужным сообщением. Наверное так логичнее, чем сделал. Просто в лоб поставил чистку ConsumersProcessMap.

 

if(pool.get_count())                                                                          
{                                                                                              
    p->Timeout = 0;                                                                            
    item = pool.pop();                                                                        
    CheckWaiters(ProducersProcessMap); 
    ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map                                                       
    return true;                                                                              
}

 

При таком варианте вываливания с таймаутом не будет, что наверное не совсем корректно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Мы спорили промеж себя, как правильнее - фиксировать ли таймаут, если к моменту получения ожидающим процессом управления таймаут уже истёк. С одной стороны ведь событие произошло - почему бы его сразу не обработать, зачем ждать следующего входа в ожидание события; с другой - заявленный таймаут реально истёк, а уж по какой причине - дело второе. На практике особой разницы (в обозримых случаях) как-то не очень видно - всё это на уровне "гонок". Главное, чтобы событие не терялось.

 

Было бы интересно узнать, решит ли на практике перестановка местами условий вашу проблему. Вопрос не праздный - в готовящейся версии логика именно такая. Если вам не сложно проверить, попробуйте, пожалуйста.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поменял местами. Как и ожидалось, проблема ушла.

Спасибо. :)

Значит, быть посему! Спасибо вам! :a14: :beer:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мы спорили промеж себя, как правильнее - фиксировать ли таймаут, если к моменту получения ожидающим процессом управления таймаут уже истёк. С одной стороны ведь событие произошло - почему бы его сразу не обработать, зачем ждать следующего входа в ожидание события; с другой - заявленный таймаут реально истёк, а уж по какой причине - дело второе. На практике особой разницы (в обозримых случаях) как-то не очень видно - всё это на уровне "гонок". Главное, чтобы событие не терялось.

 

Было бы интересно узнать, решит ли на практике перестановка местами условий вашу проблему. Вопрос не праздный - в готовящейся версии логика именно такая. Если вам не сложно проверить, попробуйте, пожалуйста.

 

Сначала был таймаут. Поэтому возвращать нужно "таймаут".

 

Например, окончание телеграммы в модбасе -- по таймату. Если пришёл байт после таймаута -- это уже следующая телеграмма.

 

Илья

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Например, окончание телеграммы в модбасе -- по таймату. Если пришёл байт после таймаута -- это уже следующая телеграмма.

А если пришёл байт (т.е. он первым пришёл, до таймаута), но пока управление передавалось от источника этого события к его обработчику, произошёл таймаут. Как быть? Что считать результатом - событие или таймаут? :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...