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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Атомарность чтения, в Cortex M3
Serg_el
сообщение Apr 1 2014, 08:41
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 13-12-06
Из: Togliatti
Пользователь №: 23 473



Коллеги!

Правильно ли я понимаю, что чтение переменной в основном цикле, значение которой изменяется в прерывании, можно считать атомарным?

Т.е. к примеру существует структура, элементами которой являются:

1) 32-битная переменная, значение которой меняется через некий интерфейс (UART, CAN и т.п.) - изменяется в прерывании получения пакета;
2) копия этой переменной, значение которой может использоваться в основном цикле как угодно (чтение, запись), но к которой нет доступа из прерываний;
3) 32-битная переменная, значение которой уменьшается до 0 в прерывании таймера (время жизни переменной 1) и устанавливается равной некой константе в прерывании получения пакета;

typedef struct
{
volatile unsigned int Value_int;

unsigned int Value;

volatile unsigned int Valid_Timer;

} RxParameterInfo;

В основном цикле, если переменная 3 не равна 0, переменная 2 = переменной 1, иначе = 0.

if (Valid_Timer)
{
Value = Value_int;
}
else
{
Value = 0;
}

Вопрос возник из-за того, что Value = Value_int; состоит из минимум 3х ассемблерных команд. Но как я понимаю при входе в прерывание регистры R0-R2 автоматически сохраняются, а остальные через PUSH.
Т.е. мы в итоге не теряем информации об адресах и в результате присваивания в худшем случае в Value мы будем иметь предыдущее значение Value_int.

Также интересно, если Value или Value_int - это сложные указатели на структуры и для того, чтобы получить в итоге адрес, нужно несколько ассемблерных команд. Гарантируется ли в это случае компилятором сохранение всех участвующих регистров в стеке?

Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 1 2014, 09:15
Сообщение #2


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

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



Цитата(Serg_el @ Apr 1 2014, 12:41) *
Правильно ли я понимаю, что чтение переменной в основном цикле, значение которой изменяется в прерывании, можно считать атомарным?
Нет не так. Не можно считать атомарным, а должно быть атомарным.

Цитата(Serg_el @ Apr 1 2014, 12:41) *
В худшем случае будет винегрет из полей структуры (часть старые, часть новые),
а целостность самих полей не пострадает, пока не станете портировать на контроллер с другой архитектурой и разрядностью.

Цитата(Serg_el @ Apr 1 2014, 12:41) *
Также интересно...
Не о том вы думаете... Не надо думать ни о стеке ни о указателях.
Главное, чтобы волатильные агрегатные переменные, значимые для логики вашей программы, читались-писались атомарно. Всё.
Например: волатильная комплексно сопряжённая пара чисел не имеет смысла к существованию, если доступ к ней в целом не атомарен.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Serg_el
сообщение Apr 1 2014, 09:20
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 13-12-06
Из: Togliatti
Пользователь №: 23 473



Цитата(demiurg_spb @ Apr 1 2014, 13:15) *
Нет не так. Не можно считать атомарным, а должно быть атомарным.
Не о том вы думаете... Не надо думать ни о стеке ни о указателях.
Главное, чтобы волатильные агрегатные переменные, значимые для логики вашей программы, читались-писались атомарно. Всё.
Например: комплексно сопряжённая пара чисел не имеет смысла к существованию, если доступ к ней в целом не атомарен.



А что же по поводу сохранения всех регистров, участвующих в копировании в стек?

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


PS Раньше просто не заморачивался, делал обертку из запрета/разрешения прерывания и все. Но пока не возникла потребность в более частых прерываниях, а переменные, которые надо скопировать, не увеличились в количестве. Про LDREXW знаю и скорее всего буду использовать, главное знать, что это обязательно при чтении без модификации и записи.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 1 2014, 09:24
Сообщение #4


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

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



Цитата(Serg_el @ Apr 1 2014, 13:20) *
А что же по поводу сохранения всех регистров, участвующих в копировании в стек?

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

Это хорошо, что ISR не портит регистры контекста. Так и задумывалосьsm.gif
Ваш вопрос для меня не понятен.
Попробуйте пожалуйста описать чего вы опасаетесь другими словами.

