Exécution de threads de modèle

Les méthodes marquées comme oneway ne sont pas bloquées. Pour les méthodes non marquées comme oneway, l'appel de méthode d'un client est bloqué jusqu'à ce que le serveur ait une exécution terminée ou appelé un rappel synchrone (selon la situation qui se présente en premier). Les implémentations de méthode serveur ne peuvent appeler qu'un seul rappel synchrone. supplémentaires les appels de rappel sont ignorés et enregistrés en tant qu'erreurs. Si une méthode est censée des valeurs renvoyées par un rappel et n'appelle pas son rappel, cet élément est consigné en tant que et signalée comme une erreur de transport au client.

Threads en mode passthrough

En mode passthrough, la plupart des appels sont synchrones. Toutefois, pour préserver que les appels oneway ne bloquent pas le client, est créé pour chaque processus. Pour en savoir plus, consultez les Présentation de HIDL

Threads dans les HAL reliés

Pour traiter les appels RPC entrants (y compris les rappels asynchrones des HAL vers utilisateurs HAL) et les notifications de décès, un pool de threads est associé à chaque processus qui utilise HIDL. Si un même processus implémente plusieurs interfaces HIDL et/ou les gestionnaires des notifications de décès, son pool de threads est partagé entre tous. Quand ? un processus reçoit un appel de méthode entrant d'un client, il choisit un thread sans frais. à partir du pool de threads et exécute l'appel sur ce thread. Si aucun fil de discussion sans frais n'est disponible, il le bloque jusqu'à ce qu'il en soit disponible.

Si le serveur ne comporte qu'un seul thread, les appels sur le serveur sont effectués dans l'ordre. Un serveur avec plusieurs threads peut effectuer des appels dans le désordre même si le client n'a qu'un seul thread. Cependant, pour un objet d'interface donné, L'ordre des appels oneway est garanti (voir Modèle de thread de serveur). Pour un serveur multithread qui héberge plusieurs interfaces, oneway appelle différentes interfaces peuvent être traités simultanément entre eux ou avec d'autres appels bloquants.

Plusieurs appels imbriqués sont envoyés sur le même thread hwbinder. Par exemple, si un processus (A) effectue un appel synchrone d'un thread de liaison vers le processus (B), puis le processus (B) effectue un rappel synchrone dans le processus (A), l'appel est exécuté sur le thread hwbinder d'origine dans (A) qui est bloqué sur l'original . Cette optimisation permet de disposer d'un serveur à thread unique capable de pour gérer les appels imbriqués, mais cela ne s'applique pas aux cas où ils transitent une autre séquence d'appels d'IPC. Par exemple, si le processus (B) a réalisé appel de liaison/vndbinder qui appelle un processus (C), puis traite (C) les appels dans (A), elle ne peut pas être diffusée sur le fil de discussion d'origine dans (A).

Modèle de thread de serveur

À l'exception du mode passthrough, les implémentations serveur d'interfaces HIDL sont actives dans un processus différent de celui du client et nécessitent qu'un ou plusieurs threads attendent les appels de méthode entrants. Ces threads constituent le pool de threads du serveur. le serveur peut décider du nombre de threads qu'il souhaite exécuter dans son pool de threads et utiliser 1 pour sérialiser tous les appels sur ses interfaces. Si le serveur dispose de plusieurs threads dans le pool de threads, il peut recevoir simultanément sur l'une de ses interfaces (en C++, cela signifie que les données partagées doivent être et soigneusement verrouillée).

Les appels à sens unique dans la même interface sont sérialisés. Si un serveur multithread le client appelle method1 et method2 sur l'interface IFoo et method3 sur l'interface IBar method1 et method2 sont toujours sérialisés, mais method3 peut s'exécuter en parallèle avec method1 et method2

Un seul thread client d'exécution peut entraîner une exécution simultanée sur un avec plusieurs threads de deux manières:

  • Les appels oneway ne sont pas bloqués. Si un appel oneway est exécuté puis qu'une valeur non-oneway est appelée, le serveur peut exécuter l'appel oneway et l'appel non-oneway simultanément.
  • Les méthodes serveur qui transmettent des données avec des rappels synchrones peuvent débloquer au client dès que le rappel est appelé à partir du serveur.

