[Kos-dev] "Race condition" 1
d2
kos-dev@enix.org
28 May 2003 15:52:59 +0200
>>>>> "Thomas" == Thomas Petazzoni <thomas.petazzoni@enix.org> writes:
Thomas> Et pourquoi ma première solution qui consistait à
Thomas> supprimer le thread dans cpl0_switch_no_return_internal
Thomas> juste après le changement de pile n'est pas valide ?
Ok, je vois mieux ou tu en es. Tu t'es dit : "finalement il suffit de
supprimer le thread_to_be_destroyed juste apres avoir change de pile
dans cpl0_switch_no_return_internal". Car a priori ce code ne peut
etre appele qu'avec IE a 0 (puisque gros ASSERT). Donc a priori entre
le moment ou on positionne thread_to_be_destroyed a 'myself' dans
cpl0_switch_no_return et le moment ou on fait movl %eax,%esp puis call
delete_pending_thread dans cpl0_switch_no_return_internal il y aurait
forcement preemption (puisqu'on arrive forcement a
delete_pending_thread par ce chemin). Bon, effectivement, je vois.
En gros on a un code qui fait la chose suivante (je trace a partir de
cpl0_switch_no_return) :
- Verif interruptions disabled
- Verif thread_to_be_destroyed == NULL
- thread_to_be_destroyed <- myself;
- call cpl0_switch_no_return_internal(next_cpu_state)
- movl 0x4(%esp),%eax // recup next_cpu_state
- movl %eax,%esp
- call delete_pending_thread
- thread_to_destroy <- thread_to_be_destroyed
- thread_to_be_destroyed <- NULL
- suppr thread_to_destroy
- ret
- pop registres
- iret
Hypothese : en dehors de ce chemin, thread_to_be_destroyed == NULL.
3 possibilites "classiques" :
- Il existe un autre chemin que celui-ci qui mene a modifier
thread_to_be_destroyed
- Il y'a ecrasement de thread_to_be_destroyed par un autre thread
(probleme memoire) => afficher l'adresse thread_to_be_destroyed et
verifier que ca ressemble a un thread
- Il y'a preemption par un autre thread qui se termine sur ce
chemin.
je crois pas trop a la derniere explication. Pour la 1ere, faudrait
faire un gros grep et voir ou cette variable peut etre modifiee. Quant
a la 2eme, elle est plausible, mais faudrait des preuves. La seule
possibilite de preemption, ca serait au niveau de suppr
thread_to_destroy (y'a du gros code derriere qui fait peut-etre des
choses bizarres avec IE), mais j'ai des gros doutes vu que
thread_to_be_destroyed est positionne a false avant.
Autres explications moins "classiques" : probleme d'optimisation gcc
sur le chemin (?) => volatile dans le .h sur
thread_to_be_destroyed. Ou alors probleme de cache (j'y crois a
0.00001% ! surtout dans bochs). Ou alors problemes plus delicats,
genre on est a cheval sur 2 contextes (registres de l'ancien thread a
supprimer, pile du nouveau thread a elire, current_thread == nouveau
thread), qui font que gcc fait n'importe quoi (mais la je maitrise
pas). 1 solution si on s'approche de cette explication : cf fin de
mail.
Tu peux rajouter un test IE == 0 (IE du eflags du thread en cours, ie
de celui qui se termine ; pas le eflags du thread destination) dans le
delete_pending_thread() ? Et meme avant, carrement juste avant et
juste apres le movl %eax,%esp ?
Sinon, si tu fais comme ca (ie call delete_pending_thread dans
cpl0_switch_no_return_internal apres chgt de pile), tu peux enlever
tout appel de delete_pending_thread a la fois dans
cpl0_switch_with_return() et dans execute_thread(), puisqu'ils ne
servent plus a rien vu que c'est cpl0_switch_no_return_internal qui se
charge de tout depuis la pile du thread destination. Tu peux a ce
moment-la aussi enlever le IE a 0 lors de la creation de nouveaux
threads.
Si ca marche pas : eviter d'etre bancal ancien/nouveau thread (cf
supra) : essaye de rajouter les call delete_pending_thread depuis le
reschedule_after_interrupt, et dans le execute_thread en mettant le IE
du nouveau thread a 0 pour le coup.
A lundi !
--
d2