7

このトピックは、このフォーラムや他のすべてのフォーラムで何度も議論されてきましたが、それでも私には疑問があります. 助けてください。

do{} while(0)in マクロは Linux カーネルでどのように機能しますか? 例えば、

#define preempt_disable()    do { } while (0)

どのようにプリエンプションを無効にしますか?

#define might_resched()    do { } while (0)

再スケジュールはどのように行われますか?

同様に、mutex ロックなどのマクロも見てきました。これはどのように役立ちますか? 次の問題については理解していますが、上記の例については理解していません。

#define foo(x)    do { do something } while(0)

編集:

の次のコードはrt_mutex_lockどうですか?

/**
 * rt_mutex_lock - lock a rt_mutex
 *
 * @lock: the rt_mutex to be locked
 */
void __sched rt_mutex_lock(struct rt_mutex *lock)
{
        might_sleep();
        rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
}
EXPORT_SYMBOL_GPL(rt_mutex_lock);


/*
 * debug aware fast / slowpath lock,trylock,unlock
 *
 * The atomic acquire/release ops are compiled away, when either the
 * architecture does not support cmpxchg or when debugging is enabled.
 */

static inline int rt_mutex_fastlock(struct rt_mutex *lock, 
    int state, int detect_deadlock, int (*slowfn)(struct rt_mutex *lock, 
    int state, struct hrtimer_sleeper *timeout, int detect_deadlock))
{
        if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
                rt_mutex_deadlock_account_lock(lock, current);
                return 0;
        } else{
                return slowfn(lock, state, NULL, detect_deadlock);
        }
}

rt_mutex_deadlock_account_lockカーネル内の 2 つの場所で定義されているため、混乱しています。

kernel/rtmutex-debug.c

void rt_mutex_deadlock_account_lock(struct rt_mutex *lock, 
    struct task_struct *task)
{
    //....
}

kernel/rtmutex.h

#define rt_mutex_deadlock_account_lock(m, t) do { } while (0)

i2c ドライバーの新しいカーネル 2.6.35.4 ではrt_mutex_lock(&adap->bus_lock);mutex_lock(). これはどのようにロックしますか?

4

3 に答える 3

12

私が与えるよりも良い説明については、このリンクを参照してください。

于 2010-09-22T06:38:13.393 に答える
5

@Kragen は、do...while コンストラクトの目的に答えました。基本的に、マクロをより安全に使用できるようにします。

ただし、「これはどのように機能するのですか?」という質問には答えていないと思います。

#define preempt_disable()    do { } while (0)

マクロは何もしないように定義されています。なぜ何もしたくないのですか?

  • 場合によっては、何かを行うためのプレースホルダーとしてマクロを使用したいことがあります。たとえば、「プリエンプト」が問題にならない 1 つのシステムでコードを記述したとしても、「プリエンプト」に特別な処理が必要なシステムにそのコードが移植される可能性があることがわかっているとします。したがって、2 番目のシステムが必要とするすべての場所でマクロを使用します (後で処理を有効にするのが簡単になるようにするため) が、最初のシステムではそのマクロを空のマクロとして定義します。

  • 場合によっては、さまざまな部分で構成されるタスクのようなことを実行したい場合があります (例: START_TABLE(); TABLE_ENTRY(1); TABLE_ENTRY(2); END_TABLE();)。これにより、テーブルのきれいで明確な実装が作成されます。しかし、実際には END_TABLE() マクロは必要ないことがわかります。クライアント コードを整理するには、マクロを定義したままにして、何もしないように定義します。そうすれば、すべてのテーブルに END_TABLE が含まれ、コードが読みやすくなります。

  • 同様のケースが 2 つの状態 (有効化/無効化) で発生する可能性があります。一方の状態では何かを実行するためにマクロが必要ですが、もう一方の状態はデフォルトで発生するだけなので、一方の実装は「空」です。物事が有効または無効になっている場所が明示的に示されているため、クライアントコードが理解しやすくなります。

于 2010-09-22T07:25:49.243 に答える
3

IIRC マクロでの do-while の使用は、それらを通常の関数呼び出しのように見せることです。unbraced if ステートメントやそのようなものには、いくつかの微妙な構文の問題があります。do-while がないと、マクロは通常の関数呼び出しのように見えますが、動作が異なります。

この場合、これらのマクロが使用されているため、特定の関数呼び出しは何もコンパイルされないと思います。設定されていない場合は、それが得られるように見えるCONFIG_PREEMPTため、プリエンプトにのみ必要なカーネルの特定の部分は、それがないと単純に消えてしまいます。したがって、これらのループは、プリエンプトを無効にしたり、何かを再スケジュールしたりしません。カーネル ソースの別の場所に別の定義 (おそらく実際の関数) があります。

于 2010-09-22T06:41:57.440 に答える