Кстати, копия переменной не нужна вовсе, т.к. на CM3 доступ к 32-ух битным переменным атомарен от рождения (в смысле чтения и записи),
а вот например её инкремент нифига не атомарная операция, а LOAD-MODIFY-STORE (аж 3 шага, которые не должны быть прерваны соответствующим ISR).


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Serg_el
сообщение Apr 1 2014, 09:42
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 13-12-06
Из: Togliatti
Пользователь №: 23 473



Цитата(demiurg_spb @ Apr 1 2014, 13:24) *
Это хорошо, что ISR не портит регистры контекста. Так и задумывалосьsm.gif
Ваш вопрос для меня не понятен.
Попробуйте пожалуйста описать чего вы опасаетесь другими словами.


Опасаюсь того, что при копировании значения из переменной, которая изменяется в прерывании, в переменную, которая работает только в основном цикле произойдет порча какого-либо регистра и я считаю не то значение. Боюсь этого потому, что нашел в доках, что сохраняются R0-R3, но не нашел, что и другие тоже. Т.е. почему это делает IAR и гарантирует ли он подобные сохранения я не знаю. Вот запрет/разрешение прерываний это гарантирует. __LDREXW и __STREXW тоже гарантирует, но увеличивает время при копировании переменных. Хочу понять можно ли просто скопировать значение без использования обертки?

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

void SysTick_Handler (void)
{
if (Counter_Timer)
{
Counter_Timer--;
}
}

int main(void)
{
while (1)
{
__disable_irq();
Counter_Timer = 10;
__enable_irq();

if (!Counter_Timer)
{
// Do something
}
}
}

Также допустимо ли это в случае, если Counter_Timer - часть сложной структуры?
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 1 2014, 10:31
Сообщение #6


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

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



Повторюсь, не нужно блокировать прерывания при записи int - это и так атомарная операция.
Да, никакой разницы нет, является ли int частью структуры или нет.
Код
volatile int Counter_Timer;

void SysTick_Handler(void)
{
    if (Counter_Timer)
        Counter_Timer--;
}

int main(void)
{
    while (1)
    {
        Counter_Timer = 10;

        while (Counter_Timer)
           ; // wait
        ...
    }
}


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Serg_el
сообщение Apr 1 2014, 11:12
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 13-12-06
Из: Togliatti
Пользователь №: 23 473



Цитата(demiurg_spb @ Apr 1 2014, 14:31) *
Повторюсь, не нужно блокировать прерывания при записи int - это и так атомарная операция.
Да, никакой разницы нет, является ли int частью структуры или нет.


Т.е. для CM3 вопрос атомарности возникает только для чтения/записи переменных long long?

Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 1 2014, 12:05
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Serg_el @ Apr 1 2014, 15:42) *
Опасаюсь того, что при копировании значения из переменной, которая изменяется в прерывании, в переменную, которая работает только в основном цикле произойдет порча какого-либо регистра и я считаю не то значение. Боюсь этого потому, что нашел в доках, что сохраняются R0-R3, но не нашел, что и другие тоже.

У вас каша в голове. Атомарность и сохранение контекста при прерываниях - совершенно не связанные между собой вещи.
Будет-ли эта вещь красной если она круглая? как вы думаете?

Цитата(Serg_el @ Apr 1 2014, 17:12) *
Т.е. для CM3 вопрос атомарности возникает только для чтения/записи переменных long long?

Да. Чтения и записи long long в общем случае могут быть не атомарными (хотя не обязательно есть LDRD/STRD).
Любые операции чтения или записи переменных с такой разрядностью, для которой нет соотв. команд в системе команд CPU (или эти команды не используются компилятором),
буду неатомарными.
Также почти все операции чтения-модификации-записи в Cortex-M3 будут неатомарными. Исключение - операции установки/сброса одиночных (или даже смежных для LDRD/STRD)
битов в слове, реализуемые через bitbanding.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 1 2014, 12:06
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Да вы вообще не о том думаете.

Какая разница вам про регистры?

Если пишите на C, то нефиг думать про ASM пока не припрет временем или чем-то подобным.

Во время возникновения прерывания все что надо будет сохранено, а потом восстановлено обратно. Если внутри обработчика потребуются другие регистры то компилятор их сам сохранит, а до выхода восстановит. Чтобы там ни было, по выходу из функции прерывания ничего не испортиться.

