2012-08-10 79 views
12

私はARM用の組み込みOSで作業していましたが、ARMARMとLinuxソースを参照した後でも、アーキテクチャについて理解できなかったことがいくつかあります。ARMのアトミック操作

アトミック操作。

ARM ARMでは、ロード命令とストア命令はアトミックであり、実行は割り込みハンドラが実行される前に完了することが保証されています。しかし

arch/arm/include/asm/atomic.h : 
    #define atomic_read(v) (*(volatile int *)&(v)->counter) 
    #define atomic_set(v,i) (((v)->counter) = (i)) 

を見て、確認済み、問題は、私はのARMv7ためのLDREXとSTREX(私のターゲット)を使用するCPU命令(atomic_inc、atomic_dec、atomic_cmpxchgなど...)を使用して、アトミックこの値を操作したいときに来て。

ARMARMはこのセクションで割り込みがブロックされているとは言わないので、LDREXとSTREXの間で割り込みが発生することが想定されます。それが言及していることは、私が推測するメモリバスをロックすることですが、同時に同じ場所にアクセスしようとするCPUが増えるかもしれないMPシステムにのみ役立ちます。しかし、UP(とおそらくMP)の場合、LDREXとSTREXのこの小さなウィンドウでタイマ割り込み(またはIPI for SMP)が起動すると、ExceptionハンドラはCPUコンテキストを変更して新しいタスクに戻る可能性がありますが、 'CLREX'を実行して、前のスレッドが保持する排他ロックをすべて削除します。それで、UPシステムのアトミック性のために、LDREXとSTREXをLDRとSTRよりもうまく使う方が良いでしょうか?

排他ロックモニタについて何か読んだので、スレッドがSTREXを再開して実行すると、osモニタがこの呼び出しを検出してループを再開することができ、プロセスで新しい値を使用して実行されました(LDREXに戻って分岐します)、私はここにいますか?

答えて

9

さて、答えはwebsiteです。

プロセスがロード・エクスクルーシブを実行した後で、ストア・エクスクルーシブを実行する前にコンテキスト・スイッチがプロセスをスケジューリングすると、ストア・エクスクルーシブはプロセスが再開し、メモリが更新されないと偽の結果を返します。これは、処理がすぐに操作を再試行できるため、プログラムの機能には影響しません。

8

ロード・リンク/ストア排他的パラダイムの背後にある考え方は、もしあれば店が介在しないメモリ操作で、負荷後すぐに追従し、他に何も場所に触れていない場合は、ストアがであるということです可能であればが成功する可能性がありますが、何か他の場所にアクセスした場合は、が失敗します。明白な理由がなくても店舗が失敗することはないという保証はありません。ロードとストアの間の時間は、しかし、最小限に抑え、そして何のメモリがそれらの間にアクセスしないがある場合は、のようなループ:

do 
{ 
    new_value = __LDREXW(dest) + 1; 
} while (__STREXW(new_value, dest)); 

は、一般的に数の試行中に成功するために頼ることができます。新しい値が計算されている間、このコードは何かが変更された場合* DESTをそのメインループを再実行する必要があります

do 
{ 
    old_value = *dest; 

    new_value = complicated_function(old_value); 
} while (CompareAndStore(dest, new_value, old_value) != 0); 

... Assuming CompareAndStore is something like: 

uint32_t CompareAndStore(uint32_t *dest, uint32_t new_value, uint_32 old_value) 
{ 
    do 
    { 
    if (__LDREXW(dest) != old_value) return 1; // Failure 
    } while(__STREXW(new_value, dest); 
    return 0; 
} 

:古い値に基づいて新しい値を計算すると、いくつかの重要な計算を必要に応じて、1はループを書き換える必要がありますが、唯一の小さなループが

補遺 [のみ__LDREXWと__STREXWの間に約2つの命令があるだろうことを考えると、できればあまりそうではありません] __STREXWは、他のいくつかの理由で失敗した場合に再実行する必要があります「古いものに基づいて新しい価値を計算する」という複雑な状況の例は、「値」ar効果的に複雑なデータ構造への参照コードは古い参照をフェッチし、古いものから新しいデータ構造を派生させ、次にその参照を更新することができる。このパターンは、「ベアメタル」プログラミングよりもガベージコレクションフレームワークではるかに頻繁に現れますが、ベアメタルをプログラミングするときでさえさまざまな方法があります。通常のmalloc/callocアロケータは、一般的にはスレッドセーフ/割り込みセーフではありませんが、固定サイズ構造のアロケータはしばしばあります。頻繁にしようと何でも複数のスレッド/割り込み/存在しない場合

#define FOO_POOL_SIZE_SHIFT 8 
#define FOO_POOL_SIZE (1 << FOO_POOL_SIZE_SHIFT) 
#define FOO_POOL_SIZE_MASK (FOO_POOL_SIZE-1) 

void do_update(void) 
{ 
    // The foo_pool_alloc() method should return a slot number in the lower bits and 
    // some sort of counter value in the upper bits so that once some particular 
    // uint32_t value is returned, that same value will not be returned again unless 
    // there are at least (UINT_MAX)/(FOO_POOL_SIZE) intervening allocations (to avoid 
    // the possibility that while one task is performing its update, a second task 
    // changes the thing to a new one and releases the old one, and a third task gets 
    // given the newly-freed item and changes the thing to that, such that from the 
    // point of view of the first task, the thing never changed.) 

    uint32_t new_thing = foo_pool_alloc(); 
    uint32_t old_thing; 
    do 
    { 
    // Capture old reference 
    old_thing = foo_current_thing; 

    // Compute new thing based on old one 
    update_thing(&foo_pool[new_thing & FOO_POOL_SIZE_MASK], 
     &foo_pool[old_thing & FOO_POOL_SIZE_MASK); 
    } while(CompareAndSwap(&foo_current_thing, new_thing, old_thing) != 0); 
    foo_pool_free(old_thing); 
} 

:1のデータ構造の一部2のべき乗の数の「プール」を持っている場合は1のようなものを使用することができ、(255と言います)同時に同じことを更新すると、この方法では更新を安全に実行できるはずです。同じ項目を更新しようとする可能性のあるものの中に優先順位の関係が存在する場合、最も優先順位の高いものが最初の試行で成功することが保証され、次に優先順位の高いものが優先されます。ロックを使用していた場合、更新を実行したい最も優先度の高いタスクは、優先度の低い更新が終了するまで待つ必要があります。 CompareAndSwapパラダイムを使用すると、最も優先度の高いタスクは下位のタスクの影響を受けません(しかし、下位のタスクは無駄な作業をする必要があります)。

+0

私はまったく同じことをやってきましたが、重要なコンピューティングが新しい価値に必要な部分は、私をまだ困惑させます。コンテキストスイッチで排他的なモニターをクリアすることはできないが、重要なコンピューティングを再実行するには、明らかに理由がなく、通りが壊れているのを見ているので、cmxchgループを使用することは意味がある(PSRでマスクされたIRQ )あなたのポストに記載されています。 – sgupta

+0

@ user1075375:addendum – supercat

+0

これらの(__LDREXWおよび__STREXW)は、主流ARMターゲット(たとえばAArch64)およびコンパイラ(gcc、llvmなど)では一般的に使用できないCortex-Mシリーズマイクロコントローラレベルのプロセッサ用のKeilコンパイラでサポートされている組み込み関数です) 右? http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABDEEJC.html – ahcox

関連する問題