[英]atomic linked-list LIFO in AArch64 assembly, using load or store between ldxr / stxr
我使用 ARMv8 64 位的程序集為共享的 memory 上下文實現了 LIFO。
LIFO 在開頭插入一個節點,每個節點結構的第一個屬性必須是下一個指針。
這是為 LIFO 實現原子插入和刪除的正確程序集嗎?
它使用LL/SC在 LDXR 和 STXR 之間進行額外的加載或存儲來讀取 head->next 或將指針存儲到新節點中。
typedef union {
void * head[1];
}lifo;
int atomic_lifo_init(lifo * h) {
if (h) {
h->head[0]=NULL;
}
}
inline void *
atomic_lifo_delete (lifo *h)
{
void *ret = NULL;
/*sa_ignore UNUSED_VAR*/
void * tmp = NULL;
asm volatile ("\n"
"2: ldxr %0,[%2] \n" //load the head from h, which points the 1st node of list to local ret pointer.
" cbz %0, 3f \n" //check if the lifo is empty.
" ldr %1,[%0] \n" //store in tmp the 2nd node by derefencing the ret (h->head points 1st node. value of each node is next node as 1st attribute of node structure is pointing next.)
" stxr %w1, %1,[%2] \n" //update h->head with tmp.
" cbnz %w1, 2b \n" //continue if failed
"3: \n"
: "=&r" (ret), "=&r" (tmp)
: "r" (h)
: "memory"
);
return(ret);
}
/*
* atomic_lifo_insert()
* Put an element on a list, protected against SMP
*/
void
atomic_lifo_insert (lifo *h, void *__new)
{
/*sa_ignore UNUSED_VAR*/
void * next = NULL;
void * flag = NULL;
asm volatile (" \n"
"1: ldxr %1,[%2] \n" //load head[0] from h,which points 1st node to local next pointer
" str %1,[%3] \n" //store the local next pointer to value of __new, as 1st attribute of the any node is next (convention used here). so __new's next is pointing current 1st node.
" stxr %w0, %3,[%2] \n" //update the h->head with
__next.
" cbnz %w0, 1b \n" //if stxr is failure try again.
: "=&r" (flag), "=&r" (next)
: "r" (h), "r" (__new)
: "memory"
);
}
我對 ARM 組件真的很陌生,所以非常感謝任何幫助。
您的內聯 asm 約束看起來正確,這應該按照您的預期方式編譯。 您可能可以使用"+m" (*h)
讓編譯器選擇尋址模式,而不是使用"r"(h)
和[%2]
對其進行硬編碼。
就排序而言, ldr
在 ldxr 之后是依賴排序的(如 C11 memory_order_consume
),因此有效。
但是在stxr
將地址發布到其他線程之后, insert
中的 LL/SC 之間的str
可能不會變得可見。 所以我認為你需要stlxr
(一個發布商店)在insert
。
在 LDXR/STXR 之間進行額外的加載或存儲是不安全的。 Wikipedia 的LL/SC 文章提到,如果您在 LL 和 SC 之間進行任何加載或存儲,某些實現可能會虛假失敗。 Wiki 說 PowerPC 確實允許這樣做。 但 AArch64 通常明確不:根據 ARM 參考手冊( 請參閱@James Greenhalgh 的評論):
只有在 [...] Load-Exclusive 和 Store-Exclusive 之間沒有明確的 memory 訪問時,LoadExcl/StoreExcl 循環才能保證向前推進。
可能有一些 AArch64 CPU 會在其中創建stxr
故障的無限循環,但可能還有其他 CPU 可以正常工作。 如果它在您測試的 CPU 上實際工作,那么查看是否有任何文檔支持它可能是個好主意。
如果new_
節點恰好與頭節點位於同一高速緩存行(或 LL/SC 獨占塊)中,則這很可能是一個問題。 如果這在您關心的微架構上完全有效,請確保您測試該案例,或者以某種方式使其成為不可能。
除此之外,我認為您的整體算法看起來是正確的,所以如果您已經對其進行了測試並發現它有效,那么這可能很好。
但是,我並沒有真正仔細考慮過您的算法。 我也沒有任何設計或使用原始 LL/SC 的經驗。 我原則上知道它們是如何工作的,但我不准備說這絕對是正確的。 從我所做的一點點思考來看,我沒有看到任何問題,但這並不意味着沒有任何問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.