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 appeloneway
est exécuté puis qu'une valeur non-oneway
est appelée, le serveur peut exécuter l'appeloneway
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é avecReturn::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.