[Relacionados con el kernel Linux_] bajo x86_64 entender el proceso de conmutación de horario

I. Antecedentes

programar como un proceso núcleo de conmutación de entrada para la selección de un nuevo proceso de programación.

 

En segundo lugar, un importante método de la función interna

calendario

     | ----------> __ horario (falso)

                                | ----------------> pick_next_task (el proceso de la política de selección, seleccione un proceso)

                                | ----------------> (proceso de cambio de contexto) context_switch

                                                                      | -------------------> switch_mm_irqs_off (un cambio de página, por ejemplo, actualizar el registro CR3)

                                                                      | -------------------> switch_to (interruptores de pila del núcleo y registros de hardware interruptor)

 

En tercer lugar, se centran en la comprensión de la función

3.1 switch_mm_irqs_off (conmutación de la página)

todo.

3.1 switch_to

La finalización de la función de transferencia, la definición de función entre dos procesos:

#define switch_to(prev, next, last) \
    asm volatile(SAVE_CONTEXT                     \
         "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */   \
         "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */    \
         "call __switch_to\n\t"                   \
         "movq "__percpu_arg([current_task])",%%rsi\n\t"          \
         __switch_canary                          \
         __retpoline_fill_return_buffer               \
         "movq %P[thread_info](%%rsi),%%r8\n\t"           \
         "movq %%rax,%%rdi\n\t"                       \
         "testl  %[_tif_fork],%P[ti_flags](%%r8)\n\t"         \
         "jnz   ret_from_fork\n\t"                    \
         RESTORE_CONTEXT                          \
         : "=a" (last)                        \
           __switch_canary_oparam                     \
         : [next] "S" (next), [prev] "D" (prev),              \
           [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \
           [ti_flags] "i" (offsetof(struct thread_info, flags)),      \
           [_tif_fork] "i" (_TIF_FORK),               \
           [thread_info] "i" (offsetof(struct task_struct, stack)),   \
           [current_task] "m" (current_task)              \
           __switch_canary_iparam                     \
         : "memory", "cc" __EXTRA_CLOBBER)

En primer lugar, algunos puntos Descripción:

Anterior: renunciar al proceso de la CPU, la estructura de dirección de task_struct

siguiente: obtener proceso de la CPU, la estructura de dirección de task_struct

última: el dar real y dejar que la próxima CPU CPU conseguir el proceso, la estructura de dirección de task_struct

[Siguiente] "S" (siguiente): significa que el siguiente valor del registro en RSI, pero con una línea de montaje [próximos] símbolos en lugar de

[Anterior] "D" (prev): valor medio de prev abajo registro RDI, pero con una línea de montaje [PREV] símbolos en lugar de

"= A" (último): significa que cuando el final de línea de montaje, será almacenado en el registro de valor actual Rax último valor, en el que un context_switch corriente parcial última variable (dependiendo del valor de la RBP registro)

RBP: variables locales para la consulta, ya que no cambia con el empuje y el pop su dirección

RSP: de empuje y pop

Esta función se puede dividir en cinco partes descritas, en donde A representa proceso prev, B para el siguiente proceso:

1) SAVE_CONTEXT:

#define SAVE_CONTEXT    "pushq %%rbp ; movq %%rsi,%%rbp\n\t"

Aquí un simple datos que representan la pila del núcleo de dos procesos, ya que switch_to definiciones de macros, por lo que no cambia el valor de una función RSP context_switch RBP y, esta vez, A_prev (a prev Un Proceso parcialmente variable) y A_next ( un proceso representa la siguiente) variables locales almacenados en su propia pila del núcleo, esta vez después de ejecutar el SAVE_CONTEXT, RBP empujar la corriente (es decir, el valor actual de RBP es el valor rbp de un proceso llama context_switch, se define como A_cs_rbp valor) A_cs_rbp es decir, el valor en la pila, RSP se mueve hacia abajo, y RBP = RSI = A_next, RDI = A_prev.

Del mismo modo B proceso de la CPU dejó escapar cuando el proceso de conmutación se realiza llamando context_switch, de la misma manera que la pila del núcleo ahorrará B_prev (ant B representa una variable local en el proceso) y B_next (variable de proceso parcial B siguiente), no RBP operación de inserción B_cs_rbp después SAVE_CONTEXT terminación de llamadas (RBP valor de las llamadas de procedimiento b context_switch, se define como el valor B_cs_rbp).

 

