« Publicité Windows 7Pauvre Edison... »

RPL/2 internal error

20.06.10 | par Le Grincheux | Catégories: Mauvaise humeur, Je hais l'informatique

Je hais la programmation multithreadée à un point qui devrait vous donner une très vague idée de l'infini. Si j'écoutais ma mauvaise conscience, étant d'une fainéantise crasse, je ne passerais pas ma vie à corriger des erreurs dans des bouts de programmes, qu'il s'agisse de simple fuite de mémoire ou comme on dit joliment de « race conditions », beaucoup plus pénibles à corriger car non reproductibles.

Le problème majeur de l'informatique moderne est la qualité du code qui tend asymtotiquement vers zéro et ce d'autant plus vite que la puissance des machines s'accroît. Je ne sais pas si vous voyez bien ce que je veux dire. À l'heure où il faut une machine tournant à l'aide de deux processeurs cadencés à quelques milliers de mégahertz et munie de quelques gigaoctets de mémoire vive pour afficher en deux ou trois secondes un bête 'Hello, World!' écrit en Java, il n'existe plus personne pour se préoccuper de l'utilisation optimale des ressources. Enfin, si, il reste des types comme moi qui n'ont pas vraiment le choix.

Mon problème est aujourd'hui le calcul intensif. Il faut absolument utiliser le maximum des possibilité d'un ordinateur pour réduire les temps de calcul. J'ai dû essayer une grande partie des outils disponibles sans trouver mon bonheur. Il faut dire que le plus petit calculateur à ma disposition est un système à trente-deux processeurs UltraSPARC et que l'immense majorité des outils ne s'adapte que très mal à une telle configuration. Sachant qu'on n'est jamais aussi bien servi que par soi-même, j'ai décidé de me prendre par la main et de coder mon propre langage de programmation. Il y a au moins deux avantages à cela, il suivra au mieux mes besoins et si je suis embêté par un problème dans ce langage, je ne pourrai m'en prendre qu'à moi-même plutôt que d'attendre le bon vouloir du concepteur pour apporter une correction. Toute médaille ayant son revers, je ne peux plus accuser un tiers des défauts de mes programmes et par moment, c'est vraiment difficile…

Depuis quelques années, je passe ainsi le plus clair de mon temps à rajouter des fonctions et corriger des dysfonctionnements majeurs provenant essentiellement des possibilités de programmation multitâche et multithread. En effet, chaque système d'exploitation comprend les spécifications POSIX de manière subtilement différente et parfaitement incompatible quand il n'en manque pas des bouts. Certains autre systèmes comme Windows sont même très reposants parce qu'ils ne comprennent rien.

Le dernier dysfonctionnement en date provient d'un calculateur fonctionnant sous Linux. Une machine vraiment spéciale puisqu'il s'agit d'un bête PC muni de deux processeurs amd64. Au bout de quelques heures d'un calcul d'optimisation, le processus s'arrêtait avec le message d'insulte suivant :

[1610] BUG! <librpl_liberation()> at line #767 of gestion_objets.conv.c
(*s_objet).nombre_occurrences=0
[1610-140395925845840] BACKTRACE <librpl_liberation()> at line #767
/usr/local/bin/rpl(librpl_liberation+0x36c) [0x48390c]
/usr/local/bin/rpl(librpl_liberation+0x1423) [0x4849c3]
/usr/local/bin/rpl(librpl_instruction_save+0x1f8) [0x533958]
/usr/local/bin/rpl(librpl_analyse+0xe1) [0x45bca1]
/usr/local/bin/rpl(librpl_evaluation+0x2773) [0x46fb13]
/usr/local/bin/rpl(librpl_traitement_interruptions_logicielles+0x142) [0x481d92]
/usr/local/bin/rpl(librpl_analyse+0x34f) [0x45bf0f]
/usr/local/bin/rpl(librpl_evaluation+0x2773) [0x46fb13]
/usr/local/bin/rpl(librpl_evaluation+0x1e39) [0x46f1d9]
/usr/local/bin/rpl(librpl_evaluation+0x3076) [0x470416]
/usr/local/bin/rpl(librpl_instruction_detach+0x23ad) [0x4b948d]
/usr/local/bin/rpl(librpl_analyse+0xe1) [0x45bca1]
/usr/local/bin/rpl(librpl_evaluation+0x2773) [0x46fb13]
/usr/local/bin/rpl(librpl_sequenceur_optimise+0x346) [0x553086]
/usr/local/bin/rpl(librpl_rplinit+0x3fea) [0x557e8a]
/usr/local/bin/rpl(main+0xd) [0x562cad]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7fb076d24abd]
/usr/local/bin/rpl [0x454529]
[1610-140395925845840] END OF BACKTRACE

