ARM 皮质:使用位带的互斥体

发布于 2024-09-01 14:50:07 字数 301 浏览 6 评论 0原文

鉴于此,在 ARM Cortex M3 上,我可以:

  • 原子地读取单个位
  • 原子地设置单个位
  • 原子地清除单个位

如何将这些组合起来以形成互斥体样式的操作集:

try lock
take lock
release lock

似乎 try_lock 或 take_lock 需要两个非原子操作。

我需要更多的控制来实现这一目标吗?禁用全局中断可以做到这一点,但似乎应该有一种更外科手术的方法。

Given that, on the ARM Cortex M3, I can:

  • atomically read a single bit
  • atomically set a single bit
  • atomically clear a single bit

How can I combine these for a mutex style set of operations:

try lock
take lock
release lock

It seems that try_lock or take_lock would require two operations that would not be atomic.

Do I need more control to accomplish this? Disable global interrupts would do it but it seems there should be a more surgical approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦醒时光 2024-09-08 14:50:07

如果调用时已持有锁,则 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 寄存器的简单更新)。您确定您的系统不能忍受额外的几个中断延迟周期来保持处理锁数据结构的代码简单(这通常意味着更容易正确)?

Your rwl_TryLock() doesn't necessarily return a failure if the lock is already held when it's called (your compiler should be giving at least a warning about a code path that has no return value). Try the following:

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;
}

Note that the above will not work for recursively claiming the same lock (ie., if the task specified by who == 1 already has the lock and tries to claim it again, the code above will not work correctly), but that was true of your original as well.

Also, interrupts can be disabled/enabled on the Cortex M3 pretty quickly (it's a simple update to an NVIC register). Are you sure your system can't live with an additional few cycles of interrupt latency to keep the code for handling the lock data structures simple (which generally means easier to make correct)?

掐死时间 2024-09-08 14:50:07

一些搜索后的信息:


ARM Cortex-M3 位带
ARM 的微控制器内核提供了另一种实现信号量的方法。对位带别名区域中的变量的写访问会导致对系统总线级别的位带区域中的内存位置进行原子读-修改-写访问。
这如何转化为信号量?位带区域中的变量可以用作信号量的容器。每个客户端都“拥有”该容器中的一点。每当客户端需要声明信号量时,它都会通过将 1 写入位带别名区域中的相应位置来设置自己的位。然后它会读取容器(位带区域)并检查是否设置了其他位,这意味着客户端已成功声明信号量。如果设置了其他位,客户端将必须再次清除自己的位,然后重试(可能在等待之后)。

来源

这是我的粗略(未经测试)解释:

/*
 * 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 :使用位带设置/清除位。 (原子)

但是,它不起作用!

Some for info after some searching:

"
ARM Cortex-M3 bit-banding
ARM's microcontroller core offers yet another way to implement semaphores. Write access to variables in the bit-band alias region causes an atomic read–modify–write access to a memory location in the bit-band region at system bus level.
How does that translate into semaphores? A variable in the bit-band region could serve as container for semaphores. Every client "owns" a bit in that container. Whenever a client needs to claim the semaphore, it sets its own bit by writing a 1 to the corresponding location in the bit-band alias region. It would then read the container (bit-band region) and check that no other bits are set, meaning the client has sucessfully claimed the semaphore. In case that other bits are set, the client would have to clear its own bit again, and retry (perhaps after waiting).
"
(source)

Here is my crude (untested) interpretation:

/*
 * 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: set / clear a bit using bit banding. (atomic)

However, it does not work!!!

瑾夏年华 2024-09-08 14:50:07

位带不适用于这种情况。这是在设备寄存器文件和内存中设置位的一种非常巧妙的方法。使用“加载独占”和“存储独占”指令来实现信号量/互斥体。您可以使用以下示例文档,该文档使用这些指令实现信号量,并详细说明了其工作原理。

http://infocenter.arm。 com/help/index.jsp?topic=/com.arm.doc.ddi0439b/CHDDIGAC.html

也就是说,您可以通过使用位带来减少互斥体的内存占用...

Bit banding won't work for this situation. It is just a really neat way of setting bits in device register files and your memory. Use the Load Exclusive and Store Exclusive instructions to implement your semaphore/mutex. Here's an example document you can use which implements a semaphore using these instructions and it details how this works.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/CHDDIGAC.html

That being said, you can reduce the memory footprint of your mutexes by using bit banding...

与君绝 2024-09-08 14:50:07

我从未在 ARM 上使用过位带;相反,我倾向于对所有此类操作使用加载独占/存储条件。使用循环加载独占旧值,计算新值,然后使用条件存储将其写回。循环直到条件存储成功(如果第一次没有成功,则可能是第二次)。

I've never used bit-banding on the ARM; my inclination instead would be to use load-exclusive/store-conditional for all such operations. Use a loop to load-exclusive the old value, compute the new value, and use a conditional store to write it back. Loop until the conditional store succeeds (which it probably will the second time, if it doesn't the first).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文