2010-09-22 16 views
7

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 {} mientras (0) funciona en macro?

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

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

¿Cómo TI Desactivar preempt?

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

¿Cómo se reprograma?

De forma similar, he visto macros para bloqueos 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 es definir 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 nuevo kernel 2.6. 35.4 en el controlador i2c rt_mutex_lock(&adap->bus_lock); ha s reemplazado el mutex_lock(). ¿Cómo se bloquea esto?

+0

me parece que redefine esa función para no hacer nada. – mpen

+0

@Mark: suena convincente. ravspratapsingh: ¿Hemos acertado que para las dos afirmaciones superiores, realmente no hay nada entre las llaves? ¿O simplemente has simplificado el código de esta manera? – chiccodoro

+0

posible duplicado de [¿Cuál es el uso de do while (0) cuando definimos una macro?] (Http://stackoverflow.com/questions/923822/whats-the-use-of-do-while0-when-we- define-a-macro) – paxdiablo

Respuesta

5

@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 responde a la pregunta "¿cómo funciona esto?":

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

La macro se define a 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 manera predeterminada, por lo que la implementación de uno es "vacía"; usted todavía usa la macro porque hace que el código del cliente sea más fácil de entender, porque establece explícitamente los lugares donde las cosas están habilitadas o deshabilitadas.

+0

si 'do {} while (0)' no hace nada. ¿El compilador genera instrucciones de basura debido a eso o el bucle se optimizará? – Zingam

+1

Los compiladores tienen muy buenos optimizadores en estos días, por lo que es muy poco probable que encuentre uno que pierda el tiempo en un caso vacío evidente como este. –

11

Ver this link para una mejor explicación de la que yo podría dar.

+2

+1 Solo para que aparezca un nivel de direccionamiento indirecto, la primera cita responde a la pregunta: (de Dave Miller) Las declaraciones vacías dan una advertencia del compilador, así que es por eso que ves '#define FOO do {} while (0) '. –

3

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 sintaxis 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 están utilizando para que ciertas llamadas a funciones se compilen en nada; parece que eso podría ser lo que obtienes si no se configuró CONFIG_PREEMPT, 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 reprograman nada; habrá otra definición (probablemente una función real) en otro lugar de la fuente del kernel.

+0

Gracias, entendí cómo funciona esta acción preventiva, pero todavía estoy confundido sobre el bloqueo mutex. Por favor, consulte mi respuesta sobre rt_mutex_lock – iSegFault

+1

. Supongo que el bloqueo de exclusión mutua es algo similar: hay una implementación "real" y otra "falsa" que no hace nada. Es de suponer que, en algunos casos, el dummy one se usa si el kernel está configurado de forma tal que nunca lo necesite, ¿tal vez si CONFIG_SMP no está habilitado? – Peter

Cuestiones relacionadas