Por que o SIGSTOP não funciona dentro da sessão de tela?

2

Considere o seguinte script:

#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP $$
echo 'after stop' > ${OFILE}

Em um shell interativo, o script é interrompido e a saída é ok . No entanto, se for iniciado como

screen -d -m ./test.sh

a saída é after stop . A tela manipula o sinal? Como suspender um processo em uma sessão de tela?

    
por Andrey 05.11.2015 / 04:50

2 respostas

1

O exame do código-fonte do GNU screen-4.0.2 mostrou essa tela verifica se seus processos filhos estão parados e, em seguida, tenta reativá-los com SIGCONT. Aqui está uma parte relevante do screen.c :

1561 if (WIFSTOPPED(wstat))
1562   {   
1563     debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
....
1578     /* Try to restart process */
1579     Msg(0, "Child has been stopped, restarting.");
1580     if (killpg(p->w_pid, SIGCONT))
1581       kill(p->w_pid, SIGCONT);
1582   }   

Parece que esse comportamento não pode ser alterado com uma opção ou por meio de um arquivo de configuração. A solução sugerida para interromper o processo de tela pode ter efeitos colaterais indesejáveis. Uma abordagem melhor é ocultar o processo interrompido da tela. Para um script bash, isso pode ser feito com um subshell:

#!/bin/bash
(   
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP ${BASHPID}
echo 'after stop' > ${OFILE}
)   

Para outras camadas, pode não ser tão simples, por exemplo para tcsh:

#!/bin/tcsh
(\  
set OFILE='log' ;\
echo 'ok' > ${OFILE} ;\
kill -STOP 'exec sh -c 'echo ${PPID}'' ;\
echo 'after stop' > ${OFILE} \
)   

A principal diferença é o método para obter o PID do subshell, mais informações aqui .

Como alternativa, o script pode ser iniciado sem modificação com um script wrapper :

#!/bin/bash
SCRIPTDIR="$(dirname "$(readlink -f -n "$0")")"
${SCRIPTDIR}/test.sh

Para executar:

screen -d -m ./wrapper.sh
    
por 05.11.2015 / 21:58
1

Provavelmente, o processo de tela está reiniciando o processo bash parado. Eu tentei seguir (enviando sinal SIGSTOP para ambos os processos):

test.sh

#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
echo 'screen pid ' $(screen -list | grep sc_test | cut -f1 -d'.' | sed 's/\W//g') >> ${OFILE}
echo 'test.sh pid ' $$ >> ${OFILE}
kill -SIGSTOP $(screen -list | grep sc_test | cut -f1 -d'.' | sed 's/\W//g')
kill -SIGSTOP $$
echo 'after stop' >> ${OFILE}

comando de tela

screen -dmS sc_test ./test.sh

arquivo de log

ok
screen pid  4453
test.sh pid  4454

listando telas

screen -list
There is a screen on:
        4453.sc_test    (11/05/2015 10:45:20 AM)        (Detached)
1 Socket in /var/run/screen/S-root.
    
por 05.11.2015 / 09:00