Вопрос атомарности связан с другим:
вот допустим есть счетчик который считает A = A + 1;
и есть таймер который его сбрасывает, А = 0;

процесс счета такой

<---0
выбираем из памяти А
<---1
увеличиваем выбранное значение А на 1
<---2
сохраняем полученное значение обратно в А
<---3

процесс сброса
Схраняем по адресу А, значение 0.

если прерывание произойдет (вызовется обработчик) на 0, или 3, все пройдет штатно
а если на 1 или 2, то что будет?

А сброситься в 0, и по возвращению обратно пройдут прочие процедуры с сохраненным до прерывания значением и А не изменится...


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

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

А если взять наш первоначальный пример, но в прерывании А не будет сбрасываться, а будет только читаться и выводиться наружу, например, то даже вызванное в 1 и 2 прерывание, все отработает штатно, ничего не испортится, до тех пор пока чтение и запись переменной будет в 1 такт, и не будет шансов попасть между чтением первой половины и второй, например...






Go to the top of the page
 
+Quote Post
Serg_el
сообщение Apr 1 2014, 12:48
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 13-12-06
Из: Togliatti
Пользователь №: 23 473



Всем спасибо за комментарии!
Go to the top of the page
 
+Quote Post
amaora
сообщение Apr 1 2014, 16:41
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778



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

Про атомароность правильно заметили, что это другой вопрос.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 2 2014, 03:30
Сообщение #12


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

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



Цитата(Serg_el @ Apr 1 2014, 16:48) *
Всем спасибо за комментарии!
Всегда пожалуйста!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Apr 2 2014, 05:20
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Serg_el @ Apr 1 2014, 09:41) *
Коллеги!
Правильно ли я понимаю, что чтение переменной в основном цикле, значение которой изменяется в прерывании, можно считать атомарным?
Т.е. к примеру существует структура, элементами которой являются:

Как уже отвечали ниже, определенные инструкции обеспечивают атомарность операций чтения/записи элементарных данных. Это, однако, частные случаи. В общем же необходимо обеспечивать "атомарность" целого блока действий. Например, быстрый прием потока данных по прерываниям по UART в очередь (FIFO) и выборка этих данных в основной программе. В таком случае возникает проблема "атомарности" даже не чтения, а модификации целого ряда указателей и счетчиков. Обрамлять такие действия критической секцией с запретом прерываний - это по меньшей мере нарваться на "фе-е-е" крутых программеров на форуме. Поэтому подойдите к проблеме комплексно с самого начала, решив ее для себя один раз и навсегда.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 2 2014, 06:06
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



туманно вы в конце написали а главное решения то не подсказалиsm.gif... того что раз и навсегда...
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Apr 2 2014, 08:28
Сообщение #15


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Golikov A. @ Apr 2 2014, 07:06) *
туманно вы в конце написали а главное решения то не подсказалиsm.gif... того что раз и навсегда...

Направление пути ясно, Google в помощь.
Ну, а если разойтись-таки на многа букаф, то повторю то, что я уже как-то писал в форуме по поводу незапрета прерываний в основной программе (мы не говорим об ОСях и в них встроенные механизмы разграничения доступа).

Принцип (на котором у меня надежно работают FIFO) заключается в использовании свойства NVIC вызывать прерывания до тех пор, пока соответствующий флаг не сброшен. Впрочем, и другие архитектуры в основном также работают, но не всегда: в MSC-51 с UART может не прокатить.

Стояла как всегда задача реализации FIFO с приемом от последовательного устройства (UART|SPI) по прерыванию и выборки данных в основной программе. Чтобы не запрещать прерывания в основной программе я применил следующее решение:
1. Заводится флаг критической секции.
2. Основная программа окружает критическую секцию, в которой она модифицирует общие с прерыванием ресурсы FIFO (указатели/счетчики), следующими действиями:
2.1. Установить флаг.
2.2. Выполнить действия.
2.3. Сбросить флаг.
2.4. (Пере)разрешить прерывание от источника данных.

Прерывание работает так:
3. проверить флаг критической секции.
4. Если установлен - НЕ сбрасывать свои биты прерывания, ЗАПРЕТИТЬ свое прерывание и выйти. Если сброшен - выполнить надлежащие действия над данными и указателями/счетчиками, сбросить биты прерывания, выйти.

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

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

