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

 
 
> Глобальное прерывание, возможно ли?
Yaumen
сообщение Nov 5 2009, 13:32
Сообщение #1


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

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



В очередной раз натолкнулся на проблему. В этот раз связанную с прерываниями.

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

Есть ли решение в этой ситуации или надо полностью менять подход при работе с очередью?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
defunct
сообщение Nov 6 2009, 16:15
Сообщение #2


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Yaumen @ Nov 5 2009, 15:32) *
Есть ли решение в этой ситуации или надо полностью менять подход при работе с очередью?

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

Код
typedef struct tagQUEUE
{
     volatile int put;
     volatile int get;
     int cnt;
     PVOID *pStorage;
} TQUEUE, *PQUEUE;

void queue_define( PQUEUE pq, PVOID storage, int storage_size)
{
    pq->cnt = storage_size / sizeof( PVOID );
    pq->put = pq->get = 0;
    pq->pStorage = storage;
}

PVOID queue_read( PQUEUE pq )
{
    PVOID retval = NULL;
    if (pq->get != pq->put)
    {  // got smth to read
         int new_index = pq->get + 1;
         if (new_index >= pq->cnt)
             new_index = 0;
         retval = pq->pStorage[ pq->get ];
         pq->get = new_index;
     }
     return retval;
}

void queue_write( PQUEUE pq, PVOID msg )
{
     int new_index = pq->put + 1;
     if (new_index >= pq->cnt)
         new_index = 0;
     pq->pStorage[ pq->put ] = msg;  // <-- эта операция защищена, т.к. индекс put еще не изменился, функция чтения не знает о наличии новой записи
     pq->put = new_index;  // <-- здесь требуется атомарная модификация индекса, т.е. чтобы переменная  put записалась одной асм командой (отсюда переменная put не может быть разрядностью больше чем разрядность регистров процессора).
}
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 6 2009, 16:30
Сообщение #3


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(defunct @ Nov 6 2009, 19:15) *
Очереди (направленные очереди если быть точнее) можно организовать так, что запрет прерываний непотребуется.


У автора нет никаких очередей. Где-то в цикле в main() чего обрабатывается, а по прерыванию - заполняется. При таком подходе поможет только механизм критических секций.

Цитата(_dem)
Позволю себе подправить - запоминает текущее состояние контроллера прерывания, а главное - pending interrupts. И при выходе из секции делает текущему OR с сохраненным.


Если запрещать/восстанавливать глобальное прерывание на уровне процессора, то в контроллере прерываний все автоматом запоминается/выполняется и нет никакого смысла на уровне контроллера прерываний усложнять себе жизнь.
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 6 2009, 16:41
Сообщение #4


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(sergeeff @ Nov 6 2009, 18:30) *
У автора нет никаких очередей.

Будьте внимательнее, в самом первом посте написано:
Цитата
я организовал очередь сообщений, которая пополняется вызовом метода AddMessage


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

см. код выше. Гарантирую что он будет работать так как надо без крит секций и запрета прерываний.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 6 2009, 17:04
Сообщение #5


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(defunct @ Nov 6 2009, 19:41) *
Гарантирую что он будет работать так как надо без крит секций и запрета прерываний.


А как вы собираетесь добиться атомарности в операции модификация индекса без запрета прерываний? Если бы в левой части оператора присвоения стояла бы локальная переменная той же размерности , что и переменная слева от оператора присвоения - вопросов нет. Но слева - член структуры. И все зависит от того как конкретный компилятор при определенных опциях оттранслирует это присваивание. Да, скорее всего - атомарно. Но не факт, что это будет выполняться всегда и везде.
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 6 2009, 17:07
Сообщение #6


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(sergeeff @ Nov 6 2009, 19:04) *
А как вы собираетесь добиться атомарности в операции модификация индекса без запрета прерываний?

там написано:
(отсюда переменная put не может быть разрядностью больше чем разрядность регистров процессора)
к get это тоже относится

Цитата
И все зависит от того как конкретный компилятор при определенных опциях оттранслирует это присваивание.

Не важно сколько команд уйдет на выполнение Сишной конструкции
pq->put = new_index;

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



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

 


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


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