|
__LDREX __STREX в STM32F407 |
|
|
|
Jun 4 2017, 13:18
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Всем доброе время суток! IDE - IAR+плагин IAR для eclipse+eclipse. Решил проверить, как работает синхронизация с использованием __LDREX/__STREX. Пишем следующий код CODE typedef struct { ... volatile unsigned long sync; //переменная для синхонизации доступа к данному элементу } burst_measur;
burst_measur cur_mes;
void mpu_cfg_test() { //настраиваем область внутренней RAM, как разделяемую __DMB(); SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; MPU->CTRL = 0U;
MPU->RNR = 0UL; MPU->RBAR = 0x20000000UL; MPU->RASR = (0x10UL << MPU_RASR_SIZE_Pos) | MPU_RASR_C_Msk | MPU_RASR_S_Msk | (0x3 << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk;
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk; SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; __DSB(); __ISB();
//выполняем запрос эксклюзивного доступа к переменной cur_mes.sync DWORD sync=0; sync = __LDREX(&cur_mes.sync); __DMB(); soft_int_ini(); //настойка программного прерывания soft_int_on(); //вызов программного прерывания __WFI(); } в обработчике программного прерывания: CODE DWORD sync; do { sync = __LDREX(&cur_mes.sync); sync++; sync = __STREX(sync, &cur_mes.sync); } while (sync); Т.е. сначала выполняется __LDREX(&cur_mes.sync), потом происходит прерывание и выполняется __LDREX(&cur_mes.sync) + __STREX(sync, &cur_mes.sync). По всем документациям, как я их понял, __STREX(sync, &cur_mes.sync) должна возвратить "не ноль", однако возвращает "ноль". Помогите, пожалуйста, разобраться, что я делаю не правильно?
|
|
|
|
10 страниц
1 2 3 > »
|
 |
Ответов
(1 - 99)
|
Jun 4 2017, 18:39
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 4 2017, 17:10)  STREX всё верно возвращает. если не верно задал вопрос - от __LDREX() + __STREX() ожидаю следующее: если выполнено__LDREX(&cur_mes.sync) тогда в случае выполнения в другой части кода "__LDREX(&cur_mes.sync) + __STREX(sync, &cur_mes.sync)" __STREX вернет "не ноль". однако возвращается ноль. Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть.
|
|
|
|
|
Jun 4 2017, 19:34
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(_lexa_ @ Jun 4 2017, 19:39)  Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть. Каждый раз вспоминаю и снова забываю эти проклятые LDREX/STREX, но суть в том, что если между LDREX и последующим STREX "что-то пошло не так, Карл", а именно - возникло некоторое событие, прерывание, которое СТАВИТ ПОД УГРОЗУ целостность переменной-флага, то STREX вернет типа "ай-ай". То есть, даже если саму переменную-флаг никто и трогать не собирался где-то в недрах прерываний, но прерывание нарушило непрерывное исполнение между LDREX и STREX, то ресурс считается занятым. Поэтому у меня глубокое сомнение, можно ли строить код, как у ТС, - захватывать ресурс в основном коде и выяснять отношения в прерывании: в прерывании по определению ресурс будет занят. Если хотите организовать всякие мъютексы и прочие разделяемые флаги на системе bare bone с наличествующими прерываниями, гляньте на команду SVC. Могу даже код кинуть, если есть интерес.
|
|
|
|
|
Jun 4 2017, 20:14
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(KnightIgor @ Jun 4 2017, 19:34)  ... Могу даже код кинуть, если есть интерес. Интерес есть. Кидайте.
|
|
|
|
|
Jun 4 2017, 21:14
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(_lexa_ @ Jun 4 2017, 21:14)  Интерес есть. Кидайте. Обработчик прерывания SVC выглядит у меня следующим образом. Много подсмотрено по ссылкам, указанным в комментариях. Код // --------------------------------------------------------------------------- // // SVC_Handler used for "atomic" operations based on the the fact, that // SVC handler cannot be interrupted by higher placed interrupts. // // Upon call to SVC vector the stack holds saved register: // xPSR 0x1C (7) // PC 0x18 (6) // R14(LR) 0x14 (5) // R12 0x10 (4) // R3 0x0C (3) // R2 0x08 (2) // R1 0x04 (1) // [SP]-> R0 0x00 (0) // // The registers will be restored upon leaving the handler. The handler // to return a result, a value in the stack must be modified. // // Via stacked R0..R3 the parameters can be passed through to the // handler. For this purpose the definition of the user SVC call can // be done as (the type 'int' is for example): // // __svc(n) myfunc(int [,int, int, int]); // // See Chapter 6.19, Figure 6.5 in: // http://infocenter.arm.com/help/topic/com.arm.doc.dui0471c/ \ // DUI0471C_developing_for_arm_processors.pdf // // and // // http://www.mikrocontroller.net/topic/295183 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471j/pge1358787038365.html // http://sites.fas.harvard.edu/~libe251/spring2014/CauseOfDefaultISR.txt // // To PRESERVE8 for stack 8 bytes alignment see // http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka4127.html // __asm void SVC_Handler(void) { PRESERVE8 EXPORT SVC_Handler
; get the pointer to the saved R0-R3 to pass it ; to SVC_Dispatcher() as the second parameter ; (via R1): #ifdef SVC_OS_MODE TST LR, #4 ; kernel mode? ITE EQ MRSEQ R1, MSP ; kernel stack MRSNE R1, PSP ; user stack
; get SVC n instruction code field and ; pass it to SVC_Dispatcher() as the first ; parameter (via R0):
LDR R0, [R1, #6*4] ; PC #if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC) SUBS R0, R0, #2 LDRB R0, [R0, #0] ; SVC OPCODE low byte #else LDRB R0, [R0, #-2] ; SVC OPCODE low byte #endif
PUSH {LR, R1} EXTERN SVC_Dispatcher BL SVC_Dispatcher ; return value in R0 POP {R1}
; return the result in R0 via stacked R0:
STR R0, [R1] #else MOV R1, SP ; kernel=user stack (no OS)
; get SVC n instruction code field and ; pass it to SVC_Dispatcher() as the first ; parameter (via R0):
LDR R0, [R1, #6*4] ; PC #if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC) SUBS R0, R0, #2 LDRB R0, [R0, #0] ; SVC OPCODE low byte M0/M0+ #else LDRB R0, [R0, #-2] ; SVC OPCODE low byte M3 and higher #endif
PUSH {LR} ; preserve return address EXTERN SVC_Dispatcher BL SVC_Dispatcher ; return value in R0
; return the result in R0 via stacked R0:
STR R0, [SP, #4] ; #4 to skip LR in the stack #endif POP {PC} ; exit by LR } //------------------------------------------------------------------------------ Если исключить условные трансляции, которые разбирают варианты под OS, а также оставить универсальный вариант, работающий и на -M0 (не поддерживающих отрицательные смещения), то обработчик упростится для исполнения и понимания: Код __asm void SVC_Handler(void) { PRESERVE8 EXPORT SVC_Handler
; get the pointer to the saved R0-R3 to pass it ; to SVC_Dispatcher() as the second parameter ; (via R1): MOV R1, SP ; kernel=user stack (no OS)
; get SVC n instruction code field and ; pass it to SVC_Dispatcher() as the first ; parameter (via R0):
LDR R0, [R1, #6*4] ; PC SUBS R0, R0, #2 LDRB R0, [R0, #0] ; SVC OPCODE low byte M0/M0+
PUSH {LR} ; preserve return address EXTERN SVC_Dispatcher BL SVC_Dispatcher ; return value in R0
; return the result in R0 via stacked R0:
STR R0, [SP, #4] ; #4 to skip LR in the stack POP {PC} ; exit by LR } //------------------------------------------------------------------------------ Как видно, все готовилось для вызова C-шной процедуры-обработчика ниже. Я выбросил многие мои специфические ветви, оставив те, что иллюстрируют идею: Код uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr) { uint32_t res = UINT32_MAX; switch (svc) { case _SVC_ATOMIC_FLAG8: // atomic clear of an U8 flag res = *(uint8_t *)ptr->R0; // return the last state *(uint8_t *)ptr->R0 = 0; // clear it break; case _SVC_ATOMIC_FLAG16: // atomic clear of an U16 flag res = *(uint16_t *)ptr->R0; // return the last state *(uint16_t *)ptr->R0 = 0; // clear it break; case _SVC_ATOMIC_ADD32: // atomic add 32 res = *(uint32_t *)ptr->R0 += (int32_t)ptr->R1; break; case _SVC_ATOMIC_DEC8: res = *(uint8_t *)ptr->R0; if (res) { *(uint8_t *)ptr->R0 = --res; } break; case _SVC_MUTEX8: // mutex in an U8 variable res = !(*(uint8_t *)ptr->R0); // current mutex state *(uint8_t *)ptr->R0 = ptr->R1; // set the value break; } return res; } К этому пристегивается заголовок (существенный фрагмент): Код typedef struct svc_params_s {
uint32_t R0, R1, R2, R3; } SVC_Param_TypeDef;
#define _SVC_GETSYSCLOCKVALUE 4 #define _SVC_ATOMIC_FLAG8 8 #define _SVC_ATOMIC_FLAG16 9 #define _SVC_ATOMIC_FLAG32 10 #define _SVC_ATOMIC_ADD8 11 #define _SVC_ATOMIC_ADD16 12 #define _SVC_ATOMIC_ADD32 13 #define _SVC_ATOMIC_DEC8 14 #define _SVC_MUTEX8 16 #define _SVC_ATOMIC_SET8 21 #define _SVC_ATOMIC_SET16 22 #define _SVC_ATOMIC_SET32 23 #define _SVC_CALL_ME_PAR 25
//------------------------------------------------------------------------------ // // Clears an U8 flag pointed by 'pflag' but returns its latest value. // uint8_t __svc(_SVC_ATOMIC_FLAG8) Atomic_Flag8(uint8_t *pflag);
//------------------------------------------------------------------------------ // // Adds an I32 value to the value pointed by 'pvalue' and returns the result // uint32_t __svc(_SVC_ATOMIC_ADD32) Atomic_Add32(uint32_t *pvalue, int32_t val);
//------------------------------------------------------------------------------ // // Decrements a non zero value pointed by 'pvalue' and returns the result // uint8_t __svc(_SVC_ATOMIC_DEC8) Atomic_Dec8(uint8_t *pvalue);
//------------------------------------------------------------------------------ // // Sets the mutex ('setit'=true) pointed by 'pflag' and returns true if success. // Otherwise the mutex has been busy. // // Clears ('setit'=false) the mutex unconditionally. It's up to the user to take // care, if the mutex is allowed to be cleared. The return result to be ignored. // // NOTE: THE MUTEX VALUE AND THE SETIT PARAMETER ARE EXPECTED TO BE ONLY 0 OR 1. // NO OTHER VALUES ARE ALLOWED, SHOULD FOR INSTANCE THE MUTEX VARIABLE BE // CHANGED ELSEWHERE. // int __svc(_SVC_MUTEX8) Mutex8(uint8_t *pflag, uint8_t setit);
//------------------------------------------------------------------------------
extern uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr); Теперь о вызове на примере флага: Код uint8_t sb = Atomic_Flag8(&flag); // atomic reset if (sb) { // ... } Там для некой переменной uint8_t flag, которая устанавливается в прерывании, функция возвращает мне последнее состояние флага и сбрасывает его. Благодаря непрерываемости SVC операция по сбросу флага является атомарной.
Сообщение отредактировал KnightIgor - Jun 4 2017, 21:14
|
|
|
|
|
Jun 5 2017, 07:49
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(_lexa_ @ Jun 4 2017, 20:39)  Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть. Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности. Ну и где у вас между LDREX и STREX нарушение эксклюзивности? Цитата(KnightIgor @ Jun 4 2017, 23:14)  // SVC_Handler used for "atomic" operations based on the the fact, that // SVC handler cannot be interrupted by higher placed interrupts. Жесть какая. Вот уж действительно - одевание трусов через голову Чем способы: LDREX/STREX или запрет прерываний не угодили? Они в разы менее громоздки. А для SVC можно придумать гораздо более полезные применения.
|
|
|
|
|
Jun 5 2017, 08:17
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(AHTOXA @ Jun 5 2017, 08:38)  А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний? Полагаю, что выгода в полным отсутствием этих самых запретов/разрешений. Дабы иметь возможность гарантировать стабильную скорость реакции на критичные высокоприоритетные прерывания. Причем, в независимости используется ось или нет. Сам поглядываю на подобные решения, но таких у меня проектов очень мало, поэтому пока вполне хватает "классического" запрет/разрешение прерываний. Хожу как "кот вокруг сметаны"  Цитата Я думаю, что по скорости это даже медленнее (тратится время на сохранение и восстановление контекста). Если производительность камня выбрана хотя бы с небольшим запасом (в случае применения оси загрузка cpu никогда не достигает допустимого предела), то это не имеет значения. Смысл svc - дать гарантию реакции на важные высокоприоритетные прерывания.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 08:24
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(AHTOXA @ Jun 5 2017, 11:22)  Если, как пишет, KnightIgor, svc является непрерываемым, то чем это отличается от запрета остальных прерываний? Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку . Лишь нужно правильно настроить NVIC. Причем, это более "мощное" прерывание может вызвать это же самое SVC, а когда выйдет, продолжится обработка прерванного SVC, и после его завершения тут же опять вызовется новое, отложенное. Так по сути SVC дает гарантию целостности кусков кода. Безусловно, оверхед заметно растет, но цена этому - гарантия реакции на действительно важные события. Под SVC вообще идеально ложатся все сервисы RTOS, судя по всему прям для них SVC и задумывалось. Только вот мне не попадались готовые оси, где это используется ...
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 08:49
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 5 2017, 10:17)  Полагаю, что выгода в полным отсутствием этих самых запретов/разрешений. Дабы иметь возможность гарантировать стабильную скорость реакции на критичные высокоприоритетные прерывания. Так обработчик SVC задержит эти самые "высокоприоритетные прерывания" на ещё в разы большее время! Цитата(Forger @ Jun 5 2017, 10:24)  Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку . Лишь нужно правильно настроить NVIC. Потому что для работоспособности этого способа, обработчик SVC должен быть самым высокоприоритетным. Цитата(Forger @ Jun 5 2017, 10:24)  Безусловно, оверхед заметно растет, но цена этому - гарантия реакции на действительно важные события. Под SVC вообще идеально ложатся все сервисы RTOS, судя по всему прям для них SVC и задумывалось. Только вот мне не попадались готовые оси, где это используется ... SVC задумывалось совсем не для этого. Для этого задумывались LDREX/STREX. Именно поэтому и нет. Если у Вас другой обработчик может прерывать SVC, то никакой эксклюзивности уже нет. По определению. Цитата(Forger @ Jun 5 2017, 10:24)  Причем, это более "мощное" прерывание может вызвать это же самое SVC, а когда выйдет, продолжится обработка прерванного SVC ну-ну... учите матчасть Если это "мощное" прерывание попытается так сделать, то получит HardFault, а не SVC.
|
|
|
|
|
Jun 5 2017, 08:54
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Forger @ Jun 5 2017, 13:24)  Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку . Ну вы хоть читайте, на что отвечаете... KnightIgor написал: Цитата(KnightIgor @ Jun 5 2017, 02:14)  Благодаря непрерываемости SVC операция по сбросу флага является атомарной. Видите, "благодаря непрерываемости SVC". Это значит, что у svc в его случае самый высокий приоритет. А значит, вход в обработчик SVC блокирует остальные прерывания. Вот я и поинтересовался: Цитата(AHTOXA @ Jun 5 2017, 10:38)  А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний? А теперь вы спрашиваете, "почему непрерывный". Теперь понимаете нить?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 5 2017, 09:11
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 5 2017, 11:49)  Так обработчик SVC задержит эти самые "высокоприоритетные прерывания" на ещё в разы большее время! Потому что для работоспособности этого способа, обработчик SVC должен быть самым высокоприоритетным. Как раз наоборот - приоритет SVC должен быть самым низким ! (ну кроме разве что PendSV). Цитата SVC задумывалось совсем не для этого. Для этого задумывались LDREX/STREX. Именно поэтому и нет. Если у Вас другой обработчик может прерывать SVC, то никакой эксклюзивности уже нет. По определению. Не путайте вызов SVC с вызовом обычной функции! Цитата Если это "мощное" прерывание попытается так сделать, то получит HardFault, а не SVC. Да неужели? И по какой причине? Цитата(AHTOXA @ Jun 5 2017, 11:54)  Видите, "благодаря непрерываемости SVC". Это значит, что у svc в его случае самый высокий приоритет. Вовсе нет, непрерываемость реализуется благодаря тому, что один вызов SVC не может прервать другой на уровне ЯДРА. Другими словами все возникшие вызовы SVC становятся в очередь. Цитата А значит, вход в обработчик SVC блокирует остальные прерывания. Вот я и поинтересовался: Я смотрю, что суть SVC понятна далеко не всем. Это как раз тот самый случай - изучить матчасть.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 09:37
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 5 2017, 11:11)  Как раз наоборот - приоритет SVC должен быть самым низким ! (ну кроме разве что PendSV). Да неужели? И по какой причине? Если бы Вы открыли мануал на ядро, то узнали бы, что SVC является синхронным исключением. Т.е. - должно обработаться сразу же. А если это не возможно (например - запрещены исключения или, как Вы советуете, оно вызвано внутри более приоритетного ISR), то будет активирован механизм эскалации до Hard Fault. Цитата(Forger @ Jun 5 2017, 11:11)  Не путайте вызов SVC с вызовом обычной функции! Я то как раз не путаю, потому что у меня много где SVC используется. А вот Вам следовало бы хотя-бы ознакомиться с предметом, прежде чем советовать что-то. И вызов SVC - как раз очень похож на вызов обычной функции. Для вызывающего процесса. Только на другом уровне привилегий. Именно это и есть его главное предназначение - вызов функций с привилегиями системного уровня из прикладного уровня. Цитата(Forger @ Jun 5 2017, 11:11)  Другими словами все возникшие вызовы SVC становятся в очередь. Какая ОЧЕРЕДЬ??? Откройте наконец-то мануал! Хватит фантазировать. SVC - это синхронное прерывание, если оно не может быть активировано немедленно, то будет HF. Цитата(Forger @ Jun 5 2017, 11:11)  Я смотрю, что суть SVC понятна далеко не всем. Это как раз тот самый случай - изучить матчасть. Вот именно.... Хватит чушь нести. Здесь не одни чайники собрались. Я думаю - много кто реально использует SVC в проектах.
|
|
|
|
|
Jun 5 2017, 09:49
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 5 2017, 12:37)  Вот именно.... Согласен, я поспешил с выводами  Выходит, что в более приоритетных прерываниях нельзя использовать svc, а можно лишь в задачах/потоках. Этого я не знал (( Я рассчитывал в реализациях программных очередей (queue) отказаться от критических секций (простое запрет/разрешение прерываний), но коли в прерываниях это создает трудности (скажем, прерывание от usart), то выходит, что svc ипользовать не получится. А жаль (( Или можно просто поднять приоритет svc до уровня чуть ниже важных прерываний (в которых запрещены вызовы серсвисов оси), тогда задача решится. Я прав?
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 10:17
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 5 2017, 07:49)  Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности. Ну и где у вас между LDREX и STREX нарушение эксклюзивности? Если смотреть по коду, который я привел - первый запрос на эксклюзивный доступ здесь: CODE void mpu_cfg_test() { ... //выполняем запрос эксклюзивного доступа к переменной cur_mes.sync DWORD sync=0; sync = __LDREX(&cur_mes.sync); __DMB(); soft_int_ini(); //настойка программного прерывания soft_int_on(); //вызов программного прерывания __WFI(); } второй запрос в обработчике программного прерывания: CODE DWORD sync; do { sync = __LDREX(&cur_mes.sync); sync++; sync = __STREX(sync, &cur_mes.sync); } while (sync);
|
|
|
|
|
Jun 5 2017, 10:59
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 5 2017, 11:49)  Выходит, что в более приоритетных прерываниях нельзя использовать svc, а можно лишь в задачах/потоках. Этого я не знал (( Надо только обеспечить, чтобы в любой точке вызова SVC текущий уровень приоритета прерывания был ниже чем у SVC. И были разрешены faults. Тогда не будет HF, а будет корректный вход в ISR SVC. Цитата(Forger @ Jun 5 2017, 11:49)  Я рассчитывал в реализациях программных очередей (queue) отказаться от критических секций (простое запрет/разрешение прерываний), но коли в прерываниях это создает трудности (скажем, прерывание от usart), то выходит, что svc ипользовать не получится. А жаль (( Или можно просто поднять приоритет svc до уровня чуть ниже важных прерываний (в которых запрещены вызовы серсвисов оси), тогда задача решится. Я прав? Можно конечно, но ещё раз спрашиваю: зачем надевать трусы через голову?? Ведь если уж никак нельзя запрещать прерывания, то есть механизм LDREX/STREX, который именно для этого и создан. А SVC - даже из названия видно - это для вызова системных функций. Привилегированных. Можно конечно работу с очередями (или что там ещё) вынести на этот уровень, но зачем??? Это будет во много раз медленнее и громоздко чем LDREX/STREX. Цитата(_lexa_ @ Jun 5 2017, 12:17)  Если смотреть по коду, который я привел - первый запрос на эксклюзивный доступ здесь А что такое " запрос на эксклюзивный доступ"? Откуда Вы это взяли?? Нет такого понятия. Нет никаких запросов там. Эксклюзивный доступ read-modify-write - это пара инструкций LDREX/STREX работающих с некоей переменной. Эксклюзивно - это означает, что никто другой (другой процесс) не обращается к этой переменной между LDREX и STREX. А если это условие нарушается - это нарушение эксклюзивности. В Вашем случае есть одна только пара LDREX/STREX, её эксклюзивный доступ никто не нарушает. Похоже Вы совсем не поняли, что написано в мануале и для чего это вообще нужно. Перечитайте ещё раз.
|
|
|
|
|
Jun 5 2017, 11:00
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 5 2017, 13:50)  Надо только обеспечить, чтобы в любой точке вызова SVC текущий уровень приоритета прерывания был ниже чем у SVC. Это решаемо, просто, запрещается вызов SVC в критичных прерываниях, где запрещен вызов сервисов оси (соотв. assert). Цитата И были разрешены faults. Тогда не будет HF, а будет корректный вход в ISR SVC. Не понял ((( Т.е. запрещенные faults нарушают нормальную работу SVC?
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 11:09
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 5 2017, 13:00)  Не понял ((( Т.е. запрещенные faults нарушают нормальную работу SVC? Естественно. Я же писал уже несколько раз: Цитата(jcxz @ Jun 5 2017, 11:37)  Если бы Вы открыли мануал на ядро, то узнали бы, что SVC является синхронным исключением. Т.е. - должно обработаться сразу же. А если это не возможно (например - запрещены исключения или, как Вы советуете, оно вызвано внутри более приоритетного ISR), то будет активирован механизм эскалации до Hard Fault. Ещё раз: если SVC по каким-то причинам не может быть активировано немедленно, будет эскалация до HF. Считайте что SVC - это вызов функции. Если у Вас в коде идёт команда BL, то ведь процессор обязан её выполнить, он не может её перескочить. То же самое и с SVC - это считается вызовом системной функции. Она не может быть не выполнена. А если запрещены fault-ы - значит активировать исключение нельзя. Из-за этого конфликта и будет эскалация до HardFault. Процессор будет стоять на SVC и повышать-повышать приоритет её до тех пор, пока не сможет выполнить. Он и повысит до HF, которое может выполнить даже с запрещёнными fault-ами. Так как это синхронное прерывание, значит оно должно быть выполнено немедленно.
|
|
|
|
|
Jun 5 2017, 11:18
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 5 2017, 14:09)  Так как это синхронное прерывание, значит оно должно быть выполнено немедленно. Цитата(jcxz @ Jun 5 2017, 14:09)  И были разрешены faults. Речь как я понял идет про конкретно один fault - SVCall Handler. Или я опять не так понял?
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 5 2017, 12:40
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(AHTOXA @ Jun 5 2017, 06:38)  А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний? Я думаю, что по скорости это даже медленнее (тратится время на сохранение и восстановление контекста). Прелесть же LDREX/STREX как раз в том, что они не блокируют прерывания. Я не претендую на истину в последней инстанции и рассматриваю применение SVC в моих проектах как один из методов программирования с использованием предоставленных возможностей процессора. Ноги где-то растут из старых времен MS DOS и использованием INT 2F  . Как кто-то в теме догадался, не люблю я всякие запреты-разрешения прерываний. Зачем меня должно в участке кода заботить, какие разрешены, а какие нет? Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено? Затем необходимо множить такие блоки во всех фрагментах, которые критическую секцию используют: хоть макросы напиши, код получается громоздкий для написания и понимания. Не нравится мне это чисто стилистически. На круг получится, что суммарный код обрамления критических секций станет больше обработчика SVC. Синтаксически - как следует из заголовка, который я привел, - я работаю с на вид обычными функциями, которые порождают единственную инструкцию. И еще. Тут многие забалованы F4xx и выше. А у меня есть проекты на одной плате с опциональными F103 и F051 (ценообразование). Вы будете смеяться, но на Cortex-M0 F051 LDREX/STREX отсутствуют. А механизм SVC работает на обоих.
Сообщение отредактировал KnightIgor - Jun 5 2017, 12:50
|
|
|
|
|
Jun 5 2017, 13:26
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 5 2017, 10:59)  А что такое "запрос на эксклюзивный доступ"? Откуда Вы это взяли?? Нет такого понятия. Нет никаких запросов там. например, отсюда: "PM0214. STM32F3xxx and STM32F4xxx Cortex-M4 programming manual. 2.2.7 Synchronization primitives ... A pair of synchronization primitives comprises: ● A Load-Exclusive instruction: Used to read the value of a memory location, requesting exclusive access to that location." Цитата(jcxz @ Jun 5 2017, 10:59)  Эксклюзивный доступ read-modify-write - это пара инструкций LDREX/STREX работающих с некоей переменной. Эксклюзивно - это означает, что никто другой (другой процесс) не обращается к этой переменной между LDREX и STREX. А если это условие нарушается - это нарушение эксклюзивности. В Вашем случае есть одна только пара LDREX/STREX, её эксклюзивный доступ никто не нарушает. Эта пара нужна, чтобы монитор эксклюзивного доступа отметил выполнение LDREX, затем при выполнении STREX снял эту метку, разумеется при условии, что данной парой LDREX/STREX мы не влезли между LDREX и STREX другой части программы, например в случае возникновения прерывания. Если переписать код следующим образом: Код void mpu_cfg_test() { ... //выполняем запрос эксклюзивного доступа к переменной cur_mes.sync DWORD sync=0; sync = __LDREX(&cur_mes.sync); __DMB(); soft_int_ini(); //настойка программного прерывания soft_int_on(); //вызов программного прерывания __WFI(); __STREX(sync, &cur_mes.sync); } ничего не изменится (на всякий случай я это даже проверил). Каким образом монитор эксклюзивного доступа должен увидеть, что использована именно пара LDREX/STREX Напоминаю, это не какая-то реальная программа. Я всего лишь смоделировал ситуацию, когда после выполнения LDREX произошло прерывание и в этом прерывание производится эксклюзивный доступ к той же ячейке памяти. Цитата(jcxz @ Jun 5 2017, 10:59)  Похоже Вы совсем не поняли, что написано в мануале и для чего это вообще нужно. Перечитайте ещё раз. В таком случае, если не сложно, приведите, пожалуйста, небольшой пример кода, когда происходит нарушение эксклюзивности.
|
|
|
|
|
Jun 5 2017, 13:55
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(Forger @ Jun 5 2017, 12:22)  Я тоже его нашел, сейчас как раз изучаю. Тема также освещена в ARMv7-M Architecture Reference Manual, где среди прочего написано про разделяемую память, про глобальный и локальный мониторы эксклюзивного доступа, многопроцессорность и т.д. Все эти документы ARM-овские. У ST LDREX/STREX описаны в PM0214. STM32F3xxx and STM32F4xxx Cortex-M4 programming manual. Причем довольно коротко, многое не по какой-то причине не затронуто и даже ссылок на АРМ-овские документы не даны. В общем, поизучав все это приходит мысль, что я просто в каком-то регистре не поставил какой-то флаг и у меня, например, не работает глобальный монитор.
|
|
|
|
|
Jun 5 2017, 13:57
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(KnightIgor @ Jun 5 2017, 14:40)  Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено? void f1() { CPU_SR_ALLOCATE(); //выделение переменной (регистра) для сохранения состояния прерываний ENTR_CRT_SECTION(); //вход в критическую секцию (запрет прерываний) ... EXIT_CRT_SECTION(); //выход из критической секции (восстановление состояния прерываний) } void f2() { CPU_SR_ALLOCATE(); //выделение переменной (регистра) для сохранения состояния прерываний ENTR_CRT_SECTION(); //вход в критическую секцию (запрет прерываний) f1(); ... EXIT_CRT_SECTION(); //выход из критической секции (восстановление состояния прерываний) f1(); } Вот и всё отслеживание. Больше никаких проверок не нужно и можно вызывать сколько угодно вложенно - всё работает корректно. ENTR_CRT_SECTION() - компилится в 2 команды CPU; EXIT_CRT_SECTION() - компилится в 1 команду CPU. Теперь сравните со своим огородом в десятки команд.
|
|
|
|
|
Jun 5 2017, 13:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(KnightIgor @ Jun 5 2017, 17:40)  Как кто-то в теме догадался, не люблю я всякие запреты-разрешения прерываний. Зачем меня должно в участке кода заботить, какие разрешены, а какие нет? Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено? Ох, ну вот уж проблема так проблема Это может выглядеть, например, просто как объявление Код { TCritSect cs; ... } в начале блока кода. При выходе из блока прерывания автоматически возвращаются в исходное состояние. Я не говорю, что ваш способ ошибочен, я говорю, что он не даёт преимуществ по сравнению с простым запретом/разрешением прерываний, и к тому же он (гораздо) медленнее. Думаю, что на маленьких процессорах (типа M0(+)) это может быть критично. Кроме того, как тут выяснили, этот способ требует правильной расстановки приоритетов, а иначе способен вызвать HardFault.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 5 2017, 14:21
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(_lexa_ @ Jun 5 2017, 15:26)  ● A Load-Exclusive instruction: Used to read the value of a memory location, requesting exclusive access to that location." Видимо это какое-то изобретение терминологии деятелей из STM. Изучать ядро нужно по первоисточнику http://infocenter.arm.com/help/index.jsp, а не по переводам и толкованиям. А в первоисточнике нет никаких "requesting". Цитата(_lexa_ @ Jun 5 2017, 15:26)  ничего не изменится (на всякий случай я это даже проверил). Каким образом монитор эксклюзивного доступа должен увидеть, что использована именно пара LDREX/STREX Вот именно в таком случае - оно и сработает и обнаружит нарушение эксклюзивности. Команда LDREX взводит некий триггер в "1". STREX атомарно сбрасывает его и, если в в момент своего выполнения триггер стоял - выполняет операцию, если не стоял - не выполняет. И возвращает соотв. значение. Также любое прерывание сбрасывает этот триггер. А также команда CLREX тоже сбрасывает. Вот и всё. Всё просто.
|
|
|
|
|
Jun 5 2017, 17:37
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Начали за упокой, кончили за здравие.
Как уже было сказано, LDREX выставляет атомарный флаг при использовании команды в потоке, конкретно на используемый адрес. Точнее конкретный адрес чтения выставляется на мониторе, и отслеживается аппаратными механизмами сразу на интерфейсе памяти. Атомарный флаг может сбросить любое прерывание, любое аппаратное чтение/запись по этому адресу (например DMA). Флаг не сбрасывается в момент применения команды LDREX в прерывании и перебивании его более высоким приоритетом. Отчего костыль для использования в прерывании содержит собственный сброс до и после. STREX выполняется, или не выполняется без использования программной проверки атомарного флага, этот механизм выполнен полностью аппаратно. STREX выдаёт флаг, видимый для программы - для проверки успешности операции.
Выполнение STREX в потоке - автоматически сбрасывает атомарный флаг, не важно какой результат успеха. Использование в прерывании STREX не гарантирует сброс, но успешно и корректно выставляет программный флаг для проверки операции. Мойте перед и зад - это есть костыль.
+Ещё один важный прикол - конвейер. Лучше перебздеть, и подтверждать полный сброс данных в память. +Ещё грабли - LDREX STREX могут применяться на той памяти, что имеет прямое подключение к ядру мк. Например в М7 часть памяти заведена через ускоритель, в результате применение LDREX STREX моментально вешает мк.
------------ SVC - безусловное прерывание. Отрабатывается без вытеснения из любой позиции. Перебить SVC - просто невозможно. SVC - это рыба для сервисов ОС, с небольшим количеством шаманства - превращается в очень удобную функцию. У меня на SVC полностью работает собственная ось.
|
|
|
|
|
Jun 5 2017, 17:40
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 5 2017, 14:21)  Видимо это какое-то изобретение терминологии деятелей из STM. Изучать ядро нужно по первоисточнику http://infocenter.arm.com/help/index.jsp, а не по переводам и толкованиям. А в первоисточнике нет никаких "requesting". Вот в первоисточнике ARMv7-M Architecture Reference Manual: A3.4.2 Exclusive access instructions and Shareable memory regions.Operation of the global monitor.Load-Exclusive from Shareable memory performs a load from memory, and causes the physical address of the access to be tagged as exclusive access for the requesting processor (эксклюзивный доступ для запрашивающего процессора) Да и как не читать? Это целевой мануал, для процессора с которым я работаю. Цитата(jcxz @ Jun 5 2017, 14:21)  Вот именно в таком случае - оно и сработает и обнаружит нарушение эксклюзивности. Команда LDREX взводит некий триггер в "1". STREX атомарно сбрасывает его и, если в в момент своего выполнения триггер стоял - выполняет операцию, если не стоял - не выполняет. И возвращает соотв. значение. Вот и всё. Всё просто. Именно так я себе все это и представлял. Цитата(AHTOXA @ Jun 5 2017, 13:51)  Вот тут посмотрите: тынц. И вообще всю тему посмотрите. Там очень подробно всё разобрали, с учётом особенностей STM32. Спасибо за ссылку. Узнал много интересного.
Сообщение отредактировал _lexa_ - Jun 5 2017, 22:22
|
|
|
|
|
Jun 5 2017, 18:00
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(_lexa_ @ Jun 5 2017, 23:40)  Спасибо за ссылку. Узнал много интересного. В частности, что LDREX/STREX, по крайней мере для STM32 на cortex-m4, не могут использоваться для синхронизации доступа к памяти, т.к. любое прерывание сбрасывает тег монитор и все дальнейшее выполнение программы происходит, как будто LDREX до этого не выполнялась. Бесполезность LDREX/STREX для синхронизации косвенно подтверждается еще и тем, что в CMSIS-RTOS эти команды в мутексах и семафорах не используются. Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались. Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти. Делить на можно/нельзя - слишком сложно, проще не использовать вовсе. Однако применение LDREX/STREX даёт очень ощутимое ускорение на операциях с атомарными флагами. Словом можно - если руки растут из нужного места. Весь смысл в том чтобы не испортить другие флаги.
|
|
|
|
|
Jun 5 2017, 19:28
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(AVI-crak @ Jun 5 2017, 18:00)  Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались. Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти. Делить на можно/нельзя - слишком сложно, проще не использовать вовсе. Однако применение LDREX/STREX даёт очень ощутимое ускорение на операциях с атомарными флагами. Словом можно - если руки растут из нужного места. Весь смысл в том чтобы не испортить другие флаги. Пожалуй я в самом деле погорячился по поводу невозможности синхронизации с помощью LDREX/STREX.
|
|
|
|
|
Jun 5 2017, 19:42
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(jcxz @ Jun 5 2017, 14:57)  У меня вопросы по Вашему примеру. Что будет, если после сохранения текущего статуса разрешения прерываний в выделеной переменной (оно было разрешено), но до исполнения самой инструкции запрета прерывания произойдет-таки прерывание, которое по какой-либо логике всей программы запретит прерывания? Как я понимаю, после выхода из критической секции прерывание будет-таки разрешено , т.к. будет восстановлено из переменной?
Сообщение отредактировал KnightIgor - Jun 5 2017, 19:45
|
|
|
|
|
Jun 5 2017, 21:35
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AVI-crak @ Jun 5 2017, 19:37)  Как уже было сказано, LDREX выставляет атомарный флаг при использовании команды в потоке, конкретно на используемый адрес. Точнее конкретный адрес чтения выставляется на мониторе, и отслеживается аппаратными механизмами сразу на интерфейсе памяти. Атомарный флаг может сбросить любое прерывание, любое аппаратное чтение/запись по этому адресу (например DMA). Монитор эксклюзивного доступа не контролирует адрес. Об этом явно сказано в мануале. Да и как вы это себе представляете? Если у процессора 4гига адресное пространство - это-ж нужна 4^32 триггеров иметь в CPU - для каждого адреса. Опять-же - любое чтение/запись не может и не должно. Может только STREX, CLREX или любое изменение текущего уровня прерывания. DMA, как и прочие bus-master-ы, тоже не должны влиять - они не относятся к ядру процессора. Цитата(_lexa_ @ Jun 5 2017, 19:40)  т.к. любое прерывание сбрасывает тег монитор и все дальнейшее выполнение программы происходит, как будто LDREX до этого не выполнялась. И что??? Так в этом и заключается вся полезность LDREX/STREX! Именно для того оно и предназначено - если между LDREX и STREX было прерывание (или переключение контекста, которое тоже выполняется через прерывание), то значит - нет гарантии, что операция чтение-модификация-запись была эксклюзивной. Похоже Вы так и не поняли зачем нужен и как работает этот эксклюзивный доступ... Цитата(_lexa_ @ Jun 5 2017, 19:40)  Бесполезность LDREX/STREX для синхронизации косвенно подтверждается еще и тем, что в CMSIS-RTOS эти команды в мутексах и семафорах не используются. Они и не должны там использоваться если ОС должна быть мультиплатформенной. Они могут использоваться в портах ОС. Понятно - все дураки, и создатели ядра и создатели IAR-а например, да все кто поддерживает эти LDREX/STREX - не понимают они их бесполезность. Объясните им  Цитата(AVI-crak @ Jun 5 2017, 20:00)  Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти. Эксклюзивный доступ нужен не к массивам памяти, а к отдельным переменным, коих в программе обычно мало. Достаточно вынести их в отдельный регион памяти и объявить его некешируемым (через MPU). Цитата(KnightIgor @ Jun 5 2017, 21:42)  Что будет, если после сохранения текущего статуса разрешения прерываний в выделеной переменной (оно было разрешено), но до исполнения самой инструкции запрета прерывания произойдет-таки прерывание, которое по какой-либо логике всей программы запретит прерывания? Как я понимаю, после выхода из критической секции прерывание будет-таки разрешено , т.к. будет восстановлено из переменной? Ну наверное. А что это за прерывание такое, которое внутри себя запрещает прерывания??? Аппаратное асинхронное? Т.е. - оно может вызваться в любой точке и в произвольный момент времени запретить прерывания? А зачем это нужно и как может такая программа вообще функционировать?
|
|
|
|
|
Jun 5 2017, 23:19
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 5 2017, 21:35)  Похоже Вы так и не поняли зачем нужен и как работает этот эксклюзивный доступ...  AVI-crak доходчиво объяснил: Цитата(AVI-crak @ Jun 5 2017, 18:00)  Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались. Цитата(jcxz @ Jun 5 2017, 21:35)  Они и не должны там использоваться если ОС должна быть мультиплатформенной. Они могут использоваться в портах ОС. Понятно - все дураки, и создатели ядра и создатели IAR-а например, да все кто поддерживает эти LDREX/STREX - не понимают они их бесполезность. Объясните им  Я же чуть ниже написал, что погорячился. И сообщение поправил, чтоб глаза не резало.
|
|
|
|
|
Jun 6 2017, 07:24
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(jcxz @ Jun 6 2017, 03:35)  Монитор эксклюзивного доступа не контролирует адрес. Об этом явно сказано в мануале. Да и как вы это себе представляете? Если у процессора 4гига адресное пространство - это-ж нужна 4^32 триггеров иметь в CPU - для каждого адреса. Там всё просто, один единственный 32b регистр и схема сравнения на коммутаторе памяти, уже после арбитра и коммутатора нагрузки. Эти команды не выполняются целиком и полностью в ядре мк, они большей частью размазаны по всему кристаллу. Точно так-же как и команды DSB, ISB, ISB, WFE, и так далее.
|
|
|
|
|
Jun 6 2017, 08:20
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AVI-crak @ Jun 6 2017, 09:24)  Там всё просто, один единственный 32b регистр и схема сравнения на коммутаторе памяти, уже после арбитра и коммутатора нагрузки. Эти команды не выполняются целиком и полностью в ядре мк, они большей частью размазаны по всему кристаллу. Открываем мануал на M4, читаем: "The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX. This means that the implemented exclusives reservation granule is the entire memory address range." Фантазии про некий регистр рассеиваются Влияние доступов от DMA и прочих bus-masters на exclusive monitor - также представляется крайне сомнительным, так как: 1. зачем оно нужно? 2. где про это сказано? 3. exclusive monitor относится к ядру, а DMA- и прочие bus-masters к ядру не относятся и у каждого МК-мэйкера свои.
|
|
|
|
|
Jun 6 2017, 10:22
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(jcxz @ Jun 5 2017, 22:35)  Ну наверное. То есть, предложенное решение не на все случаи? Вы также признаете очевидность, Мистер Андерсон? Цитата А что это за прерывание такое, которое внутри себя запрещает прерывания??? Аппаратное асинхронное? Т.е. - оно может вызваться в любой точке и в произвольный момент времени запретить прерывания? А зачем это нужно и как может такая программа вообще функционировать? Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента, пока синхронная часть не обработает флаг и не сочтет нужным прерывание снова разрешить. И Ваш код породит огород, на котором пожнут не то, что сеяли.
Сообщение отредактировал KnightIgor - Jun 6 2017, 10:22
|
|
|
|
|
Jun 6 2017, 11:02
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(jcxz @ Jun 6 2017, 14:20)  1. зачем оно нужно? 2. где про это сказано? 3. exclusive monitor относится к ядру, а DMA- и прочие bus-masters к ядру не относятся и у каждого МК-мэйкера свои. Это результат проверки с отладчиком на реальном камне М3-7. В последнее время я чаще доверяю собственным экспериментам, чем расплывчатому переводу гугла. Кстати, чтобы убрать последствия действий самого отладчика - точки останова необходимо ставить за пределами тестовой функции, иначе будут увлекательные результаты. Цитата(KnightIgor @ Jun 6 2017, 16:22)  Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента Находясь в прерывании нельзя запретить само прерывание, получите сбой. Однако можно сбросить те сработавшие прерывания - что имеют более низкий приоритет, те что находятся в ожидании. Но не те что уже сработали и были вытеснены. Иначе будет разрушение стека. Кстати, эти действия могут понадобится в случае просто огромного кода в теле прерывания. То-есть нужно сначала создать себе проблемы, и только потом героически их решать. Юзайте SVC, и будет вам счастье.
|
|
|
|
|
Jun 6 2017, 12:08
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(KnightIgor @ Jun 6 2017, 12:22)  То есть, предложенное решение не на все случаи? Вы также признаете очевидность, Мистер Андерсон?  Для каких-то высосанных из пальца случае разве что. Для реальных задач из жизни - бесполезно. Цитата(KnightIgor @ Jun 6 2017, 12:22)  Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента, пока синхронная часть не обработает флаг и не сочтет нужным прерывание снова разрешить. И Ваш код породит огород, на котором пожнут не то, что сеяли. Вы сами-то хоть верите в то, что пишете? У Вас реально были такие алгоритмы? Или может у кого-то из здесь присутствующих (чайников не считаем)? Конечно - можно лисапет и с 5-ю колёсами изобрести. Ездить будет? Ну а почему бы и нет. Нужно это кому-то реально? Вопрос риторический. А если на дороге встретится 2 ямки - лисапет с 2-я колёсами ведь в них провалится, а с 5-ю - нет! Это значит что 2-колёсный лисапет никуда не годится и все кто на нём ездят - идиоты, а кто на 5-колёсном - умные? И можно ещё напридумывать кучу причин, почему 2-колёсный плох. Только все почему-то на нём ездят и не жужжат, а у Вас - не получается никак и Вам обязательно нужен 5-колёсный  Цитата(AVI-crak @ Jun 6 2017, 13:02)  эти действия могут понадобится в случае просто огромного кода в теле прерывания. В этом случае надо просто перенести этот код в задачу ОС и всё. Да и без ОС можно решить задачу нормально: возбудив программное прерывание с меньшим приоритетом и продолжив работу там, отпустив аппаратный ISR. Как видно - для всего есть штатные решения, а необходимость запрета прерываний внутри ISR - высосана из пальца. Цитата(AVI-crak @ Jun 6 2017, 13:02)  Это результат проверки с отладчиком на реальном камне М3-7. В последнее время я чаще доверяю собственным экспериментам, чем расплывчатому переводу гугла. А зачем Вам нужно, чтобы DMA-операция влияла на монитор эксклюзивности? Ну т.е. - реально, а не по надуманным причинам?
|
|
|
|
|
Jun 6 2017, 20:34
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(AVI-crak @ Jun 6 2017, 12:02)  Юзайте SVC, и будет вам счастье. Это не по адресу: я и так юзаю - почитайте сначала. Меня отговаривают и предлагают варианты, которые не всегда работоспособны. Цитата Находясь в прерывании нельзя запретить само прерывание, получите сбой. Я предполагаю, что это Вы сгоряча. Очень даже легко можно запретить прерывание, находясь в нем. Без последствий. Цитата(jcxz @ Jun 6 2017, 13:08)  Для каких-то высосанных из пальца случае разве что. Для реальных задач из жизни - бесполезно. Почитайте Мерфи: если что-то может случиться, оно случится. Цитата Вы сами-то хоть верите в то, что пишете? Инженерная наука не оперирует понятием веры. Есть факты, есть опыт. ОТ: правда, слышал, что ныне за такое высказывание в РФ и сесть можно. Цитата Как видно - для всего есть штатные решения, а необходимость запрета прерываний внутри ISR - высосана из пальца. Утверждение более чем недальновидное. Рассмотрим пример. Сразу оговорюсь, что речь не о глобальном запрете прерывания, а о запрете периферийного. Но и Вы пишете об ISR вообще. В прерывании от устройства обнаруживается, что буфер приема заполнен, т.е. недовыбран синхронным циклом. Есть два варианта: выбросить данные или таки еще немного подождать, дать возможность выбрать, тем более, что передача данных по каналу сама по себе требует времени, и можно успеть до переполнения периферийного регистра. Одно из решений: запретить прерывание, оставив флаг, выйти, дать синхронному циклу поработать. Синхронный цикл после выбоки данных просто разрешает прерывание снова. Поскольку флаг взведен, прерывание щелкнет незамедлительно еще раз, данные будут записаны в освободившееся место. Это одно из возможных решений, которое я никому не навязываю. У меня так работают многие каналы. На результаты жалоб нет.
Сообщение отредактировал KnightIgor - Jun 6 2017, 20:11
|
|
|
|
|
Jun 6 2017, 20:56
|
Участник

Группа: Участник
Сообщений: 23
Регистрация: 23-03-15
Пользователь №: 85 852

|
Цитата(jcxz @ Jun 6 2017, 08:20)  Открываем мануал на M4, читаем: "The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX. This means that the implemented exclusives reservation granule is the entire memory address range." судя по этому абзацу да по остальному в мануалах (применительно к cortex-m4) для синхронизации на LDREX/STREX достаточно одной единственной ячейки памяти, которую будут читать/писать LDREX/STREX, на весь исполняемый процессором код. А для STM32f4 даже настройки MPU не потребуется (кэша на RAM там нет) Цитата(jcxz @ Jun 6 2017, 08:20)  Влияние доступов от DMA и прочих bus-masters на exclusive monitor - также представляется крайне сомнительным, так как: Я так понимаю, AVI-crak просто провел эксперимент, в результате которого DMA сбросил тэг монитора, и здесь не стоит вопрос нужно ли это или не нужно. По поводу того, где это сказано, конечно не совсем про то, но в принципе сюда можно взглянуть: ARMv7-M Architecture Reference ManualA3.4.5 Load-Exclusive and Store-Exclusive usage restrictions• An explicit store to memory can cause the clearing of exclusive monitors associated with other processors, therefore, performing a store between the LDREX and the STREX can result in a livelock situation. As a result, code must avoid placing an explicit store between an LDREX and an STREX in a single code sequence.
|
|
|
|
|
Jun 6 2017, 21:36
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(KnightIgor @ Jun 6 2017, 22:34)  Рассмотрим пример. Сразу оговорюсь, что речь не о глобальном запрете прерывания, а о запрете периферийного. Но и Вы пишете об ISR вообще. Передёргиваете. При чём тут маскирование определённого прерывания? Это вполне штатная ситуация, сам так часто делаю. Разговор был о глобальном флаге запрета всех прерываний. Если даже это вдруг по каким-то причинам нужно, то это не является штатным случаем. Но для таких особых случаев и код особый. В остальных 99.9% - те критические секции что я описал вполне работоспособны. Да вообще - какой смысл спорить то? О чём?? Откройте исходники какой-нить ОС - посмотрите как эти критические секции реализованы. И объясняйте их создателем что они дураки, а Вы один умный. Откройте любые примеры идущие с компилятором - посмотрите. Понятно что все вокруг дураки, один Вы умный..... Цитата(_lexa_ @ Jun 6 2017, 22:56)  для синхронизации на LDREX/STREX достаточно одной единственной ячейки памяти Ну если Вашему коду достаточно - Вы счастливый человек, так как у Вас очень простая программа. Обычно таких мест в программе - десятки. Цитата(_lexa_ @ Jun 6 2017, 22:56)  По поводу того, где это сказано, конечно не совсем про то, но в принципе сюда можно взглянуть: Это не то что "не совсем то", а совсем не то. Там речь о "других CPU". Для других CPU - кто-ж спорит - это конечно нужно, если программа выполняется на нескольких ядрах. Я писал про другие bus-masters типа DMA, Ethernet-контроллеров и прочего, которое не выполняет программы, задачи, не выполняет какой-то код, задачи которого не нужно синхронизировать с другими задачами.
|
|
|
|
|
Jun 7 2017, 08:31
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(jcxz @ Jun 6 2017, 13:20)  Фантазии про некий регистр рассеиваются  Опять открываем мануалs Цитата(ARM ® v7-M Architecture Reference Manual) A3.4 Synchronization and semaphores The model for the use of a Load-Exclusive/Store-Exclusive instruction pair, accessing memory address x is: • The Load-Exclusive instruction always successfully reads a value from memory address x • The corresponding Store-Exclusive instruction succeeds in writing back to memory address x only if no other processor or process has performed a more recent store of address x. The Store-Exclusive operation returns a status bit that indicates whether the memory write succeeded. A Load-Exclusive instruction tags a small block of memory for exclusive access. The size of the tagged block is IMPLEMENTATION DEFINED, see Tagging and the size of the tagged memory block on page A3-75. A Store-Exclusive instruction to the same address clears the tag.
A3.4.3 Tagging and the size of the tagged memory block As shown in Figure A3-6 on page A3-71 and Figure A3-7 on page A3-74, when a LDREX instruction is executed, the resulting tag address ignores the least significant bits of the memory address: Tagged_address == Memory_address[31:a] The value of a in this assignment is IMPLEMENTATION DEFINED, between a minimum value of 2 and a maximum value of 11. For example, in an implementation where a = 4, a successful LDREX of address 0x000341B4 gives a tag value of bits[31:4] of the address, giving 0x000341B. This means that the four words of memory from 0x000341B0 to 0x000341BF are tagged for exclusive access. Subsequently, a valid STREX to any address in this block will remove the tag.A3 ARM Architecture Memory Model A3.4 Synchronization and semaphores A3-76 Copyright © 2006-2008, 2010, 2014 ARM. All rights reserved. ARM DDI 0403E.b Non-Confidential ID120114 The size of the tagged memory block is called the Exclusives reservation granule. The Exclusives reservation granule is IMPLEMENTATION DEFINED between: • One word, in an implementation with a == 2. • 512 words, in an implementation with a == 11. Note For the local monitor, one of the IMPLEMENTATION DEFINED options is for the monitor to treat any access as matching the address of the previous Load-Exclusive access. In such an implementation, the Exclusives reservation granule is the entire memory address range. Цитата(ARM® Cortex®‑M4 Processor Technical Reference Manual ) 3.6 Exclusive monitor
The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX. This means that the implemented exclusives reservation granule is the entire memory address range. Цитата(Cortex-M3 Technical Reference Manual (r2p0)) 3.6. Exclusive monitor The Cortex-M3 processor implements a local exclusive monitor. For more information about semaphores and the local exclusive monitor see the ARMv7M ARM Architecture Reference Manual. Так что вырисовывается вот что: - вся память поделена на регионы размером [Exclusives reservation granule] - есть N регистров эксклюзивного доступа к памяти, где N от 1 до RAM_SIZE/[Exclusives reservation granule] - сбрасывается эксклюзивный доступ РЕГИОНА при ЛЮБОЙ явной записи в этот РЕГИОН - для Cortex-M3 размер [Exclusives reservation granule] явно не определен и, по всей видимости, определяется производителем. - для Cortex-M4 размер [Exclusives reservation granule] равен всей памяти.
|
|
|
|
|
Jun 7 2017, 08:56
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alechek @ Jun 7 2017, 10:31)  Опять открываем мануалs Не тот мануал открываете. Этот мануал - на архитектуру в целом (по которой построены разные ядра), а я Вам приводил на конкретное ядро, соответствующее топику - читайте внимательнее. И даже в выделенном Вами фрагменте архитектурного мануала уже указано "IMPLEMENTATION DEFINED", а в мануале на ядро M4, основанное на этой архитектуре это NOT IMPLEMENTED - вполне законно. Цитата(Alechek @ Jun 7 2017, 10:31)  - есть N регистров эксклюзивного доступа к памяти, где N от 1 до RAM_SIZE/[Exclusives reservation granule] ... Ещё раз, для самых непонятливых: откройте мануал на конкретное ядро, то есть - "ARM Cortex-M4 Processor Technical Reference Manual" и оставьте свои пустые фантазии. Цитата(Alechek @ Jun 7 2017, 10:31)  - вся память поделена на регионы размером [Exclusives reservation granule] Эта фраза из TRM: "This means that the implemented exclusives reservation granule is the entire memory address range." - означает что "есть только одна гранула, размером со всю память". А эта фраза TRM: "The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX." Означает что инструкция LDREX относится к предыдущей инструкции STREX с любым адресом (т.е. - любой адрес является "matching the address") вне зависимости от адреса.
|
|
|
|
|
Jun 7 2017, 09:18
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата Не тот мануал открываете Ну почему же не тот? Я все открыл, смотрите выше. И мануалы на М4 и на М3 там тоже есть. Выводы подправил. А вот Вы вводите людей в заблуждение: Цитата(jcxz @ Jun 5 2017, 12:49)  Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности. Ну и где у вас между LDREX и STREX нарушение эксклюзивности? Про условие эксклюзивной записи для нарушения эксклюзивности - нет такого!
|
|
|
|
|
Jun 7 2017, 11:52
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (jcxz @ Jun 7 2017, 00:36)  Я писал про другие bus-masters типа DMA, Ethernet-контроллеров и прочего, которое не выполняет программы, задачи, не выполняет какой-то код, задачи которого не нужно синхронизировать с другими задачами. На жирных камнях с многоуровневыми кэшами - вполне может проверяться активность других bus-masters. На Cortex-M точно нет. Вообще про LDREX/STREX лучше читать не у ARM, а у авторов - Hitachi SH. А правильное применение есть в сорцах Keil RTX QUOTE (Alechek @ Jun 7 2017, 13:21)  В смысле, если между LDREX_1/STREX_1 сделать простой STR (в этот регион), то будет нарушение эксклюзивности. Нет, не будет.
|
|
|
|
|
Jun 7 2017, 12:22
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(scifi @ Jun 7 2017, 15:27)  Это называется "глюк в софте". Систему можно и проще поломать - просто забейте весь стек мусором  Цитата(jcxz @ Jun 7 2017, 16:23)  А зачем так делать?? Господа, оставьте эти риторические вопросы. Здесь не обсуждается вопрос ЗАЧЕМ. Нет ничего невозможного. Arduino уже добрался до Cortex! Сделать вызов функции между LDREX/STREX - как раз плюнуть! От неправильного применения может спасти только чтение правильной документации. Цитата(LightElf @ Jun 7 2017, 16:52)  Нет, не будет. А поподробней? Практика или документация? Пока что из того, что я привел, должно быть нарушение. Ошибка в ней или я что-то недочитал?
|
|
|
|
|
Jun 7 2017, 12:39
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(LightElf @ Jun 7 2017, 14:52)  А правильное применение есть в сорцах Keil RTX Действительно - готовое решение. Спасибо за наводку ))) Причем в примере ниже два способа - через запрет /разрешения всех прерываний и через ldrex/strex. ..\Keil 5\ARM\Pack\ARM\CMSIS\5.0.0\CMSIS\RTOS\RTX\SRC\rt_MemBox.c: CODE /*--------------------------- rt_alloc_box ----------------------------------*/
void *rt_alloc_box (void *box_mem) { /* Allocate a memory block and return start address. */ void **free; #ifndef __USE_EXCLUSIVE_ACCESS U32 irq_mask;
irq_mask = (U32)__disable_irq (); free = ((P_BM) box_mem)->free; if (free) { ((P_BM) box_mem)->free = *free; } if (irq_mask == 0U) { __enable_irq (); } #else do { if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0U) { __clrex(); break; } } while (__strex((U32)*free, &((P_BM) box_mem)->free)); #endif return (free); } и тут: rt_HAL_CM.h Код /* Functions */ #ifdef __USE_EXCLUSIVE_ACCESS #define rt_inc(p) while(__strex((__ldrex(p)+1U),p)) #define rt_dec(p) while(__strex((__ldrex(p)-1U),p)) #else #define rt_inc(p) __disable_irq();(*p)++;__enable_irq(); #define rt_dec(p) __disable_irq();(*p)--;__enable_irq(); #endif
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 7 2017, 13:27
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 7 2017, 16:13)  чтобы, если перед OS_ENTER_CRITICAL() были запрещены, то после OS_EXIT_CRITICAL() так и остались. Оно так и сделано в приведенном выше примере. см. void *rt_alloc_box (void *box_mem) в файле rt_MemBox.c Но мне гораздо нравится больше как это сделано во freertos, там юзается basepri (кроме CM0), т. е. запрещаются не все прерывания. Точнее, никогда не запрещаются прерывания, обладающие приоритетом выше, чем заданный в настройках порта freertos - configMAX_SYSCALL_INTERRUPT_PRIORITY С одним ограничением - в таких lockfree прерываниях категорически нельзя использовать сервисы rtos. Чтобы это все правильно работало, NVIC нужно настраивать исключительно на полностью вытесняющие прерывания: Код NVIC_SetPriorityGrouping(0); // 4 bits for pre-emption priority, 0 bits for subpriority CODE #define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() #define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical()
.....
static portFORCE_INLINE void vPortRaiseBASEPRI( void ) { uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm { /* Set BASEPRI to the max syscall priority to effect a critical section. */ msr basepri, ulNewBASEPRI dsb isb } } /*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void ) { __asm { /* Set BASEPRI to 0 so no interrupts are masked. This function is only used to lower the mask in an interrupt, so memory barriers are not used. */ msr basepri, #0 } }
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 7 2017, 13:30
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Alechek @ Jun 7 2017, 17:22)  А поподробней? Практика или документация? Пока что из того, что я привел, должно быть нарушение. Ошибка в ней или я что-то недочитал? Практика. Выше я уже приводил ссылку на предыдущее обсуждение LDREX/STREX. Там тесты разных вариантов. Видимо, в документации под словом "more recent store of address x" подразумевается всё же STREX.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 8 2017, 05:01
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
AHTOXA, спасибо, ознакомился. Но, опять противоречивые результаты: AVI-crak говорит, что флаг сбрасывает любая запись по адресу, хоть DMA. ArtDenis в своих тестах показывает, что даже явная запись не сбрасывает. AlexandrY утверждает, что у него явная запись сбрасывает флаг, а неявная (PUSH) - не меняет состояние. Походу, собака порылась в Цитата(ARM ® v7-M Architecture Reference Manual) A3.4.5 Load-Exclusive and Store-Exclusive usage restrictions The Load-Exclusive and Store-Exclusive instructions are designed to work together, as a pair, for example a LDREX/STREX pair or a LDREXB/STREXB pair. As mentioned in Context switch support, ARM recommends that the Store-Exclusive instruction always follows within a few instructions of its associated Load-Exclusive instructions. In order to support different implementations of these functions, software must follow the notes and restrictions given here. ... В частности, по поводу простой записи: Цитата • An explicit store to memory can cause the clearing of exclusive monitors associated with other processors, therefore, performing a store between the LDREX and the STREX can result in a livelock situation. As a result, code must avoid placing an explicit store between an LDREX and an STREX in a single code sequence. • LDREX and STREX operations must be performed only on memory with the Normal memory attribute. То есть: - LDREX/STREX применять только в паре, они для этого сделаны. Все остальное - от лукавого. Может сработать, а может и нет, зависит от конкретной реализации ядра - LDREX/STREX применять только на Normal памяти: Цитата(ARM ® v7-M Architecture Reference Manual) A3.5.1 Memory types For each memory region, the most significant memory attribute specifies the memory type. There are three mutually exclusive memory types: • Normal. • Device. • Strongly-ordered. - вроде как сброс локального монитора текущего ядра может происходить при ЛЮБОЙ записи (хоть DMA), при ЯВНОЙ записи могут сбросится только мониторы других ядер. Но по факту может быть что угодно в зависимости от конкретной реализации. Извращения проверять обязательно! Цитата(ARM ® v7-M Architecture Reference Manual) A3.4.1 Exclusive access instructions and Non-shareable memory regions When a processor writes using any instruction other than a Store-Exclusive: • If the write is to a physical address that is covered by its local monitor it is IMPLEMENTATION DEFINED whether the write affects the state of the local monitor. - локальный монитор сбрасывается при возникновении исключения. Т.е. для одноядерной системы неважно, была ли в другом процессе запись(эксклюзивная) - все равно по входу и выходу из исключения происходит сброс. Цитата A3.4.4 Context switch support In ARMv7-M, the local monitor is changed to Open Access automatically as part of an exception entry or exit sequence.
|
|
|
|
|
Jun 8 2017, 06:21
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Alechek @ Jun 8 2017, 10:01)  - LDREX/STREX применять только в паре, они для этого сделаны. Все остальное - от лукавого. Может сработать, а может и нет, зависит от конкретной реализации ядра Именно. Различия в результатах тестов вызваны, скорее всего, различиями в реализации. (Ну или кто-то накосячил в тестах  ) Способ использования от этого не меняется - только в паре. Добавьте в ваш список выводов, что монитор может срабатывать на любое изменение уровня прерываний (вход в прерывание или выход из него). ЗЫ. Хотя насчёт DMA - я лично не верю. В этом случае при непрерывно идущих быстрых транзакциях DMA можно наглухо зависнуть в LDREX/STREX.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 8 2017, 11:54
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(jcxz @ Jun 8 2017, 11:17)  И правильно! Через DMA и пр. - ЗАЧЕМ??? Импульсивный Вы наш, по делу бы что сказали! Цитата(AHTOXA @ Jun 8 2017, 11:21)  Добавьте в ваш список выводов, что монитор может срабатывать на любое изменение уровня прерываний Добавил, куда можно было. Весь этот раздел A3.4 - сплошные выводы. Читать и читать. Цитата(AHTOXA @ Jun 8 2017, 11:21)  ЗЫ. Хотя насчёт DMA - я лично не верю. В этом случае при непрерывно идущих быстрых транзакциях DMA можно наглухо зависнуть в LDREX/STREX. Мне тоже идея с DMA не очень нравится. Вроде как не обязательно Store от ядра должно исходить.... В одном месте так написано, в другом - по другому... Вобщем, все на откуп реализации:
Опыты, только опыты... Ни в одной докуметации на MCU не видел таких тонкостей.
|
|
|
|
|
Jun 8 2017, 13:39
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Alechek @ Jun 8 2017, 16:54)  Вобщем, все на откуп реализации: Хорошие картинки, теперь понятны отличия в реализации. По идее, получается, могут существовать реализации, где DMA сбрасывает монитор. Надо будет учесть. Цитата(Alechek @ Jun 8 2017, 16:54)  Опыты, только опыты... Ни в одной докуметации на MCU не видел таких тонкостей. Думаю, это плата за универсальность ядра. АРМу пришлось при проектировании закладывать разные варианты реализации.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 8 2017, 13:44
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (AHTOXA @ Jun 8 2017, 09:21)  Именно. Различия в результатах тестов вызваны, скорее всего, различиями в реализации. (Ну или кто-то накосячил в тестах  ) Способ использования от этого не меняется - только в паре. Добавьте в ваш список выводов, что монитор может срабатывать на любое изменение уровня прерываний (вход в прерывание или выход из него). ЗЫ. Хотя насчёт DMA - я лично не верю. В этом случае при непрерывно идущих быстрых транзакциях DMA можно наглухо зависнуть в LDREX/STREX. Есть архитектура, есть реализация. На Cortex-M, которые по определению одноядерные, монитор как таковой отсутствует. Есть просто один-единственный триггер. LDREX его взводит, STREX проверяет что установлен, выполняет запись и сбрасывает. Любое исключение сбрасывает бит. Принудительно можно сбросить через CLREX. На на навороченных многоядерных камнях с MMU, многоуровневыми кэшами, множеством bus-master устройств реализация может быть совсем другой.
|
|
|
|
|
Jun 8 2017, 14:52
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(LightElf @ Jun 8 2017, 18:44)  Есть архитектура, есть реализация. На Cortex-M, которые по определению одноядерные, монитор как таковой отсутствует. Есть просто один-единственный триггер. LDREX его взводит, STREX проверяет что установлен, выполняет запись и сбрасывает. Любое исключение сбрасывает бит. Принудительно можно сбросить через CLREX. Не вижу в вашем высказывании противоречия с моим. (Или вы не возражали, а дополняли?) И на Cortex-M есть нюансы. Где-то обычная запись сбрасывает монитор, а где-то -- нет. Где-то DMA сбрасывает монитор, а где-то -- нет.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 8 2017, 20:32
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AVI-crak @ Jun 8 2017, 15:21)  Неявная запись (PUSH) - является отложенным событием (как и любая запись кучи регистров), код выполняется параллельно, сбросить физику с подтверждением не получится, но можно немного подождать Сколько? Сколько вешать в граммах? Цитата(AVI-crak @ Jun 8 2017, 15:21)  в пустом цикле или сбросить конвейер. Это что такое? И как оно поможет? Цитата(AVI-crak @ Jun 8 2017, 15:21)  И наверное главное, давайте указывать явно - какой чип в тесте на данный момент. DMB/DSB/и прочие B - спасут отца русской демократии  Цитата(LightElf @ Jun 8 2017, 15:44)  На Cortex-M, которые по определению одноядерные Вы это расскажите NXP с их линейкой LPC43xx. Про свои определения. Или Ваш мир Cortex-M ограничен STM32? Курица - не птица, Cortex-M - не STM! Рифма одна-ко. Надо в подпись внести ©
|
|
|
|
|
Jun 9 2017, 07:50
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Коли SVC синхронное и его не получиться использовать нормально в прерываниях (для lockfree решений), то может быть для этой цели подойдет pendSV?
А, чтобы разделить переключатель контекста rtos и юзерские вызовы этого самого pendSV, скажем, в R0 кладем адрес функции, а в остальные регистры ее параметры, а уже внутри pendSV все это разбираем. Приоритет pendSV самый низкий (ниже лишь systick). Тогда другой вызов pendSV прервать его не сможет, а лишь поставить в очередь. Т.е. обеспечивается атомарность действий как в прерываниях, так и в основном коде. Вижу одно ограничение - передавать в такие функции указатели нежелательно, а можно лишь готовые данные (прямо в регистры R1...), т.е. ограничен объем передаваемых данных. В противном случае нет никакой гарантии, что к моменту вызова соотв. функции (внутри pendSV) данные по указателям будут актуальны.
Или тут есть какие-то подводные камни? зы. Предположительно вангую грабли со вложенными вызовами (вытесняющие прерывания), где оба обработчика вызывают pendSV...
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 10:58
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 9 2017, 13:33)  PendSV не "вызывают" ... Да, это-то понятно, это все - придирки к словам, а речь о другом: как сделать так, чтобы pendSV могли вызывать взводить разные обработчики, особенно вложенные друг в друга, но так, чтобы в стеке сформировалась очередь данных, которые позволят этот pendSV обработать несколько раз подряд и не потерять ни одного запроса и не разрушить стек? Понятно, что pendSV не для этого был задуман, но тем не менее )) Размышляя вслух дальше - выполняемый в данный момент pendSV может прервать другое более приоритетное прерывание и опять накидать в стек новых данных перед взводом pendSV, Или использовать внутри pendSV вызов соотв. SVC, который имеет приоритет выше pendSV... Заумно как-то выходит. Но возможно ли осуществить что-то подобное? Цель - избежать критических секций с запретом прерываний и "капризного" LDREX/STREX.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 13:02
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 13:58)  как сделать так, чтобы pendSV могли вызывать взводить разные обработчики, особенно вложенные друг в друга, но так, чтобы в стеке сформировалась очередь данных, которые позволят этот pendSV обработать несколько раз подряд и не потерять ни одного запроса и не разрушить стек? Очередь данных в стеке не формируется - формируйте ее отдельно, а потом обрабатывайте в PendSV. Но для данной задачи это неэффективно и не имеет смысла - есть LDREX/STREX, если его не хватает, то есть запрет части или всех прерываний.
|
|
|
|
|
Jun 9 2017, 13:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(Шаманъ @ Jun 9 2017, 16:02)  Очередь данных в стеке не формируется - формируйте ее отдельно, а потом обрабатывайте в PendSV. А все равно грабли - процесс формирования очереди должен быть защищен критической секцией, масло масляное ((( Цитата Но для данной задачи это неэффективно и не имеет смысла - есть LDREX/STREX, если его не хватает, то есть запрет части или всех прерываний. Согласен, но хочется ведь гипотетического универсального решения, вот и спрашиваю ))) Короче, задача довольно тривиальная: программная очередь, набиваемая в обработчике (скажем, очередь байтов), там же сигналим счетным семафором, переходим к соотв. задаче, которая это семафор ждет и выгребает из этой же очереди байты. Нужно защищать указатели (голова/хвост) очереди от прерывания. Сейчас сделано просто и логично - в конкретном экземпляре очереди запрещаются прерывания лишь от того, кто использует эту самую очередь - от USART.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 14:14
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 16:20)  хочется ведь гипотетического универсального решения Если пишите под GCC, то можно посмотреть на atomic built-in функции https://gcc.gnu.org/onlinedocs/gcc-4.4.3/gc...c-Builtins.html . Цитата Короче, задача довольно тривиальная: программная очередь, набиваемая в обработчике (скажем, очередь байтов), там же сигналим счетным семафором, переходим к соотв. задаче, которая это семафор ждет и выгребает из этой же очереди байты. Нужно защищать указатели (голова/хвост) очереди от прерывания. Интересно зачем? Если это что-то типа кольцевого буфера приделанного к UART, то один указатель изменяется только в задаче, а второй только в прерывании. Пересечения между ними не происходит. Семафор это головная боль ОС. Вот и все. У меня сделано похожим образом.
|
|
|
|
|
Jun 9 2017, 14:30
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(Шаманъ @ Jun 9 2017, 17:14)  Интересно зачем? Если это что-то типа кольцевого буфера приделанного к UART, то один указатель изменяется только в задаче, а второй только в прерывании. Пересечения между ними не происходит. Еще как происходит - я контролирую переполнение и исчерпание очереди (соотв. ловушки/логи)! Если в задаче в процессе извлечения свежего байта из очереди пришел еще один новый байт, который нужно быстро положить в ту же очередь, то без соотв. критических секций получим что угодно, обычно получаем HF. Поэтому эти две вещи нужно изолировать - пока достаем байт из очереди (в задаче), временно запрещаем прерывания от того, кто наполняет эту очередь. Именно это я и описал выше. У меня очередь сделана в виде шаблона, всего один параметр - тип данных. При создании экземпляра очереди ей передается ссылка на класс Interrupt, в котором есть два обязательным метода disable и enable. Для каждой очереди он может быть свой, поэтому запрещаются лишь те прерывания, которые конфликтуют с конкретным экземпляром очереди. Цитата Семафор это головная боль ОС. При чем тут это? Я лишь привел пример с осью, как наиболее универсальный. Но кто не пользуется осью, могут просто поллить некий флажок в основном коде, а в прерываниях его взводить или инкрементировать. Способ оповещения основного кода в данном случае не имеет никакого значения. Отклоняемся от темы )))
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 15:40
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 17:30)  При чем тут это? Я лишь привел пример с осью, как наиболее универсальный. Но кто не пользуется осью, могут просто поллить некий флажок в основном коде, а в прерываниях его взводить или инкрементировать. Способ оповещения основного кода в данном случае не имеет никакого значения. Отклоняемся от темы ))) Это как раз причина по которой у меня с ОС не происходит, а с "неким флажком" происходит. Поясняю: Если работа задачи, которая извлекает данные из очереди управляется семафором через ОС, то "недополнения" очереди возникнуть просто не может - задача блокируется и ожидает когда появятся данные. Поэтому указатель "хвоста" в полной безопасности. Теперь про голову - данные из UART выгребаем в прерывании, в этом же прерывании увеличиваем счетчик семафора и добавляем в очередь. Чтобы избежать переполнения очереди достаточно проверить счетчик семафора. Вот собственно и все. Счетчик семафора это проблема ОС, остальное (очередь и указатели на голову/хвост) в полной безопасности. Если интересно, как сделана у меня в ОС работа с семафорами, то через те же LDREX/STREX  Правда это если не касаться вопросов переключения задач и системных вызовов, но то уже точно другая тема.
|
|
|
|
|
Jun 9 2017, 16:27
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(Шаманъ @ Jun 9 2017, 18:40)  Это как раз причина по которой у меня с ОС не происходит, а с "неким флажком" происходит. Поясняю: Да при чем тут семафор, ось, флажки и т.п.??? Я говорю про совсем другое - манипулирование индексами головы, хвоста и изменяемых данных которые должны меняться в едином непрерывном блоке кода. Если обработчик прерываний разорвет эту цепочку в самом неподходящем месте, то рано или поздно произойдет HF. Цитата(AVI-crak @ Jun 9 2017, 17:38)  Приоритет SVC - 0. Пользовательские прерывания 1~14. Системный таймер, и таймер реального времени =15. Поменять шило на мыло? По вашей логике получится, что пока этот приоритетный SVC не отработает, ни одно более важное аппаратное прерывание не пройдет. SVC с таким высоким приоритетом, вызываемые из других менее приоритетных прерываний по сути временно задирает их собственный приоритет, который был "ниже плинтуса", отбирая "право голоса" у более приоритетных прерываний. На лицо - инверсия приоритетов. С чем боролись на то и напоролись. Ни чем не лучше глобальной критической секции (запрет/разрешение всех прерываний). А должно быть совсем иначе - срочные и архиважные аппаратные прерывания должны отработаться предельно быстро, куда надо просемафорить и тут же освободить процессор.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 17:08
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 19:27)  Я говорю про совсем другое - манипулирование индексами головы, хвоста и изменяемых данных которые должны меняться в едином непрерывном блоке кода. Если обработчик прерываний разорвет эту цепочку в самом неподходящем месте, то рано или поздно произойдет HF. От же ж...ну как Вам еще объяснить. Читайте внимательно и думайте: 1. Указатель на голову (куда добавляются данные) он используется только в прерывании которое добавляет данные, только там, и больше нигде. 2. Указатель на хвост (откуда вычитываются данные) он используется только в задаче которая читает данные, только там, и больше нигде. Синхронизация делается семафором, как и защита от переполнения/недополнения. К семафору есть доступ и у задачи, и у прерывания, но он делается через ОС. Теперь понятно? Если нет, то перечитайте пожалуйста еще раз, ну или несколько раз - не знаю как объяснить иначе...
|
|
|
|
|
Jun 9 2017, 17:23
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(Шаманъ @ Jun 9 2017, 20:08)  От же ж...ну как Вам еще объяснить. Читайте внимательно и думайте: Я про Фому, а он - про Ерему ... Ясен пень, что голова и хвост изменяются в разным местах - один в фоне задач, другой - в перрывании, но ! Чтобы проверить переполнение/исчерпание, нужно контроллировать в непрерывном куске кода ОБА указателя/индекса. Это можно делать только там, где производите изменение этих самых указателей/индексов - в прерывании и в фоне задач. В прерывании это не проблема - защищать ничего не нужно, достаточно лишь не класть в буфер новые данные и кинуть соотв. сообщение/исключение. А в фоне задачи нужно защищать обращение к ОБОИМ указателям в некой критической секции, иначе невозможно контроллировать подобные аварийные события. Если этого не делать, то буфер может быть переполнен/исчерпан так, что об этом невозможно будет узнать. Также реализуется обратная ситуация - задача кладет данные в буфер, взводит нужное прерывание и уже в соотв. обработчике буфер выгребается и отправляется во вне. Чтобы положить данные в буфер в фоне задачи, нужно обращаться в непрерывном куске кода к ОБОИМ указателям. Поэтому тут нужна критическая секция или что-то подобное. Цитата Синхронизация делается семафором... Точно, я про Фому, а он - про Ерему )))
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 17:40
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 20:23)  Чтобы проверить переполнение/исчерпание, нужно контроллировать в непрерывном куске кода ОБА указателя/индекса. Нет. Достаточно проверить состояние семафора.Цитата А в фоне задачи нужно защищать обращение к ОБОИМ указателям в некой критической секции, иначе невозможно контроллировать подобные аварийные события. Если этого не делать, то буфер может быть переполнен/исчерпан так, что об этом невозможно будет узнать. Если напрячься и таки подумать, то в задаче буфер переполнен не модет быть вообще, ибо она данные только читает. А исчерпан не может быть т.к. задача синхронизирована семафором значение которого дает кол-во данных в очереди. Про прерывание Вы и сами написали. Так кто там про Фому Цитата Также реализуется обратная ситуация - задача кладет данные в буфер, взводит нужное прерывание и уже в соотв. обработчике буфер выгребается и отправляется во вне. Чтобы положить данные в буфер в фоне задачи, нужно обращаться в непрерывном куске кода к ОБОИМ указателям. Поэтому тут нужна критическая секция или что-то подобное. Да не нужно - достаточно семафора. P.S. Может быть Вы не так понимаете что такое семафор. У меня это объект синхронизации задач, который может принимать значения от 0 до некоторого MAX. Счетчик семафора показывает доступность ресурса (в данном случае кол-во данных в очереди). Задача может запросить конкретное кол-во данных или диапазон (от и до) - если нужное кол-во доступно, то задача получит запрошенное кол-во данных, если нет, то будет приостановлена, пока не будет доступно запрошенное кол-во данных.
|
|
|
|
|
Jun 9 2017, 18:04
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(Шаманъ @ Jun 9 2017, 20:56)  Конечно, ибо то, о чем я пишу работает  И самолеты летают. Но иногда, увы, падают  Цитата ОК поставим вопрос по-другому, каким образом может быть переполнен буфер в задаче, которая из него только читает? Если она только читает, то буфер со временем просто переполнится, чтобы избежать этого, из буфера нужно не просто читать данные, но и изменять соотв. указатель. При заполнении буфера (в прерывании) нужно сравнивать ОБА указателя. Если это прерывание возникнет между чтением данных в задаче и изменением соотв. указателя, то будет беда. Обнаружить ее крайне сложно. При обратной ситуации - задача набивает буфер для передачи через прерывание - нужно контролировать переполнение этого буфера, обращаясь к обоим указателям. Я делал это несколько иначе, использовал счетчик свободного места, вообще не сравнивая указатели. Это получается несколько быстрее, но отъедает немного места в памяти. Обращение к этому счетчику и изменение соотв. указателей, должно быть непрерывным. Иначе - HF
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 18:54
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(Forger @ Jun 9 2017, 21:04)  И самолеты летают. Но иногда, увы, падают  Я тоже могу подколоть - если Вам хочется позаниматься словоблудием, то это не ко мне. Цитата Если она только читает, то буфер со временем просто переполнится, чтобы избежать этого, из буфера нужно не просто читать данные, но и изменять соотв. указатель. Гениально. Для меня чтение из очереди это всегда было как получение данных, так и коррекция указателя. Цитата При заполнении буфера (в прерывании) нужно сравнивать ОБА указателя. Если это прерывание возникнет между чтением данных в задаче и изменением соотв. указателя, то будет беда. И в чем беда? Прочитали данные, потом произошло прерывание (в нем сравнили указатели и изменили указатель головы, кстати, в некоторых случаях можно указатели и вообще не сравнивать - достаточно кол-ва данных в очереди = значения семафора), потом (когда возвратились в задачу) изменили указатель хвоста - что мы имеем - в прерывании размер очереди был на 1 ячейку меньше, все. Никаких проблем нет. Сами же выше написали про это, а теперь "надумали" проблему там, где ее нет. Цитата При обратной ситуации - задача набивает буфер для передачи через прерывание Обратная задача решается так же, но какой смысл про нее, когда с первой не закончили. Цитата Я делал это несколько иначе, использовал счетчик свободного места, вообще не сравнивая указатели. Это получается несколько быстрее, но отъедает немного места в памяти. Обращение к этому счетчику и изменение соотв. указателей, должно быть непрерывным. Иначе - HF Свободное место или занятое это одно и то же (свободное = размер - занятое  ), т.е. Вы говорите +- о том же, что и я писал выше и сейчас. Какой HF? Отчего? Выше я написал реальный пример, объясните где там будет HF? Даже если накосячить, то все, что может быть это потеря данных в очереди из-за переполнения.
Сообщение отредактировал Шаманъ - Jun 9 2017, 18:58
|
|
|
|
|
Jun 9 2017, 19:18
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 9 2017, 19:23)  А в фоне задачи нужно защищать обращение к ОБОИМ указателям в некой критической секции, иначе невозможно контроллировать подобные аварийные события. И в фоновом процессе это тоже не нужно. Так как измениться в этот момент может ТОЛЬКО ОДИН указатель. Подумайте ещё раз. Цитата(Forger @ Jun 9 2017, 19:23)  Если этого не делать, то буфер может быть переполнен/исчерпан так, что об этом невозможно будет узнать. Вы похоже просто не понимаете как работают подобные кольцевые буфера... Инфа для размышления: Кольцевые буфера, построенные подобным образом вполне можно использовать даже в тех случаях, когда критические секции в принципе невозможны, например - кольцевой буфер обмена между двумя ядрами/процессорами. Цитата(Forger @ Jun 9 2017, 19:48)  Не, это - уже бесполезный спор. Конечно бесполезный, если Вы не хотите понимать очевидных вещей. Шаманъ Вам дело говорит.
|
|
|
|
|
Jun 9 2017, 19:18
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 9 2017, 22:12)  И в фоновом процессе это тоже не нужно. Так как измениться в этот момент может ТОЛЬКО ОДИН указатель. Могут изменится оба, если в месте сравнения указателей и вычисления свободного/занятого места возникнет соотв. прерывание, которое изменит другой указатель. Если в этот момент мы начали сравнивать два указателя (или читать некий счетчик свободного/занятого места), то к моменту сравнения он будет неактуальным - ведь в прерывании выше он уже изменился. Если переполнение/исчерпание очереди не имеет значения для конкретного проекта, вообще не контролируется, то, конечно, можно забить на все эти критические участки кода.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 19:37
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 9 2017, 20:04)  Я делал это несколько иначе, использовал счетчик свободного места, вообще не сравнивая указатели. Это получается несколько быстрее, но отъедает немного места в памяти. Обращение к этому счетчику и изменение соотв. указателей, должно быть непрерывным. Иначе - HF Вот как раз со счётчиком - это плохая реализация, так как обязательно требует критической секции. Реализация кольцевого буфера на двух указателях (один - чтения, другой - записи) для своей работы не требует критических секций при условии, что есть только один процесс/ядро- писатель и только один процесс/ядро- читатель. И это справедливо только для этих процессов. Т.е. - не требуется ни для чего - ни для вычисления свободного места ни для вычисления уровня заполнения и т.п. Если состояние кольца читается 3-ей стороной (процессом/ядром отличным от читателя и писателя), то для этого критическая секция нужна. А в читателе и писателе - нет. Так как каждый из них модифицирует только один указатель, а второй указатель использует только на чтение. Цитата(Forger @ Jun 9 2017, 21:18)  Если в этот момент мы начали сравнивать два указателя (или читать некий счетчик свободного/занятого места), то к моменту сравнения он будет неактуальным - ведь в прерывании выше он уже изменился. Ну и что что станет неактуальным? Допустим пишущий процесс считал указатель чтения и, пока он его анализировал, произошло прерывание чтения, которое убавило данных из буфера. Ну и что? От этого работа кольца не разрушится. Просто пишущий процесс в этот момент будет думать что данных в кольце больше чем уже есть. Ну и что? Это не приведёт ни к каким сбоям. Вот если-б он думал что данных меньше чем там есть - вот это бы привело к разрушению работы. Но это невозможно по алгоритму.
|
|
|
|
|
Jun 9 2017, 19:39
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 9 2017, 22:31)  Вот как раз со счётчиком - это плохая реализация, так как обязательно требует критической секции. Счетчик нужен для анализа переполнения/исчерпания очереди. Если подобные события не представляют угрозы конкретному коду, то и счетчик не нужен. И критические секции не нужны. Я с этим не спорю. Я же говорю про код, где нужно контролировать такие события, нужно реагировать на такие вещи и предпринимать конкретные действия. Особенно, если устройство всегда включено и работает далеко от пользователя/обслуги. В этом случае контроль вынуждает защищать подобные куски кода. Самое простое - критическими секциями.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 20:27
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 9 2017, 21:39)  Самое простое - критическими секциями. Да... похоже Вы не понимаете.... Ниже привожу классическую реализацию кольцевого буфера. Данная реализация позволяет: вызывать функцию read() в читающем процессе/ядре; вызывать функцию write() в пишущем процессе/ядре; вызывать функции cnt() и free() в читающем и пишущем процессе/ядре. Никаких дополнительных критических секций или запрещений прерываний или LDREX/STREX или другого шаманства - не требуется. Данную реализацию кольцевого буфера можно использовать даже если читающий и пишущий процессы находятся в разных ядрах (процессорах). Теперь покажите пожалуйста нам всем и объясните - где и зачем по Вашему в приведённом ниже коде нужны критические секции??? CODE class Ring { int volatile rpos, wpos; u8 volatile buf[SIZE]; public: void init() { wpos = rpos = 0; } int read(); int write(int); int cnt() const; int free() const; };
//Чтение байта данных из buf. //return: <0 - buf пуст; >=0 - считанное значение. int Ring::read() { int i, j = rpos; if (j == wpos) return -1; i = buf[j]; if (--j < 0) j = sizeof(buf) - 1; rpos = j; return i; }
//Запись байта данных c в buf. //return: !=0-запись успешна; ==0 - запись неуспешна (buf полон). int Ring::write(int c) { int j = wpos; u8 volatile *p = &buf[j]; if (--j < 0) j = sizeof(buf) - 1; if (j == rpos) return 0; *p = c; wpos = j; return 1; }
//return: кол-во данных в buf. int Ring::cnt() const { int i = rpos; if ((i -= wpos) < 0) i += sizeof(buf); return i; }
//return: кол-во свободного места в buf. int Ring::free() const { int i = wpos; if ((i -= rpos) <= 0) i += sizeof(buf); return i - 1; } PS: Я много раз не случайно подчёркивал - процесса или ядра. Так как процесс, выполняющийся на одном ядре, не может загнать процесс другого ядра в критическую секцию. Тогда следуя Вашей логике - кольцевые буфера для межъядерного обмена невозможно использовать. А их используют!  PSS: Приведённый код можно использовать, модифицировать и распространять совершенно свободно. Разрешаю
|
|
|
|
|
Jun 9 2017, 20:44
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 9 2017, 22:37)  Допустим пишущий процесс считал указатель чтения и, пока он его анализировал, произошло прерывание чтения, которое убавило данных из буфера. Все будет хорошо, пока очередь не исчерпается - совпадут указатели головы и хвоста. Поясню. Скажем в очереди остался всего один элемент. Нужно туда положить еще один, он последний в отправляемом пакете. Кладем его в голову очереди, далее должны сдвинуть указатель головы, но не успели - произошло прерывание передатчика. В нем мы видим, что очередь непустая (сравнили два указателя), еще есть один элемент. Но всего один. Отправляем его, сдвигаем хвост. Видим, что хвост и голова совпали - прекращаем передачу и формируем соотв. сообщение. Возвращаемся из прерывания, сдвигаем голову вперед на один. Ждем сообщения об окончании всей передачи, в том числе и этого последнего байта. Успешно его дожидаемся, ведь передача была только что прекращена. В итоге последний элемент данных не был отправлен. В следующем пакете он будет отправлен, но он попадет в начало след. пакета. В пакетных протоколах эта ситуация недопустима - нарушается содержимое пакетов, если, конечно, имеют значения интервалы между пакетами и между элементами данных. Простой пример - пакетная передача по USART обычными байтами. Понимаю, ситуация редкая и очень трудноуловимая, но она вполне возможна. Именно для исключения таких ситуаций запись в очередь и сдвиг соотв. указателя должны быть атомарными. Если это реализуется атомарно на аппаратном уровне, то действительно никакие критические секции тут ни к чему.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 20:58
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 9 2017, 22:44)  Понимаю, ситуация редкая и очень трудноуловимая, но она вполне возможна. Это не редкая ситуация. Это вообще не имеет никакого отношения к работе кольцевого буфера. Кольцевой буфер - это только кольцевой буфер, а Вы описываете случай его использования для некоей задачи. Эта задача реализована неправильно. К работе кольца это отношения не имеет. Так можно предположить что и в процессе передачи вашего пакета, пишущий процесс не успеет дописать достаточно данных в буфер в любом месте, а не только в последнем байте. И в любом месте будет сбой. Это просто неправильная реализация процесса передачи, а не кольцевого буфера.
|
|
|
|
|
Jun 9 2017, 21:15
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 9 2017, 23:58)  К работе кольца это отношения не имеет. Да неужели? Речь тут как раз про возвожность разорвать атомарную операцию записи в буфер обработчиком, который к этому же очереди и обращается. Пусть заполнение буфера и передача обращаются к разным указателям, но как минимум факт исчерпания очереди требует чтения обоих указателей. Поэтому операция записи по указателю и его инкремента должна быть атомарной. Либо не использовать прерывания. Цитата Так можно предположить что и в процессе передачи вашего пакета, пишущий процесс не успеет дописать достаточно данных в буфер в любом месте, а не только в последнем байте. И в любом месте будет сбой. При чем тут не успеет дописать? В том примере все как раз и успевается и места в буфере полно. Передача производится одновременно с заполнением буфера новыми данными. Вполне обычная ситуация. Иначе хватило бы обычного массива, который заранее набивается данными, запускается передача и пока массив не будет весь передан, не будет новой передачи. Тогда тут действительно нафик не нужен кольцевой буфер. Цитата(jcxz @ Jun 10 2017, 00:10)  flush() в читающем процессе: Ring::flush() { rpos = wpos; } - однозначно очистка атомарна без всяких крит. секций Нет, неатомарна - обычная операция чтение-модификация-запись. Может быть прервана прям посреди. Или же прервать другое обращением к этим же полям в фоне задач. Ее нельзя вызывать в фоне задач, пока активно и разрешено соотв. прерывание. Цитата "Реальный код" не ограничивается только передачами по каналу связи. И далеко не везде нужен flush(). Даже скорей - редко где нужен. имха Он нужен лишь при аварийных ситуациях, в штатном коде он действительно не нужен. Я описал устройство, которое работает долго и без обслуги. Если повиснет и не сможет себя привести в норму самостоятельно, то беда будет (((
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 21:20
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Forger @ Jun 9 2017, 23:15)  Пусть заполнение буфера и передача обращаются к разным указателям, но как минимум факт исчерпания очереди требует чтения обоих указателей. Поэтому операция записи по указателю и его инкремента должна быть атомарной. Либо не использовать прерывания. Ещё раз: покажите в приведённом мной примере: прерывание в каком месте может разрушить его работу??? Ткните пальцем. Цитата(Forger @ Jun 9 2017, 23:15)  Нет, неатомарна - обычная операция чтение-модификация-запись. Может быть прервана прям посреди. Или же прервать другое обращением к этим же полям в фоне задач. И что? Работа кольца будет разрушена? Да хоть 100500 обращений. На работу кольца это никак не повлияет.
|
|
|
|
|
Jun 9 2017, 21:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 10 2017, 00:17)  Ещё раз: покажите в приведённом мной примере: прерывание в каком месте может разрушить его работу??? Вычитали один указатель (положили например в R1), произошло прерывание, изменило значение указателя. Вернулись, присвоили другому указателю старое значение, которое положили до этого в R1. Теперь два указателя не одинаковые, а код предполагает, что одинаковые. Как после этого поведет себя код никто не знает.
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Jun 9 2017, 21:27
|

Профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831

|
Цитата(jcxz @ Jun 10 2017, 00:20)  Да хоть 100500 обращений. На работу кольца это никак не повлияет. Я ж говорю, ни при чем тут кольцо как таковое, речь про ситуации исчерпания и переполнения буфера, которые обращаются к обоим указателям. А эти операции неатомарны. Пока читаем один указатель, прерывание (там изменяется один из указателей), выходим, и сравниваем с другим указателем старое неактуальное значение. Цитата(jcxz @ Jun 10 2017, 00:24)  тот пример, который Вы описали, вообще никак не говорит о правильности работы кольца. Это пример неправильного его использования. Очень убедительный довод. Оказывается, что кольцо еще и использовать нужно как-то по хитрому, чтобы оно правильно работало  Нафик тогда нужно такое кольцо, вокруг которого нужно плясать с бубном?
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|