Учитывая, что на Коре ARM M3 я могу:
Как может я комбинировать их для взаимоисключающего набора стиля операций:
try lock
take lock
release lock
Это кажется этим try_lock
или take_lock
потребовал бы двух операций, которые не будут атомарными.
Мне нужно больше управления для выполнения этого? Отключите глобальные прерывания, сделал бы это, но кажется, что должен быть более хирургический подход.
Ваш rwl_TryLock()
не обязательно возвращает ошибку, если блокировка уже удерживается в момент вызова (ваш компилятор должен выдавать хотя бы предупреждение о пути кода, который не имеет возвращаемого значения). Попробуйте сделать следующее:
int rwl_TryLock(volatile uint32_t *lock, int who){
Var_SetBit_BB((uint32_t)lock, who);
if(*lock == (1<<who)){ // check that we have exclusive access
// got the lock!
return 1;
}
// do not have the lock
Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
return 0;
}
Обратите внимание, что приведенный выше код не будет работать при рекурсивном обращении к одной и той же блокировке (т.е. если задача, указанная who == 1
, уже имеет блокировку и пытается обратиться к ней снова, приведенный выше код не будет работать корректно), но это было верно и для вашего исходного варианта.
Кроме того, прерывания могут быть отключены/включены на Cortex M3 довольно быстро (это простое обновление регистра NVIC). Вы уверены, что ваша система не может жить с дополнительными несколькими циклами задержки прерывания, чтобы сохранить код для обработки структур данных блокировки простым (что обычно означает, что его легче исправить)?
.Немного информации после некоторого поиска:
" ARM Cortex-M3 битовый биндинг Ядро микроконтроллера ARM предлагает еще один способ реализации семафоров. Доступ на запись к переменным в области псевдонимов битовой полосы вызывает атомарный доступ на чтение-модификацию-запись к ячейке памяти в области битовой полосы на уровне системной шины. Как это переводится в семафоры? Переменная в области битовой полосы может служить контейнером для семафоров. Каждый клиент "владеет" битом в этом контейнере. Всякий раз, когда клиенту нужно затребовать семафор, он устанавливает свой бит, записывая 1 в соответствующее место в области псевдонимов битовой полосы. Затем он считывает контейнер (область битовой полосы) и проверяет, что никакие другие биты не установлены, что означает, что клиент успешно затребовал семафор. В случае, если другие биты установлены, клиент должен снова очистить свой бит и повторить попытку (возможно, после ожидания). " (source)
Вот моя грубая (непроверенная) интерпретация:
/*
* Frees a lock.
*
* @note lock must point to a fully aligned 32 bit integer.
* (atomically set to 0)
*
* @returns 1 if successfull
*/
int rwl_FreeLock(volatile uint32_t *lock){
*lock = 0;
return 1; // always successful
}
/*
* Attempts to acquire a lock
* @param who is the client taking the lock
* @lock pointer to the mutex (uint32_t value in memory)
* @note lock must point to a fully aligned 32 bit integer.
* (atomically set to 1 only if set to 0)
*/
int rwl_TryLock(volatile uint32_t *lock, int who){
// initial check of lock
if(*lock == 0){
Var_SetBit_BB((uint32_t)lock, who);
if(*lock == (1<<who)){ // check that we still have exclusive access
// got the lock!
return 1;
} else {
// do not have the lock
Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
return 0;
}
}
}
Var_Set_BB / Var_Reset_BB: установка / очистка бита с использованием битового биндинга. (atomic)
Однако, это не работает!!!