2) Guardar RSP, restaurar RSP:

         "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */   \
         "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */    \

Guardar el valor RSP actual a un task_struct.thread.rsp, una respuesta para la operación posterior. Por lo tanto, el giro se establece en el RSP actual valor B task_struct.rsp, de modo subsiguiente empuje y operación pop se realiza en la pila del núcleo B. Pero recuerda que la RBP actual no se ajusta al valor de la base B correcta.

3) __switch_to llamada:

"call __switch_to\n\t"

Esta función se realiza principalmente verticalmente hardware de conmutación (es decir, número de registros, etc.), así que evita aquí, sólo para ver sus rendimientos finales prev_p, por lo que después del final de la función, además de cambiar circunstancias asociadas registros de hardware proceso de recuperación exterior B que sería A_prev (prev un proceso de dirección de task_struct) almacenado en el registro rax.

4) rax MAV, RDI:

"movq %%rax,%%rdi\n\t" 

RDI valor de ajuste en el proceso rax valor del registro, es decir, el valor almacenado A_prev

5) RESTORE_CONTEXT:

#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t"

La cifra anterior no solo RESTORE_CONTEXT este paso, hay sólo unos pocos terminan. Por lo tanto, en la siguiente explicación.

En primer lugar RESTORE_CONTEXT se establece en el valor RBP RSI continuación popq% en RBP ( recuerde RSP emergente relacionada ), así que esta vez RSP ya está apuntando al proceso de pila del núcleo B, por lo que en este momento RBP = valor de B_cs_rbp , así que esta vez se puede obtener variables locales RBP B_prev (aquí no está mal, A_prev figura más adelante los pasos se obtiene) y el B_next. El refrenado mientras que la parte trasera del Compendio:

 : "=a" (last)  

Recuerde que es el valor almacenado al último rax, entonces el valor de este tiempo es el último de valor del registro rax, es decir, el valor de A_prev. Y debido a que el switch_to llamada a la función de la función context_switch es:

switch_to(prev, next, prev);

Y esta vez RBP tiene el derecho a la pila del núcleo de proceso B, entonces el original cambiará B_prev igual al último, es decir, el valor de la A_prev. Esto completa el proceso de kernel pila de arriba abajo y pidió que cambiar el hardware.

Nota: ¿Por qué necesitamos esta última variable.

1. En primer lugar, podemos ver que explican todo lo anterior no están relacionados con la preservación de la estafa, entonces el nuevo proceso es el código de retorno cumplir dónde? Cuando el proceso se ha completado y la pila del núcleo después de cambiar el contexto de hardware (y la página de conmutación anterior), antes de que el nuevo proceso se lleva a cabo debido a la programación -> __ schdule (falso) -> switch_to cambió de tal manera que la pila del núcleo, y la pila en cada llamada a la función guardará la información de la dirección de retorno. Por lo tanto, la pila del núcleo se altera indirectamente también cambia la trayectoria del proceso de llamada inicial. Por lo tanto el nuevo proceso se despierta, va desde el horario - retorno> switch_to misma manera, la diferencia final es que la llamada que funcionan en la función de programación, que volverá a la función -> _ schdule (falso).

2. Existe la necesidad de una clara, aunque después de un proceso llamado switch_to (anterior, siguiente, última), a continuación, cuando se invoca la función anterior es el actual proceso (CPU descarte), al lado es la necesidad de que el proceso de la CPU. Cuando el proceso anterior es despertado por otro proceso, la teoría es para volver a la switch_to actual (anterior, siguiente, anterior), entonces si el valor de la pila del núcleo del proceso no han cambiado, entonces el anterior tiempo o su cuenta, pero procesos posteriores necesitan prev (CPU descarte) para limpiar el trabajo. Así que esto no es suficiente. Por lo que necesitamos para dar realidad a la información de los procesos relacionados con la CPU (task_struct) dirección se almacena al último, por lo que entonces el último valor de nuevo cambiar el valor del anterior, este tiempo será capaz de obtener la elasticidad real de la información de proceso de la CPU.

Publicados 140 artículos originales · ganado elogios 28 · vistas 180 000 +

Supongo que te gusta

Origin blog.csdn.net/qq_16097611/article/details/84249382
Recomendado
Clasificación