Сообщение отредактировал KnightIgor - Apr 2 2014, 08:30
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 2 2014, 09:04
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
2.1. Установить флаг.
2.2. Выполнить действия.
2.3. Сбросить флаг.
2.4. (Пере)разрешить прерывание от источника данных.

а чем это отличается от запрета прерывания перед входом в критическую секцию, и разрешением его после выхода?

2.1. запретить прерывание (не все, а конкретное)
2.2. Выполнить действия.
2.3. Разрешить прерывание (не все, а конкретное)
прерывание вызванное до 2.1 и после 2.3 также как в вашем случае вызванное до 2.1 и после 2.4
прерывание между 2.1 - 2.2 и 2.2 - 2.3 не будет вызвано, его вызов отложиться до после 2.3,
А в вашем случае прерывание между 2.1 - 2.2 и 2.2 - 2.3 будет вызвано, в нем оно себя запретит, выйдет, после чего будет также не вызываться, до окончания 2.4

и кого вы обманулиsm.gif? сами себя, напихав доп действий%)?
это мне надо было в гугле найти?
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Apr 2 2014, 09:33
Сообщение #17


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Golikov A. @ Apr 2 2014, 10:04) *
а чем это отличается от запрета прерывания перед входом в критическую секцию, и разрешением его после выхода?

Разница есть. Речь о том, кто запрещает прерывание: конкурент (это плохо) или сам обработчик (он в курсе, и это лучше).

Запрет прерывания в основной программе (скорее всего, некоем быстром цикле) происходил бы всегда и безусловно, и во время критической секции прерывание вообще бы не сработало. В моем же методе прерывание, как основной поставщик асинхронных данных, имеет приоритет, т.к. не запрещается извне, а само контролирует ситуацию, откладывать себя или нет. Кстати, такой же подход (когда конкурент за ресурс не запрещает, а разрешает прерывание) работает у меня в системе с двумя RF модулями на одной SPI-шине (конечно, каждый с собственным chip select): каждый модуль вырабатывает прерывание, которое должно слизать из него принятые данные. Но и основная программа может инициировать синхронный обмен с модулями. Что будет, если основная программа как раз обменивается с другим модулем, шина SPI занята, а первому модулю срочно приспичило? Нужно отложить прерывание, а конкурент, закончив обмен по SPI, его всегда переразрешает. Если оно было отложено, оно сработает. Такой подход, кстати, исключает также и взаимную блокировку, т.к. конкурент за ресурс ничего не запрещает.

P.S. Не Вам, а ТС в Гугле найти. Я никого не собираюсь переубеждать. Я рассказываю, как это работает у меня.

Сообщение отредактировал KnightIgor - Apr 2 2014, 09:35
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 2 2014, 11:48
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



давайте еще раз, я чего то не понимаю

моя последовательность действий

1. запрет прерывания
2. обработка
3. разрешение прерывания.

в случае прерывания до 1 или после 3 все работает
в случае прерывания 1-2, 2-3 обработка прерывания откладывается до после 3, и там обрабатывается

ваша последовательность действий
1. ставим флаг
2. обработка
3. снятие флага.
4. разрешение прерывания
в случае до 1 и после 4 все работает
в случае прерывания 1-2, 2-3, 3-4, прерывание вызывается, запрещает себя, выходит из прерывания, продолжает обработка, а прерывание откладывается до после 4, где повторно вызывается и обрабатывается.

результат один, прерывание работает либо до либо после критического куска, прерывание не работает внутри куска, все вызовы внутри откладываются до окончания куска.

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



Цитата
Разница есть. Речь о том, кто запрещает прерывание: конкурент (это плохо) или сам обработчик (он в курсе, и это лучше).


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

Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Apr 2 2014, 14:27
Сообщение #19


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Golikov A. @ Apr 2 2014, 12:48) *
давайте еще раз, я чего то не понимаю
результат один, прерывание работает либо до либо после критического куска, прерывание не работает внутри куска, все вызовы внутри откладываются до окончания куска.

Выделенным жирно в цитате - КЛЮЧЕВОЙ МОМЕНТ, в котором и заключается разница методов:
- при запрете прерывания перед критической секцией в основной программе (Ваш вариант) ВХОДА в прерывание действительно не будет, как Вы и написали выше. Мне такое поведение алгоритма не нравится, т.к. это есть блокировка со стороны конкурента.
- в моем варианте вход в прерывание происходит даже внутри критической секции конкурента, то есть прерывание РАБОТАЕТ внутри куска. И именно прерывание решает, что делать, поняв, что прервало критическую секцию. В простейшем случае - отложить саму себя.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Apr 2 2014, 16:15
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