De la deuxième manière, tout code de la fonction serveur qui s'exécute après le est appelé peut s'exécuter simultanément, le serveur gérant le traitement du client. Cela inclut le code dans la fonction "server" et des destructeurs qui s'exécutent à la fin de la fonction. Si le serveur possède plus de un thread dans son pool de threads, des problèmes de simultanéité se produisent même si des appels à partir d'un seul thread client. (Si une HAL desservi par un processus a besoin avec plusieurs threads, tous les HAL ont plusieurs threads, car le pool de threads est partagés par processus.)

Dès que le serveur appelle le rappel fourni, le transport peut appeler implémenté un rappel sur le client et le débloquer. Le client continue parallèlement à ce que fait l'implémentation du serveur après avoir appelé (qui peut inclure des destructeurs en cours d'exécution). Code dans la fonction serveur après le rappel ne bloque plus le client (tant que le serveur threadpool dispose de suffisamment de threads pour gérer les appels entrants, mais peut être exécuté simultanément aux futurs appels du client (sauf si le pool de threads du serveur a un seul thread).

En plus des rappels synchrones, les appels oneway provenant d'une un client à thread unique peut être géré simultanément par un serveur avec plusieurs des threads dans son pool de threads, mais uniquement si ces appels oneway sont exécutés sur différentes interfaces. oneway appels sur le même sont toujours sérialisées.

Remarque:Nous vous encourageons vivement à utiliser les fonctions de serveur de retour dès qu'ils ont appelé la fonction de rappel.

Par exemple (en C++):

Return<void> someMethod(someMethod_cb _cb) {
    // Do some processing, then call callback with return data
    hidl_vec<uint32_t> vec = ...
    _cb(vec);
    // At this point, the client's callback is called,
    // and the client resumes execution.
    ...
    return Void(); // is basically a no-op
};

Modèle de thread client

Le modèle de thread sur le client diffère entre les appels non bloquants (fonctions signalées par le mot clé oneway) et le blocage call (fonctions dont le mot clé oneway n'est pas spécifié).

Bloquer les appels

Pour bloquer les appels, le client bloque jusqu'à ce que l'une des situations suivantes se produise:

  • Une erreur de transport se produit. l'objet Return contient une erreur ; état qui peut être récupéré avec Return::isOk().
  • L'implémentation du serveur appelle le rappel (le cas échéant).
  • La mise en œuvre du serveur renvoie une valeur (en l'absence de paramètre de rappel).

En cas de réussite, la fonction de rappel transmise par le client en tant qu'argument est toujours appelé par le serveur avant le renvoi de la fonction. Le rappel est exécuté sur le même thread que celui sur lequel l'appel de fonction est effectué. veillez à maintenir des verrous pendant les appels de fonction (et évitez-les lorsque cela est possible). Une fonction sans instruction generates ou un mot clé oneway est toujours bloquant ; le client bloque jusqu'à ce que renvoie un objet Return<void>.

Appels à sens unique

Lorsqu'une fonction est marquée comme oneway, le client renvoie immédiatement et n'attend pas que le serveur termine son appel de fonction. Au (et de façon agrégée), cela signifie que l'appel de fonction prend la moitié car il exécute la moitié du code, mais lors de l'écriture d'implémentations qui sensibles aux performances, cela a des conséquences sur la planification. Habituellement, avec un appel à sens unique, l'appelant continue d'être planifié, alors que l'utilisation d'un appel synchrone normal amène le programmeur à transférer immédiatement de l'appelant vers le processus appelé. Il s'agit d'une optimisation des performances binder. Pour les services où l'appel à sens unique doit être exécuté dans le processus cible avec une priorité élevée, la règle de planification du service destinataire peut être modifié. En C++, utiliser la méthode libhidltransport setMinSchedulerPolicy avec les priorités et les règles du planificateur défini dans sched.h garantit que tous les appels au service s'exécutent au moins selon la règle et la priorité de planification définies.