~mil/sxmo-utils

ec6d08e91b94fc725733f65c7dbf313feb2a35cd — Stacy Harper 4 months ago 704f637
Rework is_idle/can_suspend mutexes

It offer a "mutex" way to manage the is_idle and can_suspend status:

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh lock "Dont want to…"

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh list
    SSH is connected
    MPD is playing music
    Playing with leds
    Dont want to…

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh free "Dont want to…"

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh list
    SSH is connected
    MPD is playing music
    Playing with leds

I removed "can_suspend" and "is_idle" hooks to make one unique
"check_state_mutexes" one. This is triggered lazyly by the
idle_locker daemon.

We will tend to use "lock" and "free" action inside some scripts (check
sxmo_leds.sh and sxmo_proximitylock.sh) but for retro-compatibility and
for things like ssh session, we keep this script to periodically check
some conditions.

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh hold

    Will check if no reason are present of wait until it happen.

    $ MUTEX_NAME=can_suspend sxmo_mutex.sh holdexec echo foo

Will check if no reason are present of wait until it happen to exec the
command.
D configs/default_hooks/can_suspend => configs/default_hooks/can_suspend +0 -54
@@ 1,54 0,0 @@
#!/bin/sh
# configversion: 1

# This hook goal is to return a non zero exit code if the device
# should wait before going to suspension

. "$(which sxmo_common.sh)"

exit_should_wait() {
	sxmo_log "$*"
	printf %s "$1"
	exit 1
}

modem_use() {
	(pgrep -f sxmo_modem.sh > /dev/null || \
		pgrep -f sxmo_mms.sh > /dev/null || \
		pgrep -f mmcli > /dev/null || \
		pgrep -f mmsctl > /dev/null || \
		pgrep -f sxmo_modemsendsms.sh > /dev/null || \
		sxmo_daemons.sh running modem_nocrust || \
		pgrep -f sxmo_modemdaemons.sh >/dev/null) && exit_should_wait "modem"
}

active_ssh() {
	(netstat | grep ESTABLISHED | grep -q ssh) && exit_should_wait "ssh"
}

screenlock() {
	pgrep -f sxmo_screenlock.sh >/dev/null && exit_should_wait "screenlock"
}

playing_mpc() {
	command -v mpc > /dev/null || return # no mpc installed

	(mpc status | grep -q '\[playing\]') && exit_should_wait "mpc"
}

photos_processing() {
	pgrep -f postprocess.sh > /dev/null && exit_should_wait "photos processing"
}

auto_suspend() {
	[ -e "$XDG_CACHE_HOME/sxmo/sxmo.nosuspend" ] && exit_should_wait "auto_suspend_off"
}

modem_use
playing_mpc
screenlock
photos_processing
auto_suspend
active_ssh

exit 0

A configs/default_hooks/check_state_mutexes => configs/default_hooks/check_state_mutexes +106 -0
@@ 0,0 1,106 @@
#!/bin/sh

# This hook goal is to setup mutexes if the device must be considered
# as idle or not, if it can go to crust or not

. "$(which sxmo_common.sh)"

lock_suspend_mutex() {
	if ! MUTEX_NAME=can_suspend sxmo_mutex.sh lockedby "$1"; then
		MUTEX_NAME=can_suspend sxmo_mutex.sh lock "$1"
	fi
}

free_suspend_mutex() {
	MUTEX_NAME=can_suspend sxmo_mutex.sh free "$1"
}

lock_idle_mutex() {
	if ! MUTEX_NAME=is_idle sxmo_mutex.sh lockedby "$1"; then
		MUTEX_NAME=is_idle sxmo_mutex.sh lock "$1"
	fi

	lock_suspend_mutex "$1" # not idle also mean not suspending
}

free_idle_mutex() {
	MUTEX_NAME=is_idle sxmo_mutex.sh free "$1"

	free_suspend_mutex "$1"
}

PIDS=""

# ongoing_call
if pgrep -f sxmo_modemcall.sh > /dev/null; then
	lock_idle_mutex "Ongoing call"
else
	free_idle_mutex "Ongoing call"
fi &
PIDS="$PIDS $!"

# camera_open
if pgrep -f megapixels > /dev/null; then
	lock_idle_mutex "Megapixels is open"
else
	free_idle_mutex "Megapixels is open"
fi &
PIDS="$PIDS $!"

# auto_screenoff
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
	lock_idle_mutex "Manually disabled"
else
	free_idle_mutex "Manually disabled"
fi &
PIDS="$PIDS $!"

# modem_use
if pgrep -f sxmo_modem.sh > /dev/null || \
	pgrep -f sxmo_mms.sh > /dev/null || \
	pgrep -f mmcli > /dev/null || \
	pgrep -f mmsctl > /dev/null || \
	pgrep -f sxmo_modemsendsms.sh > /dev/null || \
	sxmo_daemons.sh running modem_nocrust -q || \
	pgrep -f sxmo_modemdaemons.sh >/dev/null; then
	lock_suspend_mutex "Modem is used"
