Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Атомарность чтения
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Serg_el
Коллеги!

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

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

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 - это сложные указатели на структуры и для того, чтобы получить в итоге адрес, нужно несколько ассемблерных команд. Гарантируется ли в это случае компилятором сохранение всех участвующих регистров в стеке?

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

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

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



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

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


PS Раньше просто не заморачивался, делал обертку из запрета/разрешения прерывания и все. Но пока не возникла потребность в более частых прерываниях, а переменные, которые надо скопировать, не увеличились в количестве. Про LDREXW знаю и скорее всего буду использовать, главное знать, что это обязательно при чтении без модификации и записи.
demiurg_spb
Цитата(Serg_el @ Apr 1 2014, 13:20) *
А что же по поводу сохранения всех регистров, участвующих в копировании в стек?

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

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

Кстати, копия переменной не нужна вовсе, т.к. на CM3 доступ к 32-ух битным переменным атомарен от рождения (в смысле чтения и записи),
а вот например её инкремент нифига не атомарная операция, а LOAD-MODIFY-STORE (аж 3 шага, которые не должны быть прерваны соответствующим ISR).
Serg_el
Цитата(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 - часть сложной структуры?
demiurg_spb
Повторюсь, не нужно блокировать прерывания при записи 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
        ...
    }
}
Serg_el
Цитата(demiurg_spb @ Apr 1 2014, 14:31) *
Повторюсь, не нужно блокировать прерывания при записи int - это и так атомарная операция.
Да, никакой разницы нет, является ли int частью структуры или нет.


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

