GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cuándo se maneja una señal y por qué alguna información se congela?

termA no se congela. Solo muestra la devolución de llamada en el cuadro de entrada. Simplemente presione el Enter tecla para continuar con la entrada.


Antes de explicar tu problema, un poco de contexto sobre cómo read el comando funciona. Lee los datos de entrada de stdin hasta el EOF se encuentra Es seguro decir la llamada a read El comando no bloquea cuando se trata de leer archivos en el disco. Pero cuando stdin está conectado a la terminal, el comando se bloqueará hasta que el usuario escriba algo.

¿Cómo funcionan los controladores de señales?

Una explicación simple sobre cómo funciona el manejo de la señal. Vea el siguiente fragmento en C que solo actúa sobre SIGINT (también conocido como CTRL+C )

#include <stdio.h>
#include <signal.h>

/* signal handler definition */
void signal_handler(int signum){
  printf("Hello World!\n");
}

int main(){
  //Handle SIGINT with a signal handler
  signal(SIGINT, signal_handler);
  //loop forever!
  while(1);
}

Registrará el manejador de señal y luego entrará en el bucle infinito. Cuando lleguemos a Ctrl-C , todos podemos estar de acuerdo en que el controlador de señal signal_handler() debe ejecutar y "Hello World!" imprime en la pantalla, pero el programa estaba en un ciclo infinito. Para imprimir "Hello World!" debe haber sido el caso que rompió el bucle para ejecutar el controlador de señal, ¿verdad? Por lo tanto, debería salir del bucle y del programa. Veamos:

gcc -Wall -o sighdl.o signal.c
./sighdl.o 
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!

Como indica el resultado, cada vez que emitimos Ctrl-C , "Hello World!" imprime, pero el programa vuelve al bucle infinito. Es solo después de emitir un SIGQUIT señal con Ctrl-\ ¿Salió realmente el programa? Dependiendo de tu ulimit configuraciones, volcaría un núcleo o imprimiría el número de señal recibido.

Si bien la interpretación de que el ciclo saldría es razonable, no considera la razón principal para el manejo de la señal, es decir, el manejo de eventos asincrónicos. Eso significa que el manejador de señales actúa fuera del flujo estándar del control del programa; de hecho, todo el programa se guarda dentro de un contexto, y se crea un nuevo contexto solo para que se ejecute el controlador de señal. Una vez que el controlador de señal ha completado sus acciones, el contexto se vuelve a cambiar y comienza el flujo de ejecución normal (es decir, el while(1) ).

Para responder a sus preguntas,

La conclusión verificó que cuando bash está ejecutando un comando externo en primer plano, no maneja ninguna señal recibida hasta que finaliza el proceso en primer plano

Lo más importante a tener en cuenta aquí es el externo parte de mando. En el primer caso, donde sleep es un proceso externo pero en el segundo caso, read es un incorporado desde el propio shell. Entonces, la propagación de la señal a estos dos difiere en ambos casos

type read
read is a shell builtin
type sleep
sleep is /usr/bin/sleep

1. Abra una terminal, llamada termA, y ejecute el archivo creado callback.sh con /bin/bash callback.sh por primera vez, la información aparecerá instantáneamente.

Sí, este comportamiento es el esperado. Porque en este momento solo se define la función y el controlador de trampas está registrado en la función myCallback y la señal aún no se recibe en el script. A medida que avanza la secuencia de ejecución, el mensaje del read se lanza el aviso por primera vez.

2.Abra una nueva terminal, llamada termB y ejecute pkill -USR1 -f callback.sh primera vez, la información aparece instantáneamente en termA

Sí, mientras que el read el comando está esperando una cadena seguida de Enter pulsación de tecla que señala el EOF , recibe una señal SIGUSR1 desde el otro terminal, el contexto de ejecución actual se guarda y el control cambia al controlador de señal que imprime la cadena con la fecha actual.

Tan pronto como el controlador termina de ejecutarse, el contexto se reanuda en el while bucle en el que read el comando todavía está esperando una cadena de entrada. Hasta el read el comando es exitoso, todas las trampas de señal posteriores simplemente imprimirán la cadena dentro del controlador de señal.

Continúe en el término B, ejecute pkill -USR1 -f callback.sh la segunda vez.