else
	free_suspend_mutex "Modem is used"
fi &
PIDS="$PIDS $!"

# active_ssh
if netstat | grep ESTABLISHED | grep -q ssh; then
	lock_suspend_mutex "SSH is connected"
else
	free_suspend_mutex "SSH is connected"
fi &
PIDS="$PIDS $!"

# playing_mpc
if command -v mpc > /dev/null && mpc status | grep -q '\[playing\]'; then
	lock_suspend_mutex "MPD is playing music"
else
	free_suspend_mutex "MPD is playing music"
fi &
PIDS="$PIDS $!"

# photos_processing
if pgrep -f postprocess.sh > /dev/null; then
	lock_suspend_mutex "Camera postprocessing"
else
	free_suspend_mutex "Camera postprocessing"
fi &
PIDS="$PIDS $!"

# auto_suspend
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.nosuspend" ]; then
	lock_suspend_mutex "Manually disabled"
else
	free_suspend_mutex "Manually disabled"
fi &
PIDS="$PIDS $!"

for PID in $PIDS; do
	wait "$PID"
done

D configs/default_hooks/is_idle => configs/default_hooks/is_idle +0 -47
@@ 1,47 0,0 @@
#!/bin/sh
# configversion: 1

# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. "$(which sxmo_common.sh)"

# This hook goal is to return a non zero exit code if the device
# must be considered not idle (ongoing call, playing mpd, etc)

exit_not_idle() {
	sxmo_log "$*"
	printf %s "$1"
	exit 1
}


ongoing_call() {
	pgrep -f sxmo_modemcall.sh > /dev/null && exit_not_idle "call"
}

proximity_lock_on() {
	sxmo_daemons.sh running proximity_lock -q && exit_not_idle "proxlock"
}

camera_open() {
	pgrep -f megapixels > /dev/null && exit_not_idle "camera"
}

waiting_rtcwake() {
	if grep -q crust "$SXMO_LASTSTATE" && \
		grep -q rtc "$SXMO_UNSUSPENDREASONFILE"; then
			exit_not_idle "rtcwake"
	fi
}

auto_screenoff() {
	[ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ] && exit_not_idle "auto_screenoff_off"
}

ongoing_call
proximity_lock_on
waiting_rtcwake
camera_open
auto_screenoff

exit 0

M configs/default_hooks/lock => configs/default_hooks/lock +4 -2
@@ 23,7 23,9 @@ wait "$LEDPID"
# Start a periodic daemon (8s) "try to go to off" after 8 seconds
# Resume tasks stop daemons
sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \
	timeout 8 'sxmo_daemons.sh start periodic_deeper sxmo_run_periodically.sh 8 sxmo_screenlock_deeper.sh --idle' \
	resume 'sxmo_daemons.sh stop periodic_deeper'
	timeout 8 'MUTEX_NAME=is_idle sxmo_daemons.sh start going_deeper sh -c "sxmo_hooks.sh check_state_mutexes && exec sxmo_mutex.sh holdexec sxmo_screenlock.sh off"' \
	resume 'sxmo_daemons.sh stop going_deeper' \
	timeout 12 'sxmo_daemons.sh start periodic_state_mutex_check sxmo_run_periodically.sh 10 sxmo_hooks.sh check_state_mutexes' \
	resume 'sxmo_daemons.sh stop periodic_state_mutex_check'

sxmo_daemons.sh signal desktop_widget -12

M configs/default_hooks/presuspend => configs/default_hooks/presuspend +2 -0
@@ 6,6 6,8 @@
# shellcheck source=scripts/core/sxmo_common.sh
. "$(which sxmo_common.sh)"

sxmo_daemons.sh stop periodic_blink

pkill clickclack
sxmo_keyboard.sh close
pkill mpv #if any audio/video is playing, kill it (it might stutter otherwise)

M configs/default_hooks/screenoff => configs/default_hooks/screenoff +9 -5
@@ 33,12 33,16 @@ esac
# Resume tasks stop daemons
if [ -z "$SXMO_DISABLE_LEDS" ]; then
	sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \
		timeout 8 'sxmo_daemons.sh start periodic_deeper sxmo_run_periodically.sh 8 sxmo_screenlock_deeper.sh --idle' \
		resume 'sxmo_daemons.sh stop periodic_deeper' \
		timeout 8 'MUTEX_NAME=can_suspend sxmo_daemons.sh start going_deeper sh -c "sxmo_hooks.sh check_state_mutexes && exec sxmo_mutex.sh holdexec sxmo_screenlock.sh crust"' \
		resume 'sxmo_daemons.sh stop going_deeper' \
		timeout 5 'sxmo_daemons.sh start periodic_blink sxmo_run_periodically.sh 2 sxmo_led.sh blink red blue' \
		resume 'sxmo_daemons.sh stop periodic_blink'
		resume 'sxmo_daemons.sh stop periodic_blink' \
		timeout 12 'sxmo_daemons.sh start periodic_state_mutex_check sxmo_run_periodically.sh 10 sxmo_hooks.sh check_state_mutexes' \
		resume 'sxmo_daemons.sh stop periodic_state_mutex_check'
