Como inibir suspender temporariamente?


10

Pesquisei um pouco isso e não consigo encontrar nada útil.

Eu tenho meu PC executando o Ubuntu 12.10 configurado para suspender após 30 minutos de inatividade. Não quero mudar isso, funciona muito bem na maioria das vezes.

O que eu quero fazer é desativar a suspensão automática se um aplicativo específico estiver em execução. Como posso fazer isso?

A coisa mais próxima que encontrei até agora é adicionar um script de shell no /usr/lib/pm-utils/sleep.dqual verifica se o aplicativo está sendo executado e retorna 1 para indicar que a suspensão deve ser evitada. Mas parece que o sistema desiste de suspender automaticamente, em vez de tentar novamente após mais 30 minutos. (Pelo que sei, se eu mover o mouse, isso reiniciará o timer novamente.) É bem provável que o aplicativo termine após algumas horas, e prefiro que meu PC seja suspenso automaticamente se não estiver usando nesse ponto . (Portanto, não quero adicionar uma chamada para pm-suspende quando o aplicativo terminar.)

Isso é possível?

EDIT: Como observei em um dos comentários abaixo, o que eu realmente queria era inibir a suspensão quando meu PC estava servindo arquivos pelo NFS; Eu só queria me concentrar na parte "suspender" da pergunta, porque eu já tinha uma idéia de como resolver a parte do NFS. Usando a idéia do 'xdotool' dada em uma das respostas, criei o seguinte script, que corro a partir do cron a cada poucos minutos. Não é o ideal, pois impede que o protetor de tela seja ativado, mas funciona. Eu preciso dar uma olhada no porquê 'cafeína' não reativar corretamente a suspensão mais tarde, então provavelmente poderia fazer melhor. De qualquer forma, isso parece funcionar, então eu estou incluindo aqui caso alguém mais esteja interessado.

#!/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

EDIÇÃO 2: O script acima funciona, mas graças a outro comentário abaixo, agora estou usando este par de scripts, que têm a vantagem de permitir que o protetor de tela seja ativado enquanto inibir a suspensão. O primeiro é /usr/lib/pm-utils/sleep.d/000nfs-inhibit, que impedirá uma tentativa de suspensão se existir um arquivo de inibição:

#!/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

A segunda é uma versão modificada do script nfs-suspend-blocker anterior e ainda deve ser executada a partir do cron. Agora, segue a estratégia descrita no comentário abaixo:

#!/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

Em vez de desordenar a pergunta, você deve colocar suas duas soluções para o problema como resposta abaixo.
Cas

Respostas:


8

Um programa para manter seu computador acordado é a cafeína . Eu criaria um arquivo .bash_aliases para também chamar cafeína quando o código original for chamado.

alias newname="origcode && caffeine"

Dependendo do código para o qual você está tentando manter o computador acordado, será necessário criar um script personalizado que inclua a interrupção da cafeína quando o outro código for parado. Mais alguns detalhes sobre o código específico ajudariam.

Atualização: Uma maneira mais simples seria executar o xdotool , que pode ser instalado com sudo apt-get install xdotool. Você pode escrever um script chamado quando o código de destino é aberto e, em seguida, usar o sleepcomando por 29 minutos e executar xdotool key aou algo arbitrário para manter o computador acordado.


2
Para o xdo, provavelmente é melhor escolher uma chave que não faça algo inerentemente. Pressionar shift, por exemplo, ativará a tela sem digitar na janela ativa.
Oli

11
Obrigado. Eu estava deliberadamente escondendo um pouco de detalhes na pergunta original - o que eu quero fazer explicitamente é interromper a suspensão do meu PC (que está exibindo conteúdo de mídia via NFS) enquanto minha central de mídia está acessando. Se você conhece uma maneira de lidar especificamente com isso, seria ótimo; caso contrário, posso ver algumas avenidas que permitirão que isso funcione via cafeína (por exemplo, a central multimídia entrará no meu PC a cada 10 minutos e executará um shell script que dorme durante 15 minutos).
Zorn

11
Eu tentei o Caffeine e ele parece funcionar, exceto que, uma vez que o programa em execução desaparece, a saída do Caffeine diz que a suspensão não é mais inibida, mas eu o deixei por duas vezes o período de inatividade e, embora a tela tenha suspendido o PC, nunca o fez. Vou brincar com isso ainda mais, embora a rota xdo provavelmente seja ainda mais conveniente e tentarei isso primeiro. PS Existe alguma maneira de inserir uma nova linha em um comentário ?!
Zorn

