Bueno, pues hola a todos, bienvenidos a esta nueva sesión en la que vamos a ver el tema 6 de la asignatura ampliación de sistemas operativos. Como habéis visto, hasta ahora hemos estado viendo los aspectos teóricos y generales de los sistemas operativos basados en Unix, pero en estos últimos temas que vienen en el libro vamos a entrar ya en sistemas operativos concretos para ir viendo sus peculiaridades. En concreto, en este tema 6 vamos a ver el sistema operativo Linux y por lo tanto vamos a ir viendo las diferentes partes de las que consta el tema. Van a ser 5 partes, ¿vale? Y... Realmente, pues como decíamos, el tema va a estar dedicado al estudio de Linux, que es el soft Unix de código abierto más conocido y utilizado. Entonces, entre todos los sistemas operativos basados en Unix, el Linux es el más conocido y también el más utilizado. En la primera parte vamos a ver unas consideraciones generales sobre Linux, luego en la segunda analizaremos la gestión de procesos e hinos en Linux, en la tercera describiremos la planificación de tareas en Linux, en la cuarta se analizará la implementación de la gestión de memoria en Linux y por último en la quinta parte se describirá la gestión de archivos en Linux, ¿vale? Bueno, pues en cuanto a la primera parte, deciros que el libro pues os habla un poco de los orígenes, de los archivos, de los archivos, de los archivos, de los archivos, de los archivos, de los archivos, de los archivos, de los archivos. Los orígenes de Linux, ¿no? Cuando fue su primera versión, que fue en 1991, las diferentes versiones del núcleo de Linux, ¿vale? Cuando han ido surgiendo, cuáles son, cómo ha sido esa evolución, las diferentes distribuciones de Linux que ha habido, etc. Eso todo lo podéis encontrar en la página 232 y página 233. Entonces esto, como es un poco historia e introducción, pues os lo dejo para que lo miréis vosotros por vuestra cuenta determinada, ¿vale? Yo voy a irme directamente a la segunda parte del tema, que es la gestión de procesos en los en Linux, ¿vale? Para el núcleo de Linux, un proceso monohilo, un proceso ligero. O un hilo, ¿vale? Que es lo mismo. Es simplemente un flujo de ejecución independiente o una tarea que debe ser planificada y ejecutada, ¿vale? Entonces, voy a marcarlo aquí en amarillo, proceso monohilo, proceso ligero, hilo del núcleo, pues es un flujo de ejecución independiente, una tarea que debe ser planificada y ejecutada. Ahora, Linux considera un proceso monohilo como una única tarea, ¿vale? Mientras que un proceso multihilo constará de un número de tareas igual al número de procesos ligeros y los de usuario en que se descomponga, ¿vale? También cada hilo del núcleo asociado a un proceso del sistema o utilizado para ejecutar una determinada... La función del núcleo es considerado como una única tarea, ¿vale? Por otra parte, en Linux se utiliza el concepto de grupo de hilos, también para que lo tengáis en cuenta, y se utiliza para designar a todos los procesos ligeros que forman parte de una misma aplicación multihilo, ¿vale? Bueno, en cuanto a la estructura del núcleo... O las estructuras del núcleo asociadas a las tareas, decir que el núcleo asigna a cada tarea, en el momento de su creación, una estructura, que se denomina TaskStruct, una pilar en modo núcleo y una estructura TripInfo, entre otras, ¿vale? La estructura TaskStruct también se denomina descriptor del proceso. Y contiene datos y punteros a otras estructuras de datos que el núcleo necesita conocer para poder gestionar una tarea, ¿vale? Esta estructura tiene la siguiente información. Os viene ahí, de todas formas, en el libro, ¿vale? En la página 234, ¿vale? Por eso tampoco os lo he puesto aquí. Entonces... Vale, sí, es lo mismo que viene aquí. Entonces, esta sería la información, ¿vale? El estado de la tarea, por un lado. En Linux, una tarea puede encontrarse en estos estados. TaskRunning, que significa que está ejecutándose. TaskInterruptible, que significa que se interrumpió. TaskInterruptible, TaskUninterruptible, que significa que no es interrumpible. Y todas estas que vemos aquí. TaskStop, que es la parada. TaskTrust, que es rastreada. ExitZombie, que es el estado zombie. ExitBit, que es muerta. ¿Vale? Y analizando cada una de ellas, pues vamos a ir viendo qué significa, ¿no? Cada uno de los estados. Ejecutándose significa que una tarea se encuentra así si se está ejecutando en un procesador o si está preparada para ser ejecutada cuando lo determine el planificador del núcleo. En el estado interrumpible significa que la tarea se encuentra dormida a la espera de que se produzca un determinado evento. Pero puede ser despertada si llega alguna señal no bloqueada que no es NUT. ¿Vale? Si está en el estado no interrumpible, significa que la tarea se encuentra dormida a la espera de que se produzca un evento. Pero ahora sólo será despertada si se produce el evento por el que espera. Una tarea que se encuentra en este estado no podría ser despertada si llega alguna señal no bloqueada que no es NUT. ¿Vale? Eso es importante. En cuanto al estado. Si está en el estado de parada, la ejecución de la tarea ha sido detenida por otra tarea. Por ejemplo, un depurador de córdoba. ¿Vale? Entonces estaría en ese estado de parada. Si está en el estado rastreada, pues es un caso especial del estado anterior. ¿Vale? Este estado se utiliza exclusivamente para aquellas tareas cuya ejecución ha sido detenida porque está siendo rastreada mediante la llamada al sistema tras invocada por otra tarea. Si está en el estado zombie, la tarea ha terminado su ejecución pero el núcleo todavía no ha borrado el contenido de su estructura task extrude ya que el padre todavía no ha invocado una llamada al sistema white bit o white para obtener el estatus de salida del sub. ¿Vale? Ese es el estado zombie. Y por último, el estado muerta es que la tarea ha terminado su ejecución y su proceso padre ya ha invocado una llamada al sistema. White bit o white para obtener el estatus de salida de su hijo y el núcleo procederá a la eliminación de la estructura task extrude si no existen más tareas que hayan invocado una llamada al sistema del mismo tipo white bit sobre la misma tarea. ¿Vale? Bueno, tenéis aquí el diagrama de transición de estados de las tareas en Linux. Bueno, tenéis en el libro la página 235. ¿Veis que aquí es un diagrama de cómo pueden ir sucediéndose todos estos estados en una tarea? ¿Vale? Veis que aquí pues primero se crea, ¿vale? Luego pues se ejecutaría, luego podría ser parada o podría ser interrumpida, ¿vale? O no interrumpible, ¿vale? Por ejemplo, si está ejecutándose... Si tenemos una tarea en Linux ejecutándose y se produce una señal que le pida que se pare, pues nos iríamos por aquí y llegaríamos al estado de parada. ¿Vale? Volvemos así y estaríamos aquí. Cuando de nuevo una señal indique que salimos de ese estado de parada, volveríamos de nuevo al único estado de parada. Y aquí tenemos el estado posible al cual nos podemos mover, que sería el de ejecutándose de nuevo. ¿Vale? Veis que aquí es un ciclo que no me permite ir a ningún otro estado. Sin embargo, desde el estado de ejecutándose yo puedo irme a varios. Puedo terminar la tarea, puedo decir que realmente un... O mejor dicho, que la espera de un evento sea no interrumpible. O que si se produce un evento, pues sea interrumpible. ¿Vale? Entonces, pues aquí tengo las esperas, ¿vale? Y ya, pues, si la tarea es interrumpible, pues podrá pararse. Si no, pues no podrá. ¿Vale? Bueno, y lo importante que es el camino que tiene que seguir toda tarea es este de la derecha. Se ejecuta... Y se termina. Entonces, cuando se termina, pasa al estado zombie. Después de estar en el estado zombie... Se produce el tratamiento de una llamada tipo white invocada por el padre. Cuando se produjese eso, pasaríamos ya finalmente al estado muerto. ¿Vale? Bueno, en cuanto a los parámetros de planificación... Que es otra de las informaciones... Que contiene la estructura TaskStruct. Entre esos parámetros de planificación, la prioridad de la tarea sería un parámetro. El tiempo de ejecución y el tiempo promedio que duerme una tarea esperando por un evento sería otro. ¿Vale? Entonces, esos son parámetros que aparecen en cuanto a parámetros de planificación. Más información. Identificadores. ¿Vale? Cada tarea... Tiene asociada un identificador de tarea. El TaskIdentifier. Que también se denomina TID. También se denomina identificador del hilo. ¿Vale? Que identifica a esa tarea de manera única. Esto es importantísimo. ¿Vale? El TID identifica una tarea de manera unívoca. Este identificador se almacena en un campo de la estructura TaskStruct. Simplemente, a lo que se podría pensar, este campo no se denomina TID, sino que se denomina PID. ¿Vale? Bueno, esto es así porque en sus orígenes Linux únicamente soportaba procesos monohilos y en dicho caso el valor del TID es igual al PID del proceso. En el caso de procesos multihilos, cada hilo constituye una tarea y tiene asociado un TID diferente. Además, cada tarea tiene asociado un TID diferente. Por lo tanto, cada tarea tiene asignado un identificador de grupo de tareas, que también se conoce como TGID. ¿Vale? Es lo que se conoce como identificador de grupo de hilo, el cual se almacena en el campo TGID de la estructura TaskStruct. Todas las tareas pertenecientes a un mismo grupo de tareas tienen asignado el mismo TGID, el cual coincide con el mismo grupo de tareas. El TID de la tarea líder del grupo, que es la tarea principal. ¿Vale? Bueno, también decir que el PID de un proceso multihilo en Linux coincide con el valor del TGID de su sitio. ¿Vale? Bueno, más información que aparece en esta estructura TaskStruct. La información genealógica. ¿Vale? Como ejemplo de información genealógica, podríamos pensar en un puntero a la estructura TaskStruct de su proceso padre. ¿No? En la cabecera de lista doblemente enlazada de sus procesos hijos. O punteros para implementar la lista doblemente enlazada de sus procesos hermanos. ¿Vale? Bueno, más información en esta estructura. La localización del espacio de direcciones virtuales de la tarea. Muy importante también esta característica o esta información porque nos ayudan a localizar esas direcciones virtuales que son necesarias para llevar a cabo la tarea. Más información, más credenciales. Como los identificadores de usuario UID y EUID. Los identificadores de grupo GID y EGID. Y el identificador de sesión SID. ¿Vale? Contexto hardware salvado. Esto lo que hace es permitir continuar con la ejecución de la tarea en modo usuario tras retornar de la ejecución en modo núcleo de un sistema o de una interrupción. ¿Vale? Entonces esta información también es muy importante para poder estructurar esa task struct. Más información, puntero a la estructura script input. ¿Vale? También lo vimos antes. Más información, información relativa al sistema de archivos. Por ejemplo, pues un puntero a la tabla de escritores de archivos abiertos. O punteros al nodo del director de trabajo actual y al nodo del directorio RAID. ¿Vale? Bueno. Más información, información asociada al tratamiento de señales. Por ejemplo, pues las máscaras de señales ignoradas, bloqueadas y pendientes. También las acciones establecidas para cada tipo de señal y las direcciones de los manejadores de las señales que son capturadas. Bueno. Por último, información contable sobre el uso de recursos. Como el tiempo ejecutado en modo usuario o en modo núcleo, pues también decir que límites máximos a los recursos que puede utilizar son importantes. Por ejemplo, el número máximo de archivos abiertos, el tiempo máximo de uso del procesador, tamaño máximo de su pila o de su ordenador. Su segmento de datos, número máximo de marcos de página que puede consumir, etcétera. ¿Vale? Bueno. Luego tenéis aquí en el libro, en la página 136, un ejemplo que le podéis echar un vistazo. Es un programa, se denomina programa 61. ¿Vale? Y os viene ahí su código fuente, escrito en C. ¿Vale? Entonces ese programa utiliza las funciones de librería de hilos Pthreads que vimos en la sección 234 para implementar dos hilos de usuario. ¿Vale? La función de cada hilo es mostrar en pantalla el valor de su PID y de su TID asociado. ¿Vale? Eso es lo que hace cada hilo. Para obtener el PID se invoca la llamada al sistema HEADPIT. ¿Vale? Lo veis ahí en el código. Y esta llamada en Linux devuelve el TID del hilo que la invoca. ¿Vale? Pero acordaros que, os lo pongo aquí. Acordaros que... El TID es igual a TGID. ¿Vale? Entonces como se devuelve el TGID, pues ya tenemos también el PID. Para obtener el TID se invoca indirectamente la llamada al sistema HEADTID. ¿Vale? A través de la llamada al sistema SYSCAL. Porque no existe... Eh... El LIB, una función de envoltura para esta llamada al sistema. Entonces, si este programa 61 se invoca en segundo plano desde la línea de orden en un intérprete de comandos en Linux. Pues en la pantalla aparecería la salida que tenéis ahí. Hilo 1 y os dará su PID 12674 en este caso. Y también su TID. ¿Vale? Que coincide. Y también aparecerá por pantalla hilo 2 y PID igual 12674 y PID igual 12675. ¿Vale? Esto es lo que va a aparecer por pantalla en vuestro intérprete de TGID. El proceso asociado al programa tiene asignado un PID que es igual a 12674. Entonces su TGID será también ese número, 12674. Como el proceso consta de dos hilos, el hilo principal, que es este, el 1, tiene como PID 12674, decíamos. ¿Vale? Pues el PID, o sea, 12675. Entonces esta información también la podemos obtener si nuestro intérprete de comandos de nuestro sistema operativo es Aron Unix, en este caso nuestro Linux. Escribimos en el terminal PS menos L mayúscula. ¿Vale? Importante lo de la L. Porque mostraría la salida que tenéis ahí en la parte superior de la página. 238. ¿Vale? El valor del PID es el que aparece en la columna LWP. ¿Vale? En la segunda columna tenemos el valor del PID. ¿Vale? Esto de aquí, pues sería lo que aparece en esta columna. ¿Vale? Lo LWP. Bueno, pues ese ejemplo es muy interesante, lo podéis probar también para que veáis esa información de forma real. Bueno, en cuanto a la fila en modo núcleo y estructura ThreadInfo. El núcleo, cuando crea una tarea, aparte de una estructura task struct, le asigna también otras estructuras de datos. Por un lado la fila en modo núcleo y por otro lado la estructura ThreadInfo. ¿Vale? La fila en modo núcleo también se denomina pila del núcleo. Es una estructura que contiene los marcos de pila de las funciones invocadas por el núcleo durante la ejecución de la tarea en modo núcleo. Esta pila está vacía cuando la tarea se ejecuta en modo usuario. La otra estructura de datos, la estructura ThreadInfo, contiene la dirección de la estructura task struct de la tarea y también otros parámetros de esa estructura. ¿Vale? Bueno, y tenéis aquí también un ejemplo, el ejemplo 6.2 de la página 238 en la que os muestra en la figura 6.3 un diagrama en el que se representa la pila del núcleo y las estructuras task struct y ThreadInfo de los hilos del proceso del ejemplo que acabamos de ver, del 6.1. ¿Vale? Entonces aquí os aparecerían esas estructuras. La task struct y la ThreadInfo. ¿Vale? Así veis de forma real cómo son. ¿Vale? Estas estructuras, veis ahí en el ejemplo, por ejemplo la task struct se encuentra enlazada formando parte de la lista de procesos del núcleo. Cada estructura task struct tiene un puntero a su estructura ThreadInfo asociada. ¿Vale? La cual a su vez también tiene un puntero recíproco. ¿Vale? Veis ahí pues esa serie de flechas recíprocas. ¿Vale? Entre las dos estructuras. La pila del núcleo de cada hilo se implementa en una página contigua a la página donde se localiza su estructura ThreadInfo, lo que facilita la localización de dicha estructura a partir del puntero óptico. ¿Vale? También muy importante. Bueno, en cuanto a la creación de procesos e hilos en Linux, la creación de procesos al igual que en otros sistemas operativos que se basen en UNIX, se puede realizar mediante las llamadas al sistema fork y vfork. Además Linux dispone de la llamada al sistema clon. ¿Vale? Para crear un nuevo proceso ligero asociado. El proceso invocador de la llamada. Esta llamada es bastante potente y flexible ya que permite especificar los recursos asociados al proceso creador que se desea que sean accedidos por el proceso ligero que es creado. Esta llamada también permite crear un nuevo proceso de la misma forma que las llamadas fork y vfork. ¿Vale? Bueno. La llamada al sistema clon que acabamos de mencionar tiene la sintaxis que veis aquí. Esta sería su estructura, ¿no? Esta llamada al sistema y tiene pues estos parámetros de entrada que veis aquí. ¿Vale? En concreto cuatro. Fun, el primero de ellos es la función que comenzará a ejecutar el proceso ligero creado cuando sea planificado para ejecución. ¿Vale? Esa función recibe como argumento los especificados en A. ¿Vale? Aquí. El argumento upila es la dirección virtual de comienzo de la dirección de pila y modo usuario del hijo. Y el otro argumento, el int, es un mapa de bits que permite especificar los recursos del proceso padre que serán compartidos por el proceso hijo. Pues os dice que si este bit está activado, se crea un nuevo proceso ligero y lo de usuario. En caso contrario, se crea un nuevo proceso monoído. ¿Vale? En cuanto al funcionamiento de ClonVM. Si este bit está activado, entonces el proceso hijo comparte el mismo espacio de direcciones virtuales del proceso invocador. Bueno, excepto la región de pila. ¿Vale? En cuanto al funcionamiento de ClonParent. Si este bit está activado, el proceso hijo tendrá como proceso padre al mismo del proceso invocador. En caso contrario, el proceso invocador será el padre del proceso creado. ¿Vale? Bueno, en cuanto al funcionamiento de ClonParent. Si este bit está activado, el proceso... El proceso hijo comparte los descriptores de archivos del proceso padre. Y en caso contrario, el proceso hijo recibiría su copia independiente de los descriptores de archivos. En cuanto a ClonSigan. Si este bit está activado, el proceso hijo compartiría los manipuladores de señales del proceso padre. Los posibles cambios que se hagan en estos manipuladores son visualizados tanto por el padre... Como por el hijo. En caso contrario, el proceso hijo recibe su copia independiente de los manipuladores de señales. Y los cambios que realicen ellos no son visualizados por el padre. ¿Vale? Bueno. Si la llamada se ejecuta con éxito, la llamada clone, en R, en esa variable, se almacenaría el bit del proceso hijo creado. En el caso de error, como siempre, se almacena el valor menos uno. ¿Vale? Entonces esto de aquí lo voy a marcar como muy importante. Para que sepáis que hace referencia a lo que ocurre con la llamada al sistema clone y lo que se almacena en esta variable R. ¿Vale? Bueno. Y en el siguiente apartado, en el 6.3.3, que es el último de esta parte, vamos a hablar de los hilos del núcleo en linux. En linux, los hilos nucleares. Los hilos del núcleo son asociados a la ejecución de procesos del sistema. Que son procesos iniciados por el propio núcleo que se encargan de realizar diferentes tareas administrativas. Como puede ser la búsqueda de marcos de páginas libres, intercambio de procesos, copia de buffers modificados a memoria secundaria, etc. A diferencia de otras tareas. Los hilos del núcleo únicamente se ejecutan en modo núcleo y se crean con la función del núcleo kernel tree. Esta función, para implementar la creación del hilo del núcleo, también invoca a la función doFold. ¿Vale? Dependiendo del proceso del sistema al que esté asociado, un hilo del núcleo puede ser ejecutado cuando se produce un determinado evento. O. Sin embargo, también puede ser ejecutado periódicamente. ¿Vale? Bueno, ahí tenéis también en la página 240 un ejemplo, el ejemplo 6.3. ¿Vale? Que muestra de nuevo un programa, en este caso el PROC 62. Y tenéis ahí el código fuente escrito en C. De ese archivo ejecutable. Esa funcionalidad que tiene es parecida a la del programa que acabamos de ver antes en el anterior ejemplo. ¿Vale? La principal diferencia es que ahora utilizamos la llamada sistema clone para crear un nuevo hilo. ¿Vale? Clone tree. En vez de usar una función de la librería trees. ¿Vale? El hilo 2 creado comparte el espacio de direcciones virtuales. Clone vm y los manipuladores de señales clon sheehan del hilo invocador, que es el hilo 1. ¿Vale? El núcleo implementa el tratamiento de las llamadas clone for y v for a través de la función del núcleo do for. Esa función utiliza a su vez a la función copy process para configurar el descriptor del proceso. La estructura task stu y otra estructura de datos del núcleo asociadas al nuevo proceso. ¿Vale? Para echar un vistazo al ejemplo, os he leído el enunciado, pues ahora asociarlo al código fuente que tenéis ahí en la figura 6.4 en la página 241. ¿Vale? Bueno, y con esto pues hemos llegado a la tercera parte, ¿vale? En la cual vamos a ver la planificación en Linux. ¿De acuerdo? Bueno, planificación en Linux. Linux es un sistema operativo de núcleos propiable que utiliza comunidad de planificación a las tareas. Entonces, esto es lo más importante de todo. Bueno, lo voy a marcar bien. Yo tengo que saber de memoria. Linux. Este por menos marco. Así. Linux utiliza comunidad de planificación a las tareas. ¿Vale? Muy importante. El núcleo asumirá a cada tarea una prioridad, que es un número entero positivo P comprendido entre 0 y 139. 0 es la prioridad más alta posible y 139 la más baja. ¿Vale? Cuidado con esto porque puede dar lugar a confusión y podéis pensar que es al revés. 0 la más alta. O sea, perdón. 0 la más baja y 139 la más alta. ¿Vale? Pero es al revés. ¿Vale? Así que mucho ojo con esto. Marcarlo bien en el libro para que a la hora de estudiarlo no os confundáis. El núcleo siempre planifica a la tarea en el estado ejecutándose de mayor prioridad. ¿Vale? Menor valor de P. Dicha tarea será expropiada si entra en el estado ejecutándose una tarea de mayor prioridad. ¿A las tareas? Con prioridad P comprendida en el rango 100 y 139 se les considera tareas convencionales o tareas de tiempo compartido. A las tareas con prioridad P comprendida en el rango 0 y 99 se les considera tareas de tiempo real. Conviene señalar que el término tarea de tiempo real no debe ser entendido en el sentido usual. Es decir, una tarea que debe ser disputada en unos plazos determinados. Si no, tenéis que entenderlo como que se refiere al significado dado a las especificaciones POSIX 1003-4. Es decir, una tarea con una prioridad más alta que las tareas convencionales. ¿Vale? En el momento de su creación la prioridad... La prioridad de una tarea es configurada al mismo valor que la prioridad de su pago. Eso también os lo voy a marcar aquí como muy importante. Bueno, lo tengo marcado en el libro como importantísimo porque al crear una tarea tiene una prioridad que su pago. Si se trata de una tarea convencional, posteriormente la prioridad de la tarea puede ser cambiada utilizando las llamadas al sistema NICE o SET. ¿Vale? En el caso de una tarea de tiempo real se pueden usar las llamadas SETPARAM o SETSCHEDULE. ¿Vale? Que tenéis aquí. Bueno, aquí tenéis la escala de prioridades de ejecución de las tareas considerada por el núcleo de NICE. ¿Vale? Lo que decíamos antes. 0 sería la prioridad más alta y 139 sería... La prioridad más baja. ¿Vale? Fijaos también en esto importante. Las tareas de tiempo real son las que tienen más prioridad. Por eso están colocadas más arriba en esta escala. Y luego tareas más convencionales, más normales, pues están más abajo porque tienen una prioridad inferior. ¿Vale? Entonces, pues tener en cuenta esta escala sobre todo introduciendo... Como ejemplo, las tareas de tiempo real y las tareas convencionales os puede ayudar mucho para memorizar todo este tema de las prioridades de cara al examen y no confundiros con los rangos. ¿Vale? Bueno. Luego, os he puesto aquí las páginas en las que os aparecen dos planificadores para que le echéis un vistazo por vuestra cuenta. Y profundicéis todo lo posible en estos planificadores por vosotros mismos. ¿No? En el apartado 641 os van a hablar en el libro del planificador usado en las versiones del núcleo de Linux anteriores a la 2.6.23. ¿Vale? Como es un ejemplo concreto, pues os he puesto que os viene desarrollado en la página 240 y 2, 2.43, 44, 45, 46 y 47 y podéis echarle un vistazo para que veáis cómo es ese planificador y qué características tiene. ¿Vale? Os va a ir explicando pues las estructuras de datos utilizadas en su implementación. ¿Vale? Pues os explicaré los campos que tiene, los arrays, active, speed... Las políticas de planificación. Las políticas de planificación que se utilizan porque cada tarea tiene asignada una política de planificación. Entonces, digamos que es la política que establece el algoritmo de planificación y las reglas para coadoptar una tarea dentro de una determinada cola de prioridad. ¿No? Entonces, pues os pueden decir que hay diferentes políticas de planificación. ¿Vale? Luego también... Os explicaré... Os explicarán cómo se asignan las prioridades de una tarea, ¿vale? Dentro de este planificador y os vendrá, por último, un ejemplo para que veáis de forma real cómo se lleva a cabo toda esta teoría. ¿Vale? Y lo mismo con lo que os viene en el siguiente apartado, en el 642. Aquí os van a hablar del planificador utilizado a partir de la... Versión 2.6.23, ¿vale? Entonces, el apartado anterior es versiones anteriores a la 2.6.23, ¿vale? 2.6.23 y aquí a partir de la 2.6.23, ¿vale? Entonces... Aquí le podemos meter el igual porque se utilizó en Linux este planificador hasta esta versión donde se empezó a rediseñar, ¿vale? El nuevo planificador que vais a ver aquí es mucho más modular, ¿vale? Y está basado en la existencia de un planificador central y clases de planificación, ¿vale? Cada clase de planificación encapsula los detalles de las políticas. De planificación que soporta y dispone de un planificador independiente, ¿vale? De nuevo, pues, bueno, os van a explicar las clases de planificación que hay, que existen dos, ¿vale? La clase del tiempo real y la clase completamente justa. Luego también vais a ver la estructura nueva que aparece aquí, ¿vale? Que es la... Runquec, ¿vale? Ahora denominada RQ, ¿vale? El núcleo asocia esta estructura a la procesadora existente, ¿vale? Entonces, bueno, aquí realmente, pues, el igual lo podéis poner aquí, ¿vale? Mejor. A partir de la 2.6.23 que es cuando se rediseñó, ¿vale? Y, bueno, luego, pues, os dicen, por ejemplo, que en esta nueva estructura que os acabo de comentar, los campos que vimos al principio en el otro planificador, los tres que os dije, Arrays, Active y Speed, se sustituyen por otros dos, CFS y RT. Y los tenéis en la figura 6.7, ¿vale? Que está en la página 240. Vale, que es la última o la penúltima de este planificador, ¿vale? Aquí voy a borrar el igual. Es anterior a esta versión y aquí a partir de la versión 2.6.23. Bueno, y entonces hasta aquí es la... Ya vamos... A ver si pasa de página a esto. Vale. Pues hasta aquí sería la tercera parte del tema, ¿vale? Nos quedarían dos partes, que son las que vienen a continuación. Y estas partes, pues, bueno, las vamos a ver en la siguiente clase, ¿de acuerdo? En la cual vamos a ver la parte 4, la parte 5 y vamos a hacer... Tres ejercicios, ¿vale? Vamos a hacer tres ejercicios de los que os vienen al final del capítulo. En este caso, al final del tema 6, os vienen cinco ejercicios, ¿vale? Y nosotros vamos a hacer el 6-3, el 6-4 y el 6-5, ¿vale? Entonces, bueno, realmente lo vamos a hacer casi todos, ¿de acuerdo? Fijaos que, por ejemplo... El 6-2 trata sobre uno de los ejemplos que vimos hoy, el programa PROC 62, ¿vale? El apartado A nos pregunta qué sucede si la llamada al sistema CLONE es invocada únicamente con la constante simbólica CLONE3. Vale, mira, lo podemos ver ahora antes de terminar la clase. Entonces, este apartado... Nos pide que observemos qué ocurre con ese valor que se introduce en esa llamada al sistema CLONE, ¿vale? Entonces, aquí en este caso... Lo que ocurriría es que esa llamada al sistema no se ejecuta con éxito y, por lo tanto, va a devolver el valor menos uno, ¿vale? Si yo me voy ahora a ese código... Del programa 62, ¿vale? Y me voy a la fila... Ahí donde pone R igual a CLONE, Q1, fila hijo y demás. Si yo lo sustituyo por esa constante simbólica CLONE3, pues me va a devolver a R un valor menos uno. Por lo tanto, tiraría por ese I el R igual a igual menos uno y imprimiría...