|
|
  |
Требуется совет по выбору RTOS, программист я хреновый |
|
|
|
Apr 21 2006, 09:23
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(zltigo @ Apr 21 2006, 14:25)  Ну а теперь "на бис" для ARM, о которых здесь речь :-). И не в регистр сохранять. В ARM с памятью поработать - много хуже :-(. Если Вы обратили внимание, то могли заметить, что сохраняется не в регистр, а в память. :-Р И с чего это у АРМа так плохо с памятью? Обычное дело для любого фон неймана. В случае со счетчиком тоже в память надо лазить и еще больше, т.к. чтение-модификация-запись. Если так плохо при работе с памятью, то в результате этот подход вообще плохо для АРМа подходит. Цитата(zltigo @ Apr 21 2006, 14:25)  Цитата Прошу прощения, я как-то пропустил это. Можно для меня напомнить что там не единственное?
Либо руками (Про C++ - не надо, я в курсе) будете выделять индивидуальную память для сохранения текущего зачения при каждом вызове, либо не будет вложенности. Про комплиментарноть - ниже. Зачем что-то выделять руками? Внутри функции выделяется локальная переменная. Она и работа с ней скрыты внутри и совершенно не касаются пользователя. Внешне все выглядит так же - функция-вход и функция-выход. С++ позволяет лишь автоматизировать вызов фунции-выхода, чтобы не забыть ее вызвать в нужном месте. Цитата(zltigo @ Apr 21 2006, 14:25)  Цитата Как это нарушить? Т.е. вход вызвали 3 раза и выход 4? Но ведь при этом работать-то оно будет неправильно - прерывания будут разрешены не в том месте, где были запрещены.
Хоть 444 раза - посмотрите код - действия просто будут проигнорированы, в отличие от варианта "с сохранением" в котором будет упорно переписываться последнее сохраненное бог всесть когда значение, а если еще и в регистре сохранить :-) Что-то Вы не про то. Вот пример: CritEnter() // 1 раз вызвали, прерывания запретили ... CritEnter() // 2 раз вызвали ... CritEnter() // 3 раз вызвали ... ... CritExit() // это соответствует 3 ... CritExit() // это соответствует 2 ... CritExit() // а это по ошибке вызвали, здесь разрешились прерывания, а не должны! ... CritExit() // а здесь должны были быть разрешены прерывания ... Т.е. вот лишний вызов вносит семантическую ошибку из-за нарушения комплементарности вызова. И толку-то от этих проверок. Комплементарность должна строго соблюдаться, иначе будет, как уже сказал, нарушение функциональной целостности программы.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 21 2006, 09:40
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(DASM @ Apr 21 2006, 14:45)  Цитата(vet @ Apr 21 2006, 11:42)  Глупость это. Причем тут КОД ? Представьте себе 128 экземпляров некоего класса. Код у них один и тот же, разные у них данные. Пусть объект один захватил за попку одну девушку (разделяемый ресурс, вошел в свою критическую секцию) Да, это не даст другим экземплярам трогать туже поку, но разве это запрещает другим экземплярам лапать другие попы ? В том же участке кода, теми же руками. Просто Критические секции будут разными, разными объектами в памяти. Позволю себе заметить, что у всех 100 экземпляров классов КОД их функций-членов - ОДИН И ТОТ ЖЕ! Будете с этим спорить?  Цитата(DASM @ Apr 21 2006, 14:45)  И запрещать тут прерывания - форменное свинство. Запрещение прерываний - это один из способов реализации. Наверное, самый простой. Предложите другой способ защитить код, выполняемый в планировщике, где изменяются состояния объектов ядра и все изменения должны быть выполненны атомарно?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 21 2006, 09:53
|
Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937