else
	sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \
		timeout 8 'sxmo_daemons.sh start periodic_deeper sxmo_run_periodically.sh 8 sxmo_screenlock_deeper.sh --idle' \
		resume 'sxmo_daemons.sh stop periodic_deeper'
		timeout 8 'MUTEX_NAME=can_suspend sxmo_daemons.sh start going_deeper sh -c "sxmo_hooks.sh check_state_mutexes && exec sxmo_mutex.sh holdexec sxmo_screenlock.sh crust"' \
		resume 'sxmo_daemons.sh stop going_deeper' \
		timeout 12 'sxmo_daemons.sh start periodic_state_mutex_check sxmo_run_periodically.sh 10 sxmo_hooks.sh check_state_mutexes' \
		resume 'sxmo_daemons.sh stop periodic_state_mutex_check'
fi

M configs/default_hooks/unlock => configs/default_hooks/unlock +4 -2
@@ 28,7 28,9 @@ echo 16000 > "$NETWORKRTCSCAN"
# Start a periodic daemon (10s) "try to go to lock" after 120 seconds
# Resume tasks stop daemons
sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \
	timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" 'sxmo_daemons.sh start periodic_deeper sxmo_run_periodically.sh 10 sxmo_screenlock_deeper.sh --idle' \
	resume 'sxmo_daemons.sh stop periodic_deeper'
	timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" 'MUTEX_NAME=is_idle sxmo_daemons.sh start going_deeper sh -c "sxmo_hooks.sh check_state_mutexes && exec sxmo_mutex.sh holdexec sxmo_screenlock.sh lock"' \
	resume 'sxmo_daemons.sh stop going_deeper' \
	timeout "$((${SXMO_UNLOCK_IDLE_TIME:-120} + 10))" 'sxmo_daemons.sh start periodic_state_mutex_check sxmo_run_periodically.sh 10 sxmo_hooks.sh check_state_mutexes' \
	resume 'sxmo_daemons.sh stop periodic_state_mutex_check'

sxmo_daemons.sh signal desktop_widget -12

M scripts/core/sxmo_led.sh => scripts/core/sxmo_led.sh +6 -3
@@ 3,10 3,13 @@
. "$(which sxmo_common.sh)"

free_mutex() {
	MUTEX_NAME=can_suspend sxmo_mutex.sh free "Playing with leds"
	rmdir "$XDG_RUNTIME_DIR"/sxmo.led.lock
}

check_mutex() {
ensure_mutex() {
	MUTEX_NAME=can_suspend sxmo_mutex.sh lock "Playing with leds"

	while ! mkdir "$XDG_RUNTIME_DIR"/sxmo.led.lock 2> /dev/null; do
		sleep 0.1
	done


@@ 118,11 121,11 @@ cmd="$1"
shift
case "$cmd" in
	"set")
		check_mutex
		ensure_mutex
		set_leds "$@"
		;;
	get|blink)
		check_mutex
		ensure_mutex

		"$cmd"_led "$@"
		;;

A scripts/core/sxmo_mutex.sh => scripts/core/sxmo_mutex.sh +71 -0
@@ 0,0 1,71 @@
#!/bin/sh

set -e

MUTEX_NAME="${MUTEX_NAME:-default}"
ROOT_DIR="${XDG_RUNTIME_DIR:-$HOME/.local/run}/sxmo_mutex"
REASON_FILE="$ROOT_DIR/$MUTEX_NAME"
mkdir -p "$(dirname "$REASON_FILE")"
touch "$REASON_FILE"

lock() {
	printf "%s\n" "$1" >> "$REASON_FILE"
}

free() {
	grep -xnm1 "$1" "$REASON_FILE" | \
		cut -d: -f1 | \
		xargs -rn1 -I{} sed -i '{}d' "$REASON_FILE"
}

lockedby() {
	grep -qxm1 "$1" "$REASON_FILE"
}

freeall() {
	printf "" > "$REASON_FILE"
}

list() {
	cat "$REASON_FILE"
}

