реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> GCC: Аварийный выход из прерывания (функции), чем заменить оператор goto?
Xenia
сообщение May 20 2013, 19:05
Сообщение #31


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(_Артём_ @ May 20 2013, 22:56) *
В случае использования локальных переменных компилятор может использовать одни и те же адреса в ОЗУ для разных переменных, а для глобальных так не получится.


Это только в том случае, если они освобождаются вместе с окончанием той функции/блока, в котором были заведены. Но main() свои локальные переменные (те, что заводятся в ее начале) не освободит никогда - на то у нее и бесконечный цикл внутри сидит.

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

P.S. Не стоит обольщаться тем, что войдя джампом из прерывания во внутрь какой-то функции (в том числе и main), вы обнаружите там локальные переменные на тех же местах. Адреса локальных переменных отмеряются относительно текущего указателя стека, который при запрыгивании со стороны никак не может быть правильным (т.к. функция прерывания тоже пользуется стеком). Поэтому как ни крути, но валидными в этом случае могут быть только глобальные переменные, но не локальные. Причем независимо от того, сбрасывали вы стек или нет.
Go to the top of the page
 
+Quote Post
Tiro
сообщение May 20 2013, 22:31
Сообщение #32


Знающий
****

Группа: Свой
Сообщений: 781
Регистрация: 3-10-04
Из: Санкт-Петербург
Пользователь №: 768



Цитата(Xenia @ May 20 2013, 22:05) *
Адреса локальных переменных отмеряются относительно текущего указателя стека, который при запрыгивании со стороны никак не может быть правильным (т.к. функция прерывания тоже пользуется стеком). Поэтому как ни крути, но валидными в этом случае могут быть только глобальные переменные, но не локальные. Причем независимо от того, сбрасывали вы стек или нет.

Тут поддержу Ксению, но какое это имеет отношение к вопросу топикстартера? Он же сказал, что состояние программы и стека ему не известно и не важно. Возможно, стек переполнился и залез на глобальные переменные. Надежнее не использовать вообще никакие заранее определенные переменные. Используйте константы или заведите новые переменные, порушив глобальные, переставьте указатель стека на начало и вперед! Только вперед и только хардкор biggrin.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 21 2013, 07:45
Сообщение #33


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



_Артем_ ответил по всем пунктам.
Касаемо последних двух сообщений: компилятор не может знать вашей логики, заставить его "не использовать локальные переменные" нельзя. Решение с goto из одной функции в другую ущербное каким бы хаком оно бы ни было реализовано. longjump() еще куда ни шло - он поддержан компилятором.
Было же грамотное решение - функция с атрибутом noreturn. И вызывать ее как функцию, без всяких указателей и т.д. Компилятору этого noreturn по идее должно быть достаточно, чтобы не сохранять лишние регистры в каждом прерывании.

QUOTE (Xenia @ May 20 2013, 22:05) *
Но main() свои локальные переменные (те, что заводятся в ее начале) не освободит никогда - на то у нее и бесконечный цикл внутри сидит.
Во-первых не надо считать компиялтор настолько тупым. Во-вторых и внутри этого бесконечного цикла имеют право быть несколько блоков со своими локальными переменными.
QUOTE (Xenia @ May 20 2013, 22:05) *
Так я и выразилась в том духе, что заводить внутри main() локальные переменные смысла не имеет. Т.е. речь шла не об экономии памяти, как вы это неверно поняли, а об устойчивости переменных к сбросу стека.
То есть еще одна распорка чтобы конструкция перевязанная предыдущей расчалкой не навернулась.
QUOTE (Xenia @ May 20 2013, 22:05) *
P.S. Не стоит обольщаться тем, что войдя джампом из прерывания во внутрь какой-то функции (в том числе и main), вы обнаружите там локальные переменные на тех же местах. Адреса локальных переменных отмеряются относительно текущего указателя стека, который при запрыгивании со стороны никак не может быть правильным (т.к. функция прерывания тоже пользуется стеком).
Именно поэтому setjump() сохраняет состояние указателя стека. И после longjump() все локальные переменные находятся на своих местах совершенно нетронутые.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Палыч
сообщение May 21 2013, 08:00
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Совершенно непонятно: почему ТС не хочет использовать setjmp / longjmp ? ИМХО, это - хорошее решение той задачи, что стоит перед ТС, абсолютно стандартными средствами. Даже пример, взятый мной из GCC и приведенный в сообщении #9, почти один-в один совпадает с тем, что желает ТС и привел в первом сообщении. Жалко места под буфер jmp_buf ?
Решение же проблемы почему-то "крутится" вокруг goto... Зачем этот "гемморой" ?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение May 21 2013, 12:51
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Палыч @ May 21 2013, 11:00) *
Совершенно непонятно: почему ТС не хочет использовать setjmp / longjmp ?

