Fedora MacBook

Iš Žinynas.
14:04, 17 balandžio 2024 versija, sukurta \dev\null (Aptarimas | indėlis) (Naujas puslapis: == Sleep fix == Fedora Linux on Apple MacBook might not be able to wake from sleep. (Or it might eventually wake up, but it can take several minutes.) This package “apple_sle...)
(skirt) ← Ankstesnė versija | Dabartinė versija (skirt) | Vėlesnė versija → (skirt)
Jump to navigation Jump to search

Sleep fix

Fedora Linux on Apple MacBook might not be able to wake from sleep. (Or it might eventually wake up, but it can take several minutes.)

This package “apple_sleep”" is a workaround using “isolation” of CPUs, that allows the laptop to wake up from sleep within a normal timeframe.

I have no idea why it works, but I found the trick online - and polished the implementation as far as my Linux-fu allows. And it helps my Fedora-ized MacBook wake up from sleep.

There was some uncertainty about which cpu-num to isolate, so I made a script that isolates all but the first cpu; cpu0, and this seems to work … speedily.

The package consists of a Bash script and a systemd service file.

Usage

Put the files where you prefer, and edit the service file to point to the script. Enable the service, and sleep.target will trigger the service to source the script when the laptop goes to sleep, and again when it wakes up.

 systemctl enable apple_sleep

apple_sleep.service

[Unit]
Description=Isolate cpu cores before sleep and restore after wake
Documentation=https://gist.github.com/jakob-hede/66e9f3439d0891f090fe99daef45cf0d
PartOf=sleep.target

[Service]
Type=simple
RemainAfterExit=yes
# Edit to customize script location:
Environment="APPLE_SLEEP_SCRIPT=/opt/optulation/mixed/apple_sleep/apple_sleep.sh"
ExecStart=/bin/bash -c '. ${APPLE_SLEEP_SCRIPT} START'
ExecStop=/bin/bash -c '. ${APPLE_SLEEP_SCRIPT} STOP'

[Install]
WantedBy=sleep.target

apple_sleep.sh

#!/bin/bash

# Documentation=https://gist.github.com/jakob-hede/66e9f3439d0891f090fe99daef45cf0d
# You must be root to run this script.
execute() {
  debug() {
    # Change to 'false' to disable debug output
    true && printf "\e[35m%s\e[0m\n" "$*"
  }

  fail() {
    printf "\e[31m%s\e[0m\n" "$*"
    exit 1
  }

  is_apple() {
    declare system_vendor txt
    declare -i response
    system_vendor=$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null)
    if [[ "$system_vendor" == *Apple* ]]; then
      response=0
      txt="Running on Apple hardware"
    else
      response=1
      txt="NOT running on Apple hardware"
    fi
    debug "${txt}"
    return "${response}"
  }

  is_root() {
    [[ $UID -eq 0 ]]
  }

  check_circumstances() {
    is_root || fail "You must be root to run this script."
    is_apple || fail "You must be running on Apple hardware to run this script."
  }

  argparse() {
    indx=-99
    if [[ $1 == 'START' ]]; then
      indx=0
      num=0
    elif [[ $1 == 'STOP' ]]; then
      indx=0
      num=1
    else
      fail "Usage: $0 [START|STOP]"
    fi
  }

  logify() {
    declare log_file timestamp
    timestamp=$(date +%H:%M:%S)
    log_file="/tmp/${name}.log"
    echo "${timestamp} ${*}. cpu_statuses: ${cpu_statuses}" >>"${log_file}"
    debug "${name} ${timestamp} ${log_file} $* ${cpu_statuses}"
  }

  isolate() {
    declare directory file
    while ((indx > -1)); do
      ((indx++)) # We do not isolate CPU0, so we start at 1.
      directory="/sys/devices/system/cpu/cpu${indx}"
      [[ ! -d $directory ]] && indx=-99 && break
      file="${directory}/online"
      is_apple >/dev/null && echo "${num}" >"${file}"
      cpu_statuses+="${indx}:$(cat ${file}) "
    done
  }

  flow() (# <- subshell !!!
    # Subshell ensures not to break some system stuff by doing 'exit'.
    declare -i num indx
    declare name cpu_statuses
    name="$(basename "${BASH_SOURCE[0]%.*}")"
    debug "${name} FLOW $*"
    check_circumstances # Optionally disable while testing
    argparse "$@"
    #    debug "solitude: ${num}"
    isolate
    logify "$@"
  )
  flow "$@"
}

execute "$@"
printf '\e[34mapple_sleep DONE %s\e[0m\n' "$?"