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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Про реентерабельность, малоизвестная фича GCC
_Pasha
сообщение Feb 15 2009, 23:51
Сообщение #1


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Только не говорите, что знали и часто пользуетесь! smile.gif

В общем, тем, кому позарез нада получить сабж, оказалось все очень просто

Код
void somefunc (volatile int param)

  volatile int local1;
  volatile char local2;
//body
local1 |= param;
return;
}


Как объявили все volatile - компилятор все, включая входные параметры, кладет в стек-фрейм.

И логика проста: без соответствующих оптимизаций функции генерятся реентерабельными. Volatile как-раз и отключает эту оптимизацию локальных переменных.

В общем, в мануале ГЦЦ настолько туманно это описано, что побудило поделиться радостной новостью.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Feb 16 2009, 00:13
Сообщение #2


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Вы меня, конечно, извините, но это - "ацкий боян". IAR кстати, действует аналогично.

Только одна фигня есть - неатомарный доступ к переменным длинной больше байта на AVR-архитектуре.

Ну а кроме всего прочего - это совершенно бредовый способ обеспечения повторного входа. Куда безопаснее работать с указателем на блок параметров. Или с классом в плюсах.

Кроме того, если уж так хочется извращений - покурите еще одну фичу гнуся - вычисляемый goto. Может натолкнет на какие мысли.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 16 2009, 00:37
Сообщение #3


Гуру
******

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



Цитата(_Pasha @ Feb 16 2009, 01:51) *
Как объявили все volatile - компилятор все, включая входные параметры, кладет в стек-фрейм.
А как стековый фрейм связан с реентерабельностью?


--------------------
На любой вопрос даю любой ответ
"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
_Pasha
сообщение Feb 16 2009, 07:10
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Сергей Борщ @ Feb 16 2009, 03:37) *
А как стековый фрейм связан с реентерабельностью?
Обеспечивает копию блока локальных переменных - одно из необходимых условий. 
ЗЫ: Кстати, в WinAVR красивый код коррекции стека
Код
in r0,SREG
cli
.... атомарные операции
out SPL,YL
out SREG,r0
out SPH,YH

Поскольку сам так никогда не делал - на первый взгляд показалось, что бага - прерывания разрешаются при восстановлении SREG до того как завершена коррекция стека. На самом деле все правильно, т.к. следующая после out SREG,r0 команда гарантированно выполнится и прерывание наступит только после out SPH,YH. Таким образом, прерывания разрешаются максимально раньше
Go to the top of the page
 
+Quote Post
aesok
сообщение Feb 16 2009, 07:51
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(_Pasha @ Feb 16 2009, 10:10) *
Обеспечивает копию блока локальных переменных - одно из необходимых условий. 


Вот условия реентерабельности:

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

Нет никакой разницы где храняться параметры и локальные переменные, в стеке или в регистрах.

Анатолий.

Цитата(_Pasha @ Feb 16 2009, 10:10) *
ЗЫ: Кстати, в WinAVR красивый код коррекции стека
Код
in r0,SREG
cli
.... атомарные операции
out SPL,YL
out SREG,r0
out SPH,YH


PS: Немного не в тему, в xmega, запись в регистр стека будет выглядеть намного короче;
Код
out SPL,YL
out SPH,YH


В Атмеле догадались сделать это:
Цитата
To prevent corruption when updating the Stack Pointer from software, a write to SPL will automatically
disable interrupts for up to 4 instructions or until the next I/O memory write.


Сообщение отредактировал aesok - Feb 16 2009, 07:59
Go to the top of the page
 
+Quote Post
Rst7
сообщение Feb 16 2009, 08:26
Сообщение #6


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Вот условия реентерабельности:


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


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 16 2009, 08:46
Сообщение #7


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Rst7 @ Feb 16 2009, 03:13) *
Куда безопаснее работать с указателем на блок параметров.
Тоже был во власти этого заблуждения sad.gif


Цитата(Rst7 @ Feb 16 2009, 11:26) *
как некий костыль, позволяющий организовать многопоточность с минимумом затрат памяти.


В общем, по большому счету  я  сморозил глупость, потому что когда  блок локальных параметров не помещается в регистры, компилятор все равно кладет все в стек. И тогда уж
Цитата
Нет никакой разницы где храняться параметры и локальные переменные, в стеке или в регистрах.
поскольку регистры -то все равно сохраняются/восстанавливаются. А объявления volatile в первом посте - просто проиллюстрировали концепцию размещения локальных переменных. 
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 16 2009, 08:51
Сообщение #8


Гуру
******

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



