Linux駆動(同時):04---原子操作(atomic_t、atomic_set、set_bit)


一、原子操作の紹介

  • 原子操作は、1つの整数データの修正が排他的な
  • であることを保証することができる.
  • Linuxカーネルはカーネル内の原子操作を実現するための一連の関数を提供し、これらの関数はまた2種類に分けられ、それぞれビットと整数変数に対して原子操作
  • を行う.
  • ビットおよび整数変数の原子操作はいずれも最下位CPUの原子操作に依存するため、これらの関数はすべてCPUアーキテクチャと密接に関連する
  • である.
  • ARMプロセッサの場合、下位層は、atomic_のようなLDREXおよびSTREX命令を使用するinc()の最下位レベルのインプリメンテーションはatomic_に呼び出されますadd()は、
  • のコードです.
    static inline void atomic_add(int i, atomic_t *v)
    {
        unsigned long tmp;
        int result;
        prefetchw(&v->counter);
        __asm__ __volatile__("@ atomic_add
    " "1: ldrex %0, [%3]
    " " add %0, %0, %4
    " " strex %1, %0, [%3]
    " " teq %1, #0
    " " bne 1b" : "=&r" (result),"=&r" (tmp),"+Qo" (v->counter) : "r" (&v->counter),"Ir" (i) : "cc"); }

    二、整型原子操作


    原子変数の値の設定

    void atomic_set(atomic_t *v, int i); /*  i */
    atomic_t v = ATOMIC_INIT(0);         /*  v 0 */

    原子変数の値の取得

    atomic_read(atomic_t *v); /*  */

    原子変数の増減

    void atomic_add(int i, atomic_t *v); /*  i */
    void atomic_sub(int i, atomic_t *v); /*  i */

    原子変数の自己増加/自己減少

    void atomic_inc(atomic_t *v); /*  1 */
    void atomic_dec(atomic_t *v); /*  1 */

    操作とテスト

  • 下記の操作は、原子変数に対して自己増加、自己減少、および減算操作を行った後(加算していないことに注意)、0であるかどうかをテストし、0であればtrueを返し、そうでなければfalse
  • を返す.
    int atomic_inc_and_test(atomic_t *v);
    int atomic_dec_and_test(atomic_t *v);
    int atomic_sub_and_test(int i, atomic_t *v);

    操作して戻る

  • 次の操作は、原子変数に対して加算/減算および自己加算/自己減算を行い、新しい値
  • を返す.
    int atomic_add_return(int i, atomic_t *v);
    int atomic_sub_return(int i, atomic_t *v);
    int atomic_inc_return(atomic_t *v);
    int atomic_dec_return(atomic_t *v);

    三位原子操作


    セットビット

  • addrアドレスのnr番目のビットを設定、いわゆるビットを1
  • と書く.
    void set_bit(nr, void *addr);

    クリアビット

  • addrアドレスのnr番目のビットをクリア、クリアビットとは0
  • と書く.
    void clear_bit(nr, void *addr);

    へんいビット

  • addrアドレスのnr番目のビットを反転する
  • の操作を行う.
    void change_bit(nr, void *addr);

    テストビット

  • 下記の動作はaddrアドレスのnr番目のビット
  • に戻る.
    test_bit(nr, void *addr);

    ビットのテストと操作

  • 下記test_and_xxx_bit(nr,void*addr)操作はtest_の実行と同等bit(nr,void*addr)後にxxx_を実行bit(nr,void*addr)
  • int test_and_set_bit(nr, void *addr);
    int test_and_clear_bit(nr, void *addr);
    int test_and_change_bit(nr, void *addr);

    四、実例

  • は、デバイスが最大
  • のプロセスによってのみ開くことができるようにする原子変数の使用例を以下に示す.
    static atomic_t xxx_available = ATOMIC_INIT(1); /*  */
    
    static int xxx_open(struct inode *inode, struct file *filp)
    {
        ...
        if (!atomic_dec_and_test(&xxx_available)) {
            atomic_inc(&xxx_available);
            return - EBUSY; /*  */
        }
        ...
        return 0; /*   */
    }
    
    static int xxx_release(struct inode *inode, struct file *filp)
    {
        atomic_inc(&xxx_available); /*   */
        return 0;
    }