質問
このトピックは、このフォーラムと他のすべてのフォーラムで何度も議論されていますが、それでも疑問があります。助けてください。
どうしますか do{} while(0)
Linuxカーネルでのマクロ作業で?例えば、
#define preempt_disable() do { } while (0)
プリエンプトをどのように無効にしますか?
#define might_resched() do { } while (0)
どのようにスケジュールを変更しますか?
同様に、Mutex Locksなどのマクロも見ました。これはどのように役立ちますか?私は問題に従うことを理解していますが、上記の例については理解していません。
#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()
. 。これはどのようにロックされますか?
解決
@kragenは、何が何をするのかに答えました...コンストラクトが目的です - 基本的にはマクロをより安全に使用します。
しかし、「これはどのように機能しますか?」という質問に答えるとは思いません。
#define preempt_disable() do { } while (0)
マクロはに定義されています 何もしない. 。なぜあなたは何もしたくないのですか?
場合によっては、何かをするためにマクロをプレースホルダーとして使用したいと思うことがあります。たとえば、「先制」が問題ではない1つのシステムにコードを作成する場合がありますが、「先制」が特別な取り扱いに必要なシステムにコードが移植される可能性があることがわかります。したがって、2番目のシステムが必要な場所でマクロを使用します(ハンドリングを後で簡単に有効にするため)が、最初のシステムでは、そのマクロを空白のマクロとして定義します。
場合によっては、さまざまな部分で構成されるタスクのようなことをしたい場合があります(eg start_table(); table_entry(1); table_entry(2); end_table();)。これにより、テーブルのきれいな明確な実装ができます。しかし、その後、実際にはend_table()マクロは必要ないことがわかります。クライアントコードを整頓するために、マクロを定義したままにして、何もしないように定義します。そうすれば、すべてのテーブルにEND_TABLEがあり、コードの読み取りが簡単です。
同様のケースは、1つの状態が何かを行うためにマクロを必要とする2つの状態(有効化/無効)で発生する可能性がありますが、もう一方の状態はデフォルトで発生するため、1つの実装は「空」です。クライアントコードは、物事が有効化または無効になっている場所を明示的に述べているため、理解しやすいです。
他のヒント
見る このリンク 私が与えることができるよりも良い説明のために。
IIRCマクロでのdo-の使用は、それらを通常の関数の呼び出しのように見せることです。ステートメントやそのようなものがあれば、ブレースされていないものにいくつかの微妙な構文の問題があります。 Do-Do-がなければ、マクロは通常の関数の呼び出しのように見えるかもしれませんが、異なる動作をします。
この場合、これらのマクロが使用されているため、特定の関数呼び出しが何もままになると思います。それはあなたが得たものかもしれないように見えます CONFIG_PREEMPT
設定されていなかったので、先制が単にそれなしで消滅するためにのみ必要なカーネルの特定の部分。したがって、これらのループは、先制を無効にしたり、何も再スケジュールしたりしません。カーネルソースの他の場所に別の定義(おそらく実際の関数)があります。