По-моему, задача обработки фифо решена была несколько раньше, чем я пошёл в школу. А мне уже 47.
Стандартно делается 2 указателя на начало и конец. Прерывание работает с указателем на конец, а голова с указателем на начало.
Критическим является лишь сравнение указалей для контроля "перехлёста", если это принципиально возможно (например при управлении потоком и т.п.)
Это 1 оператор. Его лучше защитить критической секцией. Это самый простой способ.
Стиральная доска, надёжнее чем стиральная машина. Усложнение программы не ведёт к увеличению её надёжности в целом. Всегда существует какой-то баланс.
Поэтому я разделяю позицию Golikov A.. Усложнение программы должно быть обосновано. Надёжностью, наглядностью, прочими критериями.
Рассуждения KnightIgor мне показались неубедительными ...
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 2 2014, 16:59
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
то есть прерывание РАБОТАЕТ внутри куска. И именно прерывание решает, что делать, поняв, что прервало критическую секцию. В простейшем случае - отложить саму себя.

то есть прерывание определяет откуда его вызвали? Не легче ли это определять тому в ком прерывание может быть потенциально вызвано? Хотя в общих чертах я понял чего вы хотели, просто пример неудачный...
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 00:39
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(SasaVitebsk @ Apr 2 2014, 22:15) *
По-моему, задача обработки фифо решена была несколько раньше, чем я пошёл в школу. А мне уже 47.
Стандартно делается 2 указателя на начало и конец. Прерывание работает с указателем на конец, а голова с указателем на начало.
Критическим является лишь сравнение указалей для контроля "перехлёста", если это принципиально возможно (например при управлении потоком и т.п.)
Это 1 оператор. Его лучше защитить критической секцией. Это самый простой способ.

Для FIFO вообще не нужны критические секции если есть только один писатель и только один читатель.
Это даёт возможность использовать их даже там, где запрет прерываний невозможен в принципе (например: в межпроцессорном обмене).
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Apr 3 2014, 02:12
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(jcxz @ Apr 3 2014, 03:39) *
Для FIFO вообще не нужны критические секции если есть только один писатель и только один читатель.

Именно об этом я и писал. Но, в случае управления потоком, когда контролируешь переполнение буфера, всё же приходится делать одну критическую секцию.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 02:54
Сообщение #24


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Как так? FIFO не должно переполняться. Что-то у вас не так...
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 3 2014, 03:57
Сообщение #25


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

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



Цитата(SasaVitebsk @ Apr 2 2014, 20:15) *
Рассуждения KnightIgor мне показались неубедительными ...
Ну отчего же?
Тоже вполне себе решение. Кстати, существенно уменьшающее латентность системы в целом.
Когда-то это может быть чуть ли не единственным выходом из ситуации (безотносительно примера с fifo).
Правда, практически того же эффекта можно добиться запрещая-разрешая прерывание _конкретного_ источника, а не всех прерываний в фоновой задаче.
Избирательность - это хорошо.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
adnega
сообщение Apr 3 2014, 06:23
Сообщение #26


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Хорошо бы примерчик взаимной блокировки от KnightIgor. Это ведь главное (ключевое) отличие Вашего подхода?
Мол, конкурирующий запрет привел к блокировке, а конкурирующее разрешение нет.

И еще: кто-нить пользуется SVC? Может, лучше через SVC, раз "лишние" прерывания KnightIgor не напрягают?
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Apr 3 2014, 06:32
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(jcxz @ Apr 3 2014, 05:54) *
Как так? FIFO не должно переполняться. Что-то у вас не так...

Да элементарно. Представим себе модем. Скорость rs232 115200, скорость по линии 33600. И ваш fifo по определению переполняется. Дабы этого не происходило, вам надо при заполнении фифо на 90% управлять потоком. То есть высылать XOFF либо снимать RTS. А при освобождении буфера необходимо опять разрешать подгрузку. В целом так будет происходить в любом случае, когда скорость обработки информации меньше чем скорость заполнения буфера.

