linux-kernel character - Que fait ERESTARTSYS lors de l'écriture du pilote Linux?




device read (2)

-ERESTARTSYS est connecté au concept d'appel système redémarrant. Un appel système réitérable est un appel qui peut être ré-exécuté de manière transparente par le noyau en cas d'interruption.

Par exemple, le processus d'espace utilisateur qui dort dans un appel système peut recevoir un signal, exécuter un gestionnaire, puis, lorsque le gestionnaire revient, il semble revenir dans le noyau et continuer à dormir sur l'appel système d'origine.

À l'aide de l' sigaction API POSIX sigaction , les processus peuvent organiser le comportement de redémarrage associé aux signaux.

Dans le noyau Linux, lorsqu'un pilote ou un autre module bloquant dans le contexte d'un appel système détecte qu'une tâche a été réveillée à cause d'un signal, il peut renvoyer -EINTR. Mais -EINTR apparaîtra dans l'espace utilisateur et provoquera le retour de l'appel système -1 avec errno défini sur EINTR.

Si vous renvoyez -ERESTARTSYS à la place, cela signifie que votre appel système peut être redémarré. Le code ERESTARTSYS ne sera pas nécessairement visible dans l'espace utilisateur. Il est soit traduit en -1 retour et errno en EINTR (alors, évidemment, vu dans l'espace utilisateur), ou il est traduit en un comportement de redémarrage de l'appel système, ce qui signifie que votre appel système est appelé avec les mêmes arguments (par aucune action sur une partie du processus de l'espace utilisateur: le noyau le fait en stockant les informations dans un bloc de redémarrage spécial).

Notez le problème évident avec "mêmes arguments" dans le paragraphe précédent: certains appels système ne peuvent pas être redémarrés avec les mêmes paramètres, car ils ne sont pas idempotent! Par exemple, supposons qu'il y ait un appel de sommeil comme nanosleep, pendant 5,3 secondes. Il est interrompu après 5 secondes. S'il redémarre naïvement, il dormira encore 5,3 secondes. Il doit passer de nouveaux paramètres à l'appel redémarré pour dormir pendant les 0,3 secondes restantes; c'est-à-dire modifier le contenu du bloc de redémarrage. Il existe un moyen de le faire: vous insérez des arguments différents dans le bloc de redémarrage de la tâche et utilisez la valeur de retour -ERESTART_RESTARTBLOCK.

Pour répondre à la deuxième question: quelle est la différence? Pourquoi ne pas simplement écrire la routine de lecture sans vérifier la valeur de retour et retourner -ERESTARTSYS? Eh bien, parce que c'est incorrect dans le cas où le réveil est dû à un signal! Voulez-vous une lecture pour retourner 0 octets lus à chaque fois qu'un signal arrive? Cela pourrait être mal interprété par l'espace utilisateur comme fin des données. Ce type de problème n'apparaîtra pas dans les cas de test qui n'utilisent pas de signaux.

J'apprends sur les fonctions d'E / S de blocage pour l'écriture du pilote de périphérique Linux et je me demande quelle est l'utilisation d' ERESTARTSYS . Considérer ce qui suit:

Variable globale:

wait_queue_head_t my_wait_q_head;
int read_avail = 0;


device_init ():

init_waitqueue_head(&my_wait_q_head);


device_read ():

printk("I'm inside driver read!\n");
wait_event_interruptible(&my_wait_q_head, read_avail != 0);
printk("I'm awaken!\n");


device_write ():

read_avail = 1;
wake_up_interruptible(&my_wait_q_head);


Lorsque j'appelle read() dans l'espace utilisateur, l'invite de commande est bloquée jusqu'à ce que j'appelle write() comme prévu. Les messages printk apparaissent également dans dmesg . Cependant, je vois certains des pilotes écrits comme ceci:

Une autre version de device_read ():

printk("I'm inside driver read!\n");
if(wait_event_interruptible(&my_wait_q_head, read_avail != 0))    
{return -ERESTARTSYS;}
printk("I'm awaken!\n");

J'ai testé la deuxième version de device_read() utilisant la même méthode dans l'espace utilisateur, et le résultat est exactement le même, alors, quelle est l'utilité d'ERESTARTSYS?

p / s: J'ai lu le livre Linux Device Driver sur ce sujet mais je ne comprends pas, quelqu'un peut-il donner un exemple à eleborate ?:

Une fois que nous avons passé cet appel, quelque chose nous a réveillés, mais nous ne savons pas quoi. Une possibilité est que le processus a reçu un signal. L'instruction if qui contient l'appel wait_event_interruptible vérifie ce cas. Cette déclaration assure la réaction correcte et attendue aux signaux, qui auraient pu être responsables du réveil du processus (puisque nous étions dans un sommeil interruptible). Si un signal est arrivé et qu'il n'a pas été bloqué par le processus, le bon comportement consiste à laisser les couches supérieures du noyau gérer l'événement. À cette fin, le conducteur renvoie -ERESTARTSYS à l'appelant; cette valeur est utilisée en interne par la couche de système de fichiers virtuel (VFS), qui redémarre l'appel système ou renvoie -EINTR à l'espace utilisateur. Nous utilisons le même type de vérification pour traiter la gestion du signal pour chaque implémentation en lecture et en écriture.

Source: http://www.makelinux.net/ldd3/chp-6-sect-2


Eh bien, pourquoi cela existe en général est probablement différent de la raison pour laquelle il existe dans votre exemple.

Tout a commencé il y a un demi-siècle avec la réutilisation de terminaux de communication sur papier en tant qu'interface utilisateur. Dans l'ère initiale Unix et C qui était le téléscripteur ASR-33.

Cet appareil était lent (10 cps) et bruyant et moche et sa vue du jeu de caractères ASCII se terminait à 0x5f, donc il n'avait (regardez de près la photo) aucune des clés:

{ | } ~ 

Les trigraphes ont été définis pour résoudre un problème spécifique. L'idée était que les programmes C pouvaient utiliser le sous-ensemble ASCII trouvé sur l'ASR-33 et dans d'autres environnements manquant les valeurs ASCII élevées.

Votre exemple est en fait deux de ??! , chaque sens | , donc le résultat est || .

Cependant, les gens qui écrivent du code C ont presque par définition un équipement moderne, 1 donc je suppose: quelqu'un qui se montre ou qui s'amuse, en laissant une sorte d'oeuf de Pâques dans le code pour que vous le trouviez.

Cela a bien fonctionné, cela a mené à une question extrêmement populaire de SO.

Teletype ASR-33

1. D'ailleurs, les trigraphes ont été inventés par le comité de l'ANSI, qui s'est rencontré pour la première fois après que C soit devenu un succès fulgurant, donc aucun des codes C ou codeurs originaux ne les aurait utilisés.





c linux-kernel linux-device-driver