hold() {
	if ! [ -s "$REASON_FILE" ]; then
		exit 0
	fi

	FIFO="$(mktemp -u)"
	mkfifo "$FIFO"
	inotifywait -mq -e "close_write" "$ROOT_DIR" >> "$FIFO" &
	NOTIFYPID=$!

	finish() {
		kill "$NOTIFYPID"
		rm "$FIFO"
		exit 0
	}
	trap 'finish' TERM INT EXIT

	while read -r; do
		if ! [ -s "$REASON_FILE" ]; then
			exit 0
		fi
	done < "$FIFO"
}

holdexec() {
	finish() {
		kill "$HOLDPID"
		exit
	}
	trap 'finish' TERM INT

	hold &
	HOLDPID=$!
	wait "$HOLDPID"

	"$@"
}

"$@"

M scripts/core/sxmo_proximitylock.sh => scripts/core/sxmo_proximitylock.sh +3 -1
@@ 6,14 6,16 @@ isLocked() {
}

finish() {
	MUTEX_NAME=can_suspend sxmo_mutex.sh free "Proximity lock is running"
	sxmo_screenlock.sh "$INITIALSTATE"
	exit 0
}


INITIALSTATE="$(sxmo_screenlock.sh getCurState)"
trap 'finish' TERM INT

MUTEX_NAME=can_suspend sxmo_mutex.sh lock "Proximity lock is running"

proximity_raw_bus="$(find /sys/devices/platform/soc -name 'in_proximity_raw')"
distance() {
	cat "$proximity_raw_bus"

M scripts/core/sxmo_rtcwake.sh => scripts/core/sxmo_rtcwake.sh +5 -15
@@ 3,22 3,12 @@
# shellcheck source=configs/profile.d/sxmo_init.sh
. /etc/profile.d/sxmo_init.sh

finish() {
	if grep -q crust "$SXMO_LASTSTATE" \
		&& grep -q rtc "$SXMO_UNSUSPENDREASONFILE" \
		&& [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then
		WAKEPROCS=$(pgrep -f sxmo_rtcwake.sh | wc -l)
		if [ "$WAKEPROCS" -gt 2 ]; then
			#each process also spawns a blink subprocess, so we check if there are more than two rather than one:
			echo "sxmo_rtcwake: returning without crust, other sxmo_rtcwake process is still running ($(date))" >&2
		else
			echo "sxmo_rtcwake: going back to crust ($(date))" >&2
			sxmo_screenlock.sh crust
		fi
	else
		echo "sxmo_rtcwake: returning without crust ($(date))" >&2
	fi
# We can have multiple cronjobs at the same time
MUTEX_NAME=can_suspend sxmo_mutex.sh lock "Executing cronjob"
MUTEX_NAME=can_suspend sxmo_mutex.sh free "Waiting for cronjob"

finish() {
	MUTEX_NAME=can_suspend sxmo_mutex.sh free "Executing cronjob"
	exit 0
}


M scripts/core/sxmo_screenlock.sh => scripts/core/sxmo_screenlock.sh +7 -2
@@ 85,8 85,6 @@ crust() {

	getCurState > "$SXMO_LASTSTATE"

	sxmo_led.sh blink red

	saveAllEventCounts

	sxmo_hooks.sh presuspend


@@ 99,6 97,9 @@ crust() {
	if [ -z "$suspend_time" ] || [ "$suspend_time" -gt "$YEARS8_TO_SEC" ]; then
		suspend_time="$YEARS8_TO_SEC"
	fi

	sxmo_led.sh blink red

	if [ "$suspend_time" -gt 0 ]; then
		sxmo_log "real crusting now (suspendtime=$suspend_time)"
		rtcwake -m mem -s "$suspend_time" >&2


@@ 114,6 115,10 @@ crust() {

	sxmo_log "woke up from crust (reason=$UNSUSPENDREASON)"

	if [ "$UNSUSPENDREASON" = "rtc" ]; then
		MUTEX_NAME=can_suspend sxmo_mutex.sh lock "Waiting for cronjob"
	fi

	sxmo_hooks.sh postwake "$UNSUSPENDREASON"
}


D scripts/core/sxmo_screenlock_deeper.sh => scripts/core/sxmo_screenlock_deeper.sh +0 -31
@@ 1,31 0,0 @@
#!/bin/sh

# this script goal is to move the screen lock state from lock to off then crust

if [ "$1" = "--idle" ]; then
	sxmo_hooks.sh is_idle >/dev/null || exit
fi

initial_state="$(sxmo_screenlock.sh getCurState)"
case "$initial_state" in
	unlock)
		target_state=lock
		case "$SXMO_WM" in
			sway)
				swaymsg mode default -q
				;;
			esac
		;;
	lock)
		target_state=off
		;;
	off)
		target_state=crust
		;;
esac

if [ "crust" = "$target_state" ] && ! sxmo_hooks.sh can_suspend >/dev/null; then
	exit
fi

sxmo_screenlock.sh "$target_state"