Так вот в момент определения уровня заполнения буфера, необходимо сравнивать 2 указателя. В общем случае требуется критическая секция.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Apr 3 2014, 06:52
Сообщение #28


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
И еще: кто-нить пользуется SVC? Может, лучше через SVC, раз "лишние" прерывания KnightIgor не напрягают?

начинаю ненавидеть аббревиатуры, впечатление что все в курсе, а ты один дурак не понимаешь о чем речь. SVS - это че?sm.gif

Цитата
Так вот в момент определения уровня заполнения буфера, необходимо сравнивать 2 указателя. В общем случае требуется критическая секция.

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


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

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

Если я чего-то упустил, был бы благодарен примеру, не стеба ради, а чтобы стать лучше чем был вчера...
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 3 2014, 06:56
Сообщение #29


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

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



Цитата(Golikov A. @ Apr 3 2014, 10:52) *
начинаю ненавидеть аббревиатуры, впечатление что все в курсе, а ты один дурак не понимаешь о чем речь. SVS - это че?sm.gif
SVC - это http://en.wikipedia.org/wiki/Supervisor_Call_instruction
ну и для ARM-CM3 конкретно.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Apr 3 2014, 06:58
Сообщение #30


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата
SVS - это че?

Это видимо имелось в виду программное прерывание. Правильнее его называть SWI.

Цитата
а чтобы стать лучше чем был вчера...

Проще использовать мютексы и не городить сложных систем с критическими секциями и платформозависимой атомарностью. Не разделяю любви с неблокирующим алгоритмам - их очень трудно поддерживать и очень легко сломать.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 08:24
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(adnega @ Apr 3 2014, 12:23) *
И еще: кто-нить пользуется SVC? Может, лучше через SVC, раз "лишние" прерывания KnightIgor не напрягают?

Я пользуюсь sm.gif

Цитата(SasaVitebsk @ Apr 3 2014, 12:32) *
Да элементарно. Представим себе модем. Скорость rs232 115200, скорость по линии 33600. И ваш fifo по определению переполняется. Дабы этого не происходило, вам надо при заполнении фифо на 90% управлять потоком. То есть высылать XOFF либо снимать RTS. А при освобождении буфера необходимо опять разрешать подгрузку. В целом так будет происходить в любом случае, когда скорость обработки информации меньше чем скорость заполнения буфера.
Так вот в момент определения уровня заполнения буфера, необходимо сравнивать 2 указателя. В общем случае требуется критическая секция.

Фловконтроль для согласования скоростей каналов и программный фифо - несколько разные вещи.
Да, управлять потоком можно от уровня заполненности программного FIFO.
Так вот - для вычисления уровня заполненности FIFO критическая секция совсем не нужна sm.gif
На чтение обе стороны могут использовать оба указателя FIFO. На запись - каждая сторона только свой указатель.

Цитата(andrewlekar @ Apr 3 2014, 12:58) *
Это видимо имелось в виду программное прерывание. Правильнее его называть SWI.

Может и правильнее, но в документации Cortex оно называется SVC (SuperVisor Call). sm.gif
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Apr 3 2014, 10:23
Сообщение #32


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(jcxz @ Apr 3 2014, 11:24) *
Так вот - для вычисления уровня заполненности FIFO критическая секция совсем не нужна sm.gif

Я написал "в общем случае". rolleyes.gif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 11:45
Сообщение #33


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(andrewlekar @ Apr 3 2014, 12:58) *
Проще использовать мютексы и не городить сложных систем с критическими секциями и платформозависимой атомарностью. Не разделяю любви с неблокирующим алгоритмам - их очень трудно поддерживать и очень легко сломать.

Интересно - как вы с помощью мьютексов и прочих блокирующих методов синхронизируете работу фоновой задачи с ISR-ами?
Научите!

К тому-же - реализация мьютексов в ОС имхо всегда основывается внутри на критических секциях и/или атомарном доступе.
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Apr 3 2014, 13:29
Сообщение #34


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата
Интересно - как вы с помощью мьютексов и прочих блокирующих методов синхронизируете работу фоновой задачи с ISR-ами?

Поллинг и фифо решают 90% задач связанных с прерываниями. Если надо из ISR сигнализировать приложению, то можно в задаче захватывать семафор, а в прерывании отпускать. Это позволит заблокировать задачу до прихода прерывания.

