2012-06-13 3 views
2

J'ai un pilote qui veut envoyer une notification à l'utilisateur à propos d'un changement de statut. Dans l'implémentation actuelle, il utilise le système de fichiers proc pour ce faire. Le processus de lecture tourne autour d'un read() vers le système de fichiers proc. Le read() bloque avec wait_event_interruptible() jusqu'à ce que le noyau reçoive une interruption qui amène la fonction write_new_data() à call wake_up_interruptible(). Voici le code de base (supprimé tout encombrement inutile):condition de course entre wait_event et wake_up

static int flag=0; 
DECLARE_WAIT_QUEUE_HEAD(info_wq); 

//user process call read() on /proc/myfile to get to this function 
int my_proc_read (struct file *filp, char *buf, size_t count, loff_t *pos) 
{ 
    wait_event_interruptible(info_wq, flag != 0); 
    flag = 0; 

    //copy buffers to user 
    return 0; 
} 


//when an interrupt comes it schedules this function on the systems' work queue 
void write_new_data() 
{ 
    //fill buffer with data 
    flag = 1; 
    wake_up_interruptible(&info_wq); 
} 

Considérons maintenant le flux suivant:

  1. processus utilisateur appelle read(), puis attend. L'interruption se produit ->write_new_data() est appelée. écrit des données et appelle wake_up_interruptible().
  2. read()read() est réveillé, lit les données mais le processus n'a pas réexécuté la lecture (n'était pas planifié pour exécuter, n'a pas obtenu à cause de l'interruption suivante ...).
  3. interruption se produit ->write_new_data() est déclenchée à nouveau, appelle wake_up_interruptible() mais pas de fil d'attente est en attente ...
  4. appels processus de lecture et les blocs.

Remarque: tout cela se produit sur un système monoprocesseur. En outre, il n'y a qu'un seul thread de lecture et un thread écrit de nouvelles données.

Comment puis-je éviter de manquer la seconde interruption? (Une solution consiste à utiliser les sockets netlink, mais je me demandais s'il y a un moyen de le faire dans la terre/proc)

+0

quel type de pilote est-ce? et quel est le statut? –

Répondre

1

Depuis l'interruption peut se produire entre l'appel à wait_event_interruptible et flag = 0, il affecte la variable flag dans un manière non désirée. Notez que même sur une machine UP, le noyau pourrait être préemptif en fonction de la configuration, et ce code serait affecté en conséquence.

De plus, je conseille de ne pas utiliser un simple drapeau 'int'. Au lieu de cela, vous devez utiliser les opérations atomic_t et atomic_dec/inc_*. Voir la mise en œuvre des complétions dans le noyau, il fait quelque chose de similaire à ce que vous faites ici.

A propos de la question elle-même:

Si vous regardez dans le code de wait_event_interruptible vous verrez que le sommeil ne se produit pas si la condition est vrai - si votre problème est un non-problème.

+0

Eh bien, pour plus de simplicité, j'ai retiré la partie code avec des verrous de spin qui contrôlent le changement du drapeau. Merci pour les conseils sur atomic_dec/inc et acheions - je vais en lire plus à propos de ceux-ci. Encore ma question de base reste sans réponse ... –

+0

Il y a quelque chose qui ne va pas avec le flux que vous présentez.Après la deuxième interruption, flag == 1, et l'appel suivant à 'read', même s'il a été retardé par l'interruption, ne peut pas sembler bloquer car' wait_Event_interruptible' va quitter immédiatement à cause de la condition fournie. –

+0

Ici, nous ne sommes pas d'accord. Ma compréhension est que si le sillage est appelé aucun thread est dans la file d'attente (pas appelé wait_event) alors le fait que la condition est vraie n'aidera pas et le processus dormira jusqu'à ce que quelqu'un appelle à nouveau wake_up (et seulement alors condition être vérifié pour vrai) –

3

Dan, voici le code de wait_event_interruptible:

#define wait_event_interruptible(wq, condition)    \ 
({         \ 
    int __ret = 0;       \ 
    if (!(condition))      \ 
     __wait_event_interruptible(wq, condition, __ret); \ 
    __ret;        \ 
}) 

Si une interruption se produit juste entre "if ((condition)!)" Et "__wait_event_interruptible", le sommeil aura lieu et le processus de lecture sera être bloqué jusqu'à ce qu'une autre interruption se produise.

+0

non, regardez __wait_event_interrupts() - il fait 'if (condition) break' avant de dormir. –

+0

typo; Je voulais dire regarder __wait_event_interruptible(). Il vérifie à nouveau la condition. Pour élucider encore plus loin - même si l'interruption s'est produite après la deuxième vérification, l'appel à schedule() retournera immédiatement à cause de l'appel à wake_up dans l'interruption. La raison pour laquelle __wait_event_interruptible appelle prepare_to_wait() * avant de vérifier à nouveau la condition est d'empêcher les courses lors de la mise à jour de la condition. Ainsi, les API sont valides, mais la gestion de 'flag' dans la question est toujours un bug. –

+0

ok, merci Dan. – Adrien

Questions connexes