|
Глобальное прерывание, возможно ли? |
|
|
|
Nov 5 2009, 13:32
|
Частый гость
 
Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213

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

кекс
     
Группа: Свой
Сообщений: 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 не может быть разрядностью больше чем разрядность регистров процессора). }
|
|
|
|
|
Nov 6 2009, 16:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(defunct @ Nov 6 2009, 19:15)  Очереди (направленные очереди если быть точнее) можно организовать так, что запрет прерываний непотребуется. У автора нет никаких очередей. Где-то в цикле в main() чего обрабатывается, а по прерыванию - заполняется. При таком подходе поможет только механизм критических секций. Цитата(_dem) Позволю себе подправить - запоминает текущее состояние контроллера прерывания, а главное - pending interrupts. И при выходе из секции делает текущему OR с сохраненным. Если запрещать/восстанавливать глобальное прерывание на уровне процессора, то в контроллере прерываний все автоматом запоминается/выполняется и нет никакого смысла на уровне контроллера прерываний усложнять себе жизнь.
|
|
|
|
|
Nov 6 2009, 16:41
|

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

|
Цитата(sergeeff @ Nov 6 2009, 18:30)  У автора нет никаких очередей. Будьте внимательнее, в самом первом посте написано: Цитата я организовал очередь сообщений, которая пополняется вызовом метода AddMessage А по поводу Цитата Где-то в цикле в main() чего обрабатывается, а по прерыванию - заполняется. При таком подходе поможет только механизм критических секций. см. код выше. Гарантирую что он будет работать так как надо без крит секций и запрета прерываний.
|
|
|
|
|
Nov 6 2009, 17:07
|

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

|
Цитата(sergeeff @ Nov 6 2009, 19:04)  А как вы собираетесь добиться атомарности в операции модификация индекса без запрета прерываний? там написано: (отсюда переменная put не может быть разрядностью больше чем разрядность регистров процессора) к get это тоже относится Цитата И все зависит от того как конкретный компилятор при определенных опциях оттранслирует это присваивание. Не важно сколько команд уйдет на выполнение Сишной конструкции pq->put = new_index; важно, чтобы именно запись (STR) осуществилась атомарно. т.е. чтобы переменная put ни при каких условиях не оказалась в памяти "частично модифицированной". А для этого достаточно сделать ее шириной в регистр проца и пользовать соответвующее выравнивание (чтобы компилятор не дробил инструкцию записи напр STR на несколько инструкций STRB).
|
|
|
|
Сообщений в этой теме
Yaumen Глобальное прерывание, возможно ли? Nov 5 2009, 13:32 _dem "В этом процессоре" - это в Athlon X2 54... Nov 5 2009, 13:43 sergeeff Да, очень интересно, что это за процессор, у котор... Nov 5 2009, 13:52 aaarrr Если речь идет о глобальном разрешении/запрещении ... Nov 5 2009, 13:53 sergeeff Вообще-то для этого существуют критические секции.... Nov 5 2009, 13:56 _dem Позволю себе подправить - запоминает текущее состо... Nov 5 2009, 15:25 sergeeff Действительно не дурно! Nov 6 2009, 17:24 Yaumen Я извиняюсь, за отсутствие в собственно созданной ... Nov 10 2009, 07:13
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|