Skip to content

Commit

Permalink
fix: prevent idle sleep if system has just waked up
Browse files Browse the repository at this point in the history
i.e. when the maintain loop is blocked

Signed-off-by: Charlie Chiang <[email protected]>
  • Loading branch information
charlie0129 committed Nov 11, 2023
1 parent 90b5ac8 commit 31b7cf4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 12 deletions.
2 changes: 1 addition & 1 deletion cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ func NewStatusCommand() *cobra.Command {
cmd.Print(", because your current charge is above the lower limit. Charging will be allowed after current charge drops below the lower limit.")
}
if pluggedIn && currentCharge < low {
cmd.Print(" If no manual intervention is involved, charging should be allowed soon. Wait for a few minutes and come back.")
cmd.Print(". However, if no manual intervention is involved, charging should be allowed soon. Wait for 5 minutes and come back.")
}
cmd.Println()
}
Expand Down
39 changes: 28 additions & 11 deletions sleepcallback.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ var (
postSleepLoopDelaySeconds = 120
)

var (
lastWakeTime = time.Now()
lastSleepTime = time.Now().Add(-time.Duration(preSleepLoopDelaySeconds) * time.Second)
)

//export canSystemSleepCallback
func canSystemSleepCallback() {
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
Expand All @@ -29,24 +34,34 @@ func canSystemSleepCallback() {
IOAllowPowerChange or IOCancelPowerChange, the system will wait 30
seconds then go to sleep.
*/
logrus.Debugln("received kIOMessageCanSystemSleep notification")
logrus.Debugln("received kIOMessageCanSystemSleep notification, idle sleep is about to kick in")

if !config.PreventIdleSleep {
logrus.Debugln("system is going to sleep, but PreventIdleSleep is disabled, nothing to do")
logrus.Debugln("PreventIdleSleep is disabled, allow idle sleep")
C.AllowPowerChange()
return
}

// We won't allow idle sleep if the system has just waked up,
// because there may still be a maintain loop waiting (see the wg.Wait() in loop.go).
// So decisions may not be made yet. We need to wait.
// Actually, we wait the larger of preSleepLoopDelaySeconds and postSleepLoopDelaySeconds. This is not implemented yet.
if time.Now().Sub(lastWakeTime) < time.Duration(preSleepLoopDelaySeconds)*time.Second {

Check failure on line 49 in sleepcallback.go

View workflow job for this annotation

GitHub Actions / Check Go Code

S1012: should use `time.Since` instead of `time.Now().Sub` (gosimple)
logrus.Debugln("system has just waked up, deny idle sleep")
C.CancelPowerChange()
return
}

// Run a loop immediately to update `maintainedChargingInProgress` variable.
maintainLoopForced()

if maintainedChargingInProgress {
logrus.Debugln("idle sleep is about to kick in, but maintained charging is in progress, deny idle sleep")
logrus.Debugln("maintained charging is in progress, deny idle sleep")
C.CancelPowerChange()
return
}

logrus.Debugln("idle sleep is about to kick in, no maintained charging is in progress, allow idle sleep")
logrus.Debugln("no maintained charging is in progress, allow idle sleep")
C.AllowPowerChange()
}

Expand All @@ -59,10 +74,11 @@ func systemWillSleepCallback() {
NOTE: If you call IOCancelPowerChange to deny sleep it returns
kIOReturnSuccess, however the system WILL still go to sleep.
*/
logrus.Debugln("received kIOMessageSystemWillSleep notification")
logrus.Debugln("received kIOMessageSystemWillSleep notification, system will go to sleep")
lastSleepTime = time.Now()

if !config.DisableChargingPreSleep {
logrus.Debugln("system is going to sleep, but DisableChargingPreSleep is disabled, nothing to do")
logrus.Debugln("DisableChargingPreSleep is disabled, allow sleep")
C.AllowPowerChange()
return
}
Expand All @@ -75,7 +91,7 @@ func systemWillSleepCallback() {
// By always disabling charging before sleep (if charge limit is enabled), we can prevent
// some rare cases.
if config.Limit < 100 {
logrus.Infof("system is going to sleep but charge limit is enabled, disabling charging just before sleep, and delaying next loop by %d seconds", preSleepLoopDelaySeconds)
logrus.Infof("charge limit is enabled, disabling charging, delaying next loop by %d seconds, and allowing sleep", preSleepLoopDelaySeconds)
// Delay next loop to prevent charging to be re-enabled after we disabled it.
// macOS will wait 30s before going to sleep, there is a chance that a maintain loop is
// executed during that time and it enables charging.
Expand All @@ -94,7 +110,7 @@ func systemWillSleepCallback() {
return
}
} else {
logrus.Debugln("system is going to sleep, no maintained charging is in progress, nothing to do")
logrus.Debugln("no maintained charging is in progress, allow sleep")
}

C.AllowPowerChange()
Expand All @@ -103,16 +119,17 @@ func systemWillSleepCallback() {
//export systemWillPowerOnCallback
func systemWillPowerOnCallback() {
// System has started the wake-up process...
logrus.Debugln("received kIOMessageSystemWillPowerOn notification")
logrus.Debugln("received kIOMessageSystemWillPowerOn notification, system has started the wake-up process")
}

//export systemHasPoweredOnCallback
func systemHasPoweredOnCallback() {
// System has finished waking up...
logrus.Debugln("received kIOMessageSystemHasPoweredOn notification")
logrus.Debugln("received kIOMessageSystemHasPoweredOn notification, system has finished waking up")
lastWakeTime = time.Now()

if config.Limit < 100 {
logrus.Debugf("system has finished waking up, delaying next loop by %d seconds", postSleepLoopDelaySeconds)
logrus.Debugf("delaying next loop by %d seconds", postSleepLoopDelaySeconds)
wg.Add(1)
go func() {
// Use sleep instead of time.After because when the computer sleeps, we
Expand Down

0 comments on commit 31b7cf4

Please sign in to comment.