Comment inhiber temporairement la suspension?

10

J'ai cherché un peu cela et je ne trouve rien d'utile.

J'ai mon PC exécutant Ubuntu 12.10 configuré pour suspendre après 30 minutes d'inactivité. Je ne veux pas changer cela, cela fonctionne très bien la plupart du temps.

Ce que je veux faire, c'est désactiver la suspension automatique si une application particulière est en cours d'exécution. Comment puis-je faire ceci?

La chose la plus proche que j'ai trouvée jusqu'à présent est d'ajouter un script shell dans /usr/lib/pm-utils/sleep.dlequel vérifie si l'application est en cours d'exécution et renvoie 1 pour indiquer que la suspension doit être empêchée. Mais il semble que le système abandonne alors la suspension automatiquement, au lieu de réessayer après 30 minutes supplémentaires. (Pour autant que je sache, si je déplace la souris, cela redémarre la minuterie.) Il est fort probable que l'application se termine après quelques heures, et je préfère que mon PC soit suspendu automatiquement si je n'utilise pas à ce point . (Je ne veux donc pas ajouter d'appel à pm-suspend lorsque l'application se termine.)

Est-ce possible?

EDIT: Comme je l'ai noté dans l'un des commentaires ci-dessous, ce que je voulais réellement, c'était empêcher la suspension lorsque mon PC servait des fichiers sur NFS; Je voulais juste me concentrer sur la partie "suspendre" de la question car j'avais déjà une idée de la façon de résoudre la partie NFS. En utilisant l'idée «xdotool» donnée dans l'une des réponses, j'ai trouvé le script suivant que je lance depuis cron toutes les quelques minutes. Ce n'est pas idéal car cela empêche également l'économiseur d'écran de se déclencher, mais cela fonctionne. J'ai besoin de voir pourquoi la «caféine» ne réactive pas correctement la suspension plus tard, alors je pourrais probablement faire mieux. Quoi qu'il en soit, cela semble fonctionner, donc je l'inclus ici au cas où quelqu'un d'autre serait intéressé.

#!/bin/bash

# If the output of this function changes between two successive runs of this
# script, we inhibit auto-suspend.
function check_activity()
{
    /usr/sbin/nfsstat --server --list
}

# Prevent the automatic suspend from kicking in. 
function inhibit_suspend()
{
    # Slightly jiggle the mouse pointer about; we do a small step and
    # reverse step to try to stop this being annoying to anyone using the
    # PC. TODO: This isn't ideal, apart from being a bit hacky it stops
    # the screensaver kicking in as well, when all we want is to stop
    # the PC suspending. Can 'caffeine' help?
    export DISPLAY=:0.0
    xdotool mousemove_relative --sync --  1  1
    xdotool mousemove_relative --sync -- -1 -1
}

LOG="$HOME/log/nfs-suspend-blocker.log"
ACTIVITYFILE1="$HOME/tmp/nfs-suspend-blocker.current"
ACTIVITYFILE2="$HOME/tmp/nfs-suspend-blocker.previous"

echo "Started run at $(date)" >> "$LOG"
if [ ! -f "$ACTIVITYFILE1" ]; then
    check_activity > "$ACTIVITYFILE1"
    exit 0;
fi

/bin/mv "$ACTIVITYFILE1" "$ACTIVITYFILE2"
check_activity > "$ACTIVITYFILE1"

if cmp --quiet "$ACTIVITYFILE1" "$ACTIVITYFILE2"; then
    echo "No activity detected since last run" >> "$LOG"
else
    echo "Activity detected since last run; inhibiting suspend" >> "$LOG"
    inhibit_suspend
fi

EDIT 2: Le script ci-dessus fonctionne mais grâce à un autre commentaire ci-dessous, j'utilise maintenant cette paire de scripts, qui ont l'avantage de permettre à l'économiseur d'écran de se déclencher pendant que j'inhibe la suspension. Le premier est /usr/lib/pm-utils/sleep.d/000nfs-inhibit, ce qui empêchera une tentative de suspension s'il existe un fichier d'inhibition:

#!/bin/sh

LOG="/home/zorn/log/nfs-suspend-blocker.log"
INHIBITFILE="/home/zorn/tmp/nfs-suspend-blocker.inhibit"