5

E se

  1. Um script em /usr/lib/pm-utils/sleep.d pode verificar se o aplicativo está em execução e retornar 1 para indicar que a suspensão deve ser evitada.
  2. O problema de "o sistema desiste de suspender automaticamente, em vez de tentar novamente após mais 30 minutos" é resolvido movendo o mouse que reinicia o temporizador novamente (espero ter entendido corretamente o que você quer dizer com isso)

então por que não apenas apontar o ponteiro do mouse após o término do aplicativo?

Para resumir:

  1. Use sleep.d para impedir a suspensão do sistema.
  2. Escreva um script que agite o mouse uma vez.
  3. Chame 'Script de execução longa && mousejiggle'

Isso não impedirá o protetor de tela.

O único problema é que serão 30 minutos após o término do processo quando o sistema for suspenso. Este é o caso da sua solução 'EDIT' também.

PS: Eu estava procurando uma solução para um problema semelhante quando soube do xdotool nesta página. Então obrigado. Espero que isto ajude.


Engenhoso, obrigado! Vou dar uma chance neste fim de semana.
Zorn

A dica sobre pm-utilsajudou. Observe que o pacote pm-utilsprecisa ser instalado para que isso funcione - o próprio diretório pode existir mesmo que o pacote não esteja instalado.
krlmlr

1

Embora a EDIT 2 permita que o protetor de tela inicie e reinicie o serviço de suspensão automática na remoção do arquivo de inibição, conforme observado acima, serão 30 minutos após a remoção do arquivo quando o sistema será suspenso.

Uma solução possível é desativar a funcionalidade de proteção automática de tela e suspensão automática incorporada e implementá-las por conta própria, e escolher o comportamento do cronômetro, conforme necessário. O comando xprintidle(pode ser necessário instalar isso) imprime o número de milissegundos para os quais não houve atividade de teclado ou mouse. Isso abre várias possibilidades. Eu implementei o seguinte gerenciador de inatividade em python (não é muito um script de bash). Os recursos incluem definir o comando, tempo limite e inibir o arquivo (eu chamei de bloqueio) para proteção de tela e / ou suspensão automática. Além disso, existe a opção de escolher se o timer de inatividade deve reiniciar quando o arquivo de inibição é removido ou não (o comportamento pode ser diferente para suspender e proteção de tela). Tentei esclarecer o uso nas notas, mas se algo não estiver claro, pergunte.

#!/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()

Uso:

  1. Basta adicionar inactivitymanager &a .profile ou .xsessionrc no diretório inicial (veja qual funciona para você. Não adicione os dois; caso contrário, duas instâncias desse script serão executadas simultaneamente, algo que eu não lidei. Acho que está nesses detalhes que as implementações convencionais superam as personalizadas).
  2. Pode ser necessário instalar o xprintidle.

Como o arquivo de inibição chega lá fica para a imaginação do usuário por enquanto (se eu me propuser a implementar um daemon para isso, colocarei isso em um EDIT para esta resposta). É claro que você (OP) resolveu o problema para o seu caso. Uma armadilha a evitar ao tentar inibir a suspensão por mais de um processo é excluir o arquivo de bloqueio quando um processo termina enquanto outro ainda está em execução. Como alternativa, o script pode ser editado levemente para inibir a suspensão, se houver algum arquivo em um diretório específico (um diretório de bloqueio). Dessa forma, cada processo pode ter seu próprio arquivo de bloqueio.

Notas:

  1. Este script é bastante claro sobre o processador e a memória. Mas remover o time.sleep (1) s no código pode causar problemas - ainda não foi verificado.
  2. pm-suspend requer permissões sudo. Para suspender pm sem fornecer verificação de senha Como executo comandos sudo específicos sem uma senha? . Como alternativa, você pode executar esse script no modo sudo e torná-lo sudoable sem senha (não é um problema se você estiver executando o script como root)
  3. O script pode ter problemas se o tempo limite for menor que ~ 10 segundos (não verifique onde exatamente o problema começa deve ser menor que 5, eu acho). Isso pode ser resolvido com a remoção de alguns time.sleep (1) s à custa dos recursos do sistema. Não pense que alguém vai precisar disso.
  4. Como temos um controle sobre os cronômetros, não é necessário nenhum ajuste de mouse!
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.