fix: goroutine leak issue of cloudBlink (#801)

* fix: goroutine leak issue of cloudBlink

* chore: add lock and allow context to be cancelled earlier
This commit is contained in:
Aveline 2025-09-12 18:30:35 +02:00 committed by GitHub
parent 37b1a8bf34
commit 1717549578
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 33 deletions

View File

@ -1,6 +1,7 @@
package kvm package kvm
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -110,12 +111,6 @@ func clearDisplayState() {
currentScreen = "ui_Boot_Screen" currentScreen = "ui_Boot_Screen"
} }
var (
cloudBlinkLock sync.Mutex = sync.Mutex{}
cloudBlinkStopped bool
cloudBlinkTicker *time.Ticker
)
func updateDisplay() { func updateDisplay() {
updateLabelIfChanged("ui_Home_Content_Ip", networkState.IPv4String()) updateLabelIfChanged("ui_Home_Content_Ip", networkState.IPv4String())
if usbState == "configured" { if usbState == "configured" {
@ -152,48 +147,81 @@ func updateDisplay() {
stopCloudBlink() stopCloudBlink()
case CloudConnectionStateConnecting: case CloudConnectionStateConnecting:
_, _ = lvImgSetSrc("ui_Home_Header_Cloud_Status_Icon", "cloud.png") _, _ = lvImgSetSrc("ui_Home_Header_Cloud_Status_Icon", "cloud.png")
startCloudBlink() restartCloudBlink()
case CloudConnectionStateConnected: case CloudConnectionStateConnected:
_, _ = lvImgSetSrc("ui_Home_Header_Cloud_Status_Icon", "cloud.png") _, _ = lvImgSetSrc("ui_Home_Header_Cloud_Status_Icon", "cloud.png")
stopCloudBlink() stopCloudBlink()
} }
} }
func startCloudBlink() { const (
if cloudBlinkTicker == nil { cloudBlinkInterval = 2 * time.Second
cloudBlinkTicker = time.NewTicker(2 * time.Second) cloudBlinkDuration = 1 * time.Second
} else { )
// do nothing if the blink isn't stopped
if cloudBlinkStopped {
cloudBlinkLock.Lock()
defer cloudBlinkLock.Unlock()
cloudBlinkStopped = false var (
cloudBlinkTicker.Reset(2 * time.Second) cloudBlinkTicker *time.Ticker
cloudBlinkCancel context.CancelFunc
cloudBlinkLock = sync.Mutex{}
)
func doCloudBlink(ctx context.Context) {
for range cloudBlinkTicker.C {
if cloudConnectionState != CloudConnectionStateConnecting {
continue
}
_, _ = lvObjFadeOut("ui_Home_Header_Cloud_Status_Icon", uint32(cloudBlinkDuration.Milliseconds()))
select {
case <-ctx.Done():
return
case <-time.After(cloudBlinkDuration):
}
_, _ = lvObjFadeIn("ui_Home_Header_Cloud_Status_Icon", uint32(cloudBlinkDuration.Milliseconds()))
select {
case <-ctx.Done():
return
case <-time.After(cloudBlinkDuration):
} }
} }
}
go func() { func restartCloudBlink() {
for range cloudBlinkTicker.C { stopCloudBlink()
if cloudConnectionState != CloudConnectionStateConnecting { startCloudBlink()
continue }
}
_, _ = lvObjFadeOut("ui_Home_Header_Cloud_Status_Icon", 1000) func startCloudBlink() {
time.Sleep(1000 * time.Millisecond) cloudBlinkLock.Lock()
_, _ = lvObjFadeIn("ui_Home_Header_Cloud_Status_Icon", 1000) defer cloudBlinkLock.Unlock()
time.Sleep(1000 * time.Millisecond)
} if cloudBlinkTicker == nil {
}() cloudBlinkTicker = time.NewTicker(cloudBlinkInterval)
} else {
cloudBlinkTicker.Reset(cloudBlinkInterval)
}
ctx, cancel := context.WithCancel(context.Background())
cloudBlinkCancel = cancel
go doCloudBlink(ctx)
} }
func stopCloudBlink() { func stopCloudBlink() {
cloudBlinkLock.Lock()
defer cloudBlinkLock.Unlock()
if cloudBlinkCancel != nil {
cloudBlinkCancel()
cloudBlinkCancel = nil
}
if cloudBlinkTicker != nil { if cloudBlinkTicker != nil {
cloudBlinkTicker.Stop() cloudBlinkTicker.Stop()
} }
cloudBlinkLock.Lock()
defer cloudBlinkLock.Unlock()
cloudBlinkStopped = true
} }
var ( var (

Binary file not shown.

View File

@ -1 +1 @@
6dabd0e657dd099280d9173069687786a4a8c9c25cf7f9e7ce2f940cab67c521 01db2bbcd0bad46c3e21eb3cc5687d15df2153c3d8e2d4665b37acb55f0b5a57