echo "$0: Started run at $(date), arguments: $*" >> "$LOG"
if [ "$1" = "suspend" ] && [ -f "$INHIBITFILE" ]; then
    echo "$0: Inhibiting suspend" >> "$LOG"
    exit 1
fi
exit 0

Le second est une version modifiée du script nfs-suspend-blocker précédent et doit toujours être exécuté à partir de cron. Il suit maintenant la stratégie décrite dans le commentaire ci-dessous:

#!/bin/bash

# This works in tandem with /usr/lib/pm-utils/sleep.d/000nfs-inhibit, which
# will prevent a suspend occurring if $INHIBITFILE is present. Once it prevents
# a suspend, it appears that it requires some "user activity" to restart the
# timer which will cause a subsequent suspend attempt, so in addition to
# creating or removing $INHIBITFILE this script also jiggles the mouse after
# removing the file to restart the timer.

# If the output of this function changes between two successive runs of this
# script, we inhibit auto-suspend.
function check_activity()
{
    /usr/sbin/nfsstat --server --list
}

# Slightly jiggle the mouse pointer about; we do a small step and reverse step
# to try to stop this being annoying to anyone using the PC.
function jiggle_mouse()
{
    export DISPLAY=:0.0
    xdotool mousemove_relative --sync --  1  1
    xdotool mousemove_relative --sync -- -1 -1
}

LOG="$HOME/log/nfs-suspend-blocker.log"
ACTIVITYFILE1="$HOME/tmp/nfs-suspend-blocker.current"
ACTIVITYFILE2="$HOME/tmp/nfs-suspend-blocker.previous"
INHIBITFILE="$HOME/tmp/nfs-suspend-blocker.inhibit"

echo "$0: Started run at $(date)" >> "$LOG"
if [ ! -f "$ACTIVITYFILE1" ]; then
    check_activity > "$ACTIVITYFILE1"
    exit 0;
fi

/bin/mv "$ACTIVITYFILE1" "$ACTIVITYFILE2"
check_activity > "$ACTIVITYFILE1"

if cmp --quiet "$ACTIVITYFILE1" "$ACTIVITYFILE2"; then
    echo "$0: No activity detected since last run" >> "$LOG"
    if [ -f "$INHIBITFILE" ]; then
            echo "$0: Removing suspend inhibit file and jiggling mouse" >> "$LOG"
            /bin/rm "$INHIBITFILE"
            jiggle_mouse
    fi
else
    echo "$0: Activity detected since last run; inhibiting suspend" >> "$LOG"
    touch "$INHIBITFILE"
fi
Zorn
la source
Plutôt que d'encombrer la question, vous devriez mettre vos deux solutions au problème comme réponse ci-dessous.
Cas

Réponses:

8

Un programme pour garder votre ordinateur éveillé est la caféine . Je créerais un fichier .bash_aliases pour appeler également la caféine lorsque votre code d'origine est appelé.

alias newname="origcode && caffeine"

Selon le code pour lequel vous essayez de garder votre ordinateur éveillé, vous devrez créer un script personnalisé qui comprend la destruction de la caféine lorsque l'autre code est arrêté. Quelques détails supplémentaires sur le code particulier seraient utiles.

Mise à jour: Une manière plus simple serait d'exécuter xdotool , qui peut être installé avec sudo apt-get install xdotool. Vous pouvez écrire un script qui est appelé lorsque votre code cible est ouvert, puis utiliser la sleepcommande pendant 29 minutes, puis exécuter xdotool key aou quelque chose d'arbitraire pour garder l'ordinateur éveillé.

philshem
la source
2
Pour xdo, il est probablement préférable de choisir une clé qui ne fait rien en soi. Appuyer sur Maj, par exemple, réveillera l'écran sans taper sur la fenêtre active.
Oli
1
Je vous remercie. Je cachais délibérément un peu de détails dans la question d'origine - ce que je veux explicitement faire, c'est arrêter mon PC (qui diffuse du contenu multimédia via NFS) pendant que mon centre multimédia y accède. Si vous connaissez un moyen de résoudre spécifiquement ce problème, ce serait formidable, sinon je peux voir quelques pistes qui permettront à cela de fonctionner via la caféine (par exemple, le centre des médias ssh dans mon PC toutes les 10 minutes et exécutera un script shell qui dort Pour 15 minutes).
Zorn
1
J'ai essayé la caféine et cela semble fonctionner, sauf qu'une fois que le programme en cours d'exécution a disparu, la sortie de caféine indique que la suspension n'est plus inhibée mais je l'ai laissé pendant deux fois la période d'inactivité et bien que l'écran suspendu, le PC ne l'a jamais fait. Je vais continuer à jouer avec cela, bien que la route xdo soit probablement encore plus pratique et je vais l'essayer en premier. PS Existe-t-il un moyen d'insérer une nouvelle ligne dans un commentaire?!
Zorn
5