Цитата
реализация мьютексов в ОС имхо всегда основывается внутри на критических секциях и/или атомарном доступе.

Кто же спорит. Но мы этого не видим и туда без необходимости не лезем.
Go to the top of the page
 
+Quote Post
adnega
сообщение Apr 3 2014, 14:23
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(jcxz @ Apr 3 2014, 12:24) *
Я пользуюсь sm.gif

На чистом C или с ASM-вставками?
В Keil или GCC?

Цитата(jcxz @ Apr 3 2014, 12:24) *
Может и правильнее, но в документации Cortex оно называется SVC (SuperVisor Call). sm.gif

Насколько я понял, разработчики Cortex-M изменили название инструкции (сохранив числовое значение) при переходе с ARM7,
чтобы программист, который портирует код уделил внимание особенностям новой системы исключений.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 14:38
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(andrewlekar @ Apr 3 2014, 19:29) *
Поллинг и фифо решают 90% задач связанных с прерываниями. Если надо из ISR сигнализировать приложению, то можно в задаче захватывать семафор, а в прерывании отпускать. Это позволит заблокировать задачу до прихода прерывания.

Фифо - это не блокирующий метод.
И что толку от сигнализации если нужно эксклюзивное чтение-модификация-запись некоей области памяти в ISR и фоновой задаче (критическая секция)?
Хорошо если можно в ISR тупо писать/читать в фифо. А если нужна работа с более сложной структорой данных в памяти?
Или то же самое фифо, но несколько писателей или несколько читателей? Как вы тут без критической секции обойдётесь?
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Apr 3 2014, 15:08
Сообщение #37


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Тут достаточно не критической секции, а запрета конкретного источника прерывания перед установкой семафора. При работе с ISR так или иначе запрещать прерывания придётся. Но но уровне операционки можно написать тонны софта ни разу не встретившись с прерыванием. В линуксе скажем они где-то глубоко запрятаны. В таком случае городить всякие lock-free и критические секции нет никакой нужды до тех пор, пока реально не понадобится улучшить производительность.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 3 2014, 15:21
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(adnega @ Apr 3 2014, 20:23) *
На чистом C или с ASM-вставками?
В Keil или GCC?

В IAR. Вызовы - на си, обработчик SVC - на асме.
Вот так декларирую:
Код
#define SVCF_trap0       0
#define SVCF_trap1       1
#define SVCF_trap2       2
#define SVCF_trap3       3
#define SVCF_trapMax     SVCF_trap3
#define SVCF_AppRestart  (SVCF_trapMax+1)
#pragma swi_number=SVCF_trap0
__swi void trap(u32);
#pragma swi_number=SVCF_trap1
__swi void trap(u32, u32);
#pragma swi_number=SVCF_trap2
__swi void trap(u32, u32, u32);
#pragma swi_number=SVCF_trap3
__swi void trap(u32, u32, u32, u32);
#pragma swi_number=SVCF_AppRestart
__swi void AppRestart();
Как видите - SVC использую для вызова обработчика критических ошибок. Вызовов таких в коде - тьма-тьмущая (одних только ASSERT-ов...).
А с использованием SVC вызов получается очень компактным.
И что самое важное - в этом обработчике у меня сохраняется дамп прерванного контекста CPU, а обычный BL в этом случае даёт меньше возможностей.
Go to the top of the page
 
+Quote Post
kostyan
сообщение Apr 4 2014, 01:26
Сообщение #39


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 8-11-05
Пользователь №: 10 577



Цитата(andrewlekar @ Apr 3 2014, 19:29) *
Поллинг и фифо решают 90% задач связанных с прерываниями. Если надо из ISR сигнализировать приложению, то можно в задаче захватывать семафор, а в прерывании отпускать. Это позволит заблокировать задачу до прихода прерывания.


Кто же спорит. Но мы этого не видим и туда без необходимости не лезем.


А если существует более чем один источник часто повторяющихся прерываний, то эти ваши "невидимые" семафоры в прерываниях уронят всю систему. И в сервисах осей как раз стопроцентно используются критические секции. Уже два раза напоролся на такое - сейчас принципиально стараюсь в прерываниях не юзать осевые сервисы.
Go to the top of the page
 
+Quote Post

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

 


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


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