Pour le néophyte total et au premier abord, on ne peut pas prétendre que ce soit vraiment clair, mais ce message signifie qu'un objet dans la pile opérationnelle a été détruit à l'insu de l'utilisateur, ce qui n'est pas franchement normal. J'ai essayé de reproduire le problème sous Solaris, NetBSD, FreeBSD, MacOS X et Linux sparc64 sans aucun résultat. Le problème ne se produit que sous Linux amd64. Je n'aime pas ces problèmes qui dépendent à la fois d'une architecture et d'un système, ce sont les pires !

Quelques longues journées de débogage plus tard, à grands coups de printf(), valgrind, hellgrind et ddd pour l'analyse des cores, je découvre que le système de « copy on write » du fork() de certaines versions de la glibc était particulièrement moisi puisque qu'il créait une image indépendante d'exécution pour le fils que lorsque celui-ci tentait une écriture en mémoire indépendamment de ce que le père pouvait faire. Autant dire que le résultat était assez aléatoire. Le problème étant identifié, restait encore à le contourner, ce qui n'était pas une mince affaire, et à inclure dans le code source les corrections adéquates.

Avec le recul, je me demande de plus en plus comment des programmes écrits pour un système Unix peuvent fonctionner sur un autre Unix tant il y a de problèmes dans les différents appels système ou appels à la libc. Non seulement chaque implantation comprend autre chose des spécifications POSIX, mais il y a souvent un monde entre ce que l'appel est censé faire — aux dires de la documentation du système — et ce qu'il fait réellement. Cela passe par des erreurs non documentées ou de façon plus amusante par des arrêts brutaux pour cause d'erreur de segmentation.

Un exemple étant plus parlant qu'un long discours, voici la page de manuel de la fonction pthread_kill() de Linux :

DESCRIPTION
The pthread_kill() function shall request that a signal be delivered to
the specified thread.

As in kill(), if sig is zero, error checking shall be performed but  no
signal shall actually be sent.

qui renvoie directement à la page de kill() indiquant ceci :

DESCRIPTION
The kill() function shall send a signal to a process or a group of pro-
cesses specified by pid. The signal to be sent is specified by sig  and
is  either one from the list given in <signal.h> or 0. If sig is 0 (the
null signal), error checking is performed but  no  signal  is  actually
sent. The null signal can be used to check the validity of pid.

puis un peu plus loin :

ERRORS
The kill() function shall fail if:

EINVAL The  value of the sig argument is an invalid or unsupported signal number.

EPERM  The process does not have permission to send the signal  to  any receiving process.

ESRCH  No  process  or process group can be found corresponding to that specified by pid.

Cette description reproduit parfaitement les spécifications POSIX. Le seul problème est qu'un pthread_kill(tid, 0) sur un thread inexistant ne renvoie pas ESRCH dans la variable globale errno mais une erreur de segmentation !

Souvent, le soir, je rêve d'un monde, d'un monde dans lequel les développeurs des différents systèmes auraient compris la même chose des spécifications POSIX, d'un monde où les libc seraient entièrement déboguées…

 

1 commentaire

Evaluations des utilisateurs
5 étoile:
 
(0)
4 étoile:
 
(1)
3 étoile:
 
(0)
2 étoile:
 
(0)
1 étoile:
 
(0)
1 note
Evaluation moyenne des utilisateurs:
****-(4.0)
tth
****-

Afin de détendre un peu l’ambiance, puis-je rappeler à l’honorable assistance ce lien salvateur : http://pafoo.net/uninstallglibc/uninstglibc.html ?

21.06.10 @ 10:02


Formulaire en cours de chargement...