ТС не хочет чтобы в прерывании куча регистров сохранялась-восстанавливалась: ссылка
Go to the top of the page
 
+Quote Post
ARV
сообщение May 21 2013, 18:08
Сообщение #36


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



Цитата(_Артём_ @ May 20 2013, 23:03) *
goto заменилось на JMP my_exit без ненужного сохранения регистров. Надо же...
так ведь это как бы и требовалось?

Цитата(Сергей Борщ)
Было же грамотное решение - функция с атрибутом noreturn. И вызывать ее как функцию, без всяких указателей и т.д. Компилятору этого noreturn по идее должно быть достаточно, чтобы не сохранять лишние регистры в каждом прерывании.
такая функция скорее всего проинлайнится внутрь обработчика, и соответственно не даст никакого выигрыша по сравнению с нормальным указанием выполняемых операторов в этом обработчике.


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



--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение May 21 2013, 19:20
Сообщение #37


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(ARV @ May 21 2013, 21:08) *
так ведь это как бы и требовалось?

Да, это оно самое и есть, чего хотел ТС.

Цитата(ARV @ May 21 2013, 21:08) *
такая функция скорее всего проинлайнится внутрь обработчика, и соответственно не даст никакого выигрыша по сравнению с нормальным указанием выполняемых операторов в этом обработчике.

Не, не проинлайнится. noreturn роли не играет.
Видимо регистров мало сохраняется из-за того что goto используется.


Цитата(ARV @ May 21 2013, 21:08) *
у меня была идея поместить эту функцию в секцию .fini1 и попадать туда стандартной функцией exit или abort, но компилятор оказался слишком глупым и тупо сохранял в стеке все регистры в обработчике прерываний...

А если так:
Код
typedef void (*exit_handler_t) (); //
ISR(SPM_RDY_vect)
{
    if (fatal_error) {
        exit_handler_t exit_handler=my_exit;
        goto *exit_handler;
    }
}

то лишних сохранений не будет и функцию можно расположить по заданному адресу.
Go to the top of the page
 
+Quote Post
rudy_b
сообщение May 21 2013, 19:32
Сообщение #38


Знающий
****

Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458



Что-то непонятно. Что значит "программа должна завершиться", если в ней есть main с бесконечным циклом? И что будет если из main дать return?

Если нужно заблокировать работу программы находясь в прерывании - запретите все прерывания и зациклитесь. Из этого можно можно выйти только по reset.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение May 21 2013, 19:47
Сообщение #39


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(rudy_b @ May 21 2013, 22:32) *
И что будет если из main дать return?

Перейдёт на какую-нибудь функцию exit (или что там предусматривается на такой случай).
Как-то так оно выглядит:
Код
  CLI         Global Interrupt Disable
  RJMP PC-0x0000        Relative jump

Но можно и своим чем-то заменить.

Цитата(rudy_b @ May 21 2013, 22:32) *
Если нужно заблокировать работу программы находясь в прерывании - запретите все прерывания и зациклитесь.

Возможно таких мест не одно. И там предполагается не только зацикливание, а ещё какие-то спасающие ситуацию действия.


Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение May 21 2013, 20:17
Сообщение #40


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(_Артём_ @ May 20 2013, 16:31) *
Мне почему-то кажется что код идущий после метки будет выкинут оптимизатором. Или нет?
Вы с какими настройками компилируете?

-Os
нет, код после метки отстается, возможно что там используются volatile-переменные

Цитата(Xenia @ May 19 2013, 22:04) *
Ветвление надо произвести только один раз - в самом начале main(), еще до вхождения в бесконечный цикл.

Идея с семафором, ветвлением вначале main и оригинальная, но все же я не очень доверяю сохранности портов после сброса ..

