首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >臂装配线C互斥增粗

臂装配线C互斥增粗
EN

Stack Overflow用户
提问于 2013-11-21 03:31:16
回答 2查看 5K关注 0票数 3

我正在使用Xilinx佐德板进行一个嵌入式系统项目。该董事会有能力不对称地分裂,它的双核ARM A9处理器,以运行两个独立的程序同时。我已经将板配置为在一个核心上运行Linux,在另一个核心上配置一个裸金属应用程序作为硬件控制器。对于处理器间的通信,我使用的是在两个处理器之间共享的片上存储器。我正在为我的锁实现而挣扎,我很好奇是否有人会经历这样的事情,或者可能会为我指明正确的方向。

我在ARM参考网站http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html上找到了一个互斥实现,并且我已经将它调整为C内联程序集。经过测试,锁功能似乎挂起了,我不知道为什么。我在组装方面的经验是有限的,我在学校见过它,并且理解了高层次的概念,但是我完全迷失在低层次的实现中。

这看起来是对的还是这甚至是正确的方法?我所需要的只是一个简单的机制,它允许我对进程间通信结构(几个消息队列)执行原子操作。

mutex.h

代码语言:javascript
运行
复制
#ifndef __OCM_MUTEX_H__
#define __OCM_MUTEX_H__

#include <stdint.h>

#define LOCKED      1
#define UNLOCKED    0

typedef uint32_t mutex_t;

extern void ocm_lock_mutex(volatile mutex_t* mutex);
extern void ocm_unlock_mutex(volatile mutex_t* mutex);

#endif

mutex.c

代码语言:javascript
运行
复制
#include "mutex.h"

void ocm_lock_mutex(volatile mutex_t* mutex) {
    int result;
    const uint32_t locked = LOCKED;

    __asm__ __volatile__("@ocm_lock_mutex\n"
"1: LDREX   %[r2], [%[r0]]\n"
"   CMP     %[r2], %[locked]\n"
"   BEQ     2f\n"
"   STREXNE %[r2], %[locked], [%[r0]]\n"
"   CMP     %[r2], #1\n"
"   BEQ     1b\n"
"   DMB\n"
"   B       3f\n"
"2: WFE\n"
"   B       1b\n"
"3: NOP\n"
    : [r2] "=r" (result), [r0] "=r" (mutex)
    : [locked] "r" (locked));
}

void ocm_unlock_mutex(volatile mutex_t* mutex) {
    const uint32_t unlocked = UNLOCKED;

    __asm__ __volatile__("@ocm_unlock_mutex\n"
"   DMB\n"
"   STR %[unlocked], [%[r0]]\n"
"   DSB\n"
"   SEV\n"
    : [r0] "=r" (mutex)
    : [unlocked] "r" (unlocked));
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-21 08:32:02

为什么不使用GNU程序集呢?应该是这样的

代码语言:javascript
运行
复制
.equ locked,1
.equ unlocked,0

@ lock_mutex
@ Declare for use from C as extern void lock_mutex(void * mutex);
    .global lock_mutex
lock_mutex:
    LDR     r1, =locked
1:  LDREX   r2, [r0]
    CMP     r2, r1        @ Test if mutex is locked or unlocked
    BEQ     2f            @ If locked - wait for it to be released, from 2
    STREXNE r2, r1, [r0]  @ Not locked, attempt to lock it
    CMPNE   r2, #1        @ Check if Store-Exclusive failed
    BEQ     1b            @ Failed - retry from 1
    # Lock acquired
    DMB                   @ Required before accessing protected resource
    BX      lr

2:  @ Take appropriate action while waiting for mutex to become unlocked
    @ WAIT_FOR_UPDATE
    B       1b            @ Retry from 1


@ unlock_mutex
@ Declare for use from C as extern void unlock_mutex(void * mutex);
    .global unlock_mutex
unlock_mutex:
    LDR     r1, =unlocked
    DMB                   @ Required before releasing protected resource
    STR     r1, [r0]      @ Unlock mutex
    @ SIGNAL_UPDATE   
    BX      lr

然后它的转储看起来像这样

代码语言:javascript
运行
复制
$ arm-linux-gnueabihf-objdump -d mutex.o

mutex.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <lock_mutex>:
   0:   e3a01001    mov r1, #1
   4:   e1902f9f    ldrex   r2, [r0]
   8:   e1520001    cmp r2, r1
   c:   0a000004    beq 24 <lock_mutex+0x24>
  10:   11802f91    strexne r2, r1, [r0]
  14:   13520001    cmpne   r2, #1
  18:   0afffff9    beq 4 <lock_mutex+0x4>
  1c:   f57ff05f    dmb sy
  20:   e12fff1e    bx  lr
  24:   eafffff6    b   4 <lock_mutex+0x4>

00000028 <unlock_mutex>:
  28:   e3a01000    mov r1, #0
  2c:   f57ff05f    dmb sy
  30:   e5801000    str r1, [r0]
  34:   e12fff1e    bx  lr

然而,我想知道的是,您是否成功地将这两个核心配置为包含在核心一致性中。据我所知,您可以指定哪些核心参与ldrex/strex操作。

票数 2
EN

Stack Overflow用户

发布于 2015-04-10 13:56:52

至于为什么您的代码挂起,这可能是因为WFE指令。如果没有任何事情发生,它就什么也做不了。永远不变。检查是否已启用并生成事件。

(此外,请参阅ARM体系结构参考手册中对STREX和LDREX的使用限制,这应该在A2.9.4节“使用限制”中)

有一个关于如何实现自旋锁的示例:Semaphores/

将他们的例子应用于您的代码会导致如下情况:

代码语言:javascript
运行
复制
__asm__ __volatile__("@ocm_lock_mutex\n"
"   LDREX   %[r2], [%[r0]]\n"
"   CMP     %[r2], %[locked]\n"
"   STREXNE %[r2], %[locked], [%[r0]]\n"
"   CMPNE   %[r2], #1\n"
"   BEQ     ocm_lock_mutex\n"
    : [r2] "=r" (result), [r0] "=r" (mutex)
    : [locked] "r" (locked));

这将在繁忙等待中实现互斥。

如果您希望代码告诉您是否在没有繁忙等待的情况下获得了互斥体,只需修改结束:

代码语言:javascript
运行
复制
__asm__ __volatile__("@ocm_lock_mutex\n"
[...]
"   CMPNE   %[r2], #1\n"
"   BEQ     ocm_lock_mutex_end\n"
"   MOV    %[r2], #2\n"
"@ocm_lock_mutex_end\n"
"   NOP\n"
    : [r2] "=r" (result), [r0] "=r" (mutex)
    : [locked] "r" (locked));

只需办理C号手续:

代码语言:javascript
运行
复制
if (result==0) {/*You didn't get the mutex, it was locked*/}
else if (result==1) {/*You didn't get the mutex, access not exclusive*/}
else if (result==2) {/*You got the mutex!*/}

(如ARM体系结构参考手册2005版A2.9.4“装载和存储操作”所示)

在C中构造外部“繁忙等待”循环是完全合理的,或者,如果您希望有一个基于中断的方案,则从那里暂停操作。

经验法则:

  • 保持您的内联汇编代码尽可能小,并无循环.
  • 使您的内联程序集一次只做一件事。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20111906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档