Цитата(Rst7 @ Feb 16 2009, 10:26) *
Тут _Pasha имеет в виду не классическое понятие реетерабельности
Тогда неплохо бы приводить свое определение термина, раз уж оно расходится с общепринятым.
Цитата(Rst7 @ Feb 16 2009, 10:26) *
Т.е. выход из процедуры в произвольном месте через longjmp в прерывании и повторный заход в процедуру приведет к продолжению работы в прерванном месте.
Как там было у классиков? "и из обломков мотоцикла в следующий запойный период устроил стационарный двигатель, который был очень похож на настоящий, но не работал.". Перед выходом по longjump делается сохранение точки возврата при помощи setjump, которая совершенно корректно сохраняет на стеке все необходимые регистры в которых могут находиться локальные переменные.

Цитата(_Pasha @ Feb 16 2009, 09:10) *
Обеспечивает копию блока локальных переменных - одно из необходимых условий.
??? Необходимых кому? Почему одну копию, а не две или три?


--------------------
На любой вопрос даю любой ответ
"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
Rst7
сообщение Feb 16 2009, 09:08
Сообщение #9


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



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

Цитата
поскольку регистры -то все равно сохраняются/восстанавливаются.


Теперь они почему-то сохраняются/восстанавливаются - тогда зачем это очень опасное извращение?


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Feb 16 2009, 09:10
Сообщение #10


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

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



Цитата(aesok @ Feb 16 2009, 10:51) *
В Атмеле догадались сделать это:
....
Лучше поздно чем никогда. А не XMega они так не планируют доработать?
А ещё лучше бы переключаемые за 1-2 такта банки регистров забабахали штук этак 8.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
ReAl
сообщение Feb 16 2009, 09:56
Сообщение #11


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(aesok @ Feb 16 2009, 09:51) *
В Атмеле догадались сделать это:
Вот интересно, если бы они читали RU.EMBEDDED лет 10 назад, где именно об этом и говорилось при обсуждении AVR в качестве очень простой правки, улучшающей жизнь (и приводился пример - x86 и запрет прерываний на некоторое время после записи в SS, чтобы пару SS:SP атомарно обновлять), то может это и раньше появилось бы, где-то вместе с movw ?

Кстати, эти temp-регистры, которе появились при каждом 16-битном SFR - можно бы бы обойтись одним, если бы так же запрещать прерывания при обращении к слову.
А так даже персональные мало спасают - а если я и в основном коде хочу читать регистр таймера, и в прерывании - всё равно в основном коде надо запретить прерывания при чтении.
Если же запрет прерываний есть, то достаточно одного регистра temp на все 16-битные SFR, в целом меньше места заняло бы. И SPH:SPL просто обрабатывался бы за компанию, ему и не нужен temp-регистр, но проще одинаково обработать


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Rst7
сообщение Feb 16 2009, 10:12
Сообщение #12


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Лучше бы - не ядро править, а в компиляторы вменяемые способы работы с многобайтовыми переменными добавили. В смысле - чтобы оно само умело загрузку-выгрузку short/long в критическую секцию оборачивать. А то макросы-костыли класса ATOMIC_STORE_SHORT/ATOMIC_LOAD_SHORT уже достали, читабельности коду они аж никак не добавляют sad.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
ReAl
сообщение Feb 16 2009, 20:42
Сообщение #13


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Rst7 @ Feb 16 2009, 12:12) *
Лучше бы - не ядро править, а в компиляторы вменяемые способы работы с многобайтовыми переменными добавили. В смысле - чтобы оно само умело загрузку-выгрузку short/long в критическую секцию оборачивать. А то макросы-костыли класса ATOMIC_STORE_SHORT/ATOMIC_LOAD_SHORT уже достали, читабельности коду они аж никак не добавляют sad.gif

Одно другому не мешает. Не поленились же ещё в 8086 запретить прерывания на одну команду после записи SS. Тут тоже можно было не кучу регистров в кристалл вставлять, а запрет прерывания при обращении к младшему байту.

Что касается атомарнсти, так dxp что-то в таком духе давным давно показывал (только там не шаблон был, а просто класс для одного конкретного типа, в те времена IAR ещё шаблоны не поддерживал).
foo.cpp:
Код
#include <stdint.h>
#include <avr/interrupt.h>

class crit_sect  {
    uint8_t _sreg;
public:
    crit_sect() : _sreg(SREG) { cli(); }
    ~crit_sect() { SREG = _sreg; }
};