jcxz
Цитата(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.
Golikov A.
Да вы вообще не о том думаете.

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

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

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

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

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

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

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

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

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


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

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

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






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

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

Как уже отвечали ниже, определенные инструкции обеспечивают атомарность операций чтения/записи элементарных данных. Это, однако, частные случаи. В общем же необходимо обеспечивать "атомарность" целого блока действий. Например, быстрый прием потока данных по прерываниям по UART в очередь (FIFO) и выборка этих данных в основной программе. В таком случае возникает проблема "атомарности" даже не чтения, а модификации целого ряда указателей и счетчиков. Обрамлять такие действия критической секцией с запретом прерываний - это по меньшей мере нарваться на "фе-е-е" крутых программеров на форуме. Поэтому подойдите к проблеме комплексно с самого начала, решив ее для себя один раз и навсегда.
Golikov A.
туманно вы в конце написали а главное решения то не подсказалиsm.gif... того что раз и навсегда...
KnightIgor
Цитата(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, переразрешит прерывание. Прерывание тут же вызовется снова, обнаружит сброшеный флаг и произведет соответствующие модицикации.

Конечно, принципиально от запрета прерывания избавиться не получается, но его запрещает не основная программа непонятно когда и зачем (и невовремя), а само прерывание, и только себя, и только, когда попало внутрь критической секции основного цикла. Получается как бы отложенная обработка прерывания.
Golikov A.
Цитата
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? сами себя, напихав доп действий%)?
это мне надо было в гугле найти?
KnightIgor
Цитата(Golikov A. @ Apr 2 2014, 10:04) *
а чем это отличается от запрета прерывания перед входом в критическую секцию, и разрешением его после выхода?

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

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

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

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

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

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

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

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

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



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


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

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

Выделенным жирно в цитате - КЛЮЧЕВОЙ МОМЕНТ, в котором и заключается разница методов:
- при запрете прерывания перед критической секцией в основной программе (Ваш вариант) ВХОДА в прерывание действительно не будет, как Вы и написали выше. Мне такое поведение алгоритма не нравится, т.к. это есть блокировка со стороны конкурента.
- в моем варианте вход в прерывание происходит даже внутри критической секции конкурента, то есть прерывание РАБОТАЕТ внутри куска. И именно прерывание решает, что делать, поняв, что прервало критическую секцию. В простейшем случае - отложить саму себя.
SasaVitebsk
По-моему, задача обработки фифо решена была несколько раньше, чем я пошёл в школу. А мне уже 47.
Стандартно делается 2 указателя на начало и конец. Прерывание работает с указателем на конец, а голова с указателем на начало.
Критическим является лишь сравнение указалей для контроля "перехлёста", если это принципиально возможно (например при управлении потоком и т.п.)
Это 1 оператор. Его лучше защитить критической секцией. Это самый простой способ.
Стиральная доска, надёжнее чем стиральная машина. Усложнение программы не ведёт к увеличению её надёжности в целом. Всегда существует какой-то баланс.
Поэтому я разделяю позицию Golikov A.. Усложнение программы должно быть обосновано. Надёжностью, наглядностью, прочими критериями.
Рассуждения KnightIgor мне показались неубедительными ...
Golikov A.
Цитата
то есть прерывание РАБОТАЕТ внутри куска. И именно прерывание решает, что делать, поняв, что прервало критическую секцию. В простейшем случае - отложить саму себя.

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

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

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

И еще: кто-нить пользуется SVC? Может, лучше через SVC, раз "лишние" прерывания KnightIgor не напрягают?
SasaVitebsk
Цитата(jcxz @ Apr 3 2014, 05:54) *
Как так? FIFO не должно переполняться. Что-то у вас не так...

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

Так вот в момент определения уровня заполнения буфера, необходимо сравнивать 2 указателя. В общем случае требуется критическая секция.
Golikov A.
Цитата
И еще: кто-нить пользуется SVC? Может, лучше через SVC, раз "лишние" прерывания KnightIgor не напрягают?

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

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

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


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

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

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

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

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

Проще использовать мютексы и не городить сложных систем с критическими секциями и платформозависимой атомарностью. Не разделяю любви с неблокирующим алгоритмам - их очень трудно поддерживать и очень легко сломать.
jcxz
Цитата(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
SasaVitebsk
Цитата(jcxz @ Apr 3 2014, 11:24) *
Так вот - для вычисления уровня заполненности FIFO критическая секция совсем не нужна sm.gif

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

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

К тому-же - реализация мьютексов в ОС имхо всегда основывается внутри на критических секциях и/или атомарном доступе.
andrewlekar
Цитата
Интересно - как вы с помощью мьютексов и прочих блокирующих методов синхронизируете работу фоновой задачи с ISR-ами?

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

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

Кто же спорит. Но мы этого не видим и туда без необходимости не лезем.
adnega
Цитата(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,
чтобы программист, который портирует код уделил внимание особенностям новой системы исключений.
jcxz
Цитата(andrewlekar @ Apr 3 2014, 19:29) *
Поллинг и фифо решают 90% задач связанных с прерываниями. Если надо из ISR сигнализировать приложению, то можно в задаче захватывать семафор, а в прерывании отпускать. Это позволит заблокировать задачу до прихода прерывания.

Фифо - это не блокирующий метод.
И что толку от сигнализации если нужно эксклюзивное чтение-модификация-запись некоей области памяти в ISR и фоновой задаче (критическая секция)?
Хорошо если можно в ISR тупо писать/читать в фифо. А если нужна работа с более сложной структорой данных в памяти?
Или то же самое фифо, но несколько писателей или несколько читателей? Как вы тут без критической секции обойдётесь?
andrewlekar
Тут достаточно не критической секции, а запрета конкретного источника прерывания перед установкой семафора. При работе с ISR так или иначе запрещать прерывания придётся. Но но уровне операционки можно написать тонны софта ни разу не встретившись с прерыванием. В линуксе скажем они где-то глубоко запрятаны. В таком случае городить всякие lock-free и критические секции нет никакой нужды до тех пор, пока реально не понадобится улучшить производительность.
jcxz
Цитата(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 в этом случае даёт меньше возможностей.
kostyan
Цитата(andrewlekar @ Apr 3 2014, 19:29) *
Поллинг и фифо решают 90% задач связанных с прерываниями. Если надо из ISR сигнализировать приложению, то можно в задаче захватывать семафор, а в прерывании отпускать. Это позволит заблокировать задачу до прихода прерывания.


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


А если существует более чем один источник часто повторяющихся прерываний, то эти ваши "невидимые" семафоры в прерываниях уронят всю систему. И в сервисах осей как раз стопроцентно используются критические секции. Уже два раза напоролся на такое - сейчас принципиально стараюсь в прерываниях не юзать осевые сервисы.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.