2017-10-06 6 views
1

J'écris un pilote de noyau où j'ai besoin de vérifier quel thread est en cours d'exécution à un certain point sur un autre c? Ur. Mon pilote exécute un thread noyau par noyau et j'ai besoin de synchroniser de temps en temps certains threads pour effectuer certaines tâches. Ce que je peux observer à partir des journaux de débogage est que parfois un thread attend trop d'autres threads. J'ai fait un patch où je stocke le __preempt_count sur d'autres cœurs pour vérifier si n'importe quel softirq/hardirq ou préemption désactivé retarde mon fil. J'ai également utilisé la fonction FTRACE pour vérifier les options irqsoff et preemptirqsoff pour la durée maximale des interruptions IRQ et la préemption désactivée. Jusqu'à présent, j'étais capable de repérer les threads kerneloops qui désactivent les interruptions jusqu'à 20msec, ce que je trouve trop long. A fait un systemctl disable kerneloops et s'est débarrassé de ce problème.Accéder au pointeur "current_task" d'une autre unité centrale dans un système Linux basé sur SMP

Maintenant, je semble traiter de certaines fenêtres désactivées de préemption. Pour l'analyse future de ce pilote, j'ai besoin d'un moyen de déterminer quels threads sont en cours d'exécution à un moment donné sur d'autres cœurs. J'essaye d'employer FTRACE principalement avec des événements pour l'entrée/sortie d'IRQ, j'utilise également trace_printk pour pousser quelque log de débogage dans le tampon de ftrace pour avoir tout dans un journal, etc.

Cependant, une chose que je voudrais comme à faire est d'accéder à la structure current_task des autres cœurs (le current ptr) et d'imprimer le champ comm qui donne le nom de la tâche (ou la valeur pid). Mais j'ai du mal à faire ça.

Pour __preempt_count Je n'avais pas question:

int *p = per_cpu_ptr(&__preempt_count,cpu); 
pr_info("Preempt count of cpu%u is 0x%08x\n",cpu,*p); 

Jusqu'à présent, j'eu aucun problème avec la déclaration ou l'accès par des variables cpu, mais pour une raison quelconque, le pointeur current_task déclenche une erreur de page lorsque vous essayez d'y accéder.

char buf[10]; 
struct task_struct *task = per_cpu_ptr(current_task,cpu); 
snprintf(buf,8,"%s",task->comm); 
pr_info("Task name: %s",buf); 

Le code ci-dessus déclenche toujours une erreur de page, NULL ptr bla bla. Je ne pouvais pas trouver la raison jusqu'à maintenant. J'ai essayé d'imprimer la valeur du pointeur pour task, j'ai eu la même erreur de page. Est-ce parce que l'adresse n'est pas accessible par d'autres cœurs? Dans l'espace du noyau ne devrait pas être le cas afaik. Je n'avais pas non plus de problème avec les variables de base et j'ai beaucoup joué avec ça.

Conclusion: quelle serait la bonne approche pour accéder aux current_task des autres cœurs et imprimer les champs comm/pid?

Merci beaucoup,

Daniel

Répondre

0

j'ai finalement compris ce qui était faux. La différence entre __preempt_count et current_task est que le premier est défini comme une variable int, tandis que le second est un pointeur vers la structure. En d'autres termes, le premier est défini comme une variable et le second comme un pointeur. Maintenant, en regardant plus en profondeur dans les variables par CPU, ce ne sont que des variables allouées par le compilateur dans des emplacements de mémoire séparés, comme un tableau. Lorsque per_cpu_ptr pour une variable Foo est appelée, la macro calcule quelque chose comme Foo[cpu], mais cela signifie que le per_cpu_ptr a besoin de l'adresse de base réelle de la variable, ce qui signifie le & afin qu'il puisse calculer la valeur de l'adresse relative à partir de cela.

En déclarant: foo = per_cpu_ptr(&__preempt_count,cpu), cette adresse est déjà donnée = &__preempt_count

En déclarant: bar = per_cpu_ptr(current_task,cpu), cette adresse n'est pas donné, comme & manque ici. Current_task est un pointeur mais pas l'adresse de base du tableau current_task.

Dans les deux cas ci-dessus l'argument à per_cpu_ptr est un pointeur, mais ici ma compréhension était erronée, je ne savais pas quel est réellement le pointeur de la variable que je dois passer, maintenant c'est clair: je dois passer l'adresse de base de la variable (var ou pointeur n'a pas d'importance) afin que la macro puisse calculer l'adresse relative de cette unité centrale.

Par conséquent, le droit des approches qui sont le travail:

bar = per_cpu(current_task,cpu) qui se traduit par *per_cpu_var(&current_task,cpu)

ou directement

bar = *per_cpu_var(&current_task,cpu);