// не претендуя на полноту
template<typename T> class atomic {
    volatile T t;
public:
    inline operator T () {
        T temp;
        {    crit_sect cs;
            temp = t;
        }
        return temp;
    }

    inline atomic<T>& operator = (const T ti) {
        {    crit_sect cs;
            t = ti;
        }
        return *this;
    }

    inline atomic<T>& operator++() {
        {    crit_sect cs;
            ++t;
        }
        return *this;
    }
};


atomic<uint16_t> va, vb;
uint16_t c;

void foo() {
    vb = va + c;
    ++va;
}


avr-gcc -Os -mmcu=atmega88 -S foo.cpp
foo.s:
Код
// operator++ не захотел инлайнить, счёл слишком толстой функцией, ключи крутить лень
// да и не нужно, главное принцип
_ZN6atomicIjEppEv:
    movw r30,r24
    in r18,95-0x20
    cli
    ld r24,Z
    ldd r25,Z+1
    adiw r24,1
    std Z+1,r25
    st Z,r24
    out 95-0x20,r18
    movw r24,r30
    ret
/* function atomic<T>& atomic<T>::operator++() [with T = unsigned int] size 12 (11) */


_Z3foov:
    in r24,95-0x20
    cli
    lds r18,va
    lds r19,(va)+1
    out 95-0x20,r24

    lds r24,c
    lds r25,(c)+1
    add r18,r24
    adc r19,r25

    in r24,95-0x20
    cli
    sts (vb)+1,r19
    sts vb,r18
    out 95-0x20,r24

    ldi r24,lo8(va)
    ldi r25,hi8(va)
    rcall _ZN6atomicIjEppEv
    movw r30,r24

    in r18,95-0x20
    cli
    ld r24,Z
    ldd r25,Z+1
    out 95-0x20,r18

    sbiw r24,5
    brne .L6
    sts (c)+1,__zero_reg__
    sts c,__zero_reg__
.L6:
    ret


Собственно, никто ведь не заставляет писать "если на С++, то до конца". Можно использовать только то, что генерирует код не толще тех макросов, о которіх шла речь, но удобнее в использовании.

====
мдя...

1) подсунть в качестве T структуру так просто не удаётся (в варианте с исключённым operator++, естественно)

2) ну да, ну да, в обработчике прерывания доступ тоже будет обрамляться запретом/восстановлением прерываний. Но и если компелятор будет сам уметь оборачивать обращение прямо и вражений, то ему ещё придётся объяснять, что вот тут-то оборачивать и не надо.
А так - просто добавить в шаблон

Код
public:
        T noatomic_get() { return t; }
        void noatomic_assign(T i) { t = i; }
и в обработчиках пользоваться ими.

Эх, нет в жизни совершенства! (С) Лис.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Rst7
сообщение Feb 16 2009, 21:52
Сообщение #14


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



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

А с IAR'ом отдельный разговор. Тот запросто во внутрь этой секции может какую-нибудь математику внести. Завтра покажу.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
ReAl
сообщение Feb 16 2009, 22:11
Сообщение #15


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Rst7 @ Feb 16 2009, 23:52) *
Нет, с плюсами конечно, неплохо получается. Но хотелось бы еще и разрешение прерываний перед последним доступом. Типа минимизации времени нахождения в состоянии запрета. Без больших извращений.
"Ну, барин, тут одному не справиться" (С) "Формула любви"
Тут точно асм придётся звать на помощь. И шаблоны лесом пустить.
Огрызок в одну сторону, а то спать хочу.
Код
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

class atomic_u32
{
    uint32_t t;
public:
    inline operator uint32_t () {
        uint32_t temp;
        uint8_t sreg_sv;
        __asm__ __volatile__ (
            "in %1, %2 \n\t"
            "cli    \n\t"
            "ld %A0, %a3+    \n\t"
            "ld %B0, %a3+    \n\t"
            "ld %C0, %a3+    \n\t"
            "out %2, %1    \n\t"
            "ld %D0, %a3    \n\t"
            : "=r" (temp)
            : "r"  (sreg_sv), "I" (_SFR_IO_ADDR(SREG)),
                 "e"(&t) /* компилятор выберет Z или Y или X */
        );
        return temp;
    }

};

atomic_u32 va;
uint32_t b;

void foo() {
    b = va;
}


Код
_Z3foov:
    ldi r24,lo8(va)
    ldi r25,hi8(va)
    movw r30,r24

    in r24, 63
    cli    
    ld r24, Z+    
    ld r25, Z+    
    ld r26, Z+    
    out 63, r24    
    ld r27, Z    
    
    sts b,r24
    sts (b)+1,r25
    sts (b)+2,r26
    sts (b)+3,r27

    ret


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 07:52
Рейтинг@Mail.ru


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