Как организовать атомарные функции в кейл для aduc70xx
Как организовать атомарные функции в кейл для aduc70xx
Доброго времени суток. Подскажите как организовать атомарные функции в кейл контроллер aduc7024 ядро ARM7. Тему штудировал но такие вещи как atomic block не нашел? просто запретить прерывание тоже не совсем то.
Re: Как организовать атомарные функции в кейл для aduc70xx
1. Реализуй какое-нибудь средство синхронизации, например, семафоры. Я думаю в интернете найдется много статей как это сделать.
2. Если запрещать все прерывания не охота, то запрещай только то, которое использует эту функцию.
Если функция вызывается только из прерываний, то не имеет смысла что-либо с ней делать, потому что контроллер прерываний не поддерживает вложенные прерывания, то есть прерывание не может прервать другое прерывание. Это конечно можно обойти, но надо реализовывать ручками функцию-обертку для прерываний.
2. Если запрещать все прерывания не охота, то запрещай только то, которое использует эту функцию.
Если функция вызывается только из прерываний, то не имеет смысла что-либо с ней делать, потому что контроллер прерываний не поддерживает вложенные прерывания, то есть прерывание не может прервать другое прерывание. Это конечно можно обойти, но надо реализовывать ручками функцию-обертку для прерываний.
Re: Как организовать атомарные функции в кейл для aduc70xx
Так то у него не Cortex, да и судя по описанию они никак не помогут в реализации атомарной операции.
DMB
Data Memory Barrier acts as a memory barrier. It ensures that all explicit memory accesses that appear in program order before the DMB instruction are observed before any explicit memory accesses that appear in program order after the DMB instruction. It does not affect the ordering of any other instructions executing on the processor.
Как я понял она предотвращает возможное внеочередное исполнение команд доступа к памяти. То что находится после нее не может быть выполнено раньше, чем то, что находится до нее и наоборот.
DSB
Data Synchronization Barrier acts as a special kind of memory barrier. No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
All explicit memory accesses before this instruction complete.
All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
Как я понял это некий способ удостоверится, что перечисленные операции (explicit memory accesses, Cache, Branch predictor and TLB maintenance operations) полностью завершены к моменту "выхода" из этой инструкции.
Однако, начиная с ARMv6 есть инструкции которые действительно могут помочь (только помочь) в реализации средства синхронизации: LDREX и STREX. Но ARM7 реализует ARMv4 и там этого нету. Так что в любом случае придется делать что-то самому на Си или на Си+Ассемблер.
DMB
Data Memory Barrier acts as a memory barrier. It ensures that all explicit memory accesses that appear in program order before the DMB instruction are observed before any explicit memory accesses that appear in program order after the DMB instruction. It does not affect the ordering of any other instructions executing on the processor.
Как я понял она предотвращает возможное внеочередное исполнение команд доступа к памяти. То что находится после нее не может быть выполнено раньше, чем то, что находится до нее и наоборот.
DSB
Data Synchronization Barrier acts as a special kind of memory barrier. No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
All explicit memory accesses before this instruction complete.
All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
Как я понял это некий способ удостоверится, что перечисленные операции (explicit memory accesses, Cache, Branch predictor and TLB maintenance operations) полностью завершены к моменту "выхода" из этой инструкции.
Однако, начиная с ARMv6 есть инструкции которые действительно могут помочь (только помочь) в реализации средства синхронизации: LDREX и STREX. Но ARM7 реализует ARMv4 и там этого нету. Так что в любом случае придется делать что-то самому на Си или на Си+Ассемблер.
- balmer
- Это не хвост, это антенна
- Сообщения: 1433
- Зарегистрирован: Вс дек 02, 2012 03:13:48
- Откуда: Калининград
Re: Как организовать атомарные функции в кейл для aduc70xx
menzoda писал(а):Однако, начиная с ARMv6 есть инструкции которые действительно могут помочь (только помочь) в реализации средства синхронизации: LDREX и STREX. Но ARM7 реализует ARMv4 и там этого нету.
Да, в сортах процессоров не разбираюсь, казалось что Thumb давно уже везде есть
LDREX и STREX хорошие инструкции. Но лично мне достаточно и простого чтения/записи в память. Достаточно того, что 4-x байтовые слова пишутся и читаются атомарно.
Так что ждем от автора темы подробного описания зачем это надо. Таки у него не многопроцессорная система, так что элементарно должно быть все.
Re: Как организовать атомарные функции в кейл для aduc70xx
Нашел такую реализацию в кейле __disable_irq();/__enable_irq(); у себя в коде не проверял
разворачивается так:
я реализовал проверку без запрета прерывания:
может кто подскажет более оптимальный вариант.
мне атомарность нужна в связи с тем что модификация может производится и в прерываниях.
разворачивается так:
Код: Выделить всё
49: __disable_irq();
0x00081844 E10F0000 MRS R0,CPSR
0x00081848 E3800080 ORR R0,R0,#0x00000080
0x0008184C E121F000 MSR CPSR_c,R0
50: __enable_irq();
0x00081B08 E10F0000 MRS R0,CPSR
0x00081B0C E3C00080 BIC R0,R0,#0x00000080
0x00081B10 E121F000 MSR CPSR_c,R0
я реализовал проверку без запрета прерывания:
Код: Выделить всё
#define FL_PT_CNT 11U // Флаг активации счетчика протопотоков
void SetFlagsis(byte flag) // Установить системный флаг
{
in_FlagS:
BitMaskSet(g_lFlagsis,(U32)(1 << flag));
if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS;
}
можно было реализовать через do while но на мой взгляд с goto тоже нормально (ни чего против goto не имею если выглядит красиво)
136: BitMaskSet(g_lFlagsis,(U32)(1 << flag));
0x00083104 E3A02001 MOV R2,#0x00000001
0x00083108 E59F101C LDR R1,[PC,#0x001C]
0x0008310C E1A00012 MOV R0,R2,LSL R0
0x00083110 E5912028 LDR R2,[R1,#0x0028]
0x00083114 E1822000 ORR R2,R2,R0
0x00083118 E5812028 STR R2,[R1,#0x0028]
137: if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS;
0x0008311C E5912028 LDR R2,[R1,#0x0028]
0x00083120 E1120000 TST R2,R0
0x00083124 0AFFFFF9 BEQ 0x00083110
может кто подскажет более оптимальный вариант.
мне атомарность нужна в связи с тем что модификация может производится и в прерываниях.
- balmer
- Это не хвост, это антенна
- Сообщения: 1433
- Зарегистрирован: Вс дек 02, 2012 03:13:48
- Откуда: Калининград
Re: Как организовать атомарные функции в кейл для aduc70xx
Код внутри SetFlagsis в общем случае не решает задачи.
Потому как сразу после проверки внутри if может вызваться прерывание, и очистить эту переменную.
Таки тебе надо описать задачу. Подозреваю, что там логическая проблема с управлением этим флагом.
Потому как сразу после проверки внутри if может вызваться прерывание, и очистить эту переменную.
Таки тебе надо описать задачу. Подозреваю, что там логическая проблема с управлением этим флагом.
Re: Как организовать атомарные функции в кейл для aduc70xx
Действительно, простая дополнительная проверка не решает поставленной задачи.
Если проверка и установка битов в фоне происходит не слишком часто, то не вижу ничего плохого в запрещении прерывании, которое будет длиться (имеется в виду запрещение) всего несколько тактов. На сколько часто они устанавливаются в прерываниях - не важно, потому что как я уже говорил в ARM7 прерывания не могут прерывать друг-друга и от использования __disable_irq()/____enable_irq() им ни тепло ни холодно.
А вообще я нашел документ от ARM, где вроде бы описано как реализовать синхронизацию (семафор или мьютекс), используя специальные инструкции. То что тебе надо находится в конце (appendix), там где про старые архитектуры до версии ARMv6.
Код: Выделить всё
136: BitMaskSet(g_lFlagsis,(U32)(1 << flag));
0x00083104 E3A02001 MOV R2,#0x00000001
0x00083108 E59F101C LDR R1,[PC,#0x001C]
0x0008310C E1A00012 MOV R0,R2,LSL R0
0x00083110 E5912028 LDR R2,[R1,#0x0028]
// Если прерывание произойдет в этот момент...
0x00083114 E1822000 ORR R2,R2,R0
// ...или в этот, то изменения внесенные прерыванием потеряются.
0x00083118 E5812028 STR R2,[R1,#0x0028]
137: if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS;
0x0008311C E5912028 LDR R2,[R1,#0x0028]
0x00083120 E1120000 TST R2,R0
0x00083124 0AFFFFF9 BEQ 0x00083110
Если проверка и установка битов в фоне происходит не слишком часто, то не вижу ничего плохого в запрещении прерывании, которое будет длиться (имеется в виду запрещение) всего несколько тактов. На сколько часто они устанавливаются в прерываниях - не важно, потому что как я уже говорил в ARM7 прерывания не могут прерывать друг-друга и от использования __disable_irq()/____enable_irq() им ни тепло ни холодно.
А вообще я нашел документ от ARM, где вроде бы описано как реализовать синхронизацию (семафор или мьютекс), используя специальные инструкции. То что тебе надо находится в конце (appendix), там где про старые архитектуры до версии ARMv6.
Re: Как организовать атомарные функции в кейл для aduc70xx
Спасибо за ссылку
документ сохранил. У меня проблем в коде нет, в данный момент разрабатываю программу от стабильности которой зависит здоровье людей (проект называть не имею права...). В связи с чем хочу избежать глюков связанных "с фазой луны ))" я понимаю, что разрыв модификации переменной может привести к "красивым" глюкам. Система критична ко времени (реалтайм система). От выше перечисленной переменой в принципе стабильность мало зависит но все таки... в программе использую протопотоки по этому процессы друг на друга не накладываются. А спрашиваю для того, что-бы избежать глюков с атомарностью, при этом данные модули не должны задерживать прерывания.
документ сохранил. У меня проблем в коде нет, в данный момент разрабатываю программу от стабильности которой зависит здоровье людей (проект называть не имею права...). В связи с чем хочу избежать глюков связанных "с фазой луны ))" я понимаю, что разрыв модификации переменной может привести к "красивым" глюкам. Система критична ко времени (реалтайм система). От выше перечисленной переменой в принципе стабильность мало зависит но все таки... в программе использую протопотоки по этому процессы друг на друга не накладываются. А спрашиваю для того, что-бы избежать глюков с атомарностью, при этом данные модули не должны задерживать прерывания.Re: Как организовать атомарные функции в кейл для aduc70xx
По поводу протопотоков, может откажусь от них немного тормознутая вещь... над проектом только начал работу до конца не решил всю структуру программы, ОС однозначно использовать не буду. Смотрю на написание кооперативной многозадачности, но тема для меня новая поэтому пока остановился на протопотоках так как с их помощью получается не сложная диспетчеризация, ну или по крайней мере мне так показалось.
-
SII
- Вымогатель припоя
- Сообщения: 635
- Зарегистрирован: Пт янв 30, 2009 14:50:35
- Откуда: Солнечногорск
Re: Как организовать атомарные функции в кейл для aduc70xx
В процессорах до версии ARMv6 единственные инструкции для атомарных операций -- это SWP и SWPB. Они считывают из памяти одно значение и заменяют другим, при этом в промежутке между чтением и записью никто вклиниться не может. Но, если система однопроцессорная, то в них нужды нет: достаточно запрещать прерывания на время чтения-сравнения-модификации тех или иных переменных. Но в любом случае это низкоуровневые механизмы, а задачу надо сначала решить на высоком уровне (т.е. понять, что же конкретно нужно).
Re: Как организовать атомарные функции в кейл для aduc70xx
такая реализация __disable_irq();/__enable_irq(); у меня в коде периодически нарушает работу программы, помогает только сброс! 
Re: Как организовать атомарные функции в кейл для aduc70xx
Что делать ? пришел к выводу что необходимо запрещать прерывания на время модификации очереди задач, и флага состояния, эти процедуры модифицируется как в прерывании так и в основной ветке, но как написал выше кейловские функции шлепают мне программу. Проверял без них работает нормально.
Re: Как организовать атомарные функции в кейл для aduc70xx
Нужен рабочий аналог, полагаю наверно загвоздка при переключении режимов User <----> Interrupt 
Re: Как организовать атомарные функции в кейл для aduc70xx
SII писал(а):В процессорах до версии ARMv6 единственные инструкции для атомарных операций -- это SWP и SWPB. Они считывают из памяти одно значение и заменяют другим, при этом в промежутке между чтением и записью никто вклиниться не может. Но, если система однопроцессорная, то в них нужды нет: достаточно запрещать прерывания на время чтения-сравнения-модификации тех или иных переменных. Но в любом случае это низкоуровневые механизмы, а задачу надо сначала решить на высоком уровне (т.е. понять, что же конкретно нужно).
По поводу SWP и SWPB ниже пример кода, чтобы в данном случае сделать атомарность как я понял функцию необходимо написать на АСМ и вклинить между SWP и SWPB? Т.Е. Си функцию туда уже не вклинишь.
Код: Выделить всё
SWP R0,R1,[R2] ; Загрузить в R0 слово по адресу в R2, и сохранить R1 в R2.
SWPB R2,R3,[R4] ; Загрузить в R2 байт по адресу в R4,
; и сохранить младший байт R3 в R4.
SWPEQ R0,R0,[R1] ; По условию обменять слово, определенное по адресу в R1
; и содержимым в регистре R0.
Re: Как организовать атомарные функции в кейл для aduc70xx
1. Странно, что они у тебя рушат программу, я их использовал вполне успешно. Что именно работает не так?
2. Функции __enable/__disable запрещают прерывания модифицируя регистр состояния ядра. Если не получается использовать их, то как я уже говорил, можешь запрещать прерывания в контроллере прерываний. Во-первых, можно будет запретить только те прерывания, которые осуществляют доступ к защищаемым данным, оставив остальные прерывания разрешенными, что может повысить "отзывчивость" системы. Во-вторых, при запрещении через контроллер прерываний ломаться просто нечему, все должно работать как надо.
3. Насчет примитивов синхронизации, типа SWP, LDREX и других. Они всего-лишь примитивы, основа для реализации полноценного и удобного средства синхронизации на Си/Си++, которое можно использовать как угодно, оборачивать любые участки кода и т.п. А иначе, действительно придется реализовывать функцию на ассемблере, или использовать какие-нибудь ассемблерные вставки в Си, что по моему мнению является костылем.
Я за запрещение прерываний через VIC. Это не потребует никаких лишних затрат и должно хорошо работать.
2. Функции __enable/__disable запрещают прерывания модифицируя регистр состояния ядра. Если не получается использовать их, то как я уже говорил, можешь запрещать прерывания в контроллере прерываний. Во-первых, можно будет запретить только те прерывания, которые осуществляют доступ к защищаемым данным, оставив остальные прерывания разрешенными, что может повысить "отзывчивость" системы. Во-вторых, при запрещении через контроллер прерываний ломаться просто нечему, все должно работать как надо.
3. Насчет примитивов синхронизации, типа SWP, LDREX и других. Они всего-лишь примитивы, основа для реализации полноценного и удобного средства синхронизации на Си/Си++, которое можно использовать как угодно, оборачивать любые участки кода и т.п. А иначе, действительно придется реализовывать функцию на ассемблере, или использовать какие-нибудь ассемблерные вставки в Си, что по моему мнению является костылем.
Я за запрещение прерываний через VIC. Это не потребует никаких лишних затрат и должно хорошо работать.
-
SII
- Вымогатель припоя
- Сообщения: 635
- Зарегистрирован: Пт янв 30, 2009 14:50:35
- Откуда: Солнечногорск
Re: Как организовать атомарные функции в кейл для aduc70xx
Если делать спин-блокировку (т.е. поток тупо крутится в цикле захвата блокировки до тех пор, пока не захватит), то последовательность действий примерно такова:
1. Изначальное состояние спин-блокировки (байта или слова в памяти) -- нуль.
2. Когда поток хочет захватить блокировку, он делает SWP или SWPB, запихивая в блокировку любое ненулевое значение. После этого он проверяет, что было из блокировки считано. Если был считан не нуль (т.е. если блокировка уже была захвачена другим потоком), он повторяет п. 2 -- и так до тех пор, пока не будет считан нуль.
3. Блокировка захвачена. Поток выполняет свои чёрные дела, для которых ему требовалась блокировка.
4. Закончив дела, поток записывает в блокировку нуль (не через SWP, а обычным STR -- здесь доступ к памяти однократный, а не дважды подряд, поэтому нужды в SWP нет).
У этой схемы есть тот недостаток, что, если потоки не переключаются каким-то внешним для них образом, программа "зависнет" при неудачной попытке захвата спин-блокировки. Т.е. необходимо обеспечить, чтобы, обнаружив, что блокировка уже занята, поток передавал управление другому потоку (который и захватил эту блокировку) и лишь потом опять повторял попытку захвата. Ну а как это сделать, зависит целиком от программиста и используемой им ОС.
А вот насчёт приведённого Вами фрагмента кода я, честно говоря, ничего не понял. Зачем там три команды SWP и как вообще Вы собираетесь вести обработку?
1. Изначальное состояние спин-блокировки (байта или слова в памяти) -- нуль.
2. Когда поток хочет захватить блокировку, он делает SWP или SWPB, запихивая в блокировку любое ненулевое значение. После этого он проверяет, что было из блокировки считано. Если был считан не нуль (т.е. если блокировка уже была захвачена другим потоком), он повторяет п. 2 -- и так до тех пор, пока не будет считан нуль.
3. Блокировка захвачена. Поток выполняет свои чёрные дела, для которых ему требовалась блокировка.
4. Закончив дела, поток записывает в блокировку нуль (не через SWP, а обычным STR -- здесь доступ к памяти однократный, а не дважды подряд, поэтому нужды в SWP нет).
У этой схемы есть тот недостаток, что, если потоки не переключаются каким-то внешним для них образом, программа "зависнет" при неудачной попытке захвата спин-блокировки. Т.е. необходимо обеспечить, чтобы, обнаружив, что блокировка уже занята, поток передавал управление другому потоку (который и захватил эту блокировку) и лишь потом опять повторял попытку захвата. Ну а как это сделать, зависит целиком от программиста и используемой им ОС.
А вот насчёт приведённого Вами фрагмента кода я, честно говоря, ничего не понял. Зачем там три команды SWP и как вообще Вы собираетесь вести обработку?
Re: Как организовать атомарные функции в кейл для aduc70xx
menzoda писал(а):1. Странно, что они у тебя рушат программу, я их использовал вполне успешно. Что именно работает не так?
2. Функции __enable/__disable запрещают прерывания модифицируя регистр состояния ядра. Если не получается использовать их, то как я уже говорил, можешь запрещать прерывания в контроллере прерываний. Во-первых, можно будет запретить только те прерывания, которые осуществляют доступ к защищаемым данным, оставив остальные прерывания разрешенными, что может повысить "отзывчивость" системы. Во-вторых, при запрещении через контроллер прерываний ломаться просто нечему, все должно работать как надо.
3. Насчет примитивов синхронизации, типа SWP, LDREX и других. Они всего-лишь примитивы, основа для реализации полноценного и удобного средства синхронизации на Си/Си++, которое можно использовать как угодно, оборачивать любые участки кода и т.п. А иначе, действительно придется реализовывать функцию на ассемблере, или использовать какие-нибудь ассемблерные вставки в Си, что по моему мнению является костылем.
Я за запрещение прерываний через VIC. Это не потребует никаких лишних затрат и должно хорошо работать.
Точно я за VIC не подумал, спасибо за подсказку.
По поводу потоков там все макросы для безопасной работы присутствуют, например, есть мьютексы, PT_END, PT_EXIT и пр. если интересно как строить OC на протопотоках, можно прочитать о них, например, тут [url]sics.se/~adam/pt/[/url]