Está en la página 1de 511
Programacioén Linux 2.0 API de sistema y funcionamiento de nucleo Rémy CARD Eric DUMAS Franck MEVEL “Ouvrage publié avec l'aide du Ministere chargé de la Culture / Obra publicada con la ayuda del Ministerio francés responsable de la Cultura” ¥ EYROLLES | EDICIONES GESTION 2000, S.A. A Prefacio Hi dear Reader, The book you hold in your hand will hopefully help you understand the Linux operating system kernel better, and you can delve into the strange and wonder- ful world of systems programming. Because it really is a strange and won- derful world, full of subtle details ranging from how to control the physical hardware to how to manage multiple different users at the same time with limi- ted resources. I certainly still, after more than five years, enjoy working on the Linux kernel, and hope that others will find it as fascinating as I have. Linus Torvalds University of Helsinki Indice BC) ee. ¢ I CAPITULO 1; LINUX: INTRODUCCION .. 1 Historia. 6.2... eee eee eee 2 Descripcién de Linux y sus funcionalidades . 3. ;Gracias, Internet! bese 4 Referencias CAPITULO 2: PRESENTACION GENERAL ... 1 Los diferentes tipos de sistemas operativos 2 Funcién del sistema operativo . teas 2.1 Méquina virtual 2.2. Compartir el procesador 2.3 Gestién de la memoria . 24 GestiGn de recursos.......- 2.5 Centro de comunicacién de la maquina Estructura general del sistema .... . - 4 Modo micleo, modo usuario . 4.1 Principio.......... 4.2 Llamadas al sistema . . . w CAPITULO 3: DESARROLLO BAJO LINUX . 1 Los productos GNU 1.1 Presentacién .. 1.2. Herramientas GNU 12.1 Presentacion . 122 gee......... 2 Las herramientas del desarrollador . 2.1 Las diferentes fases de la compilacién .. iv Programacién Linux 2.0 DQ BOC eee eee eee eee ee erect e eee ee eee e etn t tte eee eee 25 2.3 Depurador Le 24 strace . 2.5 make.. 2.5.1 Presentacion . 3 Formato de los ejecutables 3.1 a.out: el ancestro 32 ELF. 3.2.1 Bienvenida al mundo ELF ... 3.2.2. ELF y su formato... 4 Presentacién de las bibliotecas .. 4.1 Utilidad 4.2 Utilizaci6n de bibliotecas . . . 5 Organizacién del cédigo fuente del micleo . 5.1 Nicleo 5.2 Archivos de cabecera 6 Funcionamiento del nucleo 6.1 Llamadas al sistema - 6.1.1 Implementacién de una Hamada al sistema 6.1.2 Creacién de una llamada al sistema 6.1.3 Cédigos de retorno . 6.2 Funciones de utilidad . 6.2.1 Manipulacion de es espacio de direccionamiento 6.2.2 Asignaciones y liberaciones .............. CAPITULO 4: PROCESOS 1 Conceptos basicos ... 1.1 Nocién de proceso 1.2 Estado de un proceso ... 1.3. Atributos de un proceso . 1.4 Identificadores de un proceso . 1.5 Filiacién 1.6 Grupos de procesos 1.7 Sesiones ....... 1.8 Multiprogramacién .. 2 Liamadas al sistema de base 2.1 Creacién de procesos .... 2.2 Finalizacién del proceso actual . 23. Espera de la finalizacién de un proceso hijo. 2.4 Lectura de los atributos del proceso actual 2.5 Modificacién de atributos 2.6 Informacién de contabilidad 2.7 Limites 2.8 Grupos de procesos . 2.9 Sesiones ......... 2.10 Bjecucién de programa . Conceptos avanzados 3.1. Coordinador .. 3.2 Personalidades 3.3. Clonado ...... Llamadas al sistema complementarias . 4.1 Cambio de personalidad ...... 4.2 Modificacién de la coordinacién 4.3 Prioridades de los procesos . . 4.4 Control de la ejecucién de un proceso . 4.5 Clonado ...............000008 Presentacién general de la implementacién 5.1 La tabla de procesos ....... 5.1.1 Descriptor de proceso 5.1.2 Organizacién de ta tabla de procesos . 5.1.3 Manipulacion de la tabla de procesos 5.2. Registros del procesador . . 5.3. Sincronizacién de procesos 5.3.1 Principio 5.3.2 Colas de espera 5.3.3 Semdforos . 5.4 Los timers . 5.8 Ambitos de ejecucién . 3.6 Formatos de los archivos ejecutables . 6.1.1 Sincronizacién de procesos 6.1.2 Coordinacién ............ 6.1.3 Lostimers 0.0.0... 6.1.4 Espera con demora 6.2 Implementacién de las Hamadas al sistema . 6.2.1 Creacién de procesos .. 6.2.2 Terminacién de proceso . 6.2.3 Obtencién de los atributos . 6.2.4 Modificacién de atributos . 6.2.5 Grupos de procesos y sesiones 6.2.6 Control de procesos ...... . vi Programacion Linux 2.0 CAPITULO 5: SENALES . 1 Conceptos basicos . 1.1 Introduccién . 1.2 Definicién de sefiales . 1.3 Lista de sefiales 1.4 — Visualizacién de las sefiales - 2 Liamadas al sistema de base - 2.1 Emisién de una sefial 2.2 Desviacién de una sefial . 2.3 Espera de una sefia ... 3 Conceptos avanzados . 3.1 Las Mamadas al sistema interrumpibles 3.2 Las funciones reentrantes . 3.3. Los grupos de sefiales ... . 4 Liamadas al sistema complementarias . . 4.1 La gestién avanzada de las sefiales . 4.1.1 La interrupcién de las lamadas al sistema 4.1.2 El bloqueo de las senales 4.1.3 El desvio de sefales .. 414 La esperade sefales ... 4.2 Lagestién de las alarmas . 4.2.1 La Hamada al sistema alarm 4.2.2 Una gestién mds precisa del tiempo 43 Lasefial SIGCHLD... 5 Presentacién general de la implementacién _. . 5.1 Las estructuras de datos 5.1.1 La creacion y la terminacién de procesos ... 5.1.2 La emisidn de sefales 5.1.3 La recepcién de las sefales . 6 Presentacién detallada de la implementacién. 6.1 Funciones de biblioteca 6.1.1 La gestion de los grupos de sefales . 6.1.2 La funcién raise .. 6.2 Las amadas al sistema 6.2.1 El bloqueo de tas senates ... 6.2.2 El desvio de sefiales .. 6.2.3 Las sefiales en espera 6.2.4 La suspension dei proceso en espera de sefales 6.2.5 Elenviode sefales ...... 6.2.6 La gestién de las alarmas . Indice vii CAPITULO 6: SISTEMAS DE ARCHIVOS ...............0.........- 127 1 Conceptes basicos 1.1 Organizacién de los archivos 1.2 Tipos de archivos ...... 1.3 Enlaces con los archivos . 1.4 Atributos de archivos . 1.5 Primitivas de entrada/salida . 1.6 Descriptores de entradas/salidas 2 Liamadas bdsicas al sistema ..... 2.1 Entradas/salidas sobre archivos . 2.1.1 Apertura y cierre de archivos 2.1.2 Lectura y escritura de datos... 2.1.3 Posicionamiento en un archivo 2.1.4 Guardar los datos modificados 2.2 Manipulaci6n de archivos ... 2.2.1 Creacién de enlaces .. 2.2.2 Supresion de archivos 2.2.3 Cambio de nombre de un archivo . 2.2.4 Cambio de tamafio de un archivo . 2.2.5 Derechos de acceso sobre un archivo 2.2.6 Modificacién del usuario propietario 2.3. Gestién de directorios ........ 2.3.1 Creacién de directorios . 2.3.2 Supresion de directorios . 2.3.3 Directorio actual ... 2.3.4 Directorio ratz local 2.3.5 Exploracién de los directorios 2.4 Enlaces simb6licos 3 Conceptos avanzados 3.1 ienodos ....... 3.2 Descriptores de entrada/salida . 3.3. Compartir descriptores 3.4 Bloqueo de archivos .. 3.5 Montaje de sistemas de archivos 4.1 Lectura y escritura de varias memorias intermedias . 4.2 Duplicacién de descriptor de entrada/salida . 4.3 Atributos de archivos 4.4 Fechas asociadas a los archivos . 4.5 Propiedades de los archivos abiertos ............ viii Programacion Linux 2.0 46 47 48 49 4.10 4.11 5 Presentacién general de la implementacién 5a 5.2 $3 6 Presentacién detallada de Ila implementacién 61 62 Control del proceso bdflush . Bloqueo . 4.7.1 Bloqueo de un archivo 4.7.2 Bloqueo de una seccidn de un archivo Montaje de sistemas de archivos .......... . Informaciones sobre un sistema de archivos ....... . Informacién sobre los tipos de sistemas de archivos soportados Manipulaci6n de cuotas de disco Et sistema virtual de archivos Sid Principio 5.1.2 Operaciones aseguradas por el SVA . Estructuras del SVA ......- 5.2.1 Tipos de sistemas de archivos . 5.2.2 Sistemas de archivos montados 5.2.3 I-nodos en curso de utilizacién 5.2.4 Archivos abiertos ........... 5.2.5 Archivos abiertos por un proceso . 5.2.6 Descriptores de bloqueos .... 5.2.7 Descriptores de cuotas de disco 5.2.8 Memorias intermedias del bufer caché . 5.29 Caché de nombres .... Operaciones genéricas 5.3.1 Operaciones sobre superbloques 5.3.2 Operaciones sobre i-nodos . 5.3.3 Operaciones sobre archivos abiertos 5.34 Operaciones sobre cuotas de disco . Funciones intemas del SVA ... tee . : 6.1.1 Gestién de descriptores de sistemas de archivos montados 6.1.2 Gestién de los i-nodos . 6.1.3 Gestién de descriptores de archivos abiertos . 6.1.4 Gestién de descriptores de cuotas de disco 6.1.5 El caché de nombres 6.1.6 Funciones de soporte de gestién de i-nodos 6.4.7 Gestion de los nombres de archivos . 6.1.8 Gestién de bloqueos . EI béfer caché . 6.2.1 Presentacién . - 6.2.2 Gestion de las listas de memorias intermedias 6.2.3 Entradas/salidas .... Lndice 63 6.4 66 CAPITULO 7; ENTRADAS/SALIDAS 1 Conceptos 2 Liamadas al sistema 6.2.4 Modificacién del tamaiio del bifer caché . 6.2.5 Funciones de gestién de dispositivos .... 6.2.6 Funciones de acceso a las memorias intermedias .. 6.2.7 Reescritura de las memorias intermedias modificadas 6.2.8 Gestion de clusters ......... 6.2.9 Inicializacin del bifer caché Implementacién de las }lamadas al sistema . . 6.3.1 Organizacién de los archivas fuente 6.3.2. Manipulacién de archivos 6.3.3 Gestidn de los atributos de archivos 6.3.4 Entrada/salida sobre archivos 6.3.5 Lectura de directorio 6.3.6 Gestién de bloqueos . 6.3.7 Gestién del bifer caché 6.3.8 Gestidn de tos sistemas de archivos ... 6.3.9 Manipulacién de descriptores de entrada/salida 6.3.10 Herencia de descriptores . 6.3.11 Cambio de directorio . 6.3.12 Gestién de las cuatas de disco . Sistemas de archivos soportados Implementacién del sistema de archivos Ext2 6.5.1 Caracteristicas de Ext2 6.5.2 Estructura fisica de un sistema de archivos Ex2. 6.5.3 El superbloque 6.5.4 Los descriptores de grupo de bloques 6.5.5 Estructura de un i-nodo . : 6.5.6 Entrada de directorio . 6.5.7 Operaciones vinculadas al sistema de archivos 6.5.8 Asignacion y liberacién de bloques e i-nodos 6.5.9 Gestion de los i-nodos en disco 6.5.10 Gestion de directorios ..... 6.5.11 Entradas/salidas sobre archivos Implementacién del sistema de archivos ‘roe 6.6.1 Presentacion : 6.6.2 Entradas de /proc . 6.6.3 Operaciones sobre sistema de archivos . 6.6.4 Gestion de directorios ............ 6.6.5 Operaciones sobre i-nodos y sobre archivos . x Programacién Linux 2.0 2.1 Creacién de un archivo especial ... 2.2. Entradas/salidas sobre dispositives . 2.3. Multiplexado de entradas/salidas . 2.4 — Operacién de control sobre un dispositivo . 3. Presentacién general de Ia implementacién 3.L Dispositivos soportados por el niicleo . 3.2 Entradas/salidas en disco .......... 4 Presentaci6n detallada de la implementacién 4.1 Gestién de los dispositivos efectuados 4.2 Entradas/salidas de disco ... 43 Entradas/salidas sobre dispositivos en modo bloque 44 Multiplexado de entradas/salidas............... 44.1 Principio .......... 4.4.2 Funciones de utilidad . 4.4.3 La operacin sobre archivo select . 4.4.4 Implementacién de la primitiva select 4.5 Gestion de las interrupciones .. 4.6 Gestién de los canales DMA ... 4.7 Acceso a los puertos de entrada/salida 4.8 Ejemplo de dispositive en modo bloque: 48.1 Presentacion .......0.026 00200 . 4.8.2 Acceso al contenido del disco en memoria . 4.8.3 Operaciones sobre archivos . 4.8.4 Inicializacién .......... 48.5 Carga de disco de memoria . 4.9 Bjemplo de dispositivo en modo carécter: Ia impresora 4.9.1 Funcionamiento 4.9.2 Descripcién de los puertos . : 4.9.3 Funciones de gestion de la it impresora con exploracién wee 49.4 Funciones de gestién de la impresora con interrupciones . | 49.5 Operaciones de entrada/salida sobre archivo : 4.9.6 Funciones de inicializacién . CAPITULO 8: GESTION DE LA MEMORIA 1 Conceptos basicos .................. 1.1 Espacio de direccionamiento de un proceso. 1.2 Asignacién de memoria . 2 Llamadas al sistema de base . 2.1 Cambio del tamaiio del segmento de datos . 2.2. Funciones de asignaci6n y liberacin de memoria . 3 Conceptos avanzados .. 3.1 Regiones de memoria . hidice xi 3.2 Proteccién de la memoria . . . 284 3.3. Bloqueo de zonas de memoria - 1285 3.4 Proyeccién de archivos en memoria 3.5 Dispositivos de swap ......... 4 Liamadas al sistema complementarias 4.1 Proteccién de paginas de memoria ... 4.2 Bloqueo de paginas de memoria 4.3 Proyeccién en memoria 4.4 Sincronizacién de péginas en memoria 4.5 Gestidn de los dispositives de swap .. 5 Presentaci6n general de la implementacién 5.1 Gestion de las tablas de pagina . SF Segmentacion ..... 34.2 Paginacién ..... : 5.1.3 Tablas de pdginas gestionadas por Linux .. 5.1.4 Compartir pdginas . . 5.1.5 Tipos 5.2 Gestién de las p4ginas de memoria . 5.2.1 Descriptores de pdgina 5.3 Asignacién de memoria para el nucleo 5.3.1 Asignacién de paginas de memoria . 5.3.2 Asignacin de zonas de memoria . 5.4 Espacios de direccionamiento de los procesos 5.4.1 Descriptores de regiones de memoria . 5.4.2 Descriptores de espacio de direccionamienta . 5.4.3 Organizacién de los descriptores de regiones . 5.5 Asignaci6n de memoria no contigua al nticleo 5.6 Gestién del swap 5.6.1 Formato de los dispositivos de swap . 5.6.2 Descriptores de dispositivos de swap . 5.6.3 Direcciones de entradas del swap ... 5.6.4 Seleccién de paginas a descartar . 5.7 Operaciones de memoria........... 6 Presentacién detallada de la implementacién .. - 6.1 Asignacién de memoria para el micleo .... 6.1.1 Asignacién de pdginas de memoria . 6.1.2 Asignacién de regiones de memoria . 6.2 Gestién de las tablas de paginas ... . 6.3 Gestién de las regiones de memoria . 6.4 Tratamiento de las excepciones ...... 6.5 Acceso al espacio de direccionamiento de los procesos . xii Programacién Linux 2.0 6.6 Modificaci6n de regiones de memoria 6.6.1 Creacién y supresion de regiones de memoria .. . 6.6.2 Bloqueo de regiones de memoria ........- 6.6.3 Modificaciones de protecciones de memoria 6.6.4 Reasignar regiones de memoria .......... 6.7 Creacién y supresién de espacio de direccionamiento . 6.8 Proyecci6n de archivos en memoria . 6.9 Gestiéndel swap .........-...-- 6.9.1 Gestién de los dispositivos de swap 6.9.2 Entrada/salida de pdginas de swap .. wee 6.9.3 Eliminacion de pdginas de memoria ....... 00.00.06. CAPITULO 9: TERMINALES POSIX 1 Conceptos bésicos 1.1 Presentacién general 1.2 Configuraci6n de un terminal 12.4 Modo canénico - modo no canénico . 1.2.2 La estructura termios ........+-+ 1.2.3 Funcionamiento de una comunicacién 1.2.4 Configuracién de los modos de entrada 1.2.5 Configuracién de los modos de salida . 1.2.6 Configuracidn de los modos de control 1.2.7 Configuracién de los modos locales . . 1.3 Los caracteres especiales y la tabla c_ce . 1.4 El mandato stty ...... 1.5 El mandato setserial 1.6 Grupos de terminales - sesién . 1,7 Pseudoterminales .......- 2 Las funciones POSIX ... 2.1. Acceder y modificar los atributos de un terminal 2.2 -Un ejemplo de configuracién de linea . . 1 2.3 La velocidad de wansmisién ......... 2.4 Control de Hinea 2.5 Identificacién del terminal - 2.6 Grupos de procesos . 2.7 Pseudoterminales .. 3° Organizacién en el nicleo - estructuras de datos 3.1 Organizacion ..........- 3.2 Estructuras de datos internas 3.3 La estructura try_struct .. 3.4 La estructura try_driver 3.5 La estructura tty_Idise .. . Indice xiii 3.6 Laestructura winsize 3.7 La estructura tty_flip_buffer 4 Implementacién .. 4.1 Lainicializaci6n 4.2 Las entradas/salidas en los terminales 4.3. Otras funciones generales . . 44 Gestién de la desconexién . . 45 La gestién de la disciplina de la Ifnea os 4.6 Los pseudoterminales 2.02.02... 0.0 c cece ees eeeeeee ci nees CAPITULO 10:COMUNICACION POR TUBERLAS 1 Conceptos basicos . . . 1.1 Presentaci6n .. 1.2 Tuberfas anénimas y tuberfas con nombre . 2 Liamadas al sistema ... 2.1 Tuberfas anénimas . . 2.1.1 Creacin de una tuberia 2.1.2 Un ejemplo deuso .... 2.1.3 Creacién de una tuberia y ejecucién de un programa .. . 2.2 Las tuberfas con nombre 3. Presentaci6n general de la implementaci6n . 3.1 Las tuberfas con nombre 3.2 Las mberfas anénimas .............. 4 Presentacién detallada de la implementacién 4.1 Creacién del i-nodo de una tuberfa .... 4.2. Creacién de una tuberia con nombre . 43 Creacién de una tuberia anénima 4.4 Operaciones de entradas/salidas . .. CAPITULO 11: IPC SYSTEM V ... . 395 1 Conceptos bésicos . . 1.1 Introduccién . . 1.2 La gestién de claves . 1.3 Los derechos de acceso . 2 Liamadas al sistema . . 2.1 Colas de mensajes 2.1.1 Las estructuras bdsicas 2.1.2 Creacién y busqueda de colas de mensajes . 2.1.3 Control de las colas de mensajes .... 2.14 Emisién de mensajes .. 21.5 Recepcién de mensajes . 2.1.6 Unejemplo de uso .... Programacién Linux 2.0 2.2. Seméforos - All 2.2.1 Las estructuras bdsicas . 2.2.2 Creacién y bitsqueda de grupos de semdforos . 2.2.3 Operaciones sobre los semdforos . 2.2.4 El control de los semdforos ..... 2.3. Memorias compartidas 2.3.1 Las estructuras bdsicas . 2.3.2 Creacién y biisqueda de una zona de memoria compartida AIS 2.3.3 Vinculacién de una zona de memoria . : 2.3.4 Desvincular una zona de memoria ... 2.3.5 Control de las zonas de memoria compartidas . 2.3.6 interaccién con otras ilamadas al sistema 2.3.7 Ejemplo de uso Conceptos avanzados ..... 3.1. Opcidn de compilacién del nécleo . 3.2 Los programas ipes e iperm . 3.2.1 ipes .. 3.2.2 iperm . Presentaciém general de la implementacién 4.1 Funciones comunes . 4.2. Algoritmos ..... 4.3 Gestion de las claves . Presentacién detallada de la implementacién 5.1 Colas de mensajes 5.1.1 Representacién interna de las colas de mensajes . 5.1.2 La inicializacién ............46- 5.1.3 Creacién de una cola de mensajes 5.1.4 El envio de un mensaje .......... 5.1.5 La recepcién de wn mensaje 5.1.6 El control de una cola de mensajes . 5.2 Seméforos 5.2.1 Representacion interna de los semdforos 5.2.2 La inicializacién .... 5.2.3 Creacién de semdforos . 5.2.4 Control de los semdforos ............- 5.2.5 Modificacién de los vaiores de semdforos . 5.2.6 La finalizacién .. . 5.3 Memorias compartidas 5.3.1 Representacion interna 5.3.2 La inicializacién 5.3.3 Creacién de una zona de memoria compartida . memorias comparti. tndice xv 5.3.4 Vinculacién de una zona de memoria 5.3.8 Desvinculacién de una zona de memoria compartida 5.3.6 Control de las zonas de memoria compartidas .. 5.3.7 Herencia de las zonas de memoria compartidas . CAPITULO 12: LOS MODULOS CARGABLES 1 Conceptos basicos . 1.1 Presentacién : 1,2 Compilacién . . 1.3 Operaciones en Ifnea de mandatos: la carga manual . 1.4 Carga dinamica . 2 Conceptos avanzados 2.1 La realizacién de un médulo cargable ... . ‘ 2.1. Presentacién . 242 Ejemplo... 2.1.3 Compilacién y ejecucién . 2.2 Las tlamadas al sistema espectficas de 2.2.1 get_kernel_syms . 2.2.2 create_module .. i 2.2.3 init_module .... 2.2.4 delete_module .. 3 Implementactén de los médulos cargables .. ' 3.1 Presentacién . 3.2 Inmplementacién de las Ilamadas al sistema 3.2.1 create_module 7 3.2.2. init_module 3.2.3 delete_module 3.2.4 get_kernel_syms . 3.3. Gestién de los archivos virtuales . 3.4 Funciones anexas .............. 4 Carga automatica de médulos (kerneld) 4.1 Presentacion CAPITULO13:ADMINISTRACION DEL SISTEMA . 1 Conceptos basicos ....... denne nee enae 1.1 Informaciones destinadas a los procesos . . 1.2. Informaciones que controlan la ejecucién . 1.3. Cambio de estado del niicleo , 1.4 Configuracién din4mica del sistema 1.4.) Presentacién . 1.4.2 Otro método: Iproctsys - xvi Programacion Linux 2.0 2 Liamadas al sistema de administracién .. . 2.1 Informaciones respecto a la estacién 2.2 Control de la ejecucién 2.2.1 Eltiempo . 2.2.2. Modo de visualizacién de los mensajes del hiteleo 2.2.3 Estado de ta maquina 2.2.4 Sincronizacién de relojes 2.3. Cambio de estado del nticleo 2.4 Configuracién dindmica del sistema 3 Implementaci6n 3.1 sethostname, gethostname, setdomainname y uname B.2 PeDOOL oo eee eee eee eee ence eee 3.3 syslog bones 3.4 gettimeofday, settimeofday, time y stime | 34.1 time .. 3.4.2. stime . 3.4.3 gettimeofday 3.4.4 settimeofday . 3.5 sysctl . 3.6 adjtimex APENDICE A: FASES DE UNA COMPILACION C . - 483 1 Preprocesador . . 2 Compilador .. 3 Ensamblador . 4 Enlazador ... APENDICE B: UTILIZACION DEGDB ...........0..0...02.00000004 487 APENDICE C: UTILIZACION DE MAKE . 1 Funcionamiento de make .. 2. Escritura de un archivo makefile . APENDICE D: GESTION DE LAS BIBLIOTECAS ...................¥ 493 1 Herramientas de creacién y de manipulacién 2 Bibliotecas estéticas ...... 3 Bibliotecas dindmicas a.out 4 Bibliotecas dinamicas ELF - $ La carga dindmica de bibtiotecas . BIBLIOGRAFIA |... . 000 e cece cece eee e terete eee eae ed 499 Prélogo Desde hace algunos aiios, e] sistema operativo Linux se implanta cada vez més en los medios universitarios ¢ industriales. Este clénico de Unix cuya estabilidad y potencia le permiten rivalizar sin complejos con los otros sistemas operativos comerciales, posee ciertas especificidades que lo hacen muy interesante. La libre difusién de su c6diga fuente en Internet ha contribuido ampliamente a popularizar Linux, que se ha convertido asf en un tema de estudio ideal. Organizacién del libro Esta obra, cuya redaccién ha ocupado alrededor de un aii, tiene como objetivo pre- sentar los diferentes aspectos de Linux 2.0 desde el punto de vista de un desarrollador, y asimismo analizar su micleo, que constituye el centro del sistema operativo Linux. Este libro no es solamente un libro de programacién de sistemas para Unix (y para Linux en particular): es también un medio para comprender el funcionamiento interno del niicleo. El libro se divide en 13 capftulos que detallan la mayor parte de aspectos de este sistc- ma, excepto la gestién de los protocolos de red, que necesitarfan un libro completo. Los tres primeros capitulos son introductorios: + El primer capftulo presenta el origen y las funcionalidades del sistema Linux. También proporciona una lista de referencias. + Et segundo capitulo es una presentacién rapida de los distintos componentes de un sistema operativo y de Linux en particular. En él se explica la nocién de modo ticle y modo usuario y se detalta el mecanismo de las Ilamadas al sistema. Contiene una descripcién de la organizacién de las fuentes del niicleo y algunas refe- rencias sobre la instalacién y la manipulacién de las herramientas bésicas de Linux. 2 Programacién Linux 2.0 + El tercer capitulo describe las herramientas de desarrollo disponibles bajo Linux, e introduce las nociones de programacién del sistema. Los capftulos siguientes describen en detalle ef sistema Linux, Cada uno de ellos pre- senta primero la interfaz de sistema relacionada con el concepto que describe seguida de la implementaci6n de dicho concepto en el micleo Linux: * Los capftulos 4 y 5 tratan la gestién de los procesos y las sefiales. * El capftulo 6 presenta la gestién de archivos. La implementacién describe el siste- ma virtual de archivos y dos ejemplos de sistemas de archivos, Ext2 y /proc. + El capitulo 7 aborda las entradas/salidas sobre dispositivos y analiza particular- mente el controlador de impresora y el gestor de disco en memoria. * Elcapitulo 8 presenta un concepto importante de los sistemas actuales, la gestién de la memoria virtual, ¢ El capftulo 9 se interesa por la gestién de los terminales. + Los capftutos 10 y 11 describen las comunicaciones interprocesos, el pipeline y los IPC System V. + Los dos tltimos capftulos tratan sobre la carga dinémica de médulos en el nécleo y sobre funciones utiles para fa administracién del sistema. Para terminar, cuatro apéndices detallan la utilizacién de las herramientas de desa- rollo bajo Linux (compilador de C, depurador, make y herramientas de gestién de bibliotecas). Cada capitulo se compone de varias partes: las primeras presentan los conceptos expuestos, asf como las Ilamadas de sistema tratadas, mientras que las siguientes deta- Ilan el funcionamiento del nicleo, describiendo las estructuras de datos ulilizadas y las funciones internas de Linux. Esta estructuraci6n permite al lector recorrer un capitulo yendo de los conceptos gene- rales hasta los detalles de la implementacién. La lectura pucde Ilevarse a cabo, pues, de manera secuencial por capitulos, pero también de manera aleatoria, en funcién de las necesidades, del tiempo, la curiosidad.. Diversos ejemplos (en lenguaje C), figuras y tablas completan e! contenido de esta obra que pretende ser clara, completa ¢ itustrada. El lector encontrar al final una bibliografia relativa a los sistemas operativos y a la documentacién técnica existentes sobre Linux. Prologo 3 Piublico y prerrequisitos Este libro va destinado a los desarrolladores de sistemas, ya sean estudiantes, profe- sionales o investigadores en informatica. Puede utilizarse como apoyo de cursos sobre sistemas, como ayuda en el desarrollo de programas, o en el desarrolio en el nticleo. La propia estructura de los capftulos lo hace accesible a un péblico muy variado: ef prin- cipiante podré limitarse al principio a leer las primeras partes de un capftulo, mientras Ab que ef hacker (programador del sistema) s¢ centrard més bien en el funcionamiento interno del niicleo. Sin embargo, es necesario precisar que se requiere e] conocimiento del lenguaje C y de su biblioteca esténdar. Ademds, el lector debe estar familiarizado con los conceptos generales relacionados con los sistemas operativos en general, y con Unix en particular, ) para comprender los ejemplos y la descripcién del funcionamiento interno del niicleo. : La lectura de estas partes es més ardua, por lo que se aconseja estudiar el c6digo fuen- te del nticleo de forma paralela. Convenciones utilizadas Todas las lamadas al sistema presentadas en un capitulo se agrupan en un cuadro al . principio de cada capitulo: 7 Primitivas detalladas . lamadat, llamada2, Se utilizan tablas para aclarar la descripcién de las estructuras y uniones presentadas. También se usan para las listas de errores correspondientes a las llamadas al sistema, las listas de constantes y las listas de macroinstrucciones. Los prototipos de las funciones de la biblioteca estindar del C y las diferentes !lama- das al sistema presentadas se escriben en forma de teletipo. Los nombres de Hamadas al sistema, de funciones de biblioteca y de mandatos se repre- } sentan en cursiva. Se utiliza un tipo de letra teletipo para los nombres de tipos, de estructuras, de variables y de funciones. F 4 Programacién Linux 2.0 Agradecimientos La redacci6n de este libro no habria sido posible sin !a colaboracién de numerosas personas. Agradecemos a todos los desarrotladores de Linux. y especialmente al primero de ellos, Linus Torvalds. Sin ellos, este sistema operativo no habria nacido, Nuestro agradecimiento a Benjamin Bayart por su valiosa ayuda sobre el uso y la pro- gramacién de LaTeX. Queremos agradecer a las personas que han aceptado hacer el trabajo ingrato de relec- tura de esta obra y han participado en gran medida a mejorar su contenido gracias a sus numerosas criticas constructivas y sugerencias: Bric Commelin, Pierre David, Pierre Ficheux, Thomas Quinot, Pierre-Guillaume Raverdy, y Stéphan Voisin. Finalmente, nuestro agradecimiento a Julien Simon, que ha contribuido ampliamente a la definicién y a la estructuracién de este libro. Evidentemente, un libro as{ contiene necesariamente errores o imprecisiones. Invitamos a los lectores a transmitimnos sus comentarios, sugerencias y correcciones de errores por correo electrénico, a la direcci6n info@gestion2900.com. Rémy Card (Remy. Card@ linux.org) Eric Dumas (dumas@ freenix.fr) Franck Mével (mevel@ Linux. EU.Org) - Capitulo 1 Linux: Introducci6n Linux, Linux, Linux... pero, ~por qué el nombre Linux? Antes de adentrarnos en los vericuetos de este sistema operativo y de su niicleo, se impone una breve presentacién de su historia y de su concepcién, pues su historia es particularmente original en el mundo de los sistemas operativos. A continuacién de esta presentacién se exponen las funcionalidades del nticleo y se proporciona una lista de referencias. 1 Historia La historia de Linux empieza en Finlandia en 1991, cuando un ta! Linus B. ‘Torvalds (Linus. Torvalds@ cs.helsinki fi), estudiante de la universidad de Helsinki, compra un PC con un procesador 386 para estudiar su funcionamiento, MS/DOS no aprovechaba las caracterfsticas del procesador 386 (por ejemplo e! modo Ilamado protegido), por lo que Linus utiliz6 otro sistema operative comercializado: Minix, desarrollado principal- mente por Andrew Tanenbaum. El sistema Minix era un pequefio sistema Unix. Sin embargo, debido a las limitaciones de este sistema, Linus empez6 a reescribir algu- nas partes, a afiadir funcionalidades, etc. Posteriormente, difundi6 el cédigo fuente de su trabajo por Internet, de manera gratuita, con el nombre de Linux, contraccién de Linus y Unix. |Habia nacido Linux! La primera difusién de Linux tuvo lugar el mes de agosto de 1991. Se trataba de la versién 0.01. Esta primera versi6n era lo que se podrfa denominar un embridn. Ni siquiera hubo anuncio oficial, La primera versi6n «oficial» se hizo piiblica el 5 de octubre de 1991 (versi6n 0.02). Esta versién permitfa el funcionamiento de algunos programas GNU como bash, gec,... pero poca cosa mas. 6 Programacién Linux 2.0 Estas primeras versiones eran muy limitadas (jLinux 0.01 sélo podfa funcionar bajo Minix!). Sin embargo, el hecho que el cédigo fuente se difundiera permitié una répida evolucién del sistema. Con el paso de los afios, el nimero de desarrolladores no ha dejado de aumentar. Al principio, s6lo algunos apasionados se enteraron de la aparicién de este sistema y se interesaron en él. Actualmente, Linux lo desarrollan decenas de personas situadas en todos los rincones del mundo, que en su mayor parte no se han visto jamAs: unas 80 personas contribuyeron a la versién 1.0, y hay més de 190 desa- rrolladores referenciados para la versi6n 2.0. El papel de la red mundial Internet es importante porque ha permitido una répida evo- lucién det sistema. Es facil imaginar a un desarrollador instalando Linux en su maqui- ha, encontrando un error, corrigiéndolo y enviando el archivo fuente corregido a Linus. Unos dias mds tarde (en ocasiones tan s6lo unos minutos), el nucleo coregido puede difundirse de nuevo. Si las primeras versiones de Linux eran relativamente inestables (jcudntas reinstala- ciones habfa que llevar a cabo!), la primera versién considerada estable (1.0) se hizo piiblica alrededor de marzo de 1994, El mimero de versién asociado al nicleo tiene un sentido muy particular porque est4 relacionado con su desarrollo, ya que la evolucién de Linux se efectia en una sucesién de dos fases: + Una fase de desarrolio: el nticleo cuya estabilidad no esté asegurada y cuyo objeti- vo es afiadirle funcionalidades, optimizaciones y nuevos conceptos. Esta fase se caracteriza por un niimero de versién impar: 1.1, 1.3. En este momento es cuando ‘se efectiia la mayor parte del trabajo sobre el niicleo. * Una fase de estabilizacién cuyo objetivo es obtener el nticleo més estable posible. En este caso, las tinicas modificaciones efectuadas en el micleo son generalmente correcciones y algunas mejoras menores. Los mimeros de versién de estos nucleos llamados estables son pares como 1.0, 1.2 y, mas recientemente, 2.0. Actualmente, Linux es un sistema Unix completo, estable, que sigue evolucionando. Ademés de gestionar los ultimos dispositivos del mercado (memorias flash, discos épticos, etc.), su rendimiento es comparable al de ciertos sistemas Unix comerciales, y es incluso superior en algunos puntos. Finalmente, aunque Linux ha permanecido mucho tiempo encerrado en el mundo universitario (a menudo debido al acceso a Internet, con el que sélo contaban los universitarios), actualmente empieza a implan- tarse en e] mundo de la empresa. Su gratuidad, su potencia y especialmente su flexibi- lidad seducen a un némero creciente de empresas. En este momento, la tiltima versién estable es la versi6n 2.0, y es la versién analizada en este libro. Linux: Introduccién 7 2 Descripcién de Linux y de sus funcionalidades Linux se diseiié inicialmente como un clénico de Unix distribuido tibremente que fun- cionaba en m&quinas PC con procesador 386, 486 o superior. Aunque se desarrollé ini- cialmente pare la arquitectura x86, en la actualidad funciona sobre otras plataformas como los procesadores Alpha, Sparc, ciertas plataformas basadas en los 68000 como ‘Amiga y Atari, las maquinas de tipo MIPS y sobre PowerPC. Linux es una implementacién de Unix que respeta las especificaciones POSIX pero que posee también ciertas extensiones propias de las versiones System V y BSD de Unix. Esto simplifica la adaptacién del cédigo de aplicaciones desarrolladas inicial- mente para otros sistemas Unix. El término POSIX significa Portable Operating System Interface. Se trata de docu- mentos producidos por el JEEE y estandarizados por el ANSI y el ISO. El objetivo de POSIX es permitir tener un cédigo fuente transportable. La versién Linux 2.0 respeta Ia norma POSIX.1 y algunas llamadas definidas por POSIX.4 (véase [Lewine 1991] y {Gallmeister 1995]). El de Linux es un cédigo original, que no es propietario en absoluto y cuyos progra- mas en cédigo fuente se distribuyen libremente bajo cobertura de la licencia GPL, que es la licencia publica general GNU. Las funcionalidades de este sistema operativo son multiples y corresponden a la idea que puede hacerse de un sistema Unix modemo: * multitarea, multiprocesador: puede ejecutar programas al mismo tiempo, ya sea con uno 0 varios procesadores; * multiplataforma: véase més arriba; + multiusuario: como en todo sistema Unix, Linux permite trabajar a varios usuarios al mismo tiempo en la misma maquina: + soporte de comunicaciones interprocesos (pipes, IPC, sockets}; * gestion de las diferentes sefiales; + gestién de terminales segtin la norma POSIX. Linux proporciona también los pseu- doterminales y los controles de procesos; 8 Programacién Linux 2.0 * soporte de un gran ntimero de dispositivos ampliamente extendidos (tarjetas de sonido, gréficas, de red, SCSI... + bifer caché: zona de memoria intermedia para las entradas/salidas de los diferentes procesos; + gestidn de memoria a la carta: una pagina s6lo se carga si es necesaria en memoria; * bibliotecas compartidas y dindmicas: las bibliotecas dindmicas s6lo se cargan cuan- do son necesarias y su cédigo se comparte si varias aplicaciones las utilizan; * sistemas de archivos que permiten gestionar tanto particiones Linux con el sistema de archivos Ext2, por ejemplo, como particiones en otros formatos (MS-DOS, 1s09660...); = soporte de la capa TCP/IP y de otros protocolos de red. Linux es ante todo un sistema Unix rapido y completo, que puede instalarse facitmen- te, Ademés, su difusién entre el gran publico le permite evolucionar rdpidamente. Finalmente, algunas distribuciones permiten la facil instalacién de este sistema, por lo que le han permitido adquirir una cierta popularidad. 3 Gracias, Internet! Si Linux es hoy tan popular se debe a que sus fuentes se han difundido por la red mun- dial Internet de manera libre y gratuita, Esta red ha borrado las distancias entre los desarrolladores. Los servicios de correo electrénico han permitido a los desarrollado- res dialogar fécilmente y, ante todo, répidamente. Las sedes ftp también han facilitado la difusiOn rapida de los fuentes y las herramientas de desarrollo. En estos momentos, la comunicacién entre los desarrolladores se efectia por medio de foros Usenet, pero especialmente por correo electrénico. Asi, existen muchas listas de difusién de correo sobre temas variados respecto a ciertos Ambitos del desarrollo de Linux. Existen varias listas de desarrolladores que estin abiertas a todos. También es posible discutir problemas encontrados, asf como aportar posibles extensiones, afladir nuevas funcionalidades al micleo, y asf sucesivamente. Se proporcionan algunas direcciones electrénicas en la proxima seccién. Linux: Introduccién 9 4 Referencias ¢ Presentamos una lista no exhaustiva de referencias y enlaces que el usuario y el desarrolla- dor pueden consultar libremente: es rica en ensefianzas respecto a numerosos documentos. , Libros de referencia Se da una amplia bibliograffa al fin de esta obra, con la gran mayorfa de las obras de referencia existentes. Sin embargo, es necesario citar tres obras: * la obra [Beck et al. 1996] en inglés que detalla el funcionamiento interno del micleo...pero de la versién 1.2 de Linux; el libro [Welsh and Kaufman 1995] que es la referencia en materia de iniciacién y administracién bajo Linux; finalmente, citemos [Kirch 1995] que es el libro de referencia respecto a la confi- guracién e instalacién de una red bajo Unix. Foros Usenet En lengua inglesa: * comp.os.linux.advocacy: ventajas de Linux respecto a otros sistemas operativos; comp.os.tinux.announce: anuncios para la comunidad Linux (grupo moderado); * comp.os.linux.answers: difusin de ciertos documentos como las FAQ (Frequently Asked Questions), HowTo’s.... (grupo moderado); + comp.os.linux.development.apps: escritura y portabilidad de aplicaciones bajo Linux; * comp.os.linux.networking: Linux y la red; * comp.os.linux.setup: instalacién y administracién del sistema; + comp.os.linux.x: X Windows bajo Linux; © comp.os.linux.mise: todo lo que no se trata en los otros grupos. 10 Programacién Linux 2.0 Listas de correo electrénico Existen numerosas listas de difusi6n respecto a Linux. Su multiplicacién impide esta- blecer una lista completa, por to que presentamos las principales: * 1inux-kernelévger.rutgers. edu: destinada a los desarrolladores; * linux-scsi¢@vger.rutgers.edu: dedicada a los problemas y al desarrollo de controladores SCSI, * linux-gecévger . rutgers . edu: para todo lo que respecta a la biblioteca estén- dar C y gee; + linux-security@tarsier.cv.nrao.edu: lista que trata de problemas de seguridad; * Linux-alert@tarsier.cv.nrao. edu: lista de difusién de mensajes de alerta, Sedes FIP Todas las herramientas necesarias para el correcto funcionamiento de Linux se agrupan en dos sedes principales: * sunsite.unc.edu: /pub/ Linux; © tax-11.mit.edu:/pub/linux. Las actualizaciones de los nticleos se efectian en las sedes siguientes: * ftp.cs.helsinki. fi: /pub/Software/Linux/Kernel; * ftp.funet. fi: /pub/Linux/PEOPLE/Linus. Sin embargo, existen numerosos espejos de estas sedes por todas partes, y es intere- sante buscar la més cercana al lector. Linux: Introduccion 11 Sedes Web ‘A medida que Linux evoluciona, el mimero de sedes Web dedicadas a él no cesa de aumentar, Presentamos aqui las dos sedes principales a partir de las que son accesibles. numerosas informaciones y enlaces a otras paginas: © http://www. linux.org; * http://www.cs.Helsinki.FI/linux/. Las dos direcciones siguientes se encuentran en inglés y francés: * http://www. freenix. fr/linux, © http://www. loria. fr/linux. Distribuciones Linux ¢s el micleo del sistema operativo. La instalacién en una maquina (con la recom- pilacién de todas las herramientas) no es cosa realmente facil. Por esta razén, se difun- den un cierto mimero de distribuciones «llaves en mano». Se encuentran en los princi- pales servidores ftp, y se difunden también ampliamente en soportes como el CD-ROM. a precios que desaffan toda competencia. Para referencia, aqu{ tiene algunas de las dis tribuciones comtinmente difundidas: + Red Hat: ftp: //ftp.redhat .com/pub/redhat; * Slackware: ftp.cdrom.com: /pub/Linux/slackware; * Débian: ftp.debian.org:/debian; » Jurix: susix.jura.uni-sb.de: /pub/linux. Estas distribuciones se agrupan en las sedes centrales Linux; lo mismo puede decirse- de los numerosos espejos de los que hemos hablado anteriormente. Capitulo 2 Presentacion general Este capftulo se dedica a presentar las caracterfsticas de un sistema de tipo Unix en gene- tal y de Linux en particular. No nos cansaremos de repetit que Linux es ante todo un sis- tema Unix, y por tanto hereda todas las caracterfsticas de este tipo de sistema operativo. No cabe duda que, aunque se sabe bien el papel que juega una aplicacién, sigue flo- tando una nebulosa sobre el término sistema operative. Efectivamente, se emplea (demasiado) a menudo inadecuadamente, y sin embargo ocupa un lugar esencial en cualquier sistema. Este capftulo presenta [a funcién que debe cumplir un sistema ope- rativo asf como su estructura y su funcionamiento. Posteriormente, entrando en mayor ptofundidad, se detallarén las nociones de modo micleo y usuario. 1 Los diferentes tipos de sistemas operativos El sistema operativo es un término genérico que designa, en realidad, varias «familias» de sistemas: * Sistemas monotarea: sélo puede ejecutarse un programa a la vez. Por tanto, sélo una persona puede trabajar a la vez en la m4quina. Sin embargo, puede aprovechar todos los recursos y la potencia de ta maquina. ¢ Sistemas multitarea: pueden ejecutarse varios procesos en paralelo, El tiempo se divide en pequefias unidades y cada uno de los procesos se ejecuta durante ese intervalo. para que los procesos no se vean perjudicados, se implementa un com- plejo algoritmo de ordenamiento y prioridad de ejecucién para asegurar un cierto reparto entre ellos. Estos sistemas pueden ser multiusuario o no, y multiprocesador. 14 Programacion Linux 2.0 Las primeras versiones de Unix para el gran piblico eran sistemas multitarea y mul- tiusuario. Pero actualmente, gracias al progreso de la tecnologia y la informética, nu- merosos sistemas Unix son capaces ademés de utilizar las mAquinas multiprocesador, Las primeras versiones de Linux s6lo funcionaban sobre PC monoprocesador, pero Ia versién 2.0 ya permite gestionar sistemas multiprocesador. 2 Funcién del sistema operativo El sistema Unix se ha desarrollado en un lenguaje de alto nivel (lenguaje C), a dife- rencia de otros sistemas que se han desarrollado en ocasiones en lenguaje ensamblador. La utilizacion de un lenguaje de alto nivel ha permitido la portabilidad del sistema a muchas m4quinas diferentes. Lo mismo ocurre con Linux. Por ello, era primordial que el cédigo de las aplicaciones pudiera compilarse de manera transparente (0 casi), sea cual sea la maquina y los dispositivos utilizados, De hecho, el transporte de Linux a otra m4quina se resume en adaptar la parte del cédi- go que es especffica de la méquina. Los médulos independientes de la arquitectura pue- den reutilizarse tal cual. 2.1 Maquina virtual Un sistema operativo ofrece una maquina virtual al usuario y a los programas que eje- cuta. Se ejecuta en una mAquina fisica que posee una interfaz de programacién de bajo nivel, y proporciona abstracciones de alto nivel y una nueva interfaz de programacién y uso més evolucionada. En los primeros sistemas operativos que existfan en los afios cincuenta, el programa- dor debfa conocer la interfaz fisica de la mAquina y programarla directamente. Un sis- tema modemo ofrece una interfaz de més alto nivel y traduce las peticiones de alto nivel, efectuadas por el usuario, en peticiones fisicas de bajo nivel. EI sistema operativo es pues una interfaz entre las aplicaciones y la mdquina, como se representa en la figura 2.1. Por ello es por lo que todas las tareas fisicas (acceso a dispositivos externos o internos, a la memoria...) se delegan en el sistema operativo. Esta encapsulacién del hardware (y Presentacion general 15 io | Dispositivos Memoria | Maquina | Fic. 2.1 - Entre tas aplicaciones y ta maquina de su diversidad) libera a los desarrolladores de la complejidad de gestionar todos los dispositivos existentes: el sistema es quien se encarga de ello. Esto evita también que el usuario se limite a una méquina. Si el sistema estd disponible sobre varias arquitecturas, la interfaz de usuario y de programacién serd la misma en todas. Cuando un desarrollador desea, por ejemplo, leer ef contenido de un archivo, efectia la misma operacién sin importar si ef archivo est4 en una cinta. en disco, en CD-ROM en otro soporte. El cédigo del programador es el mismo, pero el niicleo efectia ope- taciones diferentes en funcién del dispositive sobre el que se encuentre el archivo. Es més simple efectuar una apertura de archivo y lecturas de datos que leer fisicamente bytes proporcionando una direccién fisica formada por nimeros de disco, cilindro, cabeza de lectura/escritura y sector. 2.2 Compartir el procesador Una de tas caracteristicas principales del sistema Unix es que es multitarea, es decir, que varios programas (procesos) pueden ejecutarse al mismo tiempo. Por ejemplo, el lanzamiento de una impresién, el formateo de un disquete, el envio o la recepcién de correo electrénico pueden realizarse al mismo tiempo. Para ello, el sistema implementa un sistema de ordenamiento, que se presenta en el capitulo 4, secci6n 1.8, y que tiene por objetivo distribuir el procesador entre los pro- esos. De hecho, si sdlo hay un procesador, se ejecuta un solo programa en un momen- 16 Programacién Linux 2.0 to dado, Pero al efectuar una rotaci6n muy répida, el o Jos usuarios de la maquina tie- nen la impresién de que todos los procesos se ejecutan de manera paralela, Esta gestién debe ser muy sofisticada para no perjudicar a nadie, y se trata de uno de los mecanismos clave del sistema. 2.3 Gestién de la memoria EI sistema se encarga de gestionar la memoria fisica del ordenador. En efecto, en un entomo multiusuario y por tanto multitarea, el sistema debe efectuar una gestién muy rigurosa de la memoria. Como la memoria fisica de la maquina es a menudo insufi- ciente, el sistema utiliza entonces una parte del disco duro como memoria virtual (4rea de intercambio o swap). E] sistema operativo debe ser capaz de gestionar hdbilmente la memoria para poder satisfacer las peticiones de los distintos procesos tan deprisa como sea posible. Ademds, debe asegurar la proteccién de las zonas de memoria asignadas a los proce- sos para evitar las modificaciones no autorizadas. La gestién de la memoria se expone en el capitulo 8. 2.4 Gestién de recursos De manera general, ¢] sistema operativo se encarga de gestionar tos recursos disponi- bles (entre los cuales el procesador y la memoria son casos particulares). sistema ofrece a los procesos una interfaz que permite compartir los recursos (dis- cos, impresoras, etc.) de la mfquina fisica. Implementa un sistema de proteccién que permite a los usuarios y a los administradores proteger el acceso a sus datos. sistema mantiene listas de recursos disponibles y en curso de utilizacién, lo que le per- mite atribuirlos a los procesos que los necesiten. En todo momento conoce los procesos que utilizan los recursos de la m4quina, y puede detectar asf los conflictos de acceso. 2.5 Centro de comunicacién de la maquina ‘Una de las tareas del sistema operativo es gestionar los diferentes eventos provenien- tes del hardware (interrupciones) o de las aplicaciones (Ilamadas al sistema). Estos Presentacién general 17 eventos son importantes, y el sistema debe tratarlos y, llegado el caso, enviarlos a los procesos afectados. Pero si el sistema operative debe ser capaz de responder a un evento, también debe ser capaz de comunicar varios procesos. De esta manera, los procesos podrén comunicar entre sf, intercambiar informaciones, sincronizarse, etc. Unix pone a disposicién det desarrollador vartos mecanismos que van de las sefiales a los IPC, pasando por las tuberfas (pipes) y los sackets (que no se tratan en este libro). Bs por ello por lo que el nficleo es el centro de comunicacién de la maquina. Cuando dos procesos intercambian datos, es porque el sistema operativo implementa mecanis- mos sofisticados junto con recursos espectfficos. 3 Estructura general del sistema El sistema operativo tal como se ha presentado se compone de varios elementos, Unix _ y Linux en particular son sistemas bastante importantes, su desarrollo se ha realizado de manera modular de modo que se puedan distinguir fécilmente las diferentes partes que los componen. La ventaja de esta estructuracién, aparte del hecho que puede estudiarse facilmente, es que permite su modificacién y mejora sin excesiva dificultad. La adicién de ciertos elementos, como las llamadas al sistema, controladores de dispositivos u otros, es bas- tante simple y no obliga a redisefiar la estructura del sistema. Por esta razén, Unix, aun- que se disefié a fines de los sesenta, ha evolucionado y sigue en activo en nuestros dias. Los distintos elementos que encontramos en el nticleo del sisterna Unix son los siguientes: * Llamadas al sistema: implementacién de operaciones que deben ejecutarse en modo micleo; * sistemas de archivos: entradas/salidas de tos dispositivos; bafer caché: memoria intermedia sofisticada para entradas/salidas; * controladores de dispositivos: gestién de bajo nivel de discos, tarjetas, impresoras...; gestién de ia red: protocolos de comunicacién de red; interfaz con la méquina: cédigo (generalmente en ensamblador) de acceso de bajo nivel al hardware; 18 Programacién Linux 2.0 * centro del micleo: ~ gestién de procesos (creacién, duplicacién, destruccién...); - gestor de drdenes: ~ seflales; - médulos cargables (carga de ciertas partes de] nticleo cuando se requieren); - gesti6n de memoria (gestién de la memoria ffsica y de la memoria virtual). La figura 2.2 representa la estructura del sistema operativo Unix asf como la interac- cién entre las diferentes partes que lo componen. Este esquema ha sido adaptado lige- Tamente para Linux y difiere poco respecto a la estructura tradicional que se puede encontrar en [Bach 1993). Este esquema evidencia la frontera que existe entre la méquina y las aplicaciones. Bajo Unix, no se trata de acceder directamente a la memoria fisica de la m4quina, a la tarje- ta de video ni a cualquier otro dispositivo fisico. Ademés, la separacién del nucleo en entidades distintas facilita su depuracién y su desarrollo. Finalmente, para acceder a las funcionalidades ofrecidas por el sistema operativo, et sistema Unix pone a disposicién de los procesos una interfaz de comunicaci6n lama- da «llamadas al sistema». 4 Modo nicleo, modo usuario 4.1 Principio Un proceso en un sistema Unix posee dos niveles de ejecucién: adcleo y usuario. EI modo nucleo constituye un modo privilegiado: en este modo, no se impone ningu- na restriccién a] nticleo del sistema. Este Ultimo puede utilizar todas fas instrucciones del procesador, manipular toda la memoria y dialogar directamente con todos fos con- troladores de dispositivos. EI modo usuario es el modo de ejecucién normal de un proceso. En este modo, el pro- ceso no posee ningun privilegio: ciertas instrucciones estén prohibidas, sdlo tiene acce- so a las zonas que se le han asignado, y no puede interactuar con la maquina fisica. Un Presentacion general 19 Proceso Interfaz de llamadas al sistema (Sistemas de archivos| Centro del micleo (édulos cargables sti6n de la memori GestiGn de red ipva. ethemet si pied Interfaz con la maquina t Méguina Fic. 2.2 - Estructura del sistema proceso en modo usuario efectiia operaciones en su entomo, sin interferir con los demés procesos, y puede ser interrumpido en cualquier momento. Esto no obstaculiza su funcionamiento. 4,2 Llamadas al sistema Un proceso que se ejecute en modo usuario no pucde acceder directamente a los recur- sos de la maquina. Para ello, debe efectuar Hamadas al sistema. 20 Programacién Linux 2.0 ‘Una Hamada al sistema es una peticin transmitida por un proceso al nticleo. Este tilti- mo trata la peticién en modo micleo, con todos los privilegios, y envia el resultado al proceso, que prosigue su ejecucidn. Bajo Unix, la Itamada al sistema provoca un cambio: ¢l proceso ejecuta una instruc- cién del procesador que le hace pasar al modo ndcleo. Seguidamente ejecuta una fun- cién de tratamiento vinculada a la llamada al sistema que ha efectuado, y luego vuel- ye al modo usuario para proseguir su ejecucién. De este modo, el propio proceso trata su llamada al sistema, ejecutando una funcién det nucleo. Esta funcién se supone que es fiable y puede ejecutarse pues en modo privilegiado, contrariamente al programa ejecutado por el proceso en modo usuario. Capitulo 3 Desarrollo bajo Linux Este capftulo est4 destinado a presentar las diferentes herramientas de desarrollo, asf como las técnicas utilizadas bajo Linux. Linux es ef nicleo del sistema operativo, y va acompafiado por toda una serie de herramientas destinadas a los desarrolladores. La caracterfstica comin a todos estos productos es que son gratuitos, disponibles para su descarga en la mayorfa de sedes ftp del planeta, como e] propio sistema. A pesar de ser de libre distribucién, estos productos son generalmente tan répidos y potentes como los programas de desarrollo del comercio, 0 incluso mas. En este capitulo se detalla la organizacién de los programas fuente del nticleo. También s¢ introducen algunas nociones de programaci6n del sistema. 1 Los productos GNU 1.1 Presentacién GNU son las iniciales de Gnu’s Not Unix. La palabra inglesa gnu designa el fu (nume- rosos programas llevan nombres de animales: yacc, bison...), una especie de biifalo de Africa del Sur. Se trata de un vasto proyecto iniciado por Richard Stallman (llamado rms) en 1983. Cuando se anuncié este proyecto, RMS era el autor de un tratamiento de texto poten- te: emacs. Tras su entrada en el laboratorio de inteligencia artificial de] MIT, decidié el lanzamiento de un vasto proyecto orientado a realizar un sistema operative cuyo cédi- 22 Programacion Linux 2.0 go fuente se distribuirfa libremente. Sin embargo, el proyecto GNU se orient6 répida- mente hacia la realizacién de todas las herramientas que deben acompajiar a un siste- ma asf, desde el compitador hasta el tratamiento de texto. Pero Linux no es GNU, y no hay que confundirlos: Linux es el sistema operativo, y algunas de estas herramientas de desarrollo provienen del proyecto GNU. Todas estas herramientas se difunden con una licencia particular de uso: la GPL, Gnu Public License, que corresponde a un CopyLeft (ja diferencia de un Copyright!). Esta licencia permite difundir libremente el cédigo fuente, modificarlo, etc. Es necesario precisar que el sistema operativo deseado por RMS no es Linux. Este sis- tema se estd desarroflando y [leva el nombre de Hurd (véase http://www. gnu.ai.mit.edu/ para més informacién). 1.2 Herramientas GNU 12.1 Presentacién La cantidad de herramientas GNU es muy importante: abarca desde compiladores (gcc, ghat ...) a tratamiento de textos de propésito general (emacs) pasando por un editor de cur- vas (gnuplot) y juegos (nuchgess ...). Se pueden encontrar productos GNU que cubren la mayor parte de los dmbitos, tanto para desarrolladores como para el usuario final. Estas herramientas son generalmente de buena calidad y bastante potentes. Se incluyen en la mayorfa de distribuciones Linux y se difunden a menudo con el cédigo fuente. Estas herramientas se difunden ampliamente en las distintas sedes ftp (consuite la sede principal de las herramientas GNU: prep .ai.mit .edu). Gracias a la difusin del cédigo fuente, estas herramientas se corrigen, se mejoran y optimizan con las diferen- tes actualizaciones. Para estar al corriente de estas actualizaciones, basta con abonarse al foro Usenet gnu.announce que difunde estos anuncios. Una herramienta en particular ha marcado a Linux: el compilador gcc. 1.2.2 gee Como todo sistema operativo de tipo Unix, Linux est4 implementado en tenguaje C, y ha sido necesario desde el principio de su desarrollo disponer de un compilador C. El programa gcc, de GNU C Compiler, fue el primer compilador C que permitié la gene- Desarrollo bajo Linux 23 racién de cédigo para Linux. gcc se considera como uno de los mejores productos GNU existentes. Hay que observar que existe un documento particular ([Barlow 1996}) que proporciona ciertos detalles respecto a Linux y gcc. Elcompilador gcc se considera generalmente como uno de los compiladores mas poten- tes. Ademés de ser eficaz en términos de rapidez, de c6digo generado y de optimizacién, soporta todos los esténdares de programacién en C, tanto el ANSI como Ia forma Ila- mada K&R (Kernighan y Ritchie), u otras extensiones det lenguaje C. Para mds detalles sespecto a las formas del lenguaje C, consulte [Kernighan and Ritchie 1992) gcc es también un compilador de C++, que gestiona précticamente todas las caracte- risticas de la altima versién del lenguaje (3.0) definida por Margaret Ellis y Bjarne Stroustrup en [Ellis and Stroustrup 1990]. Gestiona por ejemplo las plantiflas (templa- tes), las excepciones, la herencia miiltiple... Finalmente, gcc permite compilar también un lenguaje bastante particular: Objective C. Se trata de un lenguaje orientado a objetos que no ha gozado de la misma difusién que C++ (fue el lenguaje elegido para el sistema operativo NextStep). 2 Las herramientas del desarrollador Para un desarroliador, el compilador, el enlazador y el depurador son vitales. El com- pilador le indica si hay errores de sintaxis en su cédigo y el enlazador resuelve los dife- fentes simbolos. Sin embargo, no basta con que un programa pase con éxito la etapa de la compilacién para que funcione. Aquf ¢s donde entra en juego el depurador, que permitiré ejecutar paso a paso la aplicacién deseada. 2.1 Las diferentes fases de la compilaci6n La fase de compilacién que empieza con un cédigo en C y produce un cédigo ejecuta- ble es de hecho el resultado de un cierto nimero de acciones. El objetive de este libro no es detallar con precisién fo que ocurre desde el punto de vista del analisis sintécti- 9, Iéxico o semantico. Algunas obras especializadas en este 4mbito como {Aho et al. 1991] detalian todo el funcionamiento de un compilador. Por esta razén, s6lo se pre- senta el funcionamiento de las herramientas a disposici6n del desarrollador. 24 Programacién Linux 2.0 Cédigo fueme C original —_ejemplo.c Preprocesador cpp Programa C completo Compitador el Programaen ensamblador —¢jemplo.s Ensamblador as Cédigo objeto ejemplo.o Enlazador id Bjecutable a.0ut Fis. 3.1 — Desarrollo de una compilacion E] desarrollo de una compilacién, como se puede constatar en la figura 3.1, est4 cons- tituido por una multitud de etapas: * Etcédigo C se envia a través de un preprocesador que efectiia la inclusin de archi- vos de cabecera asf como el reemplazo de las diferentes macroinstrucciones defini- das, El programa cpp es quien se encarga de esta operacion. * Se efectia la compilacién efectiva del c6digo para generar un c6digo ensamblador, El compilador no sélo convierte el c6digo, sino que realiza un buen nimero de opti- mizaciones. Esta operacién la realiza el programa cc/. Desarrollo bajo Linux 25 + La operacién de ensamblado efectuada por el programa as consiste en generar el archivo objeto asociado, + Finalmente, la diltima operacién consiste en generar el ejecutable propiamente dicho del programa. Se trata de reunir todos los archivos objeto y efectuar el enlazado. Esta operaci6n compleja la realiza e] programa /d. Bl apéndice A presenta las diferentes etapas de la compitaciOn de un programa en Cc. 22 gee EI mandato gec permite encadenar las diferentes fases de la compilacién de un pro- ‘grama. Se trata de un lanzador de programas que ejecuta las diferentes etapas (prepro- ‘eesador, compilacién, ensamblado y enlazado) transmitiendo a los programas las opciones proporcionadas por e] programador. La opeién -v permite visualizar los diferentes programas lanzados por gcc: fandali¥ ace -v exenple.c jading specs From Jusr/lib/gco-1ib-id86-linux/2.7.2/specs ¢ varmion 2.7.2 1 /1ib/geo-2ib/i486-1inux/2.7.2/cpp -lang-c ~v -undef -D__GNUC_-2 D_GNUC_MINUR_=7 -D,_ELF__ -Dumix -Di386 -Dlinux -D_£LF_ -D_umix__ i386 -D__linux__ -D_unix -D_{386 -D__linux -As) -cemiunix) ‘stem (posix) -Acpuli386) -Amachine(i386) -D__i486__ exemple.c emp /eeadi212. i. CPP version 2.7.2 {4386 Linux/ELF) fusc/local/ include dust /1486-Linux/ include P jusr /1ib/gee-1ib/i486-Linux/2.7.2/include fusr/include h of search list. fusr/1ib/gce-1ib/i486-Linux/2.7.2/ecl /tmp/cca0i212.1 -quiet -dumpbase le.c -version -o /tmp/cca01212.s ¢ version 2.7.2 (4386 Linux/ELP) compiled by GNU C version 2.7.2 fuer/id86-Linux/bin/as -V -Qy -o /tmp/cca)12121.0 /tmp/cca01212.s assenbler version 960228 (i486-linuxl, using BFD version 2.6.0.12 fuar/1486-Linux/bin/ld -m @lf_i386 -dynanic-linker /Lib/Id-Linux.s0.1 /lib/erti.o /uar/1ib/crti.o /usr/lib/ertbegin.o juar /1ib/gece]ib/i486-Linux/2.7.2 -L/usz/id@6-Linux/lib /cmp/ccadi2121.0 gee «le -lgce fusr/lib/ertend.o /uar/lib/crtn.o 26 Programacién Linux 2.0 Ademas de las diferentes opciones definidas de modo predeterminado (como —linux__), se puede observar que se indican todes los ntimeros de versién de las dife- rentes herramientas, lo cual es muy practico cuando el administrador desea actualizar el entomo de la maquina. Como indica la primera linea que sigue a la lamada a gcc -v, el compilador recupera las opciones predeterminadas en el archivo /usr/lib/gcc-lib/id86-linwx/2.7.2/specs. El camino de acceso es variable segtin la versi6n del compilador y de la instalacién efec- tuada. En algunos casos, puede ser interesante modificar ciertas opciones o integrar otras, a fin por ejemplo de especiatizar el compilador para su procesador. ‘Veamos un pequefio resumen de las principales opciones que pueden pasarse directa- mente a gee: + -M: parada tras la etapa del preprocesador; * -S: parada tras la generacién del cédigo ensamblador; + -c: parada tras la generacin del cédigo objeto; + -g: insercién de los simbolos para la depuracién; + -onomdest: nombre del archivo generado: * -DMACRO: define la macroinstruccién; * -DMACRO=va lor: define la macroinstruccién y le da un valor; * -IDIRECTORIO: directorio donde cpp debe ir a buscar los archivos de cabecera; * -LDIRECTORIO: directorio donde id debe ir a buscar las bibliotecas: * -lbiblioteca: incluye la biblioteca para el enlazado; + -pipe: encadenamiento de las diferentes opciones de compilacién sin utilizar archi- vos temporales. Esta opcién acelera la compilacién pero requiere mas memoria. * On: nivel de optimizaci6n (0 — 3). El mimero de opciones de gee es enorme. Consulte la pagina de manual, o bien [Stallman 1995] para mas detalles. Desarrollo bajo Linux 7 2.3 Depurador Que un programa supere la compilacién con éxito no significa que funcione. Por esta raz6n, una de las herramientas més utilizadas es el depurador. Existen varios depura- dores bajo Unix. Bajo Linux, el que se utiliza es gdb. Para poder depurar un programa, es necesario que este tiltimo se haya compilado con la opcién -g, ya que un depurador requiere ciertas informaciones sobre el programa que no se incluyen en una compilaci6n normal. Resulta de ello un codigo generado de tamaiio mayor. El campo de acci6n de gdb es muy amplio, y se proporciona un ejemplo de uso en el tpéndice B. Se aconseja consultas [Stallman and Support 1994] para saber mas. 2.4 strace mandato strace permite seguir las !lamadas al sisterna ejecutadas por un programa. Indica las primitivas Hamadas, asf como sus pardmetros (traduciendo ciertos valores por constantes simbélicas) y el c6digo de retorno que devuelven. * Damos a continuacién un ejemplo de utilizacién del strace: (0, 4056, READ|WRITE, PRIVATE, 4294967295, 0) = 0x40006000 lavs_125 (0x04048000, Ox7ce, Ox7, 0x8049000, OxB0ab084) = 0 tat ("/etc/d.so.cache", {4ev 3 2 ing 14351 mode 010064¢ nlink 1 uid 0 gid 0 ze 3154 2.41) = 0 (fetosid ache", RDONLY) = 3 (0, 3154, READ, SHARED, 3. 0) = 040007000 {*/usr/lib/1ibe.s0.5.3.9", RDONLY) = -1 (No such file or directory (n/Lib/libe.o.5.3.9*, RDONLY} = 3 (3, *\TEBLFV1\2\2\0\0\O\O\OVOVO\ONDNSVON3NOAIAONOVON FOS NOS AOVONO™. 056) = 4096 (0, 724982, , PRIVATE, 4294967295. 01 = 0x40008000 (0x40008000, 492382, READ|EXEC, PRIVATE|FIXED, 3, 0) = 0x40081006 (0x40081000, 20304, READ|WRITE, PRIVATE|FTXED, 3, 0x78000) = 0x40081000 p(0x40086000, 204856, READ|WRITE, PRIVATE|FIXED, 4294967295. 0) = 0240086000 lose(3) = 0 125 (0x40008000, Ox7835e, Ox7, 0x40008000, Ox7835e) (0x40007000, , 3154, } = 0 1-125 (0x8048000, Ox7ce, Ox5, Ox8048000, Ox?ce) = 0 1-125(0x40008000, Ox7835e, OxS, 0x40008000, 0x7835e) out of range: 136 ir(Bogua syscall: 1073774592) = 0 (OxB049918) = 0x8069918 (0x804da000) = 0x804a000 28 Programacion Linux 2.0 fatac(t, (dev 0 0 ino 35430 mode 010600 nlink 1 uid 501 gid 100 size 0 ...}) = 0 {0, 4096, READ|WRITE, PRIVATE, 4294967295. 0) = ox40007000 lwrite(1, *Cha\eene initiale : exemple \n Cha"... 68 Cadena inicial : ejemplo Cadena duplicada : ejemplo Jemplo ) = 68 Jax (2074283076) = 2 En el ejemplo anterior, el programa empieza por cargarse y seguidamente busca la biblioteca dindmica C. Tras un fracaso (ta biblioteca no se encuentra en /usr/lib), se carga la dibe que se encuentra en (lib. Las diferentes Hamadas a mmap y a mprotect (SYS_125) realizan las cargas del pro- grama y de la biblioteca, Las dos !lamadas brk corresponden a dos asignaciones de memoria efectuadas en el programa. Finalmente, las lamadas a fstat » write corresponden a la escritura en la salida estén- dar del resultado de la operacién. El programa termina por una llamada a exit. 2.5 make 2.5.1 Presentacién La herramienta make facilita ta compilaci6n de proyectos. Es una herramienta est4ndar instalada en todo sistema Unix. Este programa permite efectuar una compilacién inte- ligente de programas, en funcién de los archivos modificados que necesitan realmente ser recompilados. Sin embargo, Ja sintaxis de los archivos Makefile es relativamente compleja de escribir porque utiliza reglas de reescritura, Una muestra de las capacidades de esta herramienta se presenta en el apéndice C. Para mis detalles, se aconseja referirse a la pagina de manual de make, o ala documentacién de la versién GNU [Stallman and McGrath 1995]. 3 Formato de los ejecutables Linux soporte dos formatos de programas ejecutables. El primer formato binario utili- zado por Linux fue el formato llamado a. out. Sin embargo, este formato era de uso Poco prictico para implementar bibliotecas dindmicas, y ahora el formato binario uti- lizado es ELF. Desarrollo bajo Linux 29 3.1 a.out: el ancestro El formato a.out (Assembler.OUT put) es el formato de las bibliotecas y ejecutables uti- lizado en las primeras versiones de Unix en general y de Linux en particular. Existen diversas variantes de este formato (ZMAGIC, QMAGIC ...). QMAGIC es el for- mato de fos ejecutables que se parece algo a fos antiguos binarios a.out (también conoci- dos como ZMAGIC), pero deja la primera p4gina del programa libre. Ello permite recu- perar mds facilmente las direcciones no asignadas (como NULL) en el intervalo 0-4096, Los enlazadores anticuados sélo gestionan el formato ZMAGIC, mientras que los mAs recientes gestionan los dos. Los dos tipos son, de todos modos, soportados por el micleo, Para saber si un programa es de formato aout, basta con utilizar el mandato file: lgandalf# file /usr/local /bin/kermit fuse /1i bin/kermit: Limw/i386 demand-paged executable (ZMAGIC) Si Ja cadena Linux/i386 aparece, el binario especificado esté en formato a.out. Asimismo, se precisa que se trata de un binario en formato ZMAGIC. El formato de tos binarios de tipo a.out se implementa en el archivo fs/binfimt_aout.c. Sin embargo, la gestién de este formato s6lo se conserva por razones histéricas. Por ello no detailaremos su funcionamiento. 3.2 ELF 3.2.1 Bienvenida al mundo ELF El nuevo formato de binarios para Linux es el fomato ELF (que no tiene nada que ver con el mundo de Totkien y sus anillos, aunque a primera vista algunas caracterfsticas parezcan extrafias, enigmiticas o mégicas). ELF es la abreviatura de Executable and Linking Format. Este formate fue inicialmente disefiado y desarrollado por el USL (Unix System Laboratories), y es utilizado por los sistemas de tipo SVR4 y Solaris 2.x. Dado que ELF es mucho mis flexible y manejable que el formato a.out, los desarro- Nadores de Linux decidieron migrar hacia este formato en 1994, La técnica de migra- cién se detalla en [Barlow 1995] y en [Dumas 1996}. 30 Programacién Linux 2.0 3.2.2 ELF y su formato ELF se ha convertido en un formato extendido y muy utilizado (en varios sistemas Unix) porque es de manipulacién simple. Esta facilidad proviene de su estructura. El formato ELF se detalla completamente en [TIS 1993]. El formato ELF permite generar tres tipos de archivos: * archivo relocalizable (archivo objeto}; * archivo ejecutable; * archivo compartido (bibliotecas). (Cabecera ELF Tabla de cabecera del programa (opcién) Seecion 1 Seccién 2 — Seccién n ‘Secci6n de tabla de cabecera Po iG 3.2 — Formato ELF: estructura En todos los casos, el formato del archivo es el mismo, como lo ilustra la figura 3.2. La cabecera del archivo ELF constituye una descripcién del archivo y describe su orga- nizaci6n, Es la tnica cosa que tiene una posicién fija en el formato de un archivo ELF: Jas demds secciones pueden colocarse en cualquier lugar en el archivo. Pero es posible acceder directamente a estos datos. El archivo de cabecera (en realidad, el archivo es quien contiene los datos) contiene la declaracién de la estruc- tura de cabecera de un archivo ELF, Se trata de la estructura E1£32_Ehdr. Desarrollo bajo Linux 31 campo descripcion unsigned char | e_ident Nemero mégico del archivo con [EI_NIDENT] ciertas indicaciones E1£32_Half e_type Tipo del archivo E1£32_Half e_machine Arquitectra del archivo E1£32_Word e_version Versién del formato de archivo E1£32_Adér e_entry Direecién virtuat del punto de entrada del programa E1£32_0ff e_phoff Desplazamiento para encontrar Ia tabla de cabecera del programa E1£32_0ff e_shoft Deplazamiento para encontrar la sec+ cin de cabecera del programa E1£32_Word e_flags Opciones particulares para el procesador E1£32_Half e_ehsize Tamaio de la cabecera en bytes B1f32_Half e_phentsize ‘Tamafio de una entrada en la tabla de cabecera del programa Bif32_Hal£ e_phnum Numero de entradas en la tabla de entrada del programa B1f32_Half e_shentsize Tamafio de una cabecera de seccién B1f£32_half e_shunm Numero de entradas en la tabla de secciones E1£32_half e_shstrndx Indice de la tabla de secciones El campo de identificacién, constituide por una tabla de bytes, es muy importante. Se puede descomponer de la forma siguiente: Constituido por 4 bytes: Ox7£ EL F. Este niimeto magico est4 constituido en realidad por cuatro macrodefiniciones: ELFMAGO, ELFMAG1. ELFMAG2 y ELFMAG3. clase del archive | ELF es un formato portable, por lo que las | direcciones del archivo pueden estar en forma de 32 0 64 bits. Este byte puede tener| los valores ELFCLASSNONE (invélido), ELFCLASS32 0 ELFCLASS6&4. tipo de codificacion | Determina si se encuentra en un entorno de mayor o menor peso. Pueden darse los valores ELFDATANONE (invdlido), ELFDATA2LSS y ELFDATA2MSB. | Da el inicio de los bytes no utilizados y | asignados para extensiones futuras. 32 Programacion Linux 2.0 A partir de esta cabecera, es posible acceder a las diferentes secciones del archivo. Su trimero y posicién son completamente variables, en funcién del compilader que ha generado el c6digo, las opciones especificadas en la generacién del archivo objeto, 0 simplemente del lenguaje en el que se haya escrito el cédigo fuente Sin embargo, explorar un archivo binario ELF a mano es una operacién que resulta en ocasiones oscura y compleja. Una biblioteca facilita los accesos a las informaciones de un archivo ELF, proporcionando funciones de andlisis. Para utilizar estas dltimas, hay que incluir el archivo y afiadir Ia opci6n -1e1£ enel enlazado. 4 Presentacién de las bibliotecas 4.1 Utilidad Las bibliotecas constituyen una manera simple de agrupar varios archivos objeto. Existen dos tipos de bibliotecas: * estéticas: en el enlazado, el cédigo de la biblioteca se integra al ejecutable; + dindmicas: el cédigo de la biblioteca se carga en la ejecucién del programa, Las bibliotecas dinamicas permiten una economfa de espacio en disco pero més atin de oeupacién de memoria porque una biblioteca dinémica se carga una sola vez, y el c6di- go puede ser compartido por todas las aplicaciones que la necesiten, Finalmente, cuane do una biblioteca dindmica se actualiza, no ¢s necesario recompilar las aplicaciones que la utilizan. La biblioteca dindmica que se utiliza cotidianamente es la biblioteca en C. Todas las aplicaciones (salvo algunas excepciones) se enlazan dindmicamente con la biblioteca C. El programa Idd permite conocer la lista de bibliotecas enlazadas con una aplicacién: gandalf# idd /usr/X386/bin/xv libXext.so.6 => /usr/X11/1lib/libXext.so.6.0 1ibxl1.so.6 => /usr/X11/lib/1ibxil,.s0.6.0 libm.so.5 => /lib/libm.so.5.9.5 libe.so.5 => /lib/libe.so.$.3.9 Desarrollo bajo Linux 33 4.2 Utilizacién de bibliotecas La utilizacién de una biblioteca es muy simple: basta con especificar en cl enlazado la biblioteca. Por ejemplo: gandalf¥ gce -o demo_compleja main.c -L/usr/local/compleja - compleja -1m gandalf# 1dd demo_compleja Libm.so.5 #> /lib/libm.s0.5.0.5 libe.so.5 => /lib/libc.so.5.3.9 Eh resultado anterior corresponde al caso en que !a biblioteca haya sido generada de forma estética, y no dindmica. El apéndice D expone varias herramientas de gestién de bibliotecas. 5 Organizacién del cédigo fuente del nticleo 5.1 Nucleo Los programas fuente del nécleo Linux se instalan normalmente en el directorio fusr/srcflinux, Se organizan de manera jerdrquica, como se puede ver en la figura 3.3. Cada directo- rio o subdirectorio se dedica a ciertas funcionalidades del niicteo: © Dacumentacién: un cierto mimero de archivos de documentacién respecto a la con- figuracién del niicleo o e] funcionamiento de ciertos médulos; * include: todos los archivos de cabecera necesarios para la generacién del nucleo pero también para la compilacién de aplicaciones; + fs: sistemas de archivos; © init: el main.c de Linux; + ipc: gestién de las comunicaciones interprocesos segiin la norma System V; + mm: gestién de la memoria; * kemel: principales llamadas al sistema; Programacién Linux 2.0 * lib: médutos diversos; + drivers: controladores de dispositivos; * net: protocolos de red; * arch: cédigo dependiente de la plataforma; + scripts: scripts utilizados para la configuracién y para la generacién de las depen- dencias del niicleo. 5.2 Archivos de cabecera Los archivos de cabecera utilizados por el preprocesador del lenguaje C (como por ejemplo) se sitian en el directorio /usr/include. Definen la interfaz de las bibliotecas utilizadas por los programas que se compilan. Estos archivos de cabecera se enlazan con la biblioteca C, que se distribuye indepen- dientemente del micleo. El nicleo Linux dispone también de archivos de cabecera que se utilizan en su compi- lacién. Estos archivos se sitéan en el directorio /usr/src/linux/include. Encontramos principalmente dos subdirectorios: + linux: este directorio contiene las declaraciones independientes de la arquitectura; * asm: este directorio contiene las declaraciones dependientes de la arquitectura: se trata de un enlace con otro directorio (asm-i386 para la arquitectura x86 por ejemplo). Dos enlaces simbélicos permiten también acceder a estos archivos desde el directorio Jusr/include. También es posible incluir en un programa archivos de cabecera que defi- nen constantes y tipos utilizados por el mécleo utilizando las notaciones y . Hay que observar, sin embargo, que no es aconsejable la inclusién de tales archivos. Es preferible incluir los archivos estandar de la biblioteca C, porque estén previstos para ello. Estos archivos de cabecera se encar- gan de importar las definiciones del nticleo. En tos capftulos siguientes, la descripcién de Ilamadas ai sistema de Linux presenta los archivos de cabecera esténdar, que se pueden encontrar en todo sistema Unix. Ciertas definiciones de constantes y de tipos se efecttian en los archivos de cabecera del nticleo, pero estos iiltimos no se detallan en las primeras partes de cada capftulo, por razones de portabilidad. Desarrollo bajo Linux 35 dere ape ma 4 networking ‘Documeatidon |-———+} oO ape = ‘ata ee muheno w = ee eet 68 | motte = ext im wy ine iain fs |} om —|—|= = ™ = “ wt rien ot was = ive a moe = te ats owe os ecu et ver cet ‘ape - et a ~— | tet ey ten o q Lee Fic. 3.3 - Arbol de fuentes Por el contrario, el contenido de los archivos de cabecera del nticleo se describe en la explicacién del funcionamiento de las diversas partes del nticleo. 36 Programacion Linux 2.0 6 Funcionamiento del nticleo 6.1 Llamadas al sistema Como se explica en el capitulo 2, seccién 4.1, un proceso se ejecuta normalmente en modo usuario y debe pasar al modo micleo para ejecutar las Ilamadas af sistema. 6.1.1 Implementacién de una Ilamada al sistema Una llamada al sistema se caracteriza por un nombre y un numero Gnico que la identi- fica, Este nimero puede encontrarse en el archivo . Por ejemplo, Ja llamada al sistema open tiene el nimero 5. El nombre se define en el archivo ensam- blador arch/i386/kernel/entry.S (aunque este archivo se encuentra en un directorio dedicado a la arquitectura x86, existe para las otras arquitecturas), y se Mama sys_open. La biblioteca C proporciona funciones que permiten ejecutar una llamada al sistema. Estas funciones afectan al nombre de las ltamadas al sistema. Basta. pues, para ejecu- tar una Ilamada al sistema con Ilamar a la funcién correspondiente. En los programas fuente del micleo, una llamada al sistema posee el prototipo siguiente: asmlinkage int sys_nomllamada(lista de argumentos) { /* Cédigo de la llamada al sistema */ } E] némero de argumentos debe estar comprendido entre 0 y 5. La palabra clave asm- linkage es una macroinstruccién definida en el archivo <1inux/Linkage.h>: #ifdef _ cplusplus #define asmlinkage extern °C” felse #define asmlinkage #endif£ Cuando un Proceso ejecuta una llamada al sistema, Hama a la funcién correspondiente de la biblioteca C. Esta funcién trata los pardmetros y hace pasar al proceso al modo micleo. Desarrollo bajo Linux 37 En Ia arquitectura x86, este paso a! modo micleo se efectiia de 1a forma siguiente: + los parémetros de Ia llamada al sistema se colocan en ciertos registros del procesador; * se provoca un bloqueo desencadenando la interrupcién légica 0x80; + este bloqueo provoca el paso del proceso al modo nticleo; el proceso ejecuta la fun- cién system_call definida en el archivo fuente arch4i386/emel/entry. * esta funcién utiliza el ntéimero de Iamada al sistema (transmitido en el registro eax) como {indice en la tabla sys_call_table, que contiene las direcciones de las Iamadas al sistema, y llama a la funcién de! micleo correspondiente a la llamada al sistema; « al volver de esta funcién, system_cal1 vuelve a quien ha llamado; este retorno vuelve a pasar al proceso al modo usuario. 6.1.2 Creacién de una llamada al sistema Para comprender bien el funcionamiento de una llamada al sistema, nada mejor que crear una. La Ilamada al sistema que vamos a crear consiste en tomar tres argumentos, hacer la muttiplicaci6n de los dos primeros y colocar el resultado en el tercero. En un primer momento, es necesario «declarar» la Hamada al sistema, y por tanto asig- narle un ntimero. La versién 2.0 de Linux cuenta con 164 Hamadas al sistema. La Ila- mada al sistema show_mult tendré pues como némero el 164 (ta primera llamada al sis- tema, setup, tiene por numero 0). Para declarar nuestra Hamada, hay que afiadir en el archivo include/asm/unistd.h: /* Liamadas al sistema del nicleo */ define __NR_sched_get_priority_min 160 define _NR_sched_rr_get interval 161 #define _NR_nanosleep 162 define __NR_mremap 163 /* lamada al sistema afiadida */ define _NR_show_mult 164 Seguidamente, en el archivo arch/i386/kernel/entry.S (0 bien en el archivo entry.S de la arquitectura): /* Llamadas al sistema del nucleo */ slong SYMBOL_NAME(sys_sched_get_priority_min) /* 160 . En el caso de una llamada al sistema que acepta tres pardmetros, hay que utilizar la macroinstrucci6n _syscal13. Desarrolio bajo Linux 39 #include #include #include ~syseall3 (int, show_mult, int, x, int, y, int *resul}; main () { int ret = show_mule (2, 5, &ret); printf ("Resultado td %d = %d \n*, 2. 5, ret}: } La macroinstruccién _sysca113 es expandida por el preprocesador y proporciona el cédigo siguiente: int showmult(int x, int y, int *resul) t long _res; —asm_ _volatile (‘int $0x80” : ” (ures) sor (164), “b* ((long)( x ))- “e" ((long)t y )}. “a” ((long)( resul ))); if (_res>=0) return ( int } _res; errno=__res; return -1; te La funcién show_mult es generada por_syscal13, que inicializa los registros del procesador (e] nimero de la llamada al sistema se coloca en el registro eax y los paré- metros se colocan en tos registros ebx, ecx y edx), y seguidamente desencadena la interrupcién 0x80. De vuelta de esta interrupcién, es decir, al volver de ta Hamada al sistema, el valor de retormo se comprueba. Si es positive o nulo, se devuelve a quien Hama. En caso contrario, este valor contiene el cédigo de error devuelto; entonces se guarda en la variable global errno y se devuelve el valor -1 6.1.3 Cédigos de retorno E] nticleo puede detectar errores en Ja ejecucién de una lamada al sistema. En ese caso, se devuelve un cOdigo de error al proceso que hace la llamada, 40 Programacién Linux 2.0 Generalmente, se devuelve el valor —1 en caso de error. Este valor indica tinicamente que se ha producido un error. A fin de permitir al proceso que ha llamado determinar la causa det error, la biblioteca C properciona una variable global Hamada errno. Esta variable se actualiza tras cada llamada al sistema que cause un error, y contiene un cédigo que indica la causa del error, No se actualiza tras una Iamada al sistema con éxito, por lo que hay que comprobar el valor de retomo de cada llamada al sistema y__ utilizar el valor de errno s6lo en caso de fallo. El archivo de cabecera define numerosas constantes que representan los posibles errores. En los capitulos siguientes, se detalla en la presentacién de las llama- das al sisterna la lista de codigos de error que pueden ser devueltos. La biblioteca C proporciona también las dos variables siguientes: extern int _sys_nerr; extern char *_sys_errlist{]; La variable _sys_nerr contiene el numero de cédigos de error implementados. La tabla _sys_errlist contiene las cadenas de caracteres que describen todos los errores, E] mensaje de error correspondiente al ultimo error detectado puede obtenerse pues por medio de _sys_errlist [errno]. Adems, la biblioteca C proporciona dos funciones: #include #inclue void perror (const char *s); char *strerror (int errnum); La funcién perror muestra un mensaje en Ia salida de errores del proceso que llama. Este mensaje contiene la cadena especificada por el parémetro s y el mensaje de error correspondiente al valor de errno. La funcién strerror devuelve la cadena de carac- teres correspondiente al error cuyo cédigo se especifica en el parimetro errnum. 6.2 Funciones de utilidad El nucleo contiene numerosas funciones de utilidad que hay que presentar ya ahora. Aunque estas funciones sean descritas en capitulos ulteriores, es necesarié conocer sv funcionamiento para comprender la descripcién de las funciones internas. Desarrollo bajo Linux al 6.2.1 Manipulacién de espacio de direccionamiento E] espacio de direccionamiento de un proceso en modo niicleo es diferente de su espa- cio de direccionamiento cn modo usuario. Le resulta por tanto imposible acceder direc- tamente a los datos cuya direccién se ha pasado como parémetro a una Hamada al sis- tema. Linux proporciona varias funciones para acceder a estos datos: int verify_area (int type, const void ‘addr, unsigned long size): void put_user (unsigned long value, void *addr}; unsigned long get_user (void *addr); void memcpy_tofs (void ‘to, const void ‘from, unsigned leng size); void mamcpy_fromfs (void *to, const void *from, unsigned long size); La funcién veri fy_area verifica que la direccién pasada (parametro addr) es vali- da. El pardmetro size representa el ntimero de bytes de la zona, y tipe especifica el tipo de la verificacién. Este pardmetro puede tomar e] valor VERIFY_READ para veri- ficar que la zona de memoria es accesible para lectura 0 VERIFY_WRITE para escri- ‘ura. La funcién put_user escribe el valor especificado por el pardmetro value en el espacio de direccionamiento del proceso que lama, en la direccién especificada por el pardmetro addr. La funcién get_user devuelve el valor situado en la direccién pasada en el pardmetro addr, en el espacio de direccionamiento del proceso que llama. La funcién memcpy_tofs copia datos desde el espacio de direccionamiento del miicleo hacia el espacio de direccionamiento del proceso que Hama. El parémetro to contiene la direccién en el espacio de direccionamiento del proceso. from contiene la direcci6n en el] espacio de direccionamiento del nicleo y size especifica el nimero de bytes a copiar. La funcién memcpy_fromfs efectia la copia de datos desde el espacio de direccionamiento del proceso que Hama hacia cl espacio de direcciona- miento del nucleo. Estas funciones se detallan en el capitulo 8, seccién 6.5. 6.2.2 Asignaciones y liberaciones Se proporcionan varias funciones de asignacién dindmica y liberacién de memoria para las necesidades internas del nucleo: 42 Programacién Linux 2.0 void *kmalloc (unsigned int size, int priority); void kfree (void *addr); void *vmalloc (unsigned long size); void vfree (void *addr); La funci6n kmalloc asigna una zona de memoria cuyo tamario se especifica por el pardmetro size, y devuelve la direcci6n de la zona asignada, En caso de fracaso, se devueive el valor NULL. El parametro priority especifica el tipo de la asignacién: s Asignacién de memoria para el biifer caché Asignacién de memoria para un gestor de interrupciones. Asignacién de memoria para un proceso en modo usuario. Asignacién de memoria para el niicteo. Asignacién de memoria para el soporte del sistema de archivos NFS. La funci6n kfree libera una zona de memoria cuya direcci6n se pasa en el paréme- tro addr, Esta direcci6n debe corresponder con un valor devuelto por kmalloc, Las funciones vmalloc y vf£ree implementan también la asignacién y la liberaci6n de zonas de memoria, que son mAs flexibles que kmal loc y kfree. Estas funciones se detallan en el capitulo 8, secci6n 5.3.2. Capitulo 4 Procesos -——Primitivas detalladas exit, clone, exit, fork, getegid, geteuld, getgid, getgroups, getpgid, getperp, getpid, getppid, getpriority, getrlimit, getrusage, getsid, getuid, nice, ptrace, sched_yield, setegid, seteuid, setfsgid, setfsuid, setgid, setgroups, setpgid, setperp, setpricrity, setregid, setreuid, setrlimit, setsid, | setuid, times, wait, wait3, wait4, waitpid 1 Conceptos basicos 1.1 Nocién de proceso De manera informal, puede considerarse como un programa en curso de ejecuci6n. Este progresa de manera secuencial: en todo momento, se ejecuta una instruccién como maximo de la serie del proceso. Sin embargo, un proceso no se limita al programa que ejecuta. También se caracteriza por su actividad puntual, representada por el valor del contador ordinal y los registros det procesador. Incluye una pila, que contiene datos temporales, y un segmento de datos que contienen variables globates. Un programa en sf mismo no es un proceso: un programa es una entidad pasiva (archi- vo ejecutable residente en un disco), mientras que un proceso es una entidad activa con un contador ordinal que especifica la instruccién siguiente a ejecutar y un conjunto de recursos asociados, 44 Programacién Linux 2.0 1.2 Estado de un proceso En el transcurse de su ejecuci6n, un proceso cambia de estado. E] estado de un proce- so se define por su actividad actual. Los diferentes estados posibles de un proceso son los siguientes: * en ejecucién: el proceso es ejecutado por el procesador; * a punto: el proceso podrfa ser ejecutado pero otro proceso se estd ejecutando en ese momento; * suspendido: e] proceso est4 en espera de un recurso; por ejemplo, espera el fin de una entrada/salida; * parado: el proceso ha sido suspendido por una intervencién externa; * zombi: el proceso ha terminado su ejecucién pero sigue siendo referenciado en el sistema. ‘Los cambios de estado de un proceso se representan en ¢l grafo de estados, figura 4.1. Fic. 4.1 - Grafo de estados de un proceso Procesos 45 1.3 Atributos de un proceso Durante su ejecucién, un proceso se caracteriza por varios atributos mantenidos por el sistema: * su estado; * su identificador (nitmero tinico); + el valor de los registros, incluyendo el contador ordinal; * la identidad del usuario bajo cuyo nombre se ejecuta; + las informaciones utilizadas por el nécleo para proceder al ordenamiento de los pro- cesos (prioridad...); «las informaciones respecto al espacio de direccionamiento del proceso (segmentos de cédigo, de datos, de pila); + las informaciones respecto a las entradas/salidas efectuadas por el proceso (des- criptores de archivos abiertos, directorio actual...); * informaciones de contabilidad que resumen los recursos utilizados por el proceso. 1.4 Identificadores de un proceso A.un proceso se le asocian varios identificadores de usuarios y de grupos: + el identificador de usuario real: es el identificador del usuario que ha lanzado el pro- ceso; +* el identificador de usuario efectivo: es el identificador que utiliza el sistema para los controles de acceso; puede ser distinto del identificador de usuario real, por ejem- plo en el caso de programas que poseen el bit setuid; * el identificador de grupo real: es el identificador de grupo primario del usuario que ha lanzado ef proceso; * el identificador de grupo efectivo: es el identificador que utiliza el sistema para los controles de acceso; puede ser diferente del identificador de grupo real, por ejem- plo en el caso de programas que poseen el bit setgid; 46° Programacién Linux 2.0 + una lista de identificadores de grupos: todo usuario puede pertenecer a varios gru- pos de manera simulténea, y el nticleo mantiene una lista de grupos asociados a cada proceso a fin de proceder a los controles de acceso. Bajo Linux, un proceso puede poseer hasta 32 grupos. Linux mantiene también otros dos identificadores: el saved uid y el saved gid. Cuando un proceso modifica su identificador de usuario o de grupo efectivo, por una llamada a las primitivas setreuid 0 setregid, el miicleo autoriza la modificacién en los casos siguientes: «el proceso posee los privilegios de superusuario; «el proceso especifica el mismo valor para el nuevo identificador; * el nuevo identificador es igual al identificador guardado. Estos identificadores guardados son particularmente ttiles para un proceso que ejecu- te un programa que posee el bit setuid, resp. setgid, es decir, un proceso que posee identificadores de usuario, res. grupo, real y efectivo diferentes. Este proceso puede utilizar las primitivas setuid, resp. setgid, y setreuid, resp. setregid, para anular sus pri- vilegios, utilizando el identificador de usuario o de grupo real, efectuar un tratamiento que no necesita ningun privilegio particular, y luego restaurar su identificador de usua- rio o de grupo efectivo. 1.5 Filiaci6n La creaci6n de un proceso se efectéa duplicando el proceso actual: la llamada al siste- ma fork permite a un proceso crear una copia conforme a s{ mismo, exceptuando el identificador de proceso. El proceso que se duplica se llama et proceso padre, y el nuevo proceso se llama el proceso hijo. Cuando Linux arranca, crea el proceso nimero 1 que ejecuta el programa init, encar- gado de inicializar e] sistema. Este proceso crea a su vez procesos para efectuar dife- rentes tareas, pudiendo éstas a su vez crear nuevos procesos. El resultado es una jerar- quia de procesos emparentados. La figura 4.2 muestra una jerarqufa tfpica de procesos, mediante ¢] mandato pstree. 1.6 Grupos de procesos Linux mantiene grupos de procesos. Un grupo de procesos es un conjunto que contie- ne uno o més procesos. Todo proceso forma parte de un grupo, y sus descendientes per- tenecen en principio al mismo grupo. Un proceso puede elegir crear un nuevo grupo y Procesos 47 ‘vi (30664). ./Processus/ConceptsBase.tex *-tesh(30716) -c pstree -a -< -p *-pstree (30720) -a -c -p ~xeexm(17889) *=tesh {17893} |-make (30696) | ‘-latex (30715) Livre. tex * ~xavi (26449) Livre *-gs (28531) -SDEVICE=x11 -@NOPAUSE -q - ~xterm(10788) *-tesh (10791) *-xtexm(10790) »-tesh (10792) inte) auto |-lagetty, 9700} |-tagetty, 9699) |-(agetty, 9698) |-fagetty, 71) |-exon{26} |-innd (63) -pa -10 -c360 | ‘-overchan (72) |-Ue£lushd, 2) |- (kewapd, 3) j-selection(40) -t mac -c 1 -pm |-syslogd(36) [-(tesh, 9701) | "= (startx, 9724) I >= (xinit,9725) I 1-x(9726) :0 I * Even (9728) I |-FvwnPager (9735) 9 4 /home/card/.fwwmre 0 8 0 2 | |~Goodstuft (9733) 7 4 /home/card/.fvwmre 0 8 I |= Gxclock, 9734) I |-xterm(9731) -geometry 80x50+20+50 | | \-tesh(9737) | *=xterm(9732) -geometry 80x20+530+70 I *={tesh, 9736) | ~bash (10771) |-update(9) |-xtexm(10311) | *-teeh(10316) |-xterm(10321) | >-tesh (103281 |-xtexm(10325) | *+tesh (10330) | | i i | | | | | | | Fic, 4.2 - Jerarquia tipica de procesos convertirse asf en jefe (Jeader) del grupo. Un grupo se identifica por su mimero de. grupo, que es igual al mimero de su proceso leader. 48 Programacién Linux 2.0 Esta nocién de grupo permite enviar sefiales a todos los procesos miembros de un grupo (véase el capftulo 5, seccién 2.1), a fin de implementar el job control. Los intér- pretes de mandatos (bash, csh, ksh...) utilizan estos grupos para permitir al usuario sus- pender la ejecucién de procesos y proseguirla, en primer plano o en segundo plano. Los grupos de procesos se utitizan asimismo en la gestién de terminales (véase el capt- tulo 9, seccién 2.6). 17 Sesiones ‘Una sesi6n es un conjunto que contiene uno o mds grupos de procesos. A cada sesi6n se Ie asocia un terminal de control tinico. Este terminal de control es o bien un dispo- sitivo terminal (en una conexién a la consola), o bien un dispositivo pseudoterminal (en una conexi6n remota). Cuando un proceso crea una nueva sesi6n: = se convierte en el proceso /eader de la sesién; + se crea un nuevo grupo de procesos y el proceso que llama se convierte en su leader, * el proceso que llama no tiene terminal de control. ‘Una sesi6n se identifica por su nimero, que es igual al numero de su proceso leader. Generalmente, se crea una nueva sesién por parte del programa /ogin en la conexi6n de un usuario. Todos los procesos creados forman parte de la misma sesi6n. En el caso de encadenamiento de mandatos (por medio de tuberfas, por ejemplo), el intérprete de mandatos (shelf) crea nuevos grupos de procesos, para implementar el job control, 1.8 Multiprogramacié6n. En un instante dado, hay un solo proceso en ejecucién (al menos en un ordenador mono- procesador). Este proceso se Ilama el proceso actual. El sistema mantiene una lista de procesos a punto que podria ejecutar y procede periédicamente a un ordenamiento. ‘Accada proceso se le atribuye un lapso de tiempo. Linux elige un proceso a ejecutar, y le deja ejecutarse durante ese lapso. Cuando ha transcurrido, el sistema hace pasar al proceso actual al estado a punto, y elige otro proceso que ejecuta durante otro lapso. El lapso de tiempo es muy corto y el usuario tiene la impresién que varios procesos se eje- cutan simulténeamente, aunque sélo un proceso se ejecuta en un instante dado, Se dice que los procesos se ejecutan en pseudoparalelismo. Procesos 49 2 Llamadas al sistema de base 2.1 Creacién de pracesos El proceso actual puede crear un proceso hijo utilizando la llamada al sistema fork. Esta primitiva provoca la duplicacién del proceso actual. Su prototipo es el siguiente: #include pidt fork (void); En la llamada a fork, el proceso actual se duplica: se crea una copia que le es idéntica, excepto en su identificador y el de su padre. Al volver fork, dos procesos, el padre y el hijo, ejecutan el mismo c6digo. La primitiva fork devuelve el valor 0 al proceso hijo, y devuelve el identificador del proceso creado al proceso padre. Es pues imperative comprobar su valor de retomo para distinguir el cédigo que debe ser ejecutado por el proceso padre y ¢l que debe ser ejecutado por el proceso hijo. En caso de fallo, fork devuelve el valor ~1, y la variable exrno puede tomar los valores siguientes: error ado AGAIN | Se ha Ilegado al mimero méximo de procesos del usuario actual o del sistema. ENOMEN | E] nicleo no ha podido asignar suficiente memoria para crear un nuevo proceso. El programa siguiente ilustra la llamada al sistema fork para crear un proceso hijo. include #include include void main (void) { pidt pid; pid = fork QO; if (pid == -1) perror ("fork"); else if (pid == 0) printf (‘soy el hijo: pid = td\n",pid); else printé ("soy el padre: pid = %d\n",pid); 50 Programacién Linux 2.0 2.2 Finalizacién del proceso actual El proceso actual termina automdticamente cuando deja de ejecutar la funcién main, utilizando la instrucci6n return. También dispone de !lamadas aj sistema que le per- miten parar expl{citamente su ejecucién: #include void exit (int status); void exit (int status); Las primitivas _exit y exit provocan la finalizacién del proceso actual. El pardmetro status especifica un cédigo de retorno, comprendido entre 0 y 255, que hay que comunicar al proceso padre. Por convencién, un proceso debe devolver el valor 0 en caso de finalizacién normal, y un valor no nulo en caso de finalizacién debida a un error. Antes de terminar la ejecuci6n del proceso, exit ejecuta las funciones evenmalmente registradas por tlamadas a las funciones de biblioteca atexit y on_exit. Si el proceso actual posee procesos hijos, éstos se vinculan al proceso numero 1, que ejecuta el programa init. La sefial SIGCHLD se envia al proceso padre para prevenirle de la finalizaci6n de uno de sus procesos hijos. 2.3 Espera de la finalizacién de un proceso hijo Un proceso puede alcanzar Ia finalizacién de un proceso hijo mediante tas primitivas wait y waitpid. Su sintaxis es la siguiente: #include #include pidt wait (int *statusp): pid_t waitpid (pid_t pid, int “statusp, int options); La primitiva wait suspende la ejecucién del proceso actual hasta que acabe un proceso hijo. Si un proceso hijo ya ha terminado, wait devuelve el resultado inmediatamente. La primitiva waitpid suspende ta ejecucién del proceso actual hasta que un proceso hijo especificado por el parémetro pid termine. Si un proceso hijo correspondiente a pid ha terminado ya, waitpid devuelve el resultado inmediatamente. Procesos 51 E] resultado de waitpid depende del valor del parametro pid: « si pid es positivo, especifica el nimero del proceso hijo a esperar; + sipides nulo, especifica todo proceso hijo cuyo niimero de grupo de procesos sea igual al del proceso que llama; * sipides igual a—1, especifica la espera de la finalizacién del primer proceso hijo; en este caso, waitpid ofrece la misma seméntica que wait; * si pides inferior a -1, especifica todo proceso hijo cuyo mimero de grupo de pro- cesos es igual al valor absoluto de pid. Dos constantes, declaradas en , pueden utilizarse para inicializar el parémetro options, a fin de modificar el comportamiento de waitpid: significado Provoca un error inmediato si no ha terminado adn ningdin proceso hijo. Provoca la consideraci6n de los hijos cuyo estado cambia, es decir, los procesos hijos cuyo estado ha pasado de a punto a suspendido. Las dos primitivas devuelven et mimero del proceso hijo que ha terminado, o el valor -1 en caso de fallo. El estado del proceso hijo se devuelve en la variable cuya direc- ci6n se pasa en el parametro statusp. La interpretacién de este estado se efecnia gracias a macroinstrucciones definidas en el archivo de cabecera : Sgr No nulo si el proceso hijo ha terminado por una llamada a _exit o exit. Cédigo de retorno transmitide por el proceso hijo en su finalizacién. No nulo si el proceso hijo ha sido interrumpido por la recepci6n de una seal. Niimero de sefial que ha provocado la finalizacién del proceso hijo. No nulo si el proceso hijo ha pasado del estado a punto a suspendido. Némero de seiial que ha causado Ia suspensién del proceso hijo. Linux implementa también otras dos amadas al sistema que aseguran una compatibi- lidad con los sistemas BSD Unix. #include include #include pid_t wait3 (int *statusp, int options, struct rusage *rusage) ; 52 Programacion Linux 2 pict waité (pidt pid, int *statump, int options, struct rusage ‘rusage); Estas lamadas son relativamente parecidas a wait y waitpid. Aceptan un pardmetro suplementario, rusage, que apunta a una variable en la que se colocan las informa- ciones de compatibilidad del proceso. La estructura rusage, definida en el archivo de cabecera , contiene los campos siguientes: struct timeval struct timeval long long long long long long long long long long long long long ru_idrss ru_isrss ru_minflt ru_majfic ru_inblock ru_oublock ru_msgsnd ru_msgrev ru_nsignals xu_nvcsw eripelon Tiempo de procesador consumido por el proceso en modo usuario. Tiempo de procesador consumido por el proceso en modo niicleo. Tamafio maximo de! espacio de direccionamiento del proceso residents en memoria, en kilobytes. Némero de kilobytes del espacio de direccionamiento del proceso, compartidos con otros procesos, Niimero de kilobytes del segmento de datos del proceso, no compartides con otros procesos. Niimera de kilobytes del segmento de pila del proceso. Numero de fallos de pagina provocados por el proceso que se han resvelto sin lanzar una entrada/salida. Nomero de fallos de pagina provocados por el proceso que se han resuelto lanzando una entrada/salida. Néimero de veces que el proceso ha sido descartado de la memoria para ubicarlo en memoria secundaria Niimero de veces que el sistema de archivos ha efectuado una lectura de dates para el proceso Numero de veces que cl sistema de archivos ha efectuado una escritura de datos para el proceso. Numero de mensajes enviados por el proceso. Numero de mensajes recibidos por el proceso, Numero de sefiales recibidas por el proceso. Nomero de veces que el proceso ha abandonado voluntariamente el procesador (generalmente para esperar Ja Ilegada de un evento, como el fin de una entrada/salida). Nuimero de veces que cl proceso ha abandonado ¢l procesador porque habfa agotado.su porcién de} tiempo o porque un proceso mds prioritario entré | en el estado a punto. } Procesos 53 La estructura timeval, utilizada para definir los campos ru_utime y ru_stime, es la siguiente: La funci6n wait3 corresponde a la ilamada al sistema wait4, a la que se pasa el valor -1 para et parémetro pid, En caso de fallo de estas primitivas, la variable errno puede tomar los valores siguientes: El proceso especificado por pid no existe. statusp 0 rusage contiene una direccién invélida, La llamada al sistema ha sido interrumpida por la recepci6n de una sefial. EI proceso que llama no es privilegiado y su identificadot de usuario efectivo no ¢s igual al del proceso especificado por pid. 2.4 Lectura de los atributos del proceso actual Un proceso cuenta con varias Ilamadas al sistema para obtener los atributos que le caracterizan: #include pidt getpid (void); pidt getppid (void); widt getuid (void); uidit geteuid (void); gidt geteid (void); gidt getegid (void); int getgroups (int size, gid_t list{]}; getpid devuelve el identificador tinico del proceso actual, getppid devuelve el identifi- cador ‘nico del padre del proceso actual. 54 Programacién Linux 2.0 getuid devuelve el identificador del usuario real del proceso, geteuid devuelve el iden- tificador de usuario efectivo del proceso actual. getgid devuelve el identificador de grupo real del proceso, getegid devuelve e} identi- ficador de grupo efectivo del proceso actual. Para terminar, getgroups permite obtener la lista de grupos asociados al proceso actual. Los identificadores de estos grupos se devuelven en el parametro list, y el parfime- tro size especifica el tamafio de la tabla list. getgroups devuelve e! mimero total de grupos asociados al proceso actual. 2.5 Modificacién de atributos Un proceso puede, en ciertas circunstancias, modificar sus atributos. Linux proporcio- na varias llamadas al sistema para ello: Hincluée int setuid (uid_t wid); int setreuid (uid.t ruid, wide euid); int seteuid (uid_t euid); int setgid (gid_t gid); int setregid (gid_t rgid, gid t egid); int setegid (gid_t egid); ddefine _USE_BSD include int setgroups (size_t size, const gid t *list); La llamada setuid permite que un proceso modifique su identificador de usuario efec- tivo. El proceso debe ser privilegiado, es decir, debe poser los derechos del super- usuario, o el nuevo identificador debe ser igual al anterior o al identificador del usua- rio guardado. En el caso que el proceso sea privilegiade, el identificador de usuario real y el identificador de usuario guardado también se modifican, lo que significa que un proceso que posea privilegios del superusuario que modifica su identificador de usua- tio por setuid no puede restaurar ya sus privilegios. Los identificadores de usuario real y efectivo del proceso actual pueden modificarse por setreuid. Los parémetros ruid y euid representan estos identificadores. Si se uti- liza el valor 1, el identificador correspondiente no se modifica. Un proceso no privi- Procesos 55 legiado puede invertir estos dos identificadores. La llamada seteuid corresponde a una Mamada de setreuid donde el parmetro ruid tiene el valor -1. La llamada setgid permite a un proceso modificar su identificador de grupo efectivo. El proceso debe ser privilegiado o el nuevo identificador debe ser igual al anterior o al identificador de grupo guardado, En el caso en que el proceso sea privilegiado, e! iden- tificador de grupo real y el identificador de grupo guardado también se modifican. Los identificadores de grupo real y efectivo del proceso actual pueden modificarse por setregid, Los par4metros rgid y egid representan estos identificadores. Si se utiliza el valor —1, el identificador correspondiente no se modifica. Un proceso no privilegia- do puede invertir estos dos identificadores. La lamada setegid corresponde a una Ila- mada de setregid donde el parémetro rgid tiene el valor 1. La Ramada al sistema setgroups permite modificar los identificadores de grupo asociados al proceso actual, El parametro list especifica los grupos a posicionar, con el tamafio de la tabla indicado por el parametro size. S6lo un proceso privilegiado puede modificar los grupos que le estén asociados. Ademés de estas Ilamadas al sistema, Linux ofrece también dos primitivas especiali- zadas respecto a los controles de acceso a los archivos: int setfeuid (uid.t feuid); int setfsgid (gidt fsgid); La primitiva segfsuid modifica el identificador de usuario del cual se sirve el ndcleo en los controles de acceso a los archivos. La primitiva set/suid modifica el identificador de grupo del que se sirve el niicleo en los controles de acceso a los archivos. Estas dos llamadas a! sistema normalmente no son utilizadas por un proceso «clésico». De modo predeterminado, el nticleo utiliza los identificadores de usuario efectivo y de grupo efectivo para Jos controles de acceso a los archivos, lo que corresponde a su seméntica clisica. Estas dos primitivas estén sin embargo disponibles para permitir a los servidores acceder a los archivos utilizando los derechos de un usuario y de un grupo particulares, cuando tratan una petici6n por cuenta de dicho usuario. El servidor NFS, por ejemplo, utiliza estas dos primitivas para modificar sus derechos a cada peti- cién de acceso a los archivos. ‘Todas estas Hamadas al sistema devuelven el valor 0 en caso de éxito, o el valor ~1 en caso de fallo. La variable exrno puede tomar el valor EPERM que indica que el pro- ceso no posee los privilegios necesarios para modificar sus identificadores. 56 Programacion Linux 2.0 2.6 Informacién de contabilidad La llamada al sistema getrusage permite que un proceso conozca los recursos que ha consumido, Su sintaxis es 1a siguiente: Binclude #include finclude ing getrugage (int who, struct rusage *rusage); El pardmetro who especifica a qué proceso debe aplicarse la operacién: puede tomar el valor RUSAGE_SELF para obtener los recursos consumidos por el proceso actual, 0 RUSAGE_CHTLDREN para obtener los consumidos por los procesos hijos, El resul- tado se devuelve en una variable apuntada por el pardmetro rusage (véase la secci6n 3.3 para la definicién de la estructura rusage). En caso de éxito, se devuelve el valor 0, y en caso de fallo getrusage devuelve el valor —1 y la variable errno puede tomar el valor EFAULT, que indica que el parfmetro rusage contiene una direccién invAli- da, ‘Linux proporciona también la primitiva times que permite a un proceso obtener el tiem- po de procesador que ha consumido. Su sintaxis es la siguiente: #include clock_t times (struct tms *buf); El par4metro buf especifica la direcci6n de una variable en la que se devolverd el resultado. La estructura tms, definida en el archivo de cabecera , contiene los campos siguientes: 7p campo descripcion tms_utime | Tiempo de procesador consumido por el proceso en modo usuario, expresado en segundos. tms_stime | Tiempo de procesador consumido por el proceso en modo niicleo, expresado en segundos. tms_cutime | Tiempo de procesador consumido por los procesos hijos en modo usuario, expresado en segundos. tms_estime | Tiempo de procesador consumido por los procesos hijos en modo nécleo, expresado en segundos. dimes devuelve el mimero de ciclos de reloj transcurridos desde el arranque del siste- ma. Si el pardmetro buf contiene una direccién invalida, devuelve el valor -1 y ta variable errno toma el valor EFAULT. Procesos 57 2.7 Limites Un proceso puede imponer Ifmites sobre los recursos que puede consumir. Generalmente, estos {mites se posicionan en la conexién al sistema, y son heredados por los procesos creados, pero un proceso puede modificarlos mediante las Namadas al sistema: finclude finclude #include int setrlimnit (int resource, const struct rlimit *rlim); int getrlimit (int resource, struct rlimit *rlim); La primitiva serrlimit permite posicionar un limite. El parémetro resource indica el recurso a limitar, y el Ifmite se especifica por el parfmetro rim. En caso de éxito, se devuelve el valor 0, sino setrlimit devuelve el valor 1. La estructura rlimit, definida en el archivo , contiene los campos siguientes: descripcion xlim_cur Limite «suave» xlim_max Limite absoluto Un proceso no privilegiado puede aumentar su Ifmite «flexible», que no puede exceder el limite absoluto, o disminuir éste. Sélo un proceso privilegiado puede aumentar este limite. La llamada al sistema getrlimit permite a un proceso conocer el limite asociado a un recurso, En caso de €xito, se devuelve el valor 0, si no setrlimit devuelve el valor —1. Para estas dos llamadas al sistema, se definen constantes en el archivo de cabecera para representar los diferentes recursos: constanie significado RLIMIT_CPU ‘Tiempo de procesador expresado en milisegundos RLIMIT_FSIZE Tamafio maximo de archivo, expresado en bytes RLIMIT_DATA Tamafio maximo del segmento de datos, expresado en bytes RLIMIT_STACK Tamafio m4ximo del segmento de pila, expresado en bytes RLIME'T_CORE Tamafio maximo del archivo core a crear en caso de error fatal de! programa, expresado en bytes RLIMIT_RSS ‘Tamafio méximo de los datos residentes en memoria central, expresado en bytes 58 Programaci6n Linux 2.0 Niimero méximo de procesos por usuario Nomero maximo de archivos abiertos ‘Tamaiio méximo de datos bloqueados en memoria central, expresado en bytes Tamafio maximo del espacio de direccionamiento, expresado en bytes En caso de fallo de estas primitivas, la variable errno puede tomar los valores siguientes: significado vlimcontiene una direccién invélida resource contiene un valor invalido El proceso que lama no posee los privilegios que le permitan aumentar su lfmite absotuto 2.8 Grupos de procesos Linux proporciona varias liamadas al sistema que permiten gestionar los grupos de pro- cesos: #include int setpgid (pid.t pid. pid_t pgid); pid.t getpgid (pide pid); int setpgrp (void); pid_t getpgrp (void); La primitiva setpgid modifica el grupo asociade al proceso especificado pot el parf- metro pid. El parametro pgid especifica el ndmero del grupo. Si pid es nulo, la modificacién se aplica al proceso actual. Si pgi des nulo, el mimero del proceso actual se utiliza como numero de grupo. La llamada at sistema getpgid devuelve el niimero del grupo al que pertenece el pro- ceso especificado por el parametro pid. Si pid es nulo, se devuelve el mimero del grupo del proceso actual. La llamada al sistema geipgrp devuelve el mimero del grupo del proceso actual. La funcién setpgrp modifica el ntimero del grupo del proceso actual y corresponde a la lamada setpgid (0, 0). Procesos 59 En caso de fallo de estas primitivas, la variable errno puede tomar los valores siguientes: pgid contiene un valor negativo EL proceso no est4 autorizado a modificar el grupo al que pertenece el proceso especificado por pid El proceso especificado por pid no existe 2.9 Sesiones Dos Ilamadas al sistema permiten manipular las sesiones de procesos: pidt setsid (void); pidt getsid (pict pid); La Hamada al sistema setsid crea una nueva sesién. El proceso actual no debe ser un leader de grupo de procesos. Como consecuencia de esta !lamada, €] proceso actual es ala vez el leader de una nueva sesi6n y el leader de un nuevo grupo de procesos, y ademds no tiene asociado ningtin terminal. El nimero del proceso actual se utiliza como identificador de la nueva sesi6n y del nuevo grupo de procesos. Este identifica dor es devuelto por setsid. En caso de fallo, se devuelve ¢] valor -1, y la variable errno toma el valor EPERM, que indica que el proceso actual es ya un leader de grupo de procesos. La asociaci6n de un terminal de control a una sesién se efectia automaticamente cuan- do el proceso leader de la sesién abre un dispositivo terminal o pseudoterminal ain no asociado. La primitiva getsid devaelve el mimero de sesiOn asociada al proceso especificado por el parémetro pid, Si pid es nulo, se devuelve el niimero de la sesién del proceso actual. En caso de fallo, se devuelve el valor -1, y 1a variable errno toma el valor ESRCH, que indica que el proceso especificado por el parémetro pid no existe. 2,10 Ejecucién de programa Un nuevo proceso, creado por una llamada a la primitiva fork, es una copia conforme de su proceso padre, y por tanto ejecuta el mismo programa. Una llamada al sistema permite que un proceso ejecute un nuevo programa: 60 Programacién Linux 2.0 Hinclude int exeve (const char *pathname, const char *argv [],const char *envp[}); La primitiva execve provoca la ¢jécucién de un nuevo programa. pathname especifi- ca el nombre del archivo a ejecutar, que debe ser un programa binario o un archivo de mandatos que empiece por la linea #!nombre_de_intérprete. El pardmetro argv indica los argumentos del programa a ejecutar: cada elemento de la matriz argv debe apuntar a una cadena de caracteres que representa un argumento. E! primer ele- mento de la matriz debe contener el nombre del programa, los elementos siguientes con- tienen los argumentos, y ¢l ditimo elemento debe contener el valor NULL. El pardmetro envp especifica las variables de entomo del programa. Cada uno de los elementos debe contener la direeci6n de una cadena de caracteres de la forma nombre_de_varia- ble=valor, y el tiltimo elemento de la matriz debe contener el valor NULL. La llamada al sistema execve provoca el recubrimiento de los segmentos de c6digo, de datos y de pila por los del programa especificado. En caso de éxito no hay pues retor- ho, porque ¢! proceso que llama ejecuta ahora un nuevo programa. En caso de fallo, execve devuelve el valor —1, y la variable errno puede tomar los valores siguientes: La lista de argumentos 0 variables de entorno es de tamafio excesivo El proceso no tiene acceso en ejecucién al archivo especificado por pathname pathname contiene una direccién invalida pathname especifica un nombre de archivo demasiado largo pathname se refiere a un nombre de archivo inexisteme ‘Se ha encontrado un ciclo de enlaces simbélicos El archivo especificado pot pathname no es un programa ejecutable La memoria disponible es insuficiente para ejecutar el programa Uno de los componentes de pathname, utilizado como nombre de directorio, no es un directorio Et sistema de archivos que contiene el archivo especificado por pathname se ha montado con opciones que impiden la ejecucién de programas Linux proporciona diversas funciones de biblioteca que ofrecen variantes de execve: Winclude int execl (const char *pathname, const char ‘arg, : int execle (const char ‘pathname, const char ‘arg, ..., char ‘const envp[]); int execlp (const char ‘pathname, const char ‘arg, ...); Procesos 61 int execv (const char ‘pathnama, char ‘const argv[1)? int execvp (const char *pathname, char *const argv{]}; Para todas las funciones, el parémetro pathname especifica ¢l programa a ejecutar. El pardmetro argv de execv y execvp indica los parémetros a transmitir al programa, de la misma manera que para execve. El pardmetro envp indica las variables de entor- no a transmitir al programa. Finalmente, en el caso de las funciones execl, execle y execip, los argumentos del programa se citan por partimetros explicitos: arg debe contener la direccién de una cadena de caracteres que representa el nombre del pro- grama y debe ir seguido de una lista de punteros con ta direccién de los argumentos, y un tiltimo pardmetro de la lista que debe valer NULL. Las dos funciones execip y execvp consideran pathname como un nombre simple de mandato, contrariamente a las otras funciones y a execve: el camino de busqueda aso- ciado al proceso actual (variable de entorno PATH) se utiliza para buscar ¢] programa ejecutable especificado. 3 Conceptos avanzados 3.1 Coordinador El coordinador es la funcidn del micleo que decide qué proceso debe ser ejecutado por el procesador: ef coordinador explora la lista de procesos a punto y utiliza varios crite- rios para elegir ef proceso a ejecutar. El coordinador de Linux proporciona tres politicas de coordinacién diferentes: una para los procesos «normales», y dos para los procesos de «tiempo real». Acada proceso se le asocia un tipo de proceso, una prioridad fija y una prioridad varia- ble. El tipo de proceso puede ser: * SCHED_FIFO para un proceso de «tiempo real» no preemtivo; * SCHED_RR para un proceso de «tiempo real» preemtivo; * SCHED_OTHER para un proceso clasico. 62 Programacion Linux 2.0 La polftica de coordinacién depende del tipo de procesos contenidos en la lista de pro- cesos a punto de ejecutar: * Cuando un proceso de tipo SCHED_FIFO esti a punto, se ejecuta inmediatamente, El coordinador prioriza la eleccién del proceso de tipo SCHED_ FIFO que posea la ms alta prioridad, y lo ejecuta. Este proceso no es normalmente preemtible, es decir, que posee el procesador, y el sistema sdlo interrumpiré su ejecucién en tres casos: 1. otro proceso de tipo SCHED_FIFO que posea una prioridad mds elevada pasa al estado a punto: se ejecuta inmediatamente; 2, el proceso se suspende en espera de un evento, como por ejemplo el fin de una entrada/salida; 3. el proceso abandona voluntariamente el procesador por una llamada a la primi- tiva sched_yield. El proceso pasa al estado a punto y se ejecutan otros procesos. + Cuando un proceso de tipo SCHED_RR est4 a punto, se ejecuta inmediatamente. Su comportamiento es similar al de un proceso de tipo SCHED_FIFO, con una excep- cién: cuando el proceso se ejecuta, se le atribuye un lapso de tiempo. Cuando este lapso expira, puede elegirse y ejecutarse un proceso de tipo SCHED_FIFO 0 SCHED_RR de prioridad superior o igual a la del proceso actual. * Los procesos de tipo SCHED_OTHER tnicamente pueden ejecutarse cuando no existe ningtin proceso de «tiempo real» en estado a punto. El proceso a ejecutar se elige tras examinar las prioridades dindmicas. La prioridad dinémica de un proceso se basa por una parte en el nivel especificado por el usuario por las Ilamadas al sis- tema nice y seipriority, y por otra parte en una variacién calculada por el sistema. Todo proceso que se ejecute durante varios ciclos de reloj disminuye en prioridad y puede asf llegar a ser menos prioritario que los procesos que no se ejecutan, cuya prioridad no se ha modificado, Puede encontrarse una definicién mas completa de estas diferentes politicas de coordi- nacién en (Gallmeister 1995). 3.2 Personalidades A fin de permitir la ejecucién de programas provenientes de otros sistemas operativos, Linux soporta la nocién de personalidad. A cada proceso se le asocia un Ambito de eje- cucién. Este dmbito especifica la forma como el proceso efectia Hamadas al sistema, y la forma como se tratan las sefiales. Procesos 63 ‘Una personalidad define c6mo se tratan: + las Iamadas al sistema: Linux utiliza una interrupcién légica para pasar al modo nécleo, mientras que otros sistemas Unix utilizan un salto intersegmento; © Jos mimeros de sefiales especificados por los procesos: cuando un proceso especifi- ca un niimero de sefial, por ejemplo llamando a las primitivas sigaction o kill, el mimero de la sefial se convierte utilizando uma tabla de correspondencias; © Jos ntimeros de sefiales enviadas a los procesos: cuando una seflal debe enviarse a un proceso, su mimero se convierte utilizando una tabla de correspondencias. De modo predeterminado, los procesos utilizan el émbito de ejecucién nativo de Linux, que especifica que las Hamadas al sistema se efectian por interrupcién légica y los mimeros de sefiales no se convierten. Un sistema de emulacién puede utilizar sin embargo Ambitos de ejecucién diferentes para ejecutar programas binarios provenien- tes de otros sistemas operativos. 3.3 Clonado Bajo Linux, de la misma manera que bajo Unix, los procesos poseen un espacio de direccionamiento diferente, y deben utilizar medios de comunicacién especializados como las tuberfas (véase capftulo 10) 0 tos IPC System V (véase capftulo 11), para intercambiar datos. Pero Linux ofrece una extensién que permite crear «clones» de procesos. Un proceso clon se crea, por la primitiva clone, por duplicacién de su proceso padre. Pero, contra- riamente a un proceso clasico, puede compartir una parte de su contexto con su padre. Segiin las opciones especificadas en la Hamada a clone, se puede compartir una o més partes de su contexto: + Blespacio de direccionamiento: los dos procesos comparten los mismos segmentos de cédigo y de datos. Toda modificaci6n efecuada por uno es visible por parte del otro. * Las informaciones de control del sistema de archivos: los dos procesos comparten los mismos directorios rafz y actual. Si uno de estos directorios es modificade por uno de los procesos (por las primitivas chdir 0 chroot), la modificaci6n es efectiva para el otro. + Los descriptores de archivos abiertos: los dos procesos comparten los mismos des- criptores de archivos abiertos. Si uno de ellos cierra un archivo, el otro ya no puede acceder a él 64 Programacién Linux 2.0 + Los gestores de sefiales: los dos procesos comparten la tabla de funciones Ilamadas en la recepcién de una sefial. Toda modificacién por parte de uno de los procesos, mediante la primitiva sigaction por ejemplo, provoca el cambio de Ja rutina de tra- tamiento de la sefial por el otro proceso. * El identificador de procesos: los dos procesos pueden compartir el mismo nimero. En el caso extremo en que los dos procesos compartan el maximo de cosas, se diferen- cian Unicamente por ¢! valor de los registros del procesador y por su segmento de pila. Esta posibilidad de clonado permite, entre otras cosas, implementar servidores en los que se ejecuten varias actividades (threads), Estas actividades pueden compartir sim- plemente datos, sin emplear mecanismos de comunicacién interprocesos. 4 Llamadas al sistema complementarias 4.1 Cambio de personalidad Linux permite a un proceso que modifique su personalidad, a fin de poder ejecutar un programa proveniente de otro sistema operativo. Esta posibilidad es utilizada por los emuladores, por ejemplo el emulador iBCS2 que permite ejecutar programas binarios prvistos para SCO Unix o System V Release 4. La llamada al sistema personality permite que un proceso modifique su Ambito de eje~ cucién, a fin de que Linux emule el comportamiento de otro sistema operativo. No se incluye en Ia biblioteca C esténdar y debe declararse pues explfcitamente: include wsysealll (int personality, int pers); Esta declaracin corresponde al prototipo siguiente: int personality (int pers); El parémetro pers especifica el sistema operativo a emular. En caso de éxito, la anti- gua personalidad se devuelve en personality. En caso de error, se devuelve el valor -1, y la variable errno toma el valor EINVAL, que indica que el pardmetro pers con- tiene un valor invatido. Procesos 65 El archivo de cabecera define varias constantes que especifican los sistemas operatives a emular: System V Release 4 ‘System V Release 3 SCO Unix versién 3.2 UNIX System V/386 Release 3.2.1 Interactive Unix BSD Unix Xenix 4.2 Modificacién de la coordinacién Varias Hamadas al sistema permiten modificar la polftica y los pardmetros de coordi- nacién asociados a un proceso: finclude int sched_setscheduler (pid.t pid, int policy, const struct sched param *param); int sched_gecscheduler (pid_t pid); int sched_setparam (pid_t pid, const struct sched_param *param); int sched_getparam (pid_t pid, struct sched_param *param); La Namada al sistema sched_setscheduler permite modificar la politica y los parame- tros de coordinacién asociados a un proceso. El parimetro pid especifica e! proceso sobre el que conviene actuar. Puede ser nulo para indicar el proceso actual. El pard- metro policy especifica la polftica de coordinacién a aplicar al proceso, y debe tener uno de los valores SCHED_FIFO, SCHED_RR, 0 SCHED_OTHER. El pardmetro param especifica los parémetros de coordinaci6n a utilizar. La primitiva sched_gets- cheduler permite obtener la polftica de coordinacién asociada al proceso caracterizado por pid, o al proceso actual si pid es nulo. La Iamgda al sistema sched_setparam permite modificar los parAmetros de coordina- ci6n asociados a un proceso. El pardmetro pid especifica ¢l proceso sobre e] cual con- viene actuar. Puede ser nulo para indicar el proceso actual. El parametro param indi- ca los parémetros de coordinacién a utilizar. La primitiva sched_getparam permite obtener los par4metros de coordinacién asociados al proceso caracterizado por pid, 0 66 Programacion Linux 2.0: al proceso actual si pid es nulo. Estos pardmetros se envfan en la variable cuya direc- cién se pasa en ¢l parémetro param, Linux 2.0 s6to permite modificar la prioridad esttica asociada a un proceso. La estruc- tra sched_paran, definida en el archivo de cabecera , contiene un solo campo, sched_priority: 3 [campo id il i tno En caso de fallo, esas primitivas devuelven el valor -1, y la variable errno puede tomar los valores siguientes: param contiene una direccién invélida policy o la variable apuntada por param contiene un valor invélido El proceso no posee los privilegios necesarios para modificar sus pardmetros de ordenacion El proceso especificado por pig no existe Las primitivas sched_get_priority_min y sched_get_priority_max permiten obtener las prioridades est4ticas minima y méxima asociadas a una politica de coordinacién. Su sintaxis es la siguiente: Winclude int sched_get_priority_min (int policy); int sched_get_priority_max (int policy); La primitiva sched_rr_get_interval permite obtener el lapso de tiempo atribuido a un proceso de tipo SCHED_RR. Su sintaxis es la siguiente: #inelude int sched_rrget_interval (pict pid, struct timespec *interval); E! pardmetro pid especifica e! proceso. Puede ser nulo para indicar e! proceso actual. El proceso en cuestién debe ser de tipo SCHED_RR. El parémetro interval debe contener la direccién de una variable en la que se colocard el lapso de tiempo asocia- do al proceso especificado. En caso de éxito, se devuelve el valor 0, si no sched_rr_get_intervat devuelve el valor -1 y la variable errno puede tomar los valo- res siguientes: Procesos 67 significado interval contiene una direcci6n invélida La llamada al sistema no est4 implementada (ocurre en Linux 2.0) El proceso especificado por el parametro pid no existe La estructura timespec comporta los campos siguientes: _campo_ descripcion tv_sec Nomero de segundos tv_nsec Neimero de nanosegundos La primitiva sched_yield permite al proceso actual liberar al procesador. Su sintaxis es la siguiente: finclude Ant sched_yield (void); Al ejecutar esta primitiva, el proceso actual se coloca al final de la lista de procesos a punto, y se ejecuta el coordinader. Si existen otros procesos a punto en el sistema, cam- bia el proceso actual. 4.3 Prioridades de los procesos Linux proporciona varias Ilamadas al sistema que permiten manipular las prioridades de los procesos: #include int nice (int ine); tinclude int setpriority (int which, int who, int prio); int getpriority (int which, int who); La primitiva nice permite modificar la prioridad dindmica del proceso actual. El pard- metro inc se afiade a la prioridad actual. Sélo un proceso privilegiado puede especi- ficar un valor negativo a fin de aumentar su prioridad. En caso de éxito, se devuelve el valor 0, si no nice devuelve ef valor -1 y la variable errno toma el] valor EPERM, que indica que el proceso que Hama no posee los privilegios necesarios para aumentar su prioridad. 68 Programacién Linux 2.0 La Iamada al sistema setpriority modifica la prioridad de un proceso, de un grupo de procesos o de todos los procesos de un usuario. El parémetro which puede tomar como valor PRIO_PROCESS, PRIO_PGRP o PRIO_USER. E] parémetro who espe- cifica un ntimero de procesos, de grupo de procesos o de usuario segtin el valor del which. El parémetro prio indica la prioridad a colocar. S6lo un proceso privilegia- do puede dar a uno o mas procesos mayor prioridad. La primitiva setprioriry devuelve el valor 0 en caso de éxito, o el valor -1 en caso de error. La Ilamada al sistema getpriority permite obtener la prioridad de un proceso, de un grupo de procesos o de todos los procesos de un usuario. Los pardmetros which y who tienen el mismo significado que en setpriority. El valor devuelto es la prioridad mas importante atribuida a los procesos especificados. En Ja medida en que getpriority puede devolver el valor —1 sin que ello indique un error, es necesario volver a poner a 0 la variable errno, y comprobar su valor tras el retomo de la llamada al sistema. En caso de fallo de estas dos primitivas, la variable exrno puede tomar los valores siguientes: E] proceso que llama no posee los privilegios necesarios para aumentar la prioridad de otros procesos which contiene un valor invélido Bl proceso actual no posee los mistnos identificadores de usuarios reales y efectivos que el proceso 0 procesos especificados por. who Ninggin proceso corresponde a la combinacién especificada por los parmetros which y who 4.4 Control de la ejecucién de un proceso La Hamada al sistema pérace permite que un proceso controle la ejecucién de otro pro- ceso. Su sintaxis es la siguiente: #include int ptzace (long request, pid.t pid, long addr, long data); El parémetro request especifica la operacién a efectuar sobre el proceso cuyo nime- ro se pasa en el pardémetro pid. El significado de los parémetros addr y data depen- de dei valor de request. Las operaciones disponibles se definen en el archivo de cabecera . Las constantes son las siguientes: constante sig PTRACE_TRACEME proceso actual indica que ser4 controlado por otro proceso: PTRACE_ATTACK EI proceso actual indica que controlaré ¢! proceso identificado: por pid. La sefial SIGSTOP se envfa al proceso bajo control para suspender su ejecucién PTRACE_PEERDATA | El contenido de la palabra situada en la direcci6n addy, en el segmento de datos del espacio de direccionamiento controlado, se devuelve en la variable direccionada por la variable data El contenido de la palabra situada en la direcci6n addr, en el segmento de cédigo del espacio de direccionamiento del proceso controlado, se devuelve en la variable direccionada por la variable data El contenido de a palabra situada en la direcci6n addr en la estructura user del proceso controlado (véase 1a seccién 5.2) se devuelve en la variable direccionada por data El valor contenido en data se escribe en la palabra situada en la direccin addr, en el segmento de datos del espacio de direc- cionamiento del proceso controlado E] valor contenido en data se escribe en la palabra situada en ta direccién addr, en el segmento de cédigo del espacio de direccionamiento del proceso controlado El valor contenido en data se escribe en la palabra situada en la direccién addr en la estructura user del proceso controlado La ejecucién del proceso controlado se prosigue hasta fa ejecuci6n de la préxima Hamada al sistema. E! mandato strace utiliza esta opcién para mostrar las llamadas al sistema ejecutadas por un proceso La ejecucién del proceso controlado se prosigue La ejecucién del proceso controlado se finaliza La ejecucién del proceso controlado se prosigue para una sola instrucci6n maquina El proceso ya no esté bajo control En caso de error, ptrace devuelve el valor -1 y la variable errno puede tomar los valores siguientes: significado addr contiene una direccién invalida xequest 0 data contiene un valor invalido E! proceso que Ilama no posee los privilegios necesarios para controlar el proceso especificado por pid, o este tiltimo esté ya bajo control E\ proceso especificado por pid no existe Los depuradores, como gdb, utilizan ptrace para ejecutar un programa instruccién por instrucci6n, y para permitir al usuario visualizar las variables del programa. 70 Programacién Linux 2.0 4.5 Clonado La Hamada al sistema clone crea un «clon» del proceso actual. Esta primitiva no se incluye en la biblioteca estandar y es necesario declararla explicitamente. Antes de lamar a clone, debe asignarse un segmento de pita (ilamando a 1a funcién malloc, por ejemplo), y los pardmetros de la funcién a ejecutar deben apilarse en esta zona de memoria. Seguidamente, los registros del procesador deben inicializarse de la forma siguiente (en un procesador x86): * eax debe contener el cédigo de la llamada clone, representado por la constante __NR_clone; * ebx debe contener una combinacién de constantes presentadas més adelante; * ecx debe contener el puntero de pila para el proceso hijo. El programa clone.S siguiente, derivado de un archivo fuente de la biblioteca C del pro- yecto GNU, implementa la llamada de la primitiva clone en lenguaje ensamblador x86. El prototipo de la funcién clone proporcionado es el siguiente: int clone (int (*fn) 0, voice *child_stack, int flags, int nargs, ...); El parémetro fn es un puntero a la funci6n a ejecutar por el proceso hijo. E! pardime- tto child_stack es un puntero a Ia zona de memoria asignada para la pila del pro- ceso hijo. El parmetro #1ags define las modalidades de «clonado». Finalmente, el parimetro nargs define el mimero de argumentos a pasar a la funcién apuntada por fn y va seguido por estos argumentos. Varias constantes, definidas en el archivo de cabecera <1inux/sched.h>, definen las modalidades del «clonado»: constante CLONE_VH EI proceso hijo comparte el espacio de direccionamiento del proceso padre El proceso hijo comparte los directorios rafz y actual del proceso padre El proceso hijo comparte los descriptores de archivos abiertos del proceso padre Et proceso hijo comparte los gestores de sefiales del proceso padre El proceso hijo posee el mismo ndmero que el proceso padre Procesos “1 Ademés, puede especificarse también la sefial a enviar al proceso padre en Ja termina- cién del proceso hijo. ¥define __ASSEMBLY__ include #include #inciude text ENTRY (clone) /* Verificacién de los argumentos */ movl $-EINVAL, teax movl 4 (tesp),tecx /*E1 puntero de funcién debe ser no nulo*/ testl tecx, tecx az syscall_error movl 8 (Resp), fecx /*La direccién de pila debe ser no nulat/ testl tecx, Secx $e ayscall_error movl 16 (esp), tedx /*E] mimero de argumentos debe ser positivo*/ testl tedx, Bede je syscall_erroz 7* asignacién de espacio en la pila y copia de argumentos */ movl — tedx, eax negl teax lea -4 (Beex, Beax, 4), tecx iz 2£ L movl 16 {tesp, Sedx, 4}, Geax movl eax, 0 (Reox, tedx, 4) dec tedx jnz ob /* Guardado del puntero a la funcién Se retira de la pila tras llamar al clon */ movi —-4(tesp) , teax movil beax, 0(¢ecx) ¢* Llamada a la primitiva clone */ pushl tebx movl —-16 (esp) , tebx. movl —_$__.NR_clone, teax int $0x80 pop] — tebx #* Comprobacién del cédige de retorno */ test —teax, Beax jl syseall_error jz thread_start 72. Programacion Linux 2.0 ret syscall_error: /* Brror, se devuelve -1 */ movl —-§-1, teax ret thread_start: /* Cédiga del procezo clon */ subl | tebp, tebp call *tebx /* Llamada a la funcién */ movl $_NRexit,8eax /* Finalizacién del proceso */ int $0x80 El programa EjemploClone.c es un ejemplo simple (y poco itil) del uso de la funcién clone. Crea un proceso hijo que comparte el espacio de direccionamiento, los descrip- tores de archivos y la gestién de las sefiales con su proceso padre. El proceso hijo modi- fica una variable y cierra un archivo. El proceso padre muestra el contenido de la varia~ ble y comprucha si el archivo sigue abierto. #include #include include #include #include #inelude <1inux/sched.h> define STACKSIZE 16384 i * Esta funcién es similar a thr_create() de la biblioteca * pthreads, pero es menos evolucicnada ” int start_clone (void (*fn) (void *), void *data) { long retval; void *newstack: ” * Asignacidén de la pila de la nueva tarea + newstack = {void **) malloc (STACKSIZE); df (Inewstack) return -1; ” Procesos C * Inicializacién de la pila ay newstack = (void *) (STACKSIZE + (char *) newstack); * * Creacién del clon ” retval = clone (fn, newstack, CLONE_VM | CLONE_FS | CLONE_FILES | CLONB_SIGHAND | SIGCHLD, 1, data); 3€ (retval < 0) ( ermo = -retval; retval = -1; } return retval; int show_same_vm; void cloned_process_starts_here (void *data) C printf ("child:\t got argument td as fd\n*, (int) data); show_same_vi = 5; printf ("child:\t vm = €d\n", show_same_vm); close ({int) data); , int main (void) int fd, pid: fé = open (*/dev/null*, 0_RDONLY); if (fd < 0) ¢ perror (*/dev/null*); exit (Lh; } printf (tmother:\t fd = $d\n", fa); show_same_vm = 10; printf (*mother:\t vm = %d\n", show_same_vm); pid = start_clone (cloned process_starts_here, (void *} fd); if (pid < 0) { perror (‘start_clone*); exit (1); } sleep (1); printf (tmother:\t vm = &d\n*, show same_vm); if (write (fd, "ct, 1) < 0) printf ("mother:\t child closed our file descriptor\n") ; exit (0); 74 Programacién Linux 2.0 La ejecucién del programa provoca la visualizaci6n siguiente: fmother: fa = 3 mother: vm = 10 child: got argument 3 as fd child: vm = 5 mother: vm = 5 ther: child closed our file descriptor Hay que observar que la primitiva clone es una Hamada al sistema de muy bajo nivel, y es probablemente bastante compleja de usar directamente. Xavier Leroy est4 desa- rrollando actualmente una biblioteca de threads utilizando clone y est disponible en elURL http://pauillac.inria. fr/~xleroy/linuxthreads/. 5 Presentacién general de la implementacién 5.1 La tabla de procesos 5.1.1 Descriptor de proceso Cada proceso se referencia por un descriptor, Este descriptor contiene los atributos del Proceso, asf como las informaciones que permiten gestionar el proceso. La estructura task_struct, definida en el archivo , caracteriza un proce- so. Contiene los campos siguientes: [apo pa volatile long Estado del proceso Numero de ciclos de reloj durante los que e! Proceso actual estd autorizado a ejecutarse priority Prioridad del proceso signal Seftales en espera (véase el capftulo 5, seccién 5.1) blocked Sefiales ocultas (véase el capltulo 5, seceién 5.1) Véase més adelante (Cédigo de error originado por las lamadas al sistema Copia de los registros de hardware de depuracion Procesos struct exec_domain * struct linux_bintme * struct task struct * struct task struct * struct task struct * struct taskstruct * unsigned long unsigned leng dat ant unsigned long int:1 inti int int int int int [NGROUPS] struct taskstruct * struct task struct * struct task struct * struct task struct * struct task_struct * struct wait_queue * unsigned short unsigned short unsigned short, unsigned short exec_domain pintme next _task prev_task next_run prev_run saved_kemel_stac! kernel_stack page exit_code exit_signal personality dumpable pid session groups pLopptr popper pieptr PLysptr P_osptr wait_chidexit uid euid suid fowid 75 Ambito de ejecucién del proceso Pumtero a las operuciones relacionadas con el formato del programa ejecutsdo por e! proceso} Puntero al proceso siguiente en la lista Puntero al proceso anterior en la lista Puntero al proceso siguiente en la lista de Procesos a punto Puntero al proceso anterior en Ia lista de Procesos a punto Puntero de pila usado en modo nicleo Direccién de la pégina de memoria que contiene \a pila utilizada en modo nicleo Cédigo de retorno a devolver al proceso padre: los 8 bits de menor peso (bits 0 2 7) contienen ef mimero de fa sefial que ha causado Ia finalizaci6n del proceso, o bien los 8 bits siguientes (bits 8 2 15} contienen el c6digo de retorno dewuelto por el proceso tras lamar a la primitiva _exit \Némero de la sefal a enviar al proceso padre ena finalizacién, Personalidad asociada al proceso Booteano que indica si debe crearse un archivo core en caso de error fatal Booleano que indica si el proceso ha usado execve para ejecutar un programa Niimero del proceso Niimero del grupo que contiene el proceso Nimero de la sesi¢n que contiene el proceso Booleano que indica si el proceso es el lider de su sesién Grupos asociadas al proceso Punterg al descriptor del proceso padre original Puntero al descriptor del proceso padre Puntero af descriptor del proceso hijo creado més recientemente Puntero al proceso «hermano» siguiente, que| ha sido creado por el mismo proceso padre Punteto al proceso «hermano» anterior Variable utilizada para esperar Is finalizacién de un process hijo Tdentificador de usuario real asociado al proceso Identificador de usuario efectivo asociado al proceso Wdentificador de usuario guardado asociado al proceso Identificador de usuario asociado al proceso: para los controles de scceso a los archives 76 unsigned short unsigned short unsigned short unsigned short unsigned short unsigned short unsigned short long long Jong long long unsigned long unsigned long unsigned long unsigned long unsigned long unsigned long int:1 unsigned long struct rlimit (RLIM_NLIMITS) unsigned short char [16] int struct tty_struct ¥ struct semundo * struct sem queug * gia egid agid fagid ‘timeout policy xt_priority wutime atime cutime start_time min_flt maj_flt omin_flt omaj_flt. swappable swap_cnt rlim used_math link_count tty semeleeping Programacion Linux 2.0 Identificador de grupo real asociado al proceso Identificador de grupo efectivo asociado al Proceso Identificador de grupo guardado esociado al proceso Identificador de grupo asociado al proceso para los controles de acceso a los archivos Lapse de espera méximo durante el que el proceso debe estar suspendido Polftica de coordinacién asociada al proceso Prioridad estética asociada al proceso ‘Tiempo de procesador consumido en modo usuario ‘Tiempo de procesador consumide en modo ndicleo ‘Tiempo de procesador consumido por los procesos hijos en mado usuario ‘Tiempo de procesador consumido por los process hijos en modo nuicleo Fecha de creacién del proceso Neimero de excepciones de memoria tratadas por el proceso sin cargar paginas ‘Namero de excepciones de memoria tratadas por| ¢ proceso cargando una pagina desde el disco Nemero de pfiginas del proceso que se han guardado en la zona de swap Niimero de excepciones de memoria tratadas por los procesos hijos sin cargar paginas Nomero de excepciones de memoria tratadas por los procesos hijos cargando una pagina desde el disco Némero de paginas de los procesos hijos ‘guardadas en Ia zona de swap Booleano que indica si el proceso puede guardarse cn memoria secundaria ‘Nimero de paginas de memoria a descartar ‘Limites asociados al proceso Booleano que indica si el proceso ha utilizado el coprocesador matemstico Nombre de] programa ejecutade por el proceso Némero de enlaces simbélicos explorados en a resolucién de un nombre de archivo (véase el capttulo 6) Puntero al descriptor del terminal asociado al proceso (véase e! capfulo 9) Puntero a una lista de semAforos System Va liberar (véase el capitulo 11) Puntero a In cola de espera del seméfora System V en la que el proceso esté suspendido Procesos 77 Puntero al descriptor de la tabla de segmentos local a este proceso. Esta tabla se usa y modifica por el emulador Wine. Valor de los registras del procesador Informaciones de control utilizades en los accesos a los archivos (véase el capttulo 6, secci6a 5.2.5) Puntero a los descriptores de archivos abiertos por el proceso (véase el capitulo 6, seccién 5.2.5) Informaciones de control utilizadas para la ‘estiGn de memoria (véase el capftulo 8, seccién 5.4.1) Puntero a los descriptores de acciones asociadas a las schales (véase el capitulo 5, seccién 5.1) Identificador del procesador sobre el que se gjecuta et proceso Identificador del ditimo procesador sobre el que 8e ha ejecutado el proceso struct desc_struct * struct thread_struct struct fs_struct * struct files_struct * struct mmstruct * struct signal_struct *| Processor last_processor El estado del proceso (campo state) puede expresarse por varias constantes: sig El proceso est a punto 0 en curso de ejecucién El proceso esté suspendide pero puede ser despertade por una scftal E] proceso esté suspendide y no puede ser despertado por una sefial EI proceso ha terminado su ejecucién EI proceso ha sido suspendide por el usuario constante ‘ignificad ‘PP_PTRACED El proceso esté controlado por otro FF_TRACESYS EI proceso est controlado por otro y debe ejecutarse hasta la préxima llamada al sistema El proceso no ha ejecutado Is Itamada al sistema execve para ejecutar oo programa EI proceso ha utilizado los privilegios del superusuario EI proceso ha terminado produciende un archivo core EI proceso ha terminado por Ia legada de una sefial El proceso se est4 creando El proceso esté terminando EI proceso ha utilizado el coprocesador matemético durante su ditimo lapso de tiempo (este estado es utilizado por el ebdigo de gestién de los multiprocesadores) 78 Programacién Linux 2.0 5.1.2 Organizacién de la tabla de procesos Los descriptores de proceso los asigna dinémicamente el nticleo, !lamando a la funcién kmalloc. La matriz task, definida en el archivo fuente kernel/sched.c, contiene punteros a estos descriptores. La matriz current_set contiene punteros a los des- criptores de procesos en curso de ejecucién en cada procesador. Una macroinstruccién, llamada current, corresponde a la direccién del descriptor del proceso ejecutado por el procesador actual. La variable ini t_task contiene e] descriptor del primer proceso creado en el arran- que del sistema. Tras el arranque, este proceso sdlo se ejecuta cuando ninguno mis esté a punto, y su descriptor sirve para recuperar el inicio de la tabla de procesos. Los descriptores de procesos se organizan en forma de una lista doblemente encadena- da, por los campos next_task y prev_task. Los descriptores de tos procesos a punto o en curso de ejecucién se colocan en otra lista doblemente encadenada, median- te los campos next_run y prev_run. P_ysptr R — P_ospr Fic. 4.3 - Relaciones entre descriptores de procesos Los campos p_opptr.p_pptr, p_cptr,p_ysptr y p_osptr se ulilizan para gestionar las filiaciones entre procesos. Cuando un proceso se duplica, Ilamando a la primitiva fork: + los punteros p_opptr y p_pptr del descriptor del proceso hijo contienen la direccién del proceso padre; * el puntero p_osptr del descriptor del proceso hijo toma el valor del puntero p_cptr del descriptor del proceso padre; Procesos 79 * el puntero p_ysptr del descriptor del proceso hijo se inicializa al valor nulo; + elpuntero p_ysptr del proceso «hermano» mis reciente (referenciado por el pun- tero p_cptr del descriptor del proceso padre) contiene la direccién del descriptor del nuevo proceso hijo; * el puntero p_eptr del descriptor del proceso padre contiene la direccién del des- criptor del proceso hijo. La figura 4.3 representa estos punteros en el caso de un proceso P que ha creado suce- sivamente tres procesos hijos F1, F2 y F3. 4.1.3 Manipulacién de la tabla de procesos En el archivo se definen varias macroinstrucciones que permi- ten gestionar las listas de descriptores de procesos: Tmacromstraccian | _signific Esta macroinstrucci6n suprime un descriptor de todas las listas a las que pertenece Esta macroinstrucci6n inserta un descriptor en todas las listas: actualiza ios punteros del descriptor para insertarlo en la lista de sus , contiene los campos siguientes para la arquitectura x86; [apo campo scripel long een ‘Valor del registro ebx long ecx ‘Valor del registro ecx long eax Valor del registro edx Jong esi Valor del registro esi long edi Vator del registro edi long ebp Valor del registro ebp long eax Valor del registro eax a restaurar al volver de Ia lamada al sistema ds unsigned short Valor del registro de segmento as (descriptor del segmento de datos) 80 Programacién Linux 2.0 ‘Valor del registro de segmento es Valor del registro de segmento fs Valor del registro de segmento as ‘Valor del registro eax en la Uamada al sistema (eax contiene él mimero de la primitiva a ejecutar) ‘Valor del registro eip (contador ordinal) Valor del registro de segmento cs (descriptor del segmento de c6digo) Valor de los indicadores de} procesador ‘Valor del registro esp (puntero de pila) Valor del registro de segmente ss (descriptor del segmemo de pila) La estructura user, definida en el archivo de cabecera , es utilizada por el nticleo cuando debe crearse un archivo core: esta estructura se coloca al princi- pio del archivo para que un depurador pueda acceder al contexto del proceso cuando ha terminado. La llamada al sistema ptrace utiliza también esta estructura permitiendo aun proceso leer y modificar su contenido. Los campos contenidos en Ia estructura user son los siguientes: | pe struct pt_regs ‘Valor de los registros del procesador int Booleano que indica si el proceso utiliza el coprocesador matemético struct Vator de los registros del coprocesador matemético user_i387_estruct unsigned long int ‘Tamatio del segmento de cédigo, expresado en péginas de memoria unsigned long int “Tamafio del segmento de datos, expresado en paginas de memoria unsigned long int i ‘Tamaito del segmento de pila, expresado en paginas de memoria unsigned long Direccién virwal del inicio del segmento de cédigo unsigned long Direcci6n virtual del inicio de 1a pila long int i Néimero de la sefial que ha causado el fin del proceso ant No utilizado struct pt_regs * Direccién del valor de los registros en la estructura user (utilizado por gdb) struct user_i387_struct * Direccién del valor de los registros del coprocesador en la estructara user (utilizado por gdb) unsigned long Firma que identifica un archivo core char (32] Nombre del programa ejecutado por el proceso int [8 Valor de los registros de hardware de depuracién Procesos 81 5.3 Sincronizaci6n de procesos 5.3. Principio En un instante dado, un solo proceso puede ejecutarse en modo micleo. Aunque es posi- ble que se apliquen interrupciones de hardware y software a este proceso, Linux no pro- voca la coordinacién si el proceso actual est4 activo en modo niicleo. Un proceso que se ejecuta en modo nucleo puede provocar sin embargo un cambio de proceso actual sus- pendiendo su ejecucién. Esta suspensién voluntaria se debe generalmente a la espera de un evento, tal como el fin de una entrada/salida o la terminacién de un proceso hijo. Linux proporciona dos herramientas que permiten a los procesos sincronizarse en modo niicleo: las colas de espera (wait queues) y los semAforos. Las estructuras corres- pondientes se definen en el archivo de cabecera . 5.3.2 Colas de espera ‘Una cola de espera es una lista encadenada y circular de descriptores. Cada descriptor contiene la direccién de un descriptor de proceso asf como el puntero al elemento siguiente de la cola. La estructura wai t_queue caracteriza los elementos de ja cola de espera: oz struct task_struct * Puntero al descriptor del procese en espera struct wait_queve * Puntero al elemento siguiente de la cola 5.3.3 Sem4foros Los seméforos constituyen un mecanismo general de sincronizacién entre procesos. Un seméforo no es realmente un mecanismo de comunicacién, sino mas bien un meca- nismo de sincronizacién de procesos. En informatica, y més particularmente en ¢] caso de los sistemas operativos, un sem4- foro se utiliza para controlar e] acceso a un recurso. El seméforo y las operaciones asociadas fueron definidos en 1965 por E. W. Dijkstra [Dijkstra 1965). Un seméforo comprende un valor entero (un contador) y dos operaciones: 82 Programacién Linux 2.0 * P (del holandés proberen, probar): esta operacién se utiliza cuando un proceso quie- re entrar en una secci6n critica. Esta operacién realiza las etapas siguientes: 1. probar el valor de] contador de! seméforo que controla el recurso; 2. si este valor es positivo, ¢l proceso puede servirse del recurso, y decrementa el valor en | para indicar que utiliza una unidad del recurso; 3. si este valor es nulo, e] proceso se duerme hasta que ef valor sea de nuevo posi- tivo, Cuando el proceso se despierta, vuelve a la etapa 1. + ¥ (del holandés verhogen, incrementar): esta operacién es simétrica a la anterior, y se utiliza cuando un proceso abandona Ia seccién eritica. El valor de] contador del seméforo se incrementa y los procesos en espera son despertados. Las operaciones P y V deben realizarse de manera atémica, es decir, que no deben ser interrumpidas. En la literatura inglesa, las operaciones P y V se denominan frecuentemente down y up. Los seméforos se utilizan en el Ambito de los sistemas informéticos principalmente para resolver dos problemas: * La exclusiém mutua: se trata de impedir a dos procesos el acceso a un mismo recur- so en un mismo instante. Si esto se produjera, el recurso podria encontrarse en un estado inconsistente. + Etproblema de les productores/consumidores: se trata de permitir la cooperacién de dos procesos: uno produce informaciones que el otro utilizar. El semAforo se utiliza para prevenir al consumidor que los datos estén a punto. Estos problemas se resuelven mediante semAforos binarios, pero el contador del sem4- foro puede tomar otros valores positivos. Es el caso cuando varias unidades de un mismo recurso estén disponibles; el contador toma entonces el valor del ntimero de unidades accesibles simulténeamente. Bajo Linux, la estructura semaphore, definida en el archivo , contiene los campos siguientes: Contador del sem4foro Niimero de procesos en espera struct wait_queue * | wait Lista de procesos en espera en el semdforo Procesos 83 5.4 Los timers Linux gestiona una lista de timers a fin de poder poner procesos en espera durante un lapso especificado. Estos timers se organizan en forma de una lista circular doblemen- te encadenada. Los timers a desencadenar en un futuro préximo se colocan al princi- pio de la lista, mientras que los elementos a desencadenar en un futuro lejano se sittan al final de la lista. La estructura timex_list, definida en el archivo , define el formato de los elementos de Ja lista: P descripcion struct timer_list * Puntero al elemento siguiente en la lista struct timer_list * prev —_{Puntero al elemento anterior de la lista unsigned long Fecha de expiracién del timer unsigned long Parémetro a transmitir a fa funcién asociada void (*} (unsigned long} | function |Direccién de la funcién a lemar cuando el timer expire La variable timer_head, definida en el archivo fuente kernel/sched.c, contiene la direccién del primer elemento de la lista. La fecha de expiracién (campo expires) se expresa en ntimero de ciclos de reloj desde el arranque del sistema. La variable global ji ££ies es mantenida por el micleo (su valor se incrementa en cada interrupcién del reloj) y contiene siempre el ntimero de ciclos de teloj transcurridos desde el arranque. 5.5 Ambitos de ejecucién El micleo mantiene los 4mbitos de ejecucién soportados. Para ello, una lista encadena- da simple contiene los descriptores de ambitos. La estructura exec_domain, defini- da en el archivo , describe los elementos de esta lista: const char * Nombre del 4mbito Jeall7_fune Direccién de la funci6n llamada si el proceso efectéa una Hamada al sistema por un salto intrasegmento al segmento mimero 7 (méodo de Hamada utilizado por System V y BSD Unix) ‘Cédigo de la personalidad asociada al 4mbito Cédigo de la personalidad asociada al émbito 84 Programacién Linux 2.0 mimeros de sefiales proporcionndos por ei proceso que llama mimeros de sefiales enviados al proceso que llama INémero de procesos que utilizan este mbito Puntero al descriptor del émbito siguiente en ta tista La variable exec_domains, definida en e] archivo fuente kermel/exec_domain.c, contiene la direccién del primer descriptor de la lista. En el arranque del sistema, la lista se inicializa y sélo contiene un elemento, Hamado default_exec.domain, que define la personalidad de Linux. 5.6 Formatos de los archivos ejecutables Linux soporta varios formatos de programas ejecutables, como los binarios a.out y ELF. A cada formato se Ie asocian varias funciones de manipulacién de los programas _ejecutables. La estructura linux_binfmt, definida en el archivo de cabecera , se utiliza a este efecto y contiene los campos siguientes: Hipo. a cripeion char [128] Primeros 128 bytes del archivo ejecutable | unsigned Direcciones de las pdginas de memoria que contienen los Leng [MAX_ARG_PAGES] argumentos int Booleano que indica si se ha interpretado ya una Ifnea del tipo #!nonbre_intérprete struct inode * i Descriptor del i-nodo del archive a ejecutar Tdentificador de usuario efectivo Identificador de grupo efectivo Némero de argumentos Numero de variables de entorno Nombre del archivo a ejecutar Campo utilizado solamente en la arquitectura Alpha Booleano que indica si debe Namarse a la funcién iput para liberar el descriptor del i-nodo 6 Presentacién detallada de la implementacién 6.1 Funciones internas 6.1.1 Sincronizacién de procesos El atchivo fuente kernel/sched.c contiene funciones de servicio que permiten la sin- cronizaci6n de procesos en modo nticleo. Estas funciones se utilizan en todas las par- tes dei nticleo cuando un proceso debe suspenderse en espera de un evento, y cuando debe ser «despertado». La funcién add_to_runqueue inserta un descriptor de proceso en la lista de pro- cesos a punto. La funcién del_from_runqueue permite suprimir un descriptor de esta lista. Un descriptor de proceso puede colocarse al fin de la lista por la funcién move_last_runqueue. La funcién wake_up_process despierta un proceso suspendido: pone su estado a TASK_RUNNING y lo inserta en fa lista de procesos a punto. 86 Programacién Linux 2.0 Las colas de espera (wait queues) son manipuladas por las funciones ~-add_wait_queue y __remove_wait_queue, definidas en el archivo de cabecera . Se afiade un elemento a la cola de espera por ~~add_wait_queue, y se suprime de dicha cola por__remove_wait_queue. Las funciones add_wait_queue y remove_wait_queue Ilaman respectivamen- tea __add_wait_queue y __remove_wait_queue ocultando previamente todas las interrupciones. La funcién wake_up permite despertar todos los procesos en espera de un evento en una cola de espera. Explora la cola, y llama a wake_up_process para cada proce- so cuyo estado sea TASK_UNINTERRUPTIBLE 0 TASK_INTERRUPTIBLE. Un tra- tamiento similar se realiza por Ja funcién wake_up_interrupt ible, pero esta Ultima sélo despierta los procesos cuyo estado es TASK_INTERRUPTIBLE. La funcién __s1eep_on suspende el proceso actual, y lo coloca en una cola de espe- 1a. Modifica ei estado de? proceso, guarda su descriptor en la cola por una llamada a add_wait_queue, y provoca un cambio de proceso actual por una llamada a la fun- cién schedule. Cuando el proceso se despierta, el resto de la funci6n se ejecuta, y el descriptor del proceso se suprime de la cola de espera por una llamada a remove_wait_queue. Las funciones interruptible_sleep_on y sleep_on llaman a _sleep_on especificdndole que ponga el estado del proceso actual respectivamente a TASK_INTERRUPTIBLE y TASK_UNINTERRUPTIBLE. La funcién __down permite que el proceso actual suspenda en espera de un evento sobre un seméforo. Se afiade el descriptor del proceso actual a la cola de espera del seméforo, su estado cambia a TASK_UNINTERRUPTIBLE, y se comprueba el conta- dor del seméforo. Mientras este contador es inferior o igual a cero, la funcién sche- dule se Hama para cambiar de proceso actual, y el estado del proceso se pone a TASK_UNINTERRUPTIBLE. Cuando el contador del seméforo pasa a estrictamente positivo, ef estado del proceso actual se pone a TASK_RUNNING y el descriptor del proceso se suprime de la cola de espera del sem4foro por una Iamada a remove_wait_queue. El uso de seméforos se efectéa mediante las funciones down y up definidas en el archivo de cabecera . 6.1.2 Coordinacién El coordinador de procesos lo implementa la funcién schedule, situada en el archi- vo fuente kernel/sched.c. Procesos 87 La funcién goodness se utiliza para seleccionar un proceso. Devuelve un valor que indica hasta qué punto el proceso necesita el procesador. En el caso de un proceso en curso de ejecucién en otro procesader, devuelve -1000 a fin de indicar que el proceso no debe seleccionarse. En e] caso de un proceso en tiempo real, devuelve la pricridad estdtica del proceso (campo rt_priority) aumentada en 1000. En el caso de un proceso normal, devuelve el valor del campo counter que representa el ntimero de ciclos de reloj durante el cual el proceso debe ejecutarse. La funci6n schedule implementa la coordinacién propiamente dicha. Empieza por desplazar al proceso actual al final de la lista de procesos a punto, Mamando a la fun- cién move_last_runqueue, si este proceso ha agotado todos sus ciclos. Si el proceso actual se encuentra en el estado TASK_INTERRUPTIBLE, schedule comprueba si ha recibido una sefial no oculta; si es éste el caso, €l estado del proceso actual se coloca de nuevo a TASK_RUNNING a fin de despertarlo. Se efectia seguida- mente una exploracién de la tabla de procesos: para cada proceso, la funcién good- ness s¢ llama a fin de determinar si el proceso debe elegirse. Al volver de esta biisqueda,el proceso elegido se convierte en e] proceso actual: la funcién get_mmu_context se llama para restaurar el contexto de memoria del proceso, y el cambio de contexto se provoca mediante una llamada a switch_to. El criterio utilizado por el coordinador es el valor del campo counter del descriptor de proceso. Este campo contiene el ntimero de ciclos de reloj durante los cuales el pro- ceso debe ejecutarse, Este campo es modificado por varias funciones: * update_process_times: esta funcién es llamada periédicamente por timex_lh, que forma parte de la cola de tareas (task queue) tq_timer, activa- da por el gestor de interrupci6n de reloj. El campo counter es decrementado por update_process_times, que posiciona la variable need_xesched a |, si el proceso actual ha agotado su lapso. * schedule: cuando el campo counter es nulo para todos los procesos, el coor- dinador efectéia un bucle sobre todos los descriptores de la tabla de procesos a fin de reinicializar el campo counter. El campo priority se utiliza entonces como valor de base. « add_to_runqueue: esta funcién, que ailade un proceso a Ia lista de procesos a punto, comprueba el campo count er: si es superior al del proceso actual, la varia- ble need_resched se pone a I, a fin de provocar un cambio de proceso actual.

También podría gustarte