Files
pmomusic/Blackboard/Done/fix-backend-mutex-poisoned.md

79 lines
3.6 KiB
Markdown
Raw Normal View History

# Fix: Backend Mutex Poisoned Panic sur OpenHome Stop
**Statut** : Terminé
## Problème initial
Lors de l'arrêt de la lecture sur un lecteur OpenHome, l'erreur suivante apparaissait :
```
Impossible d'arrêter la lecture: Internal task error: task 66013 panicked with message "Backend mutex poisoned: PoisonError { .. }"
```
## Crate concernée
- **pmocontrol** (`pmocontrol/src/`)
## Analyse de la cause racine
### Round 1 : Mutex empoisonné
Le mutex backend était empoisonné par des panics non gérés lors d'opérations sur les renderers. Les appels `.unwrap()` et `.expect()` sur le mutex propageaient les panics au lieu de les gérer gracieusement.
### Round 2 : Régression révélée par Round 1
Les correctifs du Round 1 ont révélé un problème plus profond. La chaîne d'échecs était :
1. **DeleteAll échoue avec erreur 501** : Le renderer OpenHome rejette l'action `DeleteAll` pendant la lecture active
2. **Le code continue** (grâce aux correctifs Round 1 qui tolèrent les erreurs)
3. **État incohérent du renderer** : OpenHome retourne 5 IDs via `IdArray` mais une `<TrackList>` vide via `ReadList`
4. **Panic "index out of bounds"** : `sync_queue()` accède à `items[4]` alors que `items.len() == 0`
5. **Mutex empoisonné** : Le panic dans le thread empoisonne le mutex
Preuve dans les logs :
```
OpenHome Playlist IdArray returned ... id_count=5
OpenHome Playlist tracks read ... track_count=0 expected_count=5
```
## Corrections apportées
### 1. Tolérance des erreurs clear_queue
**Fichier** : `pmocontrol/src/music_renderer/musicrenderer.rs`
La méthode `clear_for_playlist_attach()` tolère maintenant les erreurs de `clear_queue()` au lieu de propager l'erreur. Le `DeleteAll` n'est pas critique car `sync_queue()` remplacera de toute façon le contenu de la queue.
### 2. Suppression du clear_queue redondant
**Fichier** : `pmocontrol/src/control_point.rs`
Suppression de l'appel `renderer.clear_queue()?` dans `attach_queue_to_playlist_internal()`. Ce `clear_queue()` était redondant car `clear_for_playlist_attach()` le fait déjà, et causait un second échec `DeleteAll`.
### 3. Bounds-check pour current_index
**Fichier** : `pmocontrol/src/queue/openhome.rs`
Ajout d'une vérification de bornes dans `sync_queue()` pour gérer l'état incohérent du renderer OpenHome. Gère le cas où le renderer retourne un état incohérent (IDs sans données de track correspondantes).
## Fichiers modifiés
| Fichier | Modification |
|---------|-------------|
| `pmocontrol/src/music_renderer/musicrenderer.rs` | Tolérance des erreurs `clear_queue()` dans `clear_for_playlist_attach()` |
| `pmocontrol/src/control_point.rs` | Suppression du `clear_queue()` redondant |
| `pmocontrol/src/queue/openhome.rs` | Bounds-check pour `current_index` + import `warn` |
## Comportement après correction
1. **DeleteAll échoue** : Warning loggé, le code continue
2. **État incohérent détecté** : Warning loggé, traité comme "pas de track courante"
3. **sync_queue réussit** : La playlist est correctement attachée au renderer
4. **Pas de panic** : Le mutex reste sain
## Leçons apprises
La correction d'erreurs (Round 1) peut révéler des bugs latents. Le code supposait que l'état du renderer OpenHome était toujours cohérent. En réalité, certains renderers peuvent retourner des IDs de tracks sans les données correspondantes, notamment lorsqu'une opération `DeleteAll` est rejetée pendant la lecture.
**Approche défensive adoptée** : Plutôt que de supposer un état cohérent, le code vérifie les bornes et traite les incohérences comme des cas dégradés plutôt que de paniquer.