¿cómo funciona {} mientras (0) funciona en macro?

Aunque este tema ha sido discutido muchas veces en este foro y en todos los demás foros, todavía tengo dudas. Por favor ayuda.

¿Cómo funciona do{} while(0) en el trabajo de macro en el kernel de Linux? Por ejemplo,

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

¿Cómo deshabilita la prevención?

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

¿Cómo se reprogtwig?

Del mismo modo, he visto macros para lockings mutex y otros también. ¿Cómo ayuda esto? Entiendo por el siguiente problema pero no por los ejemplos anteriores.

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

Editar:

¿Qué pasa con el siguiente código para 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); } } 

Estoy confundido porque rt_mutex_deadlock_account_lock está definido en dos lugares en el kernel:

En kernel/rtmutex-debug.c :

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

En kernel/rtmutex.h :

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

En el nuevo núcleo 2.6.35.4 en el controlador rt_mutex_lock(&adap->bus_lock); ha reemplazado el mutex_lock() . ¿Cómo se bloquea esto?

@Kragen ha respondido qué hacer … mientras que la construcción es para – básicamente hace que una macro sea mucho más segura de usar.

Sin embargo, no creo que responda a la pregunta “¿cómo funciona esto?”:

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

La macro está definida para no hacer nada . ¿Por qué no quieres hacer nada?

  • En algunos casos, desea utilizar una macro como marcador de posición para hacer algo. Por ejemplo, puede escribir código en un sistema donde “adelantarse” no es un problema, pero usted sabe que el código puede ser portado a un sistema donde “preemprender” necesita algún manejo especial. De modo que utiliza un macro donde el segundo sistema lo necesita (para que el manejo sea fácil de realizar más adelante), pero para el primer sistema, entonces define esa macro como una macro en blanco.

  • En algunos casos, es posible que desee hacer cosas como una tarea que se compone de diferentes partes (por ejemplo, START_TABLE (), TABLE_ENTRY (1), TABLE_ENTRY (2); END_TABLE ();). Esto hace que la implementación de su tabla sea clara y limpia. Pero luego descubre que realmente no necesita la macro END_TABLE (). Para mantener ordenado el código del cliente, deja la macro definida y simplemente defínala para no hacer nada. De esta forma, todas sus tablas tienen un END_TABLE y el código es más fácil de leer.

  • Un caso similar puede ocurrir con dos estados (habilitar / deshabilitar) donde un estado necesita la macro para hacer algo, pero el otro estado simplemente ocurre de forma predeterminada, por lo que la implementación de uno es “vacía”; usted todavía usa la macro porque hace el código del cliente es más fácil de entender, ya que establece explícitamente los lugares donde las cosas están habilitadas o deshabilitadas.

Vea este enlace para una mejor explicación de la que podría dar.

IIRC el uso de do-while en macros es hacer que se parezcan más a una invocación de función normal; hay algunos problemas de syntax sutiles en las sentencias if no aseguradas y cosas por el estilo. Sin el do-while, la macro podría parecer una invocación de función normal, pero funcionaría de manera diferente.

Supongo que en este caso esas macros se utilizan para que ciertas llamadas a funciones se compilen en nada; parece que eso podría ser lo que obtienes si CONFIG_PREEMPT no estuviera configurado, por lo que ciertas partes del kernel que solo son necesarias para adelantarse simplemente desaparecen sin él. Entonces esos bucles no desactivan el reemplazo ni reprogtwign nada; habrá otra definición (probablemente una función real) en otro lugar de la fuente del kernel.