Цитата
Функции setjmp / longjmp подойдут ?

этот вариант не подходит т.к. по сути это тот же самый вызов функции с вытекающими последствиями

Цитата(ARV @ May 20 2013, 20:12) *
если очень хочется, то можно вот так:
Код
void  __attribute__((noreturn)) my_exit(void){
     PORTB = 0xFF;
     while(1);
}

ISR(TIMER1_OVF_vect){
     if(PINB & 1){
         PORTB = 0;
     } else {
         // проблема - обрабатываем лебединую песню!!!
         void *ptr = my_exit;
         goto *ptr;
     }
}
при желании my_exit() можно вызывать и в main, не нарушая общей структуры программы. хотя с моей точки зрения это кривой костыль, правильное по моему мнению решение я озвучивал ранее.

Помоему самое оптимальное решение !
т.к. даже через снятие адреса метки:
Код
ptr=&&m1;
....
goto *ptr;
компилятор заменяет на ijmp ptr что задействует еще пару регистров, которые сохраняются в стек
Только неясно почему опять кривой костыль ?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение May 21 2013, 20:54
Сообщение #41


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(MaxiMuz @ May 21 2013, 23:17) *
возможно что там используются volatile-переменные

Может быть.

Цитата(MaxiMuz @ May 21 2013, 23:17) *
но все же я не очень доверяю сохранности портов после сброса ..

О каких портах речь? Входы-выходы? После сброа они будут сброшены в дефолтное состояние.

Цитата(MaxiMuz @ May 21 2013, 23:17) *
Помоему самое оптимальное решение !

Есть, кстати ещё вариант: в прерывании, в котором обнаружена аварийная ситуация генерить вызов другого прерывания в котором и выполнять нужные действия (уход в sleep кажется?). Программное прерывание то есть.
Код
ISR(TIMER1_COMPA_vect)
{
     if (fatal_error) {
          // вызов программного прерывания
          SPMCR=1<<SPMIE;
     }
}

ISR(SPM_RDY_vect)
{

     SPMCR&=~(1<<SPMIE);
     // действия по аварии
    while (1);
}

На запуск програмного прерывания нужно всего пара команд, поэтому дополнительных регистров не потребуется. Только сработает оно через десятков-другой тактов, но программа при этом порушена не будет.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение May 21 2013, 21:01
Сообщение #42


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(_Артём_ @ May 21 2013, 23:54) *
О каких портах речь? Входы-выходы? После сброа они будут сброшены в дефолтное состояние.

тот вариант о котором говорила Xenia
#17
с вызовом прерывани из прерывания я тоже думал , как вариант , но всеже rjmp проще всего
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 22 2013, 06:52
Сообщение #43


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Всё это (аварийный выход) стоит завернуть в какой-нибудь макрос с внятным именем типа abort();
Кстати, вариант с программным прерыванием - ИМХО самый оптимальный - вызов одна инструкция sbi, ну и обработчик со всеми нужными атрибутами...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Палыч
сообщение May 22 2013, 07:01
Сообщение #44


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(demiurg_spb @ May 22 2013, 10:52) *
вызов одна инструкция sbi...

В AVR программное прерывание "сгенерить" не так-то и просто. В АVR, обычно, запись единицы в флаг прерывания приводит к её сбросу.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 22 2013, 07:05
Сообщение #45


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(Палыч @ May 22 2013, 11:01) *
В AVR программное прерывание "сгенерить" не так-то и просто. В АVR, обычно, запись единицы в флаг прерывания приводит к её сбросу.
На худой конец можно задействовать и внешнее прерывание + дёрнуть уровень на ноге sbi или cbi или просто его разрешить на нужной ноге с нужным уровнем.
Всё это уже лирика...
Цитата
• Bit 7 – SPMIE: SPM Interrupt Enable
When the SPMIE bit is written to one, and the I-bit in the Status Register is set (one), the SPM
ready interrupt will be enabled. The SPM ready Interrupt will be executed as long as the SPMEN
bit in the SPMCR Register is cleared.
Ведь не зря же его для нужд rtos частенько используют...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 10:30
Рейтинг@Mail.ru


Страница сгенерированна за 0.01517 секунд с 7
ELECTRONIX ©2004-2016