Si

  1. Un script dans /usr/lib/pm-utils/sleep.d peut vérifier si l'application est en cours d'exécution et retourner 1 pour indiquer que la suspension doit être empêchée.
  2. Le problème de "le système abandonne alors la suspension automatiquement, au lieu de réessayer après 30 minutes supplémentaires" est résolu en déplaçant la souris qui redémarre le chronomètre (j'espère avoir bien compris ce que vous entendez par là)

alors pourquoi ne pas simplement bouger le pointeur de la souris après la fin de l'application.

Pour résumer:

  1. Utilisez sleep.d pour empêcher le système de se suspendre.
  2. Écrivez un script qui fait bouger la souris une fois.
  3. Appelez 'Long-running-script && mousejiggle'

Cela n'entravera pas l'économiseur d'écran.

Le seul problème est que ce sera 30 minutes après la fin du processus lorsque le système se suspend. C'est également le cas avec votre solution 'EDIT'.

PS: Je cherchais une solution à un problème similaire lorsque j'ai découvert xdotool sur cette page. Donc merci. J'espère que cela t'aides.

S Prasanth
la source
Ingénieux, merci! Je vais essayer ce week-end.
Zorn
L'indice concernant pm-utilsaidé. Notez que le package pm-utilsdoit être installé pour que cela fonctionne - le répertoire lui-même peut exister même si le package n'est pas installé.
krlmlr
1

Bien que EDIT 2 permette à l'économiseur d'écran de démarrer et reprend le service de suspension automatique lors de la suppression du fichier d'inhibition, comme indiqué ci-dessus, il faudra 30 minutes après la suppression du fichier lorsque le système sera suspendu.

Une solution possible consiste à désactiver la fonction d'économiseur d'écran et de suspension automatique intégrée et à les implémenter nous-mêmes, et à choisir le comportement du minuteur selon les besoins. La commande xprintidle(vous devrez peut-être l'installer) imprime le nombre de millisecondes pour lesquelles il n'y a eu aucune activité de clavier ou de souris. Cela ouvre plusieurs possibilités. J'ai implémenté le gestionnaire d'inactivité suivant en python (pas trop de script bash). Les fonctionnalités incluent la définition de la commande, du délai d'expiration et du fichier d'inhibition (je l'ai appelé verrou) pour l'économiseur d'écran et / ou la suspension automatique. De plus, il est possible de choisir si le minuteur d'inactivité doit redémarrer lorsque le fichier d'inhibition est supprimé ou non (le comportement peut être différent pour la suspension et l'économiseur d'écran). J'ai essayé de clarifier l'utilisation dans les notes, mais si quelque chose n'est pas clair, demandez.

#!/usr/bin/python

#Notes:##################

#   1. All TIMEOUTs are specified in seconds
#   2. 0 or negative TIMEOUT disables a particular action.
#   3. If an actionCOMMAND (like pm-suspend) requires 'sudo'ing, make them 'sudo'able without password. Alternatively, you may run this script in sudo mode, and make this script sudoable without password. /ubuntu/159007/specific-sudo-commands-without-password
#   4. 'action'_timer_starts_... option: True - if a lock file is created and then removed, inactivity timer (for that action) restarts at the time of deletion of lock. False - doesn't restart.
#   5. screensaverCOMMAND can be screen-lock (security) or screen-off (power saving) or both. To do both, but at different times (I can't see any reason to do so) extend this script from two actions (screensaver, autosuspend) to three (screen-lock, screen-off, autosuspend).

#########################

import os
import time
import threading
import subprocess

HOME = os.getenv('HOME') + '/'

#Configuration###########

screensaverCOMMAND = "gnome-screensaver-command --lock && xset -display :0.0 +dpms dpms force off"
autosuspendCOMMAND = "gnome-screensaver-command --lock && sudo pm-suspend"

screensaverTIMEOUT = 10*60
autosuspendTIMEOUT = 20*60

screensaverLOCK = HOME + ".inactivitymanager/screensaverLOCK"
autosuspendLOCK = HOME + ".inactivitymanager/autosuspendLOCK"

screensaver_timer_starts_only_after_lockfile_is_deleted = False
autosuspend_timer_starts_only_after_lockfile_is_deleted = False

#########################

def stayOn():
    print "inactivitymanager is running..."
    try:
        while True:
            time.sleep(10)
    except:
        print "Closed."

class inactivity_action(threading.Thread):
    def __init__(self, command, timeout, lock, timer_starts_blah):
        threading.Thread.__init__(self)
        self.daemon = True
        self.command = command
        self.timeout = timeout
        self.lock = lock
        self.timer_starts_blah = timer_starts_blah
    def run(self):
        if not(self.timer_starts_blah):
            while True:
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                except IOError:
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if xidletime > self.timeout:
                        os.system(self.command)
                    else:
                        time.sleep(self.timeout - xidletime + 2)
        else:
            lockremovetime = 0
            while True:
                lockdetected = False
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                        lockdetected = True
                except IOError: #Will enter this section if/when lockfile is/becomes absent
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if lockdetected:
                        lockremovetime = int(time.time())
                    timesincelockremove = int(time.time()) - lockremovetime
                    if min(xidletime, timesincelockremove) > self.timeout:
                        os.system(self.command)

if screensaverTIMEOUT > 0:
    inactivity_screensaver = inactivity_action(screensaverCOMMAND, screensaverTIMEOUT, screensaverLOCK, screensaver_timer_starts_only_after_lockfile_is_deleted)
    inactivity_screensaver.start()

if autosuspendTIMEOUT > 0:
    inactivity_autosuspend = inactivity_action(autosuspendCOMMAND, autosuspendTIMEOUT, autosuspendLOCK, autosuspend_timer_starts_only_after_lockfile_is_deleted)
    inactivity_autosuspend.start()

stayOn()

Usage:

  1. Ajoutez simplement inactivitymanager &à .profile ou .xsessionrc dans le répertoire personnel (voyez celui qui vous convient. N'ajoutez pas les deux, sinon deux instances de ce script s'exécuteront simultanément, quelque chose que je n'ai pas géré. Je suppose que c'est dans ces détails que les implémentations traditionnelles l'emportent sur celles personnalisées).
  2. Vous devrez peut-être installer xprintidle.

La façon dont le fichier d'inhibition y parvient est laissée à l'imagination de l'utilisateur pour l'instant (si je me résous à implémenter un démon pour cela, je mettrai cela dans un EDIT à cette réponse). Vous (OP) l'avez bien sûr résolu pour votre cas. Un écueil à éviter en essayant d'inhiber la suspension de plusieurs processus est la suppression du fichier de verrouillage lorsqu'un processus se termine alors qu'un autre est toujours en cours d'exécution. Alternativement, le script peut être légèrement modifié pour empêcher la suspension si un fichier existe dans un répertoire particulier (un répertoire de verrouillage). De cette façon, chaque processus peut avoir son propre fichier de verrouillage.

Remarques:

  1. Ce script est assez léger sur le processeur et la mémoire. Mais la suppression des time.sleep (1) s dans le code peut causer des problèmes - mais je n'ai pas vérifié.
  2. pm-suspend nécessite des autorisations sudo. Vers pm-suspend sans donner de mot de passe checkout Comment exécuter des commandes sudo spécifiques sans mot de passe? . Alternativement, vous pouvez exécuter ce script en mode sudo et rendre ce script sudoable sans mot de passe (pas de problème si vous exécutez le script en tant que root)
  3. Le script peut rencontrer des problèmes si les délais d'attente sont définis pour être inférieurs à ~ 10 secondes (je n'ai pas vérifié où exactement le problème doit commencer à être inférieur à 5, je suppose). Cela peut être géré en supprimant certains time.sleep (1) s au détriment des ressources système. Mais ne pensez pas que quiconque en aura besoin.
  4. Parce que nous avons une poignée sur les minuteries, aucun déplacement de souris requis!
S Prasanth
la source