¿Qué es una llamada al sistema de interrupción?
La llamada interrupción se refiere a la respuesta de la CPU a un evento en el sistema. La CPU suspende el programa en ejecución, retiene la escena y cambia automáticamente para ejecutar el programa de procesamiento correspondiente. Después de manejar el evento, regresa al punto de interrupción y continúa la ejecución del programa interrumpido.
Las interrupciones se pueden dividir en tres categorías. El primer tipo es causado por el exterior de la CPU, llamado interrupciones, como interrupciones de E/S, interrupciones de reloj, interrupciones de consola, etc. La segunda categoría son los procesos causados por eventos internos de la CPU o eventos durante la ejecución del programa, que se denominan excepciones, como fallas de la CPU (el voltaje de la fuente de alimentación es inferior a 105 V o la frecuencia está fuera de 47 ~ 63 Hz), fallas del programa ( código de operación ilegal, dirección fuera de límites, desbordamiento de punto flotante, etc.). ),etc.
El tercer tipo de proceso causado por el uso de llamadas al sistema para solicitar servicios del sistema en un programa se llama "trampa" (o trampa). Las dos primeras categorías suelen denominarse interrupciones. Su aparición suele ser involuntaria y pasiva, mientras que caer en ellas es intencional y activa.
1. Procesamiento de interrupciones
El procesamiento de interrupciones generalmente se divide en dos pasos: respuesta a interrupciones y procesamiento de interrupciones. La respuesta a las interrupciones se implementa mediante hardware y el procesamiento de interrupciones se implementa principalmente mediante software.
(1) Respuesta a la interrupción
Todo el proceso de procesamiento de la solicitud de interrupción se realiza a través de un conjunto de mecanismos de interrupción formados por una combinación de software y hardware. Cuando ocurre una interrupción, la CPU suspende la ejecución del programa actual y comienza a procesar la interrupción. El proceso mediante el cual el hardware responde a las solicitudes de interrupción se denomina respuesta a la interrupción. En términos generales, la secuencia de respuesta a la interrupción realiza las siguientes tres acciones:
◆Pausar la ejecución del programa actual;
◆Guardar la información del punto de interrupción del programa original (principalmente el contador del programa). PC y programa Contenido del registro de estado PS);
◆ Saque el vector de interrupción del controlador de interrupciones y transfiéralo al controlador correspondiente.
Por lo general, después de ejecutar una instrucción, la CPU comprobará inmediatamente si hay una solicitud de interrupción y, de ser así, responderá inmediatamente.
Cuando ocurren interrupciones, ya sea que provengan de hardware (por ejemplo, de un reloj o dispositivo externo), interrupciones de programación (ejecución de una instrucción que causa una "interrupción de software") o eventos inesperados (por ejemplo, una página accedido que no está en la memoria), el sistema responderá.
Si la prioridad de ejecución de la CPU actual es menor que la prioridad de interrupción, detendrá la ejecución de la siguiente instrucción en el programa actual, aceptará la interrupción y actualizará el nivel de ejecución del procesador (generalmente igual que la prioridad de interrupción), de modo que cuando la CPU procesa la interrupción actual, pueda bloquear otras interrupciones del mismo nivel o de nivel bajo, y luego guardar la información del campo del punto de interrupción y pasarla a la entrada del controlador de interrupciones correspondiente a través el vector de interrupción obtenido.
(2) Procesamiento de interrupciones
La CPU obtiene el vector de interrupción del controlador de interrupciones y luego encuentra la entrada correspondiente de la tabla de vectores de interrupción IDT de acuerdo con el vector de interrupción específico, que debería ser una puerta de interrupción. Luego, la CPU llega a la entrada del programa de servicio total del canal según la configuración de la puerta de interrupción.
La secuencia de procesamiento de interrupciones del kernel se completa principalmente con las siguientes acciones:
◆ Guarde el contenido del registro del proceso en ejecución y colóquelo en la nueva superficie del marco de la pila central.
◆ Determine la "fuente de interrupción" o verifique la ocurrencia de la interrupción e identifique el tipo de interrupción (como interrupción de reloj o interrupción de disco) y el número de dispositivo de la interrupción (como qué disco causó la interrupción). Después de que el sistema recibe una interrupción, obtiene un número de interrupción de la máquina. Este número de interrupción es el desplazamiento de la tabla de vectores de interrupción que se recupera. Los vectores de interrupción varían de una máquina a otra, pero generalmente incluyen la dirección de entrada del manejador de interrupciones correspondiente y la palabra de estado del procesador cuando se manejó la interrupción.
◆El kernel llama al controlador de interrupciones para manejar la interrupción.
◆El procesamiento de la interrupción se completa y se devuelve. Después de ejecutar el controlador de interrupciones, el kernel ejecutará una secuencia específica de instrucciones relacionadas con la máquina, el contenido del registro se restaurará durante la interrupción, la pila del kernel de ejecución se desenrollará y el proceso volverá al modo de usuario. Si se establece el indicador de reprogramación, el proceso se programará cuando regrese al modo de usuario.
2. Llamada al sistema
En los sistemas Unix/Linux, las llamadas al sistema aparecen en los programas C como llamadas a funciones C normales. Sin embargo, una secuencia general de llamadas a funciones no puede cambiar el estado del proceso del estado de usuario al estado de kernel, pero las llamadas al sistema sí pueden.
El compilador del lenguaje C utiliza una biblioteca de funciones predeterminada (comúnmente conocida como biblioteca C), que contiene los nombres de varias llamadas al sistema. Todas las funciones de la biblioteca C utilizan una instrucción para cambiar el estado de ejecución del proceso al estado central. Las llamadas al sistema Linux se implementan mediante la instrucción de interrupción "INT 0x80".
Cada llamada al sistema tiene un número único, llamado número de llamada del sistema. Todas las llamadas al sistema están centralizadas en la tabla de entrada de llamadas del sistema para una gestión unificada.
La tabla de entrada de llamadas al sistema es una matriz de punteros de función. El puntero de función correspondiente se puede encontrar en la matriz con el número de llamada del sistema como subíndice, de modo que se pueda determinar qué llamada al sistema es el usuario. usando. El número de llamadas al sistema es diferente para diferentes sistemas. Actualmente hay 221 llamadas al sistema * * definidas en el sistema Linux.
Además, quedan algunos elementos en la tabla de llamadas del sistema que los usuarios pueden agregar por sí mismos.
Cuando la CPU ejecuta la instrucción de interrupción "INT 0x80", el hardware genera una serie de respuestas y sus acciones son las mismas que las respuestas de interrupción mencionadas anteriormente. La CPU ingresa al espacio del sistema desde el espacio del usuario a través de la trampilla. Por lo tanto, el contexto del proceso cambia de la pila de usuarios a la pila del sistema.
Luego ejecute la función del núcleo system_call(). Primero, guarde más el contenido de cada registro; luego llame a syscall_trace(), busque en la tabla de entrada de llamadas del sistema sys_call_table con el número de llamada del sistema como subíndice y busque la función correspondiente y luego ejecute la función para completar el servicio específico;
Después de ejecutar la rutina de servicio, el kernel busca errores y los maneja en consecuencia. Si el proceso recibe una señal, la maneja en consecuencia. Finalmente, el proceso regresa del espacio del sistema al espacio del usuario.
Las dos conferencias anteriores introdujeron brevemente las principales estructuras de datos y los algoritmos correspondientes del kernel de Linux. El kernel de Linux contiene mucho contenido, y aquí solo mencionaré un poco para que sirva como punto de partida.
Interrupción de señal y reinicio de llamada del sistema
# include ltsignal.h gtint sigaction(ints signo, const struct sigaction *act, struct sigaction * oact); sa_handler)();/*addr del manejador de señales, o SIG_IGN, o SIG_DFL*/SIG set_t sa_mask;/*Señales adicionales bloqueadas*/int sa_flags;/*opciones de señal* /}; _handler apunta a una función de captura de señal (no a la constante SIG_IGN o SIG_DFL), el campo sa_mask indica un conjunto de señales que debe agregarse a la palabra de máscara de señal del proceso antes de llamar a la función de captura de señal intermedia. La palabra de máscara de señal del procedimiento se restablece a su valor original sólo cuando se regresa de la función de captura de señal. De esta manera, algunas señales se pueden bloquear cuando se llama al controlador de señales. Cuando se llama a un manejador de señales, una nueva palabra de máscara de señal creada por el sistema contiene automáticamente la señal que se está transmitiendo. Por lo tanto, se garantiza que mientras se procesa una señal determinada, si esa señal vuelve a ocurrir, se bloqueará hasta que se complete el procesamiento de la señal anterior.
a. Implementación de señal() reiniciable automáticamente: # include
{
Estructura señal acción acción;
act.sa _ handler = func
sigemptyset(act . sa _ mask);
act . sa _ flags = 0;
#ifdef SA_INTTERRUPT //SUNOS
act. = SA_INTTERRUPT
#endif
if (sigaction(signo, ampactionampoac) lt; 0)
return(SIG_ERR
return); (oact . sa _ handler);
}
Nota: Solo SUNOS se reinicia automáticamente, otros no se reiniciarán automáticamente, así que simplemente marque SUNOS como reinicio no automático, como se indica arriba. .