我正在使用Xilinx佐德板进行一个嵌入式系统项目。该董事会有能力不对称地分裂,它的双核ARM A9处理器,以运行两个独立的程序同时。我已经将板配置为在一个核心上运行Linux,在另一个核心上配置一个裸金属应用程序作为硬件控制器。对于处理器间的通信,我使用的是在两个处理器之间共享的片上存储器。我正在为我的锁实现而挣扎,我很好奇是否有人会经历这样的事情,或者可能会为我指明正确的方向。
我在ARM参考网站http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html上找到了一个互斥实现,并且我已经将它调整为C内联程序集。经过测试,锁功能似乎挂起了,我不知道为什么。我在组装方面的经验是有限的,我在学校见过它,并且理解了高层次的概念,但是我完全迷失在低层次的实现中。
这看起来是对的还是这甚至是正确的方法?我所需要的只是一个简单的机制,它允许我对进程间通信结构(几个消息队列)执行原子操作。
mutex.h
#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);
#endifmutex.c
#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));
}发布于 2013-11-21 08:32:02
为什么不使用GNU程序集呢?应该是这样的
.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然后它的转储看起来像这样
$ 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操作。
发布于 2015-04-10 13:56:52
至于为什么您的代码挂起,这可能是因为WFE指令。如果没有任何事情发生,它就什么也做不了。永远不变。检查是否已启用并生成事件。
(此外,请参阅ARM体系结构参考手册中对STREX和LDREX的使用限制,这应该在A2.9.4节“使用限制”中)
有一个关于如何实现自旋锁的示例:Semaphores/
将他们的例子应用于您的代码会导致如下情况:
__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));这将在繁忙等待中实现互斥。
如果您希望代码告诉您是否在没有繁忙等待的情况下获得了互斥体,只需修改结束:
__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号手续:
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中构造外部“繁忙等待”循环是完全合理的,或者,如果您希望有一个基于中断的方案,则从那里暂停操作。
经验法则:
https://stackoverflow.com/questions/20111906
复制相似问题