[Kos-dev] "Race condition" 1
d2
kos-dev@enix.org
28 May 2003 13:49:35 +0200
Hello,
>>>>> "Thomas" == Thomas Petazzoni <thomas.petazzoni@enix.org> writes:
Thomas> Dans le cas "normal", c'est le handler de l'IRQ timer qui
Thomas> appelle reschedule_after_interrupt, qui retourne le
Thomas> nouveau cpu_state au hanlder d'IRQ, qui se charge de
Thomas> restaurer le contexte. Et la, au moment du IRET,
Thomas> clairement les interruptions redeviennent actives, et on
Thomas> ne passe pas du tout par cpl0_switch_with_return.
Attention quand meme a pas trop suspecter le IE lors des chgts de
contexte. En effet, le scenario suivant est VALIDE :
- A tourne -> clac interruption
- IT Handler: sauvegarde de l'etat de A (IE du eflags forcement a 1 !!)
- IT Handler: election d'un nouveau thread B => A en fin de
cpu_waitqueue
- IT Handler: iret
- B tourne.
- B bloque sur 1 Semaphore
- kwaitqueue_add: sauvegarde de l'etat de B (IE forcement a 0)
- kwaitqueue_add: election du prochain, il se trouve que c'est A
- cpl0_switch_with_return: restauration de A (rappel: IE sauvegarde
== 1) => apres le iret, on est dans A, avec le IE passe a 1. Mais
A n'est pas au niveau du get_there, puisque qu'il a ete
interrompu forcement ailleurs que dans cpl0_switch_with_return (ou
les IRQ sont desactivees), donc son contexte est un contexte de
fonction qui ne correspond pas a la 2eme partie de
cpl0_switch_with_return => pas de test if (thread_to_be_destroyed...)
- on repart la ou A a ete interrompu (IE = 1 et c'est NORMAL)
Donc dans ce scenario valide, IE du nouveau thread passe a 1 et ca ne
doit pas etre considere comme un cas d'erreur.
Par contre, ce qui ne va pas c'est si on imagine le scenario suivant
(seule difference, cf '***') :
- A tourne -> clac interruption
- IT Handler: sauvegarde de l'etat de A (IE du eflags forcement a 1 !!)
- IT Handler: election d'un nouveau thread B => A en fin de
cpu_waitqueue
- IT Handler: iret
*** B se termine => thread_to_be_destroyed = B ***
- kwaitqueue_add: sauvegarde de l'etat de B (IE forcement a 0)
- kwaitqueue_add: election du prochain, il se trouve que c'est A
- cpl0_switch_with_return: restauration de A (rappel: IE sauvegarde
== 1) => apres le iret, on est dans A, avec le IE passe a 1. Mais
A n'est pas au niveau du get_there, puisque qu'il a ete
interrompu forcement ailleurs que dans cpl0_switch_with_return (ou
les IRQ sont desactivees), donc son contexte est un contexte de
fonction qui ne correspond pas a la 2eme partie de
cpl0_switch_with_return => pas de test if (thread_to_be_destroyed...)
- on repart la ou A a ete interrompu (IE = 1 et c'est NORMAL)
*** MAIS du coup on n'a pas teste thread_to_be_destroyed. ***
Si on continue juste 1 peu plus loin :
- A tourne
- A se termine => BOUM ASSERT_FATAL(thread_to_be_destroyed ==
NULL); EXPLOSE dans cpl0_switch_no_return puisque
thread_to_be_destroyed pointe ENCORE sur B.
CQFD ! Conclusion, il faut appeler delete_kernel_thread avant le iret
dans les handlers d'interruption => dans
reschedule_after_interrupt(). On le fait deja a chq chgt de contexte
"manuel" (cpl0_switch_with_return), donc y'a pas besoin d'en rajouter
d'autres en dehors de celui dans reschedule_after_interrupt()..
A toi de jouer.
--
d2