Igual que se explicó anteriormente, el read El comando no está completo por una vez en su bucle while, solo si tiene éxito al leer una cadena, la siguiente iteración del bucle comenzará y se lanzará un nuevo mensaje de aviso.

Fuente de la imagen:La interfaz de programación de Linux por Michael KerrisK


La conclusión verificó que cuando bash está ejecutando un comando externo en primer plano, no maneja ninguna señal recibida hasta que finaliza el proceso en primer plano.

bash lo hace manejar las señales en C / nivel de implementación, pero no ejecutará los controladores establecidos con trap hasta que el proceso de primer plano haya terminado. Eso es requerido por el estándar:

When a signal for which a trap has been set is received while the shell is waiting for the completion of a utility executing a foreground command, the trap associated with that signal shall not be executed until after the foreground command has completed.

Tenga en cuenta que el estándar no hace ninguna diferencia entre comandos internos y externos; en el caso de una "utilidad" como read , que no se ejecuta en un proceso separado, no es obvio si una señal ocurre en su "contexto" o en el del shell principal, y si un controlador se establece con trap debe ejecutarse antes o después del read regresa.

problema 1:callback.sh contiene un ciclo while infinito, cómo explicar que no maneja ninguna señal recibida hasta que finaliza el proceso en primer plano. En este caso, el proceso en primer plano nunca termina.

Eso está mal. bash no está ejecutando el while bucle en un proceso separado. Dado que no hay un proceso en primer plano bash está esperando, puede ejecutar cualquier conjunto de controladores con trap inmediatamente. Si read fuera un comando externo, eso y no while sería el proceso de primer plano.

problema 2:No please input something for foo: shown en el término A;

vaya a termB, ejecute pkill -USR1 -f callback.sh la tercera vez.

La siguiente información se muestra en termA nuevamente:callback function called at Mon Nov 19 09:07:24 HKT 2018

Todavía no please input something for foo: se muestra en el término A. Por qué la información please input something for foo: ¿congelarse?

No se congela. Simplemente presione Entrar y volverá a aparecer.

Es simplemente que

a) bash reiniciará el read incorporado en su lugar cuando es interrumpido por una señal, no regresará y volverá a pasar por el while bucle

b) no volverá a mostrar el aviso establecido con -p en ese caso.

Note que bash ni siquiera volverá a mostrar el aviso en el caso de que SIGINT desde el teclado fue manejado, incluso si descarta la cadena leída hasta ahora del usuario:

$ cat goo
trap 'echo INT' INT
echo $$
read -p 'enter something: ' var
echo "you entered '$var'"

$ bash goo
24035
enter something: foo<Ctrl-C>^CINT
<Ctrl-C>^CINT
<Ctrl-C>^CINT
bar<Enter>
you entered 'bar'

Eso imprimirá you entered 'foobar' si la señal fue enviada desde otra ventana con kill -INT <pid> en lugar de con Ctrl-C de la terminal

Todo el material de esta última parte (cómo read se interrumpe, etc) es muy bash específico. En otros shells como ksh o dash , e incluso en bash cuando se ejecuta en modo POSIX (bash --posix ), cualquier señal manejada en realidad interrumpirá el read incorporado. En el ejemplo anterior, el shell imprimirá you entered '' y salir después del primer ^C, y si el read se llama desde un bucle, el bucle se reiniciará.


Linux
  1. ¿Qué es un servidor Linux y por qué su negocio necesita uno?

  2. ¿Qué significa Env X=() { ::}; Command' Bash Do y por qué es inseguro?

  3. ¿Cuándo y por qué debo usar Apt-get Update?

  4. ¿Qué hace un programa cuando se envía una señal Sigkill?

  5. ¿Por qué se recomienda crear un grupo y un usuario para algunas aplicaciones?

¿Por qué algunos emoji en blanco y negro y otros son demasiado grandes?

¿Cuándo es útil setsid() o por qué necesitamos agrupar procesos en Linux?

¿Por qué stdout necesita un vaciado explícito cuando se redirige al archivo?

¿Por qué clang genera texto ininteligible cuando se redirige?

¿Qué hace 'set -e' y por qué podría considerarse peligroso?

Reenvío de IP =¿cuándo y por qué es necesario?