|
Дело все в том,что понятие критическая секция ( монопольное исполнение операции над ресурсом) и ее реализация - это разные вещи. Реализована критическая секция может быть не только зарещением прерываний(что обычно делается в небольших системах),но и другими способами. Все объекты синхронизации более высокого уровня(семафоры, мьютексы и т.д.) уже используют внутри себя критические секции (в вышеуказанном понимании).
Что же касается сохранения одного из статусных регистров при прерываниях в ARM, то это надо делать дополнительно(что и делается в VxWorks,ThreadX,uC-OS,TNKernel и т.д.) - либо в стеке вызываемой ф-ции(ThreadX,uC-OS,TNKernel),либо в специальном фрейме стека/памяти (VxWorks). За это спасибо разработчикам архитектуры ARMа.
|
|
|
|
|
Apr 21 2006, 12:47
|
Гуру
     
Группа: СуперМодераторы
Сообщений: 2 065
Регистрация: 11-01-05
Из: Москва
Пользователь №: 1 892

|
Цитата(yuri_t @ Apr 21 2006, 16:22)  IMHO, пользователь любой ОS от Windows/Linux до TNKernel никогда не должен запрещать/разрешать прерывания в своей программе - OS делает это для него в своих семафорах, очередях и т.д. Если прикладной программе требуется запрещать/разрешать прерывания напрямую - это плохо написанная программа. Единственное исключение из вышесказанного - это когда программа пользователя фактически является расширением ОС - драйвером (USB,networks etc.). Вот это я категорически поддерживаю!!! Вообще, в ОСях, IMHO, должна быть такая немаловажная деталь, как синтетический порт под Win32 (или Linux) или на пЫсюк. В начале почти каждого проекта важно отладить его структуру, форматы данных и пр. А такие вещи пишутся на palin С, и им пофиг, на какой платформе работать. Это просто лично моя мечта - взять синтетический порт ОСи на Win32, запустить http://www.mingw.orghttp://www.bloodshed.net/devcpp.htmlhttp://www.codeblocks.org/И написать там весь проект без дров. Дрова на таком этапе удобно заменять консолью, файлами, IP и именованными каналами (для связи с другими процессами и машинами). Все-таки аппаратно независимую алгоритмику отлаживать на целевой платформе - глуповатое занятие  А на пЫсюке test units писать - самое то! Тут для тестирования Python, Matlab и другие мощные тулзы подрубить можно. Что касается ассемблерных вставок для эффективной реализации критических кусков - для этого препроцессор есть. Все равно такой кусок имеет вход и выход, да еще рабочую память. Вот и пишется вначале C прототип такого куска, чтобы отладить его взаимодействие с другими частями (и пусть он будет в 100 раз медленнее оптимальнго асмового кода - на этом этапе это не важно, "точность попадания компенсируется диаметром изделия", будет пЫсюк тормозить - возьмем мощнее ), и только потом переводитсмя на асм. А другой человек (или ты, но в другой момент времени) самозабвенно JTAG'ит дрова на целевой платформе. Затем на эти дрова одевается основной каркас, и делается тонкая доводка. IMHO, за счет общей оптимизации проекта можно добиться гораздо большего (главное - фантазию на этом этапе включить по полной, полностью раскрепоститься), чем за счет сверхоптимального асмового и С кодинга (как справделиво учит методология XP программизма - опитимизировать надо потом, когда станет очевидно, что именно этот кусок и надо оптимизировать!). А решать все задачи сразу - так только клиенты Кащенко умеют. Именно их этих соображений я и выбрал eCos (порт на PC (готовая загрузочная дискета) и синтетический порт на Linux), котрый потихоньку изучаю. В связи с колоссальным ростом возможностей SOC, IMHO, именно такой методологический подход будет эффекивнее на перспективу. Ибо после выхода STR91xxx "ограничений для фантазии" в плане ОС почти не останется - в 512К FLASH и 96k SRAM влезет почти все!
|
|
|
|
|
Apr 21 2006, 15:45
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
В какую-то параною скатывается разговор. Почему _Я_ начал этот разговор -я уже 'оправдывался'. Цитата(dxp @ Apr 21 2006, 12:23)  Если Вы обратили внимание, то могли заметить, что сохраняется не в регистр, а в память. :-Р - не обратил, поскольку с Atmel не имел дела и уже не буду, а увидев явное указание регистра предположил сохранение в регистре, при этом естественно, должен отметить Ваше лукавство заключающееся в отсутствии занесения регистра, ну да бог с ним.... Цитата И с чего это у АРМа так плохо с памятью? Обычное дело для любого фон неймана. В случае со счетчиком тоже в память надо лазить и еще больше, т.к. чтение-модификация-запись. Если так плохо при работе с памятью, то в результате этот подход вообще плохо для АРМа подходит. Вот как раз по причине "плохого Неймана" и по причине кривизны SAMовской реализации блокировки прерываний, и по причине возможности условного выполнения команд на ARM, как-раз для ARM сие подходит, ибо даже не особо длиннее и пожалуй быстрее ввиду отсутствия необходимости всегда бездумно выполнять кучку команд для разблокировки и особенно блокировки. Если это типа x86 pushf cli ..... popf То тогда еще можно говорить о введении вместо этого глобального счетчика, как о заметном усложнении и торможении процесса, но не для ARM. Цитата Зачем что-то выделять руками? Внутри функции выделяется локальная переменная. Она и работа с ней скрыты внутри и совершенно не касаются пользователя. Внешне все выглядит так же - функция-вход и функция-выход. С++ позволяет лишь автоматизировать вызов фунции-выхода, чтобы не забыть ее вызвать в нужном месте. Это мы о какой функции? Если о той из которой вызывается, то создание локальной переменной я и называю 'руками', а если из нее еще вызвать, то создать еще одну локальную и..... Cкрыть-то можно в функции 'entercritical' - но там она не может быть локальной :-) по определению, так что о чем мы это говорим - я не понял. (Это я все НЕ о C++) Цитата Что-то Вы не про то. Вот пример:
CritEnter() // 1 раз вызвали, прерывания запретили ... CritEnter() // 2 раз вызвали ... CritEnter() // 3 раз вызвали ... ... CritExit() // это соответствует 3 ... CritExit() // это соответствует 2 ... CritExit() // а это по ошибке вызвали, здесь разрешились прерывания, а не должны! ... CritExit() // а здесь должны были быть разрешены прерывания ...
Т.е. вот лишний вызов вносит семантическую ошибку из-за нарушения комплементарности вызова. И толку-то от этих проверок. Комплементарность должна строго соблюдаться, иначе будет, как уже сказал, нарушение функциональной целостности программы. А Вы поменяйте в своем примере две последние строчки местами и..... ошибки НЕ произойдет. Таким образом, есть ситуация, когда эти "лишние" навороты приносят пользу. И уж как минимум, эти навороты если и длинее чуть-чуть для ARM платформы, то уж НЕ ХУЖЕ справляются со своими обязаностями, нежели принятая в TNKernel реализация. И уж точно не могут быть причиной НЕ ИСПОЛЬЗОВАНИЯ FreeRTOS. Ну и "дуракоустойчивость" на мой взгляд получше. Закончим???
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 21 2006, 16:17
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(sensor_ua @ Apr 21 2006, 11:20)  У меня железка с неким ногодрыганием, устроенным типа импровизированной шины. Как известно, GPIO сами не имеют в АРМ операций чтение-модификация-запись, дык ещё в железке есть выборки внешних устройств на "шине" через опять же GPIO. Если подвигать GPIO в прерывании, а оно может возникнуть когда двигались GPIO вне прерывания, чегой-то нужно сохранять. Т.е. либо в административном порядке запрещать использовать GPIO в прерывании, либо реализовать атомарность каким-либо способом. АРМ позволяет, например, выполнить SWI, можно просто запрещать прерывания на входе в критическую секцию, при выходе - разрешать, но тогда если при входе если были запрещены прерывания, при выходе они разрешатся... иначе нужно при входе не просто запрещать, а сохранять регистр статуса, затем запрещать прерывания, а при выходе всего-лишь восстанавливать что было. Можно вообще завести обработчик IRQ, в который вваливаться через VICSoftInt, а там творить чего угодно, пока не разрешили вложенные прерывания  ... Я не понял :-( Вообще ничего из вышеизложенного не понял. Если речь идет о том, что Вы имеете некоторую процедуру,которая для обеспечения ее непрерывности обрамлена critical и по этой причине ее нельзя вызывать из обработчика прерывания, то 0. Нужно делать вещи максимально близкие к естественным. 1. Делается процедура без запретов. 2. Для работы в прерывании вызывается прямо или через прямую макроподстановку 3. Для прочего использования через макрос-обертку с __disable/enable. Если обработчики прерываний в отдельном файле, то макроимена могут быть вообще одинаковыми. В результате начисто отпадают все ненужные навороты как в виде 'счетчиков', так и ввиде 'сохранений', заодно не надо вникать в реализацию critical в каждой конкретной операционке. Все выглядит (живой пример) примерно так: Код //----------------------------------------------------------- // Read/Write SLIC Registers with CLOSED interrupts void wr_sreg_int( BYTE channel, BYTE reg, BYTE value ); ...... //----------------------------------------------------------- // Read/Write SLIC Registers #define wr_sreg( x, y, z ) \ { __disable_interrupt(); \ wr_sreg_int( x, y, z ); \ __enable_interrupt(); }
...... Если всенеприменнейше хотите critical, то можете добавить свой critical для обработчиков прерываний, единственной функцией которого будет наращивание/уменьшение 'счетчика'. Цитата(sensor_ua @ Apr 21 2006, 19:08)  2 zltigo
У меня насчёт правильности запрещения/разрешения прерываний вопрос к Вам остался. Представьте себе, что пишет подпрограмму с критической секцией не Вы, а коллега. Вы эту подпрограмму интегрируете в свой проект. Ответьте, пожалуйста, на каком основании Ваш коллега имеет право разрешать прерывания (при выходе из критической секции), если он не узнаЁт при запрещении (при входе в критическую секцию), были ли они (прерывания) разрешены? Так они и не будут разрешены если Вы вызвали его из критической секции и соответственно счетчик на входе в подпрограмму колеги уже не будет 0. Ежели коллега, или Вы пожелает в _прикладной_ программе воспользоваться прямым запретом/разрешением вместо critical , то, как здесь уже было замечено, надо наказывать, ибо против лома нет приема.
Сообщение отредактировал zltigo - Apr 21 2006, 16:26
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 21 2006, 16:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата(zltigo @ Apr 21 2006, 19:17)  Цитата(sensor_ua @ Apr 21 2006, 11:20)  У меня железка с неким ногодрыганием, устроенным типа импровизированной шины. Как известно, GPIO сами не имеют в АРМ операций чтение-модификация-запись, дык ещё в железке есть выборки внешних устройств на "шине" через опять же GPIO. Если подвигать GPIO в прерывании, а оно может возникнуть когда двигались GPIO вне прерывания, чегой-то нужно сохранять. Т.е. либо в административном порядке запрещать использовать GPIO в прерывании, либо реализовать атомарность каким-либо способом. АРМ позволяет, например, выполнить SWI, можно просто запрещать прерывания на входе в критическую секцию, при выходе - разрешать, но тогда если при входе если были запрещены прерывания, при выходе они разрешатся... иначе нужно при входе не просто запрещать, а сохранять регистр статуса, затем запрещать прерывания, а при выходе всего-лишь восстанавливать что было. Можно вообще завести обработчик IRQ, в который вваливаться через VICSoftInt, а там творить чего угодно, пока не разрешили вложенные прерывания  ... Я не понял :-( Вообще ничего из вышеизложенного не понял. Если речь идет о том, что Вы имеете некоторую процедуру,которая для обеспечения ее непрерывности обрамлена critical и по этой причине ее нельзя вызывать из обработчика прерывания, то 0. Нужно делать вещи максимально близкие к естественным. 1. Делается процедура без запретов. 2. Для работы в прерывании вызывается прямо или через прямую макроподстановку 3. Для прочего использования через макрос-обертку с __disable/enable. Если обработчики прерываний в отдельном файле, то макроимена могут быть вообще одинаковыми. В результате начисто отпадают все ненужные навороты как в виде 'счетчиков', так и ввиде 'сохранений', заодно не надо вникать в реализацию critical в каждой конкретной операционке. Все выглядит (живой пример) примерно так: Код //----------------------------------------------------------- // Read/Write SLIC Registers with CLOSED interrupts void wr_sreg_int( BYTE channel, BYTE reg, BYTE value ); ...... //----------------------------------------------------------- // Read/Write SLIC Registers #define wr_sreg( x, y, z ) \ { __disable_interrupt(); \ wr_sreg_int( x, y, z ); \ __enable_interrupt(); }
...... Цитата(sensor_ua @ Apr 21 2006, 19:08)  2 zltigo
У меня насчёт правильности запрещения/разрешения прерываний вопрос к Вам остался. Представьте себе, что пишет подпрограмму с критической секцией не Вы, а коллега. Вы эту подпрограмму интегрируете в свой проект. Ответьте, пожалуйста, на каком основании Ваш коллега имеет право разрешать прерывания (при выходе из критической секции), если он не узнаЁт при запрещении (при входе в критическую секцию), были ли они (прерывания) разрешены? Так они и не будут разрешены если Вы вызвали его из критической секции и соответственно счетчик на входе в подпрограмму колеги уже не будет 0. Ежели коллега, или Вы пожелает в _прикладной_ программе воспользоваться прямым запретом/разрешением вместо critical , то, как здесь уже было замечено, надо наказывать, ибо против лома нет приема. Я о варианте, когда в основной программе прерывания в какой-то прекрасный момент выключены не в критической секции. Как быть с разрешением в подпрограмме коллеги?
--------------------
aka Vit
|
|
|
|
|
Apr 21 2006, 16:36
|
Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937

|
To sensor_ua -------------------
Учитывая Ваш искренний интерес и желание все понять "до последнего винтика", отвечу:
Во первых,такое выражение просто не будет работать:
#define tn_disable_interrupt() { int tn_save_status_reg = tn_cpu_save_sr() #define tn_enable_interrupt() tn_cpu_restore_sr(tn_save_status_reg); }
Если следовать этим путем, то должно быть, наверное, так:
#define tn_disable_interrupt() { int tn_save_status_reg = tn_cpu_save_sr(); } #define tn_enable_interrupt() { tn_cpu_restore_sr(tn_save_status_reg); }
Теперь, если Вы вызовете это выражение внутри одной функции несколько раз, то согласно стандарта на язык С, локальная переменная int tn_save_status_reg будет видна только внутри блока, где она объявлена, следовательно, сколько раз вы вызвали tn_disable_interrupt(), столько раз она и будет создаваться. Далее, при вызове tn_enable_interrupt() компилятор не увидит tn_save_status_reg - блок, где было определение, уже завершился. (а если бы не завершился - то пришлось бы иметь несколько переменных с одним именем - что всех бы запутало(и компилятор, и программиста) и поэтому невозможно).
Поэтому давайте оставим это место в коде так, как оно существует сейчас.
И в заключение - при использовании ОС стоит работать на уровне семафоров, очередей и т.д. ОС для того и создается,чтобы избавить пользователя от всей этой возни с сохранением регистров, запрещением/разрешением преываний, etc.
C уважением, yuri_t
Сообщение отредактировал yuri_t - Apr 21 2006, 16:48
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|