Dans cet article, je présenterai brièvement PlantUML en lisant la source du pilote Linux.
Site officiel: https://plantuml.com/
Puisqu'il existe de nombreux articles de commentaires sur PlantUML, je vais omettre les détails, mais comme son nom l'indique, c'est un outil pour écrire UML. La particularité est qu'il peut être décrit sous forme de texte.
UML est souvent utilisé pour la conception, mais bien sûr, il peut également être utilisé pour l'analyse de mouvement. Par exemple, lors de la lecture de la source du pilote, la relation d'appel de fonction entre les fichiers peut devenir compliquée et vous ne pourrez peut-être pas la rattraper (puisque mon cerveau n'a que la capacité des larmes d'une araignée, le saut de balise se fait en deux étapes. Après un long moment, j'oublie immédiatement ce qu'était l'appelant). Ce serait bien de pouvoir clarifier qui appelle les fonctions dans quel ordre, et les diagrammes de séquence sont utiles dans de tels cas.
Quand j'écris un diagramme de séquence avec PlantUML, cela ressemble à ceci.
@startuml
Alice -> Bob: SYN
Alice <-- Bob: ACK
@enduml
Après avoir créé ce qui précède avec un éditeur de texte, enregistrez-le avec un nom approprié (exemple: hoge.puml) et générez une image avec la commande suivante.
$ plantuml hoge.puml
Une fois exécuté, hoge.png sera généré dans le répertoire où la commande a été exécutée.
La syntaxe est ʻFlèche du nom de l'objet (comme '->' ou '->') Nom de l'objet: Message` Ainsi, si vous mettez le nom du fichier source dans le nom de l'objet et la fonction à appeler dans le message, il semble que vous puissiez facilement exprimer la relation d'appel de fonction entre les fichiers. Veuillez vous référer au site officiel pour une syntaxe plus détaillée.
https://plantuml.com/ja/sequence-diagram
À titre d'exemple, jetons un coup d'œil au pilote de caméra USB Linux v5.4. Il est sous drivers / media / usb / uvc.
$ ls drivers/media/uvc/
Kconfig Makefile uvc_ctrl.c uvc_debugfs.c uvc_driver.c
uvc_entity.c uvc_isight.c uvc_metadata.c uvc_queue.c
uvc_status.c uvc_v4l2.c uvc_video.c uvcvideo.h
Pourquoi y a-t-il autant de fichiers?
Les pilotes de niveau le plus bas pour Linux USB (contrôleur hôte et contrôle HUB) se trouvent sous drivers / usb / core. D'autre part, le pilote UVC dans drivers / media / uvc / est la partie qui fonctionne lorsque la classe du périphérique USB connecté est UVC. Je ne sais pas quelles sont les relations entre les fichiers ici, je vais donc continuer à lire dans le but de comprendre les relations entre ces fichiers dans une certaine mesure. Cependant, puisque le but de cette fois est de présenter PlantUML **, je ne le lirai pas en détail.
Tout d'abord, c'est un début. Puisque le pilote UVC est un pilote de caméra, il devrait s'agir d'un mécanisme qui utilise le framework de capture vidéo Linux (V4L2) pour faire fonctionner la caméra conformément à ioctl () pour / dev / videoXXX depuis le userland. Commencez à lire avec cette hypothèse.
Tout d'abord, lorsque vous grep, il semble que uvc_driver.c, uvc_metadata.c et uvc_v4l2.c traitent ioctl. À titre d'exemple, suivons le processus de ioctl VIDIOC_S_FMT qui définit le format des données.
Si vous grep un nom comme celui-là, vous le trouverez dans uvc_metadata.c et uvc_ioctl.c.
$ grep -iH -n vidioc_s_fmt drivers/media/usb/uvc/*
drivers/media/usb/uvc/uvc_metadata.c:133: .vidioc_s_fmt_meta_cap = uvc_meta_v4l2_set_format,
drivers/media/usb/uvc/uvc_v4l2.c:472: * - VIDIOC_S_FMT
drivers/media/usb/uvc/uvc_v4l2.c:1474: .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap,
drivers/media/usb/uvc/uvc_v4l2.c:1475: .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
Les deux fichiers définissent leur fonction dans le pointeur de fonction de la structure v4l2_ioctl_ops.
ioctl VIDIOC_S_FMT est une API qui prend un pointeur vers une structure v4l2_format comme argument, et lorsque vous appelez ioctl (), la première entrée est v4l_s_fmt () dans drivers / media / v4l2-core / v4l2-ioctl.c. Comme vous pouvez le voir ici, cette API est appelée en spécifiant le type à définir dans le type de la structure v4l2_format. v4l2_s_fmt () appelle le pointeur de fonction défini dans la structure v4l2_ioctl_ops en fonction du type.
v4l2-ioctl.c
static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
...
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_vid_cap))
break;
CLEAR_AFTER_FIELD(p, fmt.pix);
ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
if (vfd->vfl_type == VFL_TYPE_TOUCH)
v4l_pix_format_touch(&p->fmt.pix);
return ret;
...
Lorsque V4L2_BUF_TYPE_VIDEO_CAPTURE est spécifié pour le type, il semble entrer le chemin d'appel de la fonction uvc_ioctl_s_fmt_vid_cap () définie dans .vidioc_s_fmt_vid_cap dans uvc_v4l2.c.
Donc, si vous exprimez cela dans PlantUML
@startuml
participant "User Space" as user
participant "v4l2-ioctl.c" as v4l2
participant "uvc_v4l2.c" as uvc
user -> v4l2: ioctl(fd, V4L2_S_FMT, *v4l2_format)
alt v4l2_format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
v4l2 -> uvc: uvc_ioctl_s_fmt_vid_cap()
end
@enduml
Que diriez-vous quelque chose comme ça? La raison pour laquelle "participant ~ as ..." est ajouté au début est que si un tiret '-' est inclus dans le nom de l'objet, il est nécessaire de le mettre entre guillemets pour des raisons grammaticales, il est donc difficile d'écrire chacun d'eux, donc un alias est donné.
Nous suivrons les appels de fonction à l'avenir un peu plus en profondeur.
uvc_v4l2.c
static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
return uvc_v4l2_set_format(stream, fmt);
}
Uvc_acquire_privileges () et uvc_v4l2_set_format () appelés à partir d'ici sont des fonctions de uvc_v4l2.c, mais uvc_v4l2_set_format () appelle uvc_v4l2_try_format () après cela, et drivers / media / usb / uvc / uvc. ) Est appelé. Appelez ensuite ubc_set_video_ctrl (), __uvc_query_ctrl (), et enfin appelez la fonction USB principale usb_control_msg ().
Si vous souhaitez écrire plus en détail, vous pouvez écrire tous les appels de fonction dans la séquence précédente. Écrivons tous les appels de fonction dans l'ordre.
@startuml
participant "User Space" as user
participant "v4l2-ioctl.c" as v4l2
participant "uvc_v4l2.c" as uvc
participant "uvc_video.c" as uvc_video
participant "usb/core/message.c " as usb_core
user -> v4l2: ioctl(fd, V4L2_S_FMT, *v4l2_format)
alt v4l2_format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
v4l2 -> uvc: uvc_ioctl_s_fmt_vid_cap()
uvc -> uvc: uvc_v4l2_try_format()
uvc -> uvc_video: uvc_probe_video()
uvc_video -> uvc_video: uvc_set_video_ctrl()
uvc_video -> uvc_video: __uvc_query_ctrl()
uvc_video -> usb_core: usb_control_msg()
end
@enduml
Si vous lisez jusqu'ici, vous pouvez voir la structure approximative depuis le moment où ioctl () est appelé depuis Userland jusqu'au moment où la commande est lancée sur le périphérique USB. De plus, on peut s'attendre à ce que uvc_v4l2.c soit responsable du traitement v4l2 ioctl () et uvc_video.c soit responsable du traitement des messages liés à la communication USB.
Dans cet article, j'ai présenté PlantUML en utilisant le code source Linux écrit en C comme exemple.
Personnellement, je l'aime parce que je peux l'écrire intuitivement comme écrire un mémo sur une pile d'appels. Est-ce un goulot d'étranglement qui nécessite Java ou doit être construit à chaque fois (cela peut être résolu avec les plugins Atom ou VSCode, alors consultez d'autres articles)? Cependant, être capable d'écrire du texte est un énorme avantage.
Des exemples d'utilisation de PlantUML dans la conception ont été présentés sur plusieurs sites, mais je n'ai pas trouvé beaucoup d'exemples d'utilisation de PlantUML pour l'analyse de cette manière, alors je l'ai écrit. Veuillez l'utiliser lorsque vous souhaitez vous asseoir et lire la source.
Si vous utilisez le plug-in Atom ou VSCode, vous pouvez générer automatiquement un aperçu sans appuyer sur la commande de construction à chaque fois. Il existe de nombreux articles d'introduction de ce type, veuillez donc les rechercher.