AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 789413
Accepted
Yakog
Yakog
Asked: 2025-01-12 09:36:22 +0800 CST2025-01-12 09:36:22 +0800 CST 2025-01-12 09:36:22 +0800 CST

Por que um sinal SIGTSTP não manipulado pelo pai move todo o grupo para segundo plano (ao contrário do que está escrito no TTY desmistificado)?

  • 772

Comecei a aprender sobre tty(s) e sinais do Linux e tive alguns problemas.

Estou lendo e usando o livro The TTY demystified como referência.

Criei dois programas simples de golang.

Pai:

package main

import (
    "fmt"
    "syscall"
    "time"
)

func main() {
    attr := &syscall.ProcAttr{
        Files: []uintptr{0, 1, 2},
    }

    _, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    for {
        fmt.Println("hi from parent")
        time.Sleep(time.Second * 10)
    }
}

Criança:

package main

import (
    "fmt"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    signal.Ignore(syscall.SIGTSTP) // golang's way to handle (ignore) signal

    for {
        fmt.Println("hi from child")
        time.Sleep(time.Second * 5)
    }
}

Eles são bem simples. Ambos apenas imprimem uma mensagem para tty a cada 5/10 segundos. A única diferença é que o filho ignora o sinal SIGTSTP (ctrl-z). Então, quando eu pressiono ctrl-z, ele suspende o pai, mas não o filho. É exatamente o que eu esperava. No entanto, o que eu não esperava é que todo o grupo fosse movido do primeiro plano para o grupo de segundo plano. Isso contrasta com The TTY demystified . Especificamente:

Quando todos os processos no trabalho em primeiro plano foram suspensos , o líder da sessão lê a configuração atual do dispositivo TTY e a armazena para recuperação posterior. O líder da sessão continua a se instalar como o grupo de processos em primeiro plano atual para o TTY usando uma chamada ioctl. Então, ele imprime algo como "[1]+ Stopped" para informar ao usuário que um trabalho foi suspenso.

Ele diz que somente quando todos os processos no trabalho em primeiro plano forem suspensos , o líder da sessão (shell/bash) moverá o grupo para o trabalho em segundo plano...

Resultado de ps l -t /dev/pts/0antes e depois de ctrl-z:

yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
0  1000 1747467 1747441  20   0  14288  5632 do_wai Ss   pts/0      0:00 bash
0  1000 1747496 1747467  20   0 1225432 1792 ep_pol Sl+  pts/0      0:00 ./parent
0  1000 1747501 1747496  20   0 1225424 1664 ep_pol Sl+  pts/0      0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
0  1000 1747467 1747441  20   0  14288  5632 do_sel Ss+  pts/0      0:00 bash
0  1000 1747496 1747467  20   0 1225432 1792 do_sig Tl   pts/0      0:00 ./parent
0  1000 1747501 1747496  20   0 1225680 1792 ep_pol Sl   pts/0      0:00 child

Se eu mover o ignore ( signal.Ignore(syscall.SIGTSTP)) do filho para o pai, então tudo funciona como deveria (do meu ponto de vista). O filho suspende (T), o pai retoma normalmente (R/S), mas o grupo ainda é o trabalho de primeiro plano.

yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
0  1000 1749437 1749410  20   0  14420  5632 do_wai Ss   pts/0      0:00 bash
0  1000 1749957 1749437  20   0 1225448 1920 ep_pol Sl+  pts/0      0:00 ./parent
0  1000 1749962 1749957  20   0 1225412 1664 ep_pol Sl+  pts/0      0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
0  1000 1749437 1749410  20   0  14420  5632 do_wai Ss   pts/0      0:00 bash
0  1000 1749957 1749437  20   0 1225448 1920 ep_pol Sl+  pts/0      0:00 ./parent
0  1000 1749962 1749957  20   0 1225668 1792 do_sig Tl+  pts/0      0:00 child

Por que isso está acontecendo? O que estou perdendo?

bash
  • 1 1 respostas
  • 58 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2025-01-12T17:17:30+08:002025-01-12T17:17:30+08:00

    Quando todos os processos no trabalho em primeiro plano forem suspensos, o líder da sessão...

    É impreciso em duas frentes:

    • O controle de job é feito (ativamente) por shells, não (automaticamente) por líderes de sessão . Um shell não precisa ser um líder de sessão para fazer o controle de job.

      Quando você inicia xterm, xtermexecuta seu shell (por padrão) no novo processo que ele inicia em uma nova sessão e que controlará o dispositivo escravo pseudo-terminal. Então esse shell será o líder da sessão. Mas se você iniciar outro shell interativo a partir desse shell, ele não será o líder da sessão, mas assumirá o controle do job.

    • Quando um shell bifurca um processo shell e executa um comando nele, ele não tem visibilidade sobre os processos que esse processo em si gera. Ao executar um job em primeiro plano, o shell espera pelo(s) processo(s) que ele mesmo iniciou ¹.

      Se esse processo de nível superior for suspenso, o wait*()retornará, ou o shell receberá um SIGCHLD², que o shell interpretará como se o trabalho tivesse sido suspenso (independentemente de ainda haver processos em execução naquele trabalho dos quais ele não pode saber) e informará ao driver de dispositivo tty que ele não deve mais ficar em primeiro plano (colocando seu próprio grupo de processos em primeiro plano). Mas se for um filho desse processo que está suspenso, o SIGCHLD é enviado para seu pai, não para o shell, o shell não receberá um SIGCHLD e o que wait*()ele fizer no processo que ele conhece não retornará.


    ¹ em alguns shells, nem mesmo todos, por exemplo em cmdA | cmdB, alguns shells esperam apenas o processo em execução cmdB, enquanto alguns esperam tanto o que está em execução cmdAquanto o que está executando cmdB, então no primeiro tipo (como com boshbase no Bourne shell), se você pressionar Ctrl+ zem (trap '' TSTP; sleep 100) | sleep 42, você encontrará sleep 42suspenso e sleep 100não, mas você ainda retornará ao prompt com sleep 100agora em execução em segundo plano (e sua eventual morte não será tratada até que você execute fg) e sleep 42suspenso.

    ² Alguns shells usam uma das wait*()chamadas de sistema, alguns usam manipuladores no SIGCHLD usando a sigaction()API mais recente, onde os manipuladores obtêm informações completas sobre o status dos processos, YMMV, mas o resultado final é o mesmo.

    • 0

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve