Subido por vero.of86

ampliacion de sistemas operativos

Anuncio
AMPLIACIÓN DE
SISTEMAS OPERATIVOS
,
AMPLIACION DE
SISTEMAS OPERATIVOS
José Manuel Díaz Martínez
sanz y torres
MARCAS REGISTRADAS. Los nombres de los productos (hardware, software, sistemas operativos, etc.)
que aparecen en este libro pueden ser marcas registradas por sus fabricantes. El autor ha utilizado
exclusivamente estos nombres con el propósito de identificar los productos y sin intención de infringir
las marcas ni perjudicar a los propietarios de sus derechos.
AMPLIACIÓN DE SISTEMAS OPERATIVOS
Todos los derechos reservados. Queda prohibida, salvo excepción prevista en la ley, cualquier forma
de reproducción, distribución, comunicación pública y transformación de esta obra sin contar con la
autorización de los autores yjo editores. La infracción de los derechos mencionados puede ser cons­
titutiva de delito contra la propiedad intelectual.
© José Manuel Díaz Martínez
© EDITORIAL SANZ Y TORRES, S. L.
cj Pinos Alta, 49 - 28029 Madrid
� 902 400 415 - 91 314 55 99
www.sanzytorres.com
[email protected]
www.sanzytorres.com/editorial
[email protected]
ISBN: 978-84-15550-17-4
Depósito legal: M-26492-2012
Portada:
Masterline. S. L. cj Las Minas, 1, 28250 Torrelodones (Madrid)
Composición:
Autor
Impresión:
Jacaryan, S. A., Avda. Pedro Díez, 3, 28019 Madrid
Encuadernación:
Felipe Méndez, S. A., cj Del Carbón, 6 y 8, Poi. lnd. San José de Valderas 2, 28918 Leganés (Madrid)
"
Indice general
Prefacio
XIII
Lista de acrónimos y abreviaturas
XIX
l. Sistemas Operativos Basados en UNIX (SOBUNIX): introducción general
1.1.
1 .2.
1 .3.
1 .4.
1 .5 .
1 .6.
1 .7 .
1 .8 .
l. 9.
1 . 1 O.
1.11.
Introducción . . . . . . . . . . . . . . .
Cronología histórica de los SOBUNIX . . . .
Compatibilidad entre los SOBUNIX . . . . .
Características principales de los SOBUNIX .
Interfaces con los usuarios disponibles e n SOBUNIX
1 .5. 1 . Intérpretes de comandos . . .
1 .5.2. Interfaces de usuario gráficas . . . . . . . .
1 . 5 . 3 . Llamadas al sistema . . . . . . . . . . . .
Introducción a la gestión de archivos en SOBUNIX
Seguridad y protección en SOBUNIX .
l.7 .l. Identificadores reales . . . . . .
1 .7 .2. Máscara de modo de un archivo
1 .7 . 3 . Identificadores efectivos . . . .
l.7 .4. Implementación de la seguridad
Resumen . . . . . . .
Lecturas recomendadas
Autoevaluación
Ejercicios . . . . . . .
2. SOBUNIX: implementación y control de procesos multihilos
2. 1 . Introducción . . . . . . . . . . . . . . . . . . . . . . . . .
2.2. Implementación de los procesos multihilos en SOBUNIX .
2.2. 1 . Conceptos fundamentales . . . . . . . . . . . . .
2.2.2. Estructuras de datos asociadas a los procesos multihilos
2.3. Control de procesos multihilos en SOBUNIX . . . . . . . . . .
VII
1
2
2
5
5
7
7
19
22
23
25
25
27
32
33
35
36
37
40
45
46
46
46
49
56
Ampliación de sistemas operativos
vm
20 30 1 . Creación de procesos e invocación de otros programas
20 3020 Terminación de procesos
20 30 30 Notificación de eventos: señales
20 3 .40 Control de hilos de usuario: librerías de hilos
20 3050 Grupos de procesos y sesiones
20 3060 El sistema de archivos procfs
Resumen
Lecturas recomendadas
Autoevaluación
Ejercicios
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
56
63
67
76
79
81
84
85
85
88
o
2.40
20 50
2060
2070
o
o
o
o
o
o
o
o
o
o
o
o
o
o
3. SOBUNIX: planificación, sincronización y mecanismos IPC
93
30 1 . Introducción
3020 Planificación de procesos multihilos en SOBUNIX
3020 1 . Características generales
302020 Dos ejemplos ilustrativos de la planificación en SOBUNIX
302030 Expropiación del procesador
30 30 Mecanismos de sincronización del núcleo en SOBUNIX
30 30 1 . Cerrojos
30 3020 Semáforos
3.40 Dormir/despertar y colas de hilos dormidos en S OBUNIX
3050 Mecanismos de comunicación entre procesos en SOBUNIX
3050 1 . Mecanismos IPC del System V
30 5020 Otros mecanismos IPC
3060 Resumen
3 7 Lecturas recomendadas
3080 Autoevaluación
3090 Ejercicios
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
94
94
94
95
1 09
1 10
111
1 13
1 16
1 18
1 19
133
135
136
136
1 38
o
o
4. SOBUNIX: administración de memoria
143
40 1 . Introducción
4020 Gestión del espacio de direcciones virtuales de un proceso en
SOBUNIX
40 20 1 . Organización del espacio de direcciones virtuales de un proceso
402020 Mapeado de archivos en memoria
402030 Estructuras de datos gestionadas por el núcleo asociadas al espacio de direcciones virtuales de un proceso
402.40 Memoria anónima
402050 Memoria compartida
40 20 60 Operaciones sobre el espacio de direcciones virtuales de un proceso
402070 Creación del espacio de direcciones virtuales de un proceso
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
1 44
1 45
1 45
1 48
1 52
1 55
1 57
1 59
1 60
Índice general
4.3. Traducción de direcciones virtuales a direcciones físicas en
SOBUNIX . . . . . . . . . . . . . . . . . .
4. 3 . 1 . Tablas de páginas y MMU . . . . .
4.3.2. Tratamiento de los fallos de página
4.4. Gestión de la memoria física en SOBUNIX
4.4. 1 . Estructuras de datos utilizadas en la gestión de la memoria física .
4.4.2. Reemplazamiento de páginas . . .
4.4. 3 . Intercambio de procesos . . . . . . . .
4.4.4. Asignación de memoria principal . . .
4. 5 . Gestión del área d e intercambio en SOBUNIX .
4. 6. Gestión de la memoria perteneciente al núcleo en SOBUNIX
4.6. 1 . Espacio de direcciones virtuales del núcleo
4.6.2. Asignación de la memoria del núcleo
4.7. Resumen . . . . . . .
4.8 . Lecturas recomendadas
4. 9. Autoevaluación
4. 1 0. Ejercicios . . . . . . .
161
161
1 65
1 66
1 66
1 68
171
1 72
173
1 77
1 77
1 78
18 1
182
18 2
184
5. SOBUNIX: gestión de archivos y gestión de la E/S
5. 1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2. Gestión de archivos en SOBUNIX: características principales y
llamadas al sistema
5 .2. 1 . Archivos .
5. 2.2. Directorios
5 . 2 . 3 . Enlaces . .
5 .2.4. Sistemas de archivos
5. 3 . Capa nodo virtual/sistema de archivos virtual
5 . 3 . 1 . Nodos virtuales . . . . . . . . . . . .
5 . 3 .2. S istemas de archivos virtuales . . . .
5 . 3 . 3 . Análisis d e nombres de rutas en SOBUNIX
5.4. El sistema de archivos UFS . . . . . . . . . . . .
5 .4. 1 . Características principales . . . . . . . .
5 .4.2. Estructura de un sistema de archivos UFS
5 .4. 3 . Implementación de directorios e n UFS .
5 .4.4. Gestión de un sistema UFS .
5 . 5 . Gestión d e la E/ S e n SOBUNIX
5 . 5 . 1. Perspectiva general . . .
5.5.2. Archivos de dispositivos
5 . 5 . 3 . Subsistema de E/ S . .
5 .5.4. Drivers de los dispositivos de E/ S
5 . 5 . 5 . Tratamiento d e las interrupciones
.
IX
187
•
•
o
o
o
o
o
o
187
18 8
188
1 95
1 97
200
202
203
206
208
209
209
210
21 1
212
216
216
217
219
220
22 1
x
Ampliación de sistemas operativos
5.6.
5. 7.
5.8 .
5.9.
5. 10.
Conectores . . . . . .
Resumen . . . . . . .
Lecturas recomendadas
Autoevaluación
Ejercicios . . . . . . .
6. SOBUNIX: el sistema operativo Linux
6. 1 . Introducción . . . . . . . . . . . . .
6.2. Consideraciones generales sobre Linux .
6.2. 1 . Orígenes de Linux . . . . . .
6.2.2. Versiones del núcleo de Linux
6.2.3. Distribuciones Linux . . . . .
6 . 3 . Gestión de procesos e hilos en Linux .
6.3. 1 . Estructuras del núcleo asociadas a las tareas .
6.3.2. Creación de procesos e hilos en Linux
6 . 3 . 3 . Hilos del núcleo en Linux . . . . . . . . . .
6.4. Planificación en Linux . . . . . . . . . . . . . . . .
6.4. 1 . Planificador usado en las versiones del núcleo de Linux anteriores a la 2.6.23
6.4.2. Planificador utilizado a partir de la versión 2.6.23 del núcleo de Linux
6.5. Gestión de memoria en Linux . . . . . . . . . . . .
6.5. 1 . Gestión del espacio de direcciones virtuales
6.5.2. Gestión de la memoria física . . . . . . . .
6.6. Gestión de archivos en Linux . . . . . . . . . . . .
6.6. 1 . Implementación de la capa nodo virtual/sistema de archivos virtual en Linux
6.6.2. El sistema de archivos EXT2 .
6.6. 3 . E l sistema d e archivos EXT3 .
6.6.4. El sistema de archivos EXT4 .
6. 7. Resumen . . . . . . .
6.8 . Lecturas recomendadas
6.9. Autoevaluación
6. 1 O. Ejercicios
. . . . . .
.
7. El sistema operativo MS-DOS
7 . 1 . Introducción . . . . . . . . . . . . . . . . .
7.2. Consideraciones generales sobre MS-DOS .
7.2. 1 . Cronología histórica . . . . . . . .
7.2.2. Características principales de MS-DOS
7.2.3. Estructura del sistema operativo MS-DOS .
7.2.4. Llamadas al sistema .
7.2.5. Arranque de MS-DOS
7.2.6. Interfaz con el usuario
222
224
226
226
229
231
23 1
232
232
232
233
233
234
239
240
24 1
242
247
250
250
252
26 1
26 1
263
267
268
269
270
270
272
273
274
274
274
275
276
277
278
279
Índice general
7.3. Implementación y control de procesos en MS-DOS
7 . 3 . 1 . Creación y ejecución de un proceso
7.3 .2. Terminación de un proceso .
7.4. Gestión de memoria en MS-DOS .
7.5. Gestión de archivos en MS-DOS
7 . 5 . 1 . Archivos . . . . . .
7.5.2. Directorios . . . . .
7 . 5 . 3 . Sistemas de archivos
7.6. El sistema de archivos FAT .
7.6. 1 . Estructura de un sistema FAT
7.6.2. Implementación de directorios en un sistema FAT .
7 . 6 . 3 . Localización d e los clusters de datos d e u n archivo en u n sistema FAT
7.7. Gestión de la E/S en MS-DOS . . .
7.7. 1 . Subsistema de E/S . . . . . .
7.7.2. Drivers de dispositivos E/S . .
7 . 7 . 3 . Manej adores de interrupciones
7.8 . Resumen . . . . . . .
7.9. Lecturas recomendadas
7. 1 O. Autoevaluación
7. 1 1 . Ejercicios . . . . . . .
8. El sistema operativo Windows
8 . 1 . Introducción . . . . . . . .
8 .2. Consideraciones generales sobre Windows .
8 .2. 1 . Cronología histórica . . . . . . . .
8 .2.2. Características principales de Windows
8 .2.3. Estructura del sistema operativo Windows .
8 .2.4. Implementación de la API Win32 .
8 .2.5. Interfaz con el usuario de Windows
8 .2.6. Llamadas al sistema en Windows
8 .2.7. El registro de Windows .
8 .2.8 . Arranque de Windows
8 .2.9. Objetos del núcleo . . .
8 .2. 1 0. Seguridad en Windows .
8 .3 . Implementación, control y planificación de procesos multihilos en Windows
8 . 3 . 1 . Implementación de los procesos multihilos en Windows
8 .3.2. Control de procesos multihilos en Windows . . . . . . . . . .
8 . 3 . 3 . Planificación de procesos multihilos en Windows . . . . . . .
8 .4. Sincronización y comunicación entre procesos multihilos en Windows
8 .4. 1 . Mecanismos de sincronización usados por el sistema operativo
8 .4.2. Mecanismos de sincronización entre procesos multihilos disponibles en Windows
XI
28 3
28 3
28 4
28 4
28 7
28 7
28 9
28 9
290
290
29 1
292
292
292
294
294
295
2 96
296
297
299
300
300
300
302
303
305
306
307
308
3 10
3 10
311
313
313
316
319
325
325
325
XII
Ampliación de sistemas operativos
8 .4.3. Mecanismos de comunicación entre procesos multihilos disponibles en Windows
8 .5 . Gestión de memoria en Windows . . .
8 .5 . 1 . Administrador de memoria . .
8 . 5.2. Gestión de la memoria virtual
8 .5 . 3 . Traducción de direcciones . .
8 .5.4. Gestión de la memoria física .
8 .5 . 5 . Respaldo d e páginas e n memoria secundaria .
8 .6. Gestión de archivos en Windows . . . . . . . . . . .
8 . 6. 1 . Funciones de l a API Win32 asociadas a l a gestión de archivos y directorios
8 .6.2. Sistemas de archivos . . .
8 .7. El sistema de archivos NTFS . . . . . . . . . . . .
8 .7. 1 . Características principales . . . . . . . . .
8 .7.2. Estructura en el disco de un sistema NTFS
8 .7 . 3 . Estructura d e un directorio e n NTFS . . . .
8 .7 .4. Localización de archivos en un sistema NTFS .
8 .8 . Gestión de E/S en Windows . . . . . . . .
8 .8 . 1 . Subsistema de E/S . . . . . . . . . . .
8 .8 .2. Drivers de dispositivos en Windows . .
8 .8 . 3 . Gestión d e interrupciones e n Windows .
8 .9. Resumen . . . . . . .
8 . 10. Lecturas recomendadas
8 . 1 1 . Autoevaluación
8 . 1 2. Ejercicios . . . . . . .
327
328
328
329
332
335
338
339
339
340
341
341
344
348
349
35 1
35 1
352
354
356
358
358
361
A. Soluciones completas de los ejercicios
A . 1 . Soluciones ejercicios capítulo 1 .
A.2. Soluciones ejercicios capítulo 2 .
A . 3 . Soluciones ejercicios capítulo 3 .
A.4. Soluciones ejercicios capítulo 4 .
A.5. Soluciones ejercicios capítulo 5 .
A.6. Soluciones ejercicios capítulo 6 .
A.7. Soluciones ejercicios capítulo 7 .
A.8 . Soluciones ejercicios capítulo 8 .
363
Bibliografía
401
Índice alfabético
403
363
375
38 0
38 7
38 9
392
395
397
Prefacio
Sobre el autor
José Manuel Díaz Martínez es profesor titular de universidad en el Departamento de Informática
y Automática de la Escuela Técnica Superior de Ingeniería Informática de la Universidad Nacional de
Educación a Distancia (UNED). Desde el año 2001 imparte docencia en asignaturas relacionadas con
la materia Sistemas Operativos. Asimismo ha escrito diferentes materiales para el aprendizaje de esta
materia entre ellos el libro [Díaz et al., 2011].
A quién va dirigido este libro
Este libro está concebido para ser la bibliografía básica de la asignatura Ampliación de Sistemas
Operativos que se imparte en el tercer curso del Grado en Ingeniería en Tecnologías de la Información
de la UNED. Asimismo puede resultar de utilidad a estudiantes de Escuelas de Ingenierías o Facultades
de Ciencia que tengan en sus planes de estudio asignaturas relacionadas con los sistemas operativos. Por
supuesto este libro también puede ser utilizado por cualquier persona interesada en esta materia.
Objetivos
En el Grado en Ingeniería en Tecnologías de la Información de la UNED la materia Sistemas Opera­
tivos se diversifica en dos asignaturas: Sistemas Operativos y Ampliación de Sistemas Operativos. En la
asignatura Sistemas Operativos que se imparte en el segundo curso se adquieren los fundamentos básicos
de los sistemas operativos: descripción y control de procesos, planificación de procesos, comunicación
y sincronización de procesos, interbloqueo, administración de memoria, memoria virtual, gestión de la
E/S, gestión de archivos y seguridad y protección.
Por otra parte en la asignatura Ampliación de Sistemas Operativos que se imparte en el tercer curso
se pretende consolidar y practicar con los fundamentos básicos de los sistemas operativos adquiridos en
la asignatura Sistemas Operativos. Para lograr este objetivo en esta asignatura se estudian los sistemas
operativos basados en UNIX (BSD, System V, Solaris, Linux, etc) y los sistemas operativos MS-DOS y
Windows. Este estudio se realiza tanto desde un punto de vista interno, describiendo las características
principales del núcleo de estos sistemas operativos, como desde un punto de vista externo, describiendo
y practicando con las llamadas al sistema y comandos disponibles en estos sistemas operativos.
xm
Ampliación de sistemas operativos
XIV
_
__
___
----------
Este libro tiene como objetivo fundamental explicar, de la forma más clara posible, las características
internas y externas de los Sistemas Operativos Basados en UNIX (SOBUNIX) y de los sistemas opera­
tivos MS-DOS y Windows. Como resultado del estudio y aprendizaje de los contenidos de este libro el
estudiante será capaz de:
•
Conocer las características generales de los SOBUNIX.
•
Conocer los comandos básicos de los intérpretes de comandos de los SOBUNIX.
•
Conocer las principales llamadas al sistema disponibles en los SOBUNIX.
•
Conocer la implementación y control de los procesos multihilos de los SOBUNIX.
•
Conocer la planificación de procesos multihilos, los mecanismos de sincronización del núcleo y
los mecanismos IPC de los SOBUNIX.
•
Saber cómo se realiza la administración de memoria en los SOBUNIX.
•
Saber cómo se realiza la gestión de archivos y la gestión de la E/S en los SOBUNIX.
•
Conocer las particularidades del sistema operativo Linux.
•
Conocer las características generales del sistema operativo MS-DOS .
•
Conocer los comandos básicos del intérprete de comandos de MS-DOS .
•
Conocer la implementación y control de los procesos en MS-DOS .
•
Saber cómo se realiza la administración de memoria en MS-DOS .
•
Conocer cómo se realiza la gestión de archivos y la gestión de la E/S en MS-DOS .
•
Conocer las características generales del sistema operativo Windows.
•
Conocer los principales llamadas al sistema del sistema Windows.
•
Conocer la implementación, control y planificación de los procesos multihilos en Windows.
•
Conocer los mecanismos de sincronización del núcleo y los mecanismos de comunicación entre
procesos de Windows.
•
Saber cómo se realiza la administración de memoria en Windows.
•
Saber cómo se realiza la gestión de archivos y la gestión de la E/ S en Windows.
Prefacio
xv
(�onocimientos previos necesarios
Para comprender adecuadamente los contenidos de este libro es necesario conocer los fundamentos
básicos de la materia Sistemas Operativos: [Silberschatz et. al, 2002] , [Stallings, 2005] , [Tanenbaum ,
2009 ] y [Díaz et al., 20 1 1 ] . También es necesario tener conocimientos básicos de programación en C :
1 Kernighan y Ritchie, 199 1 ] y [Gottfried, 2005] .
Organización
Los contenidos de este libro se organizan en ocho capítulos. Conviene señalar que en la organización
propuesta se ha tenido en cuenta el hecho de que muchos SOBUNIX son de código abierto a diferencia
de MS-DOS y Windows que son de código cerrado. Por ello se ha preferido dedicar más de la mitad
del libro al estudio de los S OBUNIX, ya que el estudiante interesado podrá acceder al código fuente de
diversos miembros de esta familia de sistemas operativos.
En el capítulo 1 se realiza una introducción a los SOBUNIX. En primer lugar se comentan la cro­
nología histórica , la compatibilidad y las características principales de los SOBUNIX. En segundo lugar
se describen los interfaces con los usuarios disponibles en los SOBUNIX. En tercer lugar se realiza una
introducción a la gestión de archivos en SOBUNIX. Finalmente, se describe como se implementa la
seguridad y la protección en los SOBUNIX.
El capítulo 2 está dedicado la implementación y control de procesos multihilos en los SOBUNIX . En
la primera parte del capítulo se trata la implementación de los procesos multihilos: conceptos fundamen­
tales y principales estructuras de datos. En la segunda y última parte se trata el control de los procesos
multihilos: creación, invocación y terminación de procesos, notificación de eventos mediante señales,
librerías de hilos, grupos de procesos y sesiones, y el sistema de archivos procfs.
El capítulo 3 está dedicado a la planificación, sincronización y mecanismos IPC de los SOBUNIX.
En la primera parte del capítulo se describen las características generales de la planificación de procesos
multihilos. En esta parte, a modo de ejemplo, se estudia la implementación de la planificación de dos
SOBUNIX ilustrativos : BSD 4.3 y Solaris. Posteriormente se incluyen diferentes consideraciones sobre
la expropiación del procesador. En la segunda parte del capítulo se describen los principales mecanismos
de sincronización del núcleo de los SOBUNIX: cerrojos y semáforos. También se incluyen algunas
consideraciones sobre la implementación de las operaciones de dormir y despertar y sobre las colas
de procesos o hilos dormidos. En la tercera y última parte se describen los principales mecanismos
IPC disponibles en los SOBUNIX: los mecanismos IPC del System V (semáforos, colas de mensajes y
memoria compartida), las señales y las tuberías.
El capítulo 4 está dedicado a la administración de memoria en los SOBUNIX. En primer lugar se
estudia la gestión del espacio de direcciones virtuales de un proceso. En segundo lugar se describe la tra­
ducción de direcciones virtuales a direcciones físicas. En tercer lugar se analiza la gestión de la memoria
física . En cuarto lugar se describe la gestión del área de intercambio. Finalmente se describe la gestión
de la memoria del propio núcleo.
El capítulo 5 está dedicado al estudio de la gestión de archivos y la gestión de la E/S en los SO­
BUNIX. En primer lugar se explican las características principales de los archivos, los directorios, los
XVI
Ampliación de sistemas operativos
enlaces y los sistemas de archivos en los SOBUNIX. Asimismo se enumeran y describen las principales
llamadas al sistema disponibles en los SOBUNIX para la gestión de estos elementos. En segundo lugar
se describe la capa nodo virtual/sistema de archivos virtual utilizada en la mayoría de los SOBUNIX
modernos para poder soportar diferentes tipos de sistemas de archivos. En tercer lugar se explica cómo
se analizan los nombres de rutas en los SOBUNIX. En cuarto lugar se describe el sistema de archivos
UFS , el cual es utilizado en diversos SOBUNIX. En cuarto lugar se describe la gestión de la E/S en
los SOBUNIX. El capítulo finaliza con una introducción a los conectores que son uno de los principales
mecanismos utilizados en S OBUNIX para implementar las conexiones en red.
El capítulo 6 está dedicado al estudio de las particularidades del sistema operativo Linux, uno de los
miembros más populares de la familia de SOBUNIX. En primer lugar se incluyen una serie de conside­
raciones generales sobre Linux. En segundo lugar se describe el modelo de proceso multihilo utilizado
en Linux. En tercer lugar se estudia la planificación de procesos multihilos en Linux. En cuarto lugar
se estudia la implementación de la gestión de memoria. Finalmente se estudian los sistemas archivos
nativos de Linux: EXT2, EXT3 y EXT4.
El capítulo 7 está dedicado al estudio del sistema operativo MS-DOS . En primer lugar se realizan
una serie de consideraciones generales. En segundo lugar se describen la implementación y el control
de procesos. En tercer lugar se estudia la gestión de memoria. En cuarto lugar se estudia la gestión de
archivos y el sistema de archivos FAT- 1 2. Finalmente se estudia la gestión de la E/S.
El capítulo 8 está dedicado al estudio del sistema operativo Windows. En primer lugar se realizan
una serie de consideraciones generales sobre Windows. En segundo lugar se describe la implementación,
control y planificación de procesos multihilos. En tercer lugar se estudian los mecanismos de sincroniza­
ción del núcleo y los mecanismos IPC. En cuarto lugar se estudia la gestión de memoria. En quinto lugar
se describe la gestión de archivos y el sistema de archivos NTFS . Finalmente se estudia la gestión de la
E/S .
E l libro también contiene u n apéndice A en el que s e incluyen las soluciones completas de los ejer­
cicios incluidos al final de cada capítulo, la mayoría de los cuales han sido propuestos en exámenes.
Cómo usar el libro
Este libro está pensado para la educación a distancia, por ello sus contenidos han sido organizados
y seleccionados para un aprendizaje progresivo y secuencial. Además se incluyen bastantes figuras y
ejemplos que ayudan a comprender los contenidos expuestos.
Por otra parte, el estudiante dispone de cuestiones de autoevaluación y de las soluciones de todos
los ejercicios para poder comprobar si efectivamente ha asimilado los contenidos y ha alcanzado los
objetivos marcados.
Todos los capítulos tienen una estructura uniforme. En primer lugar, se enumeran los objetivos do­
centes del capítulo. En segundo lugar, se realiza una introducción a los contenidos del capítulo. En tercer
lugar, se incluyen los contenidos propiamente dichos. En cuarto lugar, se realiza un resumen de los con­
tenidos, el cual ayuda a fijar los contenidos más importantes. En quinto lugar, se incluyen las lecturas
recomendadas. En sexto lugar, se incluyen las cuestiones de autoevaluación, a través de las cuales el estu­
diante puede establecer el grado de asimilación de los contenidos y deducir qué contenidos debe repasar.
Prefacio
XVII
Jiinalmente, se plantean varios ejercicios con los que practicar o ampliar los contenidos aprendidos . Se
recomienda intentar hacer cada ejercicio antes de mirar su solución en el apéndice A.
Sobre las unidades de almacenamiento de la información usadas en este libro
La unidades básicas de almacenamiento u organización de la información son el bit (símbolo b) y el
O o un 1 , que se utiliza para representar una
pareja de posibles estados, por ejemplo: encendido y apagado, presente y ausente, etc. Un byte son ocho
bits contiguos. En la siguiente tabla se incluyen los prefijos que se utilizan en este texto para especificar
los múltiplos de las unidades anteriores, de acuerdo con el SI y el estándar 1 54 1 del IEEE.
byte (símbolo B). Un bit es un dígito binario, es decir, un
Prefijo
kibi
kilo
mebi
mega
gibi
giga
tebi
tera
pebi
peta
exbi
exa
Símbolo
Ki
k
Mi
M
Gi
G
Ti
T
Pi
Valor
21U
10
3
220
1 06
230
10
9
240
1 01
2
250
p
1 01 5
Ei
E
1
10 8
260
Sistema de unidades
IEEE 1 54 1
SI
IEEE 1 54 1
SI
IEEE 1 54 1
SI
IEEE 1 54 1
SI
IEEE 1 54 1
SI
IEEE 1 54 1
SI
Contacto con el autor: envío de erratas, comentarios y sugerencias
Pese al esfuerzo realizado por explicar lo mej or posible los contenidos incluidos en este libro y evitar
la existencia de erratas el autor es consciente de que seguramente habrá fracaso en su objetivo, por este
motivo estará encantado de recibir en la dirección
a s o@di a . uned . e s
todas las erratas, comentarios y sugerencias que los lectores deseen enviar. Además en la página web
h t tp: / / www . uned . e s / 7 1 0 2 3 0 1 6 /ma t e r i a l e s . html
se irán recopilando todas las erratas que se vayan detectando así como las aclaraciones a los contenidos
del libro que sean necesarias.
Lista de acrónimos y abreviaturas
ALPCs
APC
API
ASCII
BCPL
BIOS
BSD
BSS
CD
CDE
CFS
CPU
DACL
DLL
DPC
DVD
E/S
EFS
EGID
EMS
EUID
EXT
EXT2
EXT3
EXT4
FAT
FCB
FFS
FIFO
FSD
GDI
Advanced Local Procedure Calls
Asynchronous Procedure Call
Application Program Interface
American Standard Code for Information
Interchange
Basic Combined Programming Language
Basic Input-Output System
Berkeley Software Distribution
Block Started by Symbol
Compact Disc
Common Desktop Environment
Completely Fair Scheduling
Central Processing Unit
Discretionary Access Control List
Dynamic Link Library
Deferred Procedure Call
Digital Versatile Disc
Encryption File System
Effective Group IDentifier
Expanded Memory Specifications
Effective U ser IDentifier
EXTended filesystem
Second EXTended filesystem
Third EXTended filesystem
Fourth EXTended filesystem
File Allocation Table
File Control B lock
Fast File System
First Input - First Output
File System Driver
Graphics Device Interface
XIX
Llamadas a procedimientos locales avanzados
Llamadas a procedimientos asíncronos
Interfaz de programas de aplicación
Código estándar americano para el intercam­
bio de información
Lenguaje de programación combinado básico
Sistema básico de Entrada/Salida
Distribución de software de B erkeley
B loque inicializado con símbolos
Disco compacto
Entorno de escritorio común
Planificación completamente j usta
Unidad central de procesamiento
Lista de acceso discrecional
Librería de enlace dinámico
Llamadas a procedimientos aplazados
Disco versátil digital
Entrada/Salida
Encriptación del sistema de archivos
Identificador de grupo efectivo
Especificaciones de memoria expandida
Identificador de usuario efectivo
Sistema de archivos extendido
Segundo sistema de archivos extendido
Tercer sistema de archivos extendido
Cuarto sistema de archivos extendido
Tabla de asignación de archivos
B loque de control del archivo
S istema de archivos rápido
Primero en entrar primero en salir
Driver del sistema de archivos
Interfaz de dispositivos gráficos
XX
Ampliación de sistemas operativos
GID
GNU
GPL
GUI
HAL
HAT
IFS
IP
IPC
IRP
IRQL
KDE
LPC
LRU
LSI
LWPID
MFT
MIT
MMU
M S-DOS
msgid
MULTICS
mutex
NFS
NTFS
NUMA
Nodo-i
Nodo-s
Nodo-v
npi
OSF
PAE
PCs
PEB
PID
PFRA
PGID
PnP
POS IX
procfs
PSP
R/W
RAM
RFS
Group IDentifier
GNU is Not Unix
General Public License
Graphical U ser Interface
Hardware Abstraction Layer
Hardware Address Translation
Installable File System
Internet Protocol
InterProcess Communications
1/0 Request Packet
Interrupt Request Level
K Desktop Environment
Local Procedure Call
Least Recently U sed
Large S cale lntegration
LightWeight Process IDentifier
Master File Table
Massachusetts Institute of Technology
Memory Management Unit
MicroSoft-Disk Operating System
Message queue identification
MULTiplexed Information and Computing
Service
mutual exclusion
Network File System
New Technology FileSystem
Non-Uniform Memory Access
Open Software Foundation
Physical Address Extension
Personal Computers
Process Environment Block
Process IDentifier
Page Frame Reclaiming Algoritm
Process Group IDentifier
Plug-and-Play
Portable Operating System Interface based
on UNIX
process file system
Program Segment Prefix
Reader/Wri ter
Random Access Memory
Remote File Sharing
Identificador de grupo
GNU No es Unix
Licencia pública general
Interfaz de usuario gráfica
Capa de abstracción del hardware
Traducción de direcciones hardware
Sistemas de archivos instalables
Protocolo de Internet
Comunicaciones entre procesos
Paquete de petición de E/ S
Nivel de petición de interrupción
Entorno de escritorio K
Llamada a procedimiento local
Usada menos recientemente
Integración a gran escala
Identificación de proceso ligero
Tabla de archivos maestra
Instituto Tecnológico de Massachusetts
Unidad de gestión de memoria
Sistema operativo de disco de Microsoft
Identificación de la cola de mensajes
Servicio de cálculo e información multiplexada
exclusión mutua
Sistema de archivos en red
Sistema de archivos de tecnología nueva
Acceso a memoria no uniforme
Nodo índice
Nodo sombra
Nodo virtual
Nivel de prioridad de la interrupción
Fundación de software abierto
Extensión de dirección física
Computadores personales
Bloque de entorno del proceso
Identificador de proceso
Algoritmo de reclamo de marcos de página
Identificador de grupo de procesos
Conectar y usar
Interfaz de sistema operativo portable basada
en UNIX
sistema de archivos de procesos
Prefijo del segmento del programa
Lector/Escritor
Memoria de acceso aleatorio
Compartición de archivos remotos
Lista de acrónimos y abreviaturas
ROM
RPCs
S5FS
SAV
SAM
SCB
semid
SFT
shmid
SI
SID
SOBUNIX
SUA
Read Only Memory
Remote Procedure Calls
System V FileSystem
sus
Single UNIX Specification
Transmission Control Protocol
Thread Environment Block
Thread Group IDentifier
Task IDentifier
Translation Lookaside Buffer
Terminate and Stay Resident
U ser Datagram Protocol
UNIX File System
User IDentifier
Uniform Memory Access
Universal Serial Bus
Virtual Address Descriptor
Virtual File System
Virtual Memory
Windows Driver Model
Extended Memory Specifications
TCP
TEB
TGID
TID
TLB
TSR
UDP
UFS
UID
UMA
USB
VAD
VFS
VM
WDM
XMS
Security Account Manager
Stream Control Block
Semaphore identification
System File Table
Shared memory identification
Le Systéme International d'Unités
Session IDentifier
Subsystem for Unix-based Applications
XXI
Memoria de sólo lectura
Llamadas a procedimientos remotos
Sistema de archivos del S ystem V
Sistema de Archivos Virtual
Administrador de cuentas de seguridad
B loque de control del flujo
Identificación del semáforo
Tabla de archivo del sistema
Identificación de la memoria compartida
S istema Internacional de unidades
Identificador de sesión
Sistemas Operativos Basados en UNIX
Subsistema para aplicaciones basadas en
UNIX
Especificación única de UNIX
Protocolo de control de transmisión
Bloque de entorno del hilo
Identificador de grupo de hilos
Identificador de tarea
Buffer de traducción de vista lateral
Terminar y permanecer residente
Protocolo datagrama de usuario
Sistema de archivos UNIX
Identificador de usuario
Acceso a memoria uniforme
Bus universal en serie
Descriptor de direcciones virtuales
Sistema de archivos virtual
Memoria virtual
Modelo de drivers de Windows
Especificaciones de memoria extendida
Capítulo 1
Sistemas Operativos Basados en UNIX
(SOBUNIX): introducción general
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes :
•
Conocer el origen y la evolución del sistema operativo UNIX y de los principales Sistemas Ope­
rativos Basados en UNIX (SOBUNIX).
•
Saber cuáles son los principales estándares de compatibilidad soportados por los SOBUNIX.
•
Conocer las características principales de los SOBUNIX.
•
Conocer el funcionamiento y la implementación de las interfaces de usuario de los SOBUNIX:
interfaz de línea de comandos (intérpretes de comandos) e interfaz gráfica.
•
Conocer las principales acciones que de forma general realiza el núcleo de un SOBUNIX para
atender una llamada al sistema.
•
Conocer los comandos básicos asociados a la gestión de archivos y directorios disponibles en los
intérpretes de comandos de los SOBUNIX.
•
Conocer la estructura básica y las características de los archivos de comandos (shell scripts) de los
SOBUNIX.
•
Conocer los conceptos de objeto de archivo abierto, descriptor de archivo y nodo virtual (nodo-v).
•
Saber cómo se implementa la seguridad y la protección en los SOBUNIX.
1
2
Ampliación de sistemas operativos
1.1.
Introducción
El sistema operativo UNIX nacido a principios de los años setenta ha sido tomado como base de un
gran número de sistemas operativos. En este texto se usará el término SOBUNIX para referirse tanto al
UNIX original como a los diferentes Sistemas Operativos Basados en UNIX.
En este primer capítulo se realiza una introducción general a los SOBUNIX. En primer lugar se
describen la cronología histórica, los estándares de compatibilidad y las principales características de
los S OBUNIX. En segundo lugar se describe el funcionamiento y la implementación de los dos tipos
de interfaz de usuario disponibles en los SOBUNIX: interfaz de línea de comandos e interfaz gráfica.
Además se comentan las acciones que de forma general realiza el núcleo de un SOBUNIX para atender
las llamadas al sistema.
En el caso de la interfaz de línea de comandos se define qué es un intérprete de comandos, se enu­
meran los principales tipos de intérpretes de comandos, se analiza la estructura de los comandos, se
introducen algunos comandos básicos asociados a la gestión de archivos y directorios, se explica qué
son las variables del intérprete de comandos y las variables de entorno, y se explica qué son, cómo se
construyen y cómo se ejecutan los archivos de comandos (shell scripts). En el caso de las interfaces de
usuario gráficas (Graphical U ser Interfaces, GUis) de los SOBUNIX, se describe el sistema X Windows,
las librerías widgets toolkits y los entornos de escritorio.
En tercer lugar se realiza una breve introducción a la gestión de archivos en los SOBUNIX para
presentar los conceptos de objeto de archivo abierto, descriptor de archivo y nodo virtual (nodo-v), los
cuales se utilizan en los siguientes capítulos.
Finalmente se describen los elementos que de forma general utilizan los SOBUNIX para implementar
la seguridad y la protección de los datos de los usuarios: los identificadores reales, los identificadores
efectivos y la máscara de modo de un archivo.
1.2.
Cronología histórica de los SOBUNIX
A finales de los años 60 los laboratorios Bell propiedad de AT&T, General Electric y el MIT cola­
boraron para desarrollar el sistema operativo de tiempo compartido MULTIC S . Las primeras versiones
de este sistema operativo tuvieron un rendimiento deficiente y su éxito comercial fue escaso. Por estos
motivos, entre otros, los laboratorios Bell decidieron desvincularse del proyecto; aunque mantuvieron a
Ken Thompson, uno de los programadores de Bell que había colaborado en MULTICS, pendiente del
proyecto.
Thompson por iniciativa propia decidió escribir en lenguaje ensamblador una versión reducida de
MULTICS para el minicomputador PDP-7. Brian Kernighan, compañero de Thompson en Bell, con­
sideraba al sistema operativo desarrollado por Thompson una versión capada de MULTICS . Por ello,
haciendo gala de un gran sentido del humor, lo bautizó inicialmente con el nombre de UNICS . Nótese
que UNICS en inglés suena igual que la palabra inglesa eunuchs, que significa eunucos en español. Por
simplificar su escritura el nombre de UNICS fue sustituido finalmente por el nombre de UNIX.
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
3
Cuando los responsables de los laboratorios Bell vieron el trabajo de Ken Thompson quedaron gra­
tamente impresionados y decidieron darle apoyo económico para que portara UNIX a la familia de mini­
computadores PDP- 1 1 , bastante popular por aquella época. Puesto que programar en lenguaje ensambla­
dor es bastante tedioso, Thompson decidió que para portar UNIX a la familia PDP- 1 1 reescribiría UNIX
en un lenguaje de alto nivel. En primer lugar se decantó por utilizar el lenguaje B que el mismo había
desarrollado basándose en BCPL; pero este lenguaje tenía algunas deficiencias importantes, por ejemplo
no soportaba estructuras de datos, por lo que pronto se dio cuenta que no era el lenguaj e más apropiado.
Dennis Ritchie, otro programador de laboratorios Bell, desarrolló en 1 972 un lenguaje de progra­
mación de alto nivel al que llamó C. Además escribió un compilador de C para los minicomputadores
PDP- 1 1 . El lenguaje C [Kemighan y Ritchie, 1 99 1 ] es un lenguaje muy flexible que crea un código
bastante eficiente. Ante sus notables ventajas, Thompson decidió reescribir UNIX en C. Para esta tarea
contó con la ayuda de Ritchie. Escrito en C el código de UNIX era mucho más conciso y compacto,
además posibilitaba su portabilidad no solo a la familia PDP- 1 1 sino también a otras arquitecturas.
En 1 974 se dio a conocer públicamente la nueva versión de UNIX [Ritchie y Thompson, 1 974] . Ello
propició que muchas universidades se interesaran por este sistema operativo. Como la legislación esta­
dounidense vigente no permitía a AT &T comercializar directamente UNIX, AT &T no tuvo inconveniente
en otorgar licencias de UNIX a las universidades con fines educativos y de investigación. Las copias de
UNIX que AT &T distribuyó a las universidades incluían también su código fuente lo que propició que la
comunidad universitaria aportara sugerencias e ideas para mej orar UNIX.
El departamento de computación de la Universidad de California en Berkeley, fue mucho más lejos,
ya que modificó tanto el código fuente que desarrolló y distribuyó su propio UNIX al que llamó BSD
(Berkeley Software Distribution). Las versiones BSD 1 .0 y BSD 2.0 no modificaban el UNIX original
de AT&T simplemente consistían en aplicaciones y utilidades. Es la versión BSD 3 . 0 lanzada en 1 979
la que se considera un sistema operativo completo como tal y la que hizo que BSD se convirtiera en
un fuerte competidor del UNIX original de AT&T. Las siguientes versiones de BSD fueron BSD 4.0 en
1 98 0, BSD 4. 1 en 1 98 1 , BSD 4.2 en 1 98 3 , BSD 4.3 en 1 98 6 y BSD 4.4 en 1 993 .
Por su parte AT&T sacó la versión 7 de UNIX en 1 979, que sería la última del UNIX original con
una amplia distribución, ya que la versión 8 que se liberó en 1 98 5 y las versiones 9 y 1 O que se liberaron
a finales de los 8 0 sólo fueron adquiridas por unas pocas universidades.
Aparte de las universidades, algunas empresas fabricantes de computadores y de software también
obtuvieron licencias de UNIX y produjeron sus propias distribuciones. Un ejemplo es el sistema Xenix,
desarrollado por Microsoft Corporation y Santa Cruz Operation (SCO) a principios de los años 8 0, que
era una adaptación del UNIX versión 7 a las máquinas lntel 8 08 6. Xenix fue una de las primeras distri­
buciones comerciales de UNIX. Señalar que Microsoft centró sus esfuerzos en otros sistemas operativos
y vendió sus derechos de Xenix a SCO, con lo que el sistema operativo pasó a llamarse SCO Xenix.
Debido a la proliferación de distribuciones de UNIX, AT &T también decidió entrar en el negocio a
través de una compañía filial. Así en 1 98 1 lanzó el sistema System III, la variante comercial del UNIX
versión 7. Poco después, en 1 98 3, lanzaría el sistema System V Release 1 , o abreviadamente SVR l .
Las siguientes versiones fueron SVR2 en 1 98 4, SVR3 en 1 98 7 y SVR4 en 1 98 8 . Señalar que el sistema
System V incorporó características de otras distribuciones de UNIX, como BSD.
4
Ampliación de sistemas operativos
El conjunto de las principales distribuciones comerciales de UNIX aparecidas en la década de los
ochenta lo completan SunOS , AIX y HP-UX. El sistema SunOS de la compañía Sun Microsystems era
una adaptación de BSD para sus máquinas Sun. El que SunOS se basará en BSD y no en el UNIX de
AT&T no es casual ya que Bill Joy, uno de los socios fundadores en 1 98 2 de Sun Microsystems, era
también uno de los creadores de BSD. Conviene señalar que a partir de su versión 4.0 de 1 98 8 , debido
a un acuerdo entre S un Microsystems y AT&T, S unOS también pasó a incorporar características del
System V. De hecho, la versión 5 . 0 de SunOS , comercializada en 1 992 con el nombre de Solaris 2,
estaba basada exclusivamente en SVR4, en cuyo desarrollo también había colaborado Sun.
El sistema AIX fue distribuido por IBM y el sistema HP-UX por Hewlett-Packard. Ambos esta­
ban basados inicialmente en el sistema System III de AT&T, aunque luego se basaron en el System V
incluyendo también características de BSD.
Otros proyectos y sistemas basados en UNIX aparecidos en la década de los 8 0 y principios de los 90
que merecen ser mencionados por su importancia y porque el objetivo de su desarrollo no era el beneficio
económico son: GNU, MINIX y Linux. El proyecto GNU fue propuesto en 1 98 3 por Richard Stallman y
pretendía crear un sistema parecido a UNIX que pudiese ser distribuido libremente y que hiciese resurgir
el espíritu de colaboración desinteresada que existió a fi nales de los 70. Aunque el proyecto GNU nunca
ha llegado a crear un sistema operativo como tal, ya que en sus inicios no se llegó a escribir un núcleo
adecuado y luego optaron por Linux, si que generó diversas aplicaciones, como el compilador de C gcc
o el editor emacs, que han sido incorporadas en otros SOBUNIX. Actualmente el proyecto GNU sigue
vivo y cuenta con una amplia comunidad de colaboradores.
El sistema MINIX basado en el funcionamiento del UNIX versión 7 fue desarrollado en 1 98 7 por
Andrew S. Tanenbaum con fines educativos; por ello su código es abierto y no muy extenso. Por su parte,
el sistema Linux, también de código abierto fue desarrollado a principios de los 90 por Linus B. Torvalds
(ver sección 6.2. 1 ) .
Volviendo al origen d e todo, e n 1 98 9 AT&T creó la división Unix Systems Laboratories (USL) y en
ella delegó el desarrolló y la comercialización del System V. En 1 99 1 , la compañía Novell adquirió parte
de USL y creo la filial Univel. Univel lanzó en 1 992 el sistema UnixWare para computadores personales.
UnixWare estaba basado en SVR4 y Netware (un sistema operativo de red). En 1 993 Novell se hizo con
el resto de USL, aunque en 1 995 la vendió junto con Univel a SCO la cual continuó con el desarrollo
del System V. De hecho la versión 7.0 de su sistema UnixWare lanzada en 1 997 estaba basada en SVR5 .
SCO también basó su sistema OpenServer en SVR5 .
Con respecto al sistema BSD su desarrolló llegó a su fin con la distribución B S D 4.4-Lite Release 2
aparecida en 1 995. Pese a ello han seguido desarrollándose sistemas operativos basados total o parcial­
mente en BSD. Algunos de estos sistemas son libres y de código abierto, como por ejemplo: NetBSD,
OpenBSD y FreeBSD. Otros son sistemas comerciales, como por ejemplo, Mac OS X de Apple.
En la actualidad la familia de SOBUNIX sigue muy viva y es muy amplia. Algunos son sistemas
comerciales, como por ejemplo: Solaris 1 0 de Sun aparecido en 2005 contando como núcleo con SunOS
5 . 1 0, AIX 7. 1 de IBM aparecido en 20 1 1 , HP-UX 1 1 .3 1 de HP aparecido en 2009 y Mac OS X 1 0.8 de
Apple aparecido en 20 1 2. Otros son sistemas libres como MINIX 3 . 2 de 20 1 2, OpenSolaris 2009.06 de
2009, NetBSD 5 . 1 .2 de 20 1 2, OpenBSD 5.0 de 20 1 1 , FreeB SD 9.0 de 20 1 2 y Linux 3 . 3 . 6 de 20 1 2 .
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
1.3.
5
Compatibilidad entre los SOBUNIX
La gran variedad de SOBUNIX resultaba un serio problema para los desarrolladores de aplicaciones
software. Las diferencias existentes entre unos SOBUNIX y otros propiciaban que una misma aplicación
pudiera no funcionar correctamente en todos los sistemas.
Para intentar resolver este problema se han creado diferentes estándares, también denominados nor­
mas o especificaciones, para definir una API para los SOBUNIX. Una aplicación que es desarrollada
usando una API definida por un determinado estándar tiene garantizado que puede ser ejecutada en todos
los sistema operativos que soporten dicho estándar. Una API queda definida, entre otros elementos, por el
conjunto de llamadas al sistema que pueden invocarse. Aparte del API los estándares también definen las
reglas que deben seguir los intérpretes de comandos (shells) y los archivos de órdenes para los intérpretes
(shell scripts).
Entre los diferentes estándares que aparecieron destaca el estándar POSIX que es soportado por
bastantes sistemas operativos. Este estándar fue desarrollado en 1 98 8 por IEEE teniendo en cuenta las
características comunes existentes en los sistemas System V y BSD. POSIX consta de diferentes docu­
mentos o extensiones los cuales se conocen con el nombre de familia IEEE Std 1 003, siendo el IEEE Std
1003 . 1 su documento base. También POS IX dispone de un conjunto de tests que permiten certificar que
un sistema cumple el estándar.
Otro estándar que cada vez está más en auge es el estándar SUS, sobre todo desde que IEEE cobra
una cantidad no despreciable por proporcionar la documentación del estándar y los test de POSIX. Este
estándar fue desarrollado en 1 997 por The Open Group, un consorcio formado por empresas y agencias
gubernamentales que se creó en 1 996 con la unión de X/Open y OSF. Este consorcio también certifica
que un sistema cumple con el estándar SUS . Dicha certificación identifica y aprueba a un sistema basado
en UNIX.
Desde su versión 3 de 200 1 , SUS es compatible con POSIX, ya que el documento base de ambos
estándares ha sido desarrollado por The Austin Group un grupo de trabajo en el que participan el IEEE
y The Open Group, entre otros. Ejemplos de sistemas operativos que cumplen con SUS versión 3 (equi­
valentemente también se dice que son sistemas UNIX 03) son: AIX 6. 1 , HP-UX 1 1 . 3 1 , Mac OS X 1 0 . 6
y Solaris 10.
Los sistemas basados en UNIX de distribución libre no suelen pasar procesos de certificación pero
suelen soportar algún estándar. Por ejemplo, Linux y MINIX son plenamente compatibles con alguna
versión de POSIX.
1.4.
Características principales de los SOBUNIX
Las características principales de los SOBUNIX son:
•
Son sistemas de tiempo compartido, también denominados sistemas interactivos. Aunque algunos
incluso soportan también aplicaciones de tiempo real.
•
Son sistemas multiprogramados y multiusuario, con soporte para multiprocesamiento.
6
Ampliación de sistemas operativos
•
El núcleo está escrito en su mayor parte en lenguaje C, lo que facilita su portabilidad a distintas
arquitecturas.
•
El núcleo posee una estructura de tipo monolítica o simple.
•
La planificación se realiza a nivel de procesos o de hilos del núcleo usando un algoritmo de plani­
ficación basada en múltiples colas de planificación y realimentación.
•
Disponen entre otros de los siguientes mecanismos de comunicación y sincronización entre proce­
sos: tuberías, semáforos, memoria compartida y colas de mensajes.
•
No suelen implementar ninguna estrategia de tratamiento de interbloqueos. Dichas estrategias si
se quieren implementar deben hacerse a nivel de los programas de aplicación.
•
Administran la memoria principal e implementan la memoria virtual usando la técnica de demanda
de página.
•
Consideran a los archivos como una secuencia de bits y delegan en las aplicaciones la interpreta­
ción de los mismos.
•
Soportan tanto el acceso secuencial como el acceso aleatorio a los archivos .
•
E n los nombres d e archivos distinguen entre minúsculas y mayúsculas.
•
Soportan una estructura de directorios de gráfica acíclica. El directorio raíz se denota con el sím­
bolo' 1 ', que además se usa para separar los componentes del nombre de ruta de un archivo.
•
Los SOBUNIX modernos implementan una capa nodo virtual/sistema de archivos virtual para
poder soportar diferentes tipos de sistemas de archivos.
•
Cada sistema de archivos se monta en un directorio del sistema de archivos principal. Con lo que
todos los sistemas de archivos quedan integrados dentro de una única estructura de directorios.
•
Los dispositivos de E/S se integran dentro del sistema de archivos mediante el uso de archivos de
dispositivos modo bloque y archivos de dispositivos modo carácter. Lo que permite operar sobre
ellos con las mismas llamadas al sistema que se utilizan para operar sobre los archivos.
•
Permiten especificar los permisos de acceso (lectura, escritura y ejecución) a un archivo o directo­
rio de forma independiente para el usuario propietario del archivo, el grupo de usuarios propietario
y el resto de usuarios.
Conviene señalar que cada SOBUNIX puede implementar estas características de distinta forma.
Además cada SOBUNIX puede poseer características particulares no disponibles en el resto de SOBU­
NIX.
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
1.5.
7
Interfaces con los usuarios disponibles en SOBUNIX
Los SOBUNIX soportan dos posibles tipos de interfaz de usuario (ver Figura 1 . 1 ) : inteifaz de línea
de comandos implementada mediante un intérprete de comandos e inteifaz de usuario gráfica (GUI) .
Nótese que desde una interfaz gráfica también se puede disponer de una interfaz de línea de comandos.
A través de estos interfaces un usuario puede invocar a otros programas o aplicaciones. Desde el
punto de vista de su ejecución tanto los interfaces como los programas tendrán asociado cada uno al
menos un proceso monohilo o multihilo. Un proceso (o un hilo) para solicitar los servicios del núcleo del
sistema operativo tiene que realizar las llamadas al sistema correspondientes. Típicamente una llamada al
sistema se realiza mediante la invocación de una función de la librería estándar C de llamadas al sistema.
Modo
Usuario
}
Il
Usuarios
Otros programas
Librería estándar C de
llamadas al sistema
f------1
Núcleo del sistema operativo
}
Modo
Núcleo
Hardware
Figura 1.1 - Interacción de los usuarios con un S OBUNIX
En las siguientes secciones se describen los intérpretes de comandos que implementan las interfaces
de línea de comandos, la implementación de las interfaces gráficas y el tratamiento de las llamadas al
sistema.
1.5.1.
Intérpretes de comandos
Definición e intérpretes más conocidos
Un intérprete de comandos (shell) es un programa que acepta un comando 1 introducido por un usua­
rio a través del dispositivo de entrada estándar (por defecto el teclado) y ejecuta su código asociado.
El resultado de la ejecución se muestra, generalmente, en el dispositivo de salida estándar (por defecto
la pantalla) . Una vez finalizada la ejecución del comando el intérprete queda a la espera de recibir otra
orden por parte del usuario.
Cada SOBUNIX suele incluir por defecto en su distribución un determinado intérprete de comandos,
pero el usuario si así lo desea puede utilizar otro. Entre los intérpretes de comandos más conocidos se
encuentran los siguientes:
1 0tro término sinónimo de comando es orden. En este texto se utilizan ambos términos indistintamente.
8
Ampliación de sistemas operativos
•
Bourne shell (sh). Este intérprete fue escrito a finales de los setenta por Steve B ourne. Se distribuyó
inicialmente con el UNIX version 7 de AT &T.
•
e shell (c sh) . Intérprete escrito a finales de los setenta por Bill Joy. Se distribuyó inicialmente con
BSD 2.0.
•
TENEX e shell ( t c sh) . Este intérprete se basa en C shell y supone una mej ora del mismo. La pri­
mera versión de este intérprete fue escrita Ken Greer a finales de los setenta. Aunque en los ochenta
y en los noventa continuaron su desarrollo, Paul Placeway y Wilfredo S ánchez, respectivamente.
Este intérprete se distribuye, entre otros sistemas, en FreeB SD y Mac OS X.
•
Korn shell (ksh) . Este intérprete fue escrito a principios de los ochenta por David Korn. Es com­
patible con B ourne shell e incluye características de C shell. Se ha distribuido, entre otros, en los
sistemas SVR4, AIX y HP-UX.
•
Bourne-Again shell (ba sh) . Fue escrito a finales de los ochenta por Brian Fax para el proyecto
GNU. Este intérprete se distribuye, entre otros sistemas, en Linux.
•
A lmquist shell (ash). Fue escrita por Kenneth Almquist a finales de los ochenta. Se distribuyó
inicialmente con BSD 4.3.
•
Z shell ( z sh) . Fue escrito por Paul Falstad en 1 990. Se considera un intérprete muy completo ya
que incluye características de TENEX C shell, B ourne-Again shell y Korn shell, entre otros.
La mayoría de los intérpretes enumerados se han ido mejorando posteriormente y han incluido tam­
bién, por motivos de compatibilidad, las especificaciones POSIX. El usar un intérprete u otro suele ser
muchas veces una cuestión de gustos, ya que todos incluyen unas características básicas similares. Las
principales diferencias entre los intérpretes se encuentran en las características adicionales y avanzadas
que pueden soportar y cómo las implementan, como por ejemplo: la corrección automática de la sintaxis
de los comandos, el histórico de comandos, el autocomplementado de órdenes y el lenguaje soportado
para la escritura de archivos de comandos (shell scripts).
Estructura de los comandos
Un comando es una cadena de caracteres que de forma general tiene la siguiente estructura:
nombre_c omando - op_l - op_2 . . . - op_M arg_l arg_2
. . . arg_N
En dicha estructura nombre_c omando es el nombre del comando que se desea ejecutar, - op_j con
j = 1 , 2, . . . ,M son opciones que permiten configurar el comportamiento del programa, y arg_i con
i = 1 , 2, . . . ,N son los argumentos que acepta el programa.
Cada opción se escribe con el prefijo' -', aunque existe la posibilidad de agrupar todas las opciones
y usar un único prefijo:
nombre_c omando - op_l op_2 . . . op_M arg_l arg_2 . . . arg_N
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
9
Si se desea conocer el significado, las opciones y los argumentos de un determinado comando, se
puede consultar el manual de ayuda del sistema desde el propio intérprete mediante la orden:
man nombre_c omando
El manual de ayuda se divide en secciones. Cada sección se identifica mediante un entero positivo y
está asociada a un determinado tipo de recurso: comandos, llamadas al sistema, funciones de librerías,
archivos del sistema, macros, etc. A su vez cada sección se divide en páginas, donde cada página está
asociada a un determinado recurso identificado por su nombre. Conviene señalar que no todos los re­
cursos disponibles están documentados en el manual de ayuda. Para acceder a una página dentro de una
determinada sección se debe especificar el número de la sección antes del nombre del recurso:
man número s e c c i ón nombre recurso
En ocasiones un mismo nombre designa a diferentes recursos. Por defecto se muestra la primera
página que se encuentra en el manual asociada a dicho nombre. Para mostrar todas las páginas asociadas
a un mismo nombre hay que usar la opción - a :
man - a nombre
Para ir avanzando por la información de una página del manual se debe ir presionando la tecla
[ intro ] o [ e spac i o ] . Asimismo para volver hacia atrás se debe presionar la tecla [ b ] . Si se desea
salir del manual se debe presionar la tecla [ q l . Para conocer las opciones y el funcionamiento del manual
de ayuda se puede consultar su propia página del manual:
man man
Aparte de este manual de ayuda principal existen otros manuales de ayuda específicos de ciertos
programas que se pueden consultar usando el comando i n f o .
e
Ejemplo 1 . 1
Supóngase que e l directorio d e trabajo actual e s 1 expo r t / home 1 j m y que en e l mismo existen, entre
otros, el subdirectorio Documento s . Para conocer el nombre de ruta absoluta del directorio de trabaj o
actual s e puede usar e l comando pwd. Luego s i e n la línea d e comandos del intérprete s e escribe l a orden
pwd
en la pantalla aparece como respuesta
/ expo r t / home / j m
Nótese que en este caso el comando ha sido escrito sin opciones ni argumentos.
Para acceder a otro directorio, es decir, para cambiar el directorio de trabajo actual, se puede usar el
comando cd, el cual admite como argumento el nombre de ruta absoluto o relativo del directorio. Por
ejemplo, si se desea acceder al subdirectorio Document o s se puede escribir la orden:
10
Ampliación de sistemas operativos
cd / expo rt / home / j m / Documen t o s
o equivalentemente:
c d Do cumen t o s
En el primer caso s e ha utilizado e l nombre d e ruta absoluto del directorio y e n e l segundo e l nombre de
ruta relativo.
Para regresar al directorio de trabaj o anterior se puede escribir la orden
cd / expo r t / home / j m
o equivalentemente la orden
cd . .
Donde " . . " hace referencia el directorio padre del directorio actual.
Para mostrar en pantalla un listado de los nombres de los archivos y directorios contenidos en el directorio
de trabajo actual se puede usar el comando l s . Este comando admite diferentes opciones que permiten
establecer la información que se mostrará sobre los archivos y directorios listados. Por ejemplo, la orden
ls -F
introduce al final del nombre de los directorios e l símbolo 1 para diferenciarlos del resto de archivos.
1
1
Otro ejemplo, la orden
ls -i
muestra el número de nodo-i asociado al archivo o directorio correspondiente.
Las dos órdenes anteriores se pueden escribir en una sola orden de la siguiente forma:
ls
-Fi
Para conocer todas las opciones que acepta e l comando l s s e puede consultar su página del manual de
ayuda
man l s
Para borrar l a pantalla del intérprete de comandos se puede usar l a orden c l ear. S i se desea cerrar la
ventana del intérprete se puede pulsar la combinación de teclas [ c ontro l ] + [ dl o usar el comando
exi t .
•
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
11
E l número d e comandos soportados por los intérpretes de los SOBUNIX e s elevado. En l a Tabla 1 . 1
se recopilan algunos comandos básicos asociados principalmente a la gestión de archivos y directorios.
A lo largo de éste y los restantes capítulos se irán presentando más comandos para la realización de otras
tareas.
Comando
cat
cd
cp
f ind
grep
ls
more
mkdir
mv
mvdi r
pwd
rm
rmdir
Utilidad
Encadenar y mostrar el contenido de archivos
Cambiar de directorio de trabaj o
Copiar archivos o directorios
B uscar un archivo
B uscar una cadena de texto en varios archivos
Listar los archivos y directorios de un directorio
Mostrar página a página el contenido de un archivo
Crear directorio
Mover de directorio o renombrar archivos
Cambiar de ubicación u n directorio
Mostrar el nombre de ruta del directorio de trabaj o actual
Borrar archivos o directorios
B orrar directorio
Tabla 1.1 - Algunos comandos básicos asociados a la gestión de archivos
y
directorios en SOBUNIX
Con el fin de reducir la longitud de la cadena de caracteres asociada a una orden, la mayoría de los
intérpretes de comandos de SOBUNIX soportan el uso de comodines (wild cards) en los argumentos de
las órdenes. Un comodín es un carácter especial que hace que el intérprete trate el argumento de una
determinada forma. Entre los comodines más frecuentemente soportados se encuentran los siguientes :
•
e
' *' . Este comodín sustituye a cualquier cadena de caracteres.
•
' ? ' . Este comodín sustituye a cualquier carácter.
•
" [ c l c 2 . . . eN ] " . Este comodín significa que se debe sustituir por uno solo de los caracteres c j
j = 1 , . . . , N incluidos dentro de los corchetes.
Ejemplo 1.2
Supóngase que en el directorio de trabajo actual existen los archivos prueba . e, t raba j o l . txt y
t raba j o 2 . txt . Supóngase además que se desea copiar en el subdirectorio Document o s los archivos
con extensión txt. Para realizar esta acción se podría usar la siguiente orden:
.
cp t raba j o l . txt t rabaj o 2 . txt Documen t o s
También s e podría reducir la longitud d e l a orden haciendo u s o del comodín' *' :
12
Ampliación de sistemas
operativos
cp * . txt Document o s
En este caso e l comodín 1 * 1 sustituye a todas las cadenas de caracteres posibles, por lo que el intérprete
busca en el directorio de trabajo todos los archivos cuyo nombre terminan en 11 • txt 11 •
Asimismo si se sabe que el subdirectorio Document o s es el único que empieza por el carácter 1 D 1 enton­
ces la orden se podría haber escrito aún de forma más reducida:
cp * . txt D *
Usando e l mismo ejemplo s e puede ilustrar el uso de los comodines 1 ? 1 y 11 [ l 11 :
cp trabaj o ? . txt Documen t o s
cp traba j o [ 1 2 ] . txt Documentos
En la primera orden el comodín 1 ? 1 permite sustituir a los caracteres 1 1 1 y 1 2 1 • En la segunda orden se
fuerza a que se sustituya por los caracteres 1 1 1 y 1 2 1 •
•
En los SOBUNIX cuando se ejecuta un programa se crea un proceso para el cual se abren por defecto
tres archivos (ver sección 5 . 2 . 1 ) : el archivo de entrada estándar, el archivo de salida estándar y el archivo
de salida de errores estándar. El archivo de entrada estándar está asociado por defecto al teclado (ver
sección 5 .5), mientras que los archivos de salida estándar y salida de errores estándar están asociados por
defecto a la pantalla.
Los intérpretes de comandos en los SOBUNIX soportan el redireccionamiento de la E/S, es decir,
permite cambiar los archivos de entrada y salida estándar de los comandos que ejecutan. Para ello se
pueden usar los siguientes operadores :
•
Operador 1 < 1 • Permite redireccionar la entrada estándar hacia otro archivo.
•
Operador 1 > 1 • Permite redireccionar la salida estándar hacia otro archivo. La salida se empieza a
almacenar desde el comienzo del archivo, con lo que se sobreescribe su contenido.
•
Operador 1 > > 1 • Permite redireccionar la salida estándar hacia otro archivo. La salida se empieza a
almacenar a partir del final del archivo, con lo que no se eliminan los datos que ya existieran en el
mismo.
•
Operador 1 2 > 1 • Permite redireccionar la salida de errores estándar hacia otro archivo. La salida se
empieza a almacenar desde el comienzo del archivo, con lo que se sobreescribe su contenido.
•
Operador 1 2 > > 1 • Permite redireccionar la salida de errores estándar hacia otro archivo. La salida
se empieza a almacenar a partir del final del archivo, con lo que no se eliminan los datos que ya
existieran en el mismo.
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
13
También es posible encadenar órdenes de tal forma que la salida de una orden se convierta en la
entrada de otra orden. Para ello hay que utilizar una tubería (ver sección 3.5 .2) la cual se representa
mediante el carácter ' 1 '.
e
Ejemplo 1.3
Supóngase que se escribe la siguiente orden:
s o r t < da t o s . da t > o rdenado s . txt
Esta orden invoca al comando s o r t que ordena por orden alfabético las líneas del archivo da t o s . da t
pasado como entrada. L a salida del comando s e guarda e n e l archivo o rdenado s . t x t .
Por s u parte l a orden
l s -F 1 sort
utiliza una tubería para que la salida d e la orden l s - F s e convierta e n la entrada d e la orden s o r t cuya
salida se mostrará en la salida estándar, en este caso la pantalla.
•
Otra característica de los intérpretes de comandos de los SOBUNIX que resulta muy útil para aho­
rrarse escribir ordenes largas o complicadas de recordar que se usen frecuentemente, es la posibilidad de
asignar un nombre o alias a una determinada orden o cadena de órdenes. De esta forma, las invocaciones
de dicha orden se realizan usando su alias correspondiente.
Para asignar un alias a una orden o cadena de órdenes se usa el comando a l i a s . También es posible
deshacer la asignación de un alias, para ello se debe usar el comando una l i a s . Es importante tener
en cuenta que por defecto la asignación de un alias tiene un carácter temporal, es decir, desaparece al
cerrarse el intérprete de comandos. Para hacer la asignación de un alias persistente, es decir, para que se
pueda utilizar un alias sin ser definido previamente cada vez que se abra el intérprete, se debe incluir su
asignación en los archivos de configuración del intérprete.
e
Ejemplo 1 .4
Supóngase que un usuario tiene que escribir con frecuencia la siguiente secuencia de órdenes:
cp * . txt Do cumen t o s ; cd Document o s ; l s - F
Para ahorrarse s u escritura puede asignarles u n alias, al que s e va a llamar por ejemplo c op i ar_txt, de
la siguiente forma:
a l i as copi ar_txt
=
' cp * . txt Document o s ; cd Document o s ; l s - F '
Si se desea quitar este alias simplemente habría que usar la orden:
una l i a s c op i ar_txt
•
14
Ampliación de sistemas operativos
Funcionamiento
Un intérprete de comandos de SOBUNIX es un archivo ejecutable que reside en un cierto directorio
del sistema de archivos, típicamente en el directorio / b i n . Cuando se invoca a un intérprete se crea
un proceso asociado a su ejecución. Este proceso en primer lugar ejecuta las órdenes establecidas en
los diferentes archivos de configuración del intérprete (ver la página del manual de ayuda del intérprete
correspondiente) con el objetivo de configurar las variables del intérprete de comandos. A continuación
muestra el apuntador (prompt) en pantalla que es un carácter o cadena de caracteres cuya aparición en
la pantalla sirve para indicar al usuario que ya puede escribir una orden.
El funcionamiento del intérprete depende del tipo de comando que se escriba. En general se distin­
guen dos tipos de comandos: externos e internos. Señalar que el comando type permite conocer el tipo
(interno o externo) de un comando.
Un comando externo es aquél cuyo código de ejecución se encuentra en un archivo ejecutable que
debe ser buscado por el intérprete. En general un comando externo es cualquier archivo ejecutable, como
por ejemplo: los programas de utilidad y aplicaciones suministrados en la distribución del S OBUNIX y
los programas de aplicación descargados o creados por los usuarios. También entran en esta categoría los
archivos de comandos (shell scripts) .
Un comando interno (built-in command) e s aquél cuyo código d e ejecución forma parte del código
del intérprete de comandos . En consecuencia no requiere ser buscado en un archivo ejecutable por el
intérprete, puesto que ya se encuentra cargado en su espacio de direcciones. Ejemplos de comandos
internos son cd, pwd y a l i a s .
Cuando s e teclea u n comando el intérprete lee el nombre d e l a orden y comprueba s i e s una orden
interna. En dicho caso analiza la sintaxis de la orden y si es correcta la ejecuta, en caso contrario muestra
un mensaje de error en la salida estándar.
Si no es un comando interno, entonces el intérprete busca el archivo ejecutable asociado al comando
externo. En el caso de que no lo localice mostrará un mensaje de error en la salida estándar. Si lo en­
cuentra crea un nuevo proceso asociado a la ejecución del archivo ejecutable y le pasa los indicadores y
argumentos del comando como parámetros.
En los SOBUNIX se suele usar el término trabajo (job) para designar al proceso o grupo de procesos
que se crean asociados a la ejecución de un comando introducido por el usuario en un intérprete de
comandos.
Un trabajo se puede ejecutar en primer plano (foreground) o en segundo plano (background). Si un
trabaj o se ejecuta en primer plano entonces puede interactuar con el usuario esperando por la recepción
de entradas y mostrando salidas. Por el contrario un trabaj o ejecutándose en segundo plano no puede
interactuar con el usuario.
En un intérprete de comandos, en un determinado instante de tiempo, solamente puede existir un
trabaj o ejecutándose en primer plano. Por el contrario pueden existir múltiples trabajos ejecutándose en
segundo plano.
Si un usuario escribe una orden en el intérprete de comandos, el trabajo asociado a dicha orden se
ejecuta por defecto en ptimer plano. Si se desea que el trabajo se ejecute en segundo plano la orden se
debe escribir seguida de un espacio y del carácter'&' , es decir:
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
15
c omando &
Un trabajo puede ser pasado de segundo plano a primer plano usando el comando f g . Asimismo
el trabajo en primer plano puede ser pasado a segundo plano usando el comando bg. Nótese que para
poder realizar este cambio el trabajo en primer plano debe ser previamente parado pulsando las teclas
[ c ontr o l ] + [ z ] .
Para obtener información sobre los trabajos que se están ejecutando en un intérprete se puede usar el
comando j obs . Si se desea terminar el trabajo que se está ejecutando en primer plano se deben pulsar
las teclas [ c ontro l ] + [ e ] .
Variables y entorno
Cuando se inicia la ejecución de un intérprete de comandos se crean y se inicializan un conjunto de
variables denominadas variables del intérprete de comandos a partir de los archivos de configuración
del intérprete. Estas variables son locales al proceso asociado a la ejecución del intérprete y pueden ser
utilizadas por los comandos internos. El comando s e t permite visualizar un listado de todas las variables
del intérprete. En la página del manual de ayuda asociada al intérprete se describe el significado de cada
una de estas variables.
Un usuario puede cambiar el valor de algunas de las variables del intérprete. Otras variables, sin
embargo, no pueden ser modificadas. Además un usuario también puede definir nuevas variables.
Si se desea que los cambios que se realicen en las variables o que las nuevas variables definidas sean
persistentes se deben definir en los archivos de configuración del intérprete.
e
Ejemplo 1.5
Supóngase que se ha iniciado una sesión de trabaj o con un determinado intérprete de comandos. Si se
teclea el comando:
set
s e mostrará en l a salida estándar e l listado de todas las variables del intérprete.
Si se desea conocer el valor de una determinada variable se puede usar el comando echo. Por ejemplo,
para conocer el valor de la variable PATH, la cual contiene los nombres de ruta de los directorios donde
el intérprete busca los comandos externos, se debe escribir la siguiente orden:
echo $ PATH
Nótese que el valor de una variable se referencia escribiendo ' $ ' delante del nombre de la variable.
Si se desea añadir un directorio a la variable PATH, por ejemplo el directorio de trabaj o actual, se puede
usar la siguiente orden:
PATH= $ PATH : .
16
Ampliación de sistemas operativos
----��---------------------------------------------------------
Recuérdese que el nombre de ruta 1 1 hace referencia al directorio de trabajo actual.
•
Se puede comprobar que la variable ha sido cambiada escribiendo de nuevo la orden:
echo $ PATH
También se puede definir una nueva variable MI_VARIABLE y asignarle un cierto valor, de la siguiente
forma:
MI_VARIABLE= l O
Si se escribe de nuevo la orden
set
s e puede comprobar que la nueva variable h a sido incorporada al listado de variables del intérprete y que
la variable PATH contiene los cambios realizados.
Señalar que si se cierra el intérprete y se vuelve a iniciar se puede comprobar usando la orden set que
los cambios realizados no son persistentes .
•
Como se describirá en la sección 2.3 . 1 , cuando se invoca a otro programa desde un proceso ya creado
se le puede pasar como argumentos una serie de cadenas de caracteres asociadas a variables inicializadas
a un cierto valor. A dicho conjunto de variables se le denomina entorno del proceso, y a cada variable
del conjunto se le denomina variable de entorno. Las variables de entorno pueden ser leídas o escritas
durante la ejecución del proceso.
Un intérprete de comandos, como cualquier otro programa, tiene asociado un proceso a su ejecución
y en consecuencia dispone de un entorno de ejecución. Para conocer las variables de entorno de un
intérprete se puede usar el comando env.
Algunas variables del intérprete proceden del entorno del proceso asociado al intérprete. Asimismo
también es posible exportar una variable del intérprete a su entorno; para ello se debe usar el comando
exp o r t .
Si se desea eliminar una variable del intérprete se debe usar el comando uns e t . Este comando
también borra a la variable del entorno, si había sido exportada allí.
e
Ejemplo 1.6
Si se teclea el comando:
env 1 s o r t
s e mostrará e n l a salida estándar e l listado d e todas las variables d e entorno del proceso asociado al
intérprete ordenadas alfabéticamente.
Para exportar al entorno las variables PATH y MI_VARIABLE del ejemplo anterior se debe escribir la
siguiente orden:
Sistemas Operativos Basados en UNIX (SOBUNIX): introducción general
17
export PATH MI_VARIABLE
Si se teclea de nuevo el comando env 1 s o r t se puede comprobar que dichas variables han sido in­
cluidas en el entorno.
Si se desea eliminar la variable MI_VARIABLE se debe usar la orden:
uns e t MI_VARIABLE
Usando el comando s e t se puede comprobar que MI_VARIABLE ha sido eliminada. Además usando el
comando env se puede comprobar que también ha desaparecido del entorno.
•
Cuando se ejecuta un comando externo en un intérprete, el proceso asociado al intérprete crea un
proceso hijo asociado al comando que recibe como entorno una copia del entorno del intérprete. Los
cambios que realice el nuevo proceso en su copia del entorno no afectan al entorno del proceso padre ya
que en los SOBUNIX los procesos poseen espacios de direcciones independientes.
Obviamente si se desea que el proceso asociado al comando externo pueda hacer uso de alguna
variable del intérprete ésta debe ser exportada al entorno del intérprete antes de ejecutar el comando.
Recuérdese que las variables del intérprete son locales al proceso asociado a la ejecución del intérprete.
Shell scripts
Usualmente los intérpretes de comandos, aparte de ser capaces de ejecutar comandos internos y
externos, también disponen de un completo lenguaje de programación con sentencias del tipo i f , f o r ,
whi l e , etc. Además también soportan la definición de funciones. Para conocer los detalles de la sintaxis
del lenguaje de programación de un intérprete se debe consultar su página del manual de ayuda.
Un shell script es un archivo ASCII que contiene comandos y sentencias del lenguaje de programa­
ción del intérprete. Para crear un shell script se puede usar cualquier editor de texto. Una vez escrito el
código del shell script se debe guardar en un archivo, al que hay que proporcionarle permiso de ejecución
(ver sección 1 .7.2) . Además hay que incluir (si no lo estaba ya) dentro de la variable PATH el nombre de
ruta del directorio donde reside el shell script.
La ejecución de un shell script se puede realizar de dos formas. La primera forma consiste en pasar
el nombre de ruta del shell script como argumento de entrada del comando s ourc e :
s ource s he l l_s c r i p t
Dicho comando carga el shell script en el espacio de direcciones del intérprete y lo ejecuta. Nótese
que en este caso la ejecución del shell script es similar a la de un comando interno, por lo que no hay que
crear un nuevo proceso.
La segunda forma de ejecución de un shell script consiste en invocarlo como un comando externo:
s he l l_s c r i p t
18
Ampliación de sistemas operativos
En este caso el intérprete invoca a otro intérprete, a veces denominado subintérprete (subshell), para
que ejecute el shell script. Nótese que el subintérprete recibe una copia del entorno del intérprete, por lo
que las variables del intérprete que no hubieran sido exportadas a su entorno no serán heredadas por el
subintérprete.
También se puede invocar directamente el subintérprete y pasarle como argumento de entrada el
nombre de ruta del shell script que se desea ejecutar. Por ejemplo si el shell script se desea ejecutar en
un subintérprete bash entonces la orden sería:
bash she l l_s c r i p t
L a utilidad d e los shell scripts e s evidente. Por u n lado, s i u n usuario ejecuta frecuentemente la
misma secuencia de comandos puede evitarse su escritura creando un shell script que contenga dicha
secuencia. De esta forma solo tendría que escribir el nombre del shell script. Por otra parte, gracias a que
un intérprete soporta un lenguaje de programación, se pueden escribir shell scripts para la realización de
todo tipo de tareas.
e
Ejemplo 1.7
En la Figura 1 .2 se muestra el código de un shell script sencillo que únicamente contiene comentarios y
algunos comandos descritos en las secciones anteriores.
# ! / b i n / ba s h
# Mo s t rar ordenadame n t e a l f abé t i c amen te y p á g i n a a p á g i n a l a s var i ab l e s
# de l e n t o rno de l i n t érpr e t e
env
1
sort
1
mo r e
# C r e a r u n a nueva var i ab l e M I V
MIV= l O
#Ver e l va l o r de l a var i ab l e
echo $MIV
# Expo r t a r l a a l entorno
exp o r t MIV
Figura 1.2 - Ejemplo de shell script
Los comentarios se introducen en el código del shell script precedidos del símbolo' # ' . El primer comen­
tario indica al intérprete el nombre de ruta del subintérprete que debe invocar para ejecutar este shell
script. En este caso es un intérprete bash. Nótese que si se omite esta orden el subintérprete que se
invoca es del mismo tipo que el intérprete. Este comentario es importante ya que un shell script escrito
con el lenguaje de programación de un cierto tipo de intérprete puede que produzca errores si se ejecuta
con otro tipo de intérprete.
Supóngase que el shell script de la Figura 1 .2 se encuentra almacenado en el archivo e j _s c r i p t . Para
poder ejecutarlo se debe habilitar el permiso de ejecución del archivo (ver sección 1 .7 . 2), usando la
siguiente orden:
chmod 0 7 4 4 e j ernp l o_s c r i p t
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
19
Además hay que asegurarse que el directorio donde se encuentra el shell script se encuentra añadido en
la variable PATH.
Si se cumplen estas dos condiciones, el shell script se puede invocar, por ejemplo, mediante su nombre
de ruta:
e j emp l o_s c r i p t
En este caso se ha supuesto que el shell script se encuentra en el directorio de trabaj o actual, por ello se
ha podido invocar mediante su nombre de ruta relativa.
•
1.5.2.
Interfaces de usuario gráficas
El sistema X Window
Las interfaces de usuario gráficas (GUis) de la mayoría de SOBUNIX se basan en el sistema X
Window, también conocido abreviadamente como X. El sistema X Window fue desarrollado a mediados
de los años ochenta por el MIT. La primera versión, denomina X 1 apareció en 1 984. En el momento de
escribir este texto la última versión de X Window es la X 1 1 R7.7 de 20 1 2 . Nótese que la versión 1 1 (X 1 1 )
aparecida en 1 987 h a sido sobre l a que s e han ido haciendo las sucesivas modificaciones.
El sistema X Window es un sistema de ventanas (windowing system), es decir, la capa de software
más interna de una GUI que se encarga de enviar y recibir datos del hardware (pantalla, teclado y ra­
tón). Además contiene las funciones primitivas básicas para la representación gráfica de líneas y fuentes
asociadas a las ventanas y al puntero del ratón.
El sistema X Window se caracteriza por su alta portabilidad ya que se ejecuta fuera del espacio de
direcciones del núcleo. Está diseñado siguiendo una arquitectura del tipo servidor-cliente (ver Figura
1 . 3). El servidor X es la parte del software del sistema X Window que se ejecuta en la máquina del
usuario y se encarga de leer datos procedentes del teclado y del ratón, así como de escribir mapas de bits
en la pantalla. Además se comunica con los clientes X.
Un cliente X es un determinado programa (gestor de ventanas, navegador web, gestor de correo
electrónico, emulador de terminal, etc) que invoca (bien directamente o a través de librerías gráficas)
funciones de la librería Xl ib para comunicarse con el servidor X. Un cliente X puede estar ejecutándose
en la misma máquina que el servidor X o en una máquina remota. En este último caso la comunicación
se realiza a través de la red. En una misma máquina pueden existir varios clientes X.
Cada cliente X envía al servidor X la información que debe mostrar en la pantalla. Además recibe del
servidor X información procedente del teclado y el ratón. Nótese que el servidor X hace un seguimiento
del puntero del ratón y la posición de las ventanas para determinar qué ventana es la que se encuentra
activa y saber a qué cliente X debe enviar la información procedente del teclado y el ratón. Además el
servidor X almacena en unas estructuras de datos denominadas recursos información sobre diferentes
objetos: ventanas, fuentes, paletas de colores, cursor, etc. Cada recurso tiene un identificador numérico
entero que lo identifica de forma única.
20
Ampliación de sistemas operativos
Protocolo X
Cliente X
Figura 1.3
-
Cliente X
Arquitectura cliente-servidor del sistema X Window
El intercambio de información entre un servidor X y un cliente X sigue el protocolo de comunicación
denominado protocolo X (Xprotocol). El cliente X solicita la conexión con el servidor X enviándole un
primer mensaje. El servidor X responde con otro mensaje para aceptar o rechazar la conexión, o para
obtener una comprobación de la identidad del cliente X. El mensaje de aceptación de la conexión por
parte del servidor X contiene información que el cliente X utilizará en las siguientes comunicaciones con
el servidor X. Una vez que la conexión se ha establecido, el servidor X y el cliente X pueden intercambiar
cuatro tipos de mensajes:
•
Mensajes de petición. Son enviados por el cliente X para pedir información al servidor X o para
solicitarle que dibuje algo en la pantalla.
•
Mensajes de respuesta. Son enviados por el servidor X en respuesta a algunos mensajes de petición
del cliente X.
•
Mensajes de aparición de eventos. Son enviados por el servidor X a un cliente X cuando se produce
algún evento asociada a la ventana asociada al cliente X: entrada de ratón o teclado, cambio de
posición o de tamaño de la ventana, etc.
•
Mensajes de error.
Por ejemplo, si un cliente X desea crear una ventana, enviará un mensaje de petición al servidor X.
É ste creará la ventana y su recurso asociado, y le asignará un identificador que enviará en el mensaje de
respuesta al cliente X. De esta forma el cliente X utilizará este identificador para referirse a la ventana
en posteriores mensajes de petición.
Los mensajes son cadenas de bytes que deben ser interpretados. Por ejemplo los mensaj es de apari­
ción de eventos tienen una longitud de 32 bytes. El byte más significativo, es decir, el situado más a la
izquierda, especifica el tipo de evento y los 31 bytes restantes especifican información adicional asociada
al evento. Obviamente desde el punto de vista del programador de aplicaciones trabajar directamente
con cadenas de bytes es muy tedioso. Afortunadamente el sistema X Window incluye una librería de
primitivas básicas de manej o del protocolo X denominada X l ib.
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
21
Widgets toolkits
Aparte del sistema de ventanas otra parte fundamental de una GUI son las librerías denominadas
widgets toolkits, que proporcionan al programador de aplicaciones funciones para crear y manipular
desde un nivel de abstracción superior los objetos gráficos típicos de una interfaz gráfica (ventanas,
menús, botones, barras de desplazamientos, etc) a los cuales se les denomina de forma general widgets.
En las interfaces gráficas basadas en el sistema X Window las widget toolkits se ejecutan por encima
de la librería Xl ib. Es decir, un programa de aplicación (cliente X) invoca a una función de una widgets
toolkit que a su vez invoca a una función de la librería Xl ib.
Entre las librerías widgets toolkits más conocidas que se ejecutan sobre el sistema X Window se
encuentran Mo t i f , Q t y GTK + .
El sistema X Window también incluye una librería widgets toolkit básica denominada X Too/kit
Intrinsics (o más abreviadamente Xt o X toolkit). Motif se ejecuta sobre Xt. En la Figura 1 .4 se muestran
las librerías gráficas más comunes de un cliente X.
Programa de aplicación
1
1
1
Qt
GTK+
1
1
Motif
1
Widgets
toolkits
Xt
1
Xlib
¡ Protocolo X
Figura 1.4 - Librerías gráficas más comunes de un cliente X
Entornos de escritorio
Cada aplicación define en su ventana asociada la interfaz gráfica específica que le desea ofrecer al
usuario. Sin embargo, la apariencia de los marcos de las ventanas y la interacción del usuario con los
mismos son controladas por una capa de software que se denomina entorno de escritorio. Algunos de los
entornos de escritorio más usados en SOBUNIX son: CDE que usa la librería Motif, KDE que usa Qt y
GNOME que usa GTK+.
Un entorno de escritorio también se encarga de controlar el fondo, la barra de tareas y los iconos del
escritorio. Consta, entre otros, de los siguientes componentes:
22
Ampliación de sistemas operativos
•
Gestor de ventanas (window manager). Es un cliente X que se encarga, entre otras tareas, de
posicionar las ventanas, colocar los marcos alrededor de las ventanas y atender la interacción del
usuario con los marcos de las ventanas, con los iconos y con la barra de tareas. También se encarga
de tratar los clics del ratón y las pulsaciones de teclas fuera de una ventana determinada, es decir, no
asociadas a un cliente X determinado. Por otra parte, ciertas peticiones de los clientes X al servidor
X son redireccionadas al gestor de ventanas, como por ejemplo, la creación o la eliminación de
ventanas.
•
Gestor de archivos (file manager), también denominado explorador de archivos (file browser).
Es un cliente X que suministra al usuario una interfaz gráfica amigable para la realización de
operaciones básicas con archivos y directorios: creación, eliminación, copia, visualización, etc.
1 .5.3.
Llamadas al sistema
Los procesos de los usuarios, tanto los que se crean para implementar las interfaces con el usuario
como los que se crean al interactuar el usuario con las interfaces, tienen que realizar llamadas al sistema
para solicitar los servicios del sistema operativo. De esta forma, las llamadas al sistema disponibles en un
sistema operativo establecen la interfaz de programación entre los procesos de los usuarios y el núcleo
del sistema operativo. Cada llamada al sistema tiene asociado un número entero positivo para poder ser
identificada por el núcleo.
En los SOBUNIX un proceso para hacer una llamada al sistema invoca a una función de envoltura o
2
redireccionamiento (wrapper function) de la librería e estándar, también denominada abreviadamente
l ib e . Cada llamada al sistema tiene asociada al menos una función de envoltura. Varias funciones de
envoltura pueden estar asociadas a la misma llamada al sistema, la diferencia entre ellas radica en los
argumentos de entrada que reciben y que pasan a la llamada. Por ejemplo, las funciones de envoltura
execv y execve invocan ambas a la llamada exe c . La diferencia entre ambas funciones es que execve
admite un mayor número de argumentos de entrada que execv.
La función de envoltura, cuando se ejecuta, copia el identificador de la llamada al sistema a la que
está asociada en algún registro o en la pila de usuario. A continuación ejecuta una trampa (trap) que
provoca la conmutación hardware de modo usuario a modo supervisor y transfiere el control al núcleo.
É ste invoca al manejador de llamadas al sistema, el cual se implementa mediante una rutina denominada
sys c a l l ( ) en la mayoría de SOBUNIX.
El manejador de llamadas al sistema, sys c a l l ( ) , realiza, entre otras, las siguientes acciones :
l . Copia los argumentos de la llamada al sistema en el área de usuario del proceso (ver sección
2.2.2) y guarda el contexto hardware del proceso, es decir, los valores actuales de los registros del
procesador, en la pila del núcleo asociada al proceso.
2. Utiliza el identificador de la llamada para acceder a la entrada adecuada de la tabla de llamadas al
sistema del núcleo. Cada entrada de esta tabla contiene, entre otros datos, la dirección de comienzo
2En programación una función
función.
de envoltura o redireccionamiento
es aquella cuya principal finalidad es invocar a otra
S istemas Operativos Basados en UNIX (SOBUNIX): introducción general
23
de la rutina del núcleo específica que hay que ejecutar para atender una determinada llamada al
sistema.
3. Cuando termina la ejecución de la rutina del núcleo que atiende a la llamada al sistema, entonces
sys c a l l ( ) copia los valores de retomo (o los códigos de error si se produjo algún error) en los
registros oportunos. A continuación restaura el contexto hardware del proceso y conmuta a modo
usuario devolviendo el control a la función de envoltura.
Cuando se devuelve el control a la función de envoltura, ya en modo usuario, ésta comprueba leyendo
los valores almacenados en los registros oportunos si la llamada al sistema se ejecutó correctamente o
si se produjeron errores. Si la llamada se ejecutó con éxito la función de envoltura retoma y se continúa
con la ejecución de la siguiente instrucción del proceso. Si se produjeron errores la función de envoltura,
antes de retomar, invoca a una función de notificación de errores, la cual almacena un identificador
numérico del error producido, en la forma de constante simbólica, en una variable global denominada
generalmente errno 3 y establece que el valor de retomo de la función de envoltura sea el valor - l . Por
ejemplo si una llamada al sistema es interrumpida por la recepción de una señal entonces en la variable
e rrno se almacena la constante E INTR.
Cada sistema operativo establece las llamadas al sistema que soporta, las cuales se pueden agrupar en
diferentes categorías: control de procesos, comunicación de procesos, gestión de archivos y directorios,
gestión de dispositivos, etc. Afortunadamente para los programadores de aplicaciones si un programa
utilizada las funciones de envoltura definidas en las especificaciones POSIX, se podrá ejecutar sin pro­
blemas en todos los sistemas operativos que cumplan con estas especificaciones.
1 .6.
Introducción a la gestión de archivos en SOBUNIX
La gestión de archivos en los SOBUNIX será descrita en detalle en el capítulo 5, en esta sección
únicamente se introducen aquellos conceptos que requieren ser conocidos antes de llegar a este capítulo.
En los SOBUNIX la información contenida en un archivo se estructura como una secuencia de bytes.
El núcleo no interpreta dicha información, simplemente se limita a operar con ella a nivel de byte. La
interpretación de los bytes recae sobre los procesos que solicitan al sistema operativo las operaciones
sobre los archivos mediante la realización de las llamadas al sistema oportunas. Por ejemplo, para leer
y escribir el contenido de un archivo se utilizan las llamadas al sistema read y wr i t e , respectivamente
(ver sección 5.2. 1 ) .
E l nombre de u n archivo e s una cadena d e caracteres ASCII. En los SOBUNIX s e pueden usar todos
los caracteres excepto los caracteres 1 y \ O Además se distingue entre caracteres en mayúsculas y en
minúsculas. La longitud máxima de un nombre depende del tipo de sistema de archivos al que pertenezca
el archivo. Los SOBUNIX modernos soportan el uso de diferentes tipos de sistemas de archivos.
A diferencia de otros sistemas operativos, en los SOBUNIX los nombres de archivos no tienen por
qué tener una extensión ya que el núcleo no las interpreta. De nuevo, el uso de extensiones en el nombre
1
3En el fichero de cabecera
errno.
errno .
1
1
1•
h puede encontrarse una descripción de los posibles valores que puede tomar la variable
Ampliación de sistemas operativos
24
de los archivos y su interpretación recae en los procesos. En este sentido, conviene señalar que un nombre
puede tener más de una extensión. Teniendo en cuenta lo anterior los nombres prueba, prueba . e y
prueba . e . g z serían nombres de archivos válidos en SOBUNIX.
Para que un proceso pueda operar sobre un archivo, éste primero tiene que ser abierto mediante la
invocación de la llamada al sistema open. La rutina del núcleo que trata esta llamada al sistema crea en
la memoria principal una estructura de datos denominada objeto de archivo abierto. Además asigna a
dicha estructura un número entero positivo pequeño denominado descriptor de archivo para identificarla.
Nótese que si un proceso abre el mismo archivo dos veces, o si dos procesos abren el mismo archivo, el
núcleo creará una estructura de objeto abierto y un descriptor de archivo en cada invocación de la llamada
al sistema open. Luego se tendrían dos objetos de archivo abierto, cada uno con su correspondiente
descriptor de archivo.
La llamada al sistema open devuelve el descriptor del archivo abierto al proceso que invocó la
llamada. Para poder operar sobre un archivo abierto el proceso debe pasar el descriptor del archivo como
argumento de las posteriores llamadas al sistema asociadas a las operaciones que desee realizar sobre el
archivo.
Todos los descriptores de archivos asociados a un mismo proceso se indexan en una tabla denomina
tabla de descriptores de archivos. Esta tabla es local a cada proceso, es decir, cada proceso tiene su
propia tabla de descriptores de archivos. Luego un mismo descriptor de archivo puede referirse en dos
procesos distintos a archivos diferentes.
Cada entrada de una tabla de descriptores de archivos contiene un puntero a la estructura de objeto
de archivo abierto a la que está asociado el descriptor. También contiene una serie de indicadores que
especifican el tratamiento que debe dar al descriptor ante la aparición de determinados eventos.
Por su parte, un objeto de archivo abierto contiene, entre otros, los siguientes datos:
•
Puntero de lectura/ escritura. Indica el byte del archivo donde se realizará la próxima operación
de lectura o de escritura. Se especifica como un desplazamiento desde el origen del archivo. En
SOBUNIX el acceso al contenido de un archivo se realiza por defecto de forma secuencial, aunque
es fácil implementar el acceso directo o aleatorio a un determinado byte del archivo usando la
llamada al sistema l s e e k (ver sección 5.2. 1 ) .
•
Puntero a l nodo virtual del archivo. L a mayoría d e S OBUNIX son capaces de soportar y mani­
pular diferentes tipos de sistemas de archivos. Para implementar esta propiedad el subsistema de
archivos del núcleo dispone de una capa de software denominada capa nodo virtual/sistema de
archivo virtual que se encarga de encaminar cada operación sobre un archivo perteneciente a un
determinado tipo de sistema de archivos hacia la función dependiente del sistema de archivos que
implementa dicha operación. Un nodo virtual, o más abreviadamente nodo-v (ver sección 5 . 3 . 1 ), es
una estructura de datos que el núcleo crea en memoria principal para cada archivo distinto abier­
to. En un nodo-v se almacena información que el núcleo necesita conocer para operar sobre un
archivo.
Los S OBUNIX implementan una estructura de directorios de gráfica acíclica. El directorio raíz
es el directorio 1 '. Este carácter también se utiliza para separar cada componente del nombre de ruta
'
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
25
absoluta o relativa de un archivo. Dentro del directorio raíz suelen existir, entre otros, los directorios que
se muestran en la Tabla 1 .2.
Directorio
/bin
/boot
/ dev
/ etc
/ home
/ l ib
/mnt
/ ro o t
/ sbin
/ tmp
/usr
Contenido
Archivos binarios asociados a comandos y programas esenciales del sistema
Archivos necesarios para el arranque del sistema
Archivos de dispositivos
Diferentes archivos de configuración del sistema
Cuentas de los usuarios ordinarios
Diferentes librerías compartidas
Montaje de dispositivos temporales
Directorio borne del superusuario
Archivos binarios fundamentales del sistema
Archivos temporales
Aplicaciones d e usuario
Tabla 1.2 - Algunos directorios existentes en el sistema de archivos de los SOBUNIX
1 .7.
Seguridad y protección en SOBUNIX
Los SOBUNIX son sistemas multiusuario, es decir, pueden atender simultáneamente a múltiples
usuarios. Además también tienen la capacidad de gestionar grupos de usuarios. En las siguientes sec­
ciones se describen los elementos que de forma general se usan en los SOBUNIX para implementar la
seguridad y la protección de los datos de los usuarios : los identificadores reales, la máscara de modo de
un archivo y los identificadores efectivos. También se describe cómo se implementa la seguridad y la
protección haciendo uso de estos elementos.
Señalar que cada SOBUNIX puede implementar mecanismos de seguridad adicionales a los meca­
nismos generales que se describen en las siguientes secciones.
1.7. 1 .
Identificadores reales
Cada usuario tiene asignado un identificador de usuario (User IDentifier, UID) que es un número
entero positivo que lo identifica de manera unívoca. El identificador de usuario UID=O está reservado
para designar a un usuario privilegiado conocido como superusuario o root, el cual dispone de privilegios
que no tienen el resto de usuarios, como por ejemplo: leer, escribir o ejecutar cualquier archivo.
Por otra parte, en los SOBUNIX cada usuario pertenece a uno o varios grupos de usuarios. Cada
grupo de usuarios tiene asignado un identificador de grupo (Group IDentifier, GID) que es otro número
entero positivo.
En los SOBUNIX a cada usuario reconocido en el sistema se le asigna un UID y un GID cuando
se le crea una cuenta de trabaj o en el sistema. A este par de valores se les denomina de forma general
26
Ampliación de sistemas operativos
como identificadores reales. En el caso del superusuario sus identificadores reales son UID=O y GID=O.
Nótese que aunque un usuario solo tiene asociado un GID puede pertenecer a varios grupos.
El núcleo mantiene los identificadores reales de los usuarios en un archivo cuya nombre de ruta
absoluta normalmente es / e t c /pas swd. Además en este archivo también se mantiene la siguiente in­
formación sobre cada usuario: nombre de usuario, contraseña de acceso encriptada, nombre completo
del usuario, nombre de ruta absoluta del directorio de trabaj o inicial y el nombre de ruta absoluta del
intérprete de comandos que utiliza por defecto.
El archivo pas swd puede ser leído por todos los usuarios, sin embargo sólo puede ser modificado
por el superusuario. Para crear un nuevo usuario, el superusuario puede usar, por ejemplo, el coman­
do u s eradd o el comando addu s e r . Para eliminar un usuario puede usar el comando u s erde l o el
comando de l u s e r . Para modificar los datos de un usuario puede usar el comando u s e rmod.
También, es posible impedir el acceso a un usuario sin borrar sus datos. Para ello el superusuario
solo tiene que escribir, en la línea asociada al usuario en el archivo pas swd, el carácter 1 * 1 delante de
la x asociada a la contraseña encriptada del usuario cuyo acceso se desea impedir.
e
Ejemplo 1.8
Supóngase que en un cierto S OB UNIX pueden acceder los siguientes usuarios : roo t , pedro 9 0 , j uan
y mar i . Si el usuario pedro 9 0 ejecuta la orden
cat / e t c / p a s swd
en la pantalla se mostrará el contenido del archivo p a s swd. Este archivo contiene una línea por cada
usuario reconocido por el sistema operativo. Supóngase que la línea asociada al usuario pedro 9 O es la
siguiente:
p edro 9 0 : x : 1 0 1 : 1 0 : Pedro B l anco : / exp o r t / home /pedro 6 9 : / b i n / ba s h
Los datos del usuario s e separan por e l carácter 1 : 1 De izquierda a derecha s e muestran l o s siguientes
datos: pedr o 9 O es el nombre de usuario, x indica que la contraseña se encuentra encriptada dentro del
archivo cuyo nombre de ruta absoluta suele ser / e t c / s hadow, 1 0 1 es el UID, 1 0 es el GID, Pedro
B l anco es el nombre completo del usuario, / expo r t / home / pedro 6 9 es el nombre de ruta absoluta
del directorio de trabaj o inicial, y / b i n / bash es el nombre de ruta absoluta del intérprete de comandos
que utiliza por defecto el usuario.
•
Por ejemplo si se desea impedir el acceso al usuario pedr o 9 O su línea del archivo debería modificarse
de la siguiente forma:
pedro 9 0 : * x : 1 0 1 : 1 0 : Pedro B l anc o : / expo r t / home /pedro 6 9 : / b i n / ba s h
Nótese que s i s e examinan detenidamente las líneas del archivo pas swd s e observará que existen más
líneas que las cuatro esperadas en principio, una por cada usuario habilitado. Esto es así porque en
SOBUNIX la ejecución de ciertos programas requiere de la asignación de un usuario ficticio.
•
Sistemas Operativos B asados en UNIX (SOBUNIX) : introducción general
27
Asimismo, la información sobre la composición de los grupos, es decir, los usuarios que forman parte
de cada grupo, es almacenada por el sistema operativo en un archivo cuyo nombre de ruta absoluta suele
ser 1 e t c 1 group.
El archivo 1 e t c / group puede ser leído por todos los usuarios, sin embargo sólo puede ser modifica­
do por el superusuario. Para crear un nuevo grupo, el superusuario puede usar, por ejemplo, el comando
groupadd o el comando addgroup . Para eliminar un grupo puede usar el comando g roupde l . Si se
desea modificar la composición de un grupo el superusuario puede usar el comando g roupmod. Otra
opción sería editar directamente el contenido del archivo 1 e t c 1 group .
e
Ejemplo 1.9
Considérese el sistema del ejemplo anterior, si un usuario ejecuta la orden:
c a t / e t c / group
en la pantalla se mostrará el contenido del archivo group. Este archivo contiene una línea por cada grupo
de usuarios reconocido por el sistema operativo. Dentro de una línea los datos asociados a un grupo se
separan por el carácter : Supóngase que este archivo contiene, entre otras, la siguiente línea:
1
1
•
s t a f f : : 1 0 : mar i , j uan
Los datos, de izquierda a derecha, contenidos en esta línea son los siguientes: s t a f f es el nombre del
grupo, : : indica que no existe especificada una contraseña de acceso al grupo, 1 0 es el GID, y mar i y
j uan son los nombres de dos usuarios añadidos a este grupo. De acuerdo con esta información al grupo
s t a f f pertenecen todos los usuarios que tengan asignado el GID= 1 0, como era el caso del usuario
pedro 9 0 , y los usuarios mar i y j uan.
Señalar que al igual que sucedía con / e t c /pas swd en / e t c / group existen líneas asociadas a gru­
pos ficticios, creados durante la instalación de ciertos programas y cuya existencia es necesaria para su
correcta ejecución.
•
l. 7 2
.
.
Máscara de modo de un archivo
Representación binaria
En los SOBUNIX cada archivo tiene asociado, entre otros atributos. (ver sección 5 . 2 . 1 ) , un número
binario de 1 6 bits denominado máscara de modo (ver Figura 1 .5). Si un bit de la máscara está a 1 se
considera activado, en caso contrario estará desactivado. La información contenida en la máscara de
modo es la siguiente:
•
Tipo de archivo (B 1 5 B 14B 1 3 B 1 2 ). Algunos de los tipos de archivos más comunes soportados en
los SOBUNIX son: archivo ordinario ( 1 000), directorio (0 1 00), archivo asociado a dispositivo
modo carácter (00 1 0), archivo asociado a dispositivo modo bloque (O 1 1 0), tubería (000 1 ), enlace
simbólico ( 1 0 1 0) y conector (socket) ( 1 1 00).
Ampliación de sistemas operativos
28
•
•
•
•
•
•
Bit s_I SUID (B u ). Si este bit se encuentra activado entonces cuando un usuario ejecute este
archivo su identificador efectivo de usuario (ver sección 1 .7 . 3 ) se hará igual al UID del propietario
del archivo.
Bit S_I SGID (B 1 0 ). Tiene una utilidad semejante al bit S_I SUID pero a nivel de grupo. Es decir,
si este bit se encuentra activado entonces cuando un usuario ejecute este archivo su identificador
efectivo de grupo (ver sección 1 .7.3) se hará igual al GID del propietario del archivo.
Bit S_I SVTX (B 9 ), también denominado bit pegajoso (sticky bit). La activación de este bit indica
al sistema operativo que la región de código del archivo ejecutable va a ser compartida por varios
procesos y en consecuencia debe mantenerse en la memoria principal aunque termine el primer
proceso cuya ejecución produj o que se cargará dicha región de código. En el caso de programas
utilizados por distintos usuarios (editores, compiladores, etc) esta técnica permite ahorrar memoria.
Permisos de acceso del usuario propietario del archivo (BsB 7 B 6 ). Se puede establecer de forma
independiente tres tipos de permisos : lectura (B8), escritura (B 7 ) y ejecución (B 6 ).
Permisos de acceso para los usuarios pertenecientes al grupo propietario del archivo (BsB 4 B 3 ).
Se pueden establecer de forma independiente tres tipos de permisos: lectura (Bs), escritura (B 4 ) y
ejecución (B 3 ). Por defecto el grupo propietario es aquel cuyo GID coincide con el GID asignado
al usuario propietario del archivo. Tanto el usuario propietario como el grupo propietario pueden
ser cambiados usando la llamada al sistema chown o el comando homónimo.
Permisos de acceso para el resto de usuarios (B 2 B 1 Bo). Es decir, para aquellos usuarios que no son
ni el propietario ni pertenecen al grupo propietario. Se pueden establecer de forma independiente
tres tipos de permisos : lectura (B 2 ), escritura (B 1 ) y ejecución (Bo).
Representación binaria
Tipo de archivo
s_r s G I D
+
S
I SU I D
S
Permisos propietario
I SVTX
Permisos otros usuarios
Permisos grupo propietario
Representación octal
Figura 1.5 - Máscara de modo de un archivo en representación binaria y en representación octal
Sistemas Operativos B asados en UNIX (SOBUNIX) : introducción general
29
Nótese que en el caso de que el archivo sea un directorio, entonces el permiso de lectura permite leer
las entradas del directorio, el permiso de escritura permite añadir o borrar una entrada al directorio y el
permiso de ejecución permite buscar una entrada en el directorio.
Representación octal
De los 1 6 bits que componen la máscara de modo de una archivo solo los bits B 1 1 a Bo pueden ser
modificados por el superusuario o el propietario. Estos doce bits se suelen representar mediante cuatro
cifras octales 0 3 0 2 0 1 00 (ver Figura 1 . 5) que tienen el siguiente significado:
•
0 3 . Establece el valor de los bits S_I SUID, s_I SGID y s_I SVTX, ya que es la codificación en
octal de los bits B l 1 B 10B 9 .
•
0 2 . Establece los permisos de acceso del usuario propietario del archivo ya que es la codificación
en octal de los bits BsB7B 6 .
•
0 1 . Establece los permisos de acceso del grupo propietario del archivo ya que es la codificación
en octal de los bits BsB4B 3 .
•
00 . Establece los permisos de acceso al archivo del resto de usuarios ya que es la codificación en
octal de los bits BzB 1 Bo .
Representación simbólica
La máscara de modo de un archivo también se suele representar usando una cadena de 1 O caracteres
(ver Figura 1 . 6) a la que se denomina máscara simbólica. El significado y los valores de cada uno de
estos caracteres es el siguiente:
•
c 9 . Este carácter establece el tipo de archivo. Puede tomar los siguientes valores :
ordinario), 1 d 1 (directorio), 1 e 1 (archivo asociado a un dispositivo modo carácter),
asociado a un dispositivo modo bloque), 1 p (tubería), 1 1 1 (enlace simbólico) y 1 s
1
•
1 - 1 (archivo
1 b 1 (archivo
1 (conector).
c 8 , c5 y c2 . Estos tres caracteres establecen el permiso de lectura para el propietario, el grupo
propietario y el resto de usuarios, respectivamente. Cada uno de estos bits puede tomar de forma
independiente los siguientes valores : r 1 (permiso de lectura concedido) o 1 - 1 (permiso de lectura
denegado) .
1
•
c7 , c4 y e 1 . Estos tres caracteres establecen el permiso de escritura para el propietario, el grupo
propietario y el resto de usuarios, respectivamente. Cada uno de estos bits puede tomar de forma
independiente los siguientes valores : 1 w (permiso de escritura concedido) o 1 1 (permiso de
escritura denegado).
1
•
c 6 . Este carácter establece la activación del bit S_I SUID y el permiso de ejecución para el propie­
tario del archivo. Puede tomar los siguientes valores : 1 - 1 (bit S_I SUID desactivado y permiso de
Ampliación de sistemas operativos
30
Estado
S
Permisos
propietario
I SG I D
-1
o
:.r::.;os
Tipo de archivo
Estado
S
S
I SU I D
I SVTX
Figura 1.6 - Máscara de modo de un archivo en representación simbólica
ejecución denegado), 1 x 1 (bit s_r sum desactivado y permiso de ejecución concedido), 1 s 1 (bit
S_I SUID activado y permiso de ejecución denegado) y 1 s 1 (bit s_r sum activado y permiso de
ejecución concedido).
•
CJ . Este carácter establece la activación del bit s_I S G I D y el permiso de ejecución para el grupo
propietario del archivo. Puede tomar los siguientes valores:
(bit s_I SGID desactivado y per­
miso de ejecución denegado), 1 x 1 (bit S_I SGID desactivado y permiso de ejecución concedido),
1 s 1 (bit S_I SGID activado y permiso de ejecución denegado) y 1 s (bit S_I SGID activado y
permiso de ejecución concedido).
1
-
1
1
•
co . Este carácter establece la activación del bit S_I SVTX y el permiso de ejecución para el resto de
usuarios del archivo. Puede tomar los siguientes valores : - (bit S_I SVTX desactivado y permiso
de ejecución denegado), 1 x 1 (bit s_I SVTX desactivado y permiso de ejecución concedido), 1 T 1
(bit S_I SVTX activado y permiso de ejecución denegado) y 1 t (bit S_I SVTX activado y permiso
de ejecución concedido).
1
1
1
e
Ejemplo 1.10
Supóngase que el archivo / heme / p rueba . txt tiene la siguiente máscara simbólica:
- r - s -ws - - t
El primer carácter ( - ) de la máscara indica que se trata de un archivo ordinario. Los siguientes tres carac­
teres (r - s ) especifican que el propietario tiene permisos de lectura y ejecución sobre el archivo, además
el bit S_I SUID está activado. Los caracteres ( -ws ) indican que el grupo propietario únicamente tiene per­
miso de escritura, además el bit S_I SGID está activado. Los últimos tres caracteres ( - - t) especifican
que el resto de usuarios tienen solo permiso de ejecución, además el bit S_I SVTX está activado.
Sistemas Operativos B asados en UNIX (SOBUNIX): introducción general
31
De acuerdo con esta máscara de modo simbólica la máscara de modo binaria sería:
1000 111 101 010 001
A partir de la representación en binario es sencillo obtener la máscara octal:
7521
•
Configuración de la máscara de modo de un archivo
Cuando un proceso crea un archivo haciendo uso de las llamadas al sistema c r e a t u open, el sistema
operativo se encarga de configurar los cuatro bits de la máscara de modo que especifican el tipo del
archivo. Los doce bits restantes de la máscara son inicializados por el proceso especificando uno de los
argumentos de entrada de estas llamadas al sistema (ver sección 5 . 2 . 1 ) . Posteriormente, el propietario del
archivo o el superusuario pueden cambiar el valor de los 1 2 últimos bits de la máscara de modo haciendo
uso de la llamada al sistema chrnod o del comando homónimo.
e
Ejemplo 1.11
Considérese el archivo / home / prueba . txt del ejemplo anterior. Se desea que todos los usuarios tengan
permiso de lectura sobre dicho archivo. La máscara de modo, expresada en binario, que debería tener el
archivo para tener estos permisos sería:
1000 111 101 110 101
Cuya máscara octal equivalente es :
7565
Para conceder estos permisos el propietario del archivo o el superusuario puede usar el comando chrnod
en un interprete de comandos de la siguiente formé :
chrnod 7 5 6 5 / home / prueba . txt
Si se ejecuta ahora el comando
l s - l / home / prueba . txt
se puede comprobar que la máscara simbólica del archivo tiene los permisos deseados, es decir, que su
máscara de modo simbólica es:
- r - s rwS r - t
•
4Si se consulta la página del comando chmod en el manual de ayuda se puede comprobar que este comando también soporta
otra sintaxis basada en argumentos de tipo carácter que especifican los permisos que se quieren añadir o eliminar en la máscara
de modo. De las dos sintaxis posibles se puede usar la que más se prefiera.
32
Ampliación de sistemas operativos
l. 7 3
.
.
Identificadores efectivos
En los SOBUNIX cada usuario, aparte de los identificadores reales, también tiene asignados un
identificador de usuario efectivo (Effective User IDentifier, EUID) y un identificador de grupo efectivo
(Effective Group IDentifier, EGID). Estos identificadores efectivos son consultados por el núcleo en
diferentes circunstancias, como por ejemplo cuando un usuario intenta crear o abrir un archivo, o si un
proceso desea enviar una señal a otro proceso.
Los identificadores efectivos se inicializan con el valor de sus identificadores reales cuando un usua­
rio inicia una sesión de trabaj o en el sistema. Por otra parte, si un usuario intenta ej ecutar un archivo que
tiene su bit S_I SUID activado entonces el EUID se configura con el valor del UID del propietario del
archivo. Lo mismo ocurre a nivel de grupo si se activa el bit S_I SGID. Esta propiedad resulta muy útil
para permitir a un usuario ej ecutar programas que son propiedad de usuarios más privilegiados, como el
superusuario.
e
Ejemplo 1.12
El programa / bin /pas swd se utiliza para cambiar la contraseña de un usuario. Este programa tiene que
acceder al archivo de texto / e t c / p a s swd que contiene los datos de todos los usuarios. Por motivos de
seguridad este archivo solo puede ser escrito por el superusuario.
Si se ejecuta el comando
ls
-1
/ b i n / p a s swd
se puede comprobar que el propietario de este archivo ejecutable es el superusuario (usuario r o o t ) y que
su máscara simbólica es :
- r-s r-s r-x
Se observa que e l archivo puede ser leído y ejecutado por todos los usuarios. Además están activa­
dos los bits S_I SUID y S_I SGID. En consecuencia cuando un usuario ejecuta el comando pas swd,
sus identificadores efectivos se hacen iguales a los identificadores reales del superusuario, es decir,
EUID=O y EGID=O. Ello posibilita que durante la ejecución del comando se pueda escribir el archi­
vo / e t c /pas swd.
•
Un usuario puede conocer los valores de sus identificadores UID, EUID, GID, EGID usando las
llamadas al sistema getu i d, g e t eu i d, getgid y g e t e g i d, respectivamente. Asimismo para cambiar
los valores de estos identificadores se pueden usar las llamadas al sistema s e tu i d y s e tg i d, respec­
tivamente. Si estas llamadas las invoca el superusuario entonces podrá cambiar el valor de todos los
identificadores, tanto los reales como los efectivos . Si las invoca un usuario ordinario solo podrá conse­
guir que sus identificadores efectivos tomen el valor de sus identificadores reales.
También es posible comprobar, usando la llamada al sistema a c c e s s , si un usuario dispone de acceso
a un archivo. Esta llamada usa para realizar esta comprobación los identificadores reales UID y GID en
lugar de los efectivos EUID y EGID .
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
Utilidad
Comando
chown
chmod
groupadd
groupde l
groupmod
pas swd
su
u s e radd
u s e rde l
u s e rmod
33
Cambiar el propietario de un archivo
Cambiar la máscara de modo de un archivo
Añadir un grupo de usuarios
Eliminar un grupo de usuarios
Modificar la cuenta de un grupo de usuarios
Cambiar la contraseña de un usuario
Cambiar de usuario
Añadir un usuario
Eliminar un usuario
Modificar la cuenta de un usuario
Tabla 1.3 - Algunos comandos básicos asociados a la seguridad y a la protección en S OBUNIX
Llamada al sistema
access
chmod
chown
getegid
g e t eu i d
getgid
getu i d
s e tg i d
s e tu i d
Utilidad
Comprobar s i u n usuario puede acceder a u n archivo
Cambiar el propietario de un archivo
Cambiar la máscara de modo de un archivo
Obtener e l valor del EGID d e u n usuario
Obtener e l valor del EUID d e u n usuario
Obtener e l valor del GID d e u n usuario
Obtener e l valor del UID d e u n usuario
Configurar e l valor del GID y del EGID d e u n usuario
Configurar e l valor del UID y del EUID d e u n usuario
Tabla 1.4 - Algunas llamadas al sistema básicas asociadas a la seguridad y a la protección en SOBUNIX
En las Tablas 1 . 3 y 1 .4 se recopilan los comandos y las llamadas al sistema más utilizadas en los
S OBUNIX asociadas a la seguridad y a la protección. Señalar que algunos comandos tienen el mismo
nombre que algunas llamadas al sistema, estos comandos invocan durante su ejecución a las llamadas al
sistema homónimas.
1 .7.4.
Implementación de la seguridad
Acceso al sistema
El acceso de un usuario a un SOBUNIX se realiza a través de un programa de acceso o programa
de login que puede presentar una interfaz en línea de comandos o una interfaz gráfica. Este programa
se ejecuta con el EUID del superusuario ya que el archivo asociado al programa tiene su bit S_I SUID
activado.
El programa de login en primer lugar solicita al usuario su nombre de usuario y su contraseña. A
continuación encripta la contraseña y comprueba que los valores introducidos por el usuario coinciden
34
Ampliación de sistemas operativos
con los almacenados en el archivo / e t c /pas swd. En caso afirmativo accede de nuevo a este archivo
para leer los identificadores reales del usuario e invoca a las llamadas al sistema s e tu i d y s e tg i d. Con
ello se consigue que los identificadores reales y efectivos del programa de login pasen a tomar los valores
del UID y GID del usuario que desea acceder al sistema. Finalmente, el programa de login invoca a un
intérprete de comandos, en concreto al especificado para el usuario en / e tc / p a s swd. Nótese que el
proceso asociado al intérprete y todos los procesos creados a partir de éste heredarán los identificadores
reales y efectivos del programa de login. También los heredarán los archivos u otros recursos abiertos
debido a la actividad del usuario.
Protección de los archivos
En los S OBUNIX el núcleo implementa la protección de un archivo haciendo uso de la máscara de
modo del archivo y de los identificadores efectivos. Cuando un proceso desea abrir un archivo previa­
mente creado debe invocar a la llamada al sistema open. Esta llamada analiza la mascara de modo del
archivo y los identificadores efectivos para determinar si el proceso puede acceder al archivo y con que
privilegios. En caso afirmativo, devuelve un descriptor de archivo. En caso contrario devuelve el valor
-l.
Cuando se realiza una operación sobre un archivo abierto el núcleo examina el modo de apertura del
archivo almacenado en el obj eto de archivo abierto para verificar si la operación se puede realizar o debe
ser denegada. El modo de apertura se especifica como un argumento de la llamada al sistema open (ver
sección 5 . 2 . 1 ) .
e
Ejemplo 1.13
S upóngase que en el directorio de trabajo actual existe el archivo da t o s l que tiene la siguiente máscara
de modo simbólica:
- rw- rw- rwDe la máscara se deduce que se trata de un archivo ordinario, que los bits S_I SUID, S_I SGID y S_I SVTX
están desactivados y que todos los usuarios tienen permiso de lectura y escritura sobre el archivo.
Supóngase que un proceso de un usuario distinto del propietario realiza la siguiente llamada al sistema
para abrir el archivo dat o s l con permiso de solo lectura ( o_RDONLY ) :
fd= open ( " da t o s l " , O_RDONLY )
En este caso el permiso de apertura especificado por el proceso es más restrictivo que los permisos que
especifica la máscara de modo,
El núcleo consultaría la máscara de modo del archivo y los identificadores efectivos para comprobar si
el proceso puede abrir el archivo. En este caso si que puede abrirlo por lo que el núcleo le asigna un
descriptor de archivo que se almacena en la variable fd y un objeto de archivo abierto.
•
Sistemas Operativos B asados en UNIX (SOBUNIX) : introducción general
35
Señalar que el acceso a un archivo también depende de los permisos de acceso que tengan cada uno
de los componentes (directorios) del nombre de la ruta absoluta de un archivo. Si los componentes de la
ruta no tienen permisos de lectura y ejecución no se podrá acceder al archivo.
e
Ejemplo 1.14
S upóngase que el directorio de trabajo actual es / horne . Si la máscara simbólica de este directorio se
configura a
d rwx - - - - - entonces ningún usuario excepto el propietario del directorio podrá acceder al directorio. De esta forma el
propietario no tiene necesidad de especificar los permisos de los archivos contenidos en dicho directorio
ya que ningún usuario excepto él y el superusuario pueden acceder a dicho directorio.
•
1 .8.
Resumen
El sistema operativo UNIX fue desarrollado por Ken Thompson en los laboratorios B ell de AT&T
a principios de los años setenta. Puesto que debido a la legislación norteamericana vigente AT &T no
podía comercializar UNIX directamente, no tuvo inconveniente en otorgar licencias de UNIX a las uni­
versidades con fines educativos y de investigación. Esto propicio que la comunidad universitaria aportara
sugerencias e ideas a AT&T para mejorar UNIX. De hecho la Universidad de California en B erkeley
introdujo tantos cambios en el código fuente que comercializó su propio UNIX con el nombre de B S D .
Aparte d e las universidades, algunas empresas fabricantes d e computadores y software también obtuvie­
ron sus propias licencias de UNIX y produjeron sus propias distribuciones, como por ejemplo: Xenix,
SunOS, AIX y HP-UX. Debido a la proliferación de distribuciones de UNIX, AT&T también decidió
entrar en el negocio a través de una compañía filial, y lanzó sus propias distribuciones como : System III
y System V.
La gran variedad de S OBUNIX resultaba un serio problema para los desarrolladores de aplicaciones
software. Las diferencias entre unos SOBUNIX y otros propiciaban que una misma aplicación pudiera
no funcionar correctamente en todos los sistemas . Para intentar resolver este problema se han creado
diferentes estándares o especificaciones que definen una API y las características que deben tener los
intérpretes de comandos y los shell scripts . Entre los estándares definidos destacan POSIX y SUS .
Los SOBUNIX comparten una serie de características comunes : son sistemas de tiempo compartido,
son sistemas multiprogramados y multiusuario, soportan multiprocesamiento, el núcleo está escrito en
su mayor parte en lenguaje C y posee una estructura de tipo monolítica, la planificación se realiza a
nivel de procesos o de hilos del núcleo usando un algoritmo de planificación basada en múltiples colas
de planificación y realimentación, administran la memoria principal e implementan la memoria virtual
usando la técnica de demanda de página, soportan una estructura de directorios de gráfica acíclica, el
directorio raíz se denota con el símbolo '/' que además se usa para separar los componentes del nombre
de ruta de un archivo, implementan las abstracciones de nodo virtual y sistema de archivos virtual lo
36
Ampliación de sistemas operativos
que les permite soportar diferentes tipos de sistemas de archivos, y los dispositivos de E/S se integran
dentro del sistema de archivos mediante el uso de archivos de dispositivos modo bloque y archivos de
dispositivos modo carácter.
Los SOBUNIX soportan dos posibles tipos de interfaces con los usuarios : interfaz de línea de coman­
dos e interfaz de usuario gráfica. Nótese que desde una interfaz gráfica también se puede disponer de una
interfaz de línea de comandos . A través de estos interfaces un usuario puede invocar a otros programas o
aplicaciones.
La interfaz de línea de comandos se implementa mediante un intérprete de comandos que es un pro­
grama que acepta un comando introducido por un usuario a través del dispositivo de entrada estándar
(por defecto el teclado) y ejecuta su código asociado. El resultado de la ejecución se muestra, general­
mente, en el dispositivo de salida estándar (por defecto la pantalla) . Una vez finalizada la ej ecución del
comando el intérprete queda a la espera de recibir otra orden por parte del usuario.
Cada S OBUNIX suele incluir por defecto en su distribución un determinado intérprete de comandos,
pero el usuario si así lo desea puede utilizar otro. Entre los intérpretes de comandos más conocidos se
encuentran los siguientes : B oume shell ( sh), C shell ( c s h) , TENEX C shell (tc sh), Kom shell (ksh), y
B oume-Again shell (bash).
Las interfaces de usuario gráficas de la mayoría de SOBUNIX se basan en el sistema X Window,
también denominado abreviadamente como X. El sistema X Window es un sistema de ventanas, es
decir, la capa de software más interna de un GUI que se encarga de envíar y recibir datos del hardware
(pantalla, teclado y ratón) y que contiene las funciones primitivas básicas para la representación gráfica
de líneas y fuentes, asociadas a las ventanas y al puntero del ratón. X Windows se caracteriza por su alta
portabilidad ya que se ej ecuta fuera del espacio de direcciones del núcleo.
Desde el punto de vista de su ejecución tanto los interfaces como los programas tendrán asociado
cada uno al menos un proceso monohilo o multihilo. Un proceso (o un hilo) para solicitar los servi­
cios del núcleo del sistema operativo tiene que realizar las llamadas al sistema correspondientes. En los
S OBUNIX un proceso para hacer una llamada al sistema invoca a una función de envoltura o redireccio­
namiento de la librería C estándar, también denominada l ib e abreviadamente. Cada llamada al sistema
tiene asociada al menos una función de envoltura.
Los S OBUNIX son sistemas multiusuario, es decir, pueden atender simultáneamente a múltiples
usuarios . Además también tienen la capacidad de gestionar grupos de usuarios . Para implementar la
seguridad y la protección de los datos de los usuarios los SOBUNIX utilizan los siguientes elementos:
identificadores reales (UID y GID), identificadores efectivos (EUID y EGID) y máscara de modo de un
archivo.
1 .9.
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pue­
den consultar, por ejemplo : el capítulo 10 de [Tanenbaum, 2009] , el capítulo 1 de [Vahalia, 1 995], los
capítulos 1 a 6, 10, 1 2, 1 3 y 14 de [Love et al. , 2005 ] , y los capítulos 1 , 3 y 6 de [Márquez, 2004] .
S istemas Operativos B asados en UNIX (SOBUNIX) : introducción general
1 .10.
37
Autoevaluación
1.1. ¿Cuándo se desarrollo el sistema operativo UNIX? ¿ Quién fue su creador? ¿Qué compañía era la
propietaria de sus derechos? (Respuesta en sección 1 .2)
1.2. ¿Qué motivó la proliferación de diferentes distribuciones de UNIX? (Respuesta en sección 1 .2)
1.3. ¿Qué universidad desarrolló su propia distribución de UNIX? ¿Cómo se llamaba dicha distribu­
ción? (Respuesta en sección 1 . 2)
1.4. ¿Qué distribuciones de UNIX comercializó AT &T a través de una compañía filial ?
(Respuesta en sección 1 .2)
1.5. Enumerar tres ejemplos actuales de distribuciones comerciales de UNIX y tres ejemplos actuales
de distribuciones libres . (Respuesta en sección 1 .2)
1.6. ¿Cuáles son los estándares de compatibilidad más usados en los SOBUNIX?
(Respuesta en sección 1 .3)
1.7. Enumerar las características principales de los SOBUNIX . (Respuesta en sección 1 .4)
1.8. ¿Qué es un intérprete de comandos? ¿Cuáles son los intérpretes de comandos más conocidos en
los S OBUNIX? (Respuesta en sección 1 .5 . 1 )
1.9. ¿Cuál es l a estructura general de un comando? (Respuesta en sección 1 .5 . 1 )
1. 10. ¿Para que sirve el comando roan? ¿ Y el comando i n f o ? (Respuesta en sección 1 .5 . 1 )
1.11. Explique l a utilidad de los siguientes comandos: cd, cp, l s , mkd i r , mv, mvd i r , pwd, rm y rmd i r .
(Respuesta e n sección 1 . 5 . 1 )
1.12. Explique la utilidad de los siguientes comandos : c a t , f i nd, grep, more y s o r t .
(Respuesta e n sección 1 .5 . 1 )
1. 13. ¿Qué es un comodín en los intérpretes de comandos de los SOBUNIX? Explique la utilidad de los
siguientes comodines : ' * , ? y [ J (Respuesta en sección 1 .5 . 1 )
'
'
'
11
11 •
1. 14. ¿Cómo se puede conseguir el redireccionamiento de l a entrada y de l a salida en un intérprete de
comandos? ¿ Y el encadenamiento de órdenes ? (Respuesta en sección 1 .5 . 1 )
1. 15. ¿Cómo se puede asignar un alias a una orden o cadena de órdenes ? ¿Cómo s e elimina dicho alias ?
(Respuesta en sección 1 .5 . 1 )
1. 16. Explicar razonadamente si la asignación de un alias es temporal o permanente.
(Respuesta en sección 1 .5 . 1 )
1. 17. ¿Qué es un comando externo? ¿ Y un comando interno? (Respuesta en sección 1 .5 . 1 )
38
Ampliación de sistemas operativos
1. 18. ¿Qué se entiende por trabaj o (j ob) en el contexto de un intérprete de comandos?
(Respuesta en sección 1 .5 . 1 )
1. 19. ¿Cómo se debe escribir una orden para que sea ejecutada e n segundo plano?
(Respuesta en sección 1 .5 . 1 )
1 .20. Explique l a utilidad de los siguientes comandos : fg, b g y j obs . (Respuesta e n sección 1 .5 . 1 )
1.21. Explique qué sucede e n u n intérprete de comandos s i s e pulsan las teclas :
a) [contro l ] + [ z ] . b) [contro l ] + [ e ] . (Respuesta en sección 1 .5 . 1 )
1 .22. ¿Qué son las variables del intérprete de comandos? ¿Cómo s e pueden visualizar?
(Respuesta en sección 1 .5 . 1 )
1 .23. ¿Qué información contiene l a variable del intérprete PATH? ¿Cómo se puede añadir el directorio
de trabajo actual a dicha variable? (Respuesta en sección 1 .5 . 1 )
1 .24. ¿ Qué son las variables de entorno de un proceso? ¿Cómo s e pueden visualizar las variables de
entorno del intérprete de comandos? (Respuesta en sección 1 .5 . 1 )
1 .25. ¿Cómo s e puede exportar una variable del intérprete a s u entorno? ¿Cómo se puede eliminar una
variable del intérprete? (Respuesta en sección 1 .5 . 1 )
1 .26. ¿Qué es un shell script? ¿Cómo se crea? (Respuesta e n sección 1 .5 . 1 )
1 .27. Explicar razonadamente las diferentes formas posibles d e ejecutar u n shell script.
(Respuesta en sección 1 .5 . 1 )
1 .28. Explicar razonadamente qué es el sistema X Window y cómo funciona. (Respuesta en sección 1 .5.2)
1 .29. ¿Qué es un widget toolkit? Enumerar algunas widgets toolkits usadas en SOBUNIX.
(Respuesta en sección 1 .5 .2)
1 .30. ¿Qué componentes básicos suele incluir un entorno de escritorio de los SOBUNIX? Enumerar
algunos ejemplos. (Respuesta en sección 1 .5 .2)
1.31. Explicar razonadamente cómo se invocan y cómo se tratan las llamadas al sistema en los S OBU­
NIX. (Respuesta en sección 1 .5 . 3 )
1 .32. ¿Cómo s e estructura la información contenida en los archivos e n los SOBUNIX?
(Respuesta en sección 1 .6)
1 .33. Los SOBUNIX ¿distinguen entre mayúsculas y minúsculas en los nombres de los archivos ?
(Respuesta e n sección 1 .6)
1 .34. Explicar razonadamente si en los SOBUNIX los nombres de los archivos pueden usar extensiones.
(Respuesta en sección 1 .6)
Sistemas Operativos B asados en UNIX (SOBUNIX) : introducción general
39
1.35. ¿Qué es un descriptor de archivo? ¿Y un obj eto de archivo abierto? (Respuesta en sección 1 .6)
1.36. ¿Cuántas tablas de descriptores de archivos existen en el núcléo? (Respuesta en sección 1 . 6)
1.37. ¿Qué información contiene un objeto de archivo abierto? (Respuesta en sección 1 .6)
1.38. ¿Qué tipo de estructura de directorios implementan los SOBUNIX? ¿Con que carácter se repre­
senta al directorio raíz del sistema de archivos principal? (Respuesta en sección 1 .6)
1.39. Enumerar y explicar el contenido de cinco de los directorios contenidos dentro del directorio raíz
del sistema de archivos principal de los SOBUNIX. (Respuesta en sección 1 .6)
1.40. ¿Cuáles son los identificadores reales de un usuario? ¿Qué valor toman estos identificadores en el
caso del superusuario? (Respuesta en sección 1 .7 . 1 )
1.41. ¿Qué información contiene el archivo / e t c / pa s swd? ¿ Y el archivo / e t c / gr oup ?
(Respuesta en sección 1 .7 . 1 )
1.42. ¿Cómo s e pueden crear y eliminar usuarios en los SOBUNIX? ¿Es posible impedir el acceso a un
usuario sin eliminar su cuenta? (Respuesta en sección 1 .7 . 1 )
1.43. ¿Cómo s e pueden crear, modificar y eliminar grupos de usuarios en los SOBUNIX?
(Respuesta en sección l . 7 . 1 )
1.44. Explicar razonadamente qué es la máscara de modo de u n archivo y comentar e l significado de
cada uno de los bits en su representación binaria. (Respuesta en sección 1 .7 .2)
1.45. Explicar razonadamente el significado de cada uno de los caracteres de la representación simbólica
de la máscara de modo de un archivo. (Respuesta en sección 1 .7 .2)
1.46. ¿Qué comando se utiliza para modificar la máscara de modo de un archivo?
(Respuesta en sección 1 .7.2)
1.47. ¿Cuáles son los identificadores efectivos de un usuario? ¿Cuándo son consultados por el núcleo?
(Respuesta en sección 1 .7 . 3 )
1.48. Explicar l a relación existente entre e l bit s_I SUID d e la máscara d e modo d e un archivo y el
identificador EUID . (Respuesta en sección 1 .7 . 3 )
1.49. Explicar para qué se utilizan las siguientes llamadas a l sistema: getuid, g e t eu i d, getgid,
g e t e g i d, s e tu i d, s e t e u i d y acc e s s . (Respuesta en sección 1 .7.3)
1.50. Explicar cómo se realiza el acceso de un usuario a un SOBUNIX . (Respuesta en sección 1 .7 .4)
1.51. Explicar cómo se implementa la protección de archivos en los S OBUNIX.
(Respuesta en sección 1 .7 .4)
40
Ampliación de sistemas operativos
1.11.
Ejercicios
1.1. Supóngase que en un cierto S OBUNIX el directorio de trabajo actual de un usuario contiene los
archivos da t o s , f o t o smu l , l i s t as . txt, ex l , a l umno s . da t , trabaj o s . txt y asdo, y los
directorios f o t o s , v i d e o s y corre o s . Indicar la orden que se debe escribir en un intérprete de
comandos para realizar cada una de las siguientes acciones :
a) Visualizar la ruta absoluta del directorio de trabaj o actual .
b) Visualizar un listado del contenido del directorio de trabajo que permita diferenciar entre
archivos y directorios.
e) Visualizar un listado que únicamente contenga los nombres de los archivos que acaban con
la letra 'o' o con la letra ' t ' .
d ) Mover al subdirectorio f o t o s los archivos dat o s y f o t o smu l .
e) Hacer que el directorio f o t o s pase a ser el directorio de trabajo actual .
1.2. Explique razonadamente cuál sería el resultado de la ej ecución de las siguientes órdenes :
a) s o r t < fA > f B
b) l s
-1
> asd
e) l s
-i
> > wer t 2 3
d) more � / prueba . tx t
e ) c p par t e { p r imera , s egunda } trabaj o s
1.3. Consulte l a página del manual man o l a bibliografía que considere necesarias y conteste a las
siguientes cuestiones relativas al intérprete de comandos bash:
a) ¿Cómo es posible conocer todos los intérpretes de comandos disponibles en un cierto SO­
BUNIX?
b) ¿Cómo se puede saber dónde se aloj a el intérprete bash?
e) ¿Cómo es posible saber si el intérprete de comandos que estamos utilizando es el intérprete
bash?
d) ¿Cómo se puede saber la versión de bash que estamos utilizando?
e) ¿Qué variables son consideradas especiales en bash?
f) ¿Para qué sirve la sustitución de comandos y cómo se implementa?
g) Explicar la diferencia entre los siguientes entrecomillados: " c adena " y 'c adena'
h) ¿Cómo se pueden introducir datos procedentes del teclado?
i) Enumerar los operadores lógicos, los operadores de comparación de cadenas y los operadores
de comparación de números enteros disponibles en bash.
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
41
j) Enumerar algunos de los operadores de comparación de atributos de archivos disponibles en
bash.
k) Explicar el significado del operador [ expre s i ón J .
1) Explicar cómo se pueden realizar operaciones aritméticas con enteros en bash.
m) Explicar cómo se declara una sentencia condicional de tipo i f.
n) Explicar cómo se declara un bucle de tipo whi l e o de tipo unt i l .
o) Explicar cómo s e declara un bucle de tipo f o r .
p ) Explicar cómo s e declara una sentencia d e tipo c a s e .
q) Explicar cómo s e declara y s e invoca una función que reciba parámetros d e entrada. Explicar
también cómo se pueden retornar valores desde una función.
1.4. Explique razonadamente el funcionamiento del shell script que se muestra en la Figura 1 .7.
1.5. Explique razonadamente el funcionamiento del shell script que se muestra en la Figura 1 . 8 .
1.6. Escribir un shell script para e l intérprete b a s h que muestre l a fecha y l a hora del sistema cada
segundo durante un minuto. Ayuda: para la realización de este ejercicio resulta muy útil el uso de
los comandos s l e ep y da t e .
1.7. Escribir u n shell script para e l intérprete ba sh que muestre e l día d e l a semana que fue ayer. Ayuda:
para la realización de este ejercicio resulta muy útil el uso del comando da t e .
1.8. Buscar l a utilidad d e l a función sys t em y escribir u n programa en C d e ejemplo d e uso d e esta
función.
1.9. La máscara de modo del archivo regular resul t ado s expresada en octal es 6644 :
a) Explique razonadamente el significado de todos los bits de esta máscara de modo.
b) Escriba la máscara de modo simbólica asociada a este archivo.
e) ¿Qué orden se debe escribir en un intérprete de comandos para que la máscara simbólica del
archivo pasase a ser
-
rwx r-
-
- -T?
1.10. La máscara de modo simbólica del archivo ej ecutable s 0 7 que resulta de compilar el programa que
se muestra en la Figura 1 .9 es - rwxrw- rwx y dicho archivo pertenece al usuario Wo l f (UID=50 1 ,
GID=202). Explique razonadamente el funcionamiento del programa en los siguientes casos: a)
El programa lo ej ecuta wo l f . b) El programa lo ejecuta el usuario Fox (UID=502, GID=203) .
42
Ampliación de sistemas operativos
# ! / b i n / ba s h
#
echo
" I n t ro du c e una c adena : "
read CADENA
wc - e )
LONG I TUD= $ ( echo $ CADENA
wh i l e
[
$ L ONGI TUD - g t O
do
X= " $ X " $ ( e cho $ CADENA
J
c u t - c $ LONG I TUD )
LONG I TUD= $ ( ( $ LONG I TUD -
1) )
done
echo
" $X "
Figura 1.7 - Shell script del Ejercicio 1 .4
# ! / b i n / ba s h
#
if
[
$#
-gt O
for i
)
;
then
in $ *
do
mv $ i
if
[
$ HOME / p ap e l e r a 2 >
$?
- eq O
)
;
/ dev / nu l l
then
echo
" $ i ha s i do mov i do a l a pap e l e r a con éxi t o "
echo
" $ i no h a p o d i do s e r movi do a l a p ap e l e ra "
else
fi
done
e ls e
echo
" Error :
echo
" $ 0 archivo 1
hay qu e e s p e c i f i c ar argumen t o s "
[ ar c h i vo 2 )
. . .
"
exi t 1
fi
ex i t O
Figura 1.8 - Shell script del Ejercicio 1 .5
Sistemas Operativos Basados en UNIX (SOBUNIX) : introducción general
f l o a t a l ( f l oa t
( *b )
( float a ) ) ;
f l o a t a 2 ( f l oa t a ) ;
ma i n ( )
{
int u [ 3 ] ;
f l oa t z = O ;
u [ 0 ] =getui d ( ) ;
u [ l ] = g e t eu i d ( ) ;
u [ 2 ] = s e tu i d ( u [ l ] ) ;
if
(u [ 2 ] ==0 )
{
z = a l ( a2 ) ;
p r i n t f ( " \ n [ %d ,
f l oat al ( f l oat
( *b )
!hl ,
!hl ,
% . 2f ] \n" , u [ O ] , u [ l ] , u [ 2 ] , z ) ;
( f loat a ) )
{
f l oat u = 3 0 . 4 ;
u= ( *b ) ( u ) ;
return ( u ) ;
f l oa t a 2 ( f l oa t a )
{
int h ;
f o r ( h= - l ; h< 3 ; h+ + )
{
return ( a ) ;
Figura 1.9
-
Código e del programa S o 7 del Ejercicio 1 . 1 o
43
Capítulo 2
SOBUNIX: implementación y control de
procesos multihilos
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes :
•
Conocer los conceptos y las estructuras de datos fundamentales que utilizan los SOBUNIX para
implementar los procesos multihilos.
•
S aber cómo se realiza la creación de nuevos procesos y la invocación de programas en los SOBU­
NIX.
•
Saber cómo se realiza la terminación de procesos en los SOBUNIX.
•
Conocer el uso, funcionamiento e implementación de la notificación de eventos mediante señales
en los S OBUNIX.
•
Saber cómo se realiza el control de los hilos de usuario mediante el uso de la librería de hilos
Pthreads de POSIX.
•
Conocer qué son y para qué sirven los conceptos de grupos de procesos y sesiones en los S OBU­
NIX.
•
Saber qué es el sistema de archivos de procesos (procfs), conocer la información que contiene y
cómo se consulta.
45
Ampliación de sistemas operativos
46
2. 1.
Introducción
Uno de los principales servicios que debe proporcionar un sistema operativo es posibilitar la eje­
cución de los programas de los usuarios. Para lograr este objetivo se utiliza el modelo de proceso. Un
proceso es una instancia de un programa en ejecución que requiere la asignación de diferentes recursos
para poder existir y progresar. El modelo de proceso utilizado en los primeros S OBUNIX consideraba
que un proceso únicamente sigue una determinada traza o ruta de instrucciones en su ej ecución, es decir,
tiene un único hilo de control. Sin embargo los SOBUNIX desarrollados con posterioridad comenzaron
a utilizar diferentes modelos de procesos multihilos ya que permiten mejorar el rendimiento del sistema.
Este capítulo está dedicado al estudio de la implementación y control de los procesos multihilos
en los SOBUNIX. En primer lugar se introducen los conceptos fundamentales necesarios para entender
los posibles modelos de procesos multihilos . En segundo lugar se describen las estructuras de datos
que se utilizan para implementar los procesos multihilos. En tercer lugar se describe la creación de
procesos y la invocación de programas. En cuarto lugar se describe la terminación de procesos. En
quinto lugar se estudia la notificación de eventos mediante el uso de señales. En sexto lugar se describe
el control de los hilos de usuario mediante el uso de librería de hilos, en concreto se toma como ejemplo la
librería Pthreads de POSIX. En séptimo lugar se estudia los conceptos de grupos de procesos y sesiones.
Finalmente se describe el sistema de archivos de procesos (procfs).
2.2.
2.2.1.
Implementación de los procesos multihilos en SOBUNIX
Conceptos fundamentales
Un programa es un archivo ejecutable que típicamente se encuentra almacenado en memoria secun­
daria. Considerado como archivo, un programa es una entidad pasiva o estática. Cuando un programa es
ej ecutado se convierte en una entidad activa o dinámica denominada proceso que va pasando por dife­
rentes estados y utiliza distintos recursos del computador. En definitiva, un proceso es un programa en
ej ecución.
Un proceso se puede considerar como una entidad computacional básica que tiene asignado un con­
j unto de recursos y que durante su existencia ejecuta una serie de instrucciones. Así un proceso queda
caracterizado por dos elementos que se pueden tratar de forma independiente:
•
Conjunto de recursos asignados. Un proceso tiene asociado un espacio de direcciones de memo­
ria virtual (código, datos, pila, . . . ) y otros recursos, tales como archivos abiertos, procesos hijos,
manejadores de señales, información de contabilidad, etc.
•
Hilos de control o simplemente hilos (thread). Un hilo es un subconjunto de instrucciones del có­
digo del proceso que se puede ej ecutar independientemente del resto de instrucciones del proceso.
En un computador con N procesadores es posible ejecutar en paralelo N hilos pertenecientes a uno
o varios procesos .
En general se distinguen los siguientes tipos de hilos en función de sus propiedades y usos :
SOBUNIX: implementación y control de procesos multihilos
47
•
Hilos del núcleo (kernel threads) . Son hilos asociados al código del núcleo del sistema operativo
que son creados y gestionados por el propio núcleo para la realización de funciones especificas,
como por ej emplo: dar soporte a procesos, atender operaciones de E/S , tratamiento de interrup­
ciones, etc . Los hilos del núcleo no necesitan estar asociados a ningún proceso.
•
Hilos de usuario (user threads) . Son parte del código de un determinado proceso de usuario. El
programador al diseñar un programa es el encargado de establecer el número de hilos de usuario
en que se va descomponer el código del programa. Si el código de un programa consta de un único
hilo de usuario entonces al proceso asociado se le denomina proceso monohilo. M ientras que si se
descompone en varios hilos de usuario se denomina proceso multihilo. Para la gestión de los hilos
de usuario el programador utiliza una librería de hilos, como por ej emplo la librería Pthreads de
POSIX (ver sección 2 . 3 .4). Una librería de hilos contiene funciones para la creación, destrucción,
planificación y sincronización de los hilos de usuario, entre otras operaciones . El sistema operativo
generalmente no suele conocer la existencia de los hilos de usuario, aunque debe dar servicio a las
llamadas al sistema que pueda realizar la librería de hilos para implementar la gestión de los hilos.
Además internamente la librería de hilos puede crear hilos cuya existencia es desconocida por los
hilos de usuario que gestiona.
•
Procesos ligeros (lightweight processes). También denomi nados procesadores virtuales. Son hilos
de usuario cuya gestión es realizada por el núcleo 1 del sistema operativo. Un proceso ligero puede
estar asociado a uno o varios hilos de usuario. Es la librería de hilos la que se encarga de multiplexar
los hilos de usuario de un determinado proceso en un número menor o igual de procesos ligeros.
Los procesos ligeros solo se pueden utilizar en aquellos sistemas operativos cuyo núcleo soporte
hilos del núcleo, ya que cada proceso ligero tiene que tener asociado un hilo del núcleo para poder
ser planificado y ej ecutado.
Los SOBUNIX desarrollados hasta mediados de los ochenta usaban el proceso como unidad de
planificación y ej ecución. El principal inconveniente de estos sistemas es que el bloqueo de un hilo de
usuario de un proceso produce el bloqueo del proceso completo.
Posteriormente se comenzaron a desarrollar SOBUNIX que usaban al hilo del núcleo como unidad
básica de planificación y ejecución. Estos sistemas también pueden soportar, por lo tanto, procesos lige­
ros . La principal ventaj a de soportar hilos del núcleo es que el bloqueo de un hilo del núcleo asociado
a un proceso ligero de un proceso no supone el bloqueo de todos los procesos ligeros de dicho proceso;
por lo que se evita tener que realizar un cambio de proceso. B asta con realizar un cambio de hilo, el cual
introduce una menor sobrecarga. Además en un computador con varios procesadores (o un procesador
con varios núcleos) es posible obtener un verdadero paralelismo durante la ej ecución de un proceso, ya
que cada proceso ligero de un proceso se puede planificar, a través de su hilo del núcleo asociado, en un
procesador.
El principal inconveniente de los hilos del núcleo es que, a diferencia de los hilos de usuario, consu­
men recursos del núcleo y su gestión implica la ej ecución del núcleo. Por este motivo, muchos sistemas
1 En algunos sistemas operativos el te1mino proceso ligero también se utiliza como sinónimo del término
independientemente de si el núcleo conoce la existencia y gestiona dicho hilo.
hilo de usuario
48
Ampliación de sistemas operativos
reciclan los hilos de núcleo existentes . Cuando un hilo del núcleo finaliza su ejecución, se marca como
no planificable, pero sus estructuras de datos asociados no son eliminadas . Cuando se tiene que crear
un nuevo hilo del núcleo, lo que se hace es que se reactiva algún hilo del núcleo marcado como no
planificable con el objetivo de ahorrarse la sobrecarga de asignar estructuras de datos al nuevo hilo.
e
Ejemplo 2. 1
Un ej emplo de SOBUNIX que soporta hilos del núcleo y procesos ligeros es el sistema operativo Solaris.
Desde su versión 2.2 hasta su versión 8.0 soportaba un modelo de proceso multihilo en el cual los hilos
de usuario eran multiplexados en un número menor de procesos ligeros.
La gestión de los hilos de usuario se realiza mediante el uso de una librería de hilos . Solaris dispone de su
propia librería de hilos l ibthread, aunque también soporta la librería p threads de POSIX. Haciendo
uso de las funciones de estas librerías es posible crear, destruir, planificar y sincronizar hilos de usuario.
Una librería de hilos también se encarga de crear por defecto un conj unto de procesos ligeros asociado a
cada proceso, y de multiplexar los hilos de usuario sobre los procesos ligeros. El tamaño de ese conjunto
depende del número de hilos de usuario y del número de procesadores del computador.
Los procesos ligeros son invisibles por defecto al programador, con lo que solo se tiene que preocupar
de programar los hilos de usuario. Aunque si lo desea puede especificar el número de procesos ligeros
que se deben crear. También puede asociar un proceso ligero a un único hilo de usuario, garantizando de
esta forma que dicho hilo siempre tendrá un proceso ligero asociado .
En la Figura 2. 1 a se representa, a modo de ejemplo, un proceso multihilo que consta de cuatro hilos de
usuario. Uno de los hilos está asociado a un proceso ligero. Los tres hilos restantes son multiplexados
sobre dos procesos ligeros. Cada proceso ligero tiene a su vez un hilo del núcleo asociado.
Usar un modelo de proceso multihilo con un mayor número de hilos de usuario que procesos ligeros
resulta útil para aplicaciones en las cuales no es necesario que la mayoría de sus hilos se ejecuten concu-
Proceso multihilo
Proceso multihilo
Hilo de usuario
Proceso ligero
Hilo del núcleo
(a)
(b)
Figura 2.1 - Ejemplo de proceso multihilo soportado en: a) Solaris 2.2. b) Solaris 1 0 .
SOBUNIX : implementación y control de procesos multihilos
49
rrentemente. Por ejemplo, cada elemento de la interfaz gráfica de una aplicación (ventana, iconos, barra
deslizadora, menús, etc) puede ser programado como un hilo de usuario. En un cierto instante solo unos
pocos de dichos elementos se encontrarán activos, luego solo los hilos de usuario asociados a dichos
elementos deben estar ej ecutándose y en consecuencia necesitan tener asignado un proceso ligero.
Este modelo de proceso no resulta adecuado para aplicaciones que requieren que la mayoría de sus hilos
se ejecuten concurrentemente, ya que la librería de hilos gastaría un tiempo de ejecución importante en la
planificación y en los cambios de hilos. Recuérdese que al existir un mayor número de hilos de usuario
que de procesos ligeros, la librería de hilos debe decidir que hilos de usuarios van a tener un proceso
ligero asociado.
En defi nitiva, este modelo de proceso multihilo presenta como principal ventaj a que permite implementar
la concurrencia sin usar demasiados recursos del núcleo. Su principal inconveniente es que la implemen­
tación de un buen planificador de hilos en la librería de hilos es compleja y costosa computacionalmente.
También con este modelo resulta bastante laborioso implementar el tratamiento de las señales (ver sec­
ción 2 . 3 . 3 ) a nivel de la librería de hilos.
Con el fin de evitar los inconvenientes de este modelo Solaris a partir de su versión 8.0 comenzó a
soportar también un modelo de proceso multihilo donde cada hilo de usuario tiene asociado un único
proceso ligero (ver Figura 2. 1 b) . Desde Solaris 10 este es el único modelo soportado.
En este modelo de proceso multihilo la planificación y sincronización de los hilos de usuario, entre otras
tareas de gestión, se delega en el núcleo. Ello ha permitido simplificar el código fuente de la librería de
hilos l i bthread.
•
2.2.2.
Estructuras de datos asociadas a los procesos multihilos
La implementación de un modelo de proceso multihilo requiere la creación y manejo de diferentes
estructuras de datos tanto para el proceso como para los hilos de usuario. Además si el sistema operativo
soporta hilos del núcleo y procesos ligeros entonces también debe mantener estructuras de datos aso­
ci adas a los mismos. En las siguientes secciones se comentan las principales estructuras de datos que
generalmente se mantienen en los S OBUNIX para implementar los procesos multihilos.
Estructuras asociadas a los procesos
Los SOBUNIX suelen mantener en el espacio de direcciones del núcleo una estructura de datos
denominada tabla de procesos que tiene una entrada por cada proceso existente en el sistema. Dicha
entrada se implementa como una estructura de datos, la cual se denomina en algunos SOBUNIX como
estructura pro c . Esta estructura contiene, entre otros, los siguientes datos sobre un determinado proceso :
•
Localización del espacio de direcciones virtuales del proceso. Se mantiene un puntero a una es­
tructura que contiene información sobre la ubicación del espacio de direcciones virtuales de un
proceso (ver sección 4 . 2 . 3 ) .
50
Ampliación de sistemas operativos
•
Identificadores del proceso. Cada proceso tiene asociado un número entero positivo que lo identi­
fica de manera univoca. A dicho identificador se le conoce generalmente con el nombre de identi­
ficador del proceso (Process IDentifier, PID). El número máximo de procesos que pueden existir
de manera simultánea está limitado y suele ser configurable por el superusuario. En consecuencia
el PID puede tomar valores comprendidos entre O y un cierto valor máximo PIDmax . Este límite
máximo no supone generalmente un problema ya que como el tiempo de vida de algunos procesos
es corto sus PIDs pueden ser reutilizados. También un proceso tiene asociado un identificador de
grupo de procesos y un identificador de sesión (ver sección 2 . 3 . 5) .
•
Credenciales del proceso. Generalmente quedan definidos por los identificadores d e usuario y de
grupo reales y efectivos, es decir, UID, GID, EUID y EGID. Estos identificadores relacionan a un
proceso con un determinado usuario y grupo.
•
Estado del proceso. El tiempo de vida de un proceso puede descomponerse en un conjunto de
estados que definen su comportamiento. Las transiciones entre los estados se realizan debido a la
aparición de diferentes eventos. El número y el nombre de los estados soportados dependen de
cada S OBUNIX. Algunos estados habituales son: inicial o creado, preparado para ej ecución, ej e­
cutándose en modo usuario, ejecutándose en modo núcleo, dormido (bloqueado), parado y zombi
(terminado).
•
Parámetros de planificación. Es la información que utiliza el planificador para decidir que proceso
planificar, como por ej emplo, la prioridad de planificación del proceso o el tiempo de uso del
procesador.
•
Información estadística. Como el tiempo de ejecución en modo usuario y el tiempo de ejecución
en modo supervisor del proceso y de sus procesos hijos.
•
Información sobre los procesos ligeros en que se descompone el proceso. Esta información solo se
mantiene si el núcleo soporta hilos del núcleo.
•
Información genealógica. Como el PID del proceso padre y punteros a las estructuras proc de su
proceso padre, de sus procesos hijos y de sus procesos hermanos.
•
Información para el tratamiento de las señales. Como se verá en la sección 2 . 3 . 3 existen máscaras
de bits que permiten especificar qué señales serán ignoradas, qué señales serán bloqueadas y cuáles
serán capturadas .
•
Información para la implementación del sistema de archivos procfs. El sistema de archivos de pro­
cesos procfs es un pseudosistema de archivos existente en algunos S OBUNIX que permite acceder
a los usuarios a la información que mantiene el núcleo sobre los procesos . Dicha información se
almacena en archivos y se organiza en directorios.
•
Á rea de usuario, denominada abreviadamente área-u. Se trata de una estructura de datos que con­
tiene aquella información asociada al proceso que necesita ser consultada por el núcleo únicamente
SOBUNIX: implementación y control de procesos multihilos
51
cuando el proceso está siendo ejecutado, como por ejemplo: un puntero a la tabla de descriptores
de archivos abiertos por el proceso, información sobre el archivo ejecutable a partir del cual se
generó el proceso, los argumentos pasados a la función principal ma in del código del proceso,
los argumentos de la llamada al sistema exec (ver sección 2 . 3 . 1 ), las variables de entorno, las
direcciones de los manejadores definidos para el tratamiento de las señales capturadas, etc.
En los SOBUNIX que no soportan hilos del núcleo en el área-u también se suelen almacenar
la pila del núcleo asociada al proceso y el contexto hardware salvado del proceso. Una pila del
núcleo es una estructura que contiene los marcos de pila de las funciones invocadas por el núcleo
durante la ej ecución del proceso en modo núcleo. El contexto hardware salvado son los valores
que contenían los registros del computador (contador de programa, registro de pila, registro de
estado del procesador, etc) cuando se interrumpió la ej ecución del proceso debido a un cambio
de contexto. El contexto hardware será restaurado cuando el proceso vuelva a ser planificado y se
continúe con la ej ecución del proceso.
En algunos S OBUNIX el área-u de un proceso se implementa en el espacio de direcciones del
proceso en una estructura externa a la estructura proc del proceso. En dicho caso en la entrada de
la tabla de procesos se mantiene un puntero al área-u .
•
Punteros para implementar listas enlazadas de procesos. E l núcleo mantiene diferentes listas para
poder consultarlas durante la planificación de los procesos o cuando se produce algún evento. Por
ejemplo, pueden existir listas de procesos preparados, listas de procesos dormidos (bloqueados)
por determinados eventos, etc. Estas listas se implementan mediante punteros a las estructuras
proc de los procesos que forman parte de cada lista.
Estructuras asociadas a los hilos de usuario
En el modelo de proceso multihilo, el proceso es entendido como un contenedor de recursos y los
hilos de usuarios como unas secuencias de instrucciones. Los hilos de usuario comparten el espacio de
direcciones virtuales del proceso y todos sus recursos (credenciales, archivos abiertos, etc).
Cada hilo de usuario tiene asignada una pila de usuario, que es una estructura que contiene los
marcos de pila de las funciones invocadas por el hilo durante su ejecución en modo usuario. Además
también es necesario mantener, entre otros, los siguientes datos de cada hilo de usuario :
•
Identificador del hilo de usuario. Es un número entero positivo que identifica de manera univoca a
un hilo de usuario dentro de un proceso.
•
Contexto hardware salvado en modo usuario. Son los valores que contenían los registros del
computador cuando se interrumpió la ejecución del hilo en modo usuario debido a una llamada
al sistema o a un cambio de hilo. El contexto hardware en modo usuario será restaurado cuando se
continúe con la ej ecución del hilo en modo usuario.
•
Prioridad. Es consultada por el planificador implementado a nivel de la librería de hilos, si existe
alguno.
52
Ampliación de sistemas operativos
•
Máscara de señales. Especifica el tratamiento que se realizará cuando llegue una determinada
señal (ver sección 2 . 3 . 3 ) .
La pila d e usuario y la información asociada a u n hilo d e usuario e s mantenida e n e l espacio de
direcciones del proceso por la librería de hilos de usuario.
Estructuras asociadas a los procesos ligeros
Los S OBUNIX que soportan procesos ligeros deben mantener en el espacio de direcciones del núcleo
una estructura de datos por cada uno de los procesos ligeros en que se descompone un proceso. Dicha
estructura, denominada lwp en algunos SOBUNIX, contiene entre otros los siguientes datos: contexto
hardware salvado en modo usuario, un puntero a la estructura proc del proceso del que forma parte, un
puntero al hilo del núcleo que tiene asociado, información estadística de uso de recursos e información
sobre el tratamiento de señales.
Nótese que un proceso ligero no tiene asignado un identificador numérico, esto es así porque real­
mente no le hace falta ya que queda identificado por el hilo del núcleo al que está asociado, el cual si
tiene asignado un identificador numérico, como se verá en la siguiente subsección.
Recuérdese también que es la librería de hilos la que asocia un proceso ligero a un determinado hilo
de usuario. Por otra parte es el núcleo el que asocia un hilo del núcleo a dicho proceso ligero.
Estructuras asociadas a los hilos del núcleo
En los SOBUNIX que soportan hilos del núcleo el sistema operativo debe mantener en su espacio de
direcciones una estructura de datos y una pila del núcleo por cada hilo del núcleo. La estructura de datos
asociada a un hilo del núcleo contiene la siguiente información:
•
Identificador del hilo núcleo. Es un número entero positivo que identifica de manera univoca a
cada hilo del núcleo.
•
Contexto hardware salvado. Son los valores que contenían los registros del computador cuando se
interrumpió la ejecución del hilo del núcleo debido a un cambio de contexto. El contexto hardware
será restaurado cuando el hilo del núcleo vuelva a ser planificado y se continúe con la ejecución
del hilo.
•
Parámetros de planificación. Es la información que utiliza el planificador del núcleo para decidir
qué hilo del núcleo planificar, como por ejemplo, la prioridad de planificación del hilo o el tiempo
de uso del procesador.
•
Punteros para implementar diferentes colas de hilos del núcleo. Como colas de hilos preparados
para ejecución, colas de hilos dormidos, etc.
•
Puntero a la pila del núcleo asociada al hilo.
SOBUNIX : implementación y control de procesos multihilos
•
53
Información sobre el proceso ligero asociado. Como por ejemplo un puntero a la estructura lwp
del proceso ligero al que está asociado y un puntero a la estructura pro e del proceso del que forma
parte el proceso ligero. Si el hilo del núcleo no está asociado a ningún proceso ligero, entonces
estos punteros contienen valores NULL.
Por su parte, una pila del núcleo es una estructura que contiene los marcos de pila de las funciones
invocadas por el hilo durante su ejecución en modo núcleo. Está pila está vacía cuando el hilo del núcleo
se ejecuta en modo usuario.
e
Ejemplo 2.2
El sistema operativo Solaris 1 0 soporta un modelo de proceso multihilo en el que cada hilo de usua­
rio tiene asociado un proceso ligero (ver Figura 2. 1 b) . El núcleo para implementar este modelo utiliza
principalmente las siguientes estructuras de datos:
•
Estructura proc. Se utiliza para implementar una entrada de la tabla de procesos. Algunos de los
campos presentes en una estructura proc son :
- p_exe c . Puntero al nodo-v del archivo ejecutable a partir del cual se creó el espacio de
direcciones virtuales del proceso.
- p_a s . Puntero a una estructura que contiene información sobre la ubicación del espacio de
direcciones virtuales del proceso.
- p_c red. Puntero a una estructura que contiene los credenciales del proceso .
- p_s t a t . Contiene e l estado del proceso. E n un determinado instante d e tiempo e l estado de
un proceso puede tomar uno de los siguientes valores:
o
S I DL (creado). Estado inicial de un proceso mientras está siendo creado.
o
SRUN (preparado para ejecución). El proceso se encuentra preparado para ser planifica­
do.
o
SONPROC (ejecutándose). El proceso está siendo ejecutado en un procesador.
o
SSLEEP (dormido). El proceso se encuentra dormido a la espera de que ocurra un deter­
minado evento, por ejemplo, que se complete una operación de E/ S .
o
S STOP (parado). La ejecución del proceso h a sido detenida por u n depurador de proce­
sos.
o
S Z OMB (zombi) . El proceso ha terminado.
Si un proceso únicamente consta de un único hilo de usuario entonces el estado del proceso
coincide con el estado del hilo de usuario, el cual queda definido por el estado del hilo del
núcleo asociado al proceso ligero del hilo de usuario.
Si se tiene un proceso multihilo, cada hilo puede encontrarse en un estado distinto . En es­
te caso el estado del proceso se fij a al de un hilo del núcleo asociado a un proceso ligero
representativo del proceso seleccionado por el núcleo.
54
Ampliación de sistemas operativos
- p__pp id. PID del proceso padre.
- Información genealógica del proceso. Se implementa mediante punteros a las estructuras
proc de algunos familiares del proceso: puntero al proceso padre ( * p__parent ) , puntero al
primer proceso hijo ( * P_chi l d) , puntero al último proceso hijo ( * P_chi l d_ns ), puntero al
siguiente proceso hermano ( * p_s ibl i ng ) , etc.
- p_s e s sp . Puntero a una estructura que almacena información sobre la sesión de trabaj o del
terminal al que pertenece el proceso (ver sección 2.3.5).
- p__p i dp. Puntero a una estructura que almacena el PID del proceso y otras informaciones
relacionadas .
- p__pgp i dp. Puntero a una estructura que almacena el identificador del grupo de procesos (ver
sección 2.3.5) y otras informaciones relacionadas.
- Información sobre los procesos ligeros asociados al proceso. Como por ejemplo el núme­
ro total de procesos ligeros asociados al proceso (p_lwpcnt ) , el número de procesos lige­
ros bloqueados (p_lwpb l o c ked) , el número de procesos ligeros preparados para ejecución
(p_lwprcnt ) , etc.
- uarea. Puntero al área-u la cual se implementa mediante una estructura u s e r . Contiene,
entre otros, los siguientes datos: puntero a la tabla de descriptores de archivos abiertos, los
argumentos pasados a la función principal ma i n del código del proceso, los argumentos de
la llamada al sistema exec y las variables de entorno.
- Campos para soportar el sistema de archivos procfs.
•
Estructura kl wp . Se utiliza para almacenar información sobre un proceso ligero. Entre la infor­
mación almacenada se encuentra la siguiente: uso de recursos, contexto hardware salvado, infor­
mación para el tratamiento de señales, puntero a la estructura proc del proceso al que pertene­
ce, puntero al hilo del núcleo asociado kthread y campos para soportar el sistema de archivos
proc f s .
•
Estructura kthread. Se utiliza para almacenar información sobre un hilo del núcleo. Algunos de
los campos presentes en esta estructura son:
- t_s tack. Puntero a la pila del núcleo asociada al hilo del núcleo.
- p_s t a t . Contiene el estado del hilo del núcleo. En un determinado instante de tiempo el
estado de un hilo del núcleo puede tomar uno de los siguientes valores (ver Figura 2.2):
o
TS_RUN (preparado para ejecución). El hilo del núcleo se encuentra preparado para ser
planificado.
o
TS_ONPROC (ejecutándose). El hilo del núcleo está siendo ejecutado en un procesador.
o
TS_SLEEP (dormido). El hilo del núcleo se encuentra dormido a la espera de que ocurra
un determinado evento, por ejemplo, que se complete una operación de E/ S .
SOBUNIX: implementación y control de procesos multihilos
Detener ej ecución
55
Ej ecución
finalizada
Continuar
Asignación
del hilo
Figura 2.2 - Diagrama de transición de estados de los hilos del núcleo en Solaris
o
TS_STOPPED (parado). La ejecución del hilo del núcleo ha sido detenida, seguramente
por un depurador.
o
TS_Z OMB (zombi). El hilo del núcleo ha terminado, pero sus datos se encuentran disponi­
bles todavía para ser leídos por los hilos encargados de recopilar información estadística
sobre el uso de recursos. Posteriormente, el hilo será recolectado por el núcleo para
formar parte de la lista de hilos del núcleo libres.
o
TS_FREE (libre) . La estructura del hilo del núcleo se encuentra disponible para ser asig­
nada a un proceso ligero o para la realización de funciones internas del núcleo. En con­
secuencia las estructuras de datos de un hilo del núcleo son reutilizadas, ahorrándose
por tanto su tiempo de su creación.
t_pr i . Prioridad de planificación del hilo del núcleo.
t_t id. Identificador numérico del hilo del núcleo.
t_lwp . Puntero a la estructura klwp del proceso ligero al que estás asociado. Si no está
asociado a ninguno, como cuando ejecuta tareas del núcleo, entonces contiene el valor NULL.
- t_procp. Puntero a la estructura proc del proceso al que estás asociado a través de un
proceso ligero. Si no está asociado a ninguno entonces contiene el valor NULL.
- t_l ink. Punteros a estructuras kthread para implementar diferentes colas de hilos del
núcleo: preparados para ejecución, dormidos y libres.
- t_next . Puntero a la siguiente estructura kthread de la lista global de hilos del núcleo. El
núcleo mantiene una lista enlazada con todos los hilos del núcleo existentes.
- t_prev. Puntero a la anterior estructura kthread de la lista global de hilos del núcleo.
56
Ampliación de sistemas operativos
En la Figura 2.3 se muestra la relación entre las estructuras de datos del núcleo de S olaris asociadas a los
procesos, a los procesos ligeros y a los hilos del núcleo, que han sido descritas en los párrafos anteriores .
Se ha considerado a modo de ej emplo un proceso A que consta de dos hilos de usuario y un proceso B
monohilo. Cada hilo de usuario tiene asociado en el núcleo un proceso ligero . A su vez cada proceso
ligero tiene asociado un hilo del núcleo de la lista global de hilos del núcleo. Señalar la existencia de
hilos del núcleo que no están asociados a ningún proceso ligero. Dichos hi los del núcleo pueden estar
libres o asociados a la ej ecución de funciones del núcleo .
En S olaris la información sobre un determinado hilo de usuario es mantenida a nivel de la librería de
hilos en una estructura u lwp . Esta estructura contiene la pila de usuario, información para la política
de planificación a nivel de hilos de usuario (si existe alguna definida), mecanismos de sincronización y
máscaras de señales.
Otra estructura de datos importante en la implementación del modelo de proceso multihilo es uberda ta.
La librería de hilos crea una estructura uberda t a por cada proceso. En ella almacena la información
necesaria para gestionar y acceder a los datos de todos los hilos de usuario asociados a un proceso.
•
2.3.
Control de procesos multihilos en SOBUNIX
2.3.1.
Creación de procesos e invocación de otros programas
La llamada al sistema
fork
En los SOBUNIX la creación de un proceso se realiza generalmente invocando a la llamada al sistema
f ork. Al proceso que invoca a f ork se le denomina proceso padre y al nuevo proceso que se crea se
le denomina proceso hijo. El proceso hijo recién creado es un copia prácticamente idéntica del proceso
padre y comparte el acceso a todos sus recursos.
La única diferencia entre el proceso hijo recién creado y el proceso padre se encuentra en algunos
campos de su estructura p r o c , es decir, de su entrada de la tabla de procesos . Por ejemplo, el PID del
proceso hij o es distinto del PID del proceso padre. Además, los campos asociados al uso de recursos
tienen que ser configurados a O. También los punteros para mantener la información genealógica tienen
que ser adaptados adecuadamente tanto en la estructura proc del padre como en la estructura del hijo.
El espacio de direcciones virtuales del proceso hij o recién creado es una copia del espacio de di­
recciones del proceso padre. Por lo tanto ambos ej ecutan el mismo programa pero en espacios indepen­
dientes . Esto significa que los cambios que realice el proceso padre en las variables de su espacio de
direcciones no afectan a los valores de las variables del espacio de direcciones del proceso hijo y vice­
versa. De hecho esta característica es un mecanismo de protección característico de los SOBUNIX . Un
proceso no puede acceder al espacio de direcciones de otro proceso, salvo que ambos compartan una
región de memoria compartida.
Para poder diferenciar, desde el punto de vista del usuario, que proceso se ej ecuta, f o rk devuelve
cuando finaliza el valor O al proceso hijo y el PID del proceso hijo al proceso padre. Es el planificador
SOBUNIX: implementación y control de procesos multihilos
57
Lista global de hilos
del núcleo
p ro e
p ro e
·- - - - - - - - - - - - - - - - - -
Figura 2.3
-
Relación entre las estructuras de datos del núcleo de Solaris para el soporte de procesos
multihilos
del núcleo el que determina si debe continuar ejecutándose el proceso padre o debe iniciarse la ejecución
del proceso hijo.
e
Ejemplo 2.3
Considérese el programa prog2 1 cuyo código en lenguaje C se muestra en la Figura 2.4. Este archivo
puede ser compilado en un SOB UNIX usando por ejemplo el compilador gcc del proyecto GNU, para
ello se puede teclear, la siguiente orden desde un intérprete de comandos:
gcc - o prog2 1 prog2 1 . c
Para ejecutar el programa compilado prog2 1 se debe escribir la siguiente orden:
prog2 1
58
Ampliación de sistemas operativos
rna i n ( )
{
int y ,
x=O ;
y= f o rk ( ) ;
if
( y= = - 1 ) {
p r i n t f ( " \nErro r " ) ;
else i f
( y= = O ) {
p r i n t f ( " \ nSoy e l h i j o P I D= %d ,
mi padre t i en e P I D= %d " , g e tp i d ( ) , g e tpp i d ( ) ) ;
x=x+ 1 ;
p r i n t f ( " \ nx= %d " , x ) ;
else {
p r i n t f ( " \ nSoy e l padre P I D= %d " , g e tp i d ( ) ) ;
x=x- 1 ;
p r i n t f ( " \ nx= %d " , x ) ;
p r i n t f ( " \ nF in " ) ;
Figura 2.4 - Código C del programa prog2 1
Nótese que para ejecutar esta orden con éxito en la variable de entorno PATH debe estar incluido el
directorio de trabajo actual. Si no es así se puede incluir escribiendo en el intérprete la siguiente orden :
PATH= $ PATH : .
S upóngase que para ejecutar el programa prog2 1 el intérprete crea el proceso A con un PID igual a 2343 .
Cuando se ejecuta este proceso en primer lugar se invoca a la llamada al sistema f o rk. Si se produjese
algún error durante el tratamiento por parte del núcleo de esta llamada al sistema, f o r k devolvería el
valor - l . Luego la condición del i f se cumpliría y se imprimiría en la salida estándar (la pantalla por
defecto) el mensaje Error. A continuación se imprimiría el mensaje F i n y la ej ecución del proceso A
finalizaría.
Si f ork se ejecuta con éxito se crea un nuevo proceso B . Se va a suponer que su PID es igual 2344.
Puesto que A y B tienen el mismo código, para distinguir su ejecución fork devuelve O al proceso hijo
y el PID del hijo al proceso padre.
S upóngase que el planificador planifica primero al proceso hij o B . En ese caso la variable y= O luego el
proceso B ejecuta el conjunto de instrucciones del bloque e l s e i f . Señalar que las funciones getpid
y g e tpp i d son llamadas al sistema que permiten obtener el PID de un proceso y el PID de su proceso
padre, respectivamente. Así en primer lugar se imprime en pantalla el mensaje:
S oy e l h i j o P I D = 2 3 4 4 , mi padre t i ene P I D= 2 3 4 3
A continuación el proceso B suma 1 a la variable x y almacena su valor en l a misma posición de memoria.
SOBUNIX: implementación y control de procesos multihilos
59
Finalmente se muestra en la pantalla el valor de x (en este caso 1) y el mensaje F in, y el proceso B
finaliza.
Supóngase que finalizado el proceso hijo B se planifica para ej ecución el proceso A. En este caso la
variable y contiene el valor 2344, es decir, el PID del proceso hijo, luego el proceso A ejecuta el conjunto
de instrucciones del bloque el s e . Así en primer lugar se imprime en pantalla el mensaj e :
Soy e l padre P I D = 2 3 4 3
A continuación el proceso resta 1 a la variable x y almacena su valor en la misma posición de memoria.
Finalmente se muestra en la salida estándar el valor de x (en este caso - 1 ) y el mensaj e F in, y el proceso
A finaliza.
Nótese que el proceso padre y el proceso hijo tienen espacios de direcciones idénticos pero indepen­
dientes. Luego los cambios que realice el proceso hij o en sus variables no afectan a los valores de las
variables homónimas del proceso padre y viceversa.
•
Las acciones que realiza la rutina del núcleo que se encarga de tratar la llamada al sistema fork
dependen de cada SOBUNIX, pero en general suele realizar las siguientes acciones [Vahalia, 1 995] :
•
Asignar una entrada de la tabla de procesos al proceso hijo, es decir, una estructura pro c .
•
Rellenar los campos d e l a estructura proc del proceso hij o a partir de l a información contenida en
la estructura proc del proceso padre.
•
Crear el área-u del proceso hij o a partir del área-u del proceso padre.
•
Asignar un PID al proceso hijo.
•
Crear el espacio de direcciones virtuales del proceso hij o a partir del espacio de direcciones del
proceso padre (ver sección 4.2.7).
•
Crear las referencias oportunas a los recursos compartidos con el proceso padre, como por ejemplo
los archivos abiertos y el directorio de trabaj o actual.
•
Inicializar el contexto hardware del proceso hijo con una copia del contexto hardware del proceso
padre para poder iniciar la ejecución del proceso hij o cuando éste sea planificado.
•
Configurar el estado del proceso a preparado para ejecución y colocarlo en alguna cola de planifi­
cación en función de su prioridad.
La llamada al sistema exe c
El proceso hijo creado por f ork ejecuta el mismo código que el proceso padre. Disponer de diferen­
tes instancias de un mismo programa resulta útil en el diseño de algunas aplicaciones, como por ejemplo,
60
Ampliación de sistemas operativos
aquellas con un esquema cliente-servidor. En otras aplicaciones interesa, sin embargo, que el proceso
hijo ej ecute un programa distinto al proceso padre. Un ej emplo típico de este caso es un intérprete de
comandos, desde el cual se invocan a otros programas .
En los S OBUNIX un proceso puede invocar a otro programa haciendo uso de la llamada al sistema
exe c . Esta llamada al sistema básicamente reemplaza las regiones del espacio de direcciones del proceso
invocador por las regiones del programa invocado. Luego cuando finaliza la llamada al sistema exec el
proceso invocador pasa a ej ecutar el código del programa invocado.
La llamada al sistema exec se utiliza en colaboración con la llamada al sistema f ork. Por ejemplo,
cuando un usuario invoca un cierto programa ej ecutable desde la línea de órdenes de un intérprete de
comandos, éste crea un proceso hij o invocando a f o rk y a continuación invoca a la llamada al sistema
exec para que el proceso hijo ejecute el programa invocado.
La llamada al sistema exec puede ser invocada a través de diferentes funciones de envoltura como
por ej emplo: exe c l , execv y exe c l e . La principal diferencia entre todas ellas radica en el número y
tipo de sus argumentos de entrada. Se distinguen tres tipos de argumentos posibles : el nombre de ruta del
archivo ejecutable, los argumentos del programa invocado especificado cada uno como un puntero a una
cadena de caracteres y el entorno que es un array de punteros a cadenas de caracteres. A cada cadena se
le conoce con el nombre de variable de entorno (ver sección 1 .5 . 1 ) .
e
Ejemplo 2.4
Considérense los archivos ejecutables prog2 2 y prog2 3 (ver Figura 2.5). S upóngase que prog2 2 es
invocado desde la línea de órdenes de un intérprete de comandos y que el intérprete crea un proceso A
para ejecutar este programa. En primer lugar el proceso A invoca una llamada al sistema f o rk. Supuesto
que la llamada se ejecuta con éxito se crea un proceso B hij o de A. Qué proceso se planificará primero,
el padre o el hijo, dependerá del planificador.
/ * C ó d i g o de prog2 2 * /
ma i n ( )
{
i f ( f o rk ( } = = 0 )
{
execv ( " prog 3 " , 0 ) ;
p r i n t f ( " \ n men s a j e l " ) ;
p r i n t f ( " \ n mens a j e 2 " ) ;
/ * C ó d i g o de prog2 3 * /
ma i n ( )
{
p r i n t f ( " \ n men s a j e 3 " ) ;
Figura 2.5 - Código C de los programas prog2 2
y
prog2 3
SOBUNIX: implementación y control de procesos multihilos
61
Se va a suponer que se ejecuta primero el proceso padre. En dicho caso, después de f ork el proceso A
evalúa la condición del i f . Como la llamada al sistema devuelve al proceso padre el PID del proceso
hijo, la condición del i f no se cumple por lo que imprime en la salida estándar men s a j e2 y finaliza su
ejecución.
Cuando se planifica el proceso B, éste evalúa la condición del i f . Como fork devuelve O al proceso
hijo, sí se cumple la condición por lo que invoca a la llamada al sistema execv. Esta llamada tiene dos
parámetros de entrada el nombre de ruta del archivo ejecutable, en este caso prog2 3 , y los argumentos
que se pasan al ejecutable, en este caso ninguno. Al atenderse esta llamada al sistema el espacio de
direcciones del proceso B es sustituido por el espacio de direcciones construido a partir de prog2 3 .
Luego, el código del proceso B pasa a ser el de prog2 3 . En consecuencia, el proceso B imprime en la
salida estándar men s a j e3 y finaliza su ejecución.
•
Las acciones que realiza la función del núcleo que se encarga de tratar la llamada al sistema exec
dependen de cada SOBUNIX, pero en general suele realizar las siguientes acciones [Vahalia, 1 995] :
•
Localizar el archivo ej ecutable del programa invocado.
•
Consultar la máscara de modo del archivo para verificar que el proceso dispone de permiso de
ejecución.
•
Leer la cabecera del archivo para comprobar si se trata efectivamente de un archivo ejecutable y
de que tipo. Si detecta que se trata de un shell script entonces invoca a un intérprete de comandos
para que lo ejecute.
•
Configurar el valor de los identificadores efectivos EUID y EGID, de acuerdo con la activación o
no de los bits S_I SUID o S_I SGID de la máscara de modo del archivo ejecutable.
•
Copiar los argumentos y el entorno en el espacio del núcleo.
•
Liberar el espacio de direcciones del proceso.
•
Asignar el nuevo espacio de direcciones del proceso a partir del archivo ejecutable del programa
invocado.
•
Copiar los argumentos y el entorno en la pila de usuario.
•
B orrar las direcciones de los manejadores de las señales y configurar su tratamiento a las acciones
por defecto.
•
Inicializar el contexto hardware salvado del proceso para que el proceso pueda comenzar cuando
vuelva de la llamada al sistema con la ejecución del programa invocado.
62
Ampliación de sistemas operativos
La llamada al sistema vfork
En los primeros SOBUNIX durante el tratamiento de f ork se duplicaban la mayoría de las páginas
del proceso padre cargadas en memoria para que el proceso hij o dispusiera de una copia de las mismas,
independiente de si el proceso hijo las iba a utilizar o no. Esto suponía un desperdició tanto de espacio
en memoria como de tiempo de uso del procesador.
Posteriormente, para evitar este duplicado innecesario de páginas los SOBUNIX comenzaron a im­
plementar la técnica de copiar al escribir ( copy on write) que consiste en aplazar la copia de una página
del proceso padre hasta que el proceso hijo tiene que escribir en la página. Señalar que esta estrategia no
se aplica sobre las páginas pertenecientes a la región de código o las regiones de memoria compartida
del proceso padre, ya que para este tipo de regiones solo se mantiene en la memoria principal una única
copia de la página, la cual es compartida por el proceso padre y sus procesos hijos.
Otra posible solución al problema del duplicado de páginas consiste en usar la llamada al sistema
v f ork. Esta llamada, introducida en el sistema BSD y posteriormente exportada a otros SOBUNIX,
bloquea al proceso padre y presta su espacio de direcciones al proceso hij o. Cuando el hij o invoca a otro
programa con exec o termina su ejecución entonces el espacio de direcciones es devuelto al proceso
padre y éste es desbloqueado.
La llamada vf ork es mucho más rápida que f o rk ya que se ahorra los pasos de configurar un nuevo
espacio de direcciones para el proceso hijo. En consecuencia, está llamada resulta muy útil cuando el
proceso hijo que se crea va a invocar posteriormente a la llamada exec para ej ecutar otro programa.
Consideraciones sobre el diseño de
fork
en procesos multihilos
En un proceso multihilo la invocación de una llamada al sistema fork es realizada por alguno de los
procesos ligeros en que se descompone el proceso. A la hora de tratar esta llamada por parte del núcleo
se plantean dos posibles opciones :
e
•
Duplicar en el proceso hijo todos los procesos ligeros del proceso. Esta opción resulta más conve­
niente cuando el proceso hij o que se crea no va a invocar posteriormente a la llamada exe c para
ejecutar otro programa. Su implementación presenta problemas asociados con el comportamiento
que deben tener los procesos ligeros del proceso hij o que sean duplicados a partir de procesos
ligeros del proceso padre que estuvieran bloqueados en espera de algún evento.
•
Duplicar en el proceso hijo solo el procesos ligero que invocó a f ork. Esta opción resulta más
conveniente cuando el proceso hijo que se crea va a invocar posteriormente a la llamada exec para
ejecutar otro programa. Su implementación puede presentar problemas asociados con la sincroni­
zación de hilos y con el soporte de la librería de hilos.
Ejemplo 2.5
S upóngase que la ejecución de un proceso A se ha descompuesto en dos procesos ligeros A l y A2. El
proceso ligero A l ha realizado una cierta llamada al sistema y se encuentra bloqueado a la espera de
recibir una entrada desde el teclado. Por su parte el proceso ligero A2 invoca a una llamada al sistema
SOBUNIX: implementación y control de procesos multihilos
63
f ork. Supóngase que esta llamada al sistema duplica todos los procesos ligeros del proceso padre. En
dicho caso se crea un proceso B con dos procesos ligeros B 1 y B2, que son duplicados de A 1 y A2,
respectivamente.
El problema surge con el proceso ligero B 1 ya que competirá con A l por obtener la entrada del teclado
produciendo una condición de carrera.
•
e
Ejemplo 2.6
Supóngase que la ejecución de un proceso A se ha descompuesto en dos procesos ligeros Al y A2.
El proceso ligero Al ha realizado una operación wa i t_s em ( s ) (ver sección 3 . 3 .2) sobre un semáforo
binario S . Por su parte el proceso ligero A2 invoca a una llamada al sistema f o rk. Supóngase que esta
llamada al sistema duplica únicamente el proceso ligero del proceso padre que invoca la llamada al
sistema. En dicho caso se crea un proceso B con un proceso ligero B2, que es un duplicado de A2.
El problema surge si el proceso ligero B2 después de ej ecutar f o rk intenta adquirir el semáforo S ha­
ciendo una operación wa i t_s em ( s ) . Como no se ha duplicado en el proceso B el proceso ligero A l el
semáforo S nunca será liberado con una operación s i gnal_s em ( s ) y en consecuencia B2 se quedará
siempre bloqueado.
•
Puesto que es complicado diseñar una única llamada al sistema f o rk que trate adecuadamente ambas
posibilidades, los SOBUNIX suelen soportan diferentes variantes de f o rk. Por ej emplo, en S olaris f o rk
duplica únicamente el proceso ligero que invoca la llamada. Si se desean duplicar todos los procesos
ligeros del proceso padre se debe utilizar la llamada al sistema f o rka l l . Cada variante trata una de las
posibilidades e intenta resolver en la manera de lo posible los problemas que dicha opción puede plantear.
Por ejemplo, durante el tratamiento de la llamada f o rka l l si alguno de los procesos ligeros del proceso
padre estaba realizando una llamada al sistema ésta es interrumpida en el duplicado del proceso ligero
del proceso hijo. Recuérdese (ver sección 1 .5 . 3 ) que si una llamada al sistema es interrumpida retorna
devolviendo el valor - 1 y almacenando un error E INTR en la variable errno . La llamada al sistema
interrumpida puede ser reiniciada por el proceso ligero duplicado si lo considera necesario.
En general, el diseño de las llamadas al sistema en SOBUNIX que soportan hilos del núcleo debe
hacerse teniendo en cuenta si los efectos de una llamada deben aplicarse únicamente al proceso ligero in­
vocador o a todos los procesos ligeros del proceso. Además en ambos casos se debe respetar la semántica
del modelo tradicional de proceso monohilo.
2.3.2.
Terminación de procesos
En los SOBUNIX si un proceso A desea terminar su ej ecución debe invocar explícitamente a la
llamada al sistema exi t. Esta llamada tiene como argumento de entrada un número entero que es puesto
a disposición del proceso padre de A para que lo examine si así lo desea. Este número denominado
generalmente estatus de salida (exit status), permite al proceso hijo especificar al padre la causa por la
que finalizó de acuerdo con un criterio previamente establecido por el programador. Generalmente se
Ampliación de sistemas operativos
64
suele considerar que si el estatus de salida es igual a O entonces el proceso termino normalmente y sin
errores, mientras que el resto de valores se utilizan para especificar los diferentes errores o causas que
produjeron la terminación del proceso.
El sistema operativo también procede de forma implícita a la terminación de un proceso después de
ejecutar la última instrucción del proceso. En este caso el núcleo también configura a un determinado
valor del estatus de salida del proceso, dicho valor depende de cada SOBUNIX.
Asimismo la terminación de un proceso A también se puede producir si el proceso A recibe una
señal (ver sección 2 . 3 . 3 ) cuyo tratamiento especifique la finalización del proceso. En este caso el núcleo
configura el valor del estatus de salida con el número que identifica a la señal que originó la terminación
del proceso.
Independientemente del motivo de la terminación de un proceso, el sistema operativo realiza esta
tarea ej ecutando una rutina del núcleo denominada exi t ( ) en la mayoría de SOBUNIX. Las acciones
que realiza exi t ( ) depende de la implementación de dicha función en cada S OBUNIX. En general
exi t ( ) suele realizar, entre otras, las siguientes acciones [Vahalia, 1 995] :
•
Deshabilitar el tratamiento de las señales.
•
Cerrar los archivos abiertos por el proceso A.
•
Almacenar en la entrada de la tabla de proceso asignada al proceso A los datos estadísticos de uso
de recursos y el estatus de salida.
•
Poner al proceso A en el estado zombi.
•
Hacer que el proceso i n i t adopte a los procesos hijos del proceso A. Conviene señalar que cuando
se arranca un SOBUNIX se crean unos pocos procesos para realizar diferentes tareas asociadas al
arranque del sistema. Entre estos procesos se encuentra el proceso inicial o proceso i n i t cuyo PID
es igual a l . Este proceso se encarga de crear todos los demás procesos necesarios para inicializar
el sistema operativo. El proceso i n i t es el primer antepasado de todos los procesos existentes,
excepto aquellos creados por el sistema operativo al arrancar. Cuando un proceso termina si tiene
hijos activos éstos son adoptados por ini t, que ejerce de proceso padre.
•
Liberar los recursos de memoria asignados al proceso.
•
Enviar una señal S I GCHLD al proceso padre del proceso A para notificarle la terminación de su
hijo.
•
Despertar al proceso padre de A si éste estaba dormido esperando por la terminación de su hijo.
En algunas aplicaciones el proceso padre necesita saber cuándo un proceso hijo ha terminado su
ejecución. Un ejemplo típico es un intérprete de comandos cuya ejecución está asociada a un cierto
proceso A. Si un usuario teclea un comando externo el proceso A crea (invocando a f ork) un proceso
hij o B y le asocia (mediante ex e e ) el código de dicho comando. A continuación ejecuta una determinada
llamada al sistema para entrar en el estado dormido a la espera de que termine su hijo. Cuando el proceso
SOBUNIX: implementación y control de procesos multihilos
65
B termine el proceso A será despertado por el núcleo y mostrará en la pantalla el apuntador del intérprete
para indicar al usuario que ya puede introducir otro comando.
Existen varias llamadas al sistema que permiten a un proceso esperar por la terminación de alguno de
sus proceso hijos, como por ejemplo : wa i t, wa i t 3 , wa i t 4 , wa i t p i d y wa i t i d. La principal diferencia
entre todas estas llamadas al sistema se encuentra en la información sobre el hij o que devuelve cada
llamada y en la posibilidad de especificar el hij o en concreto por el que se desea esperar.
e
Ejemplo 2.7
Supóngase que el programa prog2 4 (ver Figura 2.6) es invocado desde la línea de órdenes de un intér­
prete de comandos de la siguiente forma:
prog2 4 1 0
Supóngase además que a la ejecución de este programa se le asocia un proceso A . En primer lugar el
proceso A comprueba si la variable entera argc es igual a 2. En esta variable está almacenado el número
de argumentos pasados al programa por la línea de comandos. En este caso la condición se cumple ya
que el nombre del programa cuenta como primer argumento.
En segundo lugar invoca a la función de librería a t o i que convierte la cadena de caracteres argv [ 1 ]
en un número entero y almacena el resultado en la variable x . Como argv [ 1 ] contiene el segundo
argumento introducido por la línea de comandos entonces x = 1 O .
En tercer lugar comprueba si l a variable x es igual a 1 0. En caso afirmativo invoca a l a llamada al sistema
f ork para crear un proceso hijo B .
S e va a suponer que después de la llamada al sistema f o r k se continua con la ej ecución del proceso
padre. Entonces como f o rk devuelve al proceso padre el PID del proceso hijo no se cumplen las dos
ma in ( i nt argc ,
char
* argv ( ] )
{
i n t x = O , s = O , var = O ;
if
( argc = = 2 )
x = a t o i ( argv [ l ] ) ;
if
( x= = l O & &
f o rk ( ) = = O )
p r i n t f ( " \ n Pr o c e s o hi j o P I D= %d \ n " , g e tp i d ( ) ) ;
exi t ( 5 ) ;
s = wa i t ( &var ) ;
p r i n t f ( " \ n s= %d var= %d\ n " , s , var ) ;
e l s e p r i n t f ( " \ n Número de paráme t r o s i n c o r r e c t o \ n " ) ;
Figura 2.6 - Código C del programa prog2 4
66
Ampliación de sistemas operativos
condiciones del i f, luego la siguiente sentencia que ejecuta el proceso padre es una invocación de la
llamada al sistema wa i t. Esta llamada si se ejecuta con éxito devuelve en s el PID del primer hijo de
A en estado zombi que encuentra. Además almacena los ocho bits menos significativos del estatus de
salida en la dirección asociada a la variable var. Si el proceso A no tiene procesos hijos o si wa i t es
interrumpida por una señal, entonces se considera que se ha producido un error en la ejecución y la
llamada devuelve en s el valor - l .
El núcleo durante el tratamiento de una llamada al sistema wa i t borra la entrada de l a tabla de procesos
asociado al primer hijo en estado zombi que encuentra. En el caso de que el proceso A tenga procesos hi­
jos pero ninguno se encuentre en el estado zombi entonces pasa al proceso A al estado dormido mientras
espera por la terminación de alguno de sus hijos. Cuando alguno termine la función del núcleo exi t ( )
enviará al proceso A una señal S I GCHLD para notificárselo.
En este programa, supuesto que el proceso padre se ej ecuta antes que su hijo, durante el tratamiento de
wa i t el proceso A entra en el estado dormido ya que su proceso hij o no está todavía en el estado zombi.
Cuando el proceso B es planificado para ej ecución, supuesto que su PID= 3456, imprime en la salida
estándar el mensaje:
Pro c e s o hi j o P I D = 3 4 5 6
e invoca a la llamada al sistema exi t para terminar su ejecución. Nótese que el estatus de salida especi­
ficado por el proceso hijo es igual a 5 .
Durante e l tratamiento de l a llamada al sistema exi t s e despierta al proceso A. Éste al ser planificado
completa la llamada al sistema wa i t que almacena en la variable var el estatus de salida del proceso B
y en la variable s el PID del proceso B . Señalar que en realidad, debido a la implementación que hace
el núcleo de la llamada al sistema wa i t, en la variable var se almacena el estatus de salida especificado
como argumento de entrada de exi t multiplicado por 256, es decir, 256·5 = 1 280.
Por último el proceso A imprime en la salida estándar el mensaj e
s = 3 4 5 6 var = 1 2 8 0
y termina su ej ecución. Nótese que si el proceso hijo se hubiera planificado antes que el padre cuando
se tratara la llamada al sistema wa i t no hubiera hecho falta dormir al proceso A ya que el proceso B ya
estaría en el estado zombi.
Por otra parte, si el programa se hubiese invocado desde la línea de comandos de la forma
prog2 4 5
entonces el proceso hijo nunca se hubiera creado y la llamada a wa i t hubiera devuelto en s el valor - l .
En consecuencia el mensaje que se habría escrito en l a salida estándar sería:
s = - 1 var = O
•
SOBUNIX : implementación y control de procesos multihilos
2.3.3.
67
Notificación de eventos : señales
Descripción general
Las señales son un mecanismo implementado por el núcleo para la notificación de eventos a proce­
sos. Cada evento notificable tiene asociado una determinada señal. A su vez cada señal tiene asignado un
número entero positivo pequeño que la identifica de manera univoca. Además tiene asociada una cons­
tante simbólica que comienza con S IG y va seguida por una abreviatura o una palabra que resume el
evento al que está asociada. Cada S OBUNIX establece el número de señales que soporta, así como el
número entero y la constante simbólica que le asigna a cada una. En la Tabla 2. 1 se muestra a modo de
ejemplo algunas de las señales definidas en las especificaciones POSIX. Los programas que hacen uso
de señales POSIX tienen garantizada su portabilidad en todos los sistemas operativos que cumplan con
POS IX.
El núcleo envía una señal a un determinado proceso A cuando se produce algún evento que deba ser
notificado. Dicho evento puede estar causado por interrupciones, por la ejecución del propio proceso A
o por la ejecución de otro proceso B .
Efectivamente algunas interrupciones pueden producir que el núcleo envíe una señal a un proceso.
Señal
Acción por defecto
S I GABRT
S I GALRM
S I GCHLD
S I GCONT
S IGFPE
S IGILL
S I G INT
S I GKILL
S IGPI PE
S IGQUIT
S IGSEGV
S I GSTOP
S I GTERM
S I GTSTP
S I GTTIN
S I GTTOU
S IGUP
S I GUSRl
S I GUSR2
S I GXCPU
Abortar
Terminar
Ignorar
Continuar
Abortar
Abortar
Terminar
Terminar (*)
Terminar
Abortar
Abortar
Parar (*)
Terminar
Parar
Parar
Parar
Terminar
Terminar
Terminar
Abortar
Tabla 2.1
-
Evento asociado
Abortar un proceso
Alarma de tiempo real
Terminación o suspensión de un proceso
Continuar si estaba parado
Excepción de aritmética en coma flotante
Instrucción ilegal
Señal de interrupción procedente del teclado ( [ c ontro l ] + [ e ] )
Finalizar un proceso
Escritura en una tubería sin lectores
Señal de terminación procedente del teclado ([contro l ] + [ \ ] )
Referencia a una dirección de memoria ilegal
Parar proceso
Finalizar un proceso
Señal de parar procedente del teclado ( [ c ontro l ] + [ z ] )
Lectura del terminal por un proceso en segundo plano
Escritura en el terminal por un proceso en segundo plano
Desconexión del terminal
Señal definida por el usuario
Señal definida por el usuario
Excedido el tiempo de uso de CPU
Algunas señales definidas en POS IX. (*) La acción por defecto no puede ser modificada.
Ampliación de sistemas operativos
68
Por ejemplo, si se está ejecutando un proceso A en primer plano en un intérprete de comandos y el
usuario pulsa las teclas [cont r o l ] + [c ] se genera una interrupción hardware que al ser atendida por el
núcleo produce, entre otras acciones, el envío de una señal S I GINT al proceso A.
Otra de las principales fuentes de envío de señales es la ejecución de un proceso. Entre los principales
eventos asociados a la ejecución de un proceso que causan que el núcleo tenga que enviarle una señal a
dicho proceso se encuentran los siguientes :
•
Excepciones. Si durante la ejecución del proceso se produce por ejemplo una referencia a una
dirección de memoria no válida o se intenta ejecutar una instrucción ilegal, se producirá una ex­
cepción que al ser tratada por el núcleo producirá entre otras acciones el envío al proceso de una
señal. Las señales S IGFPE, S IGILL y S IGSEGV de la Tabla 2. 1 son ejemplos de señales asociadas
a excepciones.
•
Alarmas. Un proceso puede solicitar al núcleo, mediante la invocación de la llamada al sistema
adecuada, que le envíe una señal cuando haya transcurrido una cierta cantidad de tiempo. A este
mecanismo de aviso se le denomina alarma. Por ejemplo, usando la llamada al sistema a l arm
un proceso puede configurar una alarma de tiempo real, es decir, que el núcleo le envíe una señal
S I GALRM cuando hayan transcurrido un número determinado de segundos de tiempo real.
•
Cuotas. Si un proceso supera la cuota de uso de un recurso el núcleo se lo puede notificar mediante
el envío de una señal. Por ejemplo, si un proceso excede su tiempo de uso del procesador, el núcleo
le envía una señal S I GXC PU.
También, un proceso puede solicitar al núcleo, invocando la llamada al sistema oportuna, que envíe
una señal a un determinado proceso o incluso que se la envíe a si mismo. Por ejemplo, las llamadas al
sistema s i g s end y k i l l permiten enviar una determinada señal a un proceso o grupo de procesos (ver
sección 2 . 3 .5) determinado.
Una señal se considera que ha sido recibida o entregada, cuando se ejecuta la acción que se había
establecido ante la recepción de dicha señal. Existen seis posibles acciones :
•
Ignorar. La recepción de la señal no produce la realización de ninguna acción.
•
Terminar. Se finaliza la ejecución del proceso.
•
Abortar. Se crea en el directorio de trabajo actual un archivo donde se almacena información
(espacio de direcciones, contexto hardware, etc) sobre el proceso y a continuación se procede a la
terminación del proceso. El archivo creado, denominado c o r e en algunos SOBUNIX, puede ser
consultado por otros procesos, como por ejemplo, depuradores.
•
Parar. Se suspende la ejecución del proceso y éste pasa al estado parado. Esta acción es la que
se realiza por defecto cuando se recibe una señal S IGSTOP enviada al proceso por un depurador
o ante la recepción de la señal S IGTSTP generada por la pulsación de un usuario de las teclas
[contro l ] + [ z ] .
SOBUNIX: implementación y control de procesos multihilos
69
•
Continuar. Se pasa el proceso al estado preparado para ejecución para que pueda continuar con su
ej ecución cuando sea planificado. Se aplica únicamente si el proceso estaba en el estado parado.
Esta acción es la que se realiza por defecto cuando se recibe una señal S I GCONT .
•
Capturar. Se ejecuta una determinada función definida por el usuario. A dicha función se le deno­
mina manejador de la señal (signal handler) .
Cada señal tiene asociada por defecto una acción a realizar. Por ejemplo, la acción por defecto que
debe realizar el núcleo cuando un proceso reciba una señal S I GUSRl es terminar la ejecución del proceso
(ver Tabla 2. 1 ) . La información sobre la acción asociada a cada señal se almacena en una determinada
estructura de datos dentro del área-u del proceso. En esta estructura también se almacena las direcciones
de los manejadores de las señales que hayan sido especificados.
Un proceso puede configurar diferentes aspectos relativos a la recepción de las señales :
e
•
Especificar la acción asociada a la recepción de una señal. Un proceso puede especificar la acción
que se desea que se realice cuando reciba una determina señal, para ello debe invocar a la llamada
al sistema adecuada. Por ejemplo, se pueden usar las llamadas al sistema s i gna l , s i gac t i on o
s i gvec .
•
Bloquear la recepción de una señal. Un proceso también puede bloquear o enmascarar l a recep­
ción de una señal con objeto de proteger una sección crítica de su código. Para ello debe invocar una
llamada al sistema, como por ejemplo: s i g s e tma sk, s i gma sk y s i gbl o ck. El núcleo mantiene
al menos una mascara de señales bloqueadas por proceso que es un mapa de bits que permite con­
figurar el bloqueo o no de cada tipo de señal. Existen algunas señales especiales, como S IGSTOP
o S I GKILL, cuya recepción no puede ser bloqueada y cuya acción asignada por defecto tampoco
puede ser cambiada.
•
Esperar por la recepción de una señal. Un proceso puede quedarse suspendido a la espera de la
recepción de una señal que no tenga bloqueada o no ignore. Para ello debe invocar una llamada al
sistema, como por ej emplo, pau s e , s i gpau s e o s i g suspend.
Ejemplo 2.8
Supóngase que el programa prog2 5 (ver Figura 2.7) es invocado desde la línea de órdenes de un intér­
prete de comandos y que a la ejecución de este programa se le asocia un proceso A.
En primer lugar el proceso A invoca una llamada al sistema s i gna l . Esta llamada establece la acción
a realizar ante la recepción de una determinada señal. De forma general esta llamada tiene la siguiente
sintaxis :
s = s i gnal ( nombre_s eña l , a c c i ón_r e c epc i ón ) ;
nombre_s eña l es el número entero o la constante simbólica de la señal sobre la cual se desea especi­
ficar la acción a realizar. Por su parte a c c i ón_r e c epc i ón es un número entero o constante simbólica
70
Ampliación de sistemas operativos
# i n c l ude < s i gnal . h>
vo i d fun { i n t s i g ) ;
ma i n { )
{
int r l = O ,
r2 = 0 ;
s i gn a l { S I GUSR2 , fun ) ;
i f { f o rk { ) = = O )
/ * Pr o c e s o h i j o * /
{
s l e ep { 3 ) ;
p r i n t f { " \ n Env i o s eñ a l a mi padre " ) ;
k i l l { ge tpp i d { ) , S I GUSR2 ) ;
e l s e / * Pr o c e s o padr e * /
{
r l = s l e ep ( 7 ) ;
r 2 = s l e ep ( l ) ;
p r i n t f { " \ n r l= %d r 2 = %d \ n " , r l , r 2 ) ;
vo i d fun { i n t s i g )
s l e ep { l ) ;
p r i n t f { " \ n Rec ibo s eñ a l de mi h i j o " ) ;
Figura 2. 7
-
Código C del programa prog2 5
asociada a la acción a realizar al recibir la señal. Puede tomar dos posibles valores : S I G_DFL o o que es­
pecifica que la acción a realizar es la establecida por defecto y S I G_IGN o 1 que especifica que la acción
a realizar es ignorar la señal. También ac c i ón_r e c epc i ón puede ser la dirección de un manej ador de
señal, con lo que se estaría especificando que la acción a realizar es capturar la señal.
Si la llamada se ejecuta con éxito, entonces en s se devuelve la acción que se tenía asignada a la recepción
de la señal antes de ejecutar esta llamada. En caso de error en s se devuelve la constante S I G_ERR
asociada al valor - l .
En el caso de l a llamada s i gnal ( S IGUSR2 , fun ) que realiza el proceso A s e está estableciendo que
ante la recepción de una señal S IGUSR2 se ejecute el manej ador de la señal fun definido por el usuario.
En segundo lugar, el proceso A invoca a la llamada al sistema f ork para crear un proceso hijo. Supóngase
que el planificador planifica al proceso padre antes que al proceso hijo. Entonces el proceso A invoca
a la función s l eep de la librería l ibe que permite suspender la ejecución de un proceso durante un
determinado intervalo de tiempo especificado en segundos. En este caso la ej ecución del proceso A se
suspende durante 7 segundos.
Cuando se planifica el proceso hijo, éste en primer lugar invoca a la función s l eep para suspender su
SOBUNIX: implementación y control de procesos multihilos
71
ejecución durante 3 segundos. A continuación invoca a la función de librería print f para imprimir por
la salida estándar el texto:
Env i o s eña l a mi padre
Acto seguido invoca a la llamada al sistema k i 11 que permite enviar una señal a un determinado proceso
o conjunto de procesos. De forma general esta llamada tiene la siguiente sintaxis :
s =ki l l ( i d , nombre_s eña l ) ;
nombre_señal es el número entero o la constante simbólica de la señal que se va enviar. i d es un
número entero que identifica al proceso o grupo de procesos al que va dirigida la señal. Si i d es mayor
que O, la señal es enviada al proceso cuyo PID=id. Si i d es igual a O la señal es enviada a todos lo
procesos que pertenezcan al mismo grupo que el proceso que invoca la llamada. Si id es igual a - 1 ,
entonces la señal es enviada a todos los procesos cuyo UID sea igual al EUID del proceso que invoca la
llamada. En el caso de que el EUID sea el del superusuario entonces la llamada es enviada a todos los
procesos, excepto a los procesos con PID=O y con PID= l . Por último si id es menor de - 1 , entonces la
señal es enviada a todos los procesos cuyo identificador de grupo (ver sección 2.3.5) es igual a l i dl . Si la
llamada se ejecuta con éxito entonces en s se almacena un O. En caso de error se almacena el valor - 1 .
De acuerdo, con la explicación anterior el significado de la llamada ki 1 1 ( getpp i d ( ) , S I GUSR2 ) que
invoca el proceso hijo sería el de enviar la señal S I GUSR2 al proceso padre. Recuérdese que la llamada al
sistema getpp i d devuelve el PID del proceso padre del proceso que la invoca. Al retornar de la llamada
ki 1 1 el proceso hijo finaliza su ejecución.
Por su parte el envío de la señal S I GUSR2 hace que el núcleo despierte al proceso A antes de completar
sus 7 segundos de suspensión. Al ser planificado de nuevo el proceso A, se ejecuta el manej ador fun
definido para la señal S IGUSR2 . Este manejador realiza dos acciones. En primer lugar invoca a la función
de librería s l e ep para suspender la ejecución del proceso durante 1 segundo. A continuación invoca a
la función de librería p r i n t f que imprime por la salida estándar el texto
Rec ibo s eñal de mi h i j o
Finaliza la ejecución del manejador, se continúa con la ejecución de la instrucción del proceso A que
fue interrumpida por la recepción de la señal. Como s l e ep no se completó con éxito al ser interrumpida
por la señal, entonces devuelve en rl el tiempo de suspensión que le quedaba al proceso, en este caso
4 segundos. A continuación se invoca a otra función de librería s l e ep para suspender la ejecución del
proceso A durante 1 segundo. Como la función se ejecuta con éxito entonces en r2 se almacena el valor
O. Finalmente se invoca a la función de librería print f que imprime por la salida estándar el texto
r 1 = 4 r2 = 0
y finaliza la ejecución del proceso A .
•
72
Ampliación de sistemas operativos
# i n c l ude < s i gnal . h>
vo i d handl e r ( i n t s i g ) ;
ma i n ( )
{
s i gnal ( S I GUSRl , S IG_I GN ) ;
s i gnal ( S I GUSR2 , hand l e r ) ;
pau s e ( ) ;
p r i n t f { " \ n Mens a j e \ n " ) ;
vo i d handl e r ( i n t s i g )
p r i n t f ( " \ n Señal
%s capturada \ n " , s t r s i gn a l ( s i g ) ) ;
Figura 2.8 - Código C del programa prog2 6
e
Ejemplo 2.9
Supóngase que el programa prog2 6 (ver Figura 2.8 ) es invocado de la siguiente forma desde la línea de
órdenes de un intérprete de comandos:
prog2 6 &
El carácter '&' al final de la orden especifica al intérprete que el programa prog2 6 debe ser ejecutado en
segundo plano, con lo que el intérprete puede seguir recibiendo órdenes del usuario. Supóngase que para
ejecutar este programa el intérprete crea un proceso A con PID igual a 980.
En primer lugar el proceso A invoca una llamada al sistema s i gnal para especificar que la acción que se
realice cuando se reciba una señal S IGUSRl sea la de ignorar ( S I G_IGN) la señal. A continuación vuelve
a invocar una llamada al sistema s i gnal para especificar que la acción que se debe realizar cuando se
reciba una señal S IGUSR2 sea la de capturar la señal usando el manejador hand l e r .
A continuación invoca una llamada al sistema pau s e , la cual pasa al proceso al estado dormido a la
espera de recibir una señal que no ignore y que no tenga bloqueada.
Supóngase que se escribe la siguiente orden en la línea de comandos del intérprete:
k i l l - S IGUSRl 9 8 0
El comando k i l l permite enviar una señal a un proceso. En este caso se enviaría la señal S I GUSRl al
proceso con PID=980, es decir, al proceso A. Puesto que el proceso A ha especificado que esta señal
sea ignorada, el proceso A permanece a la espera de recibir una señal que no ignore o que no tenga
bloqueada. Se puede comprobar que el proceso A sigue ejecutándose haciendo uso del comando j obs o
del comando p s (ver sección 2.3 .6) .
Supóngase, ahora, que se escribe la siguiente orden:
SOBUNIX : implementación y control de procesos multihilos
73
ki l l - S IGKILL 9 8 0
En este caso se envía la señal S I GKILL al proceso A, cuya acción asignada a su recepción es la termina­
ción del proceso. Luego el proceso A termina.
Finalmente, supóngase que en vez de la orden anterior se hubiera escrito la siguiente orden:
ki l l - S IGUSR2 9 8 0
En este caso se envía la señal S IGUSR2 al proceso A, cuya acción asignada a su recepción es capturar
la señal ejecutando el manej ador handl er. Cuando se ejecuta este manejador se imprime en la salida
estándar el mensaje:
Señal User de f ined s i gnal 1 c apturada
Nótese que la función s t r s i gnal a la que se invoca en la función print f muestra un mensaje que
describe el tipo de señal, en este caso User de f ined s i gnal 1 para S I GUSRl . A continuación se
imprime en la salida estándar el texto Mens a j e y finaliza la ejecución del proceso A.
•
Una señal que ha sido enviada pero todavía no ha sido recibida se dice que está pendiente. El núcleo
mantiene una máscara de bits para especificar las señales pendientes de un proceso. También mantiene
una máscara de bits para especificar las señales ignoradas por el proceso.
El núcleo comprueba la existencia de señales pendientes de un proceso mediante la invocación de
una rutina del núcleo que en algunos SOBUNIX recibe el nombre de i s s i g ( ) . Esta función se invoca en
varios puntos del flujo de ejecución de un proceso: al retornar del tratamiento de una llamada al sistema,
al retornar del tratamiento de una interrupción hardware, una trampa o una excepción; y al despertar
(desbloquear) a un proceso.
La función i s s i g ( ) inspecciona la máscara de señales pendientes asociada al proceso. Además
consulta la máscara de señales bloqueadas y la máscara de señales ignoradas. Si encuentra una señal
que está pendiente que no sea ignorada y que no esté bloqueada entonces i s s i g ( ) finaliza su ejecución
devolviendo el valor TRUE . En dicho caso el núcleo invoca a otra rutina del núcleo, denominada p s i g ( )
en algunos SOBUNIX, para que ejecute la acción asociada a la recepción de la señal.
En el caso de que la acción asociada a la señal sea capturar la señal entonces p s i g ( ) invoca a
otra rutina del núcleo, denominada s ends i g ( ) en algunos SOBUNIX. Esta función manipula la pila
de usuario para que se pueda ejecutar el manejador de la señal cuando el proceso se ejecute en modo
usuario.
Una vez finalizada la ejecución del manej ador se continuará con la ejecución del código del proceso
justo desde la instrucción donde fue interrumpido por la señal. Si la señal produjo la interrupción de una
llamada al sistema entonces la llamada devuelve el valor - 1 y almacena en la variable errno el error
E INTR.
Nótese que la recepción de una señal por parte de un proceso requiere que dicho proceso sea planifi­
cado para ejecución. Luego desde que se produce un evento que debe ser notificado al proceso hasta que
74
Ampliación de sistemas operativos
el proceso recibe la señal puede transcurrir una cantidad importante de tiempo dependiendo del estado y
de la prioridad del proceso.
Consideraciones sobre la implementación de las señales en procesos multihilo
En la descripción general de las señales realizada en la sección anterior se ha supuesto por simplificar
que se tenía un proceso monohilo. En el caso de proceso multihilos una señal puede ser enviada a un
determinado hilo o a todos los hilos de un proceso. El escoger una opción u otra depende del evento al
que está asociada la señal.
Generalmente, si el evento al que está asociada una señal ha sido causado por un determinado hilo de
un proceso, lo más lógico es enviar la señal a dicho hilo y no a todos los hilos del proceso. Por ejemplo,
si durante la ejecución de un determinado hilo de un proceso A se ha producido una excepción, lo más
lógico es enviar la señal que notifica la excepción solamente a dicho hilo y no a todos los hilos del
proceso, sobre todo si la acción asociada a la recepción de la señal es la de terminar o abortar.
Por el contrario, si el evento está asociado a una interrupción externa no se puede asociar a un hilo
en particular y por ello lo lógico es enviar la señal a todos los hilos del proceso. Por ejemplo, si en
un intérprete de comandos se está ejecutando un proceso multihilo en primer plano y el usuario pulsa
las teclas [contro l ] + [c] para terminar la ejecución del proceso entonces se genera una interrupción
hardware que al ser tratada por el núcleo produce, entre otras acciones, el envío de la señal S I G INT cuya
acción asociada por defecto es la de terminar. Obviamente para terminar con la ejecución del proceso la
señal deberá ser enviada a todos los hilos del proceso no solamente a uno.
Otro aspecto importante a considerar en el caso de procesos multihilos está asociado con las estruc­
turas de datos que se deben mantener para implementar el mecanismo de señales. De acuerdo con la
descripción general de las señales se requiere por cada proceso al menos una estructura de datos para
mantener las acciones establecidas por cada señal y los manej adores de señales, una máscara de señales
pendientes, una máscara de señales ignoradas y una máscara de señales bloqueadas. En el caso de pro­
cesos multihilos surge la posibilidad de que cada hilo tenga sus propias estructuras de datos asociadas a
las señales o que todos los hilos compartan las mismas estructuras. La primera opción con respecto a la
segunda es más versátil aunque su gestión produce una mayor sobrecarga.
En general, se suele optar por una solución híbrida. Por una parte, la estructura de datos que mantiene
las acciones establecidas por cada señal y los manej adores de señales, así como la máscara de señales
pendientes y la máscara de señales ignoradas se implementan a nivel de proceso y son compartidas por
todos sus hilos. Mientras que la máscara de señales bloqueadas se implementa a nivel de hilo, es decir,
cada hilo dispone de su propia estructura.
e
Ejemplo 2. 10
En el Ejemplo 2.2 se describieron las principales estructuras de datos que implementan el modelo de pro­
ceso multihilo en Solaris. Cada proceso tiene asociada una estructura proc que implementa una entrada
de la tabla de procesos. Además tiene asociada una estructura denominada uarea que se implementa
dentro de la estructura pro c .
Cada hilo d e usuario existente e n u n proceso tiene asociado u n proceso ligero y u n hilo del núcleo. E l hilo
SOBUNIX: implementación y control de procesos multihilos
75
de usuario tiene asignada una estructura u lwp en el espacio de direcciones del proceso. Por su parte, el
proceso ligero tiene asignada una estructura klwp en el espacio de direcciones del núcleo. Allí también
se mantiene una estructura k thread por cada hilo del núcleo.
A continuación se enumeran algunos de los campos asociados al mecanismo de señales que contienen
estas estructuras :
•
Estructura proc.
- p_s ig. Máscara de señales pendientes. Se implementa como un mapa de 64 bits. Cada bit
está asociado a una señal. Si el bit se activa significa que la señal asociada está pendiente
para algún hilo del proceso. Nótese que en Solaris existen definidas 48 señales, luego en este
mapa existen 1 6 bits no asignados a ninguna señal.
- p_i gnor e . Máscara de señales ignoradas. Es un mapa de 64 bits que contiene un bit asociado
a cada señal. Si un bit se activa significa que la señal asociada es ignorada.
•
Estructura uarea.
- u_s ignal [ MAXS I G l . Establece las acciones a realizar al recibir cada señal. Cada entrada
puede contener alguno de los siguientes valores : S I G_IGN (si la señal es ignorada), S I G_DEF
(si se realiza la acción asignada por defecto) o la dirección del manejador definido para la
señal .
•
Estructura u lwp .
- u l_s i grna s k. Máscara de señales pendientes para el hilo.
•
Estructura klwp .
- lwp_cur s i g. Señal tratada actualmente.
•
Estructura kthread.
- p_s ig. Máscara de señales pendientes. Su contenido es idéntico al del campo homónimo de
la estructura pro c .
- p_ho l d. Máscara d e señales bloqueadas. E s u n mapa de 64 bits que contiene u n bit asociado
a cada señal. Si un bit se activa significa que la señal asociada está bloqueada.
Analizando la información enumerada se concluye que en el modelo de proceso multihilo de Solaris,
las acciones a realizar ante la recepción de una determina señal {u_s i gnal [ MAXS I G ] ) y la mascara de
señales ignoradas (p_i gno re) se mantienen a nivel de proceso, con lo que es compartida por todos los
hilos.
76
Ampliación de sistemas operativos
Por otra parte, la máscara de señales bloqueadas (p_h o l d) se mantiene a nivel de hilo, en concreto en
el hilo del núcleo. De esta forma cada hilo tiene la posibilidad de especificar las señales cuya recepción
desea bloquear.
La información sobre las señales pendientes se mantiene tanto a nivel de hilo como a nivel de proceso.
En la estructura ulwp se mantienen las señales pendientes para un determinado hilo. Mientras que en las
estructuras proc y kthread se duplica la misma información: la existencia de señales pendientes para
algún hilo del proceso. Esta duplicidad es necesaria para poder tratar de forma más eficiente todas las
situaciones en que se pueden generar señales.
•
2.3.4.
Control de hilos de usuario: librerías de hilos
En las secciones anteriores se han descrito los mecanismos de control de procesos en los SOBUNIX.
Dichos mecanismos han sido explicados en su mayor parte considerando procesos monohilos, aunque se
han realizado diferentes consideraciones asociadas al caso de los procesos multihilos. Queda sin embargo
comentar los mecanismos de control disponibles a nivel de los hilos de usuario. A este nivel los meca­
nismos de control son proporcionados por una librería de hilos, como por ejemplo la librería Pthreads
de POSIX escrita en lenguaje C .
L a librería Pthreads contiene diferentes funciones para la gestión de los hilos d e usuario: control,
sincronización, comunicación, planificación, etc. Cada hilo de usuario tiene asociado un número entero
positivo que lo identifica de forma univoca. Además tiene asociado una serie de atributos : inicialización,
tamaño y dirección de pila, herencia, parámetros y política de planificación, etc. El identificador numéri­
co del hilo de usuario se almacena en una estructura de datos p thread_t . Mientras que los atributos se
almacenan en una estructura de datos pthread_a t tr _t . Las estructuras anteriores y los prototipos de
las funciones incluidas en esta librería se encuentran disponibles en el archivo de cabecera p thread . h.
La librería Pthreads contiene, entre otras, las siguientes funciones para el control de los hilos de
usuario:
•
p thread_c r e a t . Crea un hilo de usuario para ejecutar una función determinada.
•
pthread_s e l f . Obtiene el identificador numérico asociado al hilo de usuario que ha invocado a
esta función.
•
pthread_exi t. Termina la ejecución del hilo de usuario que la ha invocado.
•
pthread_j o in. Suspende la ejecución del hilo de usuario que ha invocado a esta función hasta
que termine la ejecución de un determinado hilo de usuario.
•
pthread_k i l l . Permite enviar una determina señal a un determinado hilo de usuario.
Estas funciones suelen devolver un O si se ejecutan con éxito y un valor distinto de O en caso contrario.
SOBUNIX: implementación y control de procesos multihilos
77
# i nc lude < s t d i o . h>
# i nc lude <p thread . h>
vo i d * funl ( vo i d * i d ) ;
vo i d * fun2 ( vo i d * i d ) ;
rna i n ( )
/ * C ó d i g o de l h i l o 1
( h i l o principal } * /
{
p thread_t hu l , hu2 ;
p thre ad_c r e a t e ( &hu l ,
NULL ,
* funl ,
NULL ) ;
pthread_c rea t e ( &hu 2 ,
NULL ,
* fun2 ,
NULL ) ;
p thre ad_j o i n ( hu l ,
NULL ) ;
pthread_j o i n ( hu 2 ,
NULL ) ;
vo i d * funl ( vo i d * i d )
/ * C ó d i go d e l h i l o 2 * /
for ( ; ; ) ;
vo i d * fun2 ( vo i d * i d )
/ * C ó d i g o d e l hi l o 3 * /
int i = O ;
for ( i = O ; i < 4 ; i + + )
p r i n t f { " \ nMen s a j e 2 " ) ;
pthread_ex i t ( NULL ) ;
Figura 2.9 - Código C del programa prog2 7
e
Ejemplo 2. 1 1
Supóngase que e l programa prog2 7 (ver Figura 2.9) e s compilado con e l compilador g c c invocándolo
de la siguiente forma desde un intérprete de comandos:
g c c - o prog2 7 prog2 7 . c - lp thread
Si la orden se ejecuta con éxito se genera el archivo ejecutable prog2 7. La ejecución de este archivo
produce la creación de un proceso con tres hilos de usuario. El primer hilo de usuario se crea implíci­
tamente para ejecutar la función ma in. É ste se puede considerar como el hilo principal del proceso. La
terminación del hilo principal produce de forma implícita la terminación del proceso y en consecuencia
del resto de hilos del proceso. Afortunadamente es posible habilitar mecanismos de sincronización para
conseguir que el hilo principal termine solo cuando hayan terminado el resto de los hilos creados.
El segundo hilo se crea mediante la invocación por parte del hilo principal de la función
78
Ampliación de sistemas operativos
pthread_c rea t e ( &hu l , NULL ,
* funl , NULL ) ;
Se observa que esta función tiene cuatro argumentos. El primer argumento es la dirección de una estruc­
tura de tipo p thread_t donde se almacenará el identificador del hilo si la función se ejecuta con éxito.
En este caso dicha estructura se denomina hu l . El segundo argumento es la dirección de la estructura de
tipo pthread_at t r_t que contiene los valores de los atributos del hilo. En este caso al pasar un valor
NULL la librería se encarga de asignarle unos valores por defecto a los atributos del hilo. El tercer argu­
mento es un puntero a la función cuyo código ejecutará el hilo. En este caso el hilo ejecutará la función
fun l . Se observa que esta función ejecuta un bucle f o r infinito. El cuarto argumento es un puntero a
los argumentos de la función cuyo código ejecutará el hilo. En este caso al pasar un valor NULL se está
especificando que la función no requiere argumentos.
El tercer hilo se crea también mediante la invocación de p thread_create por parte del hilo principal.
El hilo creado ejecutará el código de la función fun2 que imprime cuatro veces Mens a j e 2 en la salida
estándar e invoca a la función p thread_exi t para terminar la ejecución del hilo. Nótese que dicha
función tiene como argumento un valor NULL. Eso significa que no hay que almacenar ningún valor
para que sea consultado por otro hilo que esté esperando por la terminación de este hilo en una función
pthread_j o in.
Posteriormente, el hilo principal invoca a la función
p thread_j o i n ( hu l , NULL )
para suspender su ejecución hasta que termine el primer hilo creado. Esta función tiene dos argumentos
de entrada. El primer argumento es el identificador del hilo por el que se desea esperar. En este caso se
trata del hilo cuyo identificador se encuentra almacenado en la estructura hu l . El segundo argumento es
un puntero al valor devuelto por el hilo por el que se está esperando. En este caso se pasa un valor NULL
luego se indica a la librería que no se desea conocer dicho valor.
Finalmente el hilo principal invoca otra vez a la función p thread_j o in pero esta vez para esperar por
la terminación del segundo hilo creado, cuyo identificador se encuentra almacenado en la estructura hu2 .
Supóngase un SOBUNIX con un hilo del núcleo por cada hilo de usuario, por ejemplo Solaris. S i el
archivo prog2 7 fuera lanzado en segundo plano
prog2 7 &
y a continuación se ejecutará el comando
ps - L
e n la salida estándar s e mostraría l a salida que s e incluye en l a Figura 2. 1 0. Se observa que la ejecución
de prog2 7 tiene asociado un proceso con PID= 1 3 1 3 cuya ejecución se descompone en tres procesos
ligeros (LWP) con identificadores 1 , 2 y 3. El proceso ligero 1 está asociado al hilo principal que ejecuta
el código de ma in. El proceso ligero 2 está asociado al primer hilo creado que ejecuta el código de fun l .
SOBUNIX: implementación y control de procesos multihilos
79
Por último el proceso ligero 3 está asociado al segundo hilo creado que ha ejecutado el código de fun2 y
que ya ha terminado (de func t). Recuérdese que en Solaris cada proceso ligero está asociado a un hilo
de usuario y a un hilo del núcleo.
PID
LWP TTY
LT IME CMD
9 64
1 pts / 3
0 : 0 0 bash
1313
1 pts / 3
0 : 0 0 prog2 7
1313
2 pts / 3
0 : 0 5 prog2 7
1313
3 pts / 3
0 : 0 0 <de func t>
1316
1 pts / 3
0 : 0 0 ps
Figura 2.10 - Salida del comando p s
-
L
en el Ej emplo 2. 1 1
•
2.3.5.
Grupos de procesos y sesiones
Terminales
Un terminal serie es un dispositivo de E/S orientado a carácter que consta de un teclado y de una
pantalla y que se comunica con el computador mediante una línea serie. En un terminal se trabaja con
una interfaz de línea de comandos implementada con un intérprete de comandos.
Los terminales serie se utilizaban en macrocomputadores y minicomputadores. Actualmente el ter­
minal serie como dispositivo hardware ha sido sustituido por computadores personales que disponen de
software para emular dichos terminales. Por ejemplo xt erm es una aplicación que trabaj a sobre X Win­
dow que emula un terminal en una ventana. Estos terminales emulados o pseudoterminales son bastante
utilizados por programadores y administradores del sistema.
Las operaciones de E/S con un terminal ya sea real o emulado se implementan como operaciones de
E/S sobre un archivo / dev / t ty [ i d ] donde [ i d ] es algún grupo de caracteres que permite distinguir
los diferentes terminales que pueden existir. El valor de [ i d ] depende de cada SOBUNIX.
Grupos de procesos
En los SOBUNIX los procesos son organizados en grupos de procesos. Cada grupo tiene asocia­
do un número entero positivo que lo identifica de manera univoca. A dicho identificador se le conoce
generalmente con el nombre de identificador del grupo de procesos (Process Group IDentifier, PGID).
Para conocer el PGID de un proceso se pueden usar las llamadas al sistema ge tpg i d y ge tpgrp o el
comando p s -j (ver sección 2 . 3 . 6).
Dentro de cada grupo de procesos puede existir un proceso el cual tiene asignado un PID que coincide
con el PGID del grupo, a dicho proceso se le denomina líder del grupo. Normalmente el resto de procesos
que pertenecen al grupo suelen ser los hijos del líder del grupo. Cuando se crea un proceso éste hereda el
PGID de su proceso padre. Luego todos los procesos con relación genealógica pertenecen por defecto al
80
Ampliación de sistemas operativos
mismo grupo de procesos. Para crear un nuevo grupo de procesos o para cambiar a un proceso de grupo
se pueden usar las llamadas al sistema s e tpgid y s e tpgrp.
De forma general un grupo de procesos puede ser creado por el núcleo o por una aplicación de usuario
para la realización de un determinado trabaj o o función. La existencia de grupos de procesos facilita el
envío de señales a todos los miembros del grupo, lo cual resulta de gran utilidad en ciertas aplicaciones.
e
Ejemplo 2. 12
La ejecución de un comando desde la línea de órdenes de un intérprete de comandos de un terminal puede
producir la creación de uno o varios procesos, todos ellos pertenecientes al mismo grupo. Recuérdese
que en el contexto de un intérprete de comandos a dicho grupo de procesos se le denomina trabajo o
tarea.
Si un proceso de un trabaj o en segundo plano intenta leer una entrada del terminal el núcleo envía una
señal S IGTT IN al grupo al que pertenece el proceso. Mientras que si intenta escribir en el terminal el
núcleo envía al grupo una señal S I GTTOU. La acción por defecto asociada a la recepción de estas señales
(ver Tabla 2. 1 ) es parar los procesos. Conviene señalar que algunos intérpretes de comandos hacen caso
omiso de la acción por defecto asociada a la señal S I GTTOU y permiten que un proceso de un trabaj o en
segundo plano pueda escribir en el terminal.
Por otra parte, si un usuario pulsa las teclas [ c ontro l ] + [ z l de un terminal se produce una interrupción
hardware que al ser atendida por el núcleo hace que éste, entre otras acciones, envíe al grupo de procesos
que forman el trabajo en primer plano una señal S IGTSTP cuya acción por defecto es parar los procesos .
•
Sesiones
Los SOBUNIX modernos soportan la abstracción de sesión. Una sesión está formada por uno o va­
rios grupos de procesos asociados a un determinado terminal de control. Cada sesión tiene asociado un
número entero positivo que la identifica de manera univoca. A dicho identificador se le conoce general­
mente con el nombre de identificador de sesión (Session IDentifier, SID). El SID de una sesión coincide
con el PGID del proceso o grupo de procesos que ha iniciado la conexión al terminal. A dicho proceso o
grupo de procesos se le denomina líder de la sesión.
Por ejemplo, cuando un usuario accede a un SOBUNIX a través de un programa de login se crea una
sesión cuyo líder es el programa de login. También cuando un usuario abre un terminal emulado se crea
una sesión cuyo líder es el intérprete de comandos del terminal.
Luego un determinado proceso pertenece a un grupo de procesos y a una determinada sesión, es
decir, tiene asociado un PGID y un SID. Cuando se crea un proceso éste hereda el PGID y el SID de
su proceso padre. Un proceso puede crear una nueva sesión usando la llamada al sistema s e t s i d. Para
conocer el SID asociado a un proceso se puede usar la llamada al sistema ge t s i d. También se puede
usar el comando ps - j (ver sección 2 . 3 . 6).
Conviene saber que cuando se trabaja con la abstracción de sesión, un proceso solo puede cambiar
de grupo si el grupo origen y el grupo destino pertenecen a la misma sesión.
SOBUNIX: implementación y control de procesos multihilos
81
Por otra parte, el uso de sesiones facilita el envío de señales a todos los grupos de procesos pertene­
cientes a una misma sesión.
2.3.6.
El sistema de archivos procfs
El sistema de archivos de procesos (process file system, procfs) es un pseudosistema de archivos
existente en algunos SOBUNIX que permite acceder a la información que mantiene el núcleo sobre los
procesos. Dicha información se almacena en archivos y se organiza en directorios. El término pseu­
dosistema se aplica sobre procfs en el sentido de que no se implementa en una partición de disco en
memoria secundaria, como un sistema de archivos ordinario, sino en el espacio de direcciones del núcleo
en memoria principal.
La implementación y la estructura del sistema procfs depende de cada SOBUNIX. Usualmente este
sistema se suele montar en el directorio /pro c . Dentro de este directorio existen, entre otros directorios,
un directorio por cada proceso existente en el sistema. Cada directorio asociado a un proceso lleva por
nombre el PID del proceso al que está asociado y contiene diferentes archivos y directorios con infor­
mación sobre el proceso. Para conocer la información contenida en los archivos y directorios del sistema
procfs soportado por un determinado SOBUNIX se recomienda consultar la página correspondiente del
manual de ayuda:
man proc
e
Ejemplo 2. 13
En la implementación que realiza Solaris del sistema procfs dentro del directorio asociado a un proceso
se aloj an, entre otros los siguientes archivos:
•
/ proc / P I D / map . Información sobre el espacio de direcciones virtuales de un proceso. Esta in­
formación puede ser consultada usando el comando pmap .
•
/proc / P I D / c red. Contiene los credenciales del proceso.
•
/proc / P I D / p s i n f o . Contiene la información asociada a un proceso que se muestra con el co­
mando p s .
•
/proc 1 P I D / lps i n f o . Contiene l a información asociada a los procesos ligeros d e u n proceso que
se muestra con el comando p s .
•
/proc / P I D / s t a tu s . Contiene diferente información sobre e l proceso: e l estado, PID, PGID,
SID, etc.
•
/proc / P I D / u sage. Contiene información sobre el uso de los recursos del computador que reali­
za el proceso.
Ampliación de sistemas operativos
82
Asimismo, cada directorio /proc / P I D / contiene, entre otros directorios, un directorio lwp dentro del
cual existe un directorio por cada proceso ligero asociado al proceso existente en el sistema. Cada di­
rectorio asociado a un proceso ligero lleva por nombre el identificador numérico del proceso ligero
(LightWeight ?rocess IDentifier, LWPID) al que está asociado y aloja, entre otros, los siguientes archi­
vos :
•
/proc / P I D / lwp / LWP I D / l wp s t a t u s . Contiene, entre otros datos, el estado del proceso ligero.
•
/proc / P I D / lwp / LWP I D / lwp s i n f o . Contiene la información asociada al proceso ligero que se
muestra con el comando p s .
•
e
Ejemplo 2. 14
Supóngase que en un sistema Solaris se está ejecutando un intérprete de comandos bash que tiene
asociado un proceso con PID=730. Si se escribe la orden
l s - F /proc
en la salida estándar, por defecto la pantalla, aparecerá un listado con todos los directorios contenidos
en el directorio /proc, en el cual está montado el sistema procfs. Existe un directorio por cada proceso
existente. Cada directorio lleva por nombre el PID del proceso al que está asociado.
Si ahora se escribe la orden
l s - l /proc / 7 3 0
en la pantalla aparecerá un listado detallado con todos los archivos y directorios contenidos en el direc­
torio /proc / 7 3 0 , que es el directorio asociado al intérprete de comandos. En dicho listado aparecen,
entre otros, los archivos y directorios comentados en los párrafos anteriores: a s , c red, c t l , etc
Si se escribe a continuación la orden
l s - l /pro c / 7 3 0 / lwp
en la pantalla aparecerá un listado detallado con todos los archivos y directorios contenidos en el direc­
torio /proc / 7 3 0 / lwp, que es el directorio que contiene información sobre los procesos ligeros en que
se descompone el intérprete de comandos. Existe un directorio por cada proceso ligero existente. Cada
directorio lleva por nombre el LWPID del proceso ligero al que está asociado. En el caso del intérprete de
comandos solo tiene un único proceso ligero cuyo LWPID = l . Luego existe un único directorio 1 dentro
de /pro c / 7 3 0 / lwp .
Finalmente si se escribe la orden
l s - l /proc / 7 3 0 / lwp / 1
SOBUNIX : implementación y control de procesos multihilos
83
en la pantalla aparecerá un listado detallado con todos los archivos y directorios contenidos en el direc­
torio /proc / 7 3 0 / lwp / 1 , que es el directorio asociado al proceso ligero LWPID= l del intérprete de
comandos. En dicho listado aparecen, entre otros, los archivos y directorios comentados en los párrafos
anteriores: lwp c t l , lwp i n f o y lwp s tatus .
•
Existen diferentes comandos que permiten extraer la información almacenada en procfs, como por
ejemplo:
•
ps. Este comando muestra un listado con información sobre los procesos existentes en el sistema.
La información que se muestra depende de cada SOBUNIX y de las opciones especificadas en el
comando.
•
pr s t a t . Este comando muestra un listado con información sobre el uso de los recursos que están
realizando los procesos existentes en el sistema. La información que se muestra se actualiza cada
cinco segundos. Otros comandos con una funcionalidad similar a prs t a t son top, mp s t a t y
vms t a t .
e
Ejemplo 2. 15
S i se escribe en un intérprete de comandos bash de Solaris la orden
ps
en la pantalla aparecería una salida semej ante a la siguiente:
P I D TTY
1 3 2 0 pts / 3
1 1 5 9 pts / 3
T IME CMD
0 : 0 0 ps
0 : 0 0 bash
Se trata de un listado que muestra información sobre los procesos asociados al intérprete de comandos:
el propio intérprete y el creado para ejecutar el comando ps. La información que se muestra de cada
proceso es la siguiente: PID, el terminal de control asociado TTY, el tiempo T IME de uso del procesador
y el comando CMD cuya ejecución ha generado el proceso.
Se puede configurar la información que se desea que aparezca por pantalla usando las opciones dispo­
nibles del comando. Para conocer las informaciones que se pueden mostrar y cómo mostrarlas se debe
consultar la página asociada al comando en el manual de ayuda. Por ejemplo, si se ahora se escribe la
orden
ps -Al
la opción -A hace que se muestren todos los procesos existentes en el sistema. Mientras que la opción
- 1 hace que se muestre un listado con más información, es decir, un mayor número de columnas. Para
incluir información sobre los procesos ligeros existentes en cada proceso se debe usar la opción - L . Así
la orden anterior se debería escribir de la siguiente forma:
84
Ampliación de sistemas operativos
ps
-
AlL
Para incluir la información sobre el PGID y el SID de cada proceso se debe usar la opción - j .
•
2.4.
Resumen
Los SOBUNIX modernos usan hilos del núcleo como unidad básica de planificación y ejecución.
Además también pueden soportar procesos ligeros, que son hilos de usuario cuya gestión es realizada
por el núcleo del sistema operativo. Un proceso ligero puede estar asociado a uno o varios hilos de
usuario. Algunos SOBUNIX utilizan un modelo de proceso multihilo con un mayor número de hilos
de usuario que procesos ligeros. Otros utilizan un modelo donde cada proceso ligero está asociado a un
único hilo de usuario.
En los SOBUNIX la creación de un proceso se realiza generalmente invocando a la llamada al sistema
f o rk. Al proceso que invoca a f o rk se le denomina proceso padre y al nuevo proceso que se crea se
le denomina proceso hijo. El proceso hijo recién creado es un copia prácticamente idéntica del proceso
padre y comparte el acceso a todos sus recursos. La única diferencia entre el proceso hijo recién creado
y el proceso padre se encuentra en algunos campos de su estructura proc, es decir, de su entrada de la
tabla de procesos.
En los SOBUNIX un proceso puede invocar a otro programa haciendo uso de la llamada al sistema
exe c . Esta llamada al sistema básicamente sustituye las regiones del espacio de direcciones del proceso
invocador por las regiones del programa invocado. Al finalizar la llamada al sistema se comienza a
ejecutar en el proceso invocador el programa invocado.
En los SOBUNIX si un proceso desea terminar su ejecución debe invocar explícitamente a la llamada
al sistema exi t. El sistema operativo también procede de forma implícita a la terminación de un proceso
después de ejecutar la última instrucción del proceso. Asimismo la terminación de un proceso también
se puede producir si el proceso recibe una señal cuyo tratamiento especifique la finalización del proceso.
Las señales son un mecanismo del núcleo para la notificación de eventos a procesos. Cada evento
notificable tiene asociado una determinada señal. A su vez cada señal tiene asignado un número entero
positivo pequeño que la identifica de manera univoca. Además tiene asociada una constante simbólica
que comienza con S I G y va seguida por una abreviatura o una palabra que resume el evento al que está
asociada. Cada SOBUNIX establece el número de señales que soporta, así como el número entero y la
constante simbólica que le asigna a cada una.
En los SOBUNIX los procesos son organizados en grupos de procesos. Asimismo los SOBUNIX
modernos soportan la abstracción de sesión. Una sesión está formada por uno o varios grupos de procesos
que pueden estar asociados a un determinado terminal de control.
El sistema de archivos de procesos (procfs) es un pseudosistema de archivos existente en algunos
SOBUNIX que permite acceder a la información que mantiene el núcleo sobre los procesos. Dicha
información se almacena en archivos y se organiza en directorios.
SOBUNIX: implementación y control de procesos multihilos
2.5.
85
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pueden
consultar, por ejemplo: los capítulos 2, 3, 4 y 9 de [Vahalia, 1 995] , el capítulo 10 de [Tanenbaum, 2009] ,
el capítulo 2 de [McDougall y Mauro, 2006], y los capítulos 5, 6 y 7 de [Márquez, 2004] .
2.6.
Autoevaluación
2.1. Definir y comentar las características de los siguientes elementos: a) Hilos del núcleo. b) Hilos de
usuario. e) Procesos ligeros. (Respuesta en sección 2.2. 1 )
2.2. Explicar razonadamente e l modelo de proceso multihilo utilizado en Solaris.
(Respuesta en sección 2.2. 1 )
2.3. ¿Qué e s l a tabla d e procesos? Enumere l a información que contiene una de sus entradas.
(Respuesta en sección 2.2.2)
2.4. Explicar razonadamente qué información es necesario mantener por cada hilo de usuario de un
proceso. ¿Quién gestiona dicha información? ¿Dónde se almacena? (Respuesta en sección 2.2.2)
2.5. Explicar razonadamente qué información es necesario mantener por cada proceso ligero. ¿Quién
gestiona dicha información? ¿Dónde se almacena? (Respuesta en sección 2.2.2)
2.6. Explicar razonadamente qué información es necesario mantener por cada hilo del núcleo. ¿Quién
gestiona dicha información? ¿Dónde se almacena? (Respuesta en sección 2.2.2)
2.7. Explicar razonadamente la relación existente entre procesos, procesos ligeros e hilos del núcleo.
(Respuesta en sección 2.2.2)
2.8. Explicar razonadamente la función de las siguientes estructuras de datos en Solaris: pro c , klwp,
kthread, ulwp y uberda ta. (Respuesta en sección 2 .2.2)
2.9. Dibujar el diagrama de transición de estados de los hilos del núcleo en Solaris.
(Respuesta en sección 2.2.2)
2.10. Explicar para qué se utiliza la llamada al sistema f o rk. ¿Qué valor devuelve al proceso padre si
se ejecuta con éxito? ¿ Y al proceso hijo? (Respuesta en sección 2. 3 . 1 )
2. 11. Explicar l a relación existente entre el espacio de direcciones virtuales de un proceso padre y su
proceso hijo. (Respuesta en sección 2. 3 . 1 )
2. 12. Enumerar las principales acciones que realiza l a función del núcleo que s e encarga de tratar la
llamada al sistema f o rk (Respuesta en sección 2. 3 . 1 )
2.13. Explicar para qué s e utiliza l a llamada al sistema exe c . (Respuesta en sección 2 . 3 . 1 )
86
Ampliación de sistemas operativos
2.14. ¿Qué tres tipos de argumentos de entrada aceptan las funciones de envo'ltura que invocan a la
llamada al sistema exe c ? (Respuesta en sección 2.3 . 1 )
2.15. Enumerar las principales acciones que realiza l a función del núcleo que s e encarga de tratar la
llamada al sistema exec (Respuesta en sección 2.3 . 1 )
2. 16. Explicar l a utilidad d e l a llamada al sistema vfork (Respuesta e n sección 2. 3 . 1 )
2.17. Explicar razonadamente las consideraciones a realizar sobre el diseño de fork en procesos multi­
hilos. (Respuesta en sección 2 . 3 . 1 )
2.18. Explicar para qué s e utiliza l a llamada al sistema exi t . Comentar su sintaxis.
(Respuesta e n sección 2 . 3 . 2)
2.19. Enumerar las principales acciones que realiza la función del núcleo que se encarga de tratar la
llamada al sistema exi t (Respuesta en sección 2.3 .2)
2.20. ¿Cuál es el PID del proceso inicial o proceso ini t ? ¿ Cuándo se crea este proceso? ¿Cuál es su
principal tarea? (Respuesta en sección 2.3.2)
2.21. Explicar para qué se utiliza la llamada al sistema wa i t . Comentar su sintaxis.
(Respuesta en sección 2 . 3 .2)
2.22. ¿Qué información mantiene el núcleo si un proceso se encuentra en el estado zombi?
(Respuesta en sección 2 . 3 .2)
2.23. ¿Qué son las señales? ¿Cómo se identifican? (Respuesta en sección 2.3.3)
2.24. Enumerar las principales fuentes de envío de señales. (Respuesta en sección 2.3.3)
2.25. Indicar los eventos que producen el envío de las siguientes señales y su acción por defecto asociada:
S IGSEGV, S I GALRM, S IGXC PU, S IGINT, S I GKILL, S I GTTIN, S IGTTOU, S I GCHLD, S IGSTOP,
S I GCONT, S I GTERM, S IGSTP, S I GUSRl y S I GUSR2 . (Respuesta en sección 2.3.3)
2.26. ¿Qué llamadas al sistema permiten enviar una señal a un proceso o grupo de procesos?
(Respuesta en sección 2 . 3 . 3 )
2.27. ¿Cuándo se considera que una señal ha sido recibida o entregada? (Respuesta e n sección 2 . 3 . 3 )
2.28. Enumerar y comentar brevemente las posibles acciones que se pueden realizar ante la recepción
de una señal. (Respuesta en sección 2 . 3 . 3 )
2.29. Enumerar qué aspectos puede configurar un proceso ante la recepción de una señal. ¿Qué llamadas
al sistema se pueden utilizar para configurar dichos aspectos? (Respuesta en sección 2 . 3 . 3 )
2.30. ¿Para qué se utiliza la llamada al sistema s i gna l ? Explicar su sintaxis.
(Respuesta en sección 2.3.3)
SOBUNIX: implementación y control de procesos multihilos
87
2.31. ¿Para qué se utiliza la llamada al sistema ki 1 1 ? Explicar su sintaxis. Comentar el uso del comando
homónimo. (Respuesta en sección 2.3.3)
2.32. ¿Para qué se utiliza la llamada al sistema paus e ? (Respuesta en sección 2 . 3 . 3 )
2.33. ¿Cuándo se dice que una señal está pendiente? (Respuesta e n sección 2.3.3)
2.34. Explicar las tareas que realizan las siguientes rutinas del núcleo: i s s i g ( ) , p s i g ( ) y s ends i g ( ) .
(Respuesta en sección 2 . 3 . 3 )
2.35. Explicar razonadamente las consideraciones a realizar sobre la implementación de las señales en
procesos multihilos. (Respuesta en sección 2 . 3 . 3 )
2.36. ¿Qué tareas permiten realizar las funciones de la librería Pthreads? (Respuesta en sección 2.3 .4)
2.37. ¿Qué información mantiene la librería Pthreads por cada hilo de usuario?
(Respuesta en sección 2.3 .4)
2.38. Enumerar e indicar la utilidad de cinco funciones para el control de los hilos de usuario de la
librería Pthreads. (Respuesta en sección 2.3 .4)
2.39. ¿Qué identificador tiene asociado cada grupo de procesos en SOBUNIX? ¿A qué proceso se le
denomina líder del grupo? (Respuesta en sección 2 . 3 . 5 )
2.40. Explicar la utilidad de las siguientes llamadas al sistema: getpg i d y s e tpgrp .
(Respuesta en sección 2 . 3 . 5 )
2.41. ¿Que elementos conforman una sesión? ¿Qué identificador tiene asociado cada sesión? ¿A qué
proceso o grupo de procesos se le denomina líder de la sesión? (Respuesta en sección 2 . 3 . 5 )
2.42. Explicar la utilidad de las siguientes llamadas al sistema: s e t s i d y ge t s i d.
(Respuesta en sección 2 . 3 . 5 )
2.43. ¿Qué comando se puede utilizar para visualizar el identificador de grupo y el identificador de
sesión de un proceso? (Respuesta en sección 2 . 3 . 5 )
2.44. ¿Para qué se utiliza el sistema de archivos procfs? (Respuesta e n sección 2 . 3 . 6)
2.45. Explicar la estructura de un sistema de archivos procfs. (Respuesta en sección 2 . 3 . 6)
2.46. Enumerar dos comandos que permiten extraer la información almacenada en procfs y comentar
qué información extraen. (Respuesta en sección 2.3 .6)
88
Ampliación de sistemas operativos
ma i n ( i n t argc ,
char
* argv [ ] )
{
i n t a , b= O , c , d ;
if
( argc ! = 2 )
exi t ( 3 ) ;
else
a = a t o i ( argv [ l ] ) ;
wh i l e
( f ork ( ) = = O & & b ! = a )
{
p r i n t f ( " \ nMen s a j e l [ %d ] \ n " ,
getpi d ( ) ) ;
b=b+ l ;
c = wa i t ( &d ) ;
p r i n t f ( " \ nMen s a j e 2 [ %d] = %d \ n " ,
Figura 2.1 1
2.7.
-
g e t p i d ( ) , g e tpp i d ( ) ) ;
Código C del programa j O 9 del Ejercicio 2. 1
Ejercicios
2. 1. Supóngase que al invocar el programa j 0 9 (ver Figura 2. 1 1 ) desde un intérprete de comandos se
crea un proceso con PID= 1 1 20. Supóngase además que la asignación de los PIDs de los procesos
hijos, si se llegaran a crear, se realiza mediante la expresión PIDh ij o = PIDpadre + h, donde h =
1 , 2, 3 , . . . hace referencia al orden de creación del proceso hijo, es decir, h = 1 es el primer hijo
creado, h = 2 es el segundo hij o creado, etc. Suponer además que el intérprete de comandos desde
donde se lanza j 0 9 tiene asignado PID= 1 000.
a) Explicar razonadamente el funcionamiento de este programa si se invoca desde el intérprete
de comandos mediante la orden: j o 9 4
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
2.2. En la Figura 2. 1 2 se muestra el código C de los programas j 0 7 y ex2 . Supóngase que al invocar
este programa desde la línea de ordenes de un intérprete de comandos se crea un proceso con
PID=789 y que la asignación de los PIDs de los procesos hijos, si se llegaran a crear, se realizaría
incrementando en una unidad el PID del proceso padre.
a) Explicar razonadamente el funcionamiento de j 0 7 si se escriben consecutivamente las si­
guientes dos órdenes : 1 ) j 0 7 2) ki l l - S IGUSRl 7 9 0
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
estos programas en un SOBUNIX.
SOBUNIX: implementación y control de procesos multihilos
89
/ * C Ó d i g o del programa j 0 7 * /
# i nc lude < s i gn a l . h>
vo i d func
( i nt x ) ;
ma in ( )
{
int u= 1 5 ;
s i gnal ( S I GUS R l , func ) ;
u=u %2 ;
if
( fork ( ) = = 0 )
{
execv ( " ex2 " , O ) ;
u=u + 7 ;
p r i n t f ( " \ n %f \ n " , u ) ;
e l s e exi t ( l ) ;
vo i d func ( i n t x )
p r i n t f ( " Men s a j e 1 " ) ;
/ * Có d i g o de l programa ex2 * /
ma in ( )
{
f l oat u ;
pau s e ( ) ;
p r i n t f ( " \ nu= %f \ n " , u ) ;
Figura 2.12 - Código C de los programas j 0 7
y
ex2 del Ejercicio 2.2
2.3. En la Figura 2. 1 3 se muestra el código C del programa so 8 . Supóngase que al invocar este progra­
ma desde la línea de ordenes de un intérprete de comandos se crea un proceso con PID= 1 035 y que
la asignación de los PIDs de los procesos hijos, si se llegaran a crear, se realizaría incrementando
en una unidad el PID del proceso padre.
a) Explicar razonadamente el funcionamiento de s O 8 si se escriben consecutivamente las si­
guientes tres órdenes :
1) sOS &
2) k i l l - S I GUSRl 1 0 3 6
3) k i l l - S I GUSR2 1 0 3 6
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
90
Ampliación de sistemas operativos
# i n c l ude < s i gnal . h>
vo i d f 1 ( i n t s i g ) ;
ma i n ( )
{
int a , b ;
s i gnal ( S I GUSR1 , S I G_DFL ) ;
i f ( fork ( ) = = 0 )
{
s i gnal ( S I GUSR1 , S I G_I GN ) ;
pau s e ( ) ;
exi t ( 5 ) ;
else
a =wa i t ( &b ) ;
pr i n t f ( " \ n
%1
%1 \ n " , a , b ) ;
vo i d f 1 ( i n t s i g )
p r i n t f ( " \ nMens a j e 1 \ n " ) ;
Figura 2.13
-
Código C del programa s O 8 del Ejercicio 2.3
# i nc l ude < s i gnal . h>
ma in ( )
{
int a , b ;
if
( ( a = f o rk ( ) ) = = O )
wh i l e ( 1 ) {
a=aA 1 Q ;
b = ra i s e ( S I GCHLD ) ;
p r i n t f ( " \ nMens a j e 1 [ %d ] :
%1 :
%1 \ a \ n " , g e tp i d ( ) , b , a ) ;
s l e ep ( 4 ) ;
s l e ep ( 1 6 ) ;
ki l l ( a , S I GUSR 1 ) ;
s l e ep ( 3 ) ;
k i l l ( ge tpp i d ( ) , S I GUSR2 ) ;
Figura 2.14 - Código C del programa m O 9 del Ejercicio 2.4
SOBUNIX: implementación y control de procesos multihilos
91
# i nc lude < s i gna l . h>
vo i d f 1 ( i n t s i g ) ;
ma in ( i nt a ,
char * b [ ] )
{
l ong c , d ;
s i gnal ( S I GUS R 1 , f 1 ) ;
s i gnal ( S I GUSR2 ,
S I G_DFL ) ;
d=atoi ( b [ 1 ] ) ;
if
( a = = 2 & & d= = 1 )
c = s i g s e tma s k ( s i gma s k ( S IGUSR1 ) ) ;
s i gb l o c k ( s i gma s k ( S IGUSR2 ) ) ;
pau s e ( ) ;
s i g s e tma s k ( c ) ;
else
pau s e ( ) ;
exi t ( 1 ) ;
v o i d f 1 ( i nt s i g )
p r i n t f ( " \ n \ n Texto 1 \ n " , s t r s i gna l ( s i g ) ) ;
Figura 2.15 - Código C del programa s 0 9 R del Ejercicio 2.5
2.4. En la Figura 2. 1 4 se muestra el código C del programa roO 9. Supóngase que al invocar este progra­
ma desde la línea de ordenes de un intérprete de comandos se crea un proceso con PID=2045 y que
la asignación de los PIDs de los procesos hijos, si se llegaran a crear, se realizaría incrementando
en una unidad el PID del proceso padre. Suponer además que el intérprete de comandos desde
donde se lanza roO 9 tiene asociado PID=2000.
a) Explicar razonadamente el funcionamiento de roO 9 si se invoca desde el intérprete de coman­
dos mediante la orden: roO 9
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
2.5. En la Figura 2. 1 5 se muestra el código C del programa s 0 9R. Supóngase que al invocar este
programa desde la línea de ordenes de un intérprete de comandos se crea un proceso con PID=245 .
a) Explicar razonadamente el funcionamiento de s 0 9 R si se escriben consecutivamente las si­
guientes tres órdenes :
92
Ampliación de sistemas operativos
1) s09R 1 &
2) ki l l - S IGUSRl 2 4 5
3 ) ki l l - S IGUSR2 2 4 5
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
2.6. Considérese el programa prog 2 7 del Ejemplo 2. 1 1 cuyo código C se muestra en la Figura 2.9.
Invocarlo en segundo plano desde la línea de ordenes del intérprete de comandos de un SOBUNIX
y a continuación escribir la orden ps j . A partir de la información que se muestra en la pantalla
contestar razonadamente a las siguientes preguntas :
-
a) ¿Cuál es el valor del SID ? ¿Cuál es el proceso líder de la sesión?
b) ¿Cuántos grupos de procesos existen? ¿Cuáles son sus PGID? ¿Cuántos miembros tiene cada
grupo?
Capítulo 3
SOBUNIX: planificación, sincronización y
mecanismos IPC
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes:
•
Conocer las características generales de la planificación de procesos multihilos en S OBUNIX.
•
Conocer los detalles de la implementación de la planificación de dos ejemplos ilustrativos de SO­
BUNIX: BSD 4.3 y S olaris.
•
Conocer las principales llamadas al sistema disponibles en los SOBUNIX para el control de la
prioridad de un proceso.
•
Conocer los conceptos de núcleo expropiable, núcleo no expropiable y puntos de expropiación
usados en SOBUNIX.
•
Conocer los principales mecanismos de sincronización usados por el núcleo de los S OBUNIX:
cerrojos y semáforos .
•
Saber e n qué consisten las operaciones d e dormir y despertar u n hilo del núcleo.
•
Saber qué es un canal de espera y cómo se le asocia una cola de hilos dormidos .
•
Saber qué son y para qué se utilizan los turnstiles.
•
Conocer el funcionamiento y las llamadas al sistema asociadas a los principales mecanismos de co­
municación entre procesos disponibles en la mayoría de SOBUNIX: mecanismos IPC del System
V (semáforos, colas de mensajes y memoria compartida), señales y tuberías.
93
94
Ampliación de sistemas operativos
3.1.
Introducción
Este capítulo se divide en tres partes. La primera parte está dedicada a describir la planificación de
procesos multihilos en SOBUNIX. En primer lugar se comentan las características generales. A conti­
nuación se describen los detalles de la implementación de la planificación en BSD 4.3 y Solaris, que
son dos ejemplos ilustrativos de SOBUNIX clásicos y modernos, respectivamente. Posteriormente se
realizan diferentes consideraciones sobre la expropiación del núcleo en los SOBUNIX.
La segunda parte de este capítulo está dedicada a describir los principales mecanismos de sincroni­
zación usados por el núcleo de un SOBUNIX: los cerrojos y los semáforos . También se describen las
operaciones de dormir y despertar un hilo del núcleo, y la implementación de las colas de hilos dormidos.
En la última parte de este capítulo se describen los mecanismos de comunicación entre procesos
disponibles en los SOBUNIX. En primer lugar se explican los mecanismos IPC del System V: semáforos,
colas de mensajes y memoria compartida. Estos mecanismos aunque introducidos en el System V han
sido adoptados por todos los SOBUNIX. Por último se explica el uso de las señales y las tuberías, que
son otros mecanismos IPC disponibles en los SOBUNIX.
3.2.
Planificación de procesos multihilos en SOBUNIX
3.2.1 .
Características generales
Los SOBUNIX son sistemas operativos multiprogramados, es decir, soportan la existencia de múlti­
ples programas cargados parcial o totalmente en la memoria principal. Cada programa, de acuerdo con
lo estudiado en el capítulo anterior, tiene asignado un proceso monohilo o un proceso multihilo. Además
si el núcleo soporta la existencia de hilos del núcleo, cada proceso tendrá asociado uno o más hilos del
núcleo.
Puesto que el número de procesos en el estado preparado para ejecución suele ser mucho mayor que
el número de procesadores existentes en un computador, el núcleo debe decidir qué procesos (o hilos del
núcleo) pasarán a ser ejecutados en los procesadores disponibles. A la parte del núcleo de un sistema
operativo encargada de esta tarea se le denomina planificador (scheduler). Nótese que si el núcleo del
SOBUNIX considerado soporta hilos del núcleo entonces el planificador utiliza como unidad o entidad
planificable a los hilos del núcleo. En caso contrario utilizará como unidad planificable a los procesos.
El planificador también se encarga de realizar los cambios de contexto, es decir, guardar el contexto
de la unidad planificable que va a ser desalojada de un procesador y cargar el contexto de la unidad
planificable que ha sido planificada para ser ejecutada en dicho procesador. Además el planificador se
encarga de la gestión de las diferentes estructuras de datos del núcleo necesarias para implementar la pla­
nificación, como por ejemplo las colas de unidades planificables en el estado preparado para ejecución.
En la mayoría de los SOBUNIX, el planificador implementa una planificación global basada en
múltiples colas de prioridad y realimentación. En este tipo de planificación, cada unidad planificable
tiene asignada una determinada prioridad, que es un número entero positivo comprendido entre O y un
cierto valor máximo Pmax · En algunos SOBUNIX el valor O corresponde a la máxima prioridad posible,
mientras que en otros la máxima prioridad corresponde a Pmax. El planificador siempre intenta que se
SOBUNIX : planificación, sincronización y mecanismos IPC
95
ejecute la unidad planificable de mayor prioridad, aunque esto no siempre es posible si el núcleo es no
expropiable (ver sección 3 .2.3).
El valor de la prioridad de una unidad planificable se establece en función de diferentes criterios:
el modo de ejecución (modo usuario o en modo núcleo), el tipo de trabajo (trabaj o interactivo, trabajo
por lotes, trabajo en tiempo real, trabajo del sistema operativo e interrupciones), el tiempo de procesador
consumido, el tiempo de espera en las colas, etc. El valor de la prioridad puede variar o no con el tiempo
de vida de la unidad planificable, es decir, la prioridad puede ser estática o dinámica. Por ejemplo, la
prioridad de las unidades planificables asociadas a las interrupciones suele ser alta y estática. Mientras
que la prioridad de las unidades planificables asociadas a trabajos por lotes suele ser baj a y dinámica.
En función del valor de su prioridad cada unidad planificable en el estado preparado forma parte de
una determinada cola de unidades planificables en el estado preparado o cola de prioridad. Las unidades
planificables que poseen una prioridad dinámica pueden pasar durante su tiempo de vida por diferentes
colas. El planificador establece una determinada planificación local para cada cola, como por ejemplo:
planificación PIFO, planificación de tiempo compartido, planificación basada en prioridades, etc.
Algunos SOBUNIX, como SVR4 o Solaris, para dotar de mayor flexibilidad al planificador definen
clases de planificación cada una de los cuales tiene asociada un rango de valores de prioridad y un
mecanismo de cálculo de la prioridad. Cada unidad planificable pertenece a una determinada clase de
planificación. Normalmente se dispone de una clase de planificación por cada tipo de trabaj o soportado
en el sistema: clase de trabajos en tiempo real, clase de trabajos de tiempo compartido o interactivos, etc.
Las clases de planificación son manipuladas por el planificador usando dos posibles tipos de funciones :
•
Funciones independientes de la clase. El planificador utiliza éstas funciones para la realización
de servicios que son comunes a todas las clases, como por ejemplo: el cambio de contexto y la
manipulación de las colas de planificación.
•
Funciones dependientes de la clase. El planificador utiliza éstas funciones para la realización de
servicios que dependen de la clase, como por ejemplo el cálculo de la prioridad. Cada clase sumi­
nistra su propia implementación de estas funciones .
Los SOBUNIX disponen de algunas llamadas al sistema para modificar, con ciertas restricciones, el
valor de la prioridad de un proceso o grupo de procesos, o para cambiar su clase de planificación. Por
ejemplo las llamadas al sistema n i c e y pr i o cnt l se encuentran disponibles en algunos SOBUNIX para
controlar la prioridad de un proceso.
3.2.2.
Dos ejemplos ilustrativos de la planificación en SOBUNIX
Aunque la planificación en los SOBUNIX presenta, en la mayoría de los casos, las características
generales comentadas en la sección anterior, cada SOBUNIX implementa estas características de una
determinada forma. En las siguientes secciones se describen a modo de ejemplo la planificación en dos
SOBUNIX diferentes : BSD 4 . 3 1 ( 1 986) y Solaris 10 (2005).
1 L a planificación e n SVR3 e s muy similar a la planificación e n BSD 4 . 3 , únicamente existen pequeñas diferencias e n el
nombre de algunas funciones y variables.
96
Ampliación de sistemas operativos
Planificación en BSD 4.3
BSD 4.3 es un sistema operativo de núcleo no expropiable (ver sección 3 .2.3) que utiliza como
unidad de planificación a los procesos, ya que el núcleo no soporta hilos del núcleo. Cada proceso tiene
asignada una prioridad de ejecución que es un número entero positivo comprendido dentro del rango de
valores [0, 1 27 ] , siendo O la prioridad más alta posible y 1 27 la prioridad más baja. La prioridad de un
proceso ejecutándose en modo usuario solo puede encontrarse dentro del rango [50, 1 27 ] . Los valores
comprendidos dentro del rango [0, 49] están reservados para la ejecución del núcleo.
El valor de la prioridad de un proceso se almacena en el campo p_pr i de su estructura pro c . Recuér­
dese (ver sección 2.2.2) que una estructura proc implementaba la entrada de un proceso en la tabla de
procesos del núcleo. También en esa misma estructura se mantiene el campo p_u s rpri donde se guarda
el valor de la prioridad que se le debe asignar al proceso cuando termine de ejecutarse en modo núcleo y
retome a modo usuario, por ejemplo al completarse una llamada al sistema. Mientras un proceso se está
ejecutando en modo usuario el valor de la prioridad almacenado en p_pri coincide con el almacenado
en p_u s rpr i .
2
E l núcleo invoca a través de u n callout una vez por segundo a l a función s chedcpu ( ) para recalcu­
lar el valor de la prioridad en modo usuario de cada proceso, el cual se almacena en p_u s rpr i . Además,
la prioridad en modo usuario del proceso en ejecución es recalculada por el manejador de la interrupción
del reloj cada cuatro tics de reloj . En ambos casos la prioridad en modo usuario se calcula usando la
siguiente fórmula [Vahalia, 1 995] :
.
p_usrpn
=
PUSER +
p cpu
.
4
+ 2·p_mce
(3 . 1 )
En la expresión anterior:
•
PUSER es una constante que vale 50 y que hace referencia a la prioridad en modo usuario base, es
decir, la prioridad más alta que puede tener un proceso ejecutándose en modo usuario.
•
p_cpu es un campo de la estructura proc que almacena una medida del uso de la CPU por parte
del proceso. El valor máximo de este campo está limitado a 1 27. Cuando se crea un proceso su
campo p_cpu se inicializa a O. Cada tic de reloj el manej ador de la interrupción de reloj incrementa
en una unidad el valor del campo p_cpu del proceso actualmente en ejecución. Un proceso que
acaba de usar la CPU tendrá un valor alto de p_cpu, luego el valor de p_u s rpri aumentará con
lo que su prioridad será más pequeña.
Por otra parte la rutina s c hedcpu ( ) , entre otras tareas, multiplica el valor del campo p_cpu
de cada proceso por un factor de decadencia (decay factor) que se calcula mediante la siguiente
expresión [Vahalia, 1 995] :
decay
=
2 · load_average
2·load_average + 1
(3.2)
2Los callouts son un mecanismo interno del núcleo para planificar la invocación de funciones de forma automática transcu­
rrido un cierto número de tics de reloj .
SOBUNIX: planificación, sincronización y mecanismos IPC
97
En la expresión anterior l o ad_average es el número medio de procesos en el estado preparado
en el último segundo. Como l oad_average es un número entero positivo entonces decay es un
número menor que l . Luego la rutina s chedcpu ( ) disminuye el valor de p_cpu de cada proceso.
Nótese que cuanto más tiempo pasa un proceso en espera de usar el procesador, el valor de su
p_cpu se hace mas pequeño debido al factor de decadencia. En consecuencia su valor p_u s rpri
se va reduciendo con lo que la prioridad del proceso en modo usuario aumenta.
•
p_n i c e . Es un campo de la estructura proc que almacena un valor entero positivo comprendido
dentro del rango [0, 39] denominado valor amable (nice value). Por defecto, el valor amable vale
20. Nótese que cuanto más pequeño sea el valor amable mayor será la prioridad en modo usuario
del proceso. El valor amable de un proceso puede ser configurado mediante el comando n i c e el
cual hace uso de la llamada al sistema homónima. Los usuarios pueden usar este comando para
aumentar el valor amable de un proceso y en consecuencia reducir su prioridad. De esta forma
estarían dejando pasar antes al procesador a otros procesos. Esto puede ser deseable por ejemplo
para los procesos que se ejecuten en segundo plano asociados a trabajos por lotes. El comando
ni ce también permite decrementar el valor amable para aumentar la prioridad de un proceso, sin
embargo esta acción solo la puede realizar el superusuario.
En modo núcleo la prioridad de un proceso no se recalcula en función del tiempo sino que se asigna
de forma directa. Un proceso cuando invoca a una llamada al sistema y pasa a ejecutarse en modo núcleo
continua ejecutándose en principio con la misma prioridad que tenía en modo usuario hasta que entra en
el estado dormido (bloqueado) en espera de que se produzca algún evento. Cuando el núcleo despierta
a un proceso en el estado dormido porque se ha producido el evento por el que se había bloqueado, el
núcleo aumenta temporalmente su prioridad asignándole un determinado valor dentro del rango [0, 49]
en función del evento por el que había entrado en el estado dormido.
En general la prioridad asignada en modo núcleo al despertar un proceso es mayor en función de
la importancia que suponga para el resto del sistema la atención rápida de dicho evento. Por ejemplo,
si un proceso esperaba por la recepción de una señal le asigna una prioridad de 40, si esperaba por la
terminación de un proceso hijo le asigna una prioridad de 30, si esperaba por la terminación de una
operación de E/S en el disco le asigna una prioridad de 20, si esperaba por el desbloqueo de un nodo-i le
asigna una prioridad de 1 O, etc.
En BSD 4.3 existen 32 colas de procesos en el estado preparado para ejecución (ver Figura 3 . 1 ) .
Cada cola s e implementa como una lista doblemente enlazada d e estructuras pro c . Cada cola i (i =
O, 1 , 2, . . . , 3 1 ) está asociada al rango de prioridades [4· i, 4·i + 3 ] formado por cuatro valores contiguos
de prioridad. Así la cola O está asociada al rango de prioridades [0, 3], la cola 1 al rango [4, 7], etc.
Solamente pueden formar parte de una determinada cola aquellos procesos en el estado preparado para
ejecución cuya prioridad esté dentro del rango de prioridades asociada a dicha cola.
Siempre se planifica para ejecución el proceso situado más cerca de la cabecera de la cola i asociada
al rango de prioridades más altas. Luego un proceso ubicado en una cola i se ejecutaría antes que uno
situado en la cola i + l .
Para determinar cuál es la cola i asociada al rango de prioridades más altas que no está vacía el núcleo
utiliza la variable global whi chqs . Esta variable es una máscara de 32 bits. Cada bit está asociado a una
98
Ampliación de sistemas operativos
cola. El bit más significativo de la máscara (el situado más a la izquierda) se toma como bit O y se asocia
a la cola O. Mientras que el bit menos significativo (el situado más a la derecha) o bit 3 1 está asociado
a la cola 3 1 . En general el bit i de la máscara se asocia a la cola i. Un bit i se configura a O si la cola i
a la que está asociado está vacía, en caso contrario se configura a l . El planificador examina la máscara
de bits de la variable whi chqs comenzando por el bit O en busca de un 1 , es decir, en busca de la cola
asociada al rango de prioridades más altas que no esté vacía.
Si en la cola i asociada al rango de mayor prioridad existen varios procesos, entonces se aplica sobre
dicha cola un algoritmo de turno rotatorio con un cuanto fijo de 1 00 ms. En el caso de un proceso
ejecutándose en modo núcleo, como el núcleo es no expropiable, su cuanto es infinito. El núcleo cuando
se termina el cuanto invoca mediante un callout a la rutina r oundrobin ( ) para planificar al siguiente
proceso de la cola i. Nótese que si en la cola i asociada al rango de mayor prioridad existe un único
proceso entonces éste se ejecutará hasta que se complete, independientemente de que expire su cuanto.
Si se está ejecutando un proceso A procedente de la cola i y entra un proceso B en una cola j con
j < i, es decir, deja de estar vacía una cola asociada a un rango de prioridades más alto que el proceso
actualmente en ejecución, entonces :
•
Si el proceso A se está ejecutando en modo usuario se le expropia el uso del procesador aunque no
haya terminado su cuanto y se le cede al proceso B .
•
Si el proceso A s e está ejecutando en modo núcleo, como el núcleo es no expropiable n o s e l e puede
expropiar al proceso A el uso del procesador. El planificador activa un indicador denominado
runrun para notificar que existe un proceso en una cola j asociada a un rango de prioridades
más alto que la prioridad del proceso A. Cuando el proceso vaya a retomar a modo usuario, el
planificador comprobará si runrun está activado y en caso afirmativo realizará un cambio de
proceso.
La rutina s chedcpu ( ) invocada cada segundo a través de un callout por el núcleo, aparte de las
tareas comentadas en los párrafos anteriores, también se encarga de colocar a lo procesos en las colas
adecuadas de acuerdo con su nuevo valor de prioridad.
e
Ejemplo 3.1
Supóngase que el estado de las colas de procesos preparados de un sistema BSD 4.3 es el que se muestra
en la Figura 3 . 1 . Se observa que no existe ningún proceso en la cola n° O ni en la cola no i. Por el contrario
hay dos procesos en la cola n° 1 y cuatro procesos en la cola no 3 1 .
Para determinar cuál será el próximo proceso que va a ser planificado el núcleo examina la variable
whi chqs de izquierda a derecha en busca de un 1 , es decir, busca la cola asociada al rango de prioridades
más altas que no esté vacía. Así, en primer lugar examina el bit O, este vale O ya que la cola n° O está
vacía. A continuación examina el bit l . Como la cola 1 contiene dos procesos el bit 1 tiene el valor l . Por
lo tanto se selecciona para ser planificado el proceso situado más cerca de la cabecera de la cola n° l .
•
La planificación usada en B S D 4.3 favorece a los procesos limitados por E/S frente a los procesos
limitados por la CPU. En general resulta adecuada para sistemas de tiempo compartido con una carga
SOBUNIX: planificación, sincronización y mecanismos IPC
99
Sentido de análisis
31
1
Prioridad
más alta
wh i chqs
Cola no O
Prioridad [0, 3 ]
Cola n o 1
Prioridad [ 4, 7]
Cola n° i
Prioridad [4i, 4i + 3]
Prioridad
más baja
Cola no 3 1
Prioridad [ 1 24, 1 27]
Figura 3.1 - Posible estado de las colas de procesos preparados
y
de la estructura whi chqs de un
sistema BSD 4.3
formada por trabajos interactivos y trabajos por lotes. Presenta sin embargo los siguientes inconvenientes
[Vahalia, 1 995] :
•
Calcular la prioridad en modo usuario de todos los procesos una vez por segundo produce una gran
sobrecarga si el número de procesos es elevado.
•
Puede presentar el problema de la inversión de prioridad debido a la no expropiabilidad del núcleo,
es decir, que un hilo de mayor prioridad tenga que esperar a usar el procesador porque lo está
usando una hilo de menor prioridad.
•
No garantiza un tiempo de respuesta determinado por lo que no sirve para aplicaciones de tiempo
real.
Planificación en Solaris
Solaris es un sistema operativo de núcleo expropiable (ver sección 3 .2.3) que utiliza como unidad
de planificación a los hilos del núcleo. Cada hilo del núcleo tiene asignado una prioridad global y una
clase de planificación. Esta información se almacena en la estructura kthread que el núcleo mantiene
por cada hilo del núcleo. En esta estructura existen, entre otros (ver sección 2.2.2), los siguientes campos
con información que se utiliza para la planificación del hilo:
100
Ampliación de sistemas operativos
Prioridad más alta
1 69
1
1
, -
�
Interrupciones (*)
1 60
1 59
1
1
1
1
1
1
-
Clase
RT
1 00
99
1
1
Clase SYS
�
60
59
Clase FX
Prioridad más baj a
1
1
1
1
1
-
Clases F S S , IA y TS
o
(*) Las interrupciones ocupan el rango [ 1 00, 1 09] si la clase RT no está cargada
Figura 3.2 - Prioridades de ejecución en Solaris
•
t__pr i . Contiene la prioridad global de ejecución del hilo que es un número entero positivo com­
prendido dentro del rango de valores [0, 1 69] , siendo 1 69 la prioridad más alta posible y O la
prioridad más baja. Las diez prioridades más altas [ 1 60, 1 69] están reservadas para la ejecución
de los hilos del núcleo asociadas al tratamiento de las interrupciones. Las prioridades restantes
comprendidas en el rango [0, 1 59] se reparten entre las clases de planificación definidas en Solaris
(ver Figura 3 .2).
•
t_epr i . Contiene la prioridad heredada del hilo que se utiliza temporalmente como prioridad
global cuando se aplica la técnica del traspaso o herencia de prioridades para evitar el problema
de la inversión de prioridades.
•
t_c i d. Contiene el identificador de la clase de planificación a la que pertenece el hilo. El identi­
ficador puede tomar los siguientes valores:
- RT (Real Time, tiempo real). Tiene asignada el rango de prioridades [ 1 00, 1 59] . Esta clase
está definida para la planificación de los hilos del núcleo asociados a trabajos de tiempo real.
- SYS (SYStem, sistema). Tiene asignada el rango de prioridades [60, 99] . Esta clase está
definida para la planificación de los hilos del núcleo asociados a tareas del núcleo.
SOBUNIX : planificación, sincronización y mecanismos IPC
101
- FX (FiXed, fija). Tiene asignada el rango de prioridades [0, 60] . Esta clase está definida para
la planificación de los hilos del núcleo asociados a trabajos cuya ejecución se desea que tenga
asignada una prioridad global fij a que no varíe durante el tiempo de vida del trabajo. Nótese
que un hilo perteneciente a esta clase puede ejecutarse con el valor de prioridad 60 de la clase
SYS, aunque durante un tiempo corto (cuanto pequeño).
- F S S (Fair Share, reparto justo). Tiene asignada el rango de prioridades [0, 59] . Esta clase está
definida para la planificación de los hilos del núcleo asociados a trabajos cuya ejecución se
desea que tenga asignada el mismo tiempo de uso del procesador. En esta clase los ciclos de
procesador son divididos en unas unidades denominadas cuotas (shares) que son distribuidas
de manera equitativa entre todos los hilos pertenecientes a la clase.
- TS (Time Share, tiempo compartido). Tiene asignada el rango de prioridades [0, 59] . Esta
clase está definida para la planificación de los hilos del núcleo asociados a trabajos de tiempo
compartido, como por ejemplo los intérpretes de comandos.
- IA (lnterActive, interactiva). Tiene asignada el rango de prioridades [0, 59] . Esta clase está
definida para la planificación de los hilos del núcleo asociados a trabajos interactivos de
interfaces de usuario gráficas (ventanas, menús, etc).
Cuando se arranca el sistema, el núcleo carga las clases SYS y T S . El resto de clases son cargadas
dinámicamente según se van necesitando o cuando se usan determinados comandos. Si la clase RT
no se carga entonces las prioridades quedan restringidas al rango [0, 1 09], siendo las prioridades
[ 1 00, 1 09] asociadas al tratamiento de las interrupciones.
•
t_c ldata. Puntero a una estructura xxproc donde xx puede ser t s , i a , f s s , fx o r t , cuya
definición puede encontrarse en el archivo xx . h. Esta estructura contiene la información necesa­
ria para poder calcular la prioridad del hilo del núcleo de acuerdo con las especificaciones de la
planificación propias de cada clase. Un hilo del núcleo perteneciente a la clase SYS no requiere de
esta estructura ya que se puede ejecutar todo el tiempo que necesite (cuanto infinito), hasta que se
complete o sea expropiado.
•
t_c l func s . Puntero a una estructura c l a s s func s que contiene un vector de funciones depen­
dientes de la clase de planificación para la asignación del cuanto, el cálculo de la prioridad, el
tratamiento del tic de reloj , etc.
El núcleo mantiene una tabla global de clases de planificación implementada como un array de
estructuras s c l a s s_t . Cada estructura s c l a s s contiene, entre otras, las siguientes informaciones sobre
una determinada clase: el nombre de la clase ( c l_narne ) , un puntero a la función de inicialización de
la clase ( c l_ini t ) y un puntero ( c l_func s ) a una estructura c l a s s func s_t que contiene un vector
de funciones dependientes de la clase. Además el núcleo mantiene una lista doblemente enlazada por
cada clase de planificación con las estructuras xxproc asociadas a los hilos del núcleo pertenecientes a
una determinada clase. En la Figura 3 . 3 se muestra a modo de resumen la relación entre las estructuras
descritas.
102
Ampliación de sistemas operativos
Tabla global de
clases de planificación
el name =RT
selass
e l init
rt
init ( )
e l f une s
e l name = SYS
selass
el
init
el
fune s
sys_i n i t ( )
e l a s s fune s
e l name = T S
selass
e l init
t s init ( )
e l fune s
[ kth] =kthread
Figura 3.3 - Estructuras de datos asociadas a las clases de planificación en Solaris
Un hilo del núcleo en el estado preparado (estado TS_RUN) es colocado en función de su prioridad
global en una determinada cola de un determinado conjunto de colas de prioridad o colas de hilos en el
estado preparado. Existe un conj unto de colas de prioridad por cada procesado¡-3 .
Además en cada conjunto existe una cola por cada valor de prioridad global disponible en función de
las clases cargadas. Por ejemplo, si estuvieran cargadas todas las clases de planificación en un conjunto
de colas asociado a un determinado procesador existirían 1 10 colas de prioridad: 1 0 colas para el rango
de valores de prioridad [ 1 60, 1 69] y 1 00 colas para el rango de prioridad [0, 99] .
Los hilos del núcleo en el estado preparado pertenecientes a la clase de planificación RT son colo­
cados en un conjunto de colas de prioridad especial denominado conjunto de colas de expropiación del
3En los computadores actuales un chip de procesador consta de M núcleos (cores) de procesanúento, además cada núcleo
tiene la capacidad de ejecutar N hilos del núcleo simultáneamente. Luego el número total de procesadores existente por chip es
M·N.
SOBUNIX: planificación, sincronización y mecanismos IPC
103
núcleo. Este conjunto consta de 60 colas de prioridad, una por cada valor de prioridad dentro del rango
[ 1 00, 1 59] asociado a la clase RT . Los hilos pertenecientes a este conjunto de colas pueden ser ejecutados,
por defecto, en cualquier procesador. Este trato preferente que reciben los hilos del núcleo pertenecientes
4
a la clase RT es para conseguir que su latencia de despacho sea lo menor posible. Recuérdese que los
trabajos de tiempo real deben ejecutarse dentro de unos plazos de tiempo preestablecidos.
El núcleo se encarga de establecer a qué conjunto de colas de prioridad pertenecerá cada hilo del
núcleo en el estado preparado, y en consecuencia de fijar el procesador en que se ejecutará cada hilo. Se­
ñalar que un usuario puede vincular la ejecución de un determinado trabajo a un determinado procesador
o grupo de procesadores.
En un determinado procesador siempre se planifica para ejecución el hilo del núcleo situado al prin­
cipio de la cola asociada a la prioridad global más alta que no esté vacía. Si en dicha cola existen varios
hilos del núcleo se aplica un algoritmo de planificación de turno rotatorio. El cuanto de ejecución asig­
nado a un hilo depende de la clase de planificación a la que pertenezca el hilo y en ocasiones también de
su prioridad global.
Los hilos del núcleo asociados a interrupciones o a la clase SYS disponen de un cuanto infinito. Los
hilos asociados a la clase F S S tienen un cuanto fijo de 1 1 0 ms. Para el resto de clases el cuanto varía
en función de la prioridad global del hilo. Normalmente cuanto menor es la prioridad del hilo mayor
es su cuanto de ejecución. Esto puede parecer contradictorio, sin embargo con esta política se pretende
compensar a los hilos de baja prioridad porque son los que más esperan para usar un procesador.
Si en la cola de mayor prioridad solo existe un hilo del núcleo éste dispondrá de un cuanto infinito,
es decir, se ejecutará hasta que finalice su ejecución, entre en el estado dormido o se le expropie el uso
del procesador porque llegué algún hilo a una cola asociada a un valor de prioridad mayor.
El núcleo mantiene por cada clase planificación (excepto la clase SYS) una tabla de despacho (dis­
patch table) en la que se almacena, entre otras informaciones, los posibles valores del cuanto. Cada
entrada de esta tabla se construye mediante una estructura xxdspent donde xx puede ser t s , i a , fx,
f s s o rt cuya definición puede encontrarse en el archivo xx . h . Unos campos presentes en la estructura
xxdspent_t de todas las clases son:
•
xx_gl obpr i . Prioridad global.
•
xx_quantum. Valor asignado al cuanto para la prioridad global xx_g l obpr i .
La información almacenada en esta tabla puede leerse haciendo uso del comando di spadmin.
e
Ejemplo 3.2
Si en un intérprete de comandos de Solaris se escribe la orden
di spadmin -g
-e
RT
en la pantalla aparecería la siguiente salida5 :
4La latencia de despacho es el tiempo transcurrido desde que un hilo entra en el estado preparado hasta que comienza a ser
ejecutado en un procesador.
5 Se han omitido varias líneas por cuestiones de espacio.
104
Ampliación de sistemas operativos
# Real T ime Di spatcher C on f i gura t i on
RES = 1 0 0 0
# TIME QUANTUM
# ( r t_quantum )
1000
#
PRIORITY
LEVEL
o
1000
800
#
#
9
10
800
600
#
#
19
20
600
400
#
#
29
30
400
200
#
#
39
40
200
100
#
#
49
50
100
#
59
S i se examina l a salida se observa que en l a segunda línea se muestra el valor asignado a l a constante
RES , cuyo inversa establece la unidad de tiempo del cuanto. Por defecto RES es igual a 1 000, luego la
unidad de tiempo del cuanto es 1 / 1 000 = 0,00 1 segundos, es decir, milisegundos (ms).
Es posible cambiar el valor de RES usando el comando di spadm i n con la opción -r. Si RES se fija a
1 00, entonces el cuanto se expresaría en tics de reloj . En Solaris, existen 1 00 tics por segundo, luego un
tic ocurre cada 10 ms.
En las siguientes líneas de la salida aparece el valor del cuanto r t_quantum en función del nivel de
prioridad ( PRIORITY LEVEL ) , el cual se relaciona directamente con la prioridad global. Para la clase RT
la prioridad global se obtiene sumando 1 00 al nivel de prioridad.
Luego el valor del cuanto toma los siguientes valores : 1 000 ms si la prioridad global pertenece al rango
[ 1 00, 1 09] , 800 ms si la prioridad global pertenece al rango [ 1 1 0, 1 1 9], 600 ms si la prioridad global
pertenece al rango [ 1 20, 1 29], 400 ms si la prioridad global pertenece al rango [ 1 30, 1 39], 200 ms si la
prioridad global pertenece al rango [ 1 40, 1 49] y 1 00 ms si la prioridad global pertenece al rango [ 1 50,
1 59] .
Se observa por lo tanto que el valor del cuanto disminuye según aumenta el rango de prioridad global
considerado.
•
SOBUNIX: planificación, sincronización y mecanismos IPC
105
Los hilos del núcleo de las clases de planificación F S S , FX, TS e IA, aparte de una prioridad global,
también tienen asociada una prioridad en modo usuario. La prioridad global determina la cola de priori­
dad en que se alojará un hilo en el estado preparado y el cuanto de ejecución que se le asignará. Por su
parte la prioridad en modo usuario es el valor que se asignará a la prioridad global cuando el hilo regrese
a modo usuario, ya que cuando un hilo de estas clases se ejecuta en modo núcleo su prioridad global
puede tomar, en algunos casos, valores de prioridad global pertenecientes a la clase de planificación SYS.
En modo usuario la prioridad global coincide con la prioridad en modo usuario.
Cada clase de planificación establece el mecanismo de cálculo de la prioridad en modo usuario.
Normalmente suele ser la suma de varias componentes, una de las cuales es configurable por el usuario.
A la componente de la prioridad en modo usuario configurable por el usuario se le denomina prioridad
de usuario.
Para configurar el valor de la prioridad de usuario de un hilo del núcleo se utiliza el comando
pri ocnt l . Este comando también permite cambiar la clase de planificación. Además permite confi­
gurar otros parámetros relativos a la planificación de un hilo (ver la página del comando en roan ) . Solo
el superusuario puede usar este comando para incrementar la prioridad de usuario de un hilo, el resto de
usuarios solo pueden decrementarla.
Cada clase de planificación tiene asociado un rango de valores permitidos para la prioridad de usua­
rio. Por ejemplo, en las clases F S S y FX la prioridad de usuario puede tomar valores comprendidos en
el rango [0, 60] . Mientras que en las clases TS y IA el rango de valores permitidos para la prioridad de
usuario es [-60, 60] . El comando p r i o c n t l - 1 permite visualizar estos rangos.
La prioridad en modo usuario y la prioridad de usuario de un hilo del núcleo se almacena en los
campos xx_umdp r i y xx_upr i , respectivamente, de su estructura xxproc, donde xx puede ser t s , i a ,
f s s o fx.
e
Ejemplo 3.3
En la clase de planificación TS la prioridad en modo usuario de un hilo del núcleo perteneciente a esta
clase se almacena en el campo t s_umdpri de su estructura t spro c . Su valor se calcula, ante la aparición
de ciertos eventos, de la siguiente forma:
ts_umdpri
=
{�
p i
59
si pri < O
si O :::; pri :::; 59
si pri > 59
(3 .3)
donde
pri
=
ts_cpupri + ts_upri
(3 .4)
De la expresión (3 .3) se deduce que la prioridad en modo usuario t s_umdpri solo puede tomar valores
comprendidos dentro del rango [0, 59] .
Por otra parte, en la expresión (3 .4) t s_upri es la prioridad de usuario y t s_cpup r i es la componente
de la prioridad en modo usuario controlada por el núcleo. Estas dos componentes se almacenan también
en la estructura t sproc_t .
106
Ampliación de sistemas operativos
Cuando se producen ciertos eventos el valor de t s_cpupri se actualiza consultando la tabla de despacho
de la clase T S . Cada entrada de esta tabla se implementa mediante una estructura t s dspend_t que
contiene los siguientes campos :
•
t s_g l obpr i . Prioridad global.
•
t s_quantum. Valor asignado al cuanto para la prioridad global t s_g l obpr i .
•
t s_tqexp . Valor que se asignará a t s_cpupri cuando el hilo consuma el cuanto asignado.
•
t s_s lpr e t . Valor que se asignará a t s_cpupri cuando el hilo regrese a modo usuario después
de ser despertado. Tiene como efecto el aumento de la prioridad del hilo, para que pueda acceder
antes a un procesador y compensar así el tiempo perdido mientras dormía.
•
t s_maxwa i t. Umbral de tiempo expresado en segundos que hay que esperar antes de aplicar
t s lwa i t .
•
t s_lwa i t . Valor que s e asignará a t s_cpupri s i e l hilo h a estado esperando para consumir su
cuanto un tiempo de espera superior a t s_maxwa i t .
E l tiempo de espera s e mantiene en el campo t s_di spwa i t de l a estructura t sproc_t asociada
a cada hilo. Este campo se inicializa a cero cuando un hilo es colocado en una cola de prioridad
después de haber consumido su cuanto o despertado porque se produjo el evento por el que estaba
esperando.
Si el hilo fue expropiado por un hilo de mayor prioridad t s_di spwa i t no se reinicia a cero. El
valor de t s_di spwa i t es incrementado una vez por segundo para cada hilo que se encuentra en
una cola de prioridad o en una cola de hilos dormidos (ver sección 3 .4).
S i el valor de t s_di spwa i t es mayor que t s_maxwa i t entonces se asigna a t s_cpupri el valor
t s_lwai t, lo que tiene como efecto el aumento de la prioridad del hilo.
De acuerdo con los campos anteriores, se deduce que el valor de t s_cpupri asociado a un hilo del
núcleo se actualiza cada vez que se produce alguno de los siguientes eventos : el hilo ha consumido su
cuanto, el hilo ha despertado y regresa a modo usuario, o el hilo lleva un tiempo de espera acumulado
superior a t s_maxwa i t .
E l valor actual de t s_cpupri especifica l a fila de l a tabla de despacho de l a clase R T que hay que
consultar. Por otra parte, el evento producido especifica la columna de la tabla de despacho donde se
encuentra el nuevo valor que hay que asignar a t s_cpupr i . Conocido este valor se recalcula de nuevo
la prioridad en modo usuario t s_umdp r i .
Por ejemplo, supóngase que un hilo del núcleo perteneciente a la clase TS tiene t s_cpup r i = 1 1 y
t s_upr i = 1 0. De acuerdo con (3 .4) p r i = 1 1 + 1 0 = 2 1 , luego de acuerdo con (3 .3) t s_umdp r i = 2 1 .
S i s e usa el comando di spadm i n g - e T S se puede visualizar el contenido de l a tabla despacho de
la clase T S . Las primeras doce entradas contienen los siguientes valores:
-
SOBUNIX: planificación, sincronización y mecanismos IPC
# t s_quanturn
200
200
200
200
200
200
200
200
200
200
160
160
t s_tqexp
o
o
o
o
o
o
o
o
o
o
o
1
t s_s lpret
50
50
50
50
50
50
50
50
50
50
51
51
t s_rnaxwa i t t s lwa i t
50
o
50
o
50
o
50
o
50
o
50
o
50
o
50
o
50
o
50
o
51
o
51
o
107
PRIORITY LEVEL
o
#
1
#
2
#
3
#
4
#
5
#
6
#
7
#
8
#
9
#
10
#
11
#
Puesto que t s_cpup r i = 1 1 l a fila de l a tabla de despacho que hay que consultar, cuando s e produzca
alguno de los eventos que generan un cambio de prioridad, es la fila asociada al nivel de prioridad
( PRIORITY LEVEL ) 1 1 . Se pueden producir los siguientes eventos:
•
Si el hilo consume su cuanto asignado entonces el valor de t s_cpupri se actualiza con el valor de
t s_tqexp de la fila 1 1 . Luego t s_cpupri = l. Como t s_upri = 1 0 entonces el nuevo valor de
la prioridad en modo usuario de acuerdo con (3.3) y (3 .4) será t s_urndp r i = 1 0 + 1 = 1 1 . Luego
la prioridad en modo usuario del hilo se reduce.
•
Si el hilo es despertado, cuando regresa a modo usuario el valor de t s_cpupr i se actualiza con
el valor de t s_s lpret de la fila 1 1 . Luego t s_cpup r i = 5 1 . Como t s_up r i = 10 entonces el
nuevo valor de la prioridad en modo usuario de acuerdo con (3 .3) y (3 .4) será t s_urndpri = 59.
Luego la prioridad en modo usuario del hilo aumenta.
•
Si el valor del tiempo de espera del hilo t s_di spwa i t es mayor que t s_rnaxwa i t entonces el
valor de t s_cpup r i se actualiza con el valor de t s_lwa i t de la fila 1 1 . Luego t s _cpupr i =
5 1 . Como t s_upr i = 1 0 entonces el nuevo valor de l a prioridad en modo usuario de acuerdo con
(3 .3) y (3.4) será t s _urndpri = 59. Luego la prioridad en modo usuario del hilo aumenta.
El nuevo valor de t s_urndpr i especifica el nuevo valor de la prioridad global, ya que en modo usuario
la prioridad global coincide con el valor de la prioridad en modo usuario. Además también especifica la
fila de la tabla de despacho que hay que consultar para conocer el nuevo valor del cuanto t s_quanturn.
Por ejemplo, si t s_urndp r i = 1 1 entonces t s_gl obpr i = 1 1 . Además hay que consultar la fila asociada
al nivel de prioridad ( PRI ORITY LEVEL ) 1 1 para conocer el nuevo valor del cuanto, que es t s_quanturn
= 1 60 ms (ya que RES = 1 000).
•
Cada clase de planificación especifica cuándo y cómo se modifican las prioridades de los hilos del
núcleo que pertenecen a dicha clase. De forma general, las prioridades de un hilo (global y en modo
usuario) pueden cambiar ante la aparición de determinados eventos, como por ejemplo:
108
Ampliación de sistemas operativos
•
El hilo ha consumido su cuanto de ejecución.
•
El hilo ha sido despertado, es decir, ha regresado al estado preparado para ejecución, porque ya se
ha producido el evento por el que entró en el estado dormido (bloqueado).
•
El hilo ha sido expropiado del procesador para ejecutar un hilo de mayor prioridad.
•
Un usuario utiliza el comando p r i ocnt l para cambiar la prioridad de usuario o/y la clase de
planificación del hilo.
Las prioridades de los hilos también pueden cambiar debido a la ejecución de funciones dependientes
de cada clase de planificación que son invocadas periódicamente para la realización de alguna de las
siguientes operaciones :
•
Procesamiento del tic de reloj. Esta operación afecta únicamente a los hilos del núcleo que están
ejecutándose en los procesadores, es decir, se encuentran en el estado ejecutándose ( T S_ONPROC ) .
Consiste en decrementar en un tic el contador xx_t ime l e f t de la estructura xxpro c , donde xx
puede ser t s , ia, f s s , fx o r t , el cual se inicializa con el valor del cuanto asignado al hilo.
Esta operación también comprueba si dicho contador ha alcanzado el valor O, es decir, el hilo
ha consumido su cuanto. En caso afirmativo, se modifica la prioridad del hilo de acuerdo con la
tabla de despacho (si procede en función de la clase) y se le fuerza a abandonar el procesador.
Esta operación es realizada por la función xx_t i c k ( ) la cual es invocada por el manejador de la
interrupción de reloj que se ejecuta 1 00 veces por segundo.
•
Actualización. Esta operación afecta a los hilos del núcleo en el estado preparado para ejecución
( TS_RUN) o en el estado dormido (TS_SLEEP ) pertenecientes a las clases T S , IA o F S S . Esta
operación es realizada por la función xx_upda t e ( ) una vez por segundo y es invocada mediante
un callout.
En el caso de las clases TS e IA la operación de actualización consiste en incrementar en un
segundo el contador del campo xx_d i s pwa i t de la estructura xxproc_t (donde xx puede ser
t s o i a ) y comprobar si el valor del tiempo de espera del hilo xx_di spwa i t es mayor que
xx_maxwa i t. En caso afirmativo se aumenta el valor de la prioridad usando la tabla de despacho.
B ásicamente con esta operación se pretende evitar el abandono de hilos.
En el caso de la clase F S S la operación de actualización consiste en actualizar el uso de cuotas y
en modificar la prioridad en función de dicho uso.
De acuerdo con la descripción realizada, se puede concluir que la planificación usada en Solaris es lo
suficientemente flexible para poder tratar adecuadamente en computadores con uno o varios procesadores
diferentes tipos de cargas de trabajos: interactivos, por lotes y de tiempo real. Por último conviene señalar
que a pesar del tratamiento privilegiado que reciben los trabajos de tiempo real, Solaris no es un sistema
operativo de tiempo real propiamente dicho sino un sistema operativo de propósito general.
SOBUNIX: planificación, sincronización y mecanismos IPC
3.2.3.
109
Expropiación del procesador
Como ha quedado puesto de manifiesto en las secciones anteriores en la planificación utilizada en los
SOBUNIX siempre tienen preferencia para ser planificadas las unidades planificables (procesos o hilos
del núcleo) situadas en la cola de unidades planificables de mayor prioridad que no esté vacía.
Si una unidad planificable U l se está ejecutando en un procesador P y llega una unidad planificable
U2 a una cola asociada al procesador P de mayor prioridad que la de U l , entonces si U l se está ejecutando
en modo usuario se le expropia el uso del procesador sin esperar a que termine su cuanto, y se planifica
para ejecución a U2. En el caso de que Ul se esté ejecutando en modo núcleo, la expropiación del
procesador depende de si el núcleo es no expropiable o expropiable.
Un núcleo se dice que es no expropiable si a una unidad planificable ejecutándose en modo núcleo
no se le puede expropiar el uso del procesador. Sólo se le puede expropiar en los siguientes casos : para
tratar las interrupciones, cuando regresa a modo usuario o cuando entra en el estado dormido a la espera
de que ocurra algún evento. Ejemplos de SOBUNIX de núcleo no expropiable son SVR3 y BSD 4 . 3 .
Este tipo d e núcleos son más propensos a sufrir e l problema d e la inversión d e prioridad, s i n embargo
reducen el número de mecanismos de sincronización usados en el núcleo (ver sección 3 . 3).
Por el contrario, un núcleo se dice que expropiable si a una unidad planificable ejecutándose en modo
núcleo se le puede expropiar el uso del procesador. En este caso, conviene tener presente que con objeto
de garantizar la integridad de las estructuras del núcleo existen algunas regiones de código del núcleo en
las que no está permitida la expropiación. A dichas regiones se les denomina puntos de no expropiación.
Un ejemplo de SOBUNIX de núcleo expropiable es Solaris . La implementación de un núcleo expropiable
requiere que las estructuras del núcleo estén protegidas por mecanismos de sincronización.
Algunos SOBUNIX, como por ejemplo SVR4, aplican una medida intermedia que consiste en per­
mitir la expropiación del núcleo sólo en determinados puntos del código del núcleo denominados puntos
de expropiación. En estos puntos se garantiza que las estructuras de datos del núcleo se encuentran en un
estado consistente. En estos sistemas una unidad planificable ejecutándose en modo núcleo solo puede
ser expropiada cuando alcanza un punto de expropiación.
La expropiación del procesador requiere la realización de un cambio de contexto y la manipulación
de las colas de prioridad asociadas al procesador P. La unidad planificable que es expropiada sin haber
concluido su cuanto, normalmente para compensarla, es colocada a la cabeza de la cola de prioridad a la
que pertenece.
Para notificar la existencia de una unidad planificable en una cola de mayor prioridad que la unidad
planificable actualmente en ejecución, es decir, para saber si hay que expropiar el procesador, el núcleo
activa uno o varios indicadores que son comprobados cuando se producen determinados eventos.
e
Ejemplo 3.4
El núcleo de BSD 4.3 para notificar que existe un proceso en una cola asociada a un rango de prioridades
más alto que la prioridad del proceso actualmente en ejecución activa un indicador denominado runrun.
Como el núcleo de BSD 4.3 es no expropiable la comprobación del estado de runrun se realiza cuando
el proceso va a retornar a modo usuario. Si runrun está activado se realiza un cambio de proceso.
•
1 10
e
Ampliación de sistemas operativos
Ejemplo 3.5
El núcleo de Solaris para notificar que existe un hilo del núcleo en una cola asociada a un rango de prio­
ridades más alto que la prioridad del hilo actualmente en ejecución, activa los indicadores cpu_runrun
o cpu_krunrun de la estructura cpu asociada al procesador en que se está ejecutando el hilo.
Recuérdese que en Solaris cada procesador tiene asociada un conjunto de colas de prioridad independien­
tes, luego existe una estructura cpu por cada procesador. Estos indicadores son comprobados cuando se
producen cambios en la prioridad de los hilos y se manipulan las colas de prioridad.
Para un determinado procesador P, el indicador cpu_krunrun se activa cuando un hilo es colocado en
una cola de P cuya prioridad es mayor o igual que 1 00 y además dicha prioridad es mayor que la del hilo
actualmente ejecutándose en P.
Por su parte, el indicador cpu_runrun se activa cuando un hilo es colocado en una cola de P cuya
prioridad es menor que 1 00 y además es mayor que la del hilo actualmente ejecutándose en P.
La expropiación asociada a cpu_krunrun se realiza más rápidamente que la asociada a cpu_runrun,
esto es así para reducir la latencia de despacho de los hilos asociados a aplicaciones de tiempo real y de
las interrupciones que son las actividades más prioritarias.
En S olaris la expropiación se deshabilita temporalmente cuando un hilo ejecutándose en modo núcleo
está dentro de un punto de no expropiación.
•
3.3.
Mecanismos de sincronización del núcleo en SOBUNIX
El código del núcleo de los SOBUNIX es reentrante. Esta característica posibilita el que varios hilos
del núcleo 6 ejecutándose en modo núcleo puedan estar ejecutando concurrentemente la misma región de
código del núcleo.
En un sistema monoprocesador solo un hilo se encontrará en el estado ejecutándose en modo núcleo.
En un sistema multiprocesador pueden existir varios hilos ejecutándose en modo núcleo, uno en cada
procesador existente.
En el código del núcleo existen secciones críticas asociadas a diferentes recursos críticos, como por
ejemplo las estructuras de datos del núcleo. Para garantizar la exclusión mutua en la ejecución de una
sección crítica del núcleo asociada a un cierto recurso crítico, el núcleo utiliza diferentes mecanismos de
sincronización, como por ejemplo los cerrojos y los semáforos. Estos mecanismos serán descritos en las
próximas secciones.
Los diseñadores del núcleo de un sistema operativo son los encargados de elegir los tipos de meca­
nismos de sincronización que utilizarán en el núcleo y dónde los aplicarán.
6 En esta sección se va a considerar, salvo que se indique lo contrario, que las unidades planificables son los hilos del núcleo.
SOBUNIX : planificación, sincronización y mecanismos IPC
3.3. 1.
111
Cerrojos
U n cerrojo (lock) e s una primitiva de sincronización que consiste e n u n indicador entero que puede
encontrarse en dos estados: abierto o libre (valor O) y cerrado o adquirido (valor 1 ) . Sobre un cerroj o se
pueden realizar dos operaciones básicas 7 :
•
•
Cerrar o adquirir cerrojo. Esta operación lee el valor del cerrojo, si vale O (abierto) lo pone a 1
(cerrado). Por el contrario si el cerrojo vale 1 (cerrado) entonces el hilo que invoca esta operación
debe esperar a que el cerrojo se ponga a O. Esta espera puede implementarse (depende del tipo de
cerrojo) como una espera activa o durmiendo en una cola de hilos dormidos asociada al cerrojo.
La comprobación y configuración del valor cerrojo se implementa con una instrucción máquina
especial que se ejecuta de forma atómica, como por ejemplo la instrucción comprobar y configurar
(test and set).
Abrir o liberar cerrojo. Esta operación configura el cerrojo al valor O (abierto) . Además si el
cerrojo no implementa espera activa entonces despierta, si existe alguno, a un hilo de la cola de
hilos dormidos del cerrojo.
Cada recurso crítico del núcleo tiene asociado su propio cerrojo. Para garantizar la exclusión mutua
en el uso de un recurso crítico R del núcleo, un hilo del núcleo antes de entrar en una sección crítica
asociada a R realiza una operación cerrar cerrojo para adquirir R. Cuando el hilo termina de ejecutar la
sección crítica realiza una operación abrir cerrojo para liberar a R y que otro hilo pueda usar el recurso.
En función de cómo se implementa la espera de un hilo del núcleo HN 1 dentro de una operación
cerrar cerrojo se distinguen tres tipos de cerrojos:
•
Spinlock 8 • La espera del hilo es activa, es decir, el hilo comprueba el valor del cerrojo dentro
de un bucle que se ejecuta mientras el cerrojo permanezca cerrado. La espera activa supone un
inconveniente si se dilata mucho en el tiempo ya que la ejecución del hilo HN 1 en un procesador
impide que otros hilos lo usen.
La principal ventaj a de los spinlocks es la rapidez con que HN l adquiere el cerrojo. Cuando el
hilo HN2 que mantiene cerrado el cerrojo lo abre, el hilo HN 1 que espera activamente lo adquiere
rápidamente puesto que HN 1 ya está ejecutándose y no hay que realizar un cambio de contexto.
Obviamente se está suponiendo que en el computador existente al menos dos procesadores, en
uno se ejecuta HN2 y en el otro HN l . Nótese que en un computador con un único procesador si
el núcleo es no expropiable y HN 1 realiza una operación cerrar cerrojo sobre un cerrojo que se
encuentra cerrado entonces la espera activa será infinita.
•
Cerrojo con bloqueo. El hilo HN 1 se bloquea y es colocado en una cola de hilos dormidos asociada
al cerrojo. Cuando el cerroj o sea abierto, se despertará al primer hilo de la cola o al hilo de mayor
prioridad, el cual debe realizar otra operación cerrar cerrojo para adquirir el cerrojo. La principal
7El nombre que reciben estas operaciones varía en la literatura y en los diferentes SOBUNIX.
8 Spinlock es un término inglés que podría traducirse como cerrojo con vuelta. Esta traducción al español no está muy
extendida en la literatura por ello se ha preferido mantener el término en su idioma original .
1 12
Ampliación de sistemas operativos
ventaja de los cerrojos con bloqueo es que al no realizar espera activa no acaparan un procesador
mientras esperan, a diferencia de los spinlocks. Su principal inconveniente es que la adquisición
de un cerrojo es más lenta que en el caso de los spinlocks ya que requiere al menos la realización
de dos cambios de contexto.
•
e
Cerrojo adaptativo. El hilo HN l puede realizar una espera activa o bloquearse. El tipo de espera
dependerá del estado del hilo HN2 que actualmente mantiene el cerrojo cerrado. Si HN2 se está
ejecutando en un procesador P l entonces tardará poco en abrir el cerrojo, luego HN l realiza una
espera activa en otro procesador P2. Por el contrario si HN2 se encuentra en el estado bloqueado
puede tardar en abrir el cerrojo, luego HN l espera bloqueado. Estos cerrojos pretenden evitar los
inconvenientes de los spinlocks y de los cerrojos con bloqueo. Su principal desventaj a es que su
implementación es más compleja ya que hay que implementar mecanismos para detectar que hilo
retiene un cerrojo y en que estado se encuentra.
Ejemplo 3.6
En la Figura 3.4 se muestra, en pseudocódigo basado en C, un ejemplo de uso de un cerrojo L de tipo
spinlock. Este cerrojo se usa para garantizar la exclusión mutua en el uso del campo d de la estructura de
datos del núcleo da to sN. Asimismo en la Figura 3 . 5 se muestra una posible definición de las operaciones
cerrar cerrojo y abrir cerrojo del spinlock. En la operación c e r rar_c erroj o se utiliza la instrucción
atómica c omprobar_y_c on f i gurar que comprueba el valor del cerrojo. Si el cerrojo vale O (abierto)
lo pone a ! (cerrado) y devuelve TRUE con lo que sale del bucle whi l e y se termina la espera activa. Por
el contrario, si el cerrojo vale 1 (cerrado) entonces devuelve FALS E y se vuelve a ejecutar el bucle, es
decir, continúa la espera activa.
•
s t ruc t dato s_nuc l e o {
s p i n l o c k_t L ;
int d ;
da t o s N ;
vo i d func i on ( )
c e rrar_c erro j o ( &da t o s N . L ) ;
da t o s N . d= l ;
/ * S e c c i ón c r í t i c a * /
abr i r_cerro j o ( &da t o s N . L ) ;
Figura 3.4 - Ejemplo de uso de un cerrojo de tipo spinlock para garantizar la exclusión mutua
SOBUNIX : planificación, sincronización y mecanismos IPC
113
vo i d c errar_ c e r ro j o ( s p i n l o c k_ t * C e rro j o )
wh i l e ( c omprobar_y_ c on f i gurar ( c e r r o j o ) ! =
vo i d abr i r_c e r r o j o ( s p i n l o c k_t
0) ;
* C e rro j o )
* C erroj o = O ;
Figura 3.5 - Posible definición de las operaciones
de tipo spinlock
c e r r a r_c e r r o j o y abr i r_c err o j o
de un cerrojo
En general al diseñar el código del núcleo de un sistema operativo se intenta que las regiones críticas
no sean muy numerosas y que éstas sean cortas. En consecuencia se suelen utilizar spinlocks para pro­
teger la mayoría de los recursos críticos del núcleo, ya que la espera activa será pequeña. Para aquellos
recursos críticos cuyas secciones críticas asociadas sean más largas o puedan requerir la suspensión del
hilo que se encuentra dentro de ellas entonces se utilizan cerrojos con bloqueo. Si no se sabe si el hilo
puede suspenderse entonces mej or usar cerrojos adaptativos.
De acuerdo con el funcionamiento de los cerrojos descrito en los párrafos anteriores, cuando un hilo
cierra un cerroj o asociado a un recurso crítico R, ningún otro hilo puede acceder a R. A los cerrojos con
este comportamiento en algunos sistemas se les denomina cerrojos exclusivos o cerrojos mutex.
Existe otro tipo de cerroj o denominado cerrojo lector1 escritor o cerrojo R/W cuyo funcionamiento
depende del tipo de acceso que se desee realizar sobre el recurso. Si el acceso es de escritura entonces
solo un hilo puede acceder al recurso. Por el contrario, si el acceso es de lectura entonces pueden acceder
múltiples hilos. Básicamente un cerrojo R/W resuelve uno de los problemas clásicos de sincronización
de hilos concurrentes : el problema de los lectores y los escritores [Díaz et al. , 20 1 1 ] .
Los cerrojos R/W a diferencia de los cerrojos mutex requieren en su implementación de dos colas de
hilos dormidos: una cola para los hilos lectores y otra para cola los hilos escritores. Los lectores duermen
mientras haya un escritor usando el recurso. Por su parte los escritores duermen si hay algún hilo, ya sea
lector o escritor.
3.3.2.
Semáforos
Un semáforo binario, también denominado mutex, es una variable entera, que puede tomar los valores
O o 1 y sobre la que es posible realizar las siguientes operaciones 9 :
•
ini t_s em ( S , va l o r ) . Inicializa el semáforo S a un determinado valor, es decir, S =va l o r, don­
de va l o r es igual a O o a l .
9EJ nombre dado a estas operaciones varía en la literatura y en Jos diferentes SOBUNIX. Aquí se utiliza el nombre propuesto
en [Díaz et al . , 20 1 1 ] . Las operaciones wa i t_s em ( S ) y s i gnal_s em ( S ) equivalen, respectivamente, a las operaciones
P(S) y V(S) definidas en [Dijkstra, 1 965 ] .
Ampliación de sistemas operativos
114
•
wa i t_s em ( S ) . Comprueba el valor del semáforo s . Si S = O , entonces el proceso pasa al estado
dormido y es colocado en una cola de hilos dormidos asociada al semáforo. Si S = l , entonces pone
el semáforo a O y el hilo puede continuar su ejecución.
•
s i gna l_s em ( s ) . Comprueba si la cola de hilos dormidos asociada al semáforo S está vacía. En
caso afirmativo, pone el semáforo a 1 , y continúa su ejecución. En caso negativo, es decir, hay hilos
bloqueados en el semáforo, entonces el sistema operativo elimina de la cola asociada al semáforo a
uno de los hilos dormidos, y le despierta lo que hace que pase al estado preparado para ejecución.
Existe, además, otro tipo de semáforo denominado semáforo general o semáforo con contador que es
una variable entera que puede tomar más valores aparte de O o l . Para un semáforo general la operación
ini t_s em ( s , val or ) consiste en inicializar el valor del semáforo S a un determinado valor entero
positivo N, es decir, S =N.
Por su parte la operación wa i t_s em ( s ) cuando se implementa para un semáforo general disminuye
en una unidad el valor del semáforo. Es decir, S = S - 1 . Si el valor resultante es un número negativo
entonces el hilo que ha invocado esta operación entra en el estado dormido y es añadido a la cola de
hilos dormidos asociada al semáforo. En el caso de la operación s i gnal_s em ( s ) se incrementa en una
unidad el valor del semáforo, es decir, S = S + l . Si el valor resultante es menor o igual a O entonces se
elimina de la cola asociada al semáforo uno de los hilos dormidos, y se le despierta, lo que hace que pase
al estado preparado para ejecución.
La realización de las operaciones wa i t_s em y s i gna l_s em, independientemente del tipo de se­
máforo, requiere garantizar la exclusión mutua durante la comprobación y configuración del valor del
semáforo. Dicha exclusión mutua se suele implementar con una instrucción máquina especial que se
ejecuta de forma atómica.
La principal ventaja de los semáforos es que proporcionan un mecanismo de sincronización a alto
nivel que se puede aplicar para resolver diferentes problemas de sincronización. Así, los semáforos bina­
rios se utilizan para garantizar la exclusión mutua o para sincronizar la ejecución de hilos que esperan por
un evento. Por su parte, los semáforos generales se pueden usar para las mismas funciones que los semá­
foros binarios. Además permiten contar el número de instancias disponibles de un determinado recurso
crítico, para ello simplemente hay que inicializar el semáforo con el número de instancias existentes.
El principal inconveniente de los semáforos [Vahalia, 1 995] es que son abstracciones de alto nivel
que se implementan con mecanismos de sincronización de baj o nivel para poder garantizar la atomicidad
y la exclusión mutua. La implementación de las operaciones wa i t_s em y s i gnal_s em requiere una
operación atómica de bajo nivel que garantice el acceso con exclusión mutua a la variable semáforo.
Por otra parte, el bloqueo y desbloqueo de procesos requiere la realización de cambios de contexto y la
manipulación de las colas de procesos preparados y de las colas de procesos dormidos, lo que ralentiza
las operaciones sobre los semáforos.
Los núcleos de los primeros SOBUNIX utilizaban como mecanismo de sincronización principal­
mente semáforos. Posteriormente, debido a la relativa lentitud de sus operaciones, han sido sustituidos
por cerrojos. En los núcleos de los S OBUNIX actuales los semáforos binarios se utilizan principalmente
para garantizar la exclusión mutua sobre aquellos recursos críticos del núcleo que pueden ser usados
SOBUNIX: planificación, sincronización y mecanismos IPC
115
sin fuertes restricciones de tiempo. También se utilizan semáforos generales para contar el número de
instancias disponibles de un determinado recurso crítico del núcleo.
e
Ejemplo 3.7
En la Figura 3 . 6 se muestra en pseudocódigo basado en C un ejemplo de uso de un semáforo binario
mu t ex l , para garantizar la exclusión mutua en el uso de una sección crítica asociada a un determinado
recurso crítico del núcleo.
Asimismo, en la Figura 3 .7 se muestra un ejemplo de uso de un semáforo general c on t ador para contar
las instancias disponibles de un determinado recurso crítico del núcleo del que existen M instancias .
•
f*
I n i c i a l i z a c i ón de l
s emá f o ro * f
s emá f o ro_binar i o mu t ex l ;
i n i t_s em ( &mu t exl ,
1) ;
f * U s o para garant i z ar l a exc l u s i ón mu tua * 1
wa i t_s em ( &mu t ex l ) ;
e j ecuc i ón s e c c i ón c r í t i c a ;
s i gnal_s em ( &mu t e x l ) ;
Ejemplo de uso de un semáforo binario para garantizar la exclusión mutua en el uso de una
sección crítica asociada a un cierto recurso del núcleo
Figura 3.6
f*
-
In i c i a l i z a c i ón del
s emá f oro * f
s emá f o ro_general c o n t a do r ;
i n i t_s em ( & contador ,
M) ;
f * U s o para contar núme r o de i n s t anc i a s d i sponi b l e s
*f
wa i t_s em ( &contador ) ;
u s o i n s t anc i a recur s o ;
s i gna l_s em ( & c on t ador ) ;
Figura 3.7 - Ejemplo de uso de un semáforo general para contar el número de instancias disponibles de
un recurso del núcleo
1 16
3.4.
Ampliación de sistemas operativos
Dormir 1 despertar y colas de hilos dormidos en SOBUNIX
En los SOBUNIX cuando un hilo ejecutándose en modo núcleo tiene que esperar un tiempo que
puede sea largo por un evento o recurso se invoca a una rutina del núcleo para dormir (bloquear) el hilo.
Esta rutina coloca al hilo en una cola de hilos dormidos del núcleo, cambia su estado a dormido e invoca
al planificador para que seleccione para ser ejecutado a otro hilo, lo cual requerirá, entre otras acciones,
la realización de un cambio de contexto.
Cuando se produzca el evento o se libere el recurso, el núcleo invocará una rutina para despertar
(desbloquear) al hilo esperando por dicho evento o recurso. Esta rutina debe encontrar al hilo en la cola
de hilos dormidos adecuada, cambiar el estado del hilo a preparado para ejecución y colocarlo en una
cola de hilos preparados para ejecución en espera de ser planificado para ejecución en un procesador.
Cada recurso o evento tiene asignado un canal de espera (wait channel), también denominado canal
de dormir (sleep channel), que es un número de 32 bits que almacena la dirección del recurso. Nótese
que todo evento también estará asociado a un recurso. Por ejemplo, el evento de que se complete una
operación de E/S estará asociado a un determinado buffer del núcleo donde se encontrará el dato que
desea leer o escribir. La rutina del núcleo que bloquea el hilo almacena el canal de espera asociado al
recurso o evento en un campo de la estructura de datos del hilo.
Por otra parte, cada canal de espera tiene asociada una cola de hilos dormidos. La asociación se
realiza mediante una función hash ya que el número de colas de hilos dormidos que mantiene el núcleo
es inferior al número de canales. Por lo tanto varios canales de espera pueden tener asociada la misma
cola.
e
Ejemplo 3.8
Considérese dos estructuras de datos del núcleo Rl y R2 cuyo acceso está protegido con los cerrojos C l
y C2, respectivamente. Supóngase que un hilo del núcleo HN l cierra C l y entra en el estado dormido en
espera de que se complete una operación de lectura de un bloque del disco duro que se almacenará en
R l . Mientras duerme HN l , otro hilo HN2 también necesita usar R l y realiza una operación cerrar sobre
C l . Como C l está cerrado por HN l , entonces HN2 entra en el estado dormido en espera de que HN l
abra C l .
Por otra parte, supóngase que un hilo del núcleo HN3 cierra C2. Mientras HN3 opera sobre la estructura
R2 otro hilo HN4, que requiere usar también R2, realiza la operación cerrar C2 y entra el estado dormido
en espera de que HN3 abra C2.
La dirección de cada recurso Rl y R2 constituye dos canales de espera independientes Wl y W2. En este
escenario, HN l y HN2 duermen en el mismo canal de espera W l . Mientras que HN4 duerme en el canal
de espera W2.
En la Figura 3 . 8 se muestra un posible estado de las colas de hilos dormidos del núcleo. Se ha supuesto
que la función hash ha asignado la misma cola de hilos dormidos a los canales W l y W2, aunque podría
haberles asignado colas diferentes, dependerá del valor de W l , de W2 y de la función hash utilizada .
•
SOBUNIX : planificación, sincronización y mecanismos IPC
Cerrojo
_____..
1 17
C1
Recurso
Rl
Canal
de espera
Wl
HN4
C2
R2
Conjunto de colas de hilos dormidos
Figura 3.8 - Asignación de colas de hilos dormidos del Ejemplo 3 . 8
L a existencia d e hilos esperando por distintos canales dentro d e una misma cola introduce retrasos
a la hora de despertar a los hilos esperando en un determinado canal, ya que hay que examinar uno
a uno todos los hilos de la cola. Para eliminar este retraso, podría mantenerse una cola por canal. El
inconveniente de esta solución es que consume bastante memoria principal ya que se necesita un número
de colas elevado.
Una solución más eficiente desde el punto de vista del consumo de memoria es la utilizada en Solaris.
Esta solución tiene en cuenta el hecho de que muchos de los bloqueos de los hilos en modo núcleo
se producen en objetos de sincronización (cerrojos, semáforos, . . . ) que protegen los recursos críticos.
Además en un determinado instante de tiempo solo se están utilizando una pequeña parte de los muchos
objetos de sincronización existentes en el código del núcleo.
Teniendo en cuenta las consideraciones anteriores, cada objeto de sincronización del núcleo de So­
laris tiene un campo de dos bytes que contiene un puntero a un turnstile que es una estructura de datos
que contiene, entre otras informaciones, la cabecera de una cola de hilos dormidos. Los hilos en la cola
de un turnstile se organizan por prioridad. Además existe la posibilidad de despertar a todos los hilos de
la cola o solamente al más prioritario.
El núcleo mantiene un conj unto de turnstiles de tamaño dinámico, siempre mayor que el número de
hilos del núcleo activos. Cuando en un objeto de sincronización se bloquea un primer hilo el núcleo asig­
na al objeto de sincronización un turnstile para implementar una cola de hilos dormidos. En el momento
que la cola se queda vacía el tumstile queda libre y puede ser asignado a otro objeto de sincronización.
Por lo tanto, en Solaris conviven dos tipos de colas de hilos dormidos : las implementadas con turns­
tiles para bloqueos en objetos de sincronización y las colas de hilos dormidos en canales de espera para
1 18
Ampliación de sistemas operativos
eventos o recursos no relacionados con objetos de sincronización, como por ejemplo la finalización de
una operación de E/S. Obviamente el número de colas de este segundo tipo es mucho más pequeño que
en otros S OBUNIX gracias al uso de turnstiles.
e
Ejemplo 3.9
En la Figura 3.9 se muestra el estado del conjunto de turnstiles del núcleo de un sistema Solaris para el
escenario descrito en el ejemplo anterior. Se observa que los cerrojos Cl y C2, al tener hilos bloquea­
dos en ellos, tienen asignado cada uno un turnstile (TU) para implementar las colas de hilos dormidos
correspondientes.
Asignado
a Cl
Recurso
Rl
Canal
de espera
Wl
Libre
Asignado
a C2
--------·
Libre
R2
HN2
1 1
8=8
TO
TU
HN4
1 1
TO
W2
Conjunto de tumstiles
Figura 3.9 - Ejemplo de uso de tumstiles
•
3.5.
Mecanismos de comunicación entre procesos en SOBUNIX
Los SOBUNIX ponen a disposición de los programadores de aplicaciones diferentes mecanismos
para garantizar la exclusión mutua en el uso de recursos críticos, sincronizar su ejecución, esperar por
la aparición de algún evento o intercambiar información. A este conjunto de mecanismos se les cono­
ce de forma general como mecanismos de comunicación entre procesos, o más abreviadamente como
mecanismos IPC(InterProcess Communications).
SOBUNIX: planificación, sincronización y mecanismos IPC
1 19
Es el programador de aplicaciones el que decide qué mecanismos IPC utilizar y dónde utilizarlos
dentro del código de sus aplicaciones. El uso de estos mecanismos requiere la invocación de las lla­
madas al sistema oportunas. El núcleo se encarga de atender dichas llamadas al sistema y mantener las
estructuras de datos necesarios para soportar dichos mecanismos IPC.
En las siguientes secciones se describen los mecanismos IPC introducidos por primera vez en 1983
en el System V Release 1 de AT&T y posteriormente adoptados por el resto de SOBUNIX: los semáforos,
las colas de mensajes y la memoria compartida. A estos tres mecanismos se les conoce de forma general
como mecanismos IPC del System V. También se describen otros mecanismos IPC como las señales y
las tuberías, usados principalmente en los intérpretes de comandos.
3.5.1.
Mecanismos IPC del System V
Los tres mecanismos IPC del System V: semáforos, colas de mensajes y memoria compartida, aun­
que son mecanismos distintos son soportados por el núcleo de forma muy similar. El núcleo mantiene una
tabla por cada tipo de mecanismo IPC. Una entrada en una de estas tablas se implementa mediante una
estructura de datos que contiene información de administración y control sobre un determinado recurso
IPC, es decir, sobre una instancia de un determinado mecanismo IPC. Entre la información contenida en
una entrada se encuentra la siguiente:
•
Creador del recurso IPC. El UID y el GID del proceso que solicita la creación el recurso.
•
Propietario del recurso IPC. El UID y el GID del proceso que actualmente es el propietario del
recurso. Inicialmente, el creador es el propietario del recurso, aunque el mismo o el superusuario
pueden transferir la propiedad del recurso a otro proceso.
•
Permisos del recurso IPC. Mascara de bits, similar a la máscara de modo de un archivo, que permite
establecer los permisos de acceso (lectura y/o escritura) al recurso para el propietario del recurso,
el grupo propietario y el resto de usuarios.
•
Llave o clave del recurso IPC . Número entero facilitado al núcleo por el proceso que solicita la
creación o el acceso al recurso IPC. Solo los procesos que conozcan dicha llave podrán acceder
al recurso. Luego se puede considerar como una especie de contraseña de acceso. La llamada al
sistema f t ok permite crear una llave de acceso.
•
Información propia de cada tipo de recurso IPC. Como por ejemplo punteros que permiten locali­
zar a los diferentes componentes de un determinado recurso IPC.
El número máximo de entradas que puede tener la tabla asociada a un determinado tipo de mecanismo
IPC, o lo que es lo mismo el número de recursos IPC de un determinado tipo, es un parámetro que puede
ser configurado por el superusuario.
Por otra parte, el núcleo asigna a cada recurso IPC creado un determinado identificador numérico
entero que lo identifica de manera unívoca. El núcleo usa este identificador para localizar la entrada
asociada al recurso en la tabla correspondiente. La asignación del identificador se realiza en el momento
Ampliación de sistemas operativos
120
de la creación o asignación del recurso. El núcleo devuelve este identificador al proceso para que lo
utilice como argumento de entrada en las posteriores llamadas al sistema que vaya a realizar para operar
sobre el recurso, y así agilizar su localización.
Semáforos
La implementación que hace el núcleo de los semáforos como mecanismo IPC es distinta a la im­
plementación de los semáforos como mecanismo de sincronización del núcleo estudiada en la sección
3 . 3 .2, y no deben ser confundidas. Un semáforo implementado como mecanismo IPC es una ampliación
del concepto de semáforo general que consiste en un conjunto de N semáforos (N = 1 , 2, 3, . . . ) sobre el
cual es posible realizar diferentes operaciones, ya sea sobre todos o algunos de sus elementos.
Para gestionar los conjuntos de semáforos existentes el núcleo mantiene una tabla. Cada entrada de
esta tabla contiene, entre otros, los siguientes datos sobre un determinado conjunto de semáforos : creador,
propietario, llave, permisos de acceso, puntero al array de semáforos que forma parte del conjunto y
número N de semáforos que forman parte del conjunto.
El núcleo asocia a cada conj unto de semáforos un identificador numérico entero positivo s emid que
lo identifica de manera univoca y que le permite localizar rápidamente su entrada asociada en la tabla
que mantiene para soportar los semáforos.
Por cada semáforo j (j = O, . . . , N - 1 ) perteneciente al conjunto de semáforos s emid el núcleo
mantiene una estructura con los siguientes datos: el valor actual del semáforo, que es un número entero
positivo o cero, el número de procesos esperando a que el semáforo valga cero, el número de procesos
esperando a que el semáforo se incremente y el PID del proceso que hizo la última operación sobre el
semáforo. También mantiene una cola de procesos dormidos en el semáforo.
El núcleo soporta las siguientes llamadas al sistema asociadas con los semáforos :
•
s emi d= s emge t ( l l ave , N , i nd ) . Esta llamada a l sistema permite crear u n conjunto d e semá­
foros u obtener el uso de un conjunto ya creado. Requiere como argumentos de entrada la llave
numérica ( l l ave) que se quiere asociar al conjunto de semáforos o que ya tiene asociada (si ya
está creado), el número N de semáforos que tendrá el conjunto y una serie de indicadores ( i nd)
que permiten especificar, entre otras cosas, los permisos de acceso al conjunto de semáforos. Un
indicador utilizado frecuentemente es I PC_CREAT que fuerza a crear un conjunto nuevo si no
existe uno ya creado. Si la llamada al sistema se ejecuta con éxito entonces guarda en s emid el
identificador del conjunto de semáforos. En caso contrario almacena en s emid el valor -l.
•
r = s emop ( s emi d , oper , M ) . Esta llamada al sistema permite realizar operaciones sobre los semá­
foros de un determinado conjunto de semáforos. Requiere como argumentos de entrada el identifi­
cador s emid del conjunto de semáforos, un puntero oper a un array de estructuras de tipo s embu f
y el número de elementos M de dicho array.
Una estructura s embu f contiene la siguiente información:
- El identificador j (j = O, . . . , N - 1 ) del semáforo del conjunto s emid sobre el que se quiere
realizar la operación.
SOBUNIX: planificación, sincronización y mecanismos IPC
121
El tipo de operación s em_op que se quiere realizar sobre el semáforo j del conjunto s emid.
Si s em_op es un entero positivo mayor que cero entonces se añade s em_op al valor del
semáforo y se despiertan a los procesos que estaban dormidos en espera de que el valor del
semáforo se incrementase.
Si s em_op es un entero negativo entonces se comprueba si el valor del semáforo es mayor
o igual que el valor absoluto de s em_op. En caso afirmativo se resta s em_op del valor del
semáforo. En caso negativo el proceso entra en el estado dormido en espera de que se cumpla
la condición.
Si s em_op es igual a cero se comprueba si el valor del semáforo es igual O. En caso afirmativo
no se realiza ninguna modificación sobre el valor del semáforo. En caso contrario el proceso
entra en el estado dormido en espera de que se cumpla la condición.
Indicadores. El indicador I PC_NOWAIT establece que en caso de que no se pueda realizar la
operación correspondiente no se bloquee el proceso y se devuelva un mensaje de error. Por
defecto todas las operaciones son bloqueantes. Por su parte el indicador S EM_UNDO indica al
núcleo que la operación debe ser deshecha cuando el proceso termine. Esta opción permite
evitar que un semáforo quede permanente bloqueado por un proceso que finalice antes de
poder liberar el recurso. El núcleo mantiene por cada semáforo una lista con las operaciones
que tienen que ser deshechas.
Cada operación sobre un semáforo j definida en una estructura s embu f es realizada de forma
atómica por el núcleo. De esta forma, hasta que una operación no se completa no se puede realizar
otra.
Si la llamada al sistema s emop se ejecuta con éxito entonces en r se almacena el valor O . En caso
de error se almacena - l .
•
r = s emc t l ( s emi d , j , o rden , arg ) . Esta llamada permite leer y configurar los datos de control
que el núcleo mantiene en la entrada asociada a un determinado conjunto de semáforos en la tabla
de semáforos. También permite leer y configurar los valores de todos o alguno de los semáforos de
un determinado conjunto. Esta llamada requiere como parámetros de entrada el identificador del
conjunto de semáforos s emi d, el identificador j de un semáforo del conjunto, un número entero
o constante simbólica orden que especifica la operación que se quiere realizar sobre los datos de
administración y control del semáforo, y los argumentos arg asociados a dicha operación. Algunos
de los posibles valores de orden son:
I PC_RMID. Especifica que el recurso IPC, en este caso el conjunto de semáforos s emid debe
ser eliminado. Además despierta a todos los procesos dormidos esperando en los semáforos
del conjunto.
SETALL . Configura el valor de todos los semáforos del conjunto s emid al valor especificado
en arg.
GETALL. Lee el valor de todos los semáforos del conjunto s emi d y los almacena en arg.
122
Ampliación de sistemas operativos
SETVAL. Configura el valor del semáforo j del conjunto s emid al valor especificado en arg.
GETVAL. Lee el valor del semáforo j del conjunto s emi d y lo almacena en r.
Si la llamada al sistema se ejecuta con éxito entonces en r se almacena O o un valor que depende
de o rden. En caso contrario en r se almacena - l .
# i n c lude < s td i o . h>
# i n c lude < sys / typ e s . h>
# i n c l ude < sys / ipc . h>
# i n c lude < sys / s em . h>
#de f ine CLAVE 3 4 2 1 L
1 * L l ave * 1
#de f i n e PERMI SOS 0 6 6 6
1 * L e c tura y e s c r i tura para t o d o s l o s usuar i o s
*1
s t ruc t s embu f decremen t a r [ 1 ] = { 0 , - 1 , 0 } ;
s t ruc t s embu f increment a r [ 1 ] = { 0 , 1 , 0 } ;
i n t s em i d ;
i n t r e s u l t ado ;
vo i d i n i t_s em ( i nt val )
1 * C r e a r u obtener un c o n j u n t o de s emá f o r o s de un s emá f o r o
I
( N= 1 )
*1
s em i d= s emge t ( CLAVE , 1 , I PC_CREAT PERM I S O S ) ;
if
( s em i d= = - 1 )
1 * C omprobar s i ha hab ido a l gún e r r o r * 1
p r i n t f ( " \ nErro r " ) ;
ex i t ( - 1 ) ;
1*
I n i c i a l i z a r e l s emá f o r o a 1
*1
r e s u l tado= s emc t l ( s emi d , O , S E TVAL , va l ) ;
vo i d wa i t_s em ( )
r e s u l tado = s emop ( s emi d , & d e c rementar [ 0 ] , 1 ) ;
vo i d s i gna l_s em ( )
r e s u l tado = s emop ( s em i d , & i n c r ementar [ 0 ] , 1 ) ;
Figura 3.10 - Código C del archivo de cabecera c omun . h del Ejemplo 3 . 1 0
SOBUNIX: planificación, sincronización y mecanismos IPC
# i nc lude
123
" c omun . h "
i n t ma i n ( }
int N= 2 ;
/ * Nume ro de p r o c e s o s hi j o s a c r e ar * /
i n i t_s em ( l } ;
wh i l e ( N> O }
{
N=N- 1 ;
i f ( fork ( } = = 0 }
{
p r i n t f ( " P I D= %d An t e s de l a r e g i ó n c r i t i c a \ n " , g e t p i d ( } } ;
wa i t_s em ( } ;
p r i n t f ( " P I D= %d Dentro de
la regi ón c r i t i c a \ n " , getp i d ( } } ;
s l e ep ( S } ;
p r i n t f ( " P I D= %d D e s p i e r t o y s a l go de l a reg i ón c r i t i c a \ n " , g e t p i d ( } } ;
s i gnal_s em ( } ;
exi t ( 0 } ;
re turn O ;
Figura 3 . 1 1 - Código C del programa prog3 1 del Ejemplo 3 . 1 0
e
Ejemplo 3.10
En la Figura 3 . 1 0 se muestra el código C de un archivo de cabecera c omun . h que hace uso de las lla­
madas al sistema s emg e t , s emop y s emc t l sobre un conjunto s emid que consta de un único semáforo
(N= 1 ) que se utiliza para implementar un semáforo binario (ver sección 3 . 3 .2) y sus operaciones básicas
ini t_s em, wa i t_s em y s i gna l_s em.
En la Figura 3 . 1 1 se muestra el código C del programa prog3 1 que utiliza el semáforo binario definido
en c omun . h para garantizar la exclusión mutua en el uso de una cierta región critica. S upóngase que se
invoca a prog3 1 desde la línea de órdenes de un intérprete de comandos y que éste crea al proceso A
para ejecutar este programa. El proceso A crea dos procesos hijos: B y C, y termina su ejecución. Se va
suponer que B tiene un PID=995 y que C tiene un PID=996.
Cuando se planifica para ejecución al proceso hij o B en primer lugar imprime en pantalla el mensaje
P I D= 9 9 5 Ant e s de la región c r i t i c a
E n segundo lugar invoca a la función wa i t_s em ( ) que decrementa en una unidad e l valor del semáforo.
Este semáforo estaba inicializado a 1 , tras la operación toma el valor O.
En tercer lugar imprime en pantalla el mensaje
124
Ampliación de sistemas operativos
P I D= 9 9 5 Dentro de l a regi ón c r i t i c a
e invoca a la llamada al sistema s l e ep ( 5 ) que suspende la ejecución del proceso B durante 5 segundos.
Mientras B está suspendido se ejecuta el proceso hijo C, que imprime en pantalla
P I D= 9 9 6 Ant e s de la reg i ón c r i t i c a
e invoca a la función wa i t_s em ( ) . Como el semáforo tiene el valor O el proceso C entra en el estado
dormido y es colocado en cola de procesos dormidos asociada al semáforo. Una vez transcurridos los
5 segundos se despierta al proceso B . Cuando se planifica para ejecución en primer lugar imprime en
pantalla
PID= 9 9 5 D e sp i e r t o
y
salgo de la r e g i ón c r i t i c a
E n segundo lugar invoca a l a función s i gnal_sem ( ) que despierta a l proceso C. Finalmente e l proceso
B invoca a la llamada al sistema exi t para terminar su ejecución.
Cuando C es planificado para ejecución imprime en pantalla el mensaje
P I D= 9 9 6 Dentro de l a regi ón c r i t i c a
e invoca a la llamada al sistema s l e ep ( 5 ) que suspende la ejecución del proceso C durante 5 segundos.
A continuación imprime en pantalla
PID= 9 9 6 D e sp i e r t o
y
s a l go de la r e g i ón c r i t i c a
Por último ejecuta l a operación s em_s i gna l ( ) que incrementa e n una unidad e l valor del semáforo,
ahora toma el valor 1 , e invoca a la llamada al sistema exi t para terminar su ejecución.
•
Colas de mensajes
Las colas de mensajes son buzones que posibilitan la realización de una comunicación indirecta
entre procesos mediante el paso de mensajes. Un proceso que adquiera el uso de una cola de mensajes
puede enviar (insertar) o recibir (extraer) mensajes de la cola. Por defecto, los mensajes son insertados y
extraídos por orden de llegada, es decir, usando un algoritmo PIFO. Aunque también es posible extraer
un mensaje determinado de una cola haciendo uso de un identificador entero positivo denominado tipo
del mensaje definido por el programador. Cada mensaje enviado o recibido por un proceso se implementa
como una estructura de datos que contiene el tipo de mensaje y el cuerpo del mensaje.
El tamaño máximo en bytes y el número máximo de mensajes de una cola de mensajes son paráme­
tros configurables por el superusuario.
Por defecto si un proceso envía un mensaje a una cola que está llena entra en el estado dormido en
espera de que el mensaje pueda ser enviado. Asimismo si un proceso desea recibir un mensaje de una
cola que está vacía entra en el estado dormido hasta que llegue el mensaje.
SOBUNIX: planificación, sincronización y mecanismos IPC
125
El núcleo implementa una cola de mensajes mediante una lista enlazada de mensajes que se almacena
en el espacio de direcciones del núcleo. Para gestionar las colas de mensajes existentes el núcleo mantiene
una tabla de colas de mensajes. Cada entrada de esta tabla contiene, entre otros, los siguientes datos sobre
una determinada cola: creador, propietario, llave, permisos de acceso, puntero al primer mensaje de la
cola, puntero al último mensaj e de la cola, número de bytes almacenados en la cola, tamaño máximo en
bytes que puede tener la cola y número de mensajes actualmente en la cola.
Además el núcleo tiene que mantener las colas de procesos dormidos en operaciones de envío o
recepción sobre una determinada cola de mensajes.
El núcleo asocia a cada cola de mensajes un identificador numérico entero positivo rnsgqi d que la
identifica de manera univoca y que le permite localizar rápidamente su entrada asociada en la tabla de
colas de mensajes.
Por cada mensaje en una cola el núcleo mantiene una estructura de datos con la siguiente informa­
ción: un puntero al siguiente mensaj e de la cola, el tipo del mensaje, el tamaño del cuerpo del mensaje y
la dirección de comienzo del cuerpo del mensaje.
El núcleo soporta las siguientes llamadas al sistema asociadas con las colas de mensajes:
•
rnsgqi d=rns gget ( l l ave , ind ) . Esta llamada al sistema permite crear una cola de mensajes nue­
va u obtener acceso a una cola de mensajes ya creada. Requiere como argumentos de entrada la
l l ave que se va asignar a la nueva cola o la llave de la cola ya creada, y una serie de indicadores
ind que permiten especificar, entre otras cosas, los permisos de acceso a la cola. Si la llamada se
ejecuta con éxito devuelve en rnsgqi d el identificador de la cola. En caso contrario devuelve - 1 .
•
r=rnsgsnd ( rns gqi d , rnen , t arn , ind ) . Esta llamada al sistema permite enviar un mensaje a una
determinada cola. Requiere como argumentos de entrada el identificador de la cola de mensajes
rnsgqi d, un puntero rnen al buffer que contiene el mensaje que se desea enviar, el tamaño t arn en
bytes del mensaje, y un indicador ind que permite especificar el comportamiento de la llamada.
Cuando un proceso invoca a la llamada rnsgsnd el núcleo comprueba si existe espacio en la cola
para poder enviar el mensaje. Si la cola está llena el núcleo bloquea al proceso hasta que exista
espacio en la cola y el mensaje pueda ser enviado. Para evitar el bloqueo del proceso se debe
especificar en ind el indicador I PC_NOWAIT. Si la llamada se ejecuta con éxito devuelve O en
caso contrario devuelve - l .
•
r=rnsgrcv ( rns gqi d , rnen , rnax , t ipornen , ind ) . Esta llamada al sistema permite recibir un men­
saje de una determinada cola. Requiere como argumentos de entrada el identificador de la cola
de mensajes rnsgqid, un puntero rnen al buffer donde se almacenará el mensaje que se desea re­
cibir, el número máximo rnax de bytes que serán almacenados del mensaje, el tipo del mensaje
t ipornen y un indicador ind que permite especificar el comportamiento de la llamada. Por defec­
to si la cola está vacía o no existe un mensaje del tipo especificado el núcleo bloquea al proceso
que invoca esta llamada. Para evitar el bloqueo del proceso se debe especificar en i nd el indicador
I PC_NOWAIT. Si la llamada se ejecuta con éxito devuelve el número de bytes escritos en el buffer,
en caso contrario devuelve - 1 .
Ampliación de sistemas operativos
126
El parámetro t ipomen de esta llamada permite seleccionar el mensaje que será extraído de la
cola de mensajes. Si t ipomen es mayor que cero se extrae el mensaje que lleva más tiempo en
la cola cuyo tipo sea igual a t ip omen. Si t ipomen es igual a cero se extrae el mensaje que lleva
más tiempo en la cola, es decir, el primer mensaje. Por último si t ipomen es menor que cero se
buscan aquellos mensajes cuyo tipo sea menor o igual al valor absoluto de t ipomen, de todos los
mensajes que cumplen esta condición se elige para ser extraído al mensaje que lleva más tiempo
en la cola cuyo tipo sea el más pequeño de todos.
•
r=msgc t l ( msgqi d , o rden , arg ) . Esta llamada permite leer y configurar los datos de control
que el núcleo mantiene en la entrada asociada a una determinada cola de mensajes en la tabla de
colas de mensajes. Requiere como argumentos de entrada el identificador de la cola de mensajes
msgqi d, un número entero o constante simbólica orden que especifica la operación que se quiere
realizar sobre los datos de administración y control de la cola, y los argumentos arg asociados a
dicha operación. Los posibles valores de o rden son:
I PC_RMID. Especifica que el recurso IPC debe ser eliminado. Además despierta a todos
los procesos dormidos esperando por una operación de envío o recepción en dicha cola de
mensajes.
I PC_STAT. Lee el contenido de la estructura de datos asociada al recurso IPC y lo almacena
en estructura apuntada en arg.
I PC_SET. Configura la estructura de datos asociada al recurso IPC con los valores almace­
nados en la estructura apuntada en arg.
Si la llamada al sistema se ejecuta con éxito entonces devuelve O. En caso contrario devuelve - l .
e
Ejemplo 3 . 1 1
En la Figura 3 . 1 2 se muestra el código del archivo de cabecera de f_c o l a . h donde se usa la llamada al
sistema msgget para crear una cola de mensajes con permisos de lectura y escritura para todos los usua­
rios. Se observa que la llave del recurso IPC es creada mediante la llamada al sistema f tok, que recibe
como argumentos la ruta de un archivo " a s d . txt " que debe estar previamente creado y un carácter K
'
'.
Por otra parte, en las Figuras 3 . 1 3 y 3 . 1 4 se muestra el código de los programas prog 3 2 y prog3 3 . El
programa prog3 2 crea u obtiene la cola de mensajes id invocando a la función obtener_c o l a ( ) y a
continuación envía un mensaje x de tipo 1 invocando a la llamada msgsnd.
Por su parte el programa prog3 3 invoca a obt ener_c o l a ( ) para acceder a la cola id y a continuación
invoca a la llamada msgrcv para solicitar la recepción del primer mensaje de tipo 1 que exista en la cola.
Si dicho mensaje existe se eliminará de la cola y se copiará en la estructura Y. Si no existe dicho mensaje
el proceso receptor se bloqueará hasta que llegue a la cola un mensaje del tipo especificado.
Cuando llegue el mensaj e se despertará al proceso receptor y cuando sea planificado para continuar su
ejecución mostrará en la pantalla el texto:
E s t e e s e l mens a j e 1
SOBUNIX: planificación, sincronización y mecanismos IPC
# i nc l ude < sys / ipc . h>
# i nc l ude < sys /msg . h>
int i d ;
key_t l l ave ;
obt ener_c o l a ( )
{
1 * Creac i ón l l ave * 1
l l ave= f t o k ( " a s d . tx t " , ' K ' ) ;
1 * Ob t enc i ón de una c o l a de mens a j e s
I
*1
i d=ms gge t ( l l ave , I PC_CREAT 0 6 6 6 ) ;
i f ( i d= = - 1 ) {
p r i n t f ( " Error al
obtener la c o l a de mens a j e s \ n " ) ;
ex i t ( 2 ) ;
Figura 3.12 - Código C del archivo de cabecera def_c o l a . h del Ejemplo 3 . 1 1
# i nc lude
" de f_c o l a . h "
ma in ( )
{
int r ;
1*
E s t ruc tura d e l mens a j e qu e s e va env i a r
*1
s t ruc t {
l ong t ipo ;
char cuerpo [ 5 0 ] ;
X;
1*
Tamaño en byt e s d e l cuerpo del men s a j e X * 1
i n t L = s i z e o f ( X ) - s i z e o f ( X . t ipo ) ;
1*
In i c i a l i z ac i ón de l men s a j e X * 1
X . t ip o = 1 ;
s t rcpy ( X . cuerp o , " E s t e
es
e l men s a j e 1 " ) ;
obtener_c o l a ( ) ;
1 * Enviar men s a j e a l a c o l a * 1
r=msgsnd ( i d , &X , L , O ) ;
i f ( r= = - 1 )
p r i n t f ( " Er r o r a l enviar e l men s a j e X " ) ;
Figura 3.13 - Código C del archivo del programa prog3 2 del Ejemplo 3 . 1 1
127
128
Ampliación de sistemas operativos
# i n c l ude
" de f_c o l a . h "
ma i n { )
{
int r ;
1 * E s t ru c tura del mens a j e que s e va r e c i b i r * 1
s t ruc t
{
l ong t ipo ;
char cuerpo [ 5 0 ] ;
Y;
1 * Tamaño en byt e s de l cuerp o del mens a j e Y * 1
i n t L = s i z e o f { Y ) - s i z e o f { Y . t i po ) ;
/ * I n i c i a l i z a c i ón de l men s a j e Y * /
s t rcpy { Y . cuerp o , " \ 0 " ) ;
obt ener_c o l a { ) ;
1 * Re c i b i r el pr imer men s a j e de t ipo 1 de l a c o l a * 1
r=msgrcv { i d , &Y , L , 1 , 0 ) ;
i f { r= = - 1 )
p r i n t f { " Error a l r e c i b i r mens a j e \ n " ) ;
el se
p r i n t f { " \ n %s \ n " , Y . cuerp o ) ;
Figura 3.14 - Código C del archivo del programa prog3 3 del Ejemplo 3 . 1 1
Señalar que la cola de mensajes i d sigue existiendo cuando finaliza la ejecución del proceso emisor y del
proceso receptor. Esto puede comprobarse invocando al comando ipc s . Para eliminarla se puede usar el
comando ipcrm. También se podría modificar los programas incluyendo al final la llamada al sistema
msgc t l ( i d , I PC_RMI D , O ) .
•
Memoria compartida
En los SOBUNIX un proceso no puede acceder al espacio de direcciones virtuales de otro proceso.
Cuando se crea un proceso hij o con la llamada al sistema f o rk, el hijo hereda una copia del espacio
de direcciones virtuales del padre. Los cambios que haga el hij o sobre su espacio de direcciones no
serán visualizados por el padre, y viceversa. Esta característica es un mecanismo de protección muy
eficiente. Sin embargo, en determinadas aplicaciones interesa que diferentes procesos tengan acceso a
una misma región de memoria compartida, de tal forma que los cambios que haga un proceso sobre los
datos almacenados en dicha región de memoria sean visibles al resto de procesos. Esta funcionalidad es
SOBUNIX: planificación, sincronización y mecanismos IPC
129
la que proporciona el mecanismo IPC del System V conocido como memoria compartida.
En definitiva una memoria compartida es una región de memoria que puede ser leída o escrita por
varios procesos. Para operar sobre una región de memoria compartida un proceso primero tiene que crear
la memoria u obtener acceso a la misma, si ya estaba creada, y a continuación adjuntarla a su espacio
de direcciones virtuales. Por otra parte, si un proceso ya no va acceder más a una región de memoria
compartida debe eliminarla de su espacio de direcciones virtuales.
Para gestionar las regiones de memoria compartida existentes el núcleo mantiene una tabla. Cada
entrada de esta tabla contiene, entre otros, los siguientes datos sobre una determinada región: creador,
propietario, llave, permisos de acceso, tamaño en bytes de la región, puntero a la estructura que permite
localizar la tabla de páginas asociada a la región y número de procesos que tienen adjuntada la región.
El núcleo asocia a cada región de memoria compartida un identificador numérico entero positivo
shmid que la identifica de manera univoca y que le permite localizar rápidamente su entrada asociada
en la tabla de memoria compartida.
El núcleo soporta las siguientes llamadas al sistema asociadas con las regiones de memoria compar­
tida:
•
shmid= shmge t ( l l ave , t amaño , ind ) . Esta llamada al sistema permite crear una nueva región
de memoria compartida u obtener acceso a una región de memoria compartida ya creada. Requiere
como argumentos de entrada la l l ave que se va asignar a la nueva región o la llave de la región ya
creada, el tamaño en bytes de la región y una serie de indicadores ind que permiten especificar,
entre otras cosas, los permisos de acceso a la región. Si la llamada se ejecuta con éxito devuelve el
identificador shm i d de la región de memoria compartida. En caso contrario devuelve - l .
•
r= shmat ( shmi d , d i r , ind ) . Esta llamada al sistema permite adjuntar una región de memoria
compartida en el espacio de direcciones virtuales del proceso invocante. Requiere como argumen­
tos de entrada: el identificador shmid de la región de memoria compartida, la dirección virtual
del espacio del proceso d i r a partir de la cual se desearía que la región de memoria compartida
fuese adjuntada, y una serie de indicadores i nd que permiten establecer el modo de acceso del
proceso a la región de memoria. Por ejemplo, el indicador SHM_RDONLY establece que la región de
memoria será accedida para solo lectura por el proceso. Si la llamada se ejecuta con éxito devuelve
un puntero a la dirección virtual de inicio Dirvo de la región de memoria compartida. En caso de
error devuelve el valor - l .
Cuando se utiliza esta llamada al sistema lo más cómodo para el programador es que el núcleo sea
el encargado de elegir la dirección Dirvo del espacio de direcciones virtuales del proceso a partir
de la cual se adjuntará la región de memoria compartida. Para ello el argumento d i r se debe fijar
a O. Por otra parte, si se fija d i r a un valor distinto de O, el núcleo intentará adjuntar la región
de memoria compartida a partir de la dirección d i r deseada pero debe tenerse en cuenta que no
siempre es posible.
Conviene señalar que para una determinada región de memoria compartida por varios procesos el
valor de Dirvo suele ser distinto en cada proceso.
Ampliación de sistemas operativos
130
e
•
r = shmdt ( D i rvo ) . Esta llamada al sistema desajunta una región de memoria compartida del espa­
cio de direcciones virtuales de un proceso. Requiere como único parámetro de entrada la dirección
virtual de inicio D i rvo de la región de memoria compartida. Si la llamada se ejecuta correctamente
devuelve O. En caso contrario devuelve - l .
•
r = s hmc t l ( shmi d , o rden , arg ) . Esta llamada permite leer y configurar los datos de control que
el núcleo mantiene sobre una región de memoria compartida. Su sintaxis es muy similar a la de las
llamadas s emc t l y ms gqc t l .
Ejemplo 3.12
Supóngase que se invoca al programa prog3 4 (ver Figura 3 . 1 5) desde la línea de órdenes de un intérprete
de comandos, y que éste crea al proceso A para ejecutar este programa.
El proceso A en primer lugar invoca a la función ini t_s em para inicializar con el valor O el semáforo
creado en c omun . h (ver Figura 3 . 1 0) . En segundo lugar invoca a la llamada al sistema shmg e t para
crear una región de memoria compartida y comprueba que la llamada se ha ejecutado correctamente. En
tercer lugar invoca a la llamada al sistema shma t para adjuntarla en su espacio de direcciones a partir de
la dirección contenida en el puntero contador. Además comprueba que la llamada se ha ejecutado sin
errores. En cuarto lugar almacena en la región compartida el valor O. En quinto lugar invoca a la llamada
al sistema f o r k para crear un proceso hijo B, el cual comparte el acceso a la región con su proceso padre.
En sexto lugar el proceso A invoca a la función wa i t_s em ( ) para esperar a que termine de ejecutarse
su hijo.
Cuando se ejecuta el proceso B , éste incrementa en una unidad el valor almacenado en la región compar­
tida, muestra en pantalla el texto
HIJO c ontado r = l
realiza una operación s i gnal_s em ( ) para desbloquear a s u proceso padre y termina s u ejecución.
Cuando el proceso A es despertado y planificado para ejecución muestra en pantalla el mensaje
PADRE c ontado r = l
invoca a l a llamada a l sistema shmdt para desajuntar la región compartida de s u espacio d e direcciones,
invoca a la llamada al sistema shmc t l para borrar el recurso IPC y finaliza. Nótese que si el proceso A
se planifica después que el proceso B entonces no se bloquea en el semáforo.
En la Figura 3 . 1 6 se muestra el código del programa prog3 5 similar a prog3 4 donde no existe una
región de memoria compartida. En dicho caso las modificaciones que hace el proceso B en su espacio de
direcciones no son visibles por el proceso A, con lo que la traza de ejecución de este programa es :
HIJO contado r = l
PADRE c ontador= O
•
SOBUNIX: planificación, sincronización y mecanismos IPC
# i nc lude
" c omun . h "
ma in ( ) {
int i d ;
i n t * C on t ador=NULL ;
i n i t_s em ( O ) ;
1 * Crear una r e g i ó n de memo r i a c ompar t i da * 1
I
i d= shmge t ( I PC_PRIVATE , s i z e o f ( i nt ) , I PC_CREAT 0 6 0 0 ) ;
if
( id== - 1 )
p r i n t f ( " Error a l c r ear l a r e g i ón de memo r i a c ompar t i da \ n " ) ;
ex i t ( 2 ) ;
1 * Adj untar
la reg i ón al
c ontador= ( i nt
if
e spac i o de d i r e c c i on e s v i r tua l e s del p ro c e s o * 1
* ) shma t ( i d , O , O ) ;
( c on t ado r = =NULL )
{
p r i n t f ( " Error a l l i gar la reg i ón de memo r i a \ n " ) ;
ex i t ( 2 ) ;
* C On t ador= O ;
i f ( f o rk ( ) = = O )
{
* C on t ador= * c on t a do r + l ;
p r i n t f ( " H IJO c ontado= %d\ n " , * C Ontado r ) ;
s i gnal_s em ( ) ;
exi t ( 0 ) ;
wa i t _ s em ( ) ;
p r i n t f ( " PADRE c on t ado= %d \ n " , * C On t ado r ) ;
1 * D e s a j un tar
la r e g i ó n de memo r i a c ompar t ida d e l e spac i o * 1
shmdt ( c ontador ) ;
1 * Borrar l a r e g i ó n de memo r i a c ompar t i da * 1
s hmc t l ( i d , I PC_RMI D , O ) ;
Figura 3.15 - Código C del archivo del programa prog3 4 del Ejemplo 3 . 1 2
131
132
Ampliación de sistemas operativos
# i nc lude
" c omun . h "
ma i n { ) {
i n t c ontador= O ;
i f { fork { ) = = 0 )
{
c ontador=c ontador+ l ;
p r i n t f { " H IJO c o n t ado= %d \ n " , contador ) ;
s i gnal_s em { ) ;
exi t { 0 ) ;
wa i t_s em { ) ;
p r i n t f { " PADRE c o n t ado= %d \ n " , c ontado r ) ;
Figura 3.16 - Código C del archivo del programa prog3 5 del Ejemplo 3 . 1 2
Ventajas e inconvenientes de los mecanismos IPC del System V
Los mecanismos IPC del System V poseen una gran versatilidad ya que pueden usarse para diferentes
funciones :
•
Los semáforos se pueden usar para garantizar la exclusión mutua en el uso de un recurso crítico o
para sincronización de procesos. Su principal inconveniente es que si no se colocan adecuadamente
en el código de la aplicación o se realiza una operación incorrecta pueden producir condiciones de
carrera e interbloqueos. En aplicaciones con un código largo y con decenas de semáforos, incurrir
en estas equivocaciones es relativamente fácil.
•
Las colas de mensajes se pueden usar para las mismas funciones que los semáforos y además para
el intercambio de pequeñas cantidades de datos. Su principal inconveniente es que la transferencia
de un mensaje requiere de dos copias en memoria lo que ralentiza la operación. En primer lugar
el mensaje enviado por un proceso emisor a una cola de mensajes es copiado desde el espacio de
direcciones del proceso en un buffer del núcleo. Posteriormente cuando el mensaje es extraído de
la cola se copia desde el buffer del núcleo al espacio de direcciones del proceso receptor.
Otro inconveniente de las colas de mensajes es que no es posible enviar un mensaje a varios
receptores, ya que cuando un receptor recibe un mensaje éste es extraído de la cola con lo que ya
no se encuentra disponible para otros receptores.
Otra forma más eficiente y versátil de implementar el paso de mensajes es mediante el uso de
STREAMS [Vahalia, 1 995] los cuales fueron desarrollados para soportar las comunicaciones en
redes de computadores, aunque pueden ser utilizados también para paso de mensajes entre proce­
sos ejecutándose en una misma máquina.
SOBUNIX: planificación, sincronización y mecanismos IPC
•
133
Las regiones de memoria compartida se pueden usar para el intercambio rápido de pequeñas o
grandes cantidades de datos. Su principal desventaja es que para evitar condiciones de carrera es
necesario utilizar algún mecanismo de sincronización, como por ejemplo semáforos o el paso de
mensajes.
Cada tipo x con x= { s em, msg, shrn} de mecanismos IPC dispone de una llamada al sistema xget
para crear o acceder a un recurso IPC del tipo x y de una llamada al sistema xc t l para leer o configurar
los datos de administración y control que el núcleo mantiene sobre un determinado recurso IPC del tipo
x. Estos datos también pueden ser visualizados en un intérprete de comandos usando el comando ipc s .
Una vez creado u n determinado recurso IPC del tipo x éste perdura incluso aunque todos los procesos
que lo estuvieran utilizando ya hubieran terminado. Esta característica en determinados escenarios puede
ser realmente útil. Sin embargo también puede suponer un desperdicio de memoria. Debe tenerse en
cuenta que el núcleo no implementa mecanismos para controlar si un determinado recurso IPC ya no va
a ser utilizado nunca más. Es responsabilidad del programador eliminar dicho recurso.
Un proceso perteneciente al usuario propietario, al usuario creador o al superusuario para eliminar
un recurso IPC del tipo x debe invocar a la llamada al sistema xc t l con el argumento I PC_RMID.
También se puede utilizar el comando ipcrm desde la línea de órdenes de un intérprete de comandos.
La eliminación del recurso IPC supone liberar el espacio ocupado por las estructuras de datos asociadas
al recurso y despertar a los procesos dormidos en el recurso.
Otro de los problemas que presentan los mecanismos IPC del System V es en relación con la segu­
ridad. Normalmente los recursos IPC son utilizados por aplicaciones que permiten el acceso a procesos
de diferentes usuarios, con lo que los permisos de acceso del recurso no suelen ser muy restrictivos.
En consecuencia un proceso no autorizado podría acceder al recurso si consigue adivinar la llave o el
identificador asociado al recurso.
3.5.2.
Otros mecanismos IPC
Señales
Las señales son un mecanismo muy útil de notificación de eventos (ver sección 2 . 3 . 3 ) que también
pueden usarse como mecanismo IPC para la sincronización de procesos. Por ejemplo, un proceso A
puede invocar a una llamada al sistema pau s e para suspender su ejecución mientras otro proceso B
realiza una determinada tarea. Cuando B haya finalizado la tarea invocará una llamada al sistema ki 1 1
para enviar una determinada señal al proceso A para que despierte y pueda continuar su ejecución.
El principal inconveniente de usar las señales como mecanismo IPC es el retardo que existe desde
que el emisor genera una señal hasta que es recibida por el receptor. Para enviar una señal el proceso
emisor debe ser planificado para ejecución e invocar la llamada al sistema adecuada, por ejemplo ki l l .
Posteriormente el núcleo debe interrumpir al proceso receptor, s i éste estaba ejecutándose, y manipular
su pila de usuario para poder ejecutar el manipulador de la señal cuando el proceso retorne a modo
usuario.
134
Ampliación de sistemas operativos
Thberías
Una tubería es un canal de comunicación unidireccional por el que se puede transmitir flujos de
datos no estructurados con un tamaño máximo fijo. Un proceso emisor puede enviar (escribir) datos por
un extremo de la tubería y un proceso receptor puede recibir (leer) los datos por el otro extremo. Los
datos son recibidos por orden de envío, es decir, siguiendo una organización de tipo FIFO. Una vez que
los datos son leídos de la tubería por un proceso receptor dej an de estar disponibles para ser leídos por
otros procesos receptores.
Si un proceso emisor intenta escribir en una tubería que está llena se bloquea hasta que exista espacio
en la tubería. Asimismo un proceso receptor que intente leer en una tubería que esté vacía se bloqueará
hasta que existan datos en la tubería.
Usadas como mecanismo IPC las tuberías resultan bastante eficientes aunque presentan los siguientes
inconvenientes [Vahalia, 1 995] :
•
No permiten el envío de información a varios receptores, ya que cuando se lee los datos de la
tubería estos son borrados de la misma.
•
Un proceso que escribe en la tubería no puede especificar que receptor debe leer los datos.
•
Si un proceso emisor transmite por la tubería varios mensajes de diferente longitud, como los
datos en la tubería son un flujo de bytes no estructurado, el proceso receptor no puede saber donde
termina un mensaje y donde empieza otro.
En los SOBUNIX las tuberías son gestionadas como los archivos (ver sección 5.2. 1 ), aunque no
requieren la realización de operaciones de E/S a disco, ya que los datos de la tubería no se mantienen en
memoria secundaria sino en la memoria principal. Cuando se crea una tubería el núcleo le asigna un par
de descriptores de archivos Do y D 1 • El descriptor Do se utiliza como argumento de la llamada al sistema
read para leer en la tubería. Mientras que D1 se utiliza como argumento de wr i te para escribir en la
tubería. Existen dos posibles tipos de tuberías:
•
Tuberías sin nombre. Se crean haciendo uso de la llamada al sistema r=pipe ( f i l d e s ) . Esta
llamada necesita como argumento de entrada la dirección de un array entero f i l d e s de dos ele­
mentos para almacenar los descriptores de archivos Do y D 1 • Si la llamada al sistema se ejecuta
con éxito devuelve O en caso contrario devuelve - 1 .
Los intérpretes de comandos utilizan estas tuberías para hacer que la salida de un programa sea la
entrada de otro programa (ver sección 1 .5 . 1 ) . Es el propio intérprete el que se encarga de manipular
los descriptores de archivos de la tubería devueltos por la llamada al sistema pipe para hacer que
un programa sea el emisor y otro el receptor.
Las tuberías sin nombre se caracterizan porque solo pueden ser utilizadas por procesos relacio­
nados genealógicamente. Además no son persistentes, es decir, son eliminadas al finalizar los
procesos que las utilizan.
La implementación de las tuberías sin nombre depende de cada SOBUNIX. Algunos SOBUNIX
las implementan usando las mismas estructuras de datos que utilizan para la gestión de archivos.
SOBUNIX: planificación, sincronización y mecanismos IPC
135
Otros SOBUNIX las implementan usando conectores (sockets) (ver sección 5 .6) o STREAMS
[Vahalia, 1 995 ] .
•
Tuberías con nombre, también denominadas archivos PIFOs o simplemente PIFOs. Se crean me­
diante la llamadas al sistema rnknod (ver sección 5 . 5 .2) o rnk f i f o , o desde un intérprete de co­
mandos usando los comandos homónimos.
Las tuberías con nombre se caracterizan porque se les puede asignar una ruta dentro del sistema
de archivos. Cualquier proceso aunque no sea hij o del proceso creador de la tubería puede acceder
a la tubería si conoce la ruta de la tubería y dispone de los permisos adecuados. Asimismo, los
tuberías con nombre son persistentes, es decir, continúan existiendo aunque todos los procesos
que lo estaban utilizando ya hayan terminado. Para eliminarlas se debe usar la llamada al sistema
unl ink o el comando homónimo.
3.6.
Resumen
El planificador es la parte del núcleo de un sistema operativo encargado de decidir qué procesos (o
hilos del núcleo) pasarán a ser ejecutados en los procesadores disponibles. Nótese que si el núcleo del
SOBUNIX considerado soporta hilos del núcleo entonces el planificador utiliza como unidad o entidad
planificable a los hilos del núcleo. En caso contrario utilizará como unidad planificable a los procesos.
En la mayoría de los SOBUNIX, el planificador implementa una planificación global basada en
múltiples colas de prioridad y realimentación. En este tipo de planificación, cada unidad planificable
tiene asignada una determinada prioridad que es un número entero positivo comprendido entre O y un
cierto valor máximo. En algunos SOBUNIX la prioridad más alta se asocia con el valor O de prioridad,
mientras que en otros se toma j ustamente el criterio contrario. El planificador siempre intenta que se
ejecute la unidad planificable de mayor prioridad, aunque esto no siempre es posible si el núcleo es no
expropiable .
El código del núcleo de los SOBUNIX es reentrante esta característica posibilita el que varias uni­
dades planificables (procesos o hilos del núcleo) ejecutándose en modo núcleo puedan estar ejecutando
concurrentemente la misma región de código del núcleo. Obviamente en el código del núcleo existen
secciones críticas asociadas a diferentes recursos críticos, como por ejemplo las estructuras de datos del
núcleo. Para garantizar la exclusión mutua en la ejecución de una sección crítica del núcleo asociada a un
cierto recurso crítico, el núcleo utiliza diferentes mecanismos de sincronización, entre los más utilizados
se encuentran los cerrojos y los semáforos.
Por otra parte, los SOBUNIX ponen a disposición de los programadores de aplicaciones diferentes
mecanismos para garantizar la exclusión mutua en el uso de recursos críticos, sincronizar su ejecución,
esperar por la aparición de algún evento o intercambiar información. A este conjunto de mecanismos
se les conoce de forma general como mecanismos de comunicación entre procesos, o más abreviada­
mente como mecanismos IPC. Es el programador de aplicaciones el que decide qué mecanismos IPC
utilizar y dónde utilizarlos dentro del código de sus aplicaciones. El uso de estos mecanismos requiere
la invocación de las llamadas al sistema oportunas. El núcleo se encarga de atender dichas llamadas al
136
Ampliación de sistemas operativos
sistema y mantener las estructuras de datos necesarios para soportar estos mecanismos IPC . Entre los
mecanismos IPC soportados en la mayoría de SOBUNIX se encuentran los mecanismos IPC del System
V (semáforos, colas de mensajes y memoria compartida), las señales y las tuberías.
3. 7.
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pueden
consultar, por ejemplo: los capítulos 5, 6 y 7 de [Vahalia, 1 995] , los capítulos 9 y 1 0 de [Márquez, 2004],
los capítulos 3 , 4 y 1 7 de [McDougall y Mauro, 2006] y el capítulo 1 0 de [Tanenbaum, 2009] .
3.8.
Autoevaluación
3.1. Explicar razonadamente las características generales de la planificación de procesos multihilos en
SOBUNIX. (Respuesta en sección 3 .2. 1 )
3.2. ¿Qué especificaciones tiene asociada cada clase de planificación? ¿Qué dos tipos de funciones
utiliza el planificador para manipular las clases de planificación? (Respuesta en sección 3 .2. 1 )
3.3. ¿Qué llamadas al sistema s e encuentran disponibles en algunos SOBUNIX para controlar la prio­
ridad de un proceso? (Respuesta en sección 3 .2. 1 )
3.4. Explicar razonadamente l a planificación usada en B S D 4 . 3 . (Respuesta en sección 3 .2.2)
3.5. Explicar razonadamente la planificación usada en Solaris. (Respuesta en sección 3 . 2.2)
3.6. Dibujar un diagrama con la distribución de las prioridades de ejecución usadas en Solaris en fun­
ción del tipo de clases de planificación y las interrupciones. (Respuesta en sección 3 .2.2)
3.7. ¿Qué información se mantiene en una tabla de despacho de Solaris? (Respuesta en sección 3 .2.2)
3.8. ¿Qué información permite visualizar el comando di spadm i n en Solaris? ¿ Y pr i o cn t l ?
(Respuesta en sección 3 . 2.2)
3.9. ¿Qué es la prioridad en modo usuario en Solaris? ¿De qué componentes consta?
(Respuesta en sección 3 .2.2)
3.10. ¿Cómo se puede configurar la prioridad de usuario en Solaris ? (Respuesta en sección 3 .2.2)
3. 1 1 . ¿En Solaris qué eventos producen que se modifique la prioridad (global y en modo usuario)?
(Respuesta en sección 3 . 2.2)
3. 12. ¿Qué operaciones realizadas periódicamente por las funciones dependientes de las clases de pla­
nificación pueden cambiar las prioridades de los hilos en S olaris? (Respuesta en sección 3 .2.2)
SOBUNIX: planificación, sincronización y mecanismos IPC
137
3.13. Defina los siguientes conceptos : núcleo no expropiable, núcleo expropiable y puntos de expropia­
ción. (Respuesta en sección 3 .2.3)
3. 14. ¿Por qué es necesaria la existencia de mecanismos de sincronización en el núcleo de un SOBU­
NIX? ¿Cuáles son los mecanismos de sincronización más utilizados? (Respuesta en sección 3 . 3 )
3. 15. Explicar qué es un cerrojo y qué operaciones básicas soporta. (Respuesta e n sección 3 . 3 . 1 )
3. 16. Explicar qué es un spinlock, u n cerrojo con bloqueo, un cerrojo adaptativo, un cerrojo mutex y un
cerrojo R/W. (Respuesta en sección 3 . 3 . 1 )
3. 17. Explicar cuándo se realizan las operaciones de dormir y despertar un hilo y en qué consisten.
(Respuesta en sección 3 .4)
3.18. ¿Qué es un canal de espera? ¿Cómo se le asocia una cola de hilos dormidos ? ¿Qué problemas
presenta dicha asociación? (Respuesta en sección 3 .4)
3.19. ¿Qué es un turnstile? ¿Cómo gestiona el núcleo de Solaris los turnstiles? (Respuesta en sección 3 .4)
3.20. Enumerar los principales mecanismos IPC disponibles en los SOBUNIX. (Respuesta en sección 3 . 5 )
3.21. ¿Qué estructuras mantiene el núcleo para soportar los mecanismos IPC del System V? ¿Qué infor­
mación contiene dichas estructuras por cada recurso IPC? (Respuesta en sección 3 . 5 . 1 )
3.22. ¿Para qué utiliza el núcleo el identificador numérico de un recurso IPC? ¿Cuándo se l o asigna?
(Respuesta en sección 3 . 5 . 1 )
3.23. Explicar la implementación de los semáforos como mecanismos IPC del System V.
(Respuesta en sección 3 . 5 . 1 )
3.24. Explicar la utilidad y l a sintaxis de las siguientes llamadas al sistema: s emg e t , s emop y s emc t l .
(Respuesta en sección 3 . 5 . 1 )
3.25. Explicar la gestión e implementación de las colas de mensajes. (Respuesta en sección 3 . 5 . 1 )
3.26. Explicar la utilidad y l a sintaxis de las siguientes llamadas al sistema: msgge t , msgsnd, msgrcv
y msgc t l . (Respuesta en sección 3 . 5 . 1 )
3.27. Explicar qué e s y cómo s e gestiona una región d e memoria compartida. (Respuesta e n sección 3 .5 . 1 )
3.28. Explicar l a utilidad y l a sintaxis de las siguientes llamadas al sistema: shmg e t , s hma t , shmdt y
shmc t l . (Respuesta en sección 3 . 5 . 1 )
3.29. Explicar razonadamente las ventajas y los inconvenientes de los mecanismos IPC del System V.
(Respuesta en sección 3 . 5 . 1 )
138
Ampliación de sistemas operativos
3.30. ¿Cuál es el principal inconveniente de usar las señales como mecanismo IPC?
(Respuesta en sección 3 . 5 .2)
3.31. Explicar qué es y cómo funciona una tubería. (Respuesta en sección 3 . 5 .2)
3.32. Explicar los principales inconvenientes que presenta el uso de las tuberías como mecanismo IPC.
(Respuesta en sección 3 . 5 .2)
3.33. Explicar cómo gestiona el núcleo las tuberías. (Respuesta en sección 3 . 5 .2)
3.34. Explicar cómo se crean y las principales características de las tuberías sin nombre y de los archivos
PIFOs. (Respuesta en sección 3 . 5 .2)
3.9.
Ejercicios
3.1. En un sistema BSD 4.3 las 32 colas de procesos preparados se gestionan con una algoritmo de turno
rotatorio con un cuanto de 1 00 ms ¿Qué valor toma el cuanto en el caso de las colas asociadas al
rango de prioridades [0, 49] ? ¿Por qué? ¿De forma efectiva qué algoritmo se estaría aplicando
realmente en dichas colas?
3.2. En un sistema BSD 4.3 se han creado en el instante t = O ms tres procesos A, B y C de forma
prácticamente simultánea. Los procesos han sido colocados en la misma cola de procesos en el
estado preparado para ejecución en el siguiente orden: primero A, luego B y después C. Los tres
procesos tienen una prioridad inicial en modo usuario igual a 90 y un factor de amabilidad igual
20. Determinar cómo evoluciona el valor de la prioridad en modo usuario para cada proceso en el
intervalo de tiempo [0, 1 000] ms. Suponer que el tic de reloj se produce cada 1 0 ms, un cuanto
de 1 00 ms, que la prioridad en modo usuario base es igual a 50, y que el factor de decadencia
es constante e igual a 0,5 . Además se debe suponer que el tiempo de ejecución del manipulador
de la interrupción de reloj , la rutina roundrob i n ( ) , la rutina s chedcpu ( ) y el tiempo de un
cambio de contexto es despreciable. Suponer también que los tres procesos durante su ejecución
no invocan a ninguna llamada al sistema y que no existe en el sistema ningún otro proceso de
mayor prioridad en el estado preparado para ejecución.
3.3. En la Tabla 3 . 1 se muestra la tabla de despacho de la clase TS del planificador de un sistema
SVR4, en el cual se basa el planificador de Solaris. Supuesto un proceso con t s_cpupr i = 1 y
t s_upr i = 1 4 determinar el valor que se le asigna a t s_cpup r i y a t s_umdpri en los siguientes
casos: a) Expira el cuanto asignado al proceso. b) El proceso ha estado esperando para poder con­
sumir su cuanto más de 5 segundos. e) El proceso retorna a modo usuario tras haberse bloqueado
en espera de un evento durante la realización de una llamada al sistema.
3.4. En la Figura 3 . 1 7 se muestra el código C del programa j l O . Supóngase que en el directorio de
trabaj o actual residen los archivos wert . txt y j 1 0 , y que el archivo wert . txt puede ser leído
por cualquier usuario.
SOBUNIX: planificación, sincronización y mecanismos IPC
139
a) Explicar razonadamente el funcionamiento de j 1 o si se invoca desde el intérprete de coman­
dos mediante la orden: j 1 o
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
3.5. En la Figura 3 . 1 8 se muestra el código C del programa s 1 0 .
a) Explicar razonadamente el funcionamiento de s 1 0 si se invoca desde el intérprete de coman­
dos mediante la orden: s l O s i s t emas_opera t i vo s_2
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
3.6. En la Figura 3 . 1 9 se muestra el código C de los programas j O S a y j 0 8b.
a) Explicar razonadamente el funcionamiento de estos programas si un usuario, que dispone de
los permisos adecuados, escribe primero en un intérprete de comandos la orden j O Ba & y al
cabo de 1 0 segundos la orden j o Bb.
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
estos programas en un SOBUNIX.
ts_quantum
1 00
1 00
. .
80
...
20
...
10
.
ts_tqexp
o
o
...
7
...
30
...
49
ts_slpret
10
11
...
25
...
50
...
59
ts_maxwait
5
5
...
5
...
5
...
5
ts_lwait
10
11
...
25
...
50
...
59
PRIORITY LEVEL
Tabla 3.1 - Tabla de despacho de la clase TS del Ejercicio 3.3
o
1
...
15
...
40
.
. .
59
Ampliación de sistemas operativos
140
# i nc lude < s t dl ib . h>
# i nc lude < s td i o . h>
# i n c l ude < sys / ipc . h>
# i nc lude < sys / s em . h>
ma i n ( )
{
int x , u ;
key_t y ;
s t ruc t s embu f z [ 2 ] ;
z [ O ] . s em_ f l g= O ;
z [ 1 ] . s em_f l g= O ;
y= f t ok ( " we r t . tx t " , ' x ' ) ;
if
( y = = ( key_t ) - 1 )
p r in t f ( " mens a j e wert " ) ;
exi t ( 3 ) ;
I
x= s emge t ( y , 2 , I PC_CREAT 0 6 0 0 ) ;
u= s emc t l ( x , O , S ETALL , O ) ;
i f ( f o rk ( ) = = 0 )
{
z [ O ] . s em_num= O ; z [ O ] . s em_op = 1 ;
u = s emop ( x , z , 1 ) ;
z [ O ] . s em_num= 1 ; z [ O ] . s em_op= - 1 ;
u = s emop ( x , z , 1 ) ;
p r i n t f ( " \ nmens a j e a s d \ n " , u ) ;
el se
i f ( f o rk ( ) = = O )
{
s l e ep ( 2 ) ;
z [ O ] . s em_num= O ; z [ O ] . s em_op= - 1 ;
u = s emop ( x , z , 1 ) ;
p r i n t f ( " \ nmen s a j e f gh \ n " , u ) ;
z [ O ] . s em_num= 1 ; z [ O ] . s em_op= 1 ;
u = s emop ( x , z , 1 ) ;
Figura 3.17 - Código C del programa j 1 0 del Ejercicio 3 .4
SOBUNIX : planificación, sincronización y mecanismos IPC
# i nc lude < s td l i b . h>
# i nc lude < s t di o . h>
ma i n { i n t b ,
char * C [ ] )
{
int p f d [ 2 ] ;
int a ;
char bu f ;
if
{b == 2)
{
if
{ pipe { p f d )
== - 1 )
perror { " E l " ) ;
exi t { - 1 ) ;
a = f o rk { ) ;
if
{a == 0 )
close ( p fd [ l ] ) ;
wh i l e
{ read { p f d [ O ] , &bu f , l )
>
0)
{
wr i t e { l , &bu f , l ) ;
wr i t e { l ,
" \n " ,
1) ;
close { p fd [ O ] ) ;
els e
c l o s e { p fd [ O ] ) ;
wr i t e { p f d [ l ] ,
e
[ 1 ] , 10 ) ;
c l o s e { p fd [ l ] ) ;
p r i n t f { " \ nMen s a j e \ n " ) ;
exi t { - 2 ) ;
Figura 3.18 - Código C del programa s l O del Ejercicio 3 . 5
141
Ampliación de sistemas operativos
142
1 * C ó d i g o del programa j O S a
*1
# i nc lude < sys / s t a t . h>
# i n c l ude < f c n t l . h>
ma i n ( )
{
int r , h ;
char * b ;
b= ( char * )
ma l l o c ( 9 * s i z e o f ( char ) ) ;
f o r ( h = O ; h< 9 ; h+ + )
{
* ( b+ h ) = ' \ o ' ;
1
mknod ( " a s d " , S_I F I FO 0 6 6 6 , O ) ;
r = op en ( " a s d " , 0 6 6 6 ) ;
read ( r , b , 7 ) ;
p r i n t f ( " \ n %s \ n " , b ) ;
close ( r ) ;
unl ink ( " a s d " ) ;
1 * C ó d i g o de l programa j 0 8 b * 1
# i nc lude < sys / s t a t . h>
# i nc lude < f c n t l . h>
ma i n ( )
{
int r ;
char b [ ) = " Texto 1 " ;
r = op en ( " a s d " , 0 6 6 6 ) ;
wr i t e ( r , b , 8 ) ;
close ( r ) ;
Figura 3.19 - Código C de los programas j O S a
y
j 0 8b del Ejercicio 3 . 6
Capítulo 4
SOBUNIX: administración de memoria
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes:
•
Conocer cómo se realiza en los SOBUNIX la gestión del espacio de direcciones virtuales de un
proceso.
•
Saber cómo se realiza en los SOBUNIX el mapeo de archivos en la memoria virtual de un proceso.
•
Saber qué es y cómo se gestiona la memoria anónima en los SOBUNIX.
•
Conocer cómo se implementa la memoria compartida en los SOBUNIX.
•
Conocer las características más relevantes de la traducción de direcciones físicas a virtuales en los
SOBUNIX.
•
Saber cómo se realiza en los SOBUNIX la gestión de la memoria física.
•
Conocer cómo se gestiona el área de intercambio en los SOBUNIX.
•
Conocer las características más importantes de la gestión de la memoria perteneciente al núcleo en
los SOBUNIX.
•
Conocer las principales llamadas al sistema y los comandos disponibles en los SOBUNIX para el
control de la memoria virtual.
1 43
Ampliación de sistemas operativos
144
4. 1.
Introducción
El subsistema de administración de memoria es el componente del núcleo de un sistema operativo
encargado de administrar, en colaboración con el hardware, la memoria principal entre los restantes
subsistemas del núcleo y entre todos los procesos de usuario que se ejecutan en el computador. Para
realizar esta tarea se pueden usar diferentes técnicas de administración de memoria. En los SOBUNIX se
utiliza la técnica de paginación por demanda la cual posibilita la implementación de la memoria virtual.
El uso de la memoria virtual evita tener cargado en la memoria principal todo el espacio de direc­
ciones virtuales de un proceso. Solo se cargan las partes del espacio de direcciones virtuales del proceso
que se van referenciando durante su ejecución. Ello posibilita tener cargados parcialmente en memoria
principal un número mayor de procesos en el estado preparado, es decir, aumentar el grado de multipro­
gramación. Además el uso de la memoria virtual también permite ejecutar procesos cuyos espacios de
direcciones virtuales sean mayores que el tamaño de la memoria principal.
En la técnica de demanda de página la memoria física se divide en bloques de tamaño fijo Sp de­
nominados marcos de página. Además el espacio de direcciones virtuales de un proceso se divide en
bloques del mismo tamaño Sp denominados páginas. En un determinado instante de tiempo un marco de
página j puede estar libre u ocupado por una página i de un cierto proceso. Una página solo es cargada en
memoria cuando se produce un fallo de página, es decir, se referencia a una dirección virtual contenida
en una página i que no está cargada en ningún marco j de memoria principal. La página se construirá a
partir del archivo ejecutable ubicado en memoria secundaria o se cargará desde el área de intercambio
si tuvo que ser intercambiada fuera de memoria principal. Si cuando se produce un fallo de página no
existe espacio libre en memoria principal, se debe seleccionar alguna página k para ser reemplazada por
la página j. Si la página k fue modificada, antes de ser reemplazada deberá ser copiada en la memoria
secundaria.
La implementación de la memoria virtual mediante demanda de página requiere de ciertos requisitos
en el hardware del computador. En primer lugar el procesador debe soportar el reinicio de instrucciones
después de que la página cuya referencia produjo un fallo de página sea cargada en memoria principal.
Por otra parte se requiere de un componente hardware denominado unidad de gestión de memoria (Me­
mory Management Unit, MMU), que se encarga de realizar la traducción de una dirección virtual e una
dirección física. También el hardware suele suministrar mecanismos de protección de las páginas. Si se
intenta realizar un acceso no autorizado el hardware produce una excepción que debe ser atendida por el
núcleo.
La implementación de la memoria virtual mediante demanda de página requiere que el subsistema
de gestión de memoria realice, entre otras, las siguientes tareas :
•
Gestionar el espacio de direcciones virtuales de los procesos.
•
Crear y mantener los mapas de traducción de memoria virtual a memoria física, es decir, las tablas
de páginas.
•
Tratamiento de los fallos de página.
•
Reemplazamiento de páginas.
SOBUNIX: administración de memoria
145
•
Copia de las páginas modificadas a memoria secundaria.
•
Asignación de páginas de memoria principal a los subsistemas del núcleo y a los procesos.
•
Control del número de procesos cargados en memoria principal, es decir, del grado de multipro­
gramación.
Este capitulo está dedicado a describir la administración de memoria en los S OBUNIX. En primer
lugar se estudia la gestión del espacio de direcciones virtuales de un proceso. En segundo lugar se analiza
la traducción de direcciones virtuales a direcciones físicas. En tercer lugar se describe la gestión de la
memoria física. En cuarto lugar se estudia la gestión del área de intercambio. Finalmente se describe la
gestión de la memoria perteneciente al núcleo.
4.2.
Gestión del espacio de direcciones virtuales de un proceso en
SOBUNIX
4.2.1.
Organización del espacio de direcciones virtuales de un proceso
En el espacio de direcciones virtuales de un proceso se pueden distinguir diferentes regiones o seg­
mentos 1 , cada una de las cuales delimita un área contigua de memoria virtual :
•
Región de código, también denominada región de texto. En la mayoría de arquitecturas comien­
za en la primera dirección virtual del espacio de direcciones virtuales del proceso. Contiene las
instrucciones máquina del código del programa para cuya ejecución se ha creado el proceso. El
contenido y el tamaño de la región de código no varían durante la ejecución del proceso.
•
Región de datos. Se sitúa a continuación de la región de código. Contiene las constantes y variables
usadas en el programa. Esta región se divide en dos partes:
- Región de datos inicializados. Contiene aquellos datos que tienen asignado un valor inicial
de forma explicita.
- Región de datos no inicializados2 • Contiene aquellos datos que no han sido inicializados de
forma explicita. Estos datos por defecto se inicializan a cero.
•
Montículo (heap). El tamaño de la región de datos puede ser aumentado dinámicamente durante la
ejecución del proceso. Para ello se puede utilizar la función de librería ma l l o c que internamente
hace uso de las llamadas al sistema brk o sbrk. Al espacio extra añadido a la región de datos
con respecto a su tamaño inicial se le denomina montículo (heap). El sentido de crecimiento del
1 Aunque en la literatura reciben el mismo nombre, los segmentos o regi ones del espacio de direcciones virtuales de un
proceso no deben confundirse con los segmentos utilizados en la técnica de segmentación de memoria cada uno de los cuales
tiene un espacio de direcciones independiente.
2 A esta región también se le denomina en la literatura como región BSS (Block Started by Symbol, bloque inicializado con
símbolos).
146
Ampliación de sistemas operativos
montículo es establecido por cada SOBUNIX dependiendo del hardware. Para liberar un espacio
asignado en el montículo se utiliza la llamada al sistema f r e e .
•
Región de pila (stack) . E n esta región s e implementa la pila de usuario del proceso, o las pilas de
los hilos del proceso. Inicialmente contiene todas las variables del entorno del intérprete de co­
mandos desde el que fue invocado el programa. Además contiene la cadena de caracteres asociada
a la orden con que fue invocado el programa, es decir, el nombre del programa y sus argumentos
de entrada. Cada vez que se invoca a una función durante la ejecución del programa se añade un
marco lógico a la pila con toda la información necesaria para poder continuar con la ejecución del
programa cuando se termine de ejecutar dicha función. Cuando la región de pila crece por encima
del espacio inicialmente asignado se produce una excepción hardware que tiene que ser tratada por
el sistema operativo. El manipulador de esta excepción entre otras acciones aumenta el tamaño de
la pila en un rango de direcciones equivalente a una página. La localización de la pila y su sentido
de crecimiento son establecidos por cada SOBUNIX en función del hardware.
•
Región de librerías. Esta región contiene las diferentes librerías de funciones utilizadas por el pro­
grama. Estas librerías suelen ser compartidas por varios programas y son implementadas mediante
el mapeo en memoria de los archivos (ver sección 4.2.2) asociados a las librerías. En una librería
se distinguen dos partes : código y datos.
Otros posibles tipos de regiones que se pueden distinguir en el espacio de direcciones virtuales de un
proceso son las regiones de memoria compartida usadas como recurso IPC y los archivos mapeados en
memoria (ver sección 4.2.2). Precisamente las librerías son un ejemplo de este último tipo de regiones.
La distribución de las regiones y el tamaño máximo del espacio de direcciones virtuales de un proceso
son fijados por cada SOBUNIX en función del hardware.
e
Ejemplo 4.1
En la Figura 4. 1 se muestra la organización del espacio de direcciones virtuales que realiza Solaris
en diferentes arquitecturas. En la arquitectura SPARC V7 de 32 bits (ver Figura 4. 1 a) el espacio de
direcciones virtuales puede tener un tamaño máximo de 4 GiB : 3,5 GiB están disponibles para el espacio
de direcciones de un proceso y 5 1 2 MiB están reservados para el núcleo.
En la arquitectura Intel x86 de 3 2 bits (ver Figura 4. 1 b), de los 4 GiB disponibles de memoria virtual,
3,75 GiB pueden ser utilizados para el espacio de direcciones de un proceso y 256 MiB están reservados
para el núcleo.
En la arquitectura SPARC V9 de 3 2 bits (ver Figura 4. 1 c) existen espacios de direcciones independientes
para el núcleo y para los procesos. En esta arquitectura el tamaño máximo del espacio de direcciones
de un proceso es de 3 ,99 GiB ya que 4,078 MiB de las direcciones más altas están reservados para el
arranque.
•
SOBUNIX: administración de memoria
OxFFFFFFFF ,....----,
OxFFFFFFFF
Espacio del
núcleo (256 MiB)
Espacio del
núcleo (5 1 2 MiB)
OxEO O O O O O O
147
- � - - - - - - - - - - - -
-
.
OxFFFFF FFF
1
OxFFBEC O O O
1------1
1
Pila
1------l
1
Librerías
OxDFFFE O O O
OxFF 3 DC O O O
Pila
1
•
1
1
1
1
1
1
1
OxDF 7 F 9 0 0 0 1------l
t
Librerías
1
1
1
Montículo
Librerías
1
1
J
1-------;
Datos
1
1
t
Código
Montículo
1
1
1
Montículo
Ox 8 0 4 8 0 0 0
Pila
Datos
Código
OxO O O l O O O O
1
1
1
1
OxO O O O O O O O L - - - - - - - - - - - - - - - 1
(a)
1
1
1
1
1
1
1
1
1
1
1
•
Datos
'
1
1
Código
OxO O O l O O O O
1
Ox O O O O O O O O L - - - - - - - - - - - - - - - 1
(b)
OxO O O O O O O O
1
1
1
1
1
L - - - - - - - - - - - - - - -'
(e)
Espacio de direcciones virtuales de un proceso en Solaris con una arquitectura [McDougall
Mauro, 2006] : (a) SPARC V7 de 32 bits (sun4d), (b) Intel x86 de 32 bits y (e) SPARC V9 de 32 bits
(sun4u)
Figura 4.1
-
y
El tipo de acceso permitido al contenido apuntando por una determinada dirección virtual depende
de cada tipo de región. Al contenido de la región de código o de la parte de código de una librería solo se
puede acceder para realizar operaciones de lectura y ejecución, mientras que al resto de regiones se puede
acceder para realizar operaciones de lectura y escritura. Para obtener información sobre los permisos de
acceso, tamaño y dirección de inicio de las regiones en que se organiza el espacio de direcciones virtuales
de un proceso se puede utilizar el comando pmap.
Por otra parte, en la técnica de demanda de página el espacio de direcciones virtuales de un proceso
se divide en páginas del mismo tamaño Sp. Luego dependiendo del tamaño de una región y del tamaño
de página, una región podrá estar contenida en una o varias páginas. Además una página puede que tenga
contenido perteneciente a una o varias regiones.
Una página i de una región del espacio de direcciones virtuales de un proceso no pasa a existir
físicamente hasta que es referenciada por primera vez y se produce un fallo de página. Entonces al tratar
148
Ampliación de sistemas operativos
el fallo se le asignará un marco j de la memoria principal el cual debe ser inicializado adecuadamente
en función de la región a la que pertenezca la página i. Si la página i pertenece a la región de código o a
la parte inicializada de la región de datos entonces el marco j se inicializa a partir del archivo ejecutable
almacenado en la memoria secundaria asociado al proceso. Asimismo si la página i pertenece a la parte
no inicializada de la región datos, al montículo o la región de pila entonces el marco j se inicializa con
ceros. En el caso de que la página i pertenezca a una región de librería entonces el marco j se inicializa
a partir del archivo de la librería en memoria secundaria.
En el caso de las páginas de las regiones de código de un programa o de una librería como no pueden
ser modificadas solamente es necesario mantener una copia de dichas páginas en la memoria principal,
las cuales pueden ser compartidas por todos los procesos que hagan uso de dicho código.
En el caso de las páginas de las regiones de datos inicializados de un programa o de una librería se
aplica la técnica de copiar al escribir, que consiste en aplazar la copia en un marco k de una página i
cargada en un marco j hasta el momento en que un proceso vaya a realizar una operación de escritura
sobre dicha página. Es entonces cuando se crea una copia privada de la página i en el marco k sobre la
cual se realizan las modificaciones. Nótese que mientras que no son modificadas estás páginas pueden ser
compartidas por todos los procesos que hacen uso de ellas. De esta forma se consiguen ahorrar marcos
de página de memoria principal ya que se evita tener cargadas en memoria varias copias de las mismas
páginas.
4.2.2.
Mapeado de archivos en memoria
Como se estudiará en la sección 5 . 2 . 1 una operación de lectura o escritura a un determinado bloque
de datos de un archivo ubicada en memoria secundaria requiere por parte de un proceso A la invocación
de tres llamadas al sistema como máximo: la llamada al sistema open para abrir el archivo (si no estaba
abierto), la llamada al sistema l s e ek para posicionar el puntero de lectura/escritura asociado al archivo
en la posición adecuada (si no estaba ya correctamente posicionado) y la llamada al sistema read o
wr i t e para leer o escribir, respectivamente, el bloque de datos. En el caso de una operación de lectura,
en primer lugar hay que realizar una operación de E/ S a disco para leer el bloque en el disco y copiarlo
en un buffer de la caché de buffers del núcleo en memoria principal. Posteriormente el bloque es copiado
desde el buffer en el espacio de direcciones virtuales del proceso A .
Supuesto que e l bloque d e datos tiene e l tamaño d e una página d e memoria, en la memoria principal
existirían dos copias de la misma página, una asociada al buffer del núcleo y otra asociada al espacio del
proceso A. Si otro proceso B desea leer la misma página del archivo, tras realizar las llamadas al sistema
oportunas, la página será copiada en el espacio de direcciones del proceso B. Luego en la memoria
principal existirán tres copias de la misma página, una en la caché de buffers, otra en el espacio de
direcciones de A y otra en el espacio de direcciones de B .
Obviamente esta forma tradicional de acceder a un archivo genera u n desperdicio de memoria princi­
pal y resulta lenta ya que involucra la realización de varias llamadas al sistema. Una forma más eficiente
y rápida de acceder a un archivo consiste en mapearlo en memoria principal.
S OBUNIX : administración de memoria
149
3
Un archivo mapeado en memoria (memory-mapped file) es una región del espacio de direcciones
virtuales de un proceso en la que se establece una correspondencia byte a byte con parte o con la totalidad
de un archivo. Para establecer esta correspondencia el núcleo debe configurar las estructuras de datos que
mantiene para gestionar el espacio de direcciones de memoria virtual de un proceso (ver sección 4.2.3).
Una vez mapeado en memoria el acceso a un determinado byte del archivo puede ser realizado como
a cualquier otro contenido del espacio de direcciones virtuales, es decir, indicando la dirección vittual
oportuna. Se evita así tener que realizar llamadas al sistema.
Aparte del ahorro de memoria principal y de la rapidez de los accesos, otra de las ventajas de lo
archivos mapeados en memoria es que se pueden usar como mecanismo IPC ya que los cambios que
realice un proceso en el archivo mapeado son visibles por todos los procesos que mapeen dicho archivo
en sus espacios de direcciones.
El uso de archivos mapeados también presenta algunos inconvenientes. En primer lugar el tamaño
de los archivos que se pueden mapear por completo queda limitado por el tamaño del espacio de di­
recciones virtuales del proceso, el cual suele menor de 4 GiB en arquitecturas de 32 bits. Para archivos
que superan dicho tamaño, el archivo debe ser dividido en trozos cuyo mapeado debe irse alternando en
memoria principal. También el tamaño del espacio de direcciones virtuales limita el número de archivos
que pueden estar mapeados total o parcialmente simultáneamente en memoria.
Otro inconveniente está relacionado al uso del mapeo de archivos como mecanismos IPC ya que al
igual que sucedía con las regiones de memoria compartida es necesario utilizar algún mecanismo IPC
adicional (semáforos o cola de mensajes) para sincronizar el acceso de los diferentes procesos al archivo
mapeado.
El mapeo de archivos puede ser utilizado tanto por el núcleo como por los procesos. Algunos SO­
BUNIX como SVR4 y Solaris generalizan el mapeo de archivos para implementar todo el espacio de
direcciones virtuales, el cual se considera como una colección de objetos mapeados en memoria, siendo
los archivos uno de los posibles objetos.
En los SOBUNIX un proceso para mapear un archivo en memoria primero debe invocar a la llamada
al sistema open para abrir el archivo y así obtener su descriptor fd. A continuación debe invocar a la
llamada al sistema mmap, la cual presenta la siguiente sintaxis :
pdi rv=mmap ( di rvO , l on , pro t ,
ind , fd , ini c i o ) ;
Esta llamada tiene los siguientes argumentos de entrada:
•
dirvO es una recomendación para el núcleo sobre la dirección virtual de comienzo de la región
del espacio de direcciones del proceso donde se va a mapear el archivo. Lo más recomendable es
configurarlo a O para que sea el núcleo el que elij a la dirección que considere más oportuna.
•
l on es la longitud de la región en bytes. Si l on no es un múltiplo del tamaño de una página Sp
entonces se redondea el múltiplo mayor más próximo.
3 0tras traducciones para este término son
archivo proyectado en memoria y archivo de memoria mapeada.
150
Ampliación de sistemas operativos
•
prot permite establecer los permisos de acceso a la región. Se implementa como una combina­
ción de las siguientes constantes : PROT_READ (leer), PROT_WRITE (escribir) y PROT_EXECUTE
(ejecutar).
•
i nd es un conjunto de indicadores que permiten especificar las características del mapeado. Entre
los indicadores más frecuentemente utilizados se encuentran los siguientes:
- MAP_SHARED. Establece que el mapeado del archivo sea de tipo compartido, con lo que las
modificaciones que realice el proceso sobre el archivo pueden ser visualizadas por los proce­
sos que mapeen este archivo en sus espacios de direcciones. Además las modificaciones se
realizarán directamente sobre las páginas del archivo cargadas en memoria y cuando las pá­
ginas sean reemplazadas de la memoria se deberán actualizar los bloques de dato del archivo
en el disco.
- MAP_PRIVA TE. Establece que el mapeado del archivo sea de tipo privado, con lo que las
modificaciones que realice el proceso sobre el archivo no pueden ser visualizadas por los
procesos que mapeen este archivo en sus espacios de direcciones. Cuando un proceso intenta
escribir por primera vez sobre una determinada página del archivo mapeada como privada
recibe una copia privada de la página sobre la que se realizan las modificaciones. Es decir
se aplica la técnica de copiar al escribir. Dichas modificaciones, cuando la página sea re­
emplazada de memoria, no serán trasladadas a los bloques de datos del archivo en el disco.
Nótese que mientras que una página no sea escrita puede ser compartida para lectura por
varios procesos.
•
f d es el descriptor del archivo.
•
i ni c i o indica el byte del archivo a partir del cual se comenzará a mapear el archivo.
Esta llamada si se ejecuta con éxito devuelve en pdi rv la dirección virtual de comienzo de la región
y crea una correspondencia byte a byte entre el rango de bytes
[ in i c i o , ini c i o + l on - 1 ]
del archivo con descriptor f d y la región del proceso situada en el rango de direcciones virtuales
[ pdirv , pdirv+ l on - 1 ]
En caso de error devuelve - l .
Para eliminar el mapeo de u n archivo en el espacio de direcciones virtuales de un proceso se debe
invocar a la llamada al sistema r=munmap ( pd i rv , l on ) . Si se ejecuta con éxito devuelve O. En caso
de error devuelve - l .
e
Ejemplo 4.2
Considérense el archivo ejecutable prog4 1 cuyo código fuente en C se muestra en la Figura 4.2. Supón­
gase que prog4 1 es invocado desde la línea de órdenes de un intérprete de comandos y que el intérprete
S OBUNIX: administración de memoria
151
# i nc lude < f c n t l . h>
# i nc lude < s td i o . h>
# i nc lude <uni s t d . h>
# i nc lude < sys / mman . h>
ma i n ( )
{
int f d , L ;
c addr_t d ;
char bu f f er [ 2 0 ] ;
L = s i z e o f ( bu f f e r ) ;
f d = open ( " t ex t o l . tx t " , 0 6 6 6 ) ;
1 * C r e a r e l roap e o d e l arch ivo e n u n a reg i ón * 1
I
d=mmap ( NULL , L , PROT_WR I T E PROT_READ , MAP_S HARED , f d , ( o f f_t ) O ) ;
i f ( d= =MAP_FAI LED )
p r i n t f ( " \ nErro r \ n " ) ;
else {
close ( fd) ;
bu f f er [ O ] = * d ;
* d= ' S ' ;
print f (
/ * L e e r en la r e g i ón * /
/ * E s c r i b i r en la r e g i ón * /
•
\ nAn t e s= %e De spue s= %c \ n •
munmap ( d , L ) ;
,
bu f f er [ O ] , * d ) ;
1 * E l iminar el map e o de l archivo en l a r e g i ó n * 1
Figura 4.2 - Código C del programa prog4 1
crea un proceso A para ejecutar este programa. El proceso en primer lugar invoca a la función s i z e o f
para determina el tamaño e n bytes que ocupa l a variable bu f f e r . Puesto que esta variable e s una cadena
de 20 caracteres y supuesto que cada carácter requiere un 1 byte, entonces en la variable L se almacena
el valor 20. En segundo lugar se invoca a la llamada al sistema open para abrir el archivo text o l . txt
con permisos de lectura y escritura para todos los usuarios. Se va a suponer que este archivo contiene
únicamente la siguiente línea de texto:
E s t o e s un e j emp l o de u s o de mmap
En tercer lugar se invoca a la llamada al sistema mmap para solicitar la creación de una región de me­
moria virtual de tamaño L bytes con acceso de lectura (PROT_READ) y escritura (PROT_WRI TE) que sea
compartida (MAP_SHARED) en la que se van a mapear L bytes del archivo con descriptor fd comenzando
desde el inicio ( ( o f f_ t ) o ) del archivo. La dirección de comienzo de esta región será elegida por el
sistema operativo (NULL). Si la llamada al sistema se ejecuta con éxito entonces en d se almacenará la
dirección de inicio de la región virtual creada, la cual ocupa el rango de direcciones [ d , d+L - 1 ] . En esta
152
Ampliación de sistemas operativos
región se ha mapeado byte a byte los L primeros bytes del archivo con descriptor fd.
A continuación se comprueba si se ha producido algún error (MAP_FAILED ) durante la ejecución de la
llamada. En dicho caso se imprime en la pantalla el mensaje Error y el proceso termina su ejecución.
Si la llamada se ha ejecutado con éxito entonces se invoca a la llamada al sistema c l a s e para cerrar
el archivo. Posteriormente se lee el primer byte de la región en la que está mapeado el archivo, que
corresponde al carácter E y se almacena en la variable bu f f e r [ o l . Luego se escribe el carácter s en el
primer byte de la región en la que está mapeado el archivo.
Finalmente se invoca a la función p r i n t f que muestra en la pantalla el mensaje
An t e s = E De spué s = S
e invoca a l a llamada al sistema rnunmap para eliminar el mapeo del archivo del espacio de direcciones
del proceso.
Señalar que puesto el mapeado del archivo en la región se solicitó con la opción MAP_SHARED la modi­
ficación que ha realizado el proceso A sobre la región ha sido trasladada el archivo t ext o l . txt en el
disco. Esto se puede comprobar abriendo el archivo con un editor o a través de un intérprete de comandos
escribiendo la orden: more text o l . txt
•
4.2.3.
Estructuras de datos gestionadas por el núcleo asociadas al espacio de direcciones
virtuales de un proceso
El núcleo mantiene diferentes estructuras para gestionar el espacio de direcciones de un proceso.
El nombre y la información contenida en estas estructuras dependen de cada SOBUNIX. Generalmente
a cada región existente se le asocia una estructura El que contiene, entre otros, los siguientes datos
sobre una región: dirección virtual base, tamaño, permisos de acceso y un puntero a la tabla de páginas.
Además existe una estructura E2 que contiene información sobre el número de regiones existentes, su
tamaño total y la localización de las estructuras El asociadas a las regiones. En la entrada asociada al
proceso en la tabla de procesos se suele mantener un puntero a su estructura E2.
e
Ejemplo 4.3
La implementación del espacio de direcciones virtuales que realiza Solaris está basada en la arquitec­
tura de gestión de memoria virtual de SunOS 4.0, también denominada abreviadamente en la literatura
[Vahalia, 1 995] como arquitectura VM (Virtual Memory, memoria virtual). Debido a su eficiencia y
versatilidad la arquitectura VM ha sido adoptada por diversos SOBUNIX, como por ejemplo: SVR4 y
Solaris.
En la arquitectura VM se utiliza el término segmento para referirse a una región del espacio de direcciones
virtuales. Además se extiende el uso de los archivos mapeados para la construcción de todas las regiones
del espacio de direcciones virtuales tanto de un proceso como del núcleo.
Cada segmento mapea un determinado objeto de datos que puede estar asociado a: parte o la totalidad de
un archivo en el sistema de archivos, bloques de datos del área de intercambio, un buffer de un dispositivo,
SOBUNIX : administración de memoria
153
etc. Cada objeto de datos comprende un rango contiguo de bytes que puede ser accedido por el rango de
direcciones virtuales contiguas que comprende el segmento. Por otra parte cada objeto tiene asociado un
nodo-v. El tamaño de un objeto es siempre un múltiplo del tamaño de una página.
Un objeto de datos constituye la fuente a partir de la cual se inicializa el contenido de los marcos de
página asociados a las páginas virtuales de un segmento. Además es el almacenamiento de respaldo
persistente de las páginas de dicho segmento. La memoria principal actúa como una memoria caché de
las páginas de los objetos de datos. La primera vez que se referencie a una dirección virtual contenida en
una página i de un segmento se producirá un fallo de página. Al tratar el fallo se asignará a la página i un
marco j de la memoria principal el cual debe ser inicializado adecuadamente a partir del objeto de datos
al que está mapeado el segmento al que pertenece la página i.
Un objeto de datos especial es el objeto anónimo que se utiliza como fuente de páginas llenas de ceros,
las cuales se utilizan, por ejemplo, en la creación del montículo y la pila de un proceso. El objeto anónimo
se implementa como un puntero al nodo-v NULL o al nodo-v del archivo / dev / z er o .
En función del objeto mapeado y del espacio d e direcciones vittuales (usuario o núcleo) e n que s e mapea
se pueden distinguir diferentes tipos de segmentos. Entre los tipos de segmentos más frecuentemente
utilizados en Solaris se encuentran los siguientes :
•
s eg_vn. Segmento perteneciente al espacio de direcciones virtuales de un proceso de usuario que
se utiliza para mapear archivos regulares o el objeto anónimo. Todos los segmentos del espacio
de direcciones de un proceso de usuario son segmentos de este tipo. Los segmentos de código y
de datos inicializados se construyen mediante el mapeo del código y los datos inicializados del
archivo ejecutable correspondiente. La región de datos no inicializados, el montículo y la pila se
construyen mediante el mapeo del objeto anónimo.
•
s eg_map . Segmento petteneciente al espacio de direcciones virtuales del núcleo que se utiliza
para mapear archivos regulares. Las páginas de un segmento de este tipo se alojan en marcos
bloqueados de memoria principal. Este tipo de segmento se utiliza para implementar la caché de
páginas de archivos del núcleo.
•
s e g_kmen. Segmento perteneciente al espacio de direcciones del núcleo que se utiliza para mapear
archivos regulares o el objeto anónimo. Las páginas de un segmento de este tipo se alojan en
marcos bloqueados de memoria principal. Los segmento de código, datos, pila y montículo del
núcleo son segmentos de este tipo.
Sobre los segmentos de un mismo tipo se opera con un determinado driver del segmento que queda
definido por un conjunto de datos privados y rutinas.
En Solaris cada proceso tiene asignada por el núcleo una estructura proc donde se mantiene diferente
información relativa a un proceso. Entre la información contenida en proc existe un puntero p_a s a una
estructura as que contiene, entre otros, los siguientes datos:
•
a_s i z e . Tamaño en bytes del espacio de direcciones virtuales.
154
Ampliación de sistemas operativos
•
a_n s e g s . Número de segmentos que forman parte del espacio de direcciones virtuales del proceso.
•
a_s egtree. Puntero a una estructura que implementa un árbol AVL4 con todos los segmentos del
espacio.
•
a_hat . Puntero a una estructura hat (ver sección 4.3) con información sobre las tablas de páginas.
s t ru c t
seg
s t ruct
S -base
S-s i z e
S - as
S -t r e e
S -base
S -dat a
S- s i z e
Operaciones del driver
de los segmentos tipo
S - as
S -t r e e
s e g_vn
s _ops
r--
seg
s e gvn_map ( )
s _op s
r-
S -da t a
s e gvn_ f ree ( )
s e gvn_ f au l t ( )
!
1
s t ru c t
s t ru c t
s e gvn_da t a
s e gvn_dat a
Figura 4.3 - Estructuras de datos usadas en Solaris para describir un segmento de tipo s eg_vn
A su vez cada segmento tiene asociada una estructura s eg que contiene, entre otros, los siguientes datos
(ver Figura 4.3):
•
s_ba s e . Dirección virtual base de comienzo del segmento.
•
s_s i z e . Tamaño del segmento en bytes.
•
s_a s . Puntero a la estructura a s a la que pertenece.
•
s_t r e e . Punteros para construir el árbol AVL de segmentos del que forma parte.
•
s_op s . Puntero a las funciones del driver del segmento que definen las operaciones que pueden
realizarse sobre el segmento una vez creado.
•
s_da t a . Puntero a una estructura que contiene diferentes datos sobre el segmento. Estos datos
dependen del tipo de segmento y son utilizados por las funciones del driver del segmento.
En la Figura 4.4 se muestra a modo de resumen un diagrama con las estructuras de datos utilizadas en
Solaris para describir el espacio de direcciones virtuales de un proceso.
•
4Un árbol AVL es un tipo especial de árbol binario autobalanceable [Cormen et al. , 2009] inventado por los matemáticos
rusos Adelson-Velskii y Landis.
SOBUNIX: administración de memoria
155
s t ru c t proc
1
1
1
1
1
1
1
1
r-- 1-p_as
Librerías
1
1
1
1
1
1
1
1
1
1
t
1
1
1
1
1
1
1
1
1
1
s t ru c t s e g
-r-
Montículo
s -b a s e
s size
S
-
as
-
S-t r e e
s_op s
....
Datos
s t ru c t a s
J
a_s e g t r e e
a- s i z e
a_n s e g s
a hat
S - da t a
s t ru c t s e g
Código
1=
'---
s -ba s e
S- s i z e
S
Árbol AVL
-a s
S -t r e e
s_op s
s da t a
Figura 4.4 - Estructuras de datos usadas en Solaris para describir el espacio de direcciones virtuales de
un proceso
4.2.4.
Memoria anónima
Una página anónima es una página que antes de su creación no dispone de un almacenamiento
persistente de respaldo en memoria secundaria. Las páginas anónimas son utilizadas por ejemplo, en la
región de datos no inicializados, el montículo y la región de pila. También son utilizadas en las regiones
asociadas a archivos mapeados en memoria con el indicador MAP_PRIVA TE, este el caso por ejemplo de
la región de datos inicializados.
Una página anónima solo se crea cuando se accede por primera vez a ella durante una operación de
escritura. Es durante el tratamiento del fallo de página correspondiente cuando se le asigna un marco de
memoria principal, se inicializa el marco con ceros o con la copia del contenido de otra página, y se le
asigna espacio en el área de intercambio.
Cuando se intenta escribir por primera vez en una página del segmento de datos no inicializados,
el montículo o la pila se produce una excepción hardware que al ser tratada por el núcleo produce la
creación de una página anónima que es inicializada con ceros. A esta operación se le denomina llenar
Ampliación de sistemas operativos
156
con ceros por demanda (Zero-Fill-On-Demand, ZFOD).
Cuando se intenta escribir por primera vez en una página de un segmento asociado a una archivo
mapeado en memoria con el indicador MAP_PRIVATE se genera una excepción hardware que al ser
tratada por el núcleo produce la creación de una página anónima en la cual se copia el contenido de
la página que originó la excepción. A esta estrategia de copiar el contenido de una página únicamente
cuando la página se modifica se le denomina copiar al escribir. Esta estrategia permite evitar durante la
creación de un proceso hijo (ver sección 4.2.7) la duplicación de ciertos segmentos del proceso padre.
El duplicado de una página de un segmento se aplaza hasta que el proceso hijo desea escribir en ella. Es
en ese momento cuando se le asigna una página anónima en la que se carga una copia de la página del
proceso padre.
Al conjunto de páginas anónimas utilizadas por un proceso se le denomina memoria anónima del
proceso. La memoria anónima se asigna por regiones del espacio de direcciones virtuales mediante el
uso de diferentes estructuras de datos. El núcleo manipula estas estructuras mediante el uso de diferentes
funciones. El nombre y el contenido de las estructuras de datos que implementan la memoria anónima,
así como el nombre y la definición de las funciones del núcleo que operan sobre dicha memoria dependen
de cada SOBUNIX.
e
Ejemplo 4.4
En los SOBUNIX que utilizan la arquitectura VM de gestión de memoria, como por ejemplo Solaris,
una página anónima se crea la primera vez que se desea realizar una operación de escritura sobre una
dirección virtual contenida en una página perteneciente a:
•
Un segmento que ha sido construido con un mapeado de tipo MAP_PRIVATE a un archivo. Este es
el caso por ejemplo, del segmento de datos inicializados de un proceso.
•
Un segmento que ha sido construido con un mapeado al objeto anónimo. Este es el caso de los
segmentos de pila, montículo y datos no inicializados .
seg
Array de referencias
a estructuras anon
.-----li-s da t a
a non
anon_map
base
a non
s i ze
cont re f = l
s e gvn_dat a
Estructuras de datos usadas en Solaris para describir las páginas anónimas de segmento de
tipo s eg_vn
Figura 4.5
-
Para este tipo de segmentos la estructura s egvn_da t a (ver Figura 4.5), a la que apunta el campo s_da t a
d e la estructura s eg que implementa u n segmento, tiene u n puntero amp a una estructura anon_rnap que
S OBUNIX: administración de memoria
157
contiene la dirección de inicio ba s e y el tamaño s i z e de un array de referencias a estructuras anon.
En este array existe una entrada por cada página del segmento. Cada entrada contiene un puntero a una
estructura anon que representa a una página anónima. Esta estructura contiene información sobre la
localización de la página anónima en el área de intercambio (ver sección 4.5). Además contiene un con­
tador de referencias que se incrementa en una unidad cada vez que el segmento de un proceso referencia
a dicha página anónima.
Sobre la memoria anónima el núcleo trabaja usando un determinado conjunto de funciones que constitu­
yen la denominada como capa anónima, entre las funciones que forman parte de esta capa se encuentran
las siguientes [Vahalia, 1 995] :
•
anon_a l l o c . Esta función permite obtener una página anónima nueva.
•
anon_dup . Esta función duplica las referencias a un conjunto de páginas anónimas. Se utiliza
durante el tratamiento de la llamada al sistema f o rk para duplicar en el espacio del proceso hijo un
segmento del proceso padre que tiene páginas anónimas. El efecto de esta operación es incrementar
en una unidad el contador de referencias de las estructuras anon de cada página anónima del
segmento compartida por el padre y el hijo.
•
anon_ f r e e . Elimina las referencias a un conj unto de páginas anónimas. El efecto de esta ope­
ración es decrementar en una unidad el contador de referencias de las estructuras anon de cada
página privada del conjunto. Solamente cuando el contador alcanza el valor O se puede eliminar
dicha página anónima y dej ar la estructura anon desasignada.
•
anon_priva t e . Hace una copia privada de una página y le asigna una estructura anon.
•
anon_ z e r o . Crea una página llena de ceros y le asigna una estructura anon.
•
4.2.5.
Memoria compartida
Una región de memoria compartida es un mecanismo IPC que permite compartir datos entre distintos
procesos. Para que un proceso pueda acceder a dichos datos debe mapear la región dentro de su espacio de
direcciones virtuales. En la sección 3 .5 . 1 al describir los mecanismos IPC del System V se describieron
las llamadas al sistema que debe invocar un proceso para crear y poder usar una región de memoria
compartida. También se comentó que el núcleo mantiene una tabla con una entrada por cada mecanismo
IPC del tipo memoria compartida existente en el sistema. Aparte de esta tabla global el núcleo mantiene
diferentes estructuras de datos para implementar las regiones de memoria compartida. El nombre y el
contenido de estas estructuras dependen de cada SOBUNIX.
e
Ejemplo 4.5
En los SOBUNIX que usan la arquitectura VM de gestión de memoria, como Solaris , una región de
memoria compartida se implementa como un segmento de tipo s eg_vn mapeado al obj eto anónimo con
158
Ampliación de sistemas operativos
Proceso A
s e gvn_dat a
Proceso B
Array d e referencias
a estructuras anon
a non
cont
re f = l
anon_map
base
c o n t re f = 3
a non
s egvn_da t a
cont
re f = l
Tabla de recursos IPC
del tipo
memoria compartida
Figura 4.6 - Estructuras de datos usadas en Solaris para implementar u n recurso IPC del tipo memoria
compartida
un mapeo del tipo MAP_SHARED. La primera vez que se escribe en una página del segmento de memoria
compartido se crea una página anónima que tiene el área de intercambio como almacenamiento de res­
paldo persistente. La estructura anon_rnap asociada a este segmento contiene un contador de referencias
que indica el número de estructuras que le referencian.
En la Figura 4.6 se muestran, a modo de ejemplo, las estructuras de datos de un recurso IPC del tipo
memoria compartida que está siendo compartido por dos procesos A y B. Se observa que el contador
de referencias de la estructura anon_rnap contiene el valor 3, ya que son tres las estructuras de datos
que la referencian: la estructura s egvn_da t a del proceso A, la estructura s egvn_da t a del proceso B
y la entrada asociada al recurso de la tabla global de recursos IPC del tipo memoria compartida. Solo
cuando este contador de referencias alcance el valor O, el núcleo podrá eliminar las páginas anónimas
asociadas al segmento y desasignar las estructuras de datos. Nótese que aunque finalicen los procesos A
y B , las páginas anónimas del segmento de memoria compartida seguirán existiendo si no se ha invocado
explícitamente a la llamada al sistema shrnc t l con la orden I PC_RMID o se ejecuta el comando ipcrrn.
Solo en ese caso se desasignará la entrada asociada a este mecanismo IPC en la tabla global y el contador
de referencias de anon_rnap alcanzará el valor O.
Nótese también que el contador de referencia de la estructura anon de una página anónima perteneciente
a un recurso IPC del tipo memoria compartida contiene el valor l . Esto es así porque todos los proce­
sos que tienen mapeado en su espacio de direcciones este recurso IPC comparten la misma estructura
anon_rnap y el mismo array de referencias a estructuras anon. A diferencia de lo que ocurre cuando se
duplica un segmento, en cuyo caso el segmento original y el duplicado tienen cada uno su propia estruc­
tura anon_rnap y su propio array de referencias a estructuras anon. Como ambos arrays de referencias
SOBUNIX : administración de memoria
159
apuntan a las mismas páginas anónimas entonces el contador de referencias de las estructuras anon de
estas páginas contienen el valor 2.
•
4.2.6.
Operaciones sobre el espacio de direcciones virtuales de un proceso
Sobre el espacio de direcciones virtuales de un proceso el núcleo puede realizar diferentes operacio­
nes. Estas operaciones se pueden clasificar en dos grandes grupos :
•
Operaciones que afectan a todo e l espacio de direcciones de u n proceso. Como l a creación de
un nuevo espacio de direcciones, y la duplicación o eliminación de un espacio de direcciones ya
existente.
•
Operaciones que afectan a una región o segmento del espacio de direcciones de un proceso. Como
la creación de una nueva región, la eliminación de una región, la configuración y la comprobación
de los permisos de acceso a una región, etc.
Cada SOBUNIX define qué operaciones sobre el espacio de direcciones soporta y cómo las imple­
menta.
e
Ejemplo 4.6
En los SOBUNIX que utilizan la arquitectura VM de gestión de memoria, como por ejemplo Solaris,
hay definidas diferentes operaciones que trabaj an sobre la estructura as que representa el espacio de
direcciones virtuales de un proceso. Algunas de estas operaciones afectan a todo el espacio de direcciones
virtuales del proceso, como por ejemplo:
•
as_a l l o c . Crea un nuevo espacio de direcciones virtuales. Esta función se invoca durante el
tratamiento de las llamadas al sistema fork y exe c .
•
as_dup . Duplica u n espacio de direcciones . Esta función s e invoca durante el tratamiento d e la
llamada al sistema f o rk.
•
as_f r e e . Elimina un espacio de direcciones ya existente. Esta función se invoca durante el trata­
miento de la llamada al sistema exi t .
Otras operaciones trabaj an a nivel de segmento, como por ejemplo:
•
as_map . Crea un segmento en el espacio de direcciones, es decir, mapea un objeto en memoria.
•
as_unmap . Elimina un segmento del espacio de direcciones.
•
as_fau l t. Trata un fallo de página originado por una dirección virtual del espacio.
Las operaciones que trabajan con la estructura a s a nivel de segmento suelen invocar, en la mayoría de
los casos, a funciones del driver del segmento para realizar las operaciones correspondientes. Recuérdese
que cada tipo de segmento tiene asignado un driver de segmento determinado.
•
160
4.2. 7.
Ampliación de sistemas operativos
Creación del espacio de direcciones virtuales de un proceso
Una de las tareas principales que debe realizar el núcleo durante el tratamiento de fork es la creación
del espacio de direcciones virtuales del proceso hijo. La implementación de esta tarea depende de cada
SOBUNIX, aunque de forma general puede afirmarse que en los SOBUNIX modernos la creación del
espacio de direcciones virtuales del proceso hijo se realiza duplicando las estructuras de datos asociadas
al espacio de direcciones virtuales del proceso padre.
Por el contrario, las páginas del proceso padre no son inicialmente duplicadas en memoria durante el
tratamiento de f ork, ya que así se ahorra memoria principal y se disminuye la sobrecarga. Las páginas
asociadas a la región de código del proceso padre o las regiones de código de las librerías compartidas,
son de solo lectura, y pueden ser compartidas por el proceso padre y el proceso hijo. También son
compartidas las páginas de las regiones de memoria compartida y las regiones asociadas a archivos
mapeados del tipo MAP_SHARED.
Por otra parte, sobre las páginas asociadas a la región de datos, a la región de pila y a las regiones
asociadas a archivos mapeados del tipo MAP_PRIVATE se aplica la técnica de copiar al escribir, es decir,
la página es copiada en memoria únicamente cuando un proceso tiene que escribir por primera vez sobre
la página. De esta forma dicho proceso hijo dispone de una copia privada de la página sobre la que realiza
las modificaciones.
e
Ejemplo 4.7
En los SOBUNIX que implementan una arquitectura VM de gestión de memoria, como Solaris, la crea­
ción del espacio de direcciones virtuales de un proceso hijo durante el tratamiento de una llamada al
sistema f ork se realiza siguiendo los siguientes pasos [Vahalia, 1 995] :
l . Tras asignar e inicializar una estructura proc para el proceso hijo se invoca a la función as_dup .
Esta función en primer lugar invoca a la función as_a l l o c para asignar una nueva estructura a s
para el proceso hijo.
2. La función as_a l l o c recorre el árbol AVL de segmentos del proceso padre e invoca para cada
segmento a la función dup del driver de segmento correspondiente con el objetivo de duplicar el
segmento dentro de la estructura as del proceso hijo. Por ejemplo, para un segmento tipo s eg_vn
se invocaría a la función s egvn_dup .
3 . Una vez que todos los segmentos han sido duplicados, la función as_dup invoca a la función
hat_dup que duplica la estructura hat (ver sección 4.3) y las tablas de páginas del proceso padre .
•
SOBUNIX: administración de memoria
4.3.
Traducción de direcciones virtuales a direcciones físicas en
SOBUNIX
4.3.1.
Tablas de páginas y MMU
161
Una de las principales tareas que es necesario realizar en la implementación de la técnica de gestión
de memoria mediante demanda de página es la traducción de direcciones virtuales a direcciones físicas.
Para su realización se utilizan dos elementos:
•
Tabla de página. Una tabla de páginas es una estructura de datos que contiene una entrada por cada
página existente en un espacio de direcciones virtuales. El tamaño de una entrada suele ser de 32
bits o de 64 bits que se descomponen en diferentes campos. El número, orden, tamaño y contenido
de los campos viene determinado por la arquitectura del computador. Entre los campos presentes
habitualmente en una entrada de una tabla de páginas se encuentran los siguientes :
- Número de marco de página. Contiene e l número de marco j de memoria principal donde se
encuentra almacenada la página i
- Validez o presencia. Este campo consta de un único bit v que se activa si la página i está
cargada en el marco j. Si la página no pertenece actualmente al espacio de direcciones del
proceso o no está cargada en memoria principal este bit está desactivado.
- Bits de protección. Este campo en su forma más simple consta de un único bit que en función
de su valor indica si la página es de solo-lectura o de lectura-escritura.
- Referenciada. Este campo consta de un único bit r que se activa cuando la página i es referen­
ciada por una dirección virtual. Este bit suele ser consultado para decidir que página puede
ser reemplazada (ver sección 4.4.2).
- Modificada. Este campo consta de un único bit m que se activa cuando la página i es modi­
ficada en una operación de lectura. Su activación indica al núcleo que debe copiar la página
en memoria secundaria antes de reemplazarla.
Cuanto mayor sea el espacio de direcciones virtuales de un proceso mayor será el tamaño de su
tabla de páginas y más espacio de memoria principal consumirá. Para ahorrar memoria algunas
arquitecturas soportan el uso de tabla de páginas paginadas de dos o más niveles. También algunas
arquitecturas trabajan con tablas de páginas invertidas.
En un determinado instante de tiempo en la memoria del núcleo existen cargadas varias tablas de
página. Generalmente existe una única tabla de páginas para describir las páginas del espacio de
direcciones del núcleo y una o más tablas para describir las páginas del espacio de direcciones de
un proceso. En algunos S OBUNIX se asocian las tablas de páginas por regiones, existiendo una
tabla de páginas asociada a cada región.
•
MMU. Es un componente hardware que se encarga de realizar la traducción de una dirección
virtual en una dirección física. Para poder realizar la traducción, en un registro de la MMU se
Ampliación de sistemas operativos
162
carga la dirección física de comienzo de la tabla de páginas del proceso en ejecución. Además se
carga en el TLB de la MMU una copia de un conjunto de entradas de dicha tabla de páginas.
Cuando la MMU recibe del procesador una dirección virtual, la descompone en dos campos : número
de página i y desplazamiento, y comprueba si la entrada de la tabla de páginas asociada a la página i está
cargado en el TLB . Si no es así se produce un fallo de TLB que al ser tratado por el hardware, el núcleo,
o ambos en colaboración, hace que se cargue en una entrada del TLB la entrada de la tabla de páginas
que se estaba buscando.
Una vez encontrada la entrada del TLB que contiene una copia de la entrada de la tabla de páginas
asociada a la página i, la MMU comprueba el campo protección para verificar que no se está intentando
realizar una operación no permitida sobre la página. Si se intenta realizar un tipo de operación no auto­
rizada la MMU genera una excepción hardware denominada fallo de protección. Si no existe un fallo de
protección comprueba el bit de validez v y si está activado se accede al campo marco j de dicha entrada
en el TLB para construir junto con el campo desplazamiento la dirección física. Si el bit de validez está
Dirv
N° de página i
1 6 bits
1
. ..
1
Sin usar
}i
9
bits
IETPN3
1
9
. ..
1
bits
. ..
IETPN2
9
bits
9
IETPN 1
bits
. ..
IETPNO
1
1 2 bits
Desplazamiento
1
llicrn
Registro
CR3
�
IrFI
Marco l
Marco m
DirFo
! Marco
m
Tabla de
páginas
de nivel 3
w
1 Marco 1
1�
4
DirF 3
Tabla de
páginas
de nivel 2
! Marco k
Tabla de
páginas
de nivel 1
Marco k
w
1 Marcoj
Tabla de
páginas
de nivel O
Marco j
w
Págma
Figura 4.7 - Tablas de páginas paginadas de 4 niveles soportadas en la arquitectura x64 de AMO
1
S OBUNIX: administración de memoria
163
desactivado se produce una excepción denominada fallo de válidez que debe ser tratado por el núcleo.
La traducción de direcciones requiere la colaboración entre el subsistema de gestión de memoria
del núcleo y la MMU. El subsistema de gestión de memoria se encarga de asignar espacio, configurar y
actualizar las tablas de páginas. Además se encarga de cargar los registros y el TLB de la MMU cada vez
que se produce un cambio de contexto. También se encarga de atender las excepciones generadas por la
MMU.
Por su parte la MMU se encarga de comprobar la validez de los accesos, generar una excepción si el
acceso no es válido, traducir las direcciones virtuales a direcciones físicas, y activar los bits referenciada
o/y modificada.
Con el objetivo de ahorrar espacio de memoria principal los SOBUNIX suelen trabaj ar con tablas
de páginas paginadas, el número de niveles de paginación utilizados es fijado por cada SOBUNIX en
función de la arquitectura.
e
Ejemplo 4.8
Solaris cuando se ejecuta en la arquitectura x64 de AMO utiliza un tamaño de página de 4 KiB y tablas
de paginas paginadas de 4 niveles de paginación (ver Figura 4.7). Cuando un proceso es planificado para
ejecución la dirección física Dirpo de la tabla de paginas del nivel 3 del espacio de direcciones de dicho
proceso es cargada en el registro CR3 del computador. Cuando durante la ejecución de dicho proceso
se referencia a una determinada dirección virtual Dirv para traducirla a la dirección física Dirp a la que
hace referencia se realizan los siguientes pasos :
l . Se suma Dirpo con el valor del campo índice de la entrada de la tabla de páginas del nivel 3
(IETPN3) de la dirección virtual Dirv para obtener la dirección física Dirp¡ de la entrada de la
tabla de páginas de nivel 3 que almacena el número m del marco de página que contiene a la tabla
de páginas del nivel 2.
2. Se accede a Dirp¡ para leer dicho número de marco m y se suma a la dirección física base del
marco m el valor del campo IETPN2 de Dirv . Se obtiene así la dirección física Dirp2 de la entrada
de la tabla de páginas de nivel 2 que almacena el número l del marco de página que contiene a la
tabla de páginas del nivel l .
3 . Se accede a Dirp2 para leer dicho número de marco l y se suma a la dirección física base del marco
l el valor del campo IETPN l de Dirv . Se obtiene así la dirección física Dirp3 de la entrada de la
tabla de páginas de nivel 1 que almacena el número k del marco de página que contiene a la tabla
de páginas del nivel O.
4. Se accede a DirF3 para leer dicho número de marco k y se suma a la dirección física base del marco
k el valor del campo IETPNO de Dirv . Se obtiene así la dirección física Dirp4 de la entrada de la
tabla de páginas de nivel O que almacena el número j del marco de página que contiene a la página
i referenciada en Dirv .
5 . Se accede a Dirp4 para leer dicho número de marco j y se suma a la dirección física base del marco
164
Ampliación de sistemas operativos
j el valor del campo desplazamiento de Dirv . Se obtiene así la dirección física Dirp a la que hace
referencia Dirv .
Señalar que aunque la arquitectura x64 de AMD soporta direcciones virtuales de 64 bits, realmente los
16 bits más significativos de una dirección virtual de 64 bits no se utilizan y por ello se configuran todos
a O o todos l . Pese a ello el espacio de direcciones virtuales sigue siendo bastante grande: 24 8 bytes= 256
TiB .
•
El núcleo para gestionar las tablas de páginas de los distintos niveles y la MMU utiliza diferentes es­
tructuras de datos y funciones, cuyo nombre, definición e implementación dependen de cada SOBUNIX
y de la arquitectura del computador donde se ejecuta.
e
Ejemplo 4.9
En los SOBUNIX que implementan la arquitectura VM de gestión de memoria, como Solaris, la tarea
de traducción de direcciones la realiza una capa de software denominada capa HAT (Hardware Address
Translation, traducción de direcciones) . Esta capa contiene todas las funciones y estructuras del núcleo
que requieren conocer los detalles del hardware relativos a la traducción de direcciones. La implementa­
ción de esta capa depende de cada arquitectura.
El uso de la capa HAT evita que el resto del subsistema de gestión de memoria del núcleo tenga que
conocer los detalles del hardware, lo cual facilita la portabilidad del núcleo entre diferentes plataformas.
Solo la capa HAT depende del hardware y en consecuencia es distinta en cada arquitectura.
La capa HAT se encarga de la realización de las siguientes tareas:
•
Creación, configuración y destrucción de las tablas de páginas.
•
Control de la MMU.
•
Atención de las excepciones hardware provocadas por la MMU durante el proceso de traducción
de direcciones.
La capa HAT utiliza una estructura ha t para mantener todos los datos relativos a la traducción de direc­
ciones del espacio de direcciones de un determinado proceso, entre ellos, un puntero a la tabla de páginas
de más alto nivel. Recuérdese (ver sección 4.2.3) que la estructura as asociada al espacio de direcciones
virtuales de un proceso mantiene un puntero a la estructura ha t asociada al espacio del proceso.
Los drivers de los segmentos invocan a una determinada función de la capa HAT para la realización de
una determinada tarea, como por ejemplo:
•
hat_a l l o c . Asigna una estructura hat para el espacio de direcciones virtuales de un proceso.
•
hat_free_end. Destruye la estructura ha t de un proceso.
•
hat_mem l o ad. Crea la traducción de direcciones de una determinada página.
SOBUNIX: administración de memoria
165
hat_unl oad. Elimina o invalida la traducción de direcciones de una determinada página.
•
Las funciones de la capa HAT reciben argumentos de entrada que son independientes del hardware como
por ejemplo: direcciones virtuales, tamaños, punteros de página y modos de protección.
•
4.3.2.
Tratamiento de los fallos de página
La MMU durante el proceso de traducción de una dirección virtual en una dirección física realiza
diferentes comprobaciones en orden secuencial. Si el resultado de una comprobación no es satisfactorio
genera una excepción denominada fallo de página que debe ser atendida por el núcleo. De forma general
se distinguen dos posibles tipos de fallos de página:
•
Fallo de validez. Se produce cuando una dirección virtual referencia a una página i cuya entrada
asociada en la tabla de páginas tiene el bit de validez desactivado (v = 0). Este bit se encuentra
desactivado si la página i no está cargada en un marco j de memoria principal o si la página no
pertenece al espacio de direcciones virtuales del proceso.
•
Fallo de protección. Se produce si la operación (lectura, escritura o ejecución) que se desea rea­
lizar sobre la página i referenciada por la dirección virtual no está autorizada por los permisos
establecidos en su entrada de la tabla de páginas.
La implementación del tratamiento de los fallos de página depende de cada SOBUNIX. Aunque de
forma general puede afirmarse que el núcleo para tratar las excepciones producidas por la MMU ejecuta
un manejador de fallos de página que realiza diferentes tareas en función del tipo de fallo de página que
se haya producido. Si se ha producido un fallo de protección o si se produce un fallo de validez porque
se ha intentado acceder a una página que no pertenece al espacio de direcciones del proceso, entonces
el manejador se lo notifica al proceso en ejecución enviándole una señal, generalmente S IGS EGV, cuya
acción establecida por defecto es la terminación del proceso .
S i s e h a producido u n fallo d e validez porque l a página i n o estaba cargada en u n marco j d e memoria
principal, entonces se le asigna un marco j de la lista de marcos de página libre y se carga en él la página i
leyéndola del área de intercambio o desde el sistema de archivos. Una vez cargada el manej ador actualiza
el contenido de la entrada asociada a la página i en la tabla de páginas y manipula el contexto hardware
salvado del proceso que produjo el fallo de página para que cuando vuelva a ser planificado para ser
ejecutado lo haga justo desde la instrucción cuya ejecución produjo el fallo de página.
e
Ejemplo 4.10
En los SOBUNIX que implementan una arquitectura VM de gestión de memoria, como S olaris, el trata­
miento de los fallos de página se realiza de la siguiente forma:
l. El manipulador de excepciones del núcleo identifica el tipo de fallo, el tipo de acceso y localiza
la estructura as del proceso cuya ejecución produjo el fallo de página. Una vez localizada dicha
estructura invoca a la función as_faul t para tratar el fallo.
166
Ampliación de sistemas operativos
2. La función as_faul t localiza el segmento del espacio de direcciones virtuales al que pertenece
la dirección virtual cuya referencia produjo el fallo de página.
3. Una vez localizado el segmento, as_faul t invoca a la función de tratamiento de fallos de página
del driver del segmento. Recuérdese que cada tipo de segmento dispone de un driver distinto y en
consecuencia su función de tratamiento de fallos de página también será distinta. Se va suponer
que el segmento es de tipo s eg_vn, luego se invocaría a la función de tratamiento de fallos de
página del driver de segmentos tipo s e g_vn, es decir, a la función segvn_faul t . Esta función
realiza diferentes acciones en función del tipo de fallo de página.
Si se trata de un fallo de protección o de un fallo de validez porque se ha intentado acceder a una
página que no pertenece al espacio de direcciones del proceso, entonces s egvn_ f au l t envía una
señal S I GSEGV al proceso que produjo el fallo de página. La acción por defecto asociada a esta
señal es terminar el proceso.
Por otra parte si se trata de un fallo de validez asociado a que la página i no estaba cargada en
un marco j de memoria principal entonces las acciones que realiza la función s e gvn_ f au l t
dependen del estado de la página:
•
Si la página tiene asignada una entrada en anon_map entonces invoca a anon_ge tpage
para leer la página en el área de intercambio.
•
Si la página no tiene asignada una entrada en anon_map y el segmento está mapeado a una
archivo, entonces invoca a la función ge tpage del nodo-v del archivo. Esta función si no
encuentra la página cargada en memoria entonces la lee en el disco.
•
Si la página no tiene asignada una entrada en anon_map y el segmento está mapeado al
objeto anónimo, entonces invoca a la función anon_ z e r o que crea una página privada llena
de ceros.
Una vez que la página está cargada en la memoria principal la función segvn_fau l t comprue­
ba si tiene que aplicar la técnica de copiar al escribir y en caso afirmativo invoca a la función
anon_private para hacer una copia privada de la página referenciada.
4. Cuando termina s egvn_ f au l t la función as_faul t invoca a la función ha t_menl oad para
actualizar el contenido de la entrada de la tabla de página tanto en memoria como en el TLB de la
MMU.
•
4.4.
Gestión de la memoria física en SOBUNIX
4.4.1 .
Estructuras de datos utilizadas en la gestión de la memoria física
Los SOBUNIX reservan una parte de la memoria principal para almacenar el código y los datos
estáticos del núcleo. El resto de la memoria principal se encuentra disponible para albergar los datos
SOBUNIX: administración de memoria
167
dinámicos del núcleo y las páginas de los procesos de los usuarios. Los marcos de página ocupados
por páginas del núcleo son marcados en su mayoría como marcos bloqueados, es decir, marcos cuyo
contenido no puede ser intercambiado fuera de la memoria principal. Con esta medida se pretende evitar
que existan fallos de página durante la ejecución del núcleo que afecten a su rendimiento. Algunos
SOBUNIX permiten que algunas pequeñas partes de su núcleo se alojen en marcos no bloqueados. Por
ejemplo, en Solaris las páginas de las pilas de los procesos ligeros se alojan en marcos no bloqueados.
Memoria principal
------
����?_i�Q
______
Zona
reservada
M arco j=N - 1
Marcoj=N
Marcoj=N+ I
ED j=N
ED j=N+ l
Zona asignable
dinámicamente
ED j=M- 1
Estructuras
de datos (ED)
asociadas a
los marcos
de página
de la zona
asignable
dinámicamente
Marcoj=M- 1
Figura 4.8 - Distribución típica de la memoria principal en los SOBUNIX
Para gestionar la parte de memoria de la memoria principal que se asigna dinámicamente el núcleo
mantiene una estructura de datos por cada marco de página existente (ver Figura 4.8). Dicha estructura
mantiene información sobre la página cargada en el marco, así como diferentes punteros para implemen­
tar diferentes listas, como por ejemplo la lista de marcos de página libres que es consultada cuando se
requiere asignar un marco de página libre para cargar una página en memoria. La implementación y la
gestión de las estructuras de datos asociados a los marcos de página, así como de las diferentes listas
mantenidas a partir de estas estructuras, dependen de cada SOBUNIX.
e
Ejemplo 4. 1 1
En los SOBUNIX que utilizan la arquitectura V M d e gestión d e memoria, como por ejemplo Solaris,
cada marco de página de la memoria principal tiene asociado una estructura page que contiene, entre
otros, los siguientes datos:
•
Identidad de la página cargada en el marco. Cada página cargada en un memoria principal queda
identificada de manera unívoca por el par de valores [nodo-v, desplazamiento], es decir, con el
Ampliación de sistemas operativos
168
nodo-v del objeto de datos a partir del cual fue creada la página y el desplazamiento (expresado en
páginas) dentro del objeto.
•
Contador de referencias. Se incrementa en una unidad por cada proceso que comparte el acceso a
la página cargada en el marco.
•
Información relacionada con las estructuras ha t . Como por ejemplo la localización de todas las
tablas de páginas que apuntan al marco.
•
Punteros. Para poder implementar las siguientes listas:
- Lista hash de marcos de página. El núcleo usa esta estructura para encontrar rápidamente al
marco que contiene una determinada página. El par de valores [nodo-v, desplazamiento] que
identifican a la página se introducen a modo de clave en una función hash que devuelve el
índice de una entrada de la lista hash. Cada entrada de la tabla hash estará vacía o contendrá
una cola de estructuras page. Todas las estructuras en una misma cola contienen páginas
cuyo par de valores [nodo-v, desplazamiento] generan el mismo índice al ser introducidos en
la función hash. Una vez conocido el índice hay que examinar la cola para ver si contiene la
página buscada. Obviamente este procedimiento es más rápido que examinar una a una todas
las estructuras page.
- Lista de páginas del nodo-v. Cada nodo-v (ver sección 5 .3 . 1 ) mantiene una lista de todas las
páginas que se encuentran cargadas en memoria principal del objeto al que hace referencia el
nodo-v. Esta lista es utilizada por las rutinas del núcleo que trabajan sobre todas las páginas
cargadas en memoria de un determinado objeto. Por ejemplo, cuando se borra un archivo el
núcleo debe invalidar todas las páginas del archivo que están cargadas en memoria.
- Lista de marcos de página libres. Forman parte de esta lista las estructuras page de los
marcos de página que no contienen ninguna página o contienen páginas que no son mapeadas
por ningún proceso ya que han sido liberadas por la función page_free.
- Lista de E/S. Forman parte de esta lista las estructuras page de los marcos de página que
contienen páginas cuyo contenido ha sido modificado y debe ser salvadas en el disco antes
de reemplazar su contenido.
•
4.4.2.
Reemplazamiento de páginas
Una de las tareas fundamentales que debe realizar un sistema operativo para implementar la técnica
de demanda de página es el reemplazamiento de páginas que consiste en seleccionar una página k cargada
en un marco de página j para ser reemplazada por la página i asociada a la dirección virtual que produjo
el fallo de página.
SOBUNIX : administración de memoria
169
Para implementar el reemplazamiento de página el núcleo debe seleccionar el conjunto de páginas
candidatas a ser reemplazadas, y usar algún algoritmo de reemplazamiento que seleccione, de entre el
conjunto de páginas candidatas, la página víctima que puede ser reemplazada.
En los SOBUNIX generalmente el conjunto de páginas candidatas está formado por todas las páginas
cargadas en la memoria principal en marcos no bloqueados, es decir, utilizan lo que en la literatura se
conoce como estrategia o política de reemplazamiento global.
Asimismo, el algoritmo de reemplazamiento utilizado mayoritariamente en los S OBUNIX es alguna
aproximación del algoritmo LRU (Least Recently Used, usada menos recientemente). La implementa­
ción de un algoritmo LRU estricto produce bastante sobrecarga por lo que se suele usar algún algoritmo
cuyo funcionamiento se aproxime al del algoritmo LRU pero que produzca menos sobrecarga.
e
Ejemplo 4.12
El algoritmo del reloj con dos manecillas (two-handed clock algorithm) utilizado en diversos SOBU­
NIX, como por ejemplo: BSD4.3, SunOS 4.0, SVR4 y Solaris, es una aproximación del algoritmo LRU
que elige como página víctima aquella no usada recientemente, en vez de la página menos usada recien­
temente que se selecciona en un algoritmo LRU.
Este algoritmo examina las estructuras de datos asociados a los marcos de página no bloqueados, a los
que considera organizados en una lista circular (horas del reloj). Para examinar las estructuras utiliza dos
punteros (manecillas) . Cada puntero apunta a una estructura. La separación entre los punteros, es decir,
el número de estructuras entre ellos, se mantiene siempre constante, siendo esta separación un parámetro
configurable del algoritmo. Ambos punteros se mueven simultáneamente en sentido horario.
Para describir el funcionamiento del algoritmo se va denominar puntero 1 al puntero que va por delante
y puntero 2 al que va por detrás (ver Figura 4.9). El puntero 1 pone a O el bit referenciada (r) de la
entrada de la tabla de páginas que referencia a la página cargada en el marco j. Por su parte el puntero
D
ED
x
D
=Estructura de datos asociada al marco
Figura 4.9
-
x
Algoritmo del reloj de dos manecillas
170
Ampliación de sistemas operativos
2 comprueba el bit r de la página cargada en el marco k. Si r = O entonces la página puede ser elegida
para ser reemplazada ya que la página no ha sido referenciada en el tiempo transcurrido desde que el
puntero 1 pasó por ella. El puntero 2 también comprueba el bit modificada m de la página cargada en el
marco k, si dicho bit está 1 la página es colocada en la lista de páginas que deben ser salvadas al área de
intercambio.
•
En los SOBUNIX para mejorar el rendimiento del sistema la búsqueda de páginas víctimas se realiza
antes de que ya no quede memoria libre disponible. Periódicamente, o cuando el tamaño de la lista de
marcos de página libres cae por debaj o de un determinado umbral, se invoca a un proceso del sistema
denominado escáner de paginas5 • Este proceso se crea cuando se arranca el sistema y generalmente tiene
asignado el PID=2.
El escáner de páginas, cuando es invocado, ejecuta el algoritmo de reemplazamiento para seleccionar
un cierto número de marcos de página cuyo contenido puede ser reemplazado. Los marcos seleccionados
cuyo contenido no ha sido modificado son colocados en la lista de marcos libres. Los marcos cuyo
contenido ha sido modificado son colocados en la lista de marcos modificados, los cuales deben ser
salvados en el área de intercambio. Cuando se realice esta operación los marcos serán colocados en la
lista de marcos libres.
Nótese que en consecuencia en la lista de marcos libres no solo hay marcos que contienen páginas que
pertenecen a procesos que ya han finalizado sino también marcos que contienen páginas pertenecientes
a procesos que pueden estar todavía activos pero que como no han sido recientemente referenciadas han
sido seleccionados como candidatas a ser reemplazadas.
Por este motivo el núcleo cuando se produce un fallo de página comprueba si dicha página se en­
cuentra en la lista de marcos de página libres y de esta forma ahorrarse tener que realizar una operación
de E/ S al disco. De hecho algunos SOBUNIX, distinguen dos tipos de listas de marcos de páginas libres :
en una lista se mantienen los marcos que contienen páginas que no van a volver a ser necesitadas y en
otra lista se mantienen páginas que pueden ser necesitadas. Solo cuando la primera se agota se empiezan
asignar marcos de la segunda.
El escáner de páginas se ejecuta hasta que se cumple un determinada condición de parada: haber
seleccionado para reemplazar un determinado número máximo de marcos de página, haber consumido
una cantidad preestablecida de ciclos de CPU, etc. Cuando se cumple la condición de parada el escáner
de páginas entra en el estado dormido hasta que vuelve a ser despertado porque haya transcurrido un
cierto tiempo o porque haya caído la memoria libre por debajo de un cierto límite.
Puesto que la disponibilidad de memoria libre afecta al rendimiento del sistema, la prioridad de
ejecución del escáner de páginas es bastante elevada.
5 A este proceso también se le conoce con el nombre de demonio de páginas (page daemon) o ladrón de páginas (page
stealer). En general el nombre de este proceso suele depender de cada SOBUNIX. En este texto se utiliza el nombre que emplea
Solaris: escáner de páginas, el cual describe bastante bien la tarea que realiza el proceso.
S OBUNIX : administración de memoria
4.4.3.
171
Intercambio de procesos
Si el número de procesos cargados parcialmente en la memoria principal supera un cierto valor
máximo, los conjuntos de trabaj o de los procesos, es decir, sus páginas referenciadas más frecuentemente,
no pueden estar todos contenidos en la memoria principal con lo que comienzan a producirse fallos de
página continuamente.
Una posible forma de eliminar el trasiego consiste en intercambiar de memoria principal al área de
intercambio todas las páginas de uno o varios procesos. En los SOBUNIX, esta tarea la realiza un pro­
ceso del sistema denominado proceso intercambiador (swapper). Este proceso tiene asignado el PID=O,
ya que es el primer proceso que se crea cuando se arranca un S OBUNIX. Este proceso inicialmente crea
al proceso ini t (PID= 1 ) y el escáner de páginas (PID=2), y a continuación pasa a ejecutar una fun­
ción, denominada s ched en algunos SOBUNIX, que contiene todo el código asociado al intercambio de
procesos.
El proceso intercambiador es invocado cada cierto tiempo o si el tamaño de la lista de marcos libres
cae frecuentemente por debajo de un cierto valor límite, lo cual recuérdese propiciaba la invocación
del escáner de páginas. El proceso intercambiador debe seleccionar de acuerdo con unos determinados
criterios los procesos cuyas páginas van a ser intercambiadas al área de intercambio. Cuando termina
de realizar su tarea el proceso intercambiador entra en el estado dormido a la espera de volver a ser
invocado.
La implementación y los criterios de selección que utiliza el proceso intercambiador dependen de
cada SOBUNIX.
e
Ejemplo 4.13
En Solaris se distinguen dos posibles tipos de intercambio :
•
Intercambio suave. Se produce s i e l tamaño d e l a lista d e marcos d e página libre permanece por
debajo de un cierto valor mínimo de s f ree durante alrededor de 30 segundos. El proceso inter­
cambiador, también denominado planificador de memoria, comienza a buscar procesos que han
estado inactivos durante al menos maxs lp segundos. Para cada proceso que cumple está condi­
ción intercambia al área de intercambio todas sus páginas privadas y las estructuras de datos del
núcleo asociadas a la gestión de sus hilos.
•
Intercambio duro. S e produce si se dan simultáneamente las siguientes condiciones: existen más
de dos procesos en las colas de procesos preparados para ejecución, el tamaño de la lista de marcos
de página libre permanece por debajo de un cierto valor mínimo de s f ree durante alrededor de
30 segundos, y la razón de fallos de página es mayor que maxpg i o . El intercambiador selecciona
en primer lugar para ser intercambiadas todos las páginas pertenecientes a módulos del núcleo que
no están activos. A continuación los procesos son intercambiados secuencialmente hasta que se
consigue el espacio libre suficiente.
•
172
Ampliación de sistemas operativos
El proceso intercambiador también comprueba periódicamente si los procesos intercambiados pue­
den volver a ser cargados en la memoria principal. El criterio de retorno que se utiliza depende de la
memoria libre disponible.
4.4.4.
Asignación de memoria principal
En los SOBUNIX la asignación de marcos de página de memoria principal la realiza un componente
del subsistema de gestión de memoria principal denominado asignador a nivel de página. Este asignador
atiende las peticiones de memoria del sistema de paginación y del asignador de la memoria del núcleo
(ver Figura 4. 1 0) .
Lista d e marcos libres
Marco j
Estructuras
de datos
para los
subsistemas
del núcleo
Procesos
usuarios
Caché de
buffers
de bloques
de disco
Figura 4.10 - Asignación de memoria principal en SOBUNIX
El sistema de paginación es la funcionalidad de la arquitectura de gestión de memoria virtual en­
cargada de asignar (y liberar) marcos de página para alojar en memoria principal las páginas virtuales
referenciadas por los procesos durante su ejecución. En algunos S OBUNIX también se encarga de asig­
nar marcos para la caché de buffers de bloques de disco. El sistema de paginación solicita marcos de
página al asignador a nivel de página para repartirlos entre sus clientes: los procesos de los usuarios o la
caché de buffers de bloques de E/S .
Por su parte, el asignador de la memoria del núcleo solicita marcos de página al asignador a nivel de
página para atender las peticiones de memoria de los diferentes subsistemas del núcleo.
El asignador a nivel de página trabaja sobre la lista de marcos de página libres sobre la que realiza,
entre otras, las siguientes operaciones:
S OBUNIX: administración de memoria
173
•
Eliminar marcos. Cuando el sistema de paginación o el asignador de la memoria del núcleo nece­
sitan una determinada cantidad de memoria principal invocan al asignador a nivel de página para
que les asigne marcos libres de memoria principal, los cuales son eliminados de la lista de marcos
de página libres.
•
Añadir marcos. Cuando el sistema de paginación o el asignador de la memoria del núcleo liberan
una cierta cantidad de memoria invocan al asignador a nivel de página para que añada los marcos
liberados a la lista de marcos de página libres.
•
Buscar páginas en los marcos. Durante determinados eventos, como por ejemplo , el tratamiento
de un fallo de página, el sistema de paginación puede solicitar al asignador a nivel de página que
busque en la lista de marcos de página libres si se encuentra cargada en un marco de dicha lista la
página cuya referencia originó el fallo de página. Puede suceder que dicha página se encuentre en
esta lista por haber sido seleccionada por el escáner de página para ser reemplazada. Si la página
se encuentra en la lista se elimina de la misma. Nótese que encontrar una página en esta lista evita
tener que leerla del disco, con lo cual se ahorra tiempo, ya que una operación de búsqueda sobre
la lista requiere de menos tiempo que una operación de lectura a disco.
El asignador a nivel de página se implementa como un conjunto de rutinas que pueden ser invocadas
por el sistema de paginación o el asignador de la memoria del núcleo. Dichas rutinas implementan toda
las operaciones que realiza el asignador.
e
Ejemplo 4.14
Entre las rutinas que implementan el asignador a nivel de página de Solaris se encuentran las siguientes:
•
page_c reat e_va . Esta función devuelve una lista enlazada con todos los marcos que han sido
extraídos de la lista de marcos de página libres de acuerdo con la cantidad de memoria solicitada.
•
page_f r e e . Esta función libera un marco de página y lo coloca en la lista de marcos de página
libres.
•
page_l ookup . Esta función busca la existencia de una determinada página, identificada por su
nodo-v y desplazamiento, en la lista de marcos de página libres.
•
4.5.
Gestión del área de intercambio en SOBUNIX
La implementación de la técnica de gestión de memoria mediante demanda de página requiere la
existencia de un espacio de almacenamiento en memoria secundaria en el que copiar aquellas páginas de
procesos activos cargadas en la memoria principal que son seleccionadas para ser reemplazadas. Obvia­
mente las páginas pertenecientes a procesos terminados no necesitan ser copiadas. A dicho espacio se le
174
Ampliación de sistemas operativos
denomina área de intercambio. En los SOBUNIX el área de intercambio está formada típicamente por
una o varias particiones de discos no formateadas a alto nivel y a las que se accede mediante operaciones
de E/S en bruto.
Las páginas pertenecientes a la mayoría de las regiones del espacio de direcciones virtuales de
un proceso (datos no inicializados, montículo, pila, archivos mapeados en memoria con el indicador
MAP_PRIVATE, etc) son copiadas en el área de intercambio si son seleccionadas para ser reemplazadas.
Las páginas de código de los procesos o de las librerías compartidas no son copiadas en el área de
intercambio. Estas páginas son generadas desde el archivo ejecutable correspondiente si es necesario
cargarlas de nuevo en la memoria principal debido a un fallo de página. Lo mismo ocurre con las páginas
seleccionadas para ser reemplazadas pertenecientes a archivos mapeados con el indicador MAP_SHARED.
En este caso, además, si las páginas han sido modificadas son salvadas en los bloques de disco del
archivo.
Cuando se crea una región del espacio de direcciones virtuales de un proceso que no sea de código
se reserva el espacio suficiente en el área de intercambio para poder almacenar todas sus páginas. Una
página i perteneciente a una determinada región de un proceso activo X se copia en el área de intercambio
la primera vez que ésta es seleccionada por el escáner de páginas para ser reemplazada. Si posteriormente
la ejecución del proceso X produce un fallo de página asociado a la página i el núcleo comprueba si
existe una copia de la página en el área de intercambio. En caso afirmativo la página es copiada en
memoria principal desde el área de intercambio. Más tarde si la página i vuelve a ser seleccionada
para ser reemplazada de la memoria principal solo se copiará de nuevo en el área de intercambio si
su contenido ha sido modificado (el bit m de su entrada de la tabla de páginas está activo), es decir, si la
copia de la página i en memoria principal difiere de la copia de la página i en el área de intercambio.
El núcleo mantiene una lista de espacio libre en el área de intercambio que consulta cuando necesita
asignar espacio del área de intercambio. También mantiene alguna clase de mapa de intercambio para
poder localizar rápidamente las páginas almacenadas en el área de intercambio. La implementación y
mantenimiento de estas estructuras depende de cada SOBUNIX.
e
Ejemplo 4.15
En los SOBUNIX que implementan la arquitectura VM de gestión de memoria, como Solaris, el área
de intercambio se utiliza para almacenar temporalmente las páginas anónimas pertenecientes a proce­
sos activos que son eliminadas de memoria principal. En consecuencia la implementación del área de
intercambio está estrechamente relacionada con la capa anónima.
Solaris implementa en la memoria principal un pseudosistema de archivos denominado swapfs que utiliza
para asignar espacio de intercambio virtual a las páginas anónimas. En un determinado instante de tiempo
el tamaño del espacio virtual definido en swapfs viene determinado por la suma del tamaño del espacio
libre existente en el área de intercambio y el tamaño del espacio libre existente en la zona paginada de
memoria principal.
S olaris también define un conj unto de funciones denominado capa swapfs que utiliza para operar sobre
el pseudosistema y sobre el área de intercambio. Las funciones de la capa swapfs son invocadas por
funciones de la capa anónima cuando se requiere asignar espacio de intercambio a una página anónima.
SOBUNIX: administración de memoria
175
Cada página anónima tiene asociado el nodo-v de un archivo de swapfs y un desplazamiento dentro de
dicho archivo medido en páginas. Nótese que el archivo no ocupa espacio físico sino virtual. Solo cuando
la página anónima es seleccionada para ser reemplazada es necesario asignarle espacio real dentro del
área de intercambio, el cual queda localizado mediante el nodo-v del archivo asociado al dispositivo
físico (ver sección 5 . 5 .2) donde se encuentra el espacio de intercambio real y un desplazamiento, medido
en páginas, dentro de dicho archivo. Si el espacio dentro del área de intercambio se agota, entonces se
utiliza como espacio de intercambio marcos libres de memoria principal, los cuales son marcados como
bloqueados.
La asignación de espacio virtual a través de swapfs permite no malgastar espacio de intercambio real. A
diferencia de lo que sucede en otros SOBUNIX, como SVR4, que utilizan una política más conservadora
consistente en reservar y asignar espacio de intercambio a todas las páginas de un segmento aunque
posiblemente algunas de ellas nunca vayan a utilizarlo.
Cuando se crea un segmento de memoria virtual que se mapea al objeto anónimo o a un archivo con un
mapeado del tipo MAP_PRIVA TE se crea un array de referencias a estructuras anon. En este array existe
una entrada por cada página virtual existente en el segmento. Cada entrada contiene un puntero a una
estructura anon, la cual contiene información sobre la localización de la página anónima en el espacio de
intercambio. En el caso de S olaris (ver Figura 4. 1 1 ) entre los campos presentes en una estructura anon
se encuentran los siguientes:
•
an_vp. Contiene un puntero al nodo-v de un archivo de swapjs.
•
an_o f f . Contiene el desplazamiento medido en páginas desde el comienzo del archivo ubicado
en swapfs.
•
an_pvp. Contiene el valor NULL si todavía no ha sido necesario asignar espacio de intercambio
real a la página anónima. En caso contrario contiene al nodo-v del archivo asociado al dispositivo
físico donde se encuentra el espacio de intercambio real.
•
an_po f f . Contiene el valor NULL si todavía no ha sido necesario asignar espacio de intercambio
real a la página anónima. En caso contrario contiene el desplazamiento medido en páginas desde el
comienzo del archivo asociado al dispositivo físico donde se encuentra el espacio de intercambio
real.
Luego el par de valores [an_vp, an_o f f ] permite localizar a una página anónima en swapfs, es decir, en
el espacio de intercambio virtual . Mientras que el par de valores [an_pvp, an_po f f] permite localizar
a una página anónima en el área de intercambio, es decir, en el espacio de intercambio real.
Cuando el driver de un segmento invoca a la función anon_a l l o c para obtener una página anónima
nueva, esta función invoca a su vez a la función swap f s_ge tvp para obtener un nodo-v de swapfs,
y posteriormente a la función swap f s_ge tpage para crear una nueva página virtual en el archivo de
swapfs. Esta función devuelve el desplazamiento dentro del archivo. Con esta información se inicializa
los campos an_vp y an_o f f de una estructura anon.
176
Ampliación de sistemas operativos
Nodo-v
an_vp
an o f f -----+--�
an__pvp =NULL
swapfs
an__p o f f =NULL
(a)
Nodo-v
swapfs
Nodo-v
Área
de
intercambio
(b)
Figura 4.11 - Asignación de espacio de intercambio virtual y real : (a) En el momento de la creación de
una página anónima. (b) Cuando la página es transferida por primera vez fuera de memoria principal.
Por otra parte los campos an__pvp y an__po f f de una estructura anon se inicializan con el valor NULL.
Cuando la página sea seleccionada por primera vez por el escáner de páginas para ser reemplazada
entonces se le asignará espacio en el área de intercambio y se configurarán adecuadamente los valores
de estos campos.
Para asignar espacio real de intercambio el escáner de páginas busca el nodo-v asignado a la página e
invoca a una operación putpage de dicho nodo-v. En el caso de una página anónima el nodo-v apunta a
un archivo de swapfs y en consecuencia se invoca a la función swap f s__pu tpage. Esta función asigna
un bloque del tamaño de una página en el área de intercambio y configura adecuadamente los valores
de los campos an__pvp y an__po f f de la estructura anon asociada a la página. Ahora sí la página tiene
asociado espacio de intercambio real y puede ser intercambiada fuera de memoria principal.
•
SOBUNIX: administración de memoria
4.6.
Gestión de la memoria perteneciente al núcleo en SOBUNIX
4.6.1.
Espacio de direcciones virtuales del núcleo
177
El núcleo al igual que los procesos de los usuarios dispone de un espacio de direcciones virtuales. La
localización de dicho espacio depende de cada SOBUNIX y de la arquitectura del computador donde se
ejecute. En algunas arquitecturas existe un único espacio de direcciones virtuales el cual es compartido
por el núcleo y los procesos de los usuarios. En dicho caso, generalmente, el espacio de direcciones
virtuales del núcleo ocupa las direcciones virtuales más altas.
En otras arquitecturas el núcleo y los procesos disponen de espacios de direcciones independientes.
En ese caso el núcleo y los procesos tiene a su disposición todo el rango de direcciones virtuales, desde
la dirección virtual O hasta una cierta dirección virtual máxima.
El espacio de direcciones del núcleo se descompone en diferentes regiones o segmentos: región de
código, región de datos, montículo, etc. Las regiones existentes en el espacio de direcciones virtuales del
núcleo y su organización dependen de cada SOBUNIX y de la arquitectura del computador.
El núcleo mantiene diferentes estructuras de datos para gestionar su propio espacio de direcciones
virtuales. Además tiene que mantener una tabla de páginas para que la MMU pueda traducir las direc­
ciones virtuales del núcleo en direcciones físicas.
e
Ejemplo 4.16
En la Figura 4. 1 2 se muestra la distribución del espacio de direcciones virtuales del núcleo de 32 bits
de Solaris en la arquitectura x64 de AMD. Se observan los siguientes segmentos en el espacio virtual
del núcleo : datos, código, estructuras de datos para la gestión de memoria, montículo y la caché de pá­
ginas de archivos ( s eg_map) . Esta caché contiene las páginas de archivos que han sido leídas o escritas
recientemente durante el tratamiento de las llamadas al sistema read o wr i te (ver sección 5 .2. 1 ) . Ini­
cialmente la dirección virtual base de la caché de archivos es OxC3 0 0 2 0 0 0 aunque puede extenderse
dentro del rango de direcciones virtuales denominado zona roja.
Como sucedía con el espacio de direcciones virtuales de los procesos el núcleo mantiene una estructura
as para mantener su propio espacio de direcciones. La dirección de la estructura as del núcleo se man­
tiene en la variable kas . Recuérdese que una estructura as contenía información sobre los segmentos de
un espacio de direcciones virtuales. En el caso del núcleo sus segmentos pueden ser, principalmente, de
tres tipos:
•
s eg_kmen. Las páginas de un segmento de este tipo se alojan en marcos bloqueados de memoria
principal. Los segmento de código, datos, pila y montículo del núcleo son segmentos de este tipo.
•
seg_map . Las páginas de un segmento de este tipo se alojan en marcos bloqueados de memoria
principal. Este tipo de segmento se utiliza para implementar la caché de páginas de archivos del
núcleo.
•
s eg_kp . Las páginas de un segmento de este tipo se alojan en marcos no bloqueados de memoria
principal. Las pilas de los procesos ligeros se alojan en segmentos de este tipo.
178
Ampliación de sistemas operativos
OxFFFFFFFF
1
1
- - - - - - - - - - - - - - - -
1
1
OxFF8 0 0 0 0 0
Datos del núcleo
OxFE C O O O O O
Código del núcleo
O x FE 8 0 0 0 0 0
va r i ab l e
Estructuras
de datos de gestión
de la memoria
Montículo
del núcleo
va r i a b l e
seg_map
OxC3 0 0 2 0 0 0
Zona roja
OxC3 0 0 0 0 0 0
Espacio de
direcciones
virtuales
de usuario
OxO O O O O O O O
-
Figura 4.12 Distribución del espacio de direcciones virtuales del núcleo de 32 bits de Solaris en la
arquitectura x64
•
4.6.2.
Asignación de la memoria del núcleo
Los subsistemas del núcleo necesitan memoria principal para alojar dinámicamente diferentes es­
tructuras de datos. Generalmente el tamaño de estas estructuras suele ser más pequeño que el tamaño de
una página y por ello asignarles páginas completas supone un desperdicio de memoria. Este es el motivo
por el que en los SOBUNIX existe un componente denominado asignador de la memoria del núcleo
que solicita marcos de página al asignador a nivel de página y los descompone en trozos más pequeños
que reparte entre los subsistemas del núcleo que solicitan memoria. Este asignador es el encargado de
atender las peticiones de memoria física realizadas por los subsistemas del núcleo para aloj ar diferentes
estructuras de datos.
El asignador de la memoria del núcleo puede implementarse de diferentes formas, las cuales pueden
ser comparadas atendiendo a criterios tales como la fragmentación de memoria que producen y la rapidez
SOBUNIX: administración de memoria
179
con que atienden las peticiones. Entre las implementaciones más usadas en los SOBUNIX se encuentran
el sistema buddy y el asignador slab. El sistema buddy se describe en la sección 6.5.2, en la siguiente
subsección se describe el asignador slab.
Asignador slab
El asignador slab 6 fue desarrollado por Jeff B onwick [Bonwick, 1 994] para implementar el asignador
de la memoria del núcleo de Solaris 2.4. Debido a su eficiencia y rapidez ha sido exportado a otros
SOBUNIX, como por ejemplo, Linux.
El asignador slab utiliza tres tipos de elementos :
•
Objeto. Hace referencia a u n determinado tipo d e estructura d e datos. Cada objeto queda identifi­
cado por el tamaño que ocupa y el nombre que se le asigna, que es una cadena de caracteres que
lo describe, por ejemplo: nodo-v, nodo-i, etc. Todos los objetos que se refieren a un mismo tipo
de estructura de datos tienen el mismo tamaño y el mismo nombre. Un objeto puede estar libre o
asignado
•
Slab. Es un conjunto de No objetos de un mismo tipo. Cada slab se construye con Np marcos de
página contiguos de memoria principal que son suministradas por el asignador a nivel de página.
•
Cache de objetos. Es un conjunto de Ns slabs de obj etos de un mismo tipo.
El asignador slab trabaj a con varias cachés de objetos. Si un subsistema del núcleo necesita crear
una caché para un determinado tipo de objetos entonces invoca a la función kmem_c ache_c r e a t e . Por
el contrario para eliminarla invoca a la función kmem_c ache_de s t roy. Si desea solicitar la asignación
de un objeto de una caché debe invocar a la función kmem_c ache_a l l o c . Cuando termine de usar el
objeto lo liberará invocando a la función kmem_c ache_f r e e .
Cuando todos los objetos d e una caché están asignados entonces e l asignador slab solicita al asigna­
dar a nivel de página un conjunto de marcos de página contiguos para crear un nuevo slab en la caché.
También es posible destruir un slab cuando todos sus objetos están libres y devolver al asignador a nivel
de páginas las páginas que ocupa dicho slab.
Dentro de una caché por cada slab existente se mantiene una estructura que contiene, entre otros, los
siguientes datos: el número de objetos asignados en el slab, una lista de objetos libres y punteros para
mantener una lista doblemente enlazada de slabs de la caché.
El asignador slab se basa en el hecho de que los subsistemas del núcleo trabaj an siempre con es­
tructuras de datos de unos determinados tamaños que son asignadas y liberadas dinámicamente. Por
ello resulta más eficiente y produce menos fragmentación mantener cachés con las estructuras que son
liberadas, para que puedan ser reutilizadas, que volver asignarles memoria para construirlas desde cero.
e
Ejemplo 4 . 17
En la Figura 4. 1 3 se muestra en un determinado instante de tiempo el estado del asignador slab, se
observa la existencia de dos cachés de objetos: una para objetos X1 de 2 KiB y otra para obj etos X2 de
6 Slab es una palabra inglesa que se puede traducir como lámina, pedazo,
bloque
o
tajada.
180
Ampliación de sistemas operativos
3 KiB . En la Figura 4. 14 se detalla el estado de la caché de objetos X 1 , se observa la existencia de dos
slabs. Cada slab consta de ocho obj etos y ocupa cinco marcos de página contiguos de 4 KiB . Nótese
que de los 20 KiB ocupados por un slab, 1 6 KiB son para almacenar los ocho objetos que contiene y los
restantes 4 KiB para almacenar la información de gestión del slab.
•
Asignador slab
..................................................
Caché de
objetos X l
de 2 KiB
Objetos X l
Subsistemas
del núcleo
Objetos X2 ¡
..
1
�! ; �� ,
Caché de
o eo 2
[_ - -
Páginas
Páginas
-
Figura 4.13 - Asignador slab
del Ejemplo 4.1 7
Marcos de página
de memoria principal
Caché de objetos X l de 2 KiB
Slab
. ..... ............. ...... ... . ..
-- . . ..
,....-
.
.
...=:::._
:
--,
_
.
. .
Objeto X l de 2 KiB
asignado a
un subsistema
del núcleo
··
·····
····
···
····
Asignado
LíQre
Libre
Asignado
Libre
Libre
Libre
Asigna o
".... ... . ..... .. .. ... ........ ...... ........ ......
. ..
. . .
.
.
.
................. ........................................ l======l
................. ..................
.----- ---... ..... ......... . ..... ...... . ......................,...-----,
Slab
..
.
····
····
······
····
I,.._____________J
Figura 4.14 -
Asignador
a nivel
se página
...
.
...................... 1....-..----'
..
................
............... ,____
..........
____
_J
Caché de objetos X 1 de 2 KiB de asignador slab del Ejemplo 4. 1 7
20 KiB
SOBUNIX: administración de memoria
4. 7.
181
Resumen
El subsistema de administración de memoria es el componente del núcleo de un sistema operativo
encargado de administrar, en colaboración con el hardware, la memoria principal entre los restantes
subsistemas del núcleo y entre todos los procesos de usuario que se ejecutan en el computador. Para
realizar esta tarea se pueden usar diferentes técnicas de administración de memoria. En los SOBUNIX se
utiliza la técnica de paginación por demanda la cual posibilita también la implementación de la memoria
virtual.
Un archivo mapeado en memoria es una región del espacio de direcciones virtuales de un proceso en
la que se establece una correspondencia byte a byte con parte o con la totalidad de un archivo. Una vez
mapeado en memoria, el acceso a un determinado byte del archivo puede ser realizado como a cualquier
otro contenido del espacio de direcciones virtuales, es decir, indicando su dirección virtual, lo que evita
tener que realizar llamadas al sistema, con lo que el acceso es mucho más rápido.
Una página anónima es una página que antes de su creación no dispone de un almacenamiento
persistente de respaldo en memoria secundaria. Las páginas anónimas son utilizadas por ejemplo, en
la región de datos no inicializados, el montículo y la región de pila. Al conjunto de páginas anónimas
utilizadas por un proceso se le denomina memoria anónima del proceso.
Con el objetivo de ahorrar espacio de memoria principal los SOBUNIX suelen trabaj ar con tablas
de páginas paginadas, el número de niveles de paginación utilizados es fijado por cada SOBUNIX en
función de la arquitectura.
En los SOBUNIX generalmente el conjunto de páginas candidatas a ser reemplazadas está formado
por todas las páginas cargadas en la memoria principal en marcos no bloqueados, es decir, utilizan lo que
en la literatura se conoce como estrategia o política de reemplazamiento global. Asimismo, el algoritmo
de reemplazamiento utilizado mayoritariamente en los SOBUNIX es alguna aproximación del algorit­
mo LRU. La implementación de un algoritmo LRU estricto produce bastante sobrecarga por lo que se
suele usar algún algoritmo cuyo funcionamiento se aproxime al del algoritmo LRU pero que produzca
menos sobrecarga. Un ejemplo de un algoritmo con estas características es el algoritmo del reloj de dos
manecillas.
El área de intercambio en los SOBUNIX está formada típicamente por una o varias particiones de
discos no formateadas a alto nivel y a las que se accede mediante operaciones de E/S en bruto. Las
páginas pertenecientes a la mayoría de las regiones del espacio de direcciones virtuales de un proceso
son copiadas en el área de intercambio si son seleccionadas para ser reemplazadas.
En los SOBUNIX la asignación de marcos de página de memoria principal la realiza un componente
del subsistema de gestión de memoria principal denominado asignador a nivel de página. Este asignador
atiende las peticiones de memoria del sistema de paginación y del asignador de la memoria del núcleo.
El asignador de la memoria del núcleo puede implementarse de diferentes formas, las cuales pueden
ser comparadas atendiendo a criterios tales como la fragmentación de memoria que producen y la rapidez
con que atienden las peticiones. Entre las implementaciones más usadas en los SOBUNIX se encuentran
el sistema buddy y el asignador slab.
182
4.8.
Ampliación de sistemas operativos
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pueden
consultar, por ejemplo: los capítulos 1 2 a 1 5 de [Vahalia, 1 995] , los capítulos 8 a 1 3 de [McDougall y
Mauro, 2006] y el capítulo 1 O de [Tanenbaum, 2009] .
4.9.
Autoevaluación
4 . 1 . ¿Qué técnica de administración de memoria se utiliza generalmente en los SOBUNIX?
(Respuesta en sección 4. 1 )
4 . 2. Enumerar y describir las regiones o segmentos e n que s e puede descomponer el espacio d e direc­
ciones virtuales de un proceso. (Respuesta en sección 4.2. 1 )
4 .3 . ¿Qué comando s e puede utilizar en los SOBUNIX para obtener información sobre e l espacio de
direcciones virtuales de un proceso? (Respuesta en sección 4.2. 1 )
4 . 4 . Explicar cómo s e inicializa u n marco de página de la memoria principal en función del tipo de
región a la que pertenece la página del espacio de direcciones virtuales de un proceso que se va
alojar en dicho marco. (Respuesta en sección 4.2. 1 )
4 .5 . ¿Qué e s u n archivo mapeado e n memoria? ¿Qué ventajas e inconvenientes presenta s u uso?
(Respuesta en sección 4.2.2)
4 . 6 . Explicar la utilidad y la sintaxis de las llamadas al sistema rrunap y munmap.
(Respuesta en sección 4.2.2)
4 .7 . Explicar cómo se implementa de forma general en los SOBUNIX el espacio de direcciones virtua­
les de un proceso. (Respuesta en sección 4.2.3)
4 . 8 . ¿Qué se entiende por objeto de datos en Solaris? ¿Qué es el objeto anónimo?
(Respuesta en sección 4.2.3)
4 . 9 . Enumerar y describir brevemente los tipos de segmentos más frecuentemente utilizados en Solaris.
(Respuesta en sección 4.2.3)
4 . 10. Dibuj ar un diagrama que ilustre la relación entre las estructuras de datos usadas en Solaris para
describir el espacio de direcciones virtuales de un proceso. Comentar brevemente la información
que contiene cada estructura. (Respuesta en sección 4.2.3)
4 . 1 1 . ¿Qué es una página anónima? ¿Cuándo se crea? ¿Qué se entiende por memoria anónima de un
proceso? (Respuesta en sección 4.2.4)
SOBUNIX: administración de memoria
183
4.12. Dibujar un diagrama que ilustre la relación entre las estructuras de datos usadas en Solaris para
describir las páginas anónimas de un segmento de tipo seg_vn. Comentar brevemente la informa­
ción que contiene cada estructura. (Respuesta en sección 4.2.4)
4.13. ¿Qué es la capa anónima de Solaris? ¿Qué funciones desempeña? (Respuesta en sección 4.2.4)
4.14. Dibujar un diagrama que ilustre la relación entre las estructuras de datos usadas en Solaris para
implementar un recurso IPC del tipo memoria compartida. Suponer que la memoria compartida es
un segmento de tipo seg_vn. Comentar brevemente la información que contiene cada estructura.
(Respuesta en sección 4.2.5)
4.15. ¿Qué operaciones se puede realizar sobre el espacio de direcciones virtuales de un proceso?
(Respuesta en sección 4.2.6)
4.16. ¿Cómo se realiza de forma general en los SOBUNIX la creación del espacio de direcciones vir­
tuales de un proceso? (Respuesta en sección 4.2.7)
4.17. Explicar razonadamente como colaboran el hardware (MMU) y el núcleo en la traducción de
direcciones virtuales a direcciones físicas en la técnica de paginación por demanda.
(Respuesta en sección 4.3.1)
4.18. ¿De qué depende el número de niveles de paginación utilizado en los SOBUNIX?
(Respuesta en sección 4.3.1)
4.19. Explicar qué es, para qué sirve y cómo se implementa la capa HAT utilizada en los SOBUNIX que
implementan la arquitectura VM de gestión de memoria. (Respuesta en sección 4.3.1)
4.20. Explicar razonadamente cómo se realiza de forma general el tratamiento de los fallos de página en
los SOBUNIX. (Respuesta en sección 4.3.2)
4.21. Describir cómo se distribuye generalmente la memoria principal en los SOBUNIX.
(Respuesta en sección 4.4.1)
4.22. ¿Qué información debe mantener el núcleo para gestionar la memoria principal?
(Respuesta en sección 4.4.1)
4.23. ¿Para qué utiliza Solaris una estructura page? ¿Qué información contiene?
(Respuesta en sección 4.4.1)
4.24. Enumerar las listas en que organiza Solaris las estructuras page. Comentar la utilidad de dichas
listas. (Respuesta en sección 4.4.1)
4.25. ¿Qué tipo de estrategia o política de reemplazamiento de páginas utilizan los SOBUNIX? ¿Cuál
es el algoritmo de reemplazamiento utilizado mayoritariamente por los SOBUNIX?
(Respuesta en sección 4.4.2)
184
Ampliación de sistemas operativos
4 . 26 . Describir el funcionamiento del algoritmo de reemplazamiento de páginas del reloj con dos mane­
cillas utilizado en diversos SOBUNIX. (Respuesta en sección 4.4.2)
4 . 27 . ¿Qué es y para qué se utiliza el escáner de páginas? ¿Cuándo se invoca? (Respuesta en sección 4.4.2)
4 . 28 . ¿Por qué el núcleo cuando se produce un fallo de página comprueba si la página que ha originado
el fallo se encuentra en la lista de marcos de página libres? (Respuesta en sección 4.4.2)
4 . 29 . ¿Qué es y para qué se utiliza el proceso intercambiador? ¿ Cuándo se invoca?
(Respuesta en sección 4.4.3)
4 .30 . ¿Qué es y a quién atiende el asignador a nivel de páginas? ¿ Qué operaciones realiza sobre la lista
de marcos de página libres? (Respuesta en sección 4.4.4)
4 .31 . ¿Cómo se forma el área de intercambio en los SOBUNIX? ¿Para qué se utiliza en los SOBUNIX
modernos? (Respuesta en sección 4.5)
4 .32 . Describir la gestión del área de intercambio en los SOBUNIX. (Respuesta en sección 4.5)
4 .33 . ¿Para que se utiliza el pseudosistema de archivos swapfs en Solaris? (Respuesta en sección 4.5)
4 .34 . ¿Qué es y para qué se utiliza la capa swapfs de Solaris? (Respuesta en sección 4.5)
4 .35 . ¿Qué parte del espacio de direcciones virtuales se reserva para el núcleo en los SOBUNIX si éste
comparte el espacio con los procesos de usuario? ¿Qué regiones o segmentos se suelen distinguir
en el espacio de direcciones virtuales del núcleo? (Respuesta en sección 4.6.1)
4 .36 . ¿Qué tareas realiza el asignador de la memoria del núcleo de los SOBUNIX? ¿Cómo se imple­
menta? (Respuesta en sección 4.6.2)
4 .37 . Explicar razonadamente la implementación y el funcionamiento del asignador slab en Solaris.
(Respuesta en sección 4.6.2)
4.10.
Ejercicios
4 . 1 . Modificar el programa prog4 1 de la Figura 4.2 para que el mapeado del archivo t ex t o l . txt sea
de tipo privado. Explicar razonadamente los efectos de esta modificación.
4 . 2 . Considérese el programa prog4 2 cuyo código C se muestra en la Figura 4. 1 5 . Invocarlo en segun­
do plano desde la línea de órdenes del intérprete de comandos de un SOBUNIX:
a) Cuando aparezca el primer mensaje en la pantalla escribir la orden prnap [ P I D ] donde
[ P I D ] hace referencia al PID del proceso asociado al programa. Explicar la información que
se muestra en la pantalla.
,
b) Repetir el apartado anterior pero ahora cuando aparezca el segundo mensaje en pantalla.
SOBUNIX: administración de memoria
185
# i nc lude < s t d i o . h>
ma i n ( )
{
int x= O ;
char * b ;
x=g e tp i d ( ) ;
pr i n t f ( " \ nPID= %d due rme 2 0 s \ n " ,
x) ;
s l e ep ( 2 0 ) ;
pr i n t f ( " \ n P ID= %d vu e lve a dorm i r o t r o s 2 0 s \ n " ,
b= ( char * )
x) ;
rna l l o c ( 1 4 * s i z e o f ( char ) ) ;
s l e ep ( 2 0 ) ;
pr i n t f ( " \ n P ID= %d F i na l i z a \ n " ,
x) ;
Figura 4.15 -
Código C del programa prog 4 2
4 .3 . Ejecutar en u n intérprete d e comandos d e u n S OBUNIX l a orden vms tat 5 2 . Consultar el ma­
nual de ayuda man para explicar la funcionalidad de este comando y el significado de la salida que
muestra en la pantalla.
Capítulo 5
SOBUNIX: gestión de archivos y gestión
de la E/S
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes:
•
Conocer las características principales de la gestión de archivos en los SOBUNIX, así como las
principales llamadas al sistema disponibles para la realización de esta tarea.
•
Saber qué es, para qué se utiliza y cómo se implementa la capa nodo virtual/ sistema de archivos
virtual existente en los SOBUNIX modernos.
•
Conocer cómo se realiza el análisis de nombres de rutas en los SOBUNIX.
•
Conocer las características principales, la estructura en disco y cómo se gestiona un sistema de
archivos UFS .
•
Saber cómo se realiza la gestión de la E/S en los SOBUNIX.
•
Saber qué son y cómo se utilizan los conectores (sockets) en los SOBUNIX.
5.1.
Introducción
Este capítulo está dedicado al estudio de la gestión de archivos y la gestión de la E/S en los SO­
BUNIX. En primer lugar se explican las características principales de los archivos, los directorios, los
enlaces y los sistemas de archivos en los SOBUNIX. Asimismo se enumeran y describen las principales
llamadas al sistema disponibles en los SOBUNIX para la gestión de estos elementos . En segundo lugar
se describe la capa nodo virtual/sistema de archivos virtual utilizada en la mayoría de los SOBUNIX
modernos para poder soportar diferentes tipos de sistemas de archivos. En tercer lugar se explica cómo
1 87
188
Ampliación de sistemas operativos
se analizan los nombres de rutas en los SOBUNIX. En cuarto lugar se describe el sistema de archivos
UFS , el cual es utilizado en diversos SOBUNIX. En cuarto lugar se describe la gestión de la E/S en
los SOBUNIX. El capítulo finaliza con una introducción a los conectores que son uno de los principales
mecanismos utilizados en los SOBUNIX para implementar las conexiones en red.
5.2.
Gestión de archivos en SOBUNIX: características principales y
llamadas al sistema
5.2.1.
Archivos
En los SOBUNIX la información contenida en un archivo se estructura como una secuencia lineal de
bytes. El núcleo no interpreta dicha información, simplemente se limita a operar (leer o escribir) con ella
a nivel de byte. Son los procesos los encargados de interpretar la información contenida en los archivos .
E l acceso a l contenido d e u n archivo s e realiza por defecto d e forma secuencial. Aunque también e s
posible realizar u n acceso directo o aleatorio a u n determinado byte d e u n archivo.
El nombre de un archivo es una cadena de caracteres ASCII. Se pueden usar todos los caracteres
excepto los caracteres 1 y \ o La longitud máxima de un nombre depende del tipo de sistema de
archivos al que pertenezca el archivo. Como se verá en la sección 5 . 2.4 los SOBUNIX soportan el uso
de diferentes tipos de sistemas de archivos.
A diferencia de otros sistemas operativos, en los SOBUNIX el nombre de un archivo no tiene por qué
tener una extensión ya que el núcleo no la interpreta. De nuevo, el uso de extensiones y su interpretación
recae en los procesos. En este sentido, conviene señalar que en los SOBUNIX un nombre puede tener
más de una extensión. Teniendo en cuenta lo anterior los nombres prueba, prueba . e y prueba . e . g z
serían nombres d e archivos válidos e n SOBUNIX.
1
1
1
1
•
Tipos de archivos
En los SOBUNIX, de forma general, se distinguen los siguientes tipos de archivos:
•
Archivos regulares. También denominados archivos ordinarios. Dentro de esta categoría de archi­
vos se encuentran los archivos binarios y los archivos ASCII. Un archivo binario es aquél que
contiene información de un determinado tipo (código compilado, texto formateado, imágenes, vi­
deo, etc) con una estructura determinada que únicamente puede ser interpretada por los programas
que los utilizan. Un archivo ASCII está compuesto de líneas de caracteres ASCII codificadas en
binario que no requieren un programa que los interprete.
•
Directorios. Son archivos cuyos bloques de datos almacenan una lista con los archivos y subdi­
rectorios aloj ados en el directorio. Cada entrada de una lista de un directorio contiene el nombre
de un archivo (o subdirectorio) alojado en el directorio y el número del nodo-i asociado a dicho
archivo (o subdirectorio).
SOBUNIX: gestión de archivos y gestión de la E/ S
•
189
Archivos especiales. Son archivos que representan a dispositivos (ver sección 5 . 5 .2). Existen dos
tipos de archivos especiales:
- Archivos de dispositivos modo carácter. Se utilizan para modelar dispositivos de E/S de tipo
serie como el teclado, el ratón, la impresora y el módem.
- Archivos de dispositivos modo bloque. Se utilizan para modelar la E/ S en bruto a particiones
de discos duros.
•
Tuberías. Una tubería (ver sección 3.5 .2) es un canal de comunicación unidireccional por el que
se pueden transmitir flujos de datos no estructurados con un tamaño máximo fijo.
•
Conectores (sockets). Son uno de los principales mecanismos usados en los S OBUNIX para im­
plementar las conexiones en red (ver sección 5 .6).
•
Enlaces simbólicos. Un enlace simbólico es un archivo que contiene el nombre de ruta absoluta o
relativa de otro archivo.
Atributos de un archivo
Además del nombre de un archivo, el núcleo tiene que mantener otras informaciones relativas a un
archivo. A los elementos componentes de dicha información se les denomina atributos del archivo. Los
atributos de un archivo se almacenan en el nodo-i asociado a dicho archivo.
Entre los atributos frecuentemente mantenidos en los S OBUNIX se encuentran los siguientes: identi­
ficador del dispositivo donde reside el archivo, número del nodo-i asociado al archivo, máscara de modo
del archivo, número de enlaces duros, UID, GID, número de dispositivo mayor y número de dispositivo
menor (está información se almacena si se trata de un archivo de dispositivo (ver sección 5 . 5 .2)), tamaño
en bytes, fecha del último acceso (lectura) al archivo, fecha de la última modificación (escritura) del
archivo, y fecha de la última modificación de los atributos del archivo. Señalar que esta última fecha no
tiene en cuenta las modificaciones en las fechas del último acceso o modificación del archivo.
Los atrib �tos de un archivo se pueden obtener mediante la llamada al sistema s ta t 1. También el
comando l s l in permite visualizar varios atributos de un archivo.
-
e
Ejemplo 5 . 1
Supóngase que en el directorio de trabajo actual existe un archivo llamado text o l . txt. Si se ejecuta la
orden
l s - l in t ext o l . tx t
entonces en la pantalla aparecerá una línea con algunos de los atributos del archivo t ex t o l . txt. Su­
póngase que la línea que aparece en la pantalla es la siguiente:
1En algunos SOBUNIX, como por ejemplo Linux, también existe un comando s t a t el cual internamente invoca a la
llamada al sistema s t a t .
190
Ampliación de sistemas operativos
1024
-
rw r
-
--
r
--
1 1 0 1 1 0 4 7 2 0 1 2 - 0 3 - 1 6 1 0 : 0 2 text o 1 . txt
El significado de los componentes de esta línea es el siguiente: 1 0 2 4 es el número de nodo-i asociado al
archivo, - r w- r --r --es la máscara de modo del archivo, 1 es el número de enlaces duros, 1 0 1 es el
UID, 1 o es el GID, 4 7 es el tamaño del archivo en bytes, y 2 o 1 2 - o 3 -1 6 1 o : o 2 es la fecha de la última
modificación del archivo.
•
Descriptores de archivos
Para que un proceso pueda poder operar sobre un archivo, éste primero tiene que ser abierto mediante
la invocación de la llamada al sistema open. La rutina del núcleo del sistema operativo que trata esta
llamada al sistema crea en la memoria principal una estructura de datos denominada objeto de archivo
abierto y asigna a dicha estructura un número entero positivo pequeño denominado descriptor de archivo
para identificarla. Nótese que si un proceso abre el mismo archivo dos veces, o si dos procesos abren el
mismo archivo, el núcleo creará una estructura de objeto abierto y un descriptor de archivo en cada
invocación de la llamada al sistema open. Luego se tendrían dos obj etos de archivo abierto, cada una
con su correspondiente descriptor de archivo.
La llamada al sistema open devuelve el descriptor del archivo abierto al proceso que invocó la
llamada. Para poder operar sobre un archivo abierto el proceso debe pasar el descriptor del archivo como
argumento de las llamadas al sistema asociadas a las operaciones que desee realizar sobre el archivo.
Todos los descriptores de archivos asociados a un proceso se indexan en una tabla denomina tabla
de descriptores de archivos. Esta tabla es local a cada proceso, es decir, cada proceso tiene su propia
tabla de descriptores de archivos. Luego un mismo descriptor de archivo puede referirse en dos procesos
distintos a archivos diferentes.
Cada entrada de una tabla de descriptores de archivos contiene un puntero a la estructura de objeto
de archivo abierto a la que está asociado el descriptor, y una serie de indicadores que especifican el
tratamiento que debe dar al descriptor ante la aparición de determinados eventos. Por construcción las tres
primeras entradas (entradas O a 2) de la tabla de descriptores de archivos de un proceso están asociadas a
los siguientes archivos: archivo estándar de entrada (descriptor 0), archivo estándar de salida (descriptor
1 ) y archivo estándar de salida de errores (descriptor 2) . Por defecto el archivo estándar de entrada está
asociado al teclado y el archivo estándar de salida está asociado a la pantalla.
Por su parte, un objeto de archivo abierto contiene la información necesaria para poder operar sobre
un archivo:
•
Puntero de lectura/ escritura. Indica el byte del archivo donde se realizará la próxima operación
de lectura o de escritura. Se especifica como un desplazamiento desde el origen del archivo. Re­
cuérdese que en SOBUNIX el acceso al contenido de un archivo se realiza por defecto de forma
secuencial.
•
Contador de referencias. Especifica el número de descriptores de archivos que hacen referencia al
objeto de archivo abierto. Normalmente el contador vale 1 , pero puede tomar valores superiores si
SOBUNIX: gestión de archivos y gestión de la E/ S
191
se duplica el descriptor usando las llamadas al sistema dup o dup2 . También cuando un proceso
padre crea un proceso hijo se duplican los descriptores de archivos del proceso padre para asignár­
selos al proceso hijo. De esta forma, el proceso hij o puede acceder a los archivos abiertos por el
proceso padre.
•
Modo de apertura del archivo. Establece las operaciones que se pueden realizar sobre el archivo
abierto. Por ejemplo, solo lectura, solo escritura, lectura y escritura, etc. El modo de apertura se
especifica como un argumento de la llamada al sistema open, bien en la forma de un número octal
similar en estructura a la máscara de modo de un archivo o en la forma de una constante simbólica.
Cada vez que se va a realizar una operación sobre el archivo abierto el núcleo comprueba el modo
de apertura del archivo para permitir o denegar la realización de la operación.
•
Puntero al nodo virtual del archivo. Un nodo virtual, o más abreviadamente nodo-v, es una es­
tructura de datos que el núcleo crea en memoria principal para cada archivo activo. La utilidad y
contenido de esta estructura de datos se describirá en la sección 5 . 3 . 1 .
La implementación de las tablas de descriptores de archivos y de los objetos de archivos abiertos
depende de cada SOBUNIX.
e
Ejemplo 5 . 2
En Solaris la tabla de descriptores de archivos asociada a un proceso se implementa mediante un array
f i_l i s t que está indexado por el número de descriptor de archivo. Cada elemento del array está for­
mado por una estructura u f_entry que contiene, entre otras informaciones, un puntero a un objeto de
.
archivo abierto, el cual se implementa mediante una estructura f i l e .
Una estructura f i l e contiene los siguientes campos :
•
f_vnode . Puntero a l nodo-v asociado a l archivo abierto.
•
f_o f f s e t . Puntero de lectura/escritura.
•
f_c red. Modo de apertura del archivo.
•
f_c oun t . Contador de referencias. Especifica el número de descriptores de archivos que referen­
cian al objeto de archivo abierto.
En la Figura 5 . 1 se muestra la relación entre estas estructuras para el caso de dos procesos A y B que han
abierto el mismo archivo. Cada proceso tiene su propia tabla de descriptores de archivos. El proceso A
referencia al archivo mediante un descriptor de archivo igual a 3 mientras que el proceso B lo referen­
cia mediante un descriptor de archivo igual a 4. Cada descriptor apunta a un obj eto de archivo abierto
distinto. Como los dos procesos han abierto el mismo archivo ambos objetos abiertos apuntan al mismo
nodo-v.
•
192
Ampliación de sistemas operativos
fi l i st
O
u f_ent ry
u f_entry
2
u f_entry
3
u f_ent ry
s t ru c t f i l e
f vnode
f off set
1
1
1
f cred
f c ount
!
11
1
1
1
1
•-------------------·
Objeto de archivo abierto
Tabla de descriptores
de archivos de un proceso A
nodo-v
f i l i st
O
uf_ent ry
uf_ent ry
2
u f_entry
3
u f_entry
4
u f_ent ry
f count
Objeto de archivo abierto
1
1
1
1
1
1
1
•-------------------'
Tabla de descriptores
de archivos de un proceso B
-
Relación existente entre las estructuras de datos asociadas a un archivo abierto por dos
procesos A y B en Solaris
Figura 5.1
Llamadas al sistema
Un proceso para operar sobre un archivo debe invocar a la llamada al sistema apropiada. De forma
general los SOBUNIX proporcionan a los procesos de los usuarios las siguientes llamadas al sistema
para poder operar sobre los archivos:
•
fd=creat ( ruta , modo ) . Esta llamada al sistema permite crear y abrir un archivo con el nombre
de ruta especificado en ruta con la máscara de modo octal 0302010o especificada en modo . Si
la llamada se ejecuta con éxito entonces en f d se guarda el descriptor del archivo. En caso de
error en fd se guarda el valor -l. Si el archivo que se deseaba crear ya existía entonces se borra su
contenido y su longitud se trunca a cero bytes.
SOBUNIX: gestión de archivos y gestión de la E/ S
•
193
fd=open ( ruta , modo_a ) . Esta llamada al sistema permite abrir el archivo localizado en ruta
con el modo de apertura especificado en modo_a . El modo de apertura se especifica en la forma de
un número octal similar en estructura a la máscara de modo de un archivo o en la forma de alguna
de las constantes simbólicas definidas en el archivo de cabecera f cnt l . h. Por ejemplo, las cons­
tantes O_RDONLY y O_WRONLY indican que el archivo se debe abrir con permisos de solo lectura
o de solo escritura, respectivamente. Mientras que la constante O_RDWR indica que el archivo se
debe abrir con permisos de lectura y escritura.
Si la llamada al sistema se ejecuta con éxito entonces en fd se guarda el descriptor del archivo. En
caso de error en fd se guarda el valor l
-
.
•
r = c l o s e ( f d ) . Esta llamada al sistema cierra el archivo con descriptor de archivo fd. Si la lla­
mada se ejecuta con éxito en r se guarda el valor O. En caso de error en r se guarda el valor
-l.
•
r = read ( fd , bu f f e r , N ) . Esta llamada permite leer N bytes del archivo con descriptor f d y escri­
birlos en memoria a partir de la posición apuntada por bu f f er. La operación de lectura comienza
desde la posición indicada en el puntero de lectura/escritura almacenado en el objeto de archivo
abierto al que apunta el descriptor de archivo fd. Si la llamada se ejecuta con éxito entonces en
r se guarda el número de bytes que se han podido leer. Luego r puede ser menor o igual a N. En
caso de error en r se guarda el valor 1
-
.
•
r=wr i t e ( f d , bu f f e r , N ) . Esta llamada permite leer N bytes desde la posición de memoria apun­
tada por bu f f er y escribirlos en el archivo con descriptor fd. La operación de escritura comienza
desde la posición indicada en el puntero de lectura/escritura almacenado en el objeto de archivo
abierto al que apunta el descriptor de archivo fd. Si la llamada se ejecuta con éxito entonces en r
se guarda el número de bytes que se han podido escribir. Luego r puede ser menor o igual a N. En
caso de error en r se guarda el valor - 1 .
•
r = l s eek ( f d , o f f s e t , o r igen ) . Esta llamada al sistema permite desplazar o f f s e t bytes desde
o r i gen el puntero de lectura/escritura del archivo con descriptor fd. El argumento o r i gen puede
tomar los siguientes valores: O o SEEK_SET que indica que el desplazamiento se realizará desde el
inicio del archivo, 1 o SEEK_CUR que indica que el desplazamiento se realizará desde la posición
actual del puntero, y 2 o SEEK_END que indica que el desplazamiento se realizará desde el final
del archivo. Por su parte, el argumento o f f s e t puede ser un número entero positivo o negativo.
Si es positivo entonces el puntero avanzará, mientras que si es negativo el puntero retrocederá. Si
la llamada al sistema se ejecuta con éxito entonces en r se guarda la nueva posición, medida en
bytes, que toma el puntero de lectura/escritura con respecto al inicio del archivo. En caso de error
en r se guarda el valor - l .
•
r = s tat ( ruta , &bu f f er ) . Esta llamada al sistema copia en la estructura bu f f e r de tipo predefi­
nido s ta t los atributos del archivo localizado en rut a . Si la llamada se ejecuta con éxito entonces
en r se guarda el valor O, en caso contrario se guarda el valor - l .
194
Ampliación de sistemas operativos
•
r = f s tat ( fdl &bu f f e r ) . Esta llamada al sistema presenta la misma funcionalidad que la llamada
s t a t . Se diferencia de dicha llamada en que recibe como argumento de entrada el descriptor del
archivo fd en lugar del nombre de ruta.
•
r = f cnt l ( fdl op 1arg ) . Esta llamada al sistema permite realizar diferentes operaciones de con­
trol sobre un archivo abierto con descriptor fd. Las operaciones op disponibles se encuentran
definidas en el archivo de cabecera f en t 1 h. Entre dichas operaciones una de las más útiles es la
.
posibilidad de bloquear o desbloquear el acceso a otros procesos a parte o la totalidad del conte­
nido de un archivo. De esta forma un proceso puede garantizarse el acceso con exclusión mutua a
un archivo usado por múltiples procesos concurrentes sin necesidad de utilizar mecanismos IPC.
Esta operación también se puede realizar utilizando la función de librería l o c k f .
Los argumentos necesarios para cada operación s e especifican e n arg. Si l a llamada s e ejecuta con
éxito en r se almacena un valor que depende de cada operación. En caso de error se almacena el
valor -l.
e
Ejemplo 5 .3
Supóngase que en el directorio de trabajo actual no existe ningún archivo. Si un proceso A invoca a la
llamada al sistema
r = c reat ( " da t o s " 10 6 6 6 ) ;
entonces se creará y se abrirá el archivo da t o s con la máscara de modo octal 0 6 6 6 , es decir, todos los
usuarios pueden leer y escribir en el archivo. El descriptor del archivo se almacenará en r .
Si a continuación e l proceso A invoca a la llamada a l sistema
wr i t e ( r1o r i gen15 0 ) ;
entonces se leerían los 50 primeros bytes desde la posición de memoria apuntada por o r i gen y se
escribirían en el archivo con descriptor r .
Supuesto que el proceso A ha terminado de usar el archivo entonces debería invocar una llamada al
sistema
close ( r ) ;
para cerrarlo.
S i posteriormente otro proceso B invoca a la llamada al sistema
f = open ( " da t o s " 1O_RDONLY ) ;
entonces el archivo da t o s se abrirá con permiso de solo lectura y el descriptor del archivo se almacenará
en f. Señalar que la constante O_RDONLY podría haberse sustituido por el número octal 0 4 0 0 .
S i el proceso B invoca a la llamada al sistema
SOBUNIX: gestión de archivos
y
gestión de la E/ S
195
l s e ek ( f , 2 5 , 0 ) ;
entonces el puntero de lectura/escritura se desplazará 25 bytes comenzando desde el origen del archivo.
Es decir, supuesto que los bytes comienzan a numerarse desde O, el puntero pasa a apuntar al byte no 25
del archivo.
Si a continuación el proceso B invoca a la llamada al sistema
read ( f , de s t i no , l O ) ;
entonces se leerían 1 O bytes en el archivo con descriptor f comenzando desde el byte no 25 y se escribirían
en memoria a partir de la posición de memoria apuntada por de s t ino.
Supuesto que el proceso B ha terminado de usar el archivo entonces debería invocar una llamada al
sistema
c lose ( f ) ;
para cerrarlo.
•
5.2.2.
Directorios
El núcleo, las aplicaciones y los usuarios organizan sus archivos en directorios. En los SOBUNIX un
directorio es un archivo en cuyos bloques de datos se almacena una lista con los archivos y directorios
contenidos en el directorio.
En los sistemas de archivos desarrollados para SOBUNIX una entrada de una lista de un directorio
contiene, entre otras informaciones, el número del nodo-i asociado a un archivo y su nombre. Además
existen dos entradas especiales : la entrada punto
que se refiere al propio directorio y la entrada punto­
punto " . . " que se refiere al directorio padre.
Los SOBUNIX implementan una estructura de directorios de gráfica acíclica. El directorio raíz es el
directorio / ' . Este carácter también se utiliza para separar cada componente del nombre de ruta absoluta
o relativa de un archivo.
1 • 1
1
Número de nodo-i
1 20
52
256
350
Tabla 5.1 - Lista
Nombre del archivo
o
o
proye c to
l i s tar
de archivos almacenada en el directorio al ex de la Figura 5 .2
196
Ampliación de sistemas operativos
Directorio 1
bin
boot
Directorio
dev
home
home
Directorio
Directorio
sara
Figura
e
5.2- Estructura de directorios del SOBUNIX del Ejemplo 5.2
Ejemplo 5.4
En la Figura 5.2 se muestra a modo de ejemplo un diagrama con la estructura de directorios de un
cierto SOBUNIX. Asimismo en la Tabla 5 . 1 se muestra la lista de archivos aloj ada en el directorio
/ home / al ex. La primera entrada corresponde a la entrada punto
que hace referencia al propio direc­
torio. Su número de nodo-i es 1 20.
1 • 1
La segunda entrada corresponde a la entrada punto-punto " . . " que hace referencia al directorio padre
del directorio / home / al ex, en este caso el directorio / home . Su número de nodo-i es 52.
La tercera entrada corresponde al archivo proyect o cuyo número de nodo-i es 256. Este archivo de
acuerdo con la Figura 5.2 es un directorio, pero realmente esto no se puede saber hasta que no se consulte
el tipo de archivo en el nodo-i número 256.
Finalmente la cuarta entrada corresponde al archivo l i s t ar cuyo número de nodo-i es 350.
•
En los SOBUNIX existen varias llamadas al sistema que permiten operar a nivel de directorios, como
por ejemplo:
•
r = chdi r ( ruta) . Esta llamada al sistema cambia el directorio de trabajo. El nuevo directorio de
trabaj o es el especificado en rut a. Si la llamada al sistema se ejecuta con éxito en r se almacena
el valor O, en caso de error se almacena el valor - 1 . Señalar que el comando cd que se utiliza para
cambiar de directorio de trabaj o invoca internamente a esta llamada al sistema.
SOBUNIX: gestión de archivos y gestión de la E/S
•
197
r=mkd i r ( ruta , modo ) . Esta llamada al sistema permite crear un directorio en el nombre de
ruta especificado en ruta con la máscara de modo octal Ü3ÜzÜ¡Üo especificada en modo. Si la
llamada se ejecuta con éxito entonces en r se guarda el valor O, en caso de error se almacena el
valor - 1 . Señalar que el comando mkd i r que permite crear un directorio invoca internamente a
esta llamada al sistema.
•
r = rmdi r ( ruta ) . Esta llamada al sistema permite eliminar el directorio localizado en ruta. Para
que pueda ser eliminado el directorio debe estar vacío. Si la llamada se ejecuta con éxito entonces
en r se guarda el valor O, en caso de error se almacena el valor -l. Señalar que el comando rmdir
que permite borrar un directorio invoca internamente a esta llamada al sistema.
5.2.3.
Enlaces
Una de las características principales de una estructura de directorios de gráfica acíclica es la posi­
bilidad de compartir archivos o directorios entre varios usuarios mediante el uso de enlaces. Un enlace
permite conectar un directorio origen con un elemento (archivo o subdirectorio) ya existente en otro
directorio destino. Se distinguen dos posibles tipos de enlaces: enlaces duros y enlaces simbólicos.
Un enlace duro es una entrada de un directorio. En los SOBUNIX un archivo puede ser referenciado
por múltiples entradas de directorios. En el nodo-i asociado al archivo, entre otras informaciones, existe
un contador de enlaces duros. Cada vez que se crea una entrada de un directorio que referencia al archivo,
es decir, un enlace duro, el contador se incrementa en una unidad.
Cuando se crea un directorio el contador de enlaces duros de su nodo-i toma el valor 2. Un enlace
corresponde a la entrada del directorio dentro de su directorio padre la cual contiene el nombre del
directorio. El otro enlace corresponde a la entrada
del directorio creado.
Cada vez que se crea un subdirectorio dentro de un directorio A, el contador de enlaces duros del
del subdirectorio creado, la
nodo-i del directorio se incrementa en una unidad debido a la entrada
cual referencia a su directorio padre, es decir, al directorio A. El contador se decrementa cada vez que se
borra un subdirectorio. En general, el número de enlaces duros NEo de un directorio es igual al número
de subdirectorios Ns más dos:
NEo = Ns + 2
(5 . 1 )
1
•
1
11
e
•
•
11
Ejemplo 5 .5
En la Figura 5 . 3 se muestra en detalle parte de la estructura de directorios del sistema de archivos del
Ejemplo 5 .4. Se observa que cuatro entradas de directorios apuntan al directorio / home : la entrada aso­
ciada al directorio / home en el directorio raíz, la entrada
del propio directorio / home , la entrada
del subdirectorio / home / s ara. Luego el con­
del subdirectorio / home / a l ex y la entrada
tador de enlaces duros del nodo-i del directorio / home tendrá almacenado el valor 4. Este valor podría
haberse determinado también usando (5 . 1 ).
1
11
•
•
11
11
•
•
•
1
11
•
S i un archivo, excepto si es de tipo directorio, tiene NEo enlaces duros eso implica que tiene NEo
nombres distintos.
198
Ampliación de sistemas operativos
Directorio 1
:
home
:
�
�hh�me ��
Directorio
. .
J
al ex
sara
Dinxtori
s a ra
. .
Directorio
al
ex
:
/
. .
:
Figura 5.3 -
Detalle de parte de la estructura de directorios del sistema de archivos del Ejemplo 5.5
A diferencia de los restantes tipos de archivos un directorio solo puede tener un único nombre para
evitar la existencia de ciclos en el árbol de directorios.
Un enlace simbólico es un archivo cuyos bloques de datos contienen el nombre de ruta absoluta o
relativa de otro archivo o directorio. S i el nombre de ruta ocupa poco espacio entonces éste se puede
almacenar directamente en el nodo-i del archivo que implementa el enlace simbólico sin necesidad de
consumir bloques de datos.
La entrada asociada a un enlace simbólico en el directorio origen no contiene un puntero al nodo-i
del elemento destino, sino un puntero al nodo-i del archivo que implementa el enlace simbólico.
La máscara de modo simbólica de cualquier enlace simbólico siempre es l rwxrwxrwx por convenio.
Esta máscara solo es una notación y no transmite la información usual sobre los permisos de acceso del
propietario, grupo propietario y otros usuarios. Es la máscara de modo del elemento destino la que será
consultada para autorizar o denegar los accesos al archivo destino. De hecho cualquier operación de
cambio de permisos que se realice sobre el enlace simbólico en realidad se estará realizando sobre el
archivo destino.
La principal ventaj a de los enlaces simbólicos es que permiten crear enlaces a directorios. S u princi­
pal inconveniente es que consumen bloques de datos de disco y que retardan el análisis de los nombres
de ruta.
En los SOBUNIX, cuando se invoca una llamada al sistema cre a te o mkdir para crear un nuevo
archivo o directorio, respectivamente, se crea una entrada en el directorio de creación, es decir, un enlace
duro. Una vez creado el elemento destino se pueden utilizar las llamadas al sistema l ink y s yml ink
para crear más enlaces duros o enlaces simbólicos, respectivamente. Para eliminar un enlace se puede
SOBUNIX: gestión de archivos y gestión de la E/ S
199
usar la llamada al sistema unl in k. Estas tareas también se pueden realizar con los comandos 1 ink,
s yml ink y unl ink, los cuales internamente invocan a las llamadas al sistema homónimas. También el
comando ln que permite crear enlaces duros y simbólicos invoca internamente a las llamadas 1 ink o
syml ink.
A la hora de usar estas llamadas al sistema y comandos conviene recordar que si se aplican para crear
un enlace duro sobre un directorio se generará un mensaje de error, ya que los directorios solo pueden
tener un nombre, el que se les asigna en el momento de su creación.
e
Ejemplo 5. 6
Supóngase la estructura de directorios de la Figura 5 .2. Considérese que el directorio de trabajo actual
es / home / s ara y que el archivo / home / al ex/ proyect o / t empo . txt tiene asignado un nodo-i con
número de nodo-i igual a 2345 . La creación del enlace duro proybp al archivo t empo . txt ha podido
ser realizada por un usuario que disponga de los permisos adecuados usando el siguiente comando:
ln / home / al ex / proyect o / t empo . txt proybp
También se puede usar el comando:
l i nk / home / al ex / proyect o / t empo . txt proybp
Tras crear el enlace duro se tienen dos nombres distintos proybp y t empo . txt asociados al archivo con
número de nodo-i 2345 . El contador de enlaces duros almacenado en el nodo-i ahora tendrá el valor 2.
Esto se puede comprobar utilizando el comando:
l s - l i proybp
Cualquiera de los dos enlaces duros al archivo con número de nodo-i 2345 puede ser borrado usando el
comando unl ink. Por ejemplo, el comando
unl i nk / home / al e x / proyect o / t empo . txt
eliminaría el primer enlace duro del archivo.
Por otra parte, el enlace simbólico / home / al ex / l i s tar al archivo /bi n / l s ha podido ser creado
usando el comando
ln - s / b i n / l s / home / al ex / l i s tar
También se puede usar el comando
syml i nk /bi n / l s / home / al ex / l i s t ar
Si se utiliza el comando
l s - l i / b i n / l s / home / al ex / l i s tar
200
Ampliación de sistemas operativos
se puede comprobar que los archivos / b in / l s y / home / a l ex / l i s tar tienen números de nodos-i
distintos, a diferencia de que lo sucede con los enlaces duros. Esto es así porque un enlaces simbólico es
un archivo distinto del archivo destino y en consecuencia tiene asignado otro nodo-i distinto.
•
5.2.4.
Sistemas de archivos
Durante el proceso de instalación de un SOBUNIX se realiza un formateo a alto nivel de una partición
del disco duro para crear el sistema de archivos principal donde se aloj a el directorio raíz !'. Cada
SOBUNIX establece el tipo de sistema de archivos principal que crea, por ejemplo, SVR3 crea un sistema
s5fs, B SD4.2 crea un sistema FFS , Linux un sistema EXT4, Solaris un sistema ZFS , etc.
Aparte de este sistema de archivos principal, los SOBUNIX son capaces de reconocer y manipular
otros sistemas de archivos del mismo o distinto tipo ubicados en memoria secundaria: discos duros,
discos ópticos (CDs, DVDs o B lu-Ray), pendrives, etc. Por ejemplo, Solaris soporta, entre otros, los
siguientes tipos de archivos : UFS , ZFS , NFS , FAT-32 e ISO 9660.
Para poder acceder a los contenidos de un determinado sistema de archivos ubicado en memoria
secundaria, éste debe ser previamente montado en algún directorio dentro de la estructura de directorios
del sistema de archivos principal. A dicho directorio se le denomina punto de montaje. Por ejemplo, el
punto de montaje del sistema de archivos principal es el directorio raíz !'.
El núcleo almacena en un archivo una tabla de montaje con los sistemas de archivos que tiene que
montar al arrancar el sistema y desmontar al apagarlo. Dicho archivo suele almacenarse en el directorio
/ e t c y su nombre depende de cada SOBUNIX. Por ejemplo, en Solaris se le denominamnt tab, mientras
que en Linux se denomina mtab. En cada entrada de la tabla de montaje se suelen mantener, entre otros,
los siguientes datos: dispositivo que se monta, punto de montaje y tipo de sistema de archivos.
En SOBUNIX la estructura de directorios accesible por el usuario queda constituida por el sistema
de archivos principal y todos los sistemas de archivos montados sobre éste. El acceso a un directorio o
archivo de un sistema de archivos montado sobre el sistema de archivos principal se realiza exactamente
igual que a cualquier archivo o directorio del sistema de archivos principal, es decir, especificando su
nombre de ruta absoluta o relativa.
Por otra parte, los permisos de acceso a un sistema de archivos montado se establecen configurando
los permisos de acceso del punto de montaje.
Algunos comandos útiles para trabaj ar con sistemas de archivos son los siguientes:
1
1
•
moun t . Monta un cierto sistema de archivos en un determinado punto de montaje. Este comando
internamente invoca a la llamada al sistema moun t .
•
umount . Desmonta un cierto sistema de archivos. Este comando internamente invoca a la llamada
al sistema umount .
•
mk f s . Crea u n sistema d e archivos de u n tipo soportado por e l SOBUNIX correspondiente en un
cierto dispositivo.
SOBUNIX: gestión de archivos
y
gestión de la E/ S
201
•
f s ck. Comprueba y repara la existencia de inconsistencias en un determinado sistema de archivos.
•
d f . Muestra datos sobre la distribución de espacio libre y asignado de un determinado sistema de
archivos.
e
Ejemplo S.7
Supóngase que el núcleo de un cierto SOBUNIX asocia a la unidad de CD-ROM el archivo de dispositivo
/ dev/ s r O . Supóngase que se inserta en la unidad de CD-ROM un disco con un sistema de archivos de
tipo ISO 9660 cuyo contenido es el que se muestra en la Figura 5 .4a. Para poder acceder a los contenidos
del sistema de archivos del CD-ROM primero debe ser montado en el sistema de archivos principal en
algún punto de montaje. Supóngase por ejemplo que se desea utilizar como punto de montaje el directorio
/ c drom.
El montaje del sistema de archivos del CD-ROM en el punto de montaje seleccionado se puede realizar
desde un intérprete de comandos mediante la siguiente orden:
mount / dev / s r O / c dr om
Una vez montado se puede listar el contenido del sistema de archivos del CD-ROM usando el comando:
ls
-1
/ c drom
El acceso a un archivo o directorio del CD-ROM se realiza igual que a cualquier otro archivo del sistema
de archivos principal, es decir, especificando su nombre de ruta. Por ejemplo, supóngase que en el direc­
torio raíz del CD-ROM existe el archivo ASCII l e eme . txt. Para mostrar su contenido en la pantalla se
puede usar la siguiente orden:
mo re / c drom / l e eme . txt
Cuando se termine de usar el CD-ROM para desmontar su sistema de archivos se debe usar la siguiente
orden:
umount / dev/ s r O
Conviene señalar que cuando un directorio D s e utiliza como punto de montaje l a lista de archivos
que contenía originalmente D es sustituida por la lista de archivos del directorio raíz ( 1 ) del sistema
de archivos montado, y en consecuencia no es posible acceder a los archivos aloj ados originalmente
en D. Por ejemplo, en la Figura 5 .4a el directorio / c drom contiene el archivo da t o s . txt. Cuando
dicho directorio pasa a utilizarse como punto de montaje (ver Figura 5 .4b) ya no se puede acceder a
da t o s . txt ya que la lista de archivos que contenía originalmente el directorio ha sido sustituida por la
lista de archivos del directorio raíz del sistema de archivos del CD-ROM. Cuando el sistema de archivos
del CD-ROM sea desmontado entonces se restaurará la lista de archivos original y podrá accederse de
nuevo al archivo da t o s . txt.
1
1
•
202
Ampliación de sistemas operativos
Directorio 1 del
sistema de archivo principal
bin
boot
dev
Directorio
home
�����--��cdrom
1
cdrom
datos.txt
(a)
Directorio 1 del
sistema de archivo principal
bin
boot
dev
home
cdrom
Directorio
cdrom
leeme.txt
vid.mpg
(b)
del sistema de archivos principal del Ejemplo 5.7 antes (a)
el sistema de archivos del CD-ROM
Figura 5.4 - Estado
5.3.
y
después (b) de montar
Capa nodo virtual/sistema de archivos virtual
Los primeros SOBUNIX únicamente soportaban un único tipo de sistema de archivos: S5FS en los
SOBUNIX basados en el System V y FFS en los SOBUNIX basados en BSD. Posteriormente, el auge
de las redes de comunicación conduj o al desarrollo de sistemas de archivos en red, como RFS de AT &T
o NFS de Sun Microsystems, lo que hizo que algunos SOBUNIX fuesen adaptados para poder soportar­
los. Asimismo, también existía en la comunidad de SUBONIX el deseo de poder soportar sistemas de
archivos nativos de otros sistemas operativos, como FAT de MS-DOS , para así acceder a la información
de las particiones de discos duros o disquetes formateadas con estos sistemas de archivos.
Con el fin de dar soporte a diferentes tipos de sistemas de archivos en 1 985 Sun Microsystems
introdujo en el núcleo de Sun OS 2.0 una capa de software conocida en la literatura como sistema
de archivos virtual (Virtual File S ystem, VFS) o capa nodo virtual (nodo-v)fsistema de archivos virtual
(SAV). Debido a su eficiencia, flexibilidad y elegancia la capa nodo-v/SAV ha sido adoptada por muchos
SOBUNIX: gestión de archivos
y
gestión de la E/S
203
SOBUNIX, aunque cada uno la implementa de distinta forma.
La capa nodo-v/SAV permite aislar los detalles de la implementación de cada tipo de sistema de
archivos del resto del núcleo, lo que simplifica su diseño. Cualquier operación sobre un archivo o sobre un
sistema de archivos completo invocada por el usuario a través de una llamada al sistema o internamente
por algún subsistema del núcleo es redireccionada por la capa nodo-v/SAV hacía la rutina dependiente
del sistema de archivos al que pertenezca el archivo que da soporte a dicha operación. Obviamente, el
núcleo de cada SOBUNIX debe disponer, por cada tipo de sistema de archivos que soporte, de las rutinas
que implementan las operaciones sobre dicho sistema de archivos.
En definitiva la capa nodo-v/SAV permite descomponer las operaciones sobre un archivo en dos
partes : una independiente del tipo de sistema de archivos y otra dependiente del tipo de sistema de
archivos. La capa nodo-v/SAV es la interfaz que permite el paso entre ambas partes (ver Figura 5 .5).
Interfaz de llamadas al sistema
(read ( )
Funciones independientes
del tipo de sistema de archivos
1
wri te ( )
1
open ( )
1
mount ( )
1
•
•
•
)
Capa nodo-v/SA V
Funciones
dependientes
de un sistema
UFS
Funciones
dependientes
de un sistema
FAT
Figura 5.5 -
- - - - - -
Funciones
dependientes
de un sistema
ISO 9660
Capa nodo-v /SAV
La capa nodo-v/SAV trabaj a con dos tipos de estructuras de datos básicas : los nodos-v y los sistemas
de archivos virtuales. La implementación y gestión de estas estructuras depende de cada S OBUNIX.
5.3.1.
Nodos virtuales
Un nodo virtual o nodo-v es una estructura de datos que representa a un archivo activo. El núcleo
asigna un nodo-v cuando se crea o se abre un archivo durante el tratamiento de las llamadas al sistema
c r e a te u open. El descriptor del archivo tiene un puntero al objeto de archivo abierto, el cual tiene a su
vez un puntero al nodo-v asociado al archivo (ver Figura 5 . 1 ) .
Nótese que s i dos procesos A y B abren e l mismo archivo ( o s i el mismo proceso abre dos veces el
mismo archivo) existirán dos descriptores de archivos y dos estructuras de objeto abierto distintas, pero
solo una estructura nodo-v. El nodo-v mantiene un contador de referencias con el número de estructuras
de datos que lo referencian. En este caso el contador de referencias contendrá el valor 2. Si un proceso
ejecuta una llamada al sistema e l o s e sobre dicho archivo el contador de referencias se decrementará en
una unidad.
En general cada vez que el núcleo referencia, a través de alguna de sus estructuras de datos, al nodo­
Y de un archivo se incrementa en una unidad el contador de referencias del nodo-v. Por el contrario,
204
Ampliación de sistemas operativos
cuando el núcleo elimina una referencia al nodo-v el contador de referencias se decrementa en una
unidad. Solo cuando el contador de referencias de un nodo-v toma el valor O entonces el nodo-v puede
ser desasignado (liberado) y las estructuras de datos (nodo-i) y bloques de datos del archivo cargadas en
memoria principal pueden ser eliminadas. Si bien dicha eliminación no se realiza de forma inmediata
sino que se demora en el tiempo por si el archivo vuelve a ser abierto en un futuro próximo. De esta
forma se evita tener que leer de nuevo en el disco el nodo-i y los bloques de datos del archivo.
Aparte de la apertura de un archivo existen otras circunstancias en las que es necesario asignar un
nuevo nodo-v o referenciar a un nodo-v ya creado, y en consecuencia incrementar su contador de refe­
rencias [Vahalia, 1 995] :
•
Un proceso mantiene una referencia al nodo-v de su directorio de trabajo actual. Cuando un pro­
ceso cambia su directorio de trabajo tiene que referenciar al nodo-v del nuevo directorio de trabaj o
y eliminar l a referencia a l nodo-v del directorio d e trabaj o antiguo.
•
Cuando se monta un nuevo sistema de archivos se crea una referencia al nodo-v del directorio
utilizado como punto de montaje.
•
Cuando el núcleo analiza un nombre de ruta absoluta o relativa introducido como argumento de
alguna llamada al sistema o comando tiene que referenciar al nodo-v de cada directorio intermedio
que aparece en la ruta. Dicha referencia se crea para poder buscar en un directorio. Cuando termina
la búsqueda en dicho directorio la referencia a su nodo-v se elimina.
La principal función del nodo-v asociado a un archivo es la de redireccionar las operaciones que se
vayan a realizar sobre el archivo hacía las rutinas dependientes del tipo de sistema de archivos al que
pertenece el archivo que implementan dichas operaciones. Por ejemplo, en Solaris la invocación de una
llamada al sistema read sobre un archivo previamente abierto perteneciente a un sistema de archivos
UFS hace que se invoque a la operación virtual VOP_ READ ( ) del nodo-v la cual invoca a su vez a
la función u f s_read ( ) . VOP_ READ ( ) es una función independiente del tipo de sistema de archivos
mientras que u f s_ read ( ) es la función que implementa dicha operación en los sistemas tipo UFS .
La estructura que implementa un nodo-v suele contener, entre otros, los siguientes datos:
•
Contador de referencias. Indica el número de estructuras de datos del núcleo que referencian al
nodo-v.
•
Tipo de nodo-v. Coincide con el tipo de archivo al que está asociado el nodo-v: archivo regular,
directorio, archivo de dispositivo modo bloque, etc.
•
Puntero a una estructura de datos dependiente del tipo de sistema de archivos. Dicha estructura
se denomina de forma general como nodo índice (nodo-i) y la información que contiene depende
de cada tipo de sistema de archivos. Por ejemplo, para un archivo perteneciente a un sistema de
archivos S 5FS o UFS el nodo-i contiene los atributos del archivo y la localización en el disco de los
bloques de datos del archivo. En este caso el nodo-i asociado al archivo al que apunta un nodo-v es
una copia en memoria principal del nodo-i almacenado en el disco. El tamaño que ocupa la copia
SOBUNIX: gestión de archivos y gestión de la E/ S
205
de un nodo-i en memoria principal es mayor que el tamaño del nodo-i en el disco, ya que contiene
más información, como por ejemplo, un puntero al nodo-v y el número de nodo-i del archivo.
•
Puntero al vector de operaciones sobre un archivo. El vector de operaciones sobre un archivo es
un array de punteros a funciones dependientes del tipo de sistema de archivos al que pertenece el
archivo. Estas funciones implementan todas las posibles operaciones sobre un archivo.
•
Lista de páginas del archivo cargadas en la memoria principal. Esta lista se consulta cuando el
contador de referencias del nodo-v toma el valor O para localizar y eliminar de memoria principal
las páginas del archivo. Puesto que el archivo ya no está activo puede ser eliminado de la memoria
principal.
.--------------------------... - - - ... - - - -------------------------------- - -------- - ----------------
s t ruct vnode op s
u f s_ c r e a t e ( )
u f s _open ( )
u f s_c l o s e ( )
u f s read ( )
u f s _wr i t e ( )
D Bloques
O de datos
O del archivo
Vector de operaciones del archivo
s t ru c t
inode
Partición de disco duro
Sistema de archivos UFS
nodo-i
--------- - - - - - - - - - - - - - - - - - - - - - ---- - --------- - -- - - - - - - - - - - - - - - - - - - - - - - - - -- - --- - - - --- - - - - - - - - - J
Estructuras en memoria principal
Figura 5.6 -
e
Implementación de un nodo-v en Solaris
Ejemplo 5 . 8
En Solaris un nodo-v (ver Figura 5 .6) se implementa con una estructura vnode que contiene, entre otros,
los siguientes campos :
•
v_type . Contiene el tipo del nodo-v, como por ejemplo: VREG (archivo regular), VD I R (directorio),
VBLK (dispositivo modo bloque), VCHR (dispositivo modo carácter), etc.
•
v_c ount. Contador de referencias.
206
Ampliación de sistemas operativos
•
v_op. Puntero al vector de operaciones virtuales sobre el archivo. Dicho vector se implementa con
una estructura vnodeop s , entre las funciones virtuales que se pueden invocar se encuentran las
siguientes: vop_open ( ) , vop_read ( ) , vop_wr i t e ( ) , vop_c l o s e ( ) , etc.
•
v_data. Puntero a una estructura de datos dependiente del tipo de sistema de archivos, es decir, a
un nodo-i.
•
v_v f sp. Puntero a la estructura v f s asociada al sistema de archivos al que pertenece el archivo.
•
v_mount edhere. Puntero a la estructura v f s asociada al sistema de archivos montado en este
directorio, si existe alguno.
•
v_page s . Lista de páginas del archivo cargadas en memoria.
•
5.3.2.
Sistemas de archivos virtuales
Un sistema de archivos virtual (SAV) es una estructura de datos que representa a un sistema de
archivos activo. El núcleo asigna un SAV cuando se monta un sistema de archivos y lo desasigna cuando
lo desmonta.
La principal función del SAV asociado a un sistema de archivos archivo es la de redireccionar las
operaciones que se vayan a realizar sobre el sistema de archivo hacía las rutinas dependientes del tipo de
sistema de archivos que implementan dichas operaciones. Por ejemplo, en Solaris la invocación de una
llamada al sistema mount para montar un cierto sistema de archivos UFS , hace que se le asigne un SAV
y que se invoque al procedimiento v f s_ mount ( ) del SAV, que es una función independiente del tipo
de sistema de archivos. A su vez esta función invoca a la función u f s_mount ( ) que implementa esta
operación en un sistema de archivos tipo UFS .
La estructura que implementa un SAV suele contener, entre otros, los siguientes datos:
•
Puntero al siguiente SAV. El núcleo mantiene una lista con todos los SAV montados.
•
Puntero al vector de operaciones sobre el sistema de archivos. El vector de operaciones sobre
un sistema de archivos es un array de punteros a funciones dependientes del tipo de sistema de
archivos que implementan todas las posibles operaciones sobre dicho sistema de archivos.
•
Puntero a una estructura de datos dependiente del tipo de sistema de archivos.
•
Puntero al nodo-v del punto de montaje.
•
Tipo de sistema de archivos. Coincide con el tipo de sistema de archivos al que está asociado el
SAV y que debe ser alguno de los soportados por el núcleo: S5FS , UFS , NFS , EXT2, FAT, etc.
Recuérdese que cada SOBUNIX establece los tipos de sistemas de archivos que soporta.
SOBUNIX : gestión de archivos y gestión de la E/ S
e
207
Ejemplo 5 .9
En Solaris un SAV se implementa con una estructura v f s . Esta estructura, contiene entre otros, los
siguientes campos :
•
vf s_next . Puntero a la siguiente estructura v f s de la lista de sistema de archivos montados. Esta
lista se implementa como una lista enlazada de estructuras v f s . La variable global r o o t v f s apun­
ta a la primera estructura vf s de la lista que siempre corresponde al sistema de archivo principal,
es decir, el que se monta sobre el directorio raíz 1
'
•
'.
v f s_ f s typ e . Tipo del sistema de archivos montado. E n Solaris s e soportan sistemas d e archivos
en discos (UFS , ZFS, UDF, PCFS, HSFS , VxFS , QFS , . . ), sistemas de archivos en red (NFS) y
pseudosistemas de archivos mantenidos en la memoria principal (procfs, swapfs, tmpfs, . . . ) .
•
vf s_op . Vector de operaciones sobre el sistema de archivos.
•
v f s_data. Puntero a una estructura de datos dependiente del sistema de archivos .
•
vf s_vnodec overed. Puntero a l nodo-v del directorio punto d e montaje.
En la Figura 5.7 se muestra una posible configuración del inicio de la lista de sistemas de archivos
montados de un sistema Solaris. La variable global r o o tv f s apunta a la primera estructura v f s de la
lista que está asociada al sistema de archivos principal o raíz que es de tipo UFS . A su vez esta estructura
contiene un puntero a la siguiente estructura v f s de la lista asociada a un sistema de tipo NFS .
s t ruct vf s
s t ru c t v f s
rootvf s
...,.
-
v f s next
v f s _ f s typ e
�
v f s_op
v f s data
v f s data
-
...
:
SAV
SAV
s t ru c t vf s op s
s t ruct vf sop s
u f s _mount ( )
n f s _mount ( )
u f s _unmount ( )
n f s _unmount ( )
:
Vector de operaciOnes del
sistema de archivos principal
de tipo UFS
Figura 5.7 -
----
v f s _ f s type
v f s _op
:
-
v f s next
:
Vector de operaciones de un
sistema de archivos tipo NFS
Posible configuración del inicio de la lista de sistemas de archivos montados de un sistema
Solaris
•
208
5.3.3.
Ampliación de sistemas operativos
Análisis de nombres de rutas en SOBUNIX
Algunas llamadas al sistema, como open, creat o exe c , tienen entre sus argumentos de entrada
el nombre de ruta absoluta o relativa de un archivo. El núcleo tiene que analizar dicha ruta para poder
localizar el nodo-v del archivo y así poder invocar a la función dependiente del tipo de sistema de archivos
que implementa la operación de la llamada al sistema.
El análisis de cada componente de la ruta requiere localizar el nodo-v de su directorio padre y buscar
en su lista de archivos y subdirectorios la entrada asociada a la componente. Nótese que la búsqueda en la
lista del directorio se implementa con una función dependiente del tipo de sistema de archivos por ello es
necesario localizar el nodo-v del directorio padre del componente. Dicha entrada, aparte del nombre del
componente, que es el que se utiliza para buscar, contiene el número del nodo-i asociado al componente.
Si dicho nodo-i está cargado en memoria entonces tendrá asignado un nodo-v, en caso contrario hay que
cargarlo y asignarle uno.
e
Ejemplo 5 . 10
El nombre de ruta absoluta 1 d i r l 1 archi vol contiene tres componentes: el directorio raíz ! el di­
rectorio di r l y el archivo archi vo l . Supóngase que el análisis de este nombre de ruta absoluta se
realiza en Solaris. La función del núcleo l o okuppn ( ) es la encargada de analizar un nombre de ruta
de un archivo o directorio. Esta función lee la variable r o o t d i r para localizar el nodo-v del directorio
raíz e invoca una operación VOP_LOOKUP sobre el nodo-v lo que produce la invocación de la función
apropiada dependiente del sistema de archivos. Supuesto que se trata de un sistema de archivos UFS se
invocaría a la función u f s_l o o kup ( ) .
'
',
Esta función, a partir del nodo-i del directorio raíz, localiza los bloques de datos que contienen la lista
de archivos y subdirectorios del directorio, y busca en ella la existencia de una entrada para el directorio
di r l . Si la encuentra, entonces dicha entrada contiene el número del nodo-i asociado a di r l . Si dicho
nodo-i ya estaba cargado en memoria entonces tendrá un nodo-v asignado y se incrementa su contador de
referencias. Si el nodo-i no estaba cargado en memoria entonces se creará y se le asignará un nodo-v. La
función u f s_lookup ( ) devuelve a l o okuppn ( ) un puntero al nodo-v de / di r l . Si u f s_l o okup ( )
no encuentra la entrada entonces devuelve un error a l o o kuppn ( ) .
A continuación l ookuppn ( ) decrementa el contador de referencias del nodo-v asociado al directo­
rio raíz, ya que ya ha terminado de trabaj ar con él, e invoca una operación VOP_LOOKUP sobre el
nodo-v del directorio / di r l la cual produce la invocación de la función u f s_ l o okup ( ) para buscar
la existencia de una entrada asociada al archivo archi vo l en la lista del directorio di r l . El funciona­
miento de esta función es idéntico al descrito en el párrafo anterior. Si se encuentra la entrada entonces
uf s_l o o kup ( ) devuelve a l o o kuppn ( ) un puntero al nodo-v de 1 d i r l 1 archi vo l .
Finalmente l o o kuppn ( ) decrementa el contador de referencias del nodo-v asociado al directorio 1 d i r l
y devuelve u n puntero a l nodo-v d e 1 d i r l 1 archi vo l a la rutina del núcleo que la había invocado .
•
Para reducir el número de lecturas en disco y el tiempo de búsqueda de entradas en directorios, los
SOBUNIX implementan una caché de búsqueda de nombres en directorios. Se trata de una caché de
estructuras de datos que se implementa en el espacio de direcciones del núcleo. Cada estructura de datos
SOBUNIX: gestión de archivos y gestión de la E/S
209
de la caché contiene, entre otros, los siguientes datos sobre una entrada de un directorio recientemen­
te accedida: un puntero al nodo-v del directorio y el nombre y un puntero al nodo-v de un archivo o
subdirectorio contenido en dicho directorio.
Cuando el núcleo tiene que buscar la entrada de un archivo o subdirectorio determinado dentro de
la lista de un directorio, primero busca la existencia de dicha entrada en la caché. En caso de acierto se
ahorra el tiempo de leer en disco el bloque de datos que contiene la lista del directorio y buscar dentro
de la lista. En general la implementación y gestión de esta caché depende de cada S OBUNIX.
El sistema de archivos UFS
5.4.
5.4.1.
Características principales
UFS (UNIX File System, sistema de archivos UNIX) es un sistema de archivos soportado por di­
versos SOBUNIX, como por ejemplo: Solaris, FreeBSD y A/UX. El sistema UFS deriva del sistema de
archivos FFS de BSD, el cual en su momento supuso una auténtica revolución dentro de los SOBUNIX
los cuales utilizaban el sistema de archivos S5FS que tenía limitaciones importantes.
Las características principales de un sistema de archivos UFS son las siguientes:
•
Trabaj a con un tamaño de bloque de datos de 4 KiB o 8 KiB . Además para reducir la fragmentación
interna cada bloque se divide en fragmentos que pueden ser asignados individualmente. De esta
forma la fragmentación interna promedio pasa de ser de medio bloque a medio fragmento. Tanto el
tamaño de bloque como el número de fragmentos ( 1 , 2, 4 o 8) se fij a al crear el sistema de archivos.
•
Tiene en cuenta la geometría del disco a la hora de alojar los nodos-i y los bloques de datos de
los archivos. Con ello se consigue mejorar el rendimiento del sistema ya que se reduce el tiempo
de búsqueda de las cabezas de lectura/escritura del disco, y en consecuencia, el tiempo de las
operaciones de E/S .
•
Por motivos de seguridad mantiene varias copias del superbloque, que es una estructura de da­
tos que contiene información administrativa y estadística de todo el sistema de archivos . Si solo
existiese una copia del superbloque, como pasaba en los sistemas de archivos S5FS , y ésta se
corrompiera debido algún error en el disco todo el sistema de archivos quedaría inutilizado.
•
Las entradas de los directorios son de tamaño variable y pueden ser compactadas para reducir la
fragmentación. El nombre de un archivo puede tener hasta 255 caracteres.
•
Soporta enlaces simbólicos los cuales pueden ser creados con la llamada al sistema syml ink.
•
Soporta la llamada al sistema rename que permite renombrar de forma atómica a un archivo o
directorio. Con el uso de r ename se evita tener que invocar primero a la llamada al sistema l i nk
para crear un enlace duro que establezca el nuevo nombre del archivo y a continuación usar la
llamada al sistema un l ink para borrar el enlace duro que establecía el nombre antiguo.
210
Ampliación de sistemas operativos
Conviene señalar que cada S OBUNIX implementa UFS de una determinada forma y con diversas
extensiones, las cuales influyen en su portabilidad ya que dichas extensiones solo son reconocidas úni­
camente por el SOBUNIX que las introduce. Por ejemplo Solaris, implementa UFS logging que permite
implementar la técnica de registro por diario (journaling) en los sistema de archivos UFS de Solaris.
5.4.2.
Estructura de un sistema de archivos UFS
Un sistema de archivos UFS presenta la siguiente estructura en la partición de disco donde se crea
(ver Figura 5 . 8):
•
Á rea de arranque. Se sitúa al principio de la partición. Contiene el código necesario para arrancar
el SOBUNIX si dicha partición se usa como partición activa.
•
Superbloque. Se sitúa a continuación del área de arranque. Es una estructura de datos que contiene
información estadística y administrativa del sistema de archivo, como por ejemplo: un número
mágico que identifica al sistema como de tipo UFS , el número, el tamaño y la localización de los
grupos de cilindros, el tamaño de bloque de datos que se utiliza, el número total de bloques de datos
y de nodos-i, etc. Esta información se configura al crear el sistema de archivos en la partición.
•
Grupos de cilindros. Un grupo de cilindros está formado por un conjunto de cilindros contiguos.
El número de grupos de cilindros (NG) y el número de cilindros que contiene un grupo son confi­
gurados cuando se crea el sistema de archivos UFS . Cada grupo de cilindro contiene la siguiente
información:
- Una copia del superbloque. La información que contiene el superbloque es fundamental para
poder operar con el sistema de archivos. En previsión de la aparición de posibles errores en
el disco el superbloque se replica en cada grupo de cilindros. La ubicación de la copia del
superbloque en cada grupo de cilindros se elige cuidadosamente para evitar que todas las
copias se encuentren en la misma superficie o plato del disco.
- Estructura de grupo de cilindros. Contiene información estadística y administrativa del grupo
de cilindros.
- Mapas de bits. Especifica cuales son los bloques, fragmentos y nodos-i libres en el grupo de
cilindros.
- Nodos-i del grupo de cilindros. Cada nodo-i tiene un tamaño de 128 bytes y almacena los
atributos del archivo. También almacena la localización de los bloques de datos de un archivo.
En concreto contiene 1 5 direcciones de bloques de disco de 32 bits cada. Las 12 primeras
direcciones son las de los 1 2 primeros bloques de datos del archivo, también denominados
bloques directos. Las tres direcciones restantes localizan a un bloque de indirección simple,
un bloque de indirección doble y un bloque de indirección triple, respectivamente.
- Bloques de datos del grupo de cilindros. Contienen los datos propiamente dichos de los
archivos.
SOBUNIX: gestión de archivos
y
gestión de la E/ S
211
Partición de disco
Arranque
Superbloque
Grupo de cilindro
NG- 1
Grupo de cilindro
o
- - - - - - - - - - - - - -
Mapa de bits
o de cil indro
Figura 5.8
5.4.3.
-
Nodos-i
Bloques de datos
Estructura de un sistema de archivos UFS
Implementación de directorios en UFS
En un sistema de archivos UFS la lista de archivos y subdirectorios de un directorio se implementa
con entradas de tamaño variable. En cada entrada se almacena la siguiente información: número de
nodo-i, longitud en bytes de la entrada, longitud en bytes del nombre, el nombre del archivo, un carácter
nulo para marcar el final del archivo y los caracteres nulos de relleno necesarios hasta alcanzar una
frontera de 4 bytes. El nombre de archivo en UFS puede tener un tamaño máximo de 255 caracteres.
Cuando se borra una entrada de un directorio, excepto si se trata de la primera, la entrada anterior se
expande hasta ocupar el espacio que tenía asignado la entrada borrada. Esta forma de proceder ayuda a
reducir la fragmentación.
e
Ejemplo 5 . 1 1
En l a Figura 5 .9a s e muestra u n ejemplo de l a implementación de u n directorio e n u n sistema UFS . El
directorio consta de 4 entradas : la primera asignada a la entrada ' . ', la segunda a la entrada " . . ", la
tercera asignada al archivo prueba y la cuarta asignada al archivo f o t o s . Las dos primeras entradas
tienen un tamaño de 1 2 bytes, mientras que las dos últimas tienen un tamaño de 1 6 bytes. Se observa
como el nombre de una entrada siempre termina con un carácter nulo \ o seguido de tantos caracteres
nulos como sean necesarios hasta completar una frontera de 4 bytes.
'
'
En la Figura 5 .9b se muestra el estado del directorio después de borrar el archivo f o t o s . Se observa
como la entrada del archivo prueba ha sido expandida hasta ocupar el espacio que tenía asignado la
entrada borrada.
•
212
Ampliación de sistemas operativos
Longitud entrada (2 bytes)
Longitud nombre (2 bytes)
N° nodo-i (4 bytes)
Nombre + caracteres de relleno
+
\0 \0 \0
\0 \0
35
12
1
36
12
2
51
16
6
p
r
u
e
b
15
16
5
f
o
t
o
S
\0 \0
\0 \0 \0
a
(a)
35
12
1
36
12
2
\0 \0 \0
\0 \0
\0 \0
\0 1 \0 1 \0 1 \0 \o 1 \o \o 1 \o \0 \0 \0 \0 \0 \0 \0 \0
51
16
p
6
r
u
e
b
a
(b)
Figura 5.9 - Implementación de
un directorio en UFS : (a) Estado inicial. (b) Después de borrar el archivo
fotos
5.4.4.
Gestión de un sistema UFS
Nodos-i
El núcleo para poder trabajar con un archivo, aparte de asignarle un nodo-v, necesita tener cargado
en la memoria principal el nodo-i asociado al archivo, ya que contiene los atributos y la localización de
sus bloques de datos. El núcleo copia el contenido de un nodo-i en una estructura de datos que crea en
su espacio de direcciones. El nombre que recibe dicha estructura depende de cada SOBUNIX, el cual lo
asigna en función del tipo de sistema de archivos. En lo que resta de sección se denotará por nodo-im a
la estructura de datos de memoria principal que contiene una copia de un nodo-i del disco duro.
En un nodo-im, aparte de una copia de un nodo-i, también se almacenan, entre otros, los siguientes
datos: un puntero al nodo-v asociado al nodo-im, punteros para colocar al nodo-im en una de las colas
hash que mantiene el núcleo en función del número de nodo-i para localizar a los nodos-im, y punteros
para colocar al nodo-im en una lista de nodos-im libres.
El núcleo coloca a un nodo-im en la lista de nodos-im libres si el contador de referencias de su nodo­
v asociado alcanza el valor O. La posición de la lista en que coloca al nodo-im depende de si la lista de
páginas de nodo-v está vacía o contiene alguna página. Por ejemplo, dependerá de cada SOBUNIX, si
SOBUNIX : gestión de archivos
y
gestión de la E/ S
213
está vacía entonces el núcleo coloca al nodo-im al principio de la lista de nodos-im libres. Por el contrario
si contiene alguna página lo coloca al nodo-im al final de la lista.
Si el núcleo no localiza a un nodo-im en la cola hash en que le correspondería estar en función de su
número de nodo-i, entonces eso significa que dicho nodo-i no está cargado en memoria. En ese caso el
nodo-i debe ser copiado en un nodo-im. El núcleo selecciona para ello al primer nodo-im de la lista de
nodos-i libres.
e
Ejemplo 5 . 12
En Solaris la estructura de datos que implementa un nodo-im de un archivo de un sistema UFS se deno­
mina inode. Esta estructura contiene, entre otros, los siguientes campos :
•
i_forw. Puntero a l siguiente nodo-im d e la cola d e hash a l a que pertenece este nodo-im.
•
i_backw. Puntero al anterior nodo-im de la cola de hash a la que pettenece este nodo-im.
•
i_free f . Puntero al siguiente nodo-im de la lista de nodos-im libres.
•
i f reeb. Puntero al anterior nodo-im de la lista de nodos-im libres.
•
i c ommon. Estructura de datos donde se copian los datos de un nodo-i del disco. Entre otros con­
tiene los siguientes campos :
- i c_smode. Máscara d e modo del archivo que establece el tipo y los permisos d e acceso. Se
distinguen, entre otros, los siguientes tipos: archivo regular (I FREG), directorio ( I F D I R) ,
enlace simbólico ( I FLNK), dispositivo modo bloque ( I FBLK), dispositivo modo carácter
( I FCHR), tuberías ( I F I FO) y sockets ( I F SOCK). Este campo toma el valor O si el nodo-i
está libre, es decir, no está asociado a ningún archivo.
- i c _nl ink. Número de enlaces duros.
- i c_su i d. UID del propietario del archivo.
- i c_sgid. GID del grupo propietario del archivo.
- i c_l s i z e . Tamaño del archivo en bytes.
- i c_a t ime . Fecha y hora del último acceso al archivo.
- i c_mt ime . Fecha y hora de la última modificación del archivo.
- i c_c t ime . Fecha y hora de la última modificación de algún campo del nodo-i asociado al
archivo.
- i c_db. Direcciones de los 12 primeros bloques de datos del archivo (bloques directos).
i c_ib. Direcciones de los tres bloques de indirección (simple, doble y triple).
•
i_vnode. Puntero al nodo-v asociado al nodo-i.
•
i_dev. Número de dispositivo físico en que reside el nodo-i.
214
Ampliación de sistemas operativos
•
i_nurnber. Número del nodo-i.
En la Figura 5 . 1 0 se muestra un ejemplo de un posible estado de las colas hash de nodos-im y de la lista
de nodos-im libres de un sistema UFS en Solaris. En este ejemplo se ha considerado que el número de
colas hash implementadas es N=3 (j = O, 1 , 2) y que la función hash utilizada para colocar a los nodos-im
en las colas hash es J= i_nurnbe r %N. Se observa que en la cola hash j = O se encuentran los nodos-im
90 y 1 32, en la cola hash j = 1 los nodos-im 1 1 5, 9 1 , 1 27 y 1 30, y en la cola hash j = 2 se encuentran
los nodos-im 1 34, 1 3 1 y 86. Además los nodo-im 1 32, 1 1 5 y 1 3 1 forman parte de la lista de nodos-im
libres.
•
Cabecera
lista
nodos-i
libres
t
1o
o
o
•
Cabecera
cola hash
j=O
struct
inode
struct
ino de
132
90
..
!
o
¡---------------------------J
1
..
Cabecera
cola hash
j=l
struct
inode
115
,---------------------------o
o
struct
ino de
91
struct
ino de
127
struct
ino de
130
..
1
:
·---------------------------,
1
11--------------------------,
:o
o
•
Cabecera
cola hash
j=2
Figura 5.10 -
struct
inode
1 34
struct
ino de
13 1
struct
inode
86
Colas hash de nodos-im y lista de nodos-im libres de un sistema UFS en Solaris
SOBUNIX: gestión de archivos
y
gestión de la E/S
215
Asignación de espacio
En un sistema de archivos UFS el tamaño de un bloque de datos puede ser de 4 KiB o 8 KiB . Además
los bloques se pueden dividir en un número prefij ado de fragmentos: 1 , 2, 4 o 8. El tamaño mínimo que
puede tener un fragmento queda limitado por el tamaño de un sector del disco. Tanto el tamaño de bloque
como el número de fragmentos se configuran al crear un sistema de archivos UFS .
Cada fragmento de un bloque puede ser direccionado y asignado individualmente, esto implica sus­
tituir la lista de bloques libres por un mapa de bits que registre los fragmentos libres y los asignados.
Todos los bloques de datos de un archivo o directorio deben ocupar bloques de datos completos en el
disco. El último bloque del archivo puede estar totalmente lleno o solo ocupar uno o varios fragmentos
contiguos del bloque. Los fragmentos libres del último bloque de un archivo pueden ser utilizados para
alojar los fragmentos del último bloque de datos de otro archivo.
Con esta forma de asignación se consigue reducir la fragmentación interna promedio a medio frag­
mento por archivo. Sin embargo pueden afectar al rendimiento del sistema ya que produce operaciones
de copia adicionales cuando un archivo crece de tamaño. Por ejemplo, supóngase un bloque de disco X
que tiene cuatro fragmentos, uno de ellos está asignado al último bloque de un archivo A y los otros tres
al último bloque de un archivo B . Si el archivo A incrementa su tamaño en un fragmento el núcleo tendrá
que buscar un bloque Y que contenga dos fragmentos consecutivos libres y copiar en él el fragmento del
archivo A que estaba en el bloque X.
Por otra parte, el núcleo con objeto de reducir los tiempos de búsqueda en disco sigue las siguientes
reglas para ubicar en el disco los bloques de datos y los nodos-i de un archivo o directorio en un sistema
de archivos UFS [Vahalia, 1 995 ] :
•
Los nodos-i d e todos los archivos pertenecientes a u n mismo directorio s e intentan colocar e n un
mismo grupo de cilindros. Con esta medida se tiene en cuenta que los usuarios suelen trabaj ar
normalmente con los archivos de su directorio de trabajo, y que algunos comandos, como por
ejemplo l s , trabajan con los nodos-i de todos los archivos de un mismo directorio.
•
Cuando se crea un nuevo directorio éste se intenta ubicar en un grupo de cilindros diferente al de
su directorio padre. De esta forma los datos se distribuyen de manera uniforme por el disco.
•
Los bloques de datos de un archivo se intentan colocar en el mismo grupo de cilindros donde está
ubicado su nodo-i, ya que normalmente se suelen acceder de forma conjunta.
•
Los bloques directos de un archivo se aloj an en un grupo de cilindros y luego se va cambiando de
grupo de cilindros cada M bloques. El valor M es configurado al crear el sistema de archivos. De
esta forma los datos se distribuyen de manera uniforme por el disco y además se evita llenar por
completo un grupo de cilindros con un archivo de gran tamaño.
•
Los bloques de datos de un archivo se intentan colocar en posiciones rotacionales óptimas teniendo
en cuenta el factor de entrelazado del disco.
216
Ampliación de sistemas operativos
5.5.
Gestión de la E/S en SOBUNIX
5.5.1.
Perspectiva general
En los SOBUNIX los dispositivos de E/S son clasificados en dos grandes categorías :
•
Dispositivos modo bloque. Son aquellos que almacenan la información en bloques de tamaño fijo,
normalmente 5 1 2 bytes o una potencia de dos múltiplo de la anterior. Estos bloques pueden ser
accedidos de forma secuencial o aleatoria. Ejemplos de dispositivos modo bloque son los discos
(magnéticos u ópticos) y las cintas magnéticas.
•
Dispositivos modo carácter. Son aquellos que envían o reciben información como una secuencia
o flujo lineal de bytes. En ellos la información no se organiza con una estructura concreta, por lo
que no es direccionable y en consecuencia no permite la realización de operaciones de búsqueda.
Ejemplos de dispositivos modo carácter son las impresoras, el ratón, el teclado y el módem.
En los SOBUNIX si un dispositivo no encaj a como dispositivo modo bloque entonces se considera
que es un dispositivo modo carácter, independientemente de que tenga las características de este tipo de
dispositivos. Por ejemplo, el reloj hardware no tiene las características de un dispositivo modo bloque ni
las de un dispositivo modo carácter. Luego de acuerdo con el criterio establecido en los SOBUNIX el
reloj hardware se considera un dispositivo modo carácter.
Los SOBUNIX también soportan el uso de pseudodispositivos que son aquellos que se implementan
por software. Ejemplos de pseudodispositivos son el dispositivo nulo, que es un agujero de negro de bits,
y el dispositivo cero, que llena de ceros las paginas de memoria cuya dirección se le suministra como
entrada.
Los SOBUNIX integran los dispositivos de E/S dentro del sistema de archivos principal, general­
mente en el directorio 1 dev, para ello asignan a cada dispositivo un archivo de dispositivo modo bloque
o modo carácter. Esta integración permite operar con los dispositivos de E/S usando las mismas llamadas
al sistema que se utilizan para operar sobre los archivos : open, r ead, wr i t e , etc.
El subsistema de E/S es el componente del núcleo encargado de gestionar las operaciones con los
dispositivos de E/S . Para comunicarse con el controlador de E/ S, el subsistema de E/ S utiliza un código
especifico por cada dispositivo denominado driver del dispositivo. Los drivers son suministrados por los
fabricantes de los dispositivos de E/S existiendo una distribución por cada sistema operativo con lo que
puede funcionar el dispositivo. Los drivers envían órdenes a los controladores de E/ S de los dispositivos
para especificarles la operación que desean realizar. Cuando un dispositivo termina una operación de
E/S, el controlador de E/S del dispositivo avisa al driver correspondiente mediante la generación de
una interrupción. Para atender a dicha interrupción el núcleo invoca al manejador de la interrupción
apropiado.
SOBUNIX : gestión de archivos y gestión de la E/S
5.5.2.
217
Archivos de dispositivos
Número de dispositivo mayor y número de dispositivo menor
En los SOBUNIX cada dispositivo de E/S tiene asignado, en función de su tipo, un archivo de
dispositivo modo bloque o un archivo de dispositivo modo carácter. Recuérdese que la máscara de modo
del archivo que se almacena en el nodo-i del archivo contiene el tipo del archivo. Todos los archivos de
dispositivos generalmente suelen encontrarse aloj ados dentro del directorio 1 dev.
El contenido del nodo-i de un archivo de dispositivo, a diferencia del nodo-i de un archivo regular o
un directorio, no contiene las direcciones de los bloques de datos del archivo sino dos números enteros
positivos denominados : número de dispositivo mayor (major device number) y número de dispositivo
menor (minor device number) .
El número de dispositivo mayor permite identificar a una cierta clase de dispositivo y el número de
dispositivo menor a una instancia de dicho dispositivo.
Por otra parte, cada tipo de dispositivo (bloque o carácter) dispone de un conjunto independiente de
números de dispositivos mayores . Luego un mismo número de dispositivo mayor puede hacer referencia
a dispositivos distintos en función de si es un dispositivo modo bloque o modo carácter.
e
Ejemplo 5. 13
Un número de dispositivo mayor igual a 3 dentro del conjunto de dispositivos modo bloque puede re­
ferirse, por ejemplo, a un cierto tipo de disco duro conectado al computador. Por otra parte, dentro del
conj unto de dispositivos modo carácter un número de dispositivo mayor igual a 3 puede referirse a una
impresora.
Asimismo si existen dos discos duros iguales conectados al computador, tendrán asignado el mismo
número de dispositivo mayor (en este ejemplo 3), pero diferentes números de dispositivos menor, por
ejemplo: 1 y 2.
•
En conclusión en los SOBUNIX la tripleta [tipo de dispositivo, número mayor, número menor] iden­
tifica de manera unívoca a un dispositivo de E/S . Esta información se almacena en el nodo-i del archivo
de dispositivo que representa al dispositivo junto con el resto de atributos del archivo.
e
Ejemplo 5. 14
Supóngase que en un cierto SOB UNIX se representa a uno de los puertos serie del computador mediante
el archivo de dispositivo 1 dev 1 t tyS O . Supóngase además que si escribe en un intérprete de comandos
de este SOBUNIX la orden
ls
-1
/ dev / t tyS O
se muestra en la pantalla la siguiente salida:
c rw- rw- - - - 1 ro o t di a l ou t 4 ,
6 4 2 0 1 1 - 0 9 - 1 4 / dev / t tyS O
218
Ampliación de sistemas operativos
Analizando la información proporcionada por el comando se deduce que / dev / t tyS O es un archivo
asociado a un dispositivo modo carácter, su número de dispositivo mayor es igual a 4 y su número de
dispositivo menor es igual a 64.
•
Llamadas al sistema
La integración de los dispositivos de E/S dentro del sistema de archivos mediante el uso de archivos
de dispositivos permite operar con los dispositivos de E/ S usando las mismas llamadas al sistema que se
utilizan para operar con los otros tipos de archivos : open, read, wri t e , etc. Esta característica de los
S OBUNIX resulta de gran utilidad para los usuarios y los programadores, ya que pueden trabajar con los
dispositivos como si fuesen un archivo más. De esta forma solo necesitan conocer el nombre de ruta del
archivo de dispositivo y se evitan trabaj ar con la tripleta descriptiva del dispositivo que manej a el núcleo.
La creación de un archivo de dispositivo, a diferencia de los archivos regulares, no se realiza con la
llamada al sistema creat sino usando la llamada al sistema mknod, la cual permite crear cualquier tipo
de archivo. Esta llamada tiene la siguiente sintaxis:
r =mknod ( ruta , modo , dev ) ;
Donde ruta es el nombre de ruta absoluta o relativa del archivo que se va a crear y modo es la máscara de
modo del archivo. En el caso de que se desee crear un archivo de dispositivo hay que indicar su número
de dispositivo mayor y su número de dispositivo menor los cuales se codifican haciendo uso por ejemplo
de la macro makedev en una misma variable dev de tipo dev_t denominada número de dispositivo. Si
la llamada al sistema se ejecuta con éxito guarda el valor O en r . En caso de error guarda -l.
También existe un comando mknod que internamente utiliza la llamada al sistema homónima. Tanto
la llamada al sistema como el comando únicamente pueden ser utilizados por el superusuario, excepto
si se desea crear una tubería con nombre (ver sección 3 .5 .2), en cuyo caso pueden ser invocados por
cualquier usuario.
Existen unas pocas llamadas al sistema especiales que únicamente pueden usarse sobre los archivos
de dispositivos. Este es el caso por ejemplo de i o c t l .
Nodos-v y nodos-i d e archivos d e dispositivos
La implementación de los nodos-v y los nodos-i asociados a los archivos de dispositivos depende de
cada SOBUNIX. En algunos S OBUNIX, como por ejemplo SVR4, los nodos-i asociados a los archivos
de dispositivos se almacenan dentro de la partición de disco que contiene el sistema de archivos principal,
que será de un determinado tipo, por ejemplo UFS .
En esta implementación cuando el núcleo realiza una operación sobre el nodo-v de un archivo de
dispositivo, se redirecciona por defecto a una función dependiente del sistema de archivos principal. Por
ejemplo, una operación VO P_OPEN sobre el nodo-v de un archivo de dispositivo redirecciona, en el caso
de un sistema UFS , a la función u f s_open ( ) . Obviamente este no es el comportamiento deseado, sino
que se debe redireccionar a la función apropiada del driver del dispositivo.
SOBUNIX: gestión de archivos y gestión de la E/ S
219
Una de las soluciones adoptadas para resolver este problema consiste en usar una estructura de datos
adicional denominada nodo sombra (nodo-s) que se encarga de realizar esta redirección hacia las fun­
ciones del driver. Todas las operaciones sobre un archivo de dispositivo son redireccionadas a través de
su nodo-s, en vez de a través del nodo-v. Luego el nodo-s a todos los efectos oculta al nodo-v, de ahí
el nombre de nodo sombra. SVR4 usa el pseudosistema de archivos specfs para implementar todos los
nodos-s.
En otros SOBUNIX, como Linux, los nodos-i asociados a los archivos de dispositivos se crean en
tiempo de arranque y se almacenan en un pseudosistema de archivos, como por ejemplo tmpfs, que se
implementa únicamente en la memoria principal sin existir almacenamiento de respaldo en el disco. En
este esquema los nodos-i se integran dentro de los nodos-v. Con lo que solo es necesario mantener una
única estructura de datos asociada al archivo de dispositivo: su nodo-v2 . En dicha estructura existe un
puntero al vector de operaciones sobre el nodo-v el cual redirecciona dichas operaciones directamente
hacía las funciones del driver adecuadas.
5.5.3.
Subsistema de E/S
El subsistema de E 1 S es el componente del núcleo que se encarga de efectuar todas aquellas tareas
necesarias para la realización de las operaciones de E/S que son comunes a todos los dispositivos e inde­
pendientes de los mismos. Es decir, el subsistema de E/ S gestiona la parte independiente del dispositivo
de todas las operaciones de E/S . Entre las tareas que realiza se encuentran las siguientes : asignación y
protección de dispositivos, bloqueo de procesos en operaciones de E/S , planificación de la E/S, gestión
de los errores producidos en la E/S, gestión de los drivers de los dispositivos y almacenamiento temporal
de datos (buffering).
Con respecto al almacenamiento temporal de datos asociados a operaciones de E/ S en los SOBUNIX
se implementa una caché de buffers de bloques de disco. Se trata de un espacio reservado en la memoria
principal para almacenar los bloques de datos del disco accedidos recientemente. Cada bloque de datos se
almacena en un buffer de memoria principal. Para localizar rápidamente a los buffers el núcleo mantiene
varias colas hash de buffers a las que se accede en función del número de dispositivo y el número de
bloque.
Cuando el núcleo desea leer un bloque del disco, primero comprueba si existe dicho bloque en la
caché. En caso afirmativo el bloque es leído de la caché. En caso negativo, el bloque debe leerse en el
disco y cargarse en un buffer libre. Si no existe ningún buffer libre, deberá seleccionarse algún buffer
mediante el uso de algún algoritmo de reemplazamiento. En conclusión, con el uso de la caché de buffers
se pretende minimizar las operaciones de E/S a disco, las cuales son varios órdenes de magnitud más
lentas que los accesos a memoria principal.
En el caso de las operaciones de escritura primero se realizan sobre la caché. Periódicamente o si el
número de bloques escritos supera un cierto valor los bloques escritos son transferidos por el núcleo al
disco. Normalmente existe un proceso del sistema que se encarga de realizar esta tarea.
En los sistemas SOBUNIX modernos la operaciones de E/S sobre archivos se integran dentro de la
2En Linux no hacen uso de la terminología nodo-v, sino que directamente le denominan nodo-i.
220
Ampliación de sistemas operativos
memoria virtual. En estos sistemas la caché de buffers de bloques de disco se utiliza generalmente para
almacenar solo los bloques de datos que contienen metadatos de los sistemas de archivos o los archivos :
superbloque, nodos-i, bloques d e indirección simple, doble, etc. Por otra parte, los bloques d e datos
lógicos de un archivo son divididos en páginas. Cada página de un archivo puede contener, en función
del tamaño de bloque y del tamaño de página, parte de un bloque, un bloque o varios bloques de datos
del archivo. Estás páginas se cargan en la caché de páginas que se implementa en la memoria principal
la cual es gestionada por el subsistema de gestión de memoria principal del núcleo.
5.5.4.
Drivers de los dispositivos de E/S
Un driver de un dispositivo contiene el código que permite al núcleo controlar un determinado tipo
de dispositivo de E/S . Así, es necesario un driver para el ratón, otro para el teclado, otro para el disco
duro, etc. Los drivers son diseñados por los fabricantes de los dispositivos teniendo en cuenta las especi­
ficaciones de la interfaz de drivers del subsistema de E/ S del núcleo y las características del dispositivo.
Un driver de un dispositivo interactúa con el subsistema de E/S del núcleo y con el controlador de
E/ S que controla el dispositivo. Un driver puede invocar a ciertas rutinas del núcleo para realizar diversas
tareas, como por ejemplo, asignación de memoria y control del DMA. Además suministra al subsistema
de E/S el conjunto de funciones que se pueden realizar sobre el dispositivo.
Los drivers de dispositivos en SOBUNIX son parte del código del núcleo y se ejecutan en modo
núcleo. El núcleo puede invocar a un driver por diferentes causas [Vahalia, 1 995] :
•
Configuración. Cuando se arranca el sistema operativo el núcleo invoca a los drivers de los dispo­
sitivos para inicializar los dispositivos.
•
E/S . El subsistema de E/S del núcleo invoca a un driver para leer o escribir datos en un cierto
dispositivo.
•
Control. Un usuario puede solicitar realizar operaciones de control sobre un cierto dispositivo,
como por ejemplo rebobinar una cinta magnética, o abrir o cerrar un cierto dispositivo.
•
Interrupciones. Los controladores de E/S generan interrupciones cuando se ha completado una
operación de E/S sobre el dispositivo que supervisan o se ha producido algún cambio en su esta­
do. Las interrupciones son tratadas por los manipuladores de las interrupciones. Un manipulador
de una interrupción, entre otras tareas, debe despertar al driver del dispositivo, si éste se había
bloqueado en espera de que el controlador de E/S estuviera preparado para procesar otra petición
de E/S .
La invocación de operaciones del drivers debido a E/S o control se realiza de forma síncrona. Mien­
tras que la invocación de operaciones del driver debido a la aparición de interrupciones se realiza de
forma asíncrona.
Atendiendo a las diferentes formas de invocar a las operaciones de un driver se distinguen en su
diseño dos partes :
SOBUNIX: gestión de archivos y gestión de la E/S
221
•
Parte superior (top half). Contiene las rutinas del driver que se invocan de forma síncrona. Estas
rutinas se ejecutan en el contexto del proceso cuya ejecución ha producido la invocación del driver.
Pueden acceder al espacio de direcciones y al área-u del proceso invocador, además pueden poner
al proceso a dormir si fuese necesario.
•
Parte inferior (bottom half). Contiene las rutinas del driver que se pueden invocar de forma asín­
crona. Se ejecutan en el contexto del núcleo e interactúan con el controlador de E/ S del dispositivo
cargando en sus registros diferentes órdenes para que las efectúe sobre el dispositivo, comprobando
su estado e inicializándolo, si es necesario.
En los SOBUNIX, el núcleo mantiene dos tablas denominadas tablas de conmutación. Cada entrada
de una tabla de conmutación está asociada a un determinado driver y contiene una estructura de datos
con punteros a las funciones que implementan las operaciones soportadas por dicho driver. Existe una
tabla de conmutación para los drivers de los dispositivos modo bloque y otra tabla de conmutación para
los drivers de los dispositivos modo carácter.
Cuando el núcleo desea realizar alguna operación sobre un determinado dispositivo, en primer lugar
en función del tipo de dispositivo (bloque o carácter) selecciona la tabla de conmutación adecuada. A
continuación localiza la estructura de datos del driver en la tabla de conmutación usando el número
mayor del dispositivo e invoca a la función apropiada del driver. Esta función recibe del núcleo, entre
otros argumentos, el número mayor y el número menor del dispositivo. El driver mantiene unas tablas
internas para traducir estos números a la dirección del registro de control o puerto del controlador de E/S
del dispositivo especificado.
Nótese que es la interfaz del subsistema de E/ S del núcleo la que define las operaciones que debe ser
capaz de soportar un driver de un dispositivo, como por ejemplo: d_open ( ) , d_c l o s e ( ) , d_read ( ) ,
d_wr i t e ( ) y d_i o c t l ( ) . Los diseñadores del driver deben ajustarse a dicha interfaz. Ahora bien, un
driver puede que no soporte todas las operaciones de la interfaz. Por ejemplo, un driver de impresora
no necesita implementar una operación de lectura. En el caso de que el núcleo solicite una operación
no soportada por un driver, éste le devuelve un código de error ENODEV. También puede ocurrir que una
operación sobre un determinado driver no suponga la realización de ninguna acción por parte del driver.
Por ejemplo, muchos drivers no realizan ninguna acción para implementar una operación d_c l o s e ( ) ,
en dicho caso el driver implementa una rutina genérica que devuelve un O al núcleo para indicarle que la
operación se ha realizado correctamente.
Cada driver recibe un prefijo identificativo que depende de cada SOBUNIX. Dicho prefijo se utiliza
en todas las operaciones de dicho driver que son invocadas a través de la tabla de conmutación corres­
pondiente. Por ejemplo, en Solaris un driver del disco suele tener asociado el prefijo dk, luego el nombre
de sus operaciones empezará con dicho prefijo: dkread ( ) , dkwr i te ( ) , etc.
5.5.5.
Tratamiento de las interrupciones
La mayoría de SOBUNIX asignan a cada tipo de interrupción un número entero positivo denominado
nivel de prioridad de la interrupción (npi), que puede tomar valores comprendidos dentro del rango
222
Ampliación de sistemas operativos
[npimil� > npimaxl · Generalmente npim in es igual a O y corresponde a la prioridad más baj a. Los procesos de
los usuarios y la mayor parte del código del núcleo se ejecutan con este nivel de prioridad.
El valor de npimax depende de cada S OBUNIX. Por ejemplo en Solaris npimax = 1 5, mientras que en
BSD npimax=3 1 .
La configuración del npi a un determinado valor bloquea o enmascara todas las interrupciones con
npi igual o inferior. De esta forma se consigue priorizar la atención de las interrupciones. Por ejemplo, en
Solaris cuando llega una interrupción de reloj el npi se configura a 1 0, ello impide que se puedan atender
interrupciones con npi igual o inferior a 1 0, como es el caso, por ejemplo, de las interrupciones de disco
(npi=4) o las interrupciones de dispositivos de red (npi=7). Dichas interrupciones serán atendidas cuando
disminuya el valor del npi al valor apropiado.
El valor del npi se almacena en el registro de estado del procesador. Cada arquitectura suele in­
cluir diferentes instrucciones máquina especiales que permiten configurar el valor del npi. Además el
núcleo implementa en su núcleo diferentes funciones para configurar este valor haciendo uso de estas
instrucciones máquina.
Generalmente cuando se detecta una interrupción en un procesador se ejecuta una rutina genérica del
núcleo de tratamiento de las interrupciones que se encarga de salvar el contexto hardware del proceso
actualmente en ejecución, elevar el npi de acuerdo con el tipo de interrupción e invocar al manejador de
la interrupción apropiado. Cuando el manej ador de la interrupción completa su ejecución se devuelve
el control a la rutina genérica que disminuye el valor del npi al valor que tenía antes de atender la
interrupción y restaura el contexto hardware del proceso que se estaba ejecutando.
Puesto que el tratamiento de las interrupciones es una tarea crítica para el buen rendimiento del
sistema, los manej adores de las interrupciones suelen ser tener un código pequeño que varía en función
de la arquitectura hardware y que es rápido de ejecutar. Además su prioridad de ejecución es muy elevada.
En algunos SOBUNIX los manejadores se implementan como rutinas del núcleo que se ejecutan en
el contexto del proceso actualmente en ejecución. En otros SOBUNIX, como Solaris, los manej adores
de interrupciones se implementan como hilos del núcleo independientes no asociados a ningún proceso.
5.6.
Conectores
Los conectores (sockets) son uno de los principales mecanismos usados en los SOBUNIX para im­
plementar las conexiones en red. Otro mecanismo muy utilizado son los STREAMS [Vahalia, 1 995] . Un
conector permite establecer un canal de comunicación a través de una red (o localmente dentro de un
mismo computador) entre un proceso emisor y un proceso receptor (ver Figura 5 . 1 1 ) .
Los conectores son implementados mediante archivos que s e crean y s e eliminan dinámicamente. Un
conector se crea invocando a la llamada al sistema
r = s o c ke t ( f ami l i a , t ipo , pro t o c o l o ) ;
Esta llamada presenta los siguientes parámetros de entrada [Márquez, 2004] :
•
f ami l i a. Especifica la familia de direcciones o protocolos que se desea emplear. Dichas familias
SOBUNIX: gestión de archivos
.;--v
Pro � es
emisor
¡.- Espacio
� _...Conector
.
1
y
Red
---+
del usuario
Espacio
¡.- del núcleo
---+
y
gestión de la E/S
223
�
Conecto!:...
�
1
roceso
receptor
y
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
L--------------------------------------------------�
Figura 5 . 1 1
-
Comunicación en red mediante el uso de conectores
suelen estar definidas generalmente en el archivo de cabecera sys 1 s o cket . h. Dos de las familias
más usadas son:
- AF_UNIX (o PF_UNI X ) . Protocolos internos de UNIX. Esta familia se utiliza para comunicar
procesos que se ejecutan en la misma máquina. En consecuencia no requiere de la existencia
de una tarjeta de red en el computador ya que no la utiliza.
- AF_INET (o PF_INET ) . Protocolos de Internet, como por ejemplo TCP o UDP.
•
t ipo. Establece la semántica de conexión para el conector. Entre otros, puede tomar, los siguientes
valores :
- SOCK_STREAM. Conector con un protocolo orientado a conexión. Consiste en realizar una
búsqueda de enlaces libres que unan los dos computadores que se quieren conectar. Una vez
establecida la conexión se pueden enviar los datos en orden secuencial, como si fuese una
tubería, ya que la conexión es permanente y fiable.
- socK_DGRAM. Conector con un protocolo no orientado a conexión o datagrama. Se trata de
conexiones no permanentes o fiables. La transmisión por datagramas se realiza a nivel de
paquetes. Cada paquete puede seguir una ruta distinta. Además la recepción de los paquetes
puede no ser secuencial.
•
pro t o c o l o . Permite especificar el protocolo particular que se va utilizar dentro de una determina­
da familia. Normalmente cada tipo de conector tiene asociado un determinado protocolo, pero en
el caso de que existiera más de uno, se especifica el adecuado con este parámetro. Si este parámetro
se configura con el valor O, entonces la elección del protocolo se delega en el núcleo.
Si durante la ejecución de esta llamada al sistema se produce algún error entonces en r se almacena
el valor -l. Si la llamada se ejecuta con éxito entonces en r se almacena el descriptor de archivo asociado
al conector.
224
e
Ampliación de sistemas operativos
Ejemplo 5 . 15
La llamada al sistema
f d= s o c k e t ( AF_UNIX , SOCK_STREAM , O ) ;
intenta crear un conector orientado a conexión ( SOCK_STREAM) que utilizará los protocolos internos de
UNIX (AF_UNIX) . El protocolo utilizado será escogido por el núcleo ( 0 ) . Si la llamada se ejecuta con
éxito entonces almacena en fd el descriptor del archivo asociado al conector. En caso de error almacena
el valor -l.
•
Antes de poder usar un conector se le debe asociar una dirección particular dentro de la familia de
protocolos seleccionada. Para ello se debe utilizar la llamada al sistema bind.
Una vez creado un conector orientado a conexión con una dirección particular asociada en cada uno
de los dos computadores X e Y que se desean comunicar por red es posible establecer una conexión entre
los dos computadores. Un proceso A en el computador X debe realizar una llamada al sistema l i s t en
sobre su conector, la cual crea un buffer y bloquea al proceso hasta que llegan datos por la red.
Otro proceso B en el computador Y debe realizar una llamada al sistema c onnec t pasándole como
parámetros de entrada el descriptor de su conector local en Y y la dirección del conector en la compu­
tadora X. Si el proceso A acepta la conexión entonces se puede establecer una comunicación entre los
conectores.
El funcionamiento de una conexión entre conectores es similar al de una tubería. Un proceso puede
leer o escribir de su conector local de la misma forma que a cualquier otro tipo de archivo, es decir,
usando las llamadas al sistema read o wr i t e . Cuando un proceso termina de usar una conexión debe
cerrarla usando la llamada al sistema e l o s e .
Los conectores aparte d e read disponen de las siguientes llamadas al sistema adicionales para leer
datos en ellos : r eadv, re cv, recvfrom y recvms g. Asimismo disponen de las siguientes llamadas
para escribir datos: wr i t ev, s end, s endto y s endms g.
5.7.
Resumen
En los SOBUNIX se distinguen los siguientes tipos de archivos : ordinarios o regulares, directorios,
especiales (asociados a dispositivos), tuberías, conectores y enlaces simbólicos. Para que un proceso
pueda poder operar sobre un archivo, éste primero tiene que ser abierto mediante la invocación de la
llamada al sistema open. La rutina del núcleo del sistema operativo que trata esta llamada al sistema crea
en la memoria principal una estructura de datos denominada objeto de archivo abierto y asigna a dicha
estructura un número entero positivo pequeño denominado descriptor de archivo para identificarla. La
llamada al sistema open devuelve el descriptor del archivo abierto al proceso que invocó la llamada. Para
poder operar sobre un archivo abierto el proceso debe pasar el descriptor del archivo como argumento de
las llamadas al sistema asociadas a las operaciones que desee realizar sobre el archivo.
SOBUNIX: gestión de archivos y gestión de la E/S
225
En los sistemas de archivos desarrollados para SOBUNIX una entrada de una lista de un directo­
rio contiene, entre otras informaciones, el número del nodo-i asociado a un archivo y su nombre. Los
SOBUNIX implementan una estructura de directorios de gráfica acíclica.
Durante el proceso de instalación de un SOBUNIX se realiza un formateo a alto nivel de una partición
del disco duro para crear el sistema de archivos principal donde se aloja el directorio raíz 1 . Cada
SOBUNIX establece el tipo de sistema de archivos principal que crea. Aparte de este sistema de archivos
principal los SOBUNIX son capaces de reconocer y manipular otros sistemas de archivos del mismo o
distinto tipo ubicados en memoria secundaria.
'
'
Los SOBUNIX modernos para soportar distintos tipos de archivos implementan una capa de software
denominada capa nodo-v/sistema de archivos virtual. Cualquier operación sobre un archivo o sobre un
sistema de archivos completo invocada por el usuario a través de una llamada al sistema o internamente
por algún subsistema del núcleo es redireccionada por la capa nodo-v 1 sistema de archivos virtual hacía la
rutina dependiente del sistema de archivos al que pertenezca el archivo que da soporte a dicha operación.
UFS es un sistema de archivos soportado por diversos SOBUNIX. Deriva del sistema de archivos
FFS de BSD y presenta la siguiente estructura en la partición de disco donde se crea: área de arranque,
superbloque y grupos de cilindros. El área de arranque contiene el código necesario para arrancar el SO­
BUNIX si dicha partición se usa como partición activa. El superbloque contiene información estadística
y administrativa del sistema de archivo, como por ejemplo: un número mágico que identifica al sistema
como de tipo UFS , el número, el tamaño y la localización de los grupos de cilindros, el tamaño de blo­
que de datos que se utiliza, el número total de bloques de datos y de nodos-i, etc. Un grupo de cilindros
está formado por un conjunto de cilindros contiguos. El número de grupos de cilindros y el número de
cilindros que contiene un grupo son configurados cuando se crea el sistema de archivos UFS . Cada gru­
po de cilindro contiene la siguiente información: una copia del superbloque, una estructura de grupo de
cilindros que contiene información estadística y administrativa del grupo de cilindros, mapas de bits para
conocer cuales son los bloques, fragmentos y nodos-i libres en el grupo de cilindros, y nodos-i del grupo
de cilindros.
Los SOBUNIX integran los dispositivos de E/S dentro del sistema de archivos principal, general­
mente en el directorio 1 dev, para ello asignan a cada dispositivo un archivo de dispositivo modo bloque
o modo carácter. Esta integración permite operar con los dispositivos de E/ S usando las mismas llamadas
al sistema que se utilizan para operar sobre los archivos : open, read, wr i te, etc.
El contenido del nodo-i de un archivo de dispositivo, a diferencia del nodo-i de un archivo regular o
un directorio, no contiene las direcciones de los bloques de datos del archivo sino dos números enteros
positivos denominados: número de dispositivo mayor y número de dispositivo menor. El número de
dispositivo mayor permite identificar a una cierta clase de dispositivo y el número de dispositivo menor
a una instancia de dicho dispositivo.
El núcleo generalmente mantiene dos tablas denominadas tablas de conmutación. Existe una tabla
de conmutación para los drivers de los dispositivos modo bloque y otra tabla de conmutación para los
drivers de los dispositivos modo carácter. Cada entrada de una tabla de conmutación está asociada a un
determinado driver y contiene una estructura de datos con punteros a las funciones que implementan las
operaciones soportadas por dicho driver.
226
Ampliación de sistemas operativos
En relación con las conexiones en red, los conectores (sockets) son uno de los principales mecanis­
mos usados en los SOBUNIX para implementarlas. Un conector permite establecer un canal de comu­
nicación a través de una red (o localmente dentro de un mismo computador) entre un proceso emisor y
un proceso receptor. Los conectores son implementados mediante archivos que se crean y se eliminan
dinámicamente.
5.8.
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pueden
consultar, por ejemplo: los capítulos 8 y 9 de [Vahalia, 1 995] , los capítulos 2, 3, 4 y 1 1 de [Márquez,
2004] , los capítulos 14 y 15 de [McDougall y Mauro, 2006] y el capítulo 10 de [Tanenbaum, 2009] .
5.9.
Autoevaluación
5. 1 . ¿Cómo se estructura la información contenida en un archivo en los SOBUNIX? ¿Qué tipos de
acceso a los archivos soportan? (Respuesta en sección 5 . 2 . 1)
5 .2. Explicar razonadamente si en los SOBUNIX el nombre de un archivo puede tener una extensión.
(Respuesta en sección 5 . 2 . 1)
5 .3. Enumerar y explicar brevemente los tipos de archivos soportados en los SOBUNIX.
(Respuesta en sección 5 . 2 . 1)
5 .4 . Enumerar los atributos de un archivo soportados en los SOBUNIX. ¿Qué llamadas al sistema y
comandos pueden usarse para visualizar los atributos de un archivo? (Respuesta en sección 5 . 2 . 1)
5 . 5 . ¿Qué es un descriptor de un archivo? ¿Cómo se obtiene? (Respuesta en sección 5.2.1)
5 . 6 . ¿Qué es una tabla de descriptores de archivos? ¿Qué información contiene una de sus entradas?
¿A quién están asignadas por defecto las tres primeras entradas de la tabla?
(Respuesta en sección 5 . 2 . 1)
5 .7 . ¿Qué es un objeto de archivo abierto? ¿Cuándo se crea? Enumerar y explicar la información que
contiene. (Respuesta en sección 5 . 2 . 1)
5 . 8 . Explicar la utilidad y la sintaxis de cada una de las siguientes llamadas al sistema: c r e a t , open,
e l o s e , read, wr i te, l s e ek, s t a t , f s ta t y fcnt l . (Respuesta en sección 5 . 2 . 1)
5. 9. En los sistemas de archivos desarrollados para los SOBUNIX ¿qué información suele contener una
entrada de una lista de un directorio? (Respuesta en sección 5 . 2.2)
5. 10. ¿Qué tipo de estructura de directorios suelen implementar los SOBUNIX? ¿Qué carácter se utiliza
en los SOBUNIX para representar al directorio raíz y separar los componentes de un nombre de
ruta? (Respuesta en sección 5 .2.2)
SOBUNIX: gestión de archivos y gestión de la E/ S
227
5. 1 1 . Explicar la utilidad y la sintaxis de cada una de las siguientes llamadas al sistema: chdi r, mkd i r
y rmd i r . (Respuesta e n sección 5 . 2.2)
5 . 12. ¿Qué es un enlace duro? ¿ Y un enlace simbólico?. (Respuesta en sección 5 .2.3)
5. 13. Explicar el funcionamiento del contador de enlaces duros del nodo-i de un directorio.
(Respuesta en sección 5.2.3)
5. 14. ¿Cuántos nombres puede tener un archivo en SOBUNIX? ¿Y un directorio?
(Respuesta en sección 5 .2.3)
5. 15. ¿Qué mascara de modo simbólica tiene asociada un enlace simbólico? (Respuesta en sección 5 .2.3)
5 . 16. ¿Qué llamadas al sistema y comandos pueden utilizarse para crear enlaces duros y simbólicos ? ¿ Y
para eliminarlos? (Respuesta en sección 5 .2.3)
5 . 17. ¿Qué es un punto de montaje? ¿ Y la tabla de montaje? (Respuesta en sección 5 . 2 .4)
5. 18. ¿Cómo se realiza el acceso a un directorio o a un archivo perteneciente a un sistema de archivos
montado sobre el sistema de archivos principal? (Respuesta en sección 5 . 2 .4)
5. 19. Explicar la utilidad de los siguientes comandos: moun t , umount , mk f s , f s c k y d f .
(Respuesta e n sección 5 . 2 .4)
5 .20. ¿Cuál es la utilidad de la capa nodo-v/SAV? (Respuesta en sección 5.3)
5 .21 . ¿Qué es un nodo-v? ¿Cuándo se asigna? ¿Qué función realiza? (Respuesta en sección 5 . 3 . 1)
5 .22. Explicar el funcionamiento del contador de referencias de un nodo-v y enumerar las circunstancias
en que se incrementa. (Respuesta en sección 5 . 3 . 1)
5 .23. Enumerar y explicar brevemente la información contenida en la estructura de datos que implementa
un nodo-v (Respuesta en sección 5 . 3 . 1)
5 .24. ¿Qué es un sistema de archivos virtual? ¿Cuándo se asigna? ¿Qué función realiza?
(Respuesta en sección 5 . 3 .2)
5 .25 . Enumerar y explicar brevemente la información contenida en la estructura de datos que implementa
un SAV. (Respuesta en sección 5 . 3 .2)
5 .26. Explicar cómo se realiza el análisis de nombres de rutas en los SOBUNIX que implementan la
capa nodo-v/SAV. (Respuesta en sección 5 . 3 . 3 )
5 .27. Explicar la información que contiene y cómo se utiliza la caché de búsqueda de nombres en direc­
torios en los SOBUNIX. (Respuesta en sección 5 . 3 .3)
5 .28. Enumerar las principales características de un sistema de archivos UFS . (Respuesta en sección 5.4.1)
228
Ampliación de sistemas operativos
5 .29. Dibujar un diagrama que represente la estructura en una partición de disco de un sistema de archi­
vos UFS . Explicar la información contenida en cada uno de sus componentes.
(Respuesta en sección 5 .4.2)
5 .30. Explicar cómo se implementan los directorios en un sistema de archivos UFS .
(Respuesta en sección 5 .4.3)
5 .3 1 . ¿Qué es un nodo-im? ¿Qué información contiene? (Respuesta en sección 5 .4.4)
5 .32. ¿Cuándo se coloca un nodo-im en la lista de nodos-im libres? ¿Dé que depende la posición de un
nodo-im en esta lista? (Respuesta en sección 5.4.4)
5 .33. ¿Qué sucede si el núcleo no localiza a un nodo-im en la cola hash donde le correspondería estar?
(Respuesta en sección 5 .4.4)
5 .34. Explicar cómo se realiza la asignación de espacio en un sistema de archivos UFS .
(Respuesta en sección 5 .4.5)
5 . 35 . Enumerar y explicar las dos grandes categorías en que se clasifican los dispositivos de E/S en los
S OBUNIX. (Respuesta en sección 5 . 5 . 1)
5 .36. ¿Qué son los pseudodispositivos ? (Respuesta en sección 5 . 5 . 1)
5. 37. Explicar cómo se integran los dispositivos de E/ S dentro del sistema de archivos.
(Respuesta en sección 5.5 .2)
5. 38. Explicar la utilidad del número de dispositivo mayor y del número de dispositivo menor. ¿Dónde
se aloj a esta información? (Respuesta en sección 5 . 5 .2)
5 .39. Explicar la utilidad y la sintaxis de la llamada al sistema mknod (Respuesta en sección 5 . 5 .2)
5 .40. Comentar las diferentes soluciones adoptadas en los SOBUNIX para implementar los nodos-v y
los nodos-i de los archivos de dispositivos. (Respuesta en sección 5 . 5 .2)
5 .41 . Explicar la información que contiene y cómo se utiliza la caché de buffers de bloques de disco en
los S OBUNIX. (Respuesta en sección 5 .5 .3)
5 .42. Explicar cómo se integran las operaciones de E/S sobre archivos dentro de la memoria virtual.
(Respuesta en sección 5 .5 . 3 )
5 .43. ¿Dónde se integra y en qué modo se ejecuta un driver de un dispositivo en los SOBUNIX?
(Respuesta en sección 5 .5 .4)
5 .44. Enumerar y comentar brevemente las principales causas por las que el núcleo puede invocar a un
driver de un dispositivo en los SOBUNIX. (Respuesta en sección 5 . 5 .4)
SOBUNIX: gestión de archivos y gestión de la E/S
229
5.45 . Explicar las partes que se distinguen en el diseño de un driver de un dispositivo en SOBUNIX
atendiendo a las diferentes formas de invocar sus operaciones. (Respuesta en sección 5 . 5 .4)
5 .46. ¿Qué son las tablas de conmutación mantenidas en los SOBUNIX? ¿Para que se utilizan?
(Respuesta en sección 5 . 5 .4)
5.47. ¿Quién define las operaciones que debe ser capaz de soportar un driver de un dispositivo? ¿Qué
indica el código de error ENODEV? (Respuesta en sección 5 . 5 .4)
5.48. Explicar cómo se realiza el tratamiento de las interrupciones en los SOBUNIX.
(Respuesta en sección 5 .5 .5)
5 .49. ¿Qué son los conectores? (Respuesta en sección 5 .6)
5 .50. Explicar la utilidad de las siguientes llamadas al sistema: s o cke t , bind, l i s t en y c onne c t .
(Respuesta en sección 5 .6)
5. 51 . ¿Cómo se puede leer o escribir en un conector? (Respuesta en sección 5. 6)
5.10.
Ejercicios
5. 1 Explicar el significado de las siguientes llamadas al sistema:
a) fd=open ( " da t o s . txt " O_RDWR J O_APPEND ) ;
1
b) fd=open ( " prueba " O_RDONLY J O_CREAT 0 6 0 0 )
1
1
;
5 .2 El nodo-i de un archivo tiene el valor 1 en su contador de enlaces duros. ¿Qué sucede si se aplica
sobre dicho archivo la llamada al sistema o el comando un l ink?
5 .3 Escribir un programa en C que ilustre el uso de la llamada al sistema s t a t .
5 .4 En el directorio de trabaj o actual de un usuario residen los ficheros wer t . t x t (ver Figura 5 . 1 2) y
j 1 0 (ver Figura 5 . 1 3 ) .
a) Explique detalladamente e l funcionamiento d e este programa s i s e invoca desde u n intérprete
de comandos mediante la orden: j 1 0 2 5 wer t . txt
b) Comprobar que la respuesta dada en el apartado anterior es correcta compilando y ejecutando
este programa en un SOBUNIX.
5 . 5 Ejecutar en un intérprete de comandos de un SOBUNIX la orden d f . Consultar el manual de ayuda
man para explicar la funcionalidad de este comando y el significado de la salida que muestra en la
pantalla.
5 . 6 Determinar el tamaño máximo que en teoría podría tener un archivo en un sistema de archivos
UFS si se utiliza un tamaño de bloque de 8 KiB .
230
Ampliación de sistemas operativos
El s i s t ema ope r a t ivo UNIX es un s i s t ema mu l t iusuar i o y mu l t iproc e s o \ n
e s c r i t o e n l engua j e C que d e s d e su nac imi ento a p r i n c i p i o s d e l a \ n
déc ada de l o s s e t en t a h a i do a l c a n z ando bas tan t e éxi t o y popu l a r i da d \ n
tanto en e l ámb i t o un ive r s i t ar i o c omo en e l emp r e s ar i a l . \ n
Figura 5.12 -
Primeras líneas del archivo wert . txt
# i nc l ude < s t d l ib . h>
# i n c l ude < s t d i o . h>
# in c l ude < f c n t l . h>
vo i d try ( i n t ,
ma in ( i nt np ,
{
char * ) ;
char * pe [ ] )
int x , T , h , a ;
char * L ;
if
( np = = 3 )
{
x = a t o i ( pe [ l ] ) ;
L = ( char * ) ma l l o c ( ( x& ( x - l ) ) * s i z e o f ( char ) ) ;
f o r ( h = O ; h< = ( ( x& ( x - 1 ) ) - 2 ) ; h+ + )
* ( L +h ) = ' \ 0 ' ;
a = open ( p e [ 2 ] , 0_RDWR ) ;
t ry ( a , L ) ;
l s eek ( a , x , x %2 ) ;
t ry ( a , L ) ;
exi t ( 3 ) ;
vo i d try ( i n t y ,
char * U )
read ( y , u , 1 5 ) ;
p r i nt f ( " \ n \ " %s \ " \ n " , u ) ;
Figura 5.13 -
Código C del programa j 1 0 del Ejercicio 5.4
Capítulo 6
SOBUNIX: el sistema operativo Linux
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes :
•
Conocer los orígenes y la naturaleza de Linux.
•
Saber cómo se implementa la gestión de procesos e hilos en Linux.
•
Conocer los detalles de la implementación de la planificación de tareas en Linux.
•
Conocer cómo se realiza la gestión de memoria en Linux.
•
Conocer las particularidades de la implementación de la gestión de archivos en Linux.
•
Conocer las principales características de los sistemas de archivos nativos de Linux: EXT2, EXT3
y EXT4.
6.1.
Introducción
Este capitulo está dedicado al estudio de las particularidades más reseñables de Linux, el SOBUNIX
de código abierto más conocido y utilizado. En primer lugar se incluyen una serie de consideraciones
generales sobre Linux. En concreto se comentan los orígenes y las diferencias entre versiones y distri­
buciones de Linux. En segundo lugar se describen las particularidades de la gestión de procesos e hilos
en Linux. En tercer lugar se describe la planificación de tareas en Linux, distinguiendo entre la planifi­
cación utilizada antes y después de la versión 2.6.23 . En cuarto lugar se analiza la implementación de
la gestión de memoria en Linux, describiendo tanto la gestión del espacio de direcciones virtuales como
la gestión de la memoria física. La última parte del capítulo está dedicada al estudio de las particula­
ridades de la gestión de archivos en Linux. En concreto se describe cómo se implementa en Linux la
23 1
232
Ampliación de sistemas operativos
capa nodo-v/sistema de archivos virtual. Además se estudian los sistemas de archivos nativos de Linux:
EXT2, EXT3 y EXT4.
Conviene señalar que en la exposición de los contenidos de este capítulo se presupone que el lector
ya se ha leído los cinco capítulos anteriores dedicados al estudio de los SOBUNIX. También conviene
tener presente que obviamente por motivos de espacio este capítulo no es más que un pequeño resumen
de las particularidades del núcleo de Linux. Los lectores que deseen profundizar en su estudio pueden
consultar las referencias bibliográficas reseñadas en la sección 6 . 8 .
6.2.
Consideraciones generales sobre Linux
6.2.1.
Orígenes de Linux
Linux es un SOBUNIX cuyo núcleo en su primera versión fue escrito en 199 1 por Linus Benedict
Torvalds, por aquel entonces un estudiante finlandés de veintiún años. Linus creó Linux 1 por hobby ya
que no estaba satisfecho con el rendimiento del sistema operativo MS-DOS del PC Intel 386 que se
había comprado; escribió Linux en C tomando como base el sistema operativo MINIX desarrollado por
Andrew S. Tanenbaum.
Linus deseaba compartir su trabaj o con otras personas por ello colgó en Internet el código fuente
de Linux, primero con una licencia propia de tipo freeware y posteriormente con una licencia GPL del
proyecto GNU. El acceso libre y gratuito al código fuente de Linux ha propiciado que miles de personas
en todo el mundo colaboren con Linus desinteresadamente en el desarrollo y mejora de este sistema
operativo.
En la actualidad Linux ha sido portado a diferentes arquitecturas hardware y continúa evolucionando.
Además cada vez interesa a más usuarios y empresas ya que, aparte de ser gratuito, es comparable en
potencia y flexibilidad a otros sistemas operativos comerciales.
6.2.2.
Versiones del núcleo de Linux
Cada versión del núcleo de Linux2 tiene asignada un identificador numérico. Hasta la versión 2.5 el
identificador podía constar de hasta tres número enteros positivos: v . T . R. Si T era un número par signi­
ficaba que se trataba de una versión estable del núcleo, mientras que si era un número impar significaba
que se trataba de una versión en desarrollo. En las versiones en desarrollo se pretendía añadir nuevas
funcionalidades al núcleo. Ello suponía la realización de cambios importantes sobre los algoritmos y las
estructuras del núcleo, lo que hacía que estas versiones no fueran muy estables. Por ejemplo, de acuer­
do con este criterio la versión 1 .2 es una versión estable mientras que la versión 1 .3 es una versión en
desarrollo.
Por otra parte, el número R denota el número de lanzamiento o liberación (release) de dicha versión.
Cada liberación incluye pequeñas modificaciones y corrige los errores que se hayan detectado desde la
1 El nombre de Linux surge como una contracción de las palabras Linus y UNIX.
2En la web www.kemel .org puede descargarse el código fuente de las últimas versiones aparecidas del núcleo de Linux.
SOBUNIX: el sistema operativo Linux
233
liberación anterior. Por ejemplo, la versión 1 .2.2 incluye pequeños cambios y corrección de errores en
relación con la versión 1 .2. 1 .
Desde la versión 2.6 el identificador numérico de la versión puede constar de hasta cuatro números
enteros positivos: v . T . R . x. Ahora el número T ya no denota si se trata de una versión estable o en
desarrollo. Cada nueva liberación R de una versión v . T puede incluir cambios importantes incluso en
componentes claves del núcleo por lo que es potencialmente inestable. Esto sucedía por ejemplo entre las
versiones 2.6. 1 O y 2.6. 1 1 . Para corregir los problemas que se van encontrando en una versión y conseguir
que sea estable se liberan sucesivas versiones parcheadas que se identifican con el número X.
Para conocer la versión del núcleo de Linux que se está utilizando se puede usar el comando
uname - r
Señalar que en este capítulo s e toman como base las versiones 2.6. 1 1 y 2.6.24 del núcleo de Linux.
6.2.3.
Distribuciones Linux
En Internet puede encontrarse el código fuente del núcleo de Linux, así como diversos programas
(intérpretes de comandos, compiladores, etc) y aplicaciones (escritorios, navegadores web, gestores del
correo electrónico, etc) que se ejecutan en Linux, la mayoría de ellos procedentes del proyecto GNU
y de la Free Software Foundation. La tarea de buscar, compilar e instalar un sistema Linux (núcleo +
programas + aplicaciones) en un computador partiendo desde cero es una tarea bastante laboriosa que
debe ser realizada por un usuario informático bien experimentado.
Afortunadamente, con la idea de acercar el sistema Linux a todo tipo de usuarios, surgieron las
distribuciones de Linux realizadas por diferentes organizaciones y empresas. Una distribución de Linux
recopila en uno o varios CDs todos los ficheros necesarios para montar un sistema Linux en una partición
del disco duro de un computador. Además incluye un programa instalador con una GUI amigable que
simplifica enormemente la instalación de Linux.
Entre las distribuciones más conocidas de Linux se encuentran las siguientes : Red Hat, Debian,
Slackware, Fedora, Gentoo, Ubuntu, Kubuntu, Mandriva y SuSE.
Las principales diferencias entre las distribuciones de Linux radican en los programas y aplicaciones
que instalan, así como en la facilidad que conceden al usuario para instalar y configurar el sistema.
6.3.
Gestión de procesos e hilos en Linux
A diferencia de otros SOBUNIX, como por ejemplo Solaris (ver sección 2.2.2), en Linux no existe
una distinción clara entre las abstracciones de proceso, proceso ligero (hilo de usuario) e hilo del núcleo.
De hecho en varías partes del código del núcleo se utilizan los términos procesos, hilos y tareas de forma
sinónima; debido seguramente a que en las primeras versiones del núcleo utilizaban como unidad de
planificación y ejecución al proceso y no soportaban procesos ligeros ni hilos del núcleo.
Para el núcleo de Linux un proceso monohilo, un proceso ligero o un hilo del núcleo es simplemente
un flujo de ejecución independiente o tarea (task) que debe ser planificada y ejecutada. Linux considera
234
Ampliación de sistemas operativos
a un proceso monohilo como una única tarea. Mientras que un proceso multihilo constará de un número
de tareas igual al número de procesos ligeros (hilos de usuario) en que se descomponga. También cada
hilo del núcleo asociado a un proceso del sistema o utilizado para ejecutar una determinada función del
núcleo es considerado como una única tarea.
Por otra parte, en Linux se utiliza el concepto de grupo de hilos para designar a todos los procesos
ligeros que forman parte de una misma aplicación multihilo.
6.3. 1.
Estructuras del núcleo asociadas a las tareas
El núcleo asigna a cada tarea en el momento de su creación una estructura t a s k_s t ruc t , una pila
en modo núcleo y una estructura thread_i n f o , entre otras estructuras de datos.
Estructura task_struct
La estructura task_s truc t , también denominada descriptor del proceso, contiene datos y punteros
a otras estructuras de datos que el núcleo necesita conocer para poder gestionar una tarea. Esta estructura
contiene la siguiente información:
•
Estado de la tarea. En Linux una tarea puede encontrarse en los siguientes estados:
- TASK_RUNNING (Ejecutándose) . Una tarea se encuentra en este estado si se está ejecutando
en un procesador o si está preparada para ser ejecutada cuando lo determine el planifica­
dor del núcleo. Nótese la diferencia entre Linux y otros SOBUNIX donde ejecutándose y
preparado para ejecución son considerados estados independientes.
- TASK_INTERRUPT I BL E (Interrumpible). La tarea se encuentra dormida a la espera de que
se produzca un determinado evento, pero puede ser despertada si llega alguna señal no blo­
queada que no ignore.
- TASK_UNINTERRUPT I BLE (No interrumpible). La tarea se encuentra dormida a la espera
de que se produzca un evento, pero solo será despertada si se produce el evento por el que
espera. Una tarea en este estado no puede ser despertada si llega alguna señal no bloqueada
que no ignore.
- TASK_STOPPED (Parada). La ejecución de la tarea ha sido detenida por otra tarea, por ejem­
plo un depurador de código.
- TASK_TRACED (Rastreada). Es un caso especial del estado anterior. Este estado se utiliza
exclusivamente para aquellas tareas cuya ejecución ha sido detenida porque está siendo ras­
treada mediante la llamada al sistema ptrace invocada por otra tarea.
- EXI T_ZOMB I E (Zombi). La tarea ha terminado su ejecución pero el núcleo todavía no ha
borrado el contenido de su estructura task_s tru c t ya que el padre todavía no ha invocado
una llamada al sistema wai tp i d o wai t4 para obtener el estatus de salida de su hijo. Nótese
que si el padre nunca invoca a esta llamada al sistema el núcleo no eliminará esta estructura
hasta que el sistema no sea reiniciado.
S OBUNIX : el sistema operativo Linux
235
- EXI T_DEAD (Muerta). La tarea ha terminado su ejecución y su proceso padre ya ha invocado
una llamada al sistema wa i tp i d o wa i t 4 para obtener el estatus de salida de su hijo. El
núcleo procederá a la eliminación de la estructura t a s k_s truc t si no existen más tareas
que hayan invocado una llamada al sistema del mismo tipo wai tp i d sobre la misma tarea.
En la Figura 6. 1 se muestra el diagrama de transición de estados de las tareas en Linux. Por
simplificar el diagrama se ha omitido el estado rastreada.
Terminación
Creación
Tratamiento de
una llamada
tipo wa it
invocada por
el padre
un evento
Figura 6.1
-
Diagrama de transición de estados de las tareas en Linux
•
Parámetros de planificación. Entre ellos la prioridad de la tarea, el tiempo de ejecución y el tiempo
promedio que duerme una tarea esperando por un evento. Como se explicará en la sección 6.4 el
planificador utiliza esta información para decidir que tarea será planificada para ejecución en un
determinado procesador del computador.
•
Identificadores. Cada tarea tiene asociada un identificador de tarea (task identifier, TID), también
denominado identificador del hilo (thread Identifier), que la identifica de manera única. Este iden­
tificador se almacena en un campo de la estructura t a s k_s truc t . Contrariamente a lo que se
podría pensar este campo no se denomina t i d sino p i d. Esto es así porque en sus orígenes Linux
únicamente soportaba procesos monohilos y en dicho caso el valor del TID es igual al PID del
proceso.
En el caso de procesos multihilos cada hilo constituye una tarea y tiene asociado un TID diferente.
Además cada tarea tiene asignado un identificador de grupo de tareas (Task Group IDentifier,
236
Ampliación de sistemas operativos
TGID), también denominado identificador de grupo de hilos, el cual se almacena en el campo
t g i d de la estructura ta s k_s t ruc t . Todas las tareas pertenecientes a un mismo grupo de tareas
tienen asignado el mismo TGID, el cual coincide con el TID de la tarea líder del grupo, que es la
tarea principal. El PID de un proceso multihilo en Linux coincide con el valor del TGID de sus
hilos.
•
Información genealógica. Como por ejemplo: un puntero a la estructura t a s k_s truc t de su
proceso padre, la cabecera de la lista doblemente enlazada de sus procesos hijos, y punteros para
implementar la lista doblemente enlazada de sus procesos hermanos.
•
Localización del espacio de direcciones virtuales de la tarea.
•
Credenciales. Como los identificadores de usuario (UID y EUID), los identificadores de grupo
(GID y EGID) y el identificador de sesión (SID).
•
Contexto hardware salvado. Permite continuar con la ejecución de la tarea en modo usuario tras
retornar de la ejecución en modo núcleo de una llamada al sistema o de una interrupción.
•
Puntero a la estructura thread_i n f o .
•
Información relativa a l sistema de archivos. Como u n puntero a l a tabla de descriptores d e archivos
abiertos y punteros al nodo-i del directorio de trabajo actual y al nodo-i del directorio raíz.
•
Información asociada al tratamiento de señales. Como las máscaras de señales ignoradas, blo­
queadas y pendientes. Así como las acciones establecidas para cada tipo de señal y las direcciones
de los manejadores de las señales que son capturadas.
•
Información contable sobre uso de recursos. Como el tiempo ejecutado en modo usuario o en modo
núcleo. También límites máximos a los recursos que puede utilizar: número máximo de archivos
abiertos, tiempo máximo de uso del procesador, tamaño máximo de su pila o de su segmento de
datos, número máximo de marcos de página que puede consumir, etc.
El núcleo enlaza todas las estructuras ta s k_s truc t existentes en una lista que se denomina lista
de procesos. Este nombre deriva de las primeras versiones de Linux donde únicamente se soportaban
procesos monohilos y en consecuencia las tareas eran procesos. En las versiones actuales con soporte
de procesos multihilos este nombre puede llevar a confusión ya que una tarea puede ser un proceso
monohilo, un hilo de usuario (proceso ligero) o un hilo del núcleo. Un nombre más apropiado sería lista
de tareas. Por otra parte señalar la analogía existente entre la estructura task_s truc t y la estructura
proc descrita en la sección 2.2.2.
e
Ejemplo 6. 1
Considérense el archivo ejecutable prog 6 1 cuyo código fuente en C se muestra en la Figura 6.2. Se
observa que el programa hace uso de funciones de la librería de hilos Pthreads (ver sección 2.3 .4) para
implementar dos hilos de usuario. La función de cada hilo es mostrar en pantalla el valor de su PID y
SOBUNIX: el sistema operativo Linux
237
# i nc lude < s td i o . h>
# i nc l ude <pthread . h>
# i nc lude < sys / sys c a l l . h>
vo i d * funl ( vo i d * i d ) ;
vo i d mo s t rar_i n f o ( char e ) ;
ma i n ( )
{
/ * Código de l h i l o 1
( pr i nc ipa l ) * /
p thread_t hu l ;
p thread_c r e a t e ( &hu l , NULL , * funl , NULL ) ;
mo s t rar_i n f o ( ' l ' ) ;
p thread_j o i n ( hu l , NULL ) ;
p r i n t f ( " \ nH i l o 2 t e rm i nado " ) ;
for ( ; ; ) ;
vo i d * funl ( vo i d * i d )
/ * C ó d i go del hi l o 2 * /
mo s t rar_i n f o ( ' 2 ' ) ;
for ( ; ; ) ;
vo i d mo s t rar_i n f o ( char e )
{
l ong i n t u , v ;
u = g e tp i d ( ) ;
v= ( l ong i n t ) sys c a l l ( SYS_g e t t i d ) ;
p r i n t f ( " \ nH i l o
%:::: :
P I D= % l d
Figura 6.2 -
T I D= % l d \ n " , c , u , v ) ;
Código C del programa prog 6 1 del Ejemplo 6 . 1
TID asociado. Para obtener el PID se invoca a la llamada al sistema g e t p i d . Realmente esta llamada en
Linux devuelve el TGID del hilo que la invoca, recuérdese que PID=TGID. Por otra parte para obtener el
TID se invoca indirectamente a la llamada al sistema g e t t i d a través de la llamada al sistema sys c a l l
ya que no existe definida en 1 ibc una función de envoltura para esta llamada al sistema.
Supóngase que prog 6 1 es invocado en segundo plano desde la línea de órdenes de un intérprete de
comandos en Linux. En la pantalla aparecería una salida parecida a la siguiente:
H i l o 1 : P I D= l 2 6 7 4 T I D= l 2 6 7 4
H i l o 2 : P I D= l 2 6 7 4 T I D= l 2 6 7 5
S e observa que el proceso asociado al programa tiene asignado un PID= 1 2674, luego su TGID = 1 2674.
Este proceso consta de dos hilos : el hilo principal (hilo 1) cuyo TID= 1 2674 y el hilo 2 cuyo TID = 1 2675 .
238
Ampliación de sistemas operativos
Esta información también se puede obtener usando el comando ps - L , que mostraría una salida similar
a la siguiente:
PID
10838
12674
12674
12 678
LWP
10838
12674
12675
12 678
TTY
pt s / 1
pt s / 1
pts / 1
pts / 1
T IME
00 : 00
00 : 00
00 : 00
00 : 00
:
:
:
:
00
00
00
00
CMD
bash
prog 6 1
prog 6 1
ps
El valor del TID aparece en la columna LWP.
•
Pila en modo núcleo y estructura thread_info
El núcleo en el momento de la creación de una tarea aparte de una estructura task_s truc t le asigna
también, entre otras, las siguientes estructuras de datos:
•
Pila en modo núcleo. También denominada pila del núcleo. Es una estructura que contiene los
marcos de pila de las funciones invocadas por el núcleo durante la ejecución de la tarea en modo
núcleo. Está pila está vacía cuando la tarea se ejecuta en modo usuario.
•
Estructura thread_i n f o . Contiene la dirección de la estructura task_s t ruc t de la tarea así
como otros parámetros de la misma.
Estas dos estructuras son creadas conjuntamente por el núcleo en una misma región que ocupa una
o dos páginas contiguas del espacio de direcciones virtuales del núcleo (ver Figura 6.3). La estructura
thread_in f o se localiza siempre en las direcciones virtuales más baj as de las páginas asignadas. Esta
disposición facilita al núcleo la localización de la estructura t a s k_s truc t de la tarea actualmente en
ejecución en un determinado procesador. Simplemente necesita conocer el valor del registro puntero
de pila del procesador. A partir del mismo puede determinar la página donde se ubica la estructura
thread_in f o , la cual apunta a la estructura ta s k_s t ruc t .
e
Ejemplo 6.2
En la Figura 6.3 se muestra un diagrama en el que se representa la pila del núcleo y las estructuras
t a s k_s t ruc t y thread_in f o de los hilos del proceso del Ejemplo 6. 1 . Se observa que las estructuras
t a s k_s t ruc t se encuentran enlazadas formando parte de la lista de procesos (lista de tareas) del núcleo.
Cada estructura task_s truc t tiene un puntero a su estructura thread_info asociada, la cual a su
vez también tiene un puntero recíproco. La pila del núcleo de cada hilo se implementa en una página
contigua a la página donde se localiza su estructura thread_in f o lo que facilita la localización de
dicha estructura a partir del puntero de pila.
•
SOBUNIX: el sistema operativo Linux
239
� - - - - - - - - - - - - - - - ,
1
1
1
1
1
�
1
1
1
1
1
i
Pila del núcleo
TID= l 2674
Puntero de pila ----.
t a s k- s t ru c t
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
,
1
1
1
•
1 o 2 páginas
contiguas
thread- i n f o
Pila del núcleo
TID= 1 2675
Puntero de pila ___.
t a s k s t ru c t
�
i
1
1
1
1
L---------------
1
1
1
1
1
1
1
1
•
thread- i n f o
Lista de procesos
(Lista de tareas)
Figura 6.3
6.3.2.
-
Relación existente entre las estructuras del núcleo asignadas a una tarea
Creación de procesos e hilos en Linux
La creación de procesos en Linux, al igual que en otros SOBUNIX, se puede realizar mediante las
llamadas al sistema fork y v f o rk. Además Linux dispone de la llamada al sistema c l one para crear
un nuevo proceso ligero asociado al proceso invocador de la llamada. Esta llamada es bastante potente
y flexible ya que permite especificar los recursos asociados al proceso creador que se desea que sean
accedidos por el proceso ligero que es creado. Esta llamada también permite crear un nuevo proceso de
la misma forma que las llamadas fork y vf ork.
La llamada al sistema c l one tiene la siguiente sintaxis:
r = c l one ( fun , u_p i l a , i nd , arg ) ;
Donde fun es la función que comenzará a ejecutar el proceso ligero creado cuando sea planificado
para ejecución. Dicha función recibe como argumentos los especificados en arg. El argumento u_p i l a
es l a dirección virtual de comienzo de l a región de pila en modo usuario del hijo. El argumento ind es un
mapa de bits que permite especificar los recursos del proceso padre que serán compartidos por el proceso
hijo. Cada bit de la máscara tiene asignado una constante simbólica, por ejemplo:
240
Ampliación de sistemas operativos
•
CLONE_THREAD. Si este bit está activado se crea un nuevo proceso ligero (hilo de usuario). En
caso contrario se crea un nuevo proceso monohilo.
•
CLONE_VM. Si este bit está activado entonces el proceso hijo comparte el mismo espacio de direc­
ciones virtuales del proceso invocador, excepto la región de pila.
•
CLONE_PARENT. Si este bit está activado el proceso hijo tendrá como proceso padre al mismo del
proceso invocador. En caso contrario el proceso invocador será el padre del proceso creado.
•
C LONE_F I L E S . Si este bit está activado el proceso hij o comparte los descriptores de archivos del
proceso padre. En caso contrario el proceso hijo recibe su copia independiente de los descriptores
de archivos.
•
CLONE_S I GHAND. Si este bit está activado el proceso hij o comparte los manipuladores de señales
del proceso padre. Los posibles cambios que se hagan en estos manipuladores son visualizados
tanto por el padre como por el hijo. En caso contrario el proceso hij o recibe su copia independiente
de los manipuladores de señales y los cambios que realice en ellos no son visualizados por el padre.
Si la llamada se ejecuta con éxito en r se almacena el TID del proceso (o proceso ligero) hijo creado.
En caso de error se almacena el valor - l .
e
Ejemplo 6.3
En la Figura 6.4 se muestra el código C del archivo ejecutable prog 6 2 cuya funcionalidad es parecida
a la del programa prog 6 1 del Ejemplo 6. 1 . La principal diferencia es que ahora se utiliza la llamada
al sistema c l one para crear un nuevo hilo ( CLONE_THREAD ) en vez de usar una función de la librería
Pthreads. El hilo 2 creado comparte el espacio de direcciones virtuales ( CLONE_VM) y los manipuladores
de señales ( CLONE_S I GHAND) del hilo invocador (hilo 1 ) .
•
El núcleo implementa el tratamiento de las llamadas c l one, f o r k y v f ork a través de la función del
núcleo do_fork ( ) . La cual utiliza a su vez a la función c opy_pro c e s s ( ) para configurar el descriptor
del proceso (estructura task_s t ruc t ) y otras estructuras de datos del núcleo asociadas al nuevo proceso
creado.
6.3.3.
Hilos del núcleo en Linux
En Linux los hilos del núcleo son asociados a la ejecución de procesos del sistema, que son procesos
iniciados por el propio núcleo que se encargan de realizar diferentes tareas administrativas como por
ejemplo: búsqueda de marcos de página libres, intercambio de procesos, copia de buffers modificados a
memoria secundaria, etc.
A diferencia de otras tareas los hilos del núcleo únicamente se ejecutan en modo núcleo y se crean
con la función del núcleo kerne l_ thread ( ) . Esta función para implementar la creación del hilo del
núcleo también invoca a la función do_fork ( ) .
Dependiendo del proceso del sistema al que esté asociado, un hilo del núcleo puede ser ejecutado
cuando se produce un determinado evento o periódicamente.
SOBUNIX: el sistema operativo Linux
241
# i ne lude < s t d i o . h>
# i n e l ude <pthread . h>
# i ne l ude < sys / sys e a l l . h>
# i ne l ude <ma l l o e . h>
# i ne lude < s ehed . h>
vo i d funl ( ) ;
v o i d mo s t rar_i n f o ( ehar e ) ;
vo i d ma i n ( )
{
int r ;
uns i gned ehar p i l a_h i j o [ 4 0 9 6 ] ;
r = e l one ( funl , p i l a_h i j o + 2 0 4 8 , CLONE_THREAD [ CLONE _VM [ CLONE_S I GHAND , NULL ) ;
if
( r= = - 1 ) {
p r i n t f ( " \ nError en la l l amada e l on e \ n " ) ;
mo s t rar_i n f o ( ' l ' ) ;
for ( ; ; ) ;
v o i d funl ( )
mo s t rar_i n f o ( ' 2 ' ) ;
for ( ; ; ) ;
vo i d mo s t rar_i n f o ( ehar e )
l ong i n t u , v ;
u=getpid ( ) ;
v= ( l ong int ) sys e a l l ( SYS _ge t t i d ) ;
p r i n t f ( " \ nH i l o
�:
P I D= % l d
Figura 6.4 -
6.4.
T I D= % l d \ n " , e , u , v ) ;
Código C del programa prog 6 2 del Ejemplo 6.3
Planificación en Linux
Linux es un sistema operativo de núcleo expropiable que utiliza como unidad de planificación a las
tareas. El núcleo asigna a cada tarea una prioridad que es un número entero positivo p comprendido
dentro del rango de valores [0, 1 39], siendo O la prioridad más alta posible y 1 39 la más baj a (ver Figura
6.5). El núcleo siempre planifica a la tarea en el estado ejecutándose de mayor prioridad (menor valor de
p ) . Dicha tarea será expropiada si entra en el estado ejecutándose una tarea de mayor prioridad.
A las tareas con prioridad p comprendida en el rango [ 1 00, 1 39] se les considera tareas convencio­
nales o tareas de tiempo compartido. A las tareas con prioridad p comprendida en el rango [0, 99] se
242
Ampliación de sistemas operativos
Prioridad más alta
o
,_
-
99
1 00
1-
1
1
1
1
1
Prioridad más baj a
Figura 6.5 -
1 39
Tareas de tiempo real
r-
Tareas convencionales
-
Escala de prioridades de ejecución de las tareas considerada por el núcleo de Linux
les considera tareas de tiempo real. Conviene señalar que el término tarea de tiempo real no debe ser
entendido en el sentido usual, es decir, una tarea que debe ser ejecutada en unos plazos determinados,
sino que se refiere al significado dado en las especificaciones POSIX 1 003 .4, es decir, una tarea con una
prioridad más alta que las tareas convencionales.
En el momento de su creación, la prioridad de una tarea es configurada al mismo valor que la priori­
dad de su padre. Posteriormente, si se trata de una tarea convencional, la prioridad de la tarea puede ser
cambiada utilizando las llamadas al sistema ni ce o s e tpr i or i ty. En el caso de una tarea de tiempo
real se pueden usar las llamadas s ched_se tparam o s ched_s e t s chedu l e r .
6.4.1.
Planificador usado en las versiones del núcleo de Linux anteriores a la 2.6.23
El planificador implementado en las primeras versiones de Linux no estaba bien escalado ya que el
tiempo empleado en seleccionar la tarea de mayor prioridad dependía del número de tareas en el estado
ejecutándose y del número de procesadores existentes en el computador.
Durante el desarrollo de la versión 2.5 de Linux el planificador fue rediseñado por completo con
objeto de asegurar que el tiempo de selección de la tarea de mayor prioridad fuese independiente del
número de tareas en el estado ejecutándose y del número de procesadores. A dicho planificador se le
3
conoce con el nombre de planificador 0 ( 1 ) .
3 La notación 0( ) se utiliza para designar la complejidad de un algoritmo matemático [Cormen et al. , 2009] .
SOBUNIX: el sistema operativo Linux
243
Estructuras de datos utilizadas en su implementación
El núcleo asigna a cada procesador existente en un computador una estructura de datos runqueue
(ver Figura 6.6). Esta estructura contiene, en otros, los siguientes campos:
•
arrays . Este campo contiene un array de dos estructuras p r i o_array_t . Cada una de estas
estructuras contiene las cabeceras de 140 colas PIFO de tareas en el estado ejecutándose, una por
cada posible valor de la prioridad. También contiene un mapa de bits, con un bit asociado a cada
cola, para saber si una cola está vacía o contiene alguna tarea. Además contiene un contador del
número total de tareas existentes en las 140 colas.
•
a c t ive. Puntero a la estructura pri o_array_t que contiene las colas de tareas activas que son
aquellas que consulta el planificador para seleccionar la próxima tarea que será planificada para
ejecución en el procesador al que esté asociada la estructura runqueue. El planificador siempre
selecciona para ejecutar a la primera tarea de la cola activa de mayor prioridad.
•
expi red. Puntero a la estructura pri o_array_t que contiene las colas de tareas expiradas que
son aquellas en las que ingresan las tareas (excepto si son de tiempo real) cuyo cuanto de ejecución
ha expirado en el procesador al que esté asociada la estructura runqueue.
Cuando no queda ninguna tarea en las colas de tareas activas entonces el núcleo intercambia los
valores de los campos ac t ive y exp i red, de tal forma que las colas de tareas expiradas pasan a ser las
colas de tareas activas, y viceversa.
Nótese que en un instante de tiempo determinado una tarea en el estado ejecutándose está asociada
a una determinada estructura runqueue y solo puede pertenecer a una única cola de tareas activas o
expiradas de entre las múltiples colas existentes en la estructura runqueue.
Una cola de tareas en el estado ejecutándose asociada a una determinada prioridad se implementa
como una lista doblemente enlazada de estructuras t a s k_s t ruc t . En la estructura t a s k_s truc t se
almacenan, entre otros, los siguientes parámetros de planificación de la tarea: prioridad, política de
planificación, tiempo de uso del procesador y tiempo promedio de espera en el estado dormido.
Políticas de planificación
Cada tarea tiene asignada una política de planificación que establece el algoritmo de planificación y
las reglas para colocar una tarea dentro de una determinada cola de prioridad. Se distinguen tres posibles
políticas de planificación4 :
•
SCHED_F IFO. Esta política utiliza un algoritmo PIFO para planificar a las tareas que tienen la mis­
ma prioridad. Luego las tareas son planificadas por orden de llegada y reciben un cuanto infinito.
Esta política de planificación solo puede ser utilizada por las tareas de tiempo real.
Esta política sigue las siguientes reglas a la hora de colocar a una tarea de tiempo real en una cola
de prioridad:
4Se está tomando como base la versión 2.6. 1 1 del núcleo de Linux.
244
Ampliación de sistemas operativos
runqueue
(asociada a CPU l )
[A] = Colas tareas activas, seleccionables para ser planificadas.
[E] = Colas tareas expiradas, solo ingresan aquí las tareas convencionales
que han consumido su cuanto.
a c t ive
exp i red
,___,__,_..-.____..._.-.__�
Cola tareas prioridad O
Cola tareas prioridad l
arrays [ O )
} [A ]
Planificador
Cola tareas prioridad 1 3 9
Cola tareas prioridad O
Cola tareas prioridad l
a rrays [ 1 )
}E;
'
Cola tareas prioridad 1 3 9
runqueue
(asociada a CPU2)
a c t ive
exp i red
Cola tareas prioridad O
Cola tareas prioridad l
arrays [ O )
�-----�r=-:=;:,_,__r---... Cola tareas prioridad 1 3 9
Cola tareas prioridad O
Cola tareas prioridad l
a rrays [ 1 )
}
[E ]
Planificador
4
�
} [A ]
Cola tareas prioridad l 3 9
Figura 6.6
-
Estructuras runqueue de un computador con dos procesadores
- Una tarea X de prioridad p que ha sido expropiada por otra tarea Y de mayor prioridad será
colocada al principio de la cola de tareas activas asociada a p.
Si se invoca a una llamada al sistema s ched_s e t s chedu l e r o s ched_s e tparam para
configurar la prioridad p de una tarea, dicha tarea será colocada, si se encuentra en el estado
ejecutándose, al principio de la cola de tareas activas asociada a p.
Cuando una tarea de prioridad p entra en el estado ejecutándose se coloca al final de la cola
de tareas activas asociada a p.
Si una tarea cede voluntariamente el uso del procesador mediante la invocación de una llama-
SOBUNIX: el sistema operativo Linux
245
da al sistema s ched_yi e l d, la tarea es colocada al final de la cola de tareas activas asociada
a p.
Una tarea X con política SCHED_F IFO continuará ejecutándose en un procesador excepto si se
producen alguno de los siguientes eventos : la tarea X se bloquea en espera de algún evento, entra
en el estado ejecutándose una tarea Y de mayor prioridad, o la tarea X invoca a la llamada al
sistema s ched_yi e l d para ceder el uso del procesador.
•
SCHED_RR. Esta política utiliza un algoritmo de turno rotatorio (round robín, RR) para planificar
a las tareas que tienen la misma prioridad. La duración del cuanto depende de su prioridad. Esta
política de planificación solo puede ser utilizada por las tareas de tiempo real.
Las reglas que utiliza esta política para colocar a una tarea de tiempo real en una cola de prioridad
son análogas a las utilizadas en la política SCHED_F I F O . Además si una tarea consume su cuanto
ésta es colocada al final de la cola de tareas activas asociada a p. Nótese que a diferencia de lo que
podría pensarse la tarea no es colocada en la cola de tareas expiradas, el objetivo de esta estrategia
es disminuir el tiempo de espera de las tareas de tiempo real.
Una tarea X con política SCHED_RR continuará ejecutándose en un procesador excepto si se pro­
ducen alguno de los siguientes eventos: la tarea X consume su cuanto de ejecución, la tarea X se
bloquea en espera de algún evento, entra en el estado ejecutándose una tarea Y de mayor prioridad,
o la tarea X invoca a la llamada al sistema s ched_yi e l d para ceder el uso del procesador.
Si una tarea X con política SCHED_RR es expropiada por otra tarea Y de mayor prioridad, cuando
X sea planificada otra vez para ejecución lo hará durante un tiempo igual al tiempo restante de
cuanto que le quedaba por ejecutar antes de ser expropiada.
•
SCHED_NORMAL (también denominada SCHED_OTHER en otras versiones). Es la política que se
aplica para planificar a las tareas convencionales. Esta política utiliza un algoritmo de turno rota­
torio para planificar a las tareas que tienen la misma prioridad. La duración del cuanto depende de
su prioridad.
Esta política sigue reglas similares a las otras políticas a la hora de colocar a una tarea en una
cola de prioridad, la principal diferencia es que si una tarea de prioridad p1 consume su cuanto, el
núcleo recalcula su prioridad (supóngase que ahora toma el valor pz) y coloca a la tarea al final de
la cola de tareas expiradas asociada al nuevo valor de prioridad (p2 ).
Asignación de la prioridad de una tarea
En Linux cada tarea tiene asignada una prioridad estática Pe · Además las tareas convencionales
también tienen asignada una prioridad dinámica Pd · El núcleo utiliza Pe para decidir qué tarea de tiempo
real planificar y para colocar a una tarea de tiempo real en una determinada cola de prioridad. Por el
contrario en el caso de una tarea convencional para realizar estas acciones utiliza Pd · Se cumple, por lo
tanto, que p = Pe en el caso de una tarea de tiempo real y p = Pd en el caso de una tarea convencional.
246
Ampliación de sistemas operativos
Si una tarea tiene asociada una política de planificación SCHED_RR o SCHED_NORMAL el núcleo
utiliza la prioridad estática de la tarea para determinar la duración de su cuanto q (en milisegundos) de
acuerdo con la siguiente fórmula [Bovet y Cesati, 2005] :
q =
{
( 1 40 - P e) · 20
( 1 40 - P e) · 5
si P e
si P e
<
�
1 20
1 20
(6. 1 )
Se observa que e l cuanto asignado a una tarea aumenta conforme mayor e s s u prioridad estática, es
decir, más bajo es el valor de P e · Por ejemplo, para P e = 1 3 9 se obtiene q = 5 ms. Mientras que para
P e = 1 00 se obtiene q = 800 ms. El máximo valor del cuanto es q = 2800 ms y se obtiene para la
prioridad estática más alta P e = O.
En el caso de una tarea de tiempo real el valor de su prioridad estática se encuentra dentro del rango
[0, 99] y puede ser configurado, por ejemplo, mediante la llamada al sistema shed_s e tparam.
En el caso de una tarea convencional su prioridad estática se encuentra dentro del rango [ 1 00, 1 39] y
puede ser configurado mediante las llamadas al sistema ni c e o s e tp r i o r i ty. Estas llamadas trabaj an
con el valor amable NI de una tarea que es un valor comprendido en el rango [ -20, 1 9] . La relación entre
la prioridad estática y el valor amable es la siguiente:
P e = NI + 1 20
(6.2)
Por defecto NI= O. Conviene tener presente que únicamente el superusuario puede establecer valores
negativos de NI, es decir, aumentar la prioridad estática de una tarea. Para visualizar el valor amable de
una cierta tarea se puede usar el comando top.
e
Ejemplo 6.4
Supóngase el programa prog 6 1 del Ejemplo 6. 1 . Supóngase que una vez lanzado en segundo plano se
introduce la orden
t op -n4 - p 1 2 6 7 5
que muestra en pantalla diferente información sobre la tarea con TID = 1 2675 . La información se actualiza
cuatro veces (opción -n4) antes de que finalice el comando. Supóngase que la última actualización que
se muestra en la pantalla es la siguiente5 :
P I D USER
1 2 6 7 5 j o s ema
PR
20
NI
o
VIRT
10132
RES
280
SHR S % C PU %MEM
216 S 0 . 0 0 . 1
TIME+ COMMAND
0 : 0 0 . 0 0 prog 6 1
S e observa que el valor amable N I es igual a O . Sustituyendo este valor en l a ecuación (6.2) s e obtiene
que la prioridad estática de la tarea es P e = O + 1 20 = 1 20, luego se trata de una tarea convencional.
Señalar que la columna PR de la salida del comando t op también contiene información sobre la prioridad
estática P e de la tarea. Ambos valores se relaciona a través de la expresión:
P e = PR + 100
5 Por cuestiones de espacio se ha omitido parte de la información que realmente aparecería en la pantalla.
(6.3)
SOBUNIX: el sistema operativo Linux
247
Para este ejemplo se observa en la salida que PR=20, luego sustituyendo este valor en (6.3) se obtiene
nuevamente que P e = 20 + 1 00 = 1 20.
Igualando las ecuaciones (6.2) y (6.3) se puede obtener la siguiente relación entre PR y NI :
NI = PR - 20
(6.4)
Se comprueba que para PR=20 se obtiene el valor NI=O.
•
La prioridad dinámica de una tarea convencional es recalculada por el núcleo cuando la tarea con­
sume su cuanto. Para calcularla utiliza la siguiente expresión [Bovet y Cesati, 2005] :
Pd = máx { 1 00, mín { Pe - b + 5 , 1 39} }
(6.5)
En la expresión anterior b es un factor denominado bonus, que puede tomar valores enteros dentro
del rango [0, 1 0] . Si b < 5 entonces se penaliza a la tarea ya que se reduce su prioridad dinámica. Por el
contrario si b > 5 se gratifica a la tarea ya que se aumenta su prioridad dinámica.
El valor del bonus se fija en función del tiempo promedio de espera en el estado dormido a través de
un conjunto de reglas heurísticas. El tiempo promedio de espera se incrementa cuando una tarea despierta
y se reduce cuando la tarea consume su cuanto o es expropiada.
Esta forma de calcular la prioridad dinámica favorece a las tareas limitadas por E/S frente a las tareas
limitadas por CPU. Luego el planificador 0( 1 ) consigue que las aplicaciones interactivas tengan un mej or
tiempo de respuesta que el que tenían con el planificador usado en las primeras versiones del núcleo de
Linux.
Otra funcionalidad reseñable del planificador 0( 1 ) es que monitoriza la carga de trabajo existen­
te en cada procesador y si lo considera necesario distribuye las tareas entre las estructuras runqueue
existentes para equilibrar la carga de trabajo de los procesadores.
Una de las principales fuentes de crítica del planificador 0( 1 ) es la utilización de reglas heurísticas
para establecer el valor de diferentes parámetros de planificación, como por ejemplo, el valor del bonus.
6.4.2.
Planificador utilizado a partir de la versión 2.6.23 del núcleo de Linux
El planificador 0( 1 ) ha sido el planificador utilizado en Linux hasta la versión 2.6.23 donde ha vuelto
a ser rediseñado. El planificador introducido en esta versión presenta un diseño mucho más modular
basado en la existencia de un planificador central y clases de planificación.
Cada clase de planificación encapsula los detalles de las políticas de planificación que soporta y
dispone de un planificador independiente. Una clase de planificación se implementa mediante una es­
tructura de tipo s ched_c l a s s la cual contiene punteros a las funciones que implementan al planificador
de la clase. Dichas funciones deben ser invocadas por el planificador central cuando se producen even­
tos relativos a la planificación que afectan a una tarea perteneciente a dicha clase, como por ejemplo: la
selección de la próxima tarea perteneciente a la clase que puede ser planificada y la colocación o elimina­
ción de una tarea en la estructura de datos (cola o árbol) que mantiene las tareas en el estado ejecutándose
perteneciente a dicha clase.
248
Ampliación de sistemas operativos
Existen dos clases de planificación:
•
•
Clase de tiempo real (shed_rt . e ) . A esta clase pertenecen las tareas de tiempo real. El planifica­
dor de esta clase implementa las políticas de planificación SCHED_F IFO y SCHED_RR. A diferencia
del planificador 0( 1 ) la duración del cuanto de las tareas de tiempo real planificadas con política
SCHED_RR es independiente de su prioridad e igual a 1 00 ms.
Clase completamente justa (shed_f a i r . e ) . A esta clase pertenecen las tareas convencionales. El
planificador de esta clase implementa las políticas de planificación SCHED_NORMAL, SCHED_IDLE
y SCHED_BATCH.
La política SCHED_BATCH fue introducida en la versión 2.6. 1 6 para dar soporte a tareas conven­
cionales de tipo batch que hacen un uso intensivo del procesador. Una tarea perteneciente a esta
política de planificación nunca puede expropiar a otra tarea. Por lo tanto estas tareas no interfieren
con las tareas interactivas de la clase SCHED_NORMAL .
La política SCHED_IDLE, disponible desde la versión 2.6.23, se utiliza para dar soporte a tareas
que pueden ser ejecutadas con la prioridad más baja.
Cada tarea pertenece a una determinada clase planificación y será tratada por el planificador de la
clase a la que pertenece de acuerdo con la política de planificación que tenga asignada.
El planificador central (s chedu l e) se encarga de seleccionar a la próxima tarea que será ejecutada
en cada procesador. Para realizar esta operación interactúa con los planificadores de cada clase invocando
las funciones apropiadas. En primer lugar invoca al planificador de la clase de tiempo real para que
seleccione una tarea de tiempo real para ser ejecutada. Si no existe ninguna tarea de tiempo real en el
estado ejecutándose entonces invoca al planificador de la clase completamente justa para que seleccione
una tarea convencional.
De esta forma, el planificador central implementa un algoritmo de planificación basado en priorida­
des, ya que siempre selecciona para ser ejecutada en un procesador a la tarea de mayor prioridad asociada
a dicho procesador.
Aparte de su diseño modular otra de las principales novedades del planificador de la versión 2.6.23
es que el algoritmo de turno rotatorio que se utilizaba en la política SCHED_NORMAL ha sido sustituido
por el algoritmo de planificación completamente justa (Completely Fair Scheduling, CFS). El algoritmo
CFS también se utiliza para las políticas SCHED_BATCH y SCHED_IDLE. Estas tres políticas son imple­
mentadas por el planificador de la clase completamente justa, también denominado planificador CFS .
El algoritmo CFS tiene como objetivo principal el realizar un reparto justo del tiempo de uso de un
procesador entre las tareas convencionales asociadas a dicho procesador. Para ello simula la existencia
de un computador ideal.
En un computador ideal si se tuvieran que ejecutar N tareas en paralelo con idéntico tiempo de ser­
vicio cada tarea recibiría 1 /N de la potencia de calculo del computador y todas terminarían de ejecutarse
en el mismo instante. Por ejemplo, si se tuviesen que ejecutar dos tareas en paralelo con un tiempo de
servicio requerido de 5 s, en un computador ideal cada tarea recibiría el 50 % de la potencia de cálculo
del computador con lo que tardaría en completarse 1 O s. Además ambas tareas finalizarán a la vez y
nunca tendrían que esperar por el uso de un procesador.
SOBUNIX: el sistema operativo Linux
rq
249
(asociada a CPU ! )
.....----.....--.___.
Cola tareas prioridad O
Cola tareas prioridad 1
rt
Cola tareas prioridad 99
Árbol roj o-negro
de tareas
convencionales
cfs
Figura 6.7 -
Diagrama de la estructura rq asociada a un procesador
En un computador real con un único procesador en un determinado instante de tiempo solo puede es­
tar ejecutándose una única tarea. La multitarea se simula conmutando rápidamente el uso del procesador
entre todas las tareas existentes . La tarea que se ejecuta en el procesador está siendo favorecida frente
al resto de las tareas que esperan para usarlo, las cuales son tratadas injustamente. El grado de injusticia
es directamente proporcional al tiempo de espera para usar el procesador. Obviamente conforme más
procesadores tenga el computador, el grado de injusticia se reduce pero no se elimina.
El algoritmo CFS utiliza como parámetro de planificación el tiempo de ejecución virtual de una tarea
que especifica cuando debería comenzar a ejecutarse dicha tarea si se dispusiera de un computador ideal.
El tiempo de ejecución virtual se almacena en la estructura t a s k_s truc t , en concreto en el campo
vrunt ime de la estructura s e . Cuanto mayor es la prioridad de la tarea menor es su vrunt ime .
El planificador CFS utiliza un árbol rojo-negro 6 para ordenar a todas las tareas convencionales aso­
ciadas a un determinado procesador. Las tareas son ordenadas en el árbol en función de su vrunt ime . En
el extremo del árbol situado más a la izquierda siempre se sitúa la tarea con menor valor de vrunt ime ,
que será la tarea convencional que será escogida para ser planificada sino existen pendientes tareas de
tiempo real.
Conforme se va ejecutando una tarea su tiempo de ejecución se añade a su vrun t ime que de esta
forma se va incrementando. Como resultado la tarea se va moviendo en el árbol hacia la derecha. O visto
de otra forma, las tareas que esperan para ejecutarse se van desplazando en el árbol hacia la izquierda.
Una tarea X se ejecutará hasta que otra tarea Y se coloque en el extremo más a la izquierda del árbol. En
dicho caso, se expropia el uso del procesador a X y se planifica para ejecución a Y.
El planificador CFS también permite trabajar a nivel de grupos de tareas con lo que es posible distri­
buir el tiempo de uso del procesador de manera justa entre los grupos de tareas existentes.
Otra novedad del planificador de la versión 2.6.23 se encuentra en la estructura runqueue, ahora
denominada estructura rq, que el núcleo asociada a cada procesador existente. En esta estructura los
6Es un árbol binario de búsqueda equilibrado [Cormen et al. , 2009] .
250
Ampliación de sistemas operativos
campos a c t ive, expi red y arrays han sido sustituidos por (ver Figura 6.7):
•
c f s . Es una estructura de tipo c f s_rq que permite implementar el árbol rojo-negro en que se
organizan las tareas en el estado ejecutándose pertenecientes a la clase justa completamente.
•
r t . Es una estructura de tipo r t_rq que permite implementar las 100 colas FIFO, una por cada
nivel de prioridad en el rango [0, 99] , en que se organizan las tareas en el estado ejecutándose
pertenecientes a la clase de tiempo real.
6.5.
Gestión de memoria en Linux
6.5.1.
Gestión del espacio de direcciones virtuales
En Linux el espacio de direcciones virtuales de un proceso comienza en la dirección O y se extiende
hasta la dirección TASK_S I Z E - 1 . El resto de direcciones virtuales desde TASK_S I Z E hasta 232 , en má­
quinas de 32 bits, o hasta 264 , en máquinas de 64 bits, están reservadas para el núcleo. TASK_S I Z E es
una constante cuyo valor depende de cada arquitectura.
Generalmente el tamaño del espacio de direcciones virtuales de un proceso es tres veces mayor que
el tamaño del espacio de direcciones del núcleo.
e
Ejemplo 6 .5
En la arquitectura Intel x86 de 32 bits el tamaño máximo del espacio de direcciones virtuales es de 4 GiB
con páginas de 4 KiB . Los primeros 3 GiB contienen el espacio de direcciones de un proceso mientras
que el espacio de direcciones del núcleo ocupa el último GiB .
En la Figura 6.8 se muestra la distribución que realiza Linux del espacio de direcciones virtuales de un
proceso en esta arquitectura. Las direcciones virtuales comprendidas entre O y el comienzo de la región
de código se utilizan para direccionar a los punteros nulos NULL . A continuación de la región de código
se ubican la región de datos y el montículo, el cual crece hacia direcciones virtuales crecientes. Los
archivos mapeados en memoria comienzan a ubicarse desde la dirección mmap_ba s e hacía direcciones
virtuales decrecientes. A continuación existe una región de protección entre la región de pila y la región
de archivos mapeados en memoria. La región de pila se ubica en la parte alta de memoria desde la
dirección TASK_S I Z E y crece hacía direcciones virtuales decrecientes. Las restantes direcciones están
reservadas para el espacio de direcciones del núcleo.
•
Linux utiliza una estructura tipo vm_area_s t ru c t para almacenar información sobre una determi­
nada región del espacio de direcciones virtuales de un proceso. Entre la información sobre una región
almacenada en esta estructura se encuentra la siguiente: permisos de acceso (solo lectura o lectura y escri­
tura), si es compartida o privada, dirección de crecimiento de la región, ubicación de su almacenamiento
de respaldo persistente (sistemas de archivos en disco o área de intercambio), etc.
Todas las estructuras vm_area_s t ruc t asociadas a las regiones de un mismo proceso son ordenadas
de dos formas distintas :
SOBUNIX: el sistema operativo Linux
251
O xFFFFFFFF
Espacio
de
direcciones
virtuales
del núcleo
OxCO O O O O O O
TAS K S I Z E
Pila
1
1
1
mmap_base
1
1
1
1
1
J
•
1
1
Protección
Archivos
mapeados en
meq¡oria
+
t
1
1
1
1
1
Montículo
Datos
Código
Ox0 8 0 4 8 0 0 0
1
1
1
O L---------------1
Figura 6.8 - Distribución del espacio de direcciones virtuales de un proceso en Linux en una arquitectura
lntel x86 de 32 bits
•
•
Lista enlazada de estructuras vm_area_s tru c t . Las estructuras se ordenan en orden ascendente
en función de la dirección virtual de comienzo de la región.
Á rbol rojo-negro de estructuras vm_area_s t ruc t . Es creado cuando el número de regiones es
superior a 32. Las búsquedas en un árbol rojo-negro son más rápidas que en una lista enlazada si
el número de elementos de la lista es elevado.
El núcleo consulta la lista o el árbol de estructuras vm_area_s t ruc t de un proceso cuando necesita
acceder a una dirección virtual determinada, o cuando necesita asignar una nueva región de memoria
252
Ampliación de sistemas operativos
virtual de un tamaño predeterminado.
Además el núcleo mantiene una estructura tipo mm_s truc t , accesible a través del campo mm de la
estructura tas k_s truc t asociada a un proceso, para recopilar toda la información que necesita conocer
sobre el espacio de direcciones virtuales de un proceso. En esta estructura se almacena las direcciones
virtuales de inicio y final de cada región. Además contiene un puntero mmap al comienzo de la lista
de la estructuras vrn_area_s t ru c t asociadas a las regiones del proceso. También contiene un puntero
mmap_rb al nodo inicial del árbol roj o-negro de estructuras vrn_area_s truc t (ver Figura 6.9).
VM
=
vm
a r e a s t ruct
task s t ru c t
mm s t ru c t --�----�---,
mm ----
Árbol roj o-negro
Figura 6.9
6.5.2.
-
Estructuras de Linux para gestionar el espacio de direcciones virtuales de un proceso
Gestión de la memoria física
Nodos y zonas
En computadores que disponen de múltiples procesadores la memoria principal puede ser organizada
de diferentes formas. Entre las organizaciones más utilizadas se encuentran las siguientes :
•
Organización de acceso a memoria uniforme (Uniform Memory Access, UMA). En este modelo
toda la memoria principal se organiza de forma contigua y todos los procesadores del computador
tardan lo mismo en acceder a cualquier posición de memoria.
•
Organización de acceso a memoria no uniforme (Non-Uniform Memory Access, NUMA). La
memoria principal se divide entre los procesadores existentes. Un procesador accede más rápido a
las posiciones de la memoria principal que tiene asignada, denominada memoria local, que a las
posiciones de las memorias locales de los otros procesadores .
Para dar soporte, tanto a la organización UMA como a la NUMA, Linux divide la memoria principal
en nodos de memoria. El tiempo de acceso a una posición de memoria de un determinado nodo es siempre
el mismo. Obviamente en una organización UMA existirá un único nodo de memoria, mientras que en
una organización NUMA existirá un nodo de memoria por cada procesador.
SOBUNIX: el sistema operativo Linux
253
Por otra parte, Linux considera las particularidades de direccionamiento (tamaño de registros, líneas
de direccionamiento para DMA, etc) de cada arquitectura hardware descomponiendo cada nodo de me­
moria en zonas, que son regiones contiguas de memoria principal. En el caso de la arquitectura Intel x86
de 32 bits cada nodo de memoria se descompone en tres zonas:
•
ZONE_DMA. Corresponde a las direcciones de memoria física por debaj o de 1 6 MiB . Esta zona
contiene los marcos de página que son utilizados para la realización de DMA en los antiguos
buses ISA.
•
ZONE_NORMAL . Corresponde a las direcciones de memoria física comprendidas entre 16 MiB y
896 MiB . Esta zona contiene los marcos de página que almacenan las páginas normales, es decir,
aquellas asociadas a los 4 primeros GiB del espacio de direcciones virtuales.
•
ZONE_H IGHMEM. Corresponde a las direcciones de memoria física por encima de 896 MiB . Esta
zona contiene los marcos de página que utilizan para almacenar páginas correspondientes a di­
recciones virtuales superiores a los 4 GiB , las cuales en arquitecturas de 32 bits no pueden ser
direccionados directamente. Esta zona en arquitecturas de 64 bits está vacía
Estructuras de datos utilizadas para gestionar la memoria principal
El núcleo numera de forma consecutiva comenzando desde O a todos los marcos de página en que
se descompone la memoria principal independientemente del nodo y la zona a la que pertenezcan. En
consecuencia no pueden existir dos marcos de página con el mismo número j aunque residan en nodos o
zonas diferentes.
El núcleo mantiene un descriptor de página por cada marco de página j existente. Cada descriptor
de página se implementa mediante una estructura de tipo page de 32 bytes que contiene, entre otros, los
siguientes datos sobre un marco:
•
Indicadores. Es una máscara de bits que se pueden configurar independientemente y que permiten
especificar los atributos del marco: bloqueado, referenciado, activo, modificado, privado, etc.
•
Contador de referencias. Se incrementa cada vez que la página contenida en este marco es referen­
ciada por el núcleo y se decrementa cuando se elimina una referencia. La página puede ser borrada
del marco cuando el contador toma el valor O. Si el contador es mayor que O la página no debería
ser borrada ya que ello seguramente originará un fallo de página.
•
Mapeado. Permite localizar el espacio de direcciones virtuales al que pertenece la página cargada
en el marco.
•
Punteros para formar diferentes listas de marcos. En un determinado instante de tiempo un des­
criptor de página estará formando parte de una de las siguientes listas : lista de bloques de marcos
contiguos libres de tamaño 2k marcos, lista de marcos de página activos (referenciados reciente­
mente) o lista de marcos de página inactivos (no referenciados recientemente).
254
Ampliación de sistemas operativos
Todos los descriptores de página de un mismo nodo se organizan en un array de descriptores de
página denominado mem_map. En una organización UMA existe un único array mem_map mientras que
en una organización NUMA existe un array mem_map por cada nodo en que se descompone la memoria.
El núcleo mantiene también un descriptor de zona por cada zona existente en un nodo. Cada descrip­
tor de zona se implementa mediante una estructura de tipo z one que contiene, entre otros, los siguientes
datos sobre una zona:
•
Número de marcos de página libres ( f r e e_pages).
•
Array de bloques de marcos de página libres ( f r e e_area). Es utilizado por el asignador a nivel
de página del núcleo, el cual implementa el algoritmo buddy. El elemento free_area [ k ] de esta
array apunta al descriptor de página del primer marco de página que forma parte de un bloque de
marcos de página contiguos libres de tamaño 2k . A su vez este descriptor de página contiene un
puntero al descriptor de página del siguiente marco que forma parte de dicho bloque. El descriptor
de página del último marco incluido en dicho bloque contiene un puntero al siguiente bloque de
marcos de página contiguos libres de tamaño 2k . En definitiva este array implementa las cabeceras
de las listas de bloques de marcos contiguos libres de la zona.
•
Cabecera de la lista de marcos de página activos (ac t i ve_l i s t) . Apunta al descriptor de página
del primer marco activo que forma parte de la lista. Esta lista es consultada por el algoritmo de
reemplazamiento de páginas que implementa el núcleo de Linux.
•
Cabecera de lista de marcos de página inactivos (inac t ive_l i s t). Apunta al descriptor de pá­
gina del primer marco inactivo que forma parte de la lista. Esta lista es consultada por el algoritmo
de reemplazamiento de páginas que implementa el núcleo de Linux.
Finalmente, el núcleo mantiene un descriptor de nodo por cada nodo de memoria existente. Cada
descriptor de nodo se implementa mediante una estructura de tipo pg_da ta_t y contiene, entre otros,
los siguientes datos :
e
•
Identificador del nodo (node_id) . Es un número entero positivo pequeño que identifica de manera
única al nodo de memoria. Puede tomar valores entre O y N - 1 siendo N el número total de nodos
existentes.
•
A rray de los descriptores de zona (node_z one s ) . El tamaño de este array será igual al número de
zonas en que se descomponga el nodo.
•
Puntero (node_mem_map) al array mem_map que contiene los descriptores de páginas del nodo.
El tamaño de este array será igual al número de marcos de página contenidos en las zonas en que
se descompone el nodo de memoria.
Ejemplo 6. 6
En la Figura 6. 1 0 se muestra un diagrama con las estructuras de datos usadas en Linux para gestionar
la memoria principal. Se supone la existencia de un único nodo de memoria (organización UMA) con
SOBUNIX: el sistema operativo Linux
255
tres zonas de memoria definidas : ZONE_DMA, ZONE_NORMAL y Z ONE_H IGHMEM. El descriptor de nodo
contiene un puntero al comienzo del array de descriptores de página mem_map . Además posee un puntero
a cada uno de los tres descriptores de zona. Nótese que por simplificar el diagrama únicamente se ha
representado el descriptor de la zona Z ONE_NORMAL .
El campo f r e e_area [ O ] del descriptor de zona apunta al descriptor de página del primer marco de
página que forma parte de un bloque de marcos de página contiguos libres de tamaño 2° = 1 marco. En
este ejemplo sería el descriptor de página del marco j = 40. A su vez este descriptor de página contiene
un puntero al siguiente descriptor de página del marco que forma parte de esta lista, en este ejemplo el
descriptor de página del marco j = 35.
También se ha representado el comienzo de la lista de marcos de página activas. El campo a c t i ve_l i s t
del descriptor de zona apunta al descriptor de página del primer marco de página que forma parte de esta
lista, en este ejemplo el descriptor de página del marco j = 43 . A su vez este descriptor contiene un
puntero al siguiente descriptor de página del marco que forma parte de esta lista, en este ejemplo el
descriptor de página del marco j = 44.
Descriptor de nodo
(estructura pg data)
node_me m_map
-
node_zone [ O ]
r-- node_zone [ l ]
Array d e descriptores de página
estructura rnern rnap)
Estructura page
Estructura page
Estructura page
node_zone [ 2 ]
node i
:
----.
Descriptor de zona
(estructura z one)
-
f re e__pag e s
f re e_area [ O ]
Estructura page
j =3 5
Estructura page
j =4 0
Estructura page
Estructura page
j=43
j =44
f re e_are a [ l ]
fre e_are a [ 2 ]
fre e_area [ l O ]
ac t ive l i st
-
inac t ive l i st
Zona
_______----
ZONE NORMAL
-
Principales estructuras de datos usadas en Linux para gestionar la memoria principal
considerada en el Ejemplo 6.6
Figura 6.10
-
•
256
Ampliación de sistemas operativos
Traducción de direcciones virtuales
Linux soporta tablas de páginas paginadas de hasta un máximo de cuatro niveles de paginación. El
número de niveles de paginación que utiliza depende de la arquitectura del computador donde se ejecuta.
Por ejemplo en la arquitectura Intel x86 se pueden utilizar hasta dos niveles de paginación.
Para implementar los cuatro niveles de paginación, el núcleo utiliza los siguientes tipos de tablas :
•
Directorio global. Cada proceso tiene asignado un único directorio de páginas global del tamaño
de una página. Si el proceso se encuentra activo entonces su directorio de páginas global reside en
memoria principal. Cada entrada en el directorio global apunta a una página del directorio superior.
•
Directorio superior. Puede ocupar varias páginas. Cada entrada en el directorio superior apunta a
una página del directorio intermedio.
•
Directorio intermedio. Puede ocupar varias páginas. Cada entrada en el directorio intermedio apun­
ta a una página que contiene una tabla de páginas.
•
Tabla de páginas. Puede ocupar varias páginas. Cada entrada de una tabla de páginas hace refe­
rencia a una página i del espacio de direcciones virtuales del procesos.
De acuerdo con esta organización de cuatro niveles de paginación una dirección virtual se descom­
pone en cinco campos (ver Figura 6. 1 1 ) cuyos tamaños dependen de cada arquitectura:
•
•
•
•
•
Índice directorio global (IDG). Contiene el número de la entrada del directorio global donde hay
que buscar el número m del marco que contiene a la página donde se ubica al directorio superior.
Índice directorio superior (IDS). Contiene el número de la entrada del directorio superior don­
de hay que buscar el número l del marco que contiene a la página donde se ubica al directorio
intermedio.
Índice directorio intermedio (IDI). Contiene el número de la entrada del directorio intermedio
donde hay que buscar el número k del marco que contiene a la página donde se ubica la tabla de
páginas.
Índice tabla de páginas (ITP) . Contiene el número de la entrada de la tabla de páginas donde hay
que buscar el número j del marco que contiene a la página i referenciada.
Desplazamiento. Contiene el desplazamiento dentro de la página i.
Nótese que en el caso de implementar únicamente tres niveles de paginación el tamaño del campo
IDS se configura a cero.
Para implementar solo dos niveles de paginación el tamaño del directorio superior y del directorio
intermedio se fij a a uno, es decir, solo constan de una única entrada. Además las referencias a esos niveles
de indirección no utilizados se eliminan en tiempo de compilación por lo que usar un esquema de cuatro
niveles de paginación en arquitecturas que solo soportan dos niveles no afecta al rendimiento del sistema.
SOBUNIX: el sistema operativo Linux
N°
,....
D irv
�
1
IDG
1
D;,,
1
257
de página i
....,_
IDS
IDI
ITP
1
Desplazamiento
1
gistro CR3
�
l rF I
!Marco
m
JI
Figura 6.1 1
1 Marco l 1�
D1rectono supenor
D1rectono global
Marco k
Marco 1
Marco m
D irro
4
Dir F3
! Marco k
w
D1rectono mtermed10
Marco j
1 Marco}
'
$
o
Tabla de pagmas
Págma 1
- Tablas de páginas de cuatro niveles de paginación utilizadas por Linux
Asignación de memoria
El subsistema de gestión de memoria para atender las necesidades de memoria de los procesos de
usuario y de los restantes subsistemas del núcleo implementa los siguientes asignadores de memoria:
•
Asignador a nivel de página. Asigna uno o varios marcos de página contiguos utilizando el al­
goritmo budd/ . Este algoritmo agrupa los marcos de página libres en M listas. La lista k con
k = O, . . . , M - 1 contiene los grupos de 2k marcos de página contiguos libres. Por ejemplo, supues­
to un tamaño de página de 4 KiB , la lista k = O contiene los bloques libres de memoria de 4 KiB
(2° = 1 marco), la lista k = 1 contiene los bloques libres de 8 KiB (2 1 = 2 marcos contiguos), la
lista k = 2 contiene bloques libres de 16 KiB (2 2 = 4 marcos contiguos), etc.
El funcionamiento del algoritmo buddy es el siguiente: cuando llega una petición de memoria
principal contigua de H marcos de páginas contiguos lo redondea por exceso a la potencia 2k más
cercana. Si la lista k no está vacía le asigna un bloque, el cual es borrado de la lista.
Si la lista k está vacía entonces busca un bloque en la lista k + l. Si dicha lista no está vacía coge el
primer bloque de la lista, cuyo tamaño es de 2k + I marcos, y lo divide en dos bloques de 2k marcos.
U no de estos bloques se coloca al final de la lista k, el otro se asigna a la petición.
7 Buddy es una palabra inglesa que puede traducirse por amigo o compañero.
258
Ampliación de sistemas operativos
Si la lista k + 1 también esta vacía, entonces busca en la lista k + 2. Si dicha lista no está vacía coge
el primer bloque de la lista, cuyo tamaño es de 2k + 2 marcos, y lo divide en dos bloques de tamaño
2k+ l marcos. Uno de los bloques se coloca al final de la lista k + 1 , el otro lo divide en dos bloques
de tamaño 2k marcos. Uno de estos bloques se coloca en la lista k, el otro se asigna a la petición.
Si la lista k + 2 también está vacía entonces busca un bloque en la lista k + 3, repitiéndose la
operación descrita, y así sucesivamente hasta encontrar un bloque libre. Si llega a la última lista y
está vacía entonces el núcleo envía una señal de error.
Cuando se liberan marcos de página, el algoritmo realiza la operación contraria, es decir, intenta
unir bloques contiguos de tamaño 2k ubicados en la lista k en bloques de tamaño 2k+ l que coloca
en la lista k + l . Si tiene éxito entonces realiza la misma operación sobre los bloques de la lista
k + 1 , y así sucesivamente. A las parej as de bloques que consigue unir se les denomina bloques
buddies, de ahí proviene el nombre del algoritmo.
El algoritmo buddy trabaj a sobre las listas de bloques de marcos contiguos libres de una zona, cu­
yas cabeceras se encuentran en el array free_area del descriptor de zona. Dada una determinada
petición de memoria es el núcleo el que determina de que zona se debe asignar el espacio, para
ello invocará al algoritmo buddy sobre dicha zona.
e
•
Asignador de la memoria del núcleo. Asigna fragmentos de memoria principal de tamaño menor
a una página. Para realizar esta función implementa un asignador slab.
•
Asignador vma l l o c . Se utiliza para asignar grandes cantidades de espacio virtual del núcleo con­
tiguo que no requiere que esté contiguo en memoria principal, como por ejemplo cuando se cargan
dinámicamente módulos del núcleo.
Ejemplo 6.7
Supóngase que el núcleo de Linux tiene que atender una petición de memoria principal de tamaño H= 1
marco. Supóngase además que en las listas de bloques de marcos contiguos libres de la zona de donde
se realizará la asignación únicamente existe en la lista k = 3 un bloque D 1 de 8 marcos contiguos libres
(ver Figura 6 . 1 2a) . El núcleo entonces comienza a aplicar el algoritmo buddy para atender la petición de
memoria. En primer lugar el algoritmo determina que la petición de memoria se puede atender con un
bloque de tamaño 2° = 1 marco y busca en la lista k = O un marco libre. Como no existe ninguno busca
entonces en la lista k = 1 un bloque libre de 2 marcos contiguos, pero esta lista también está vacía. Pasa
entonces a buscar en la lista k = 2 un bloque libre de 4 marcos contiguos pero tampoco existe ninguno.
A continuación busca en la lista k = 3 un bloque libre de 8 marcos contiguos. Selecciona entonces el
bloque D l .
Una vez seleccionado el bloque D l lo elimina de la lista k = 3 y lo divide en dos bloques C l y C2 de
4 marcos cada uno (ver Figura 6. 1 2b). A continuación coloca al bloque C2 en la lista k = 2 y al bloque
C l lo divide en dos bloques B l y B2 de 2 marcos cada uno (ver Figura 6. 1 2c). Posteriormente coloca al
bloque B2 en la lista k = 1 y al bloque B l lo divide en dos bloques A l y A2 de 1 marco cada uno (ver
SOBUNIX: el sistema operativo Linux
C2 (4)
C2 (4)
C2 (4)
C2 (4)
B2 (2)
B2 (2)
B2 (2)
A2 ( l )
Al (l)
A2 ( l )
Al (l)
(d)
(e)
259
D l (8)
C l (4)
B l (2)
(a)
(b)
(e)
Estado del conjunto de 8 marcos contiguos de memoria principal del Ejemplo 6.7 al ir
aplicando el algoritmo buddy
Figura 6.12 -
Figura 6. 1 2d). Finalmente, coloca al marco A2 en la lista k
Figura 6. 1 2e).
=
O, y asigna el marco A 1 a la petición (ver
•
Reemplazamiento de páginas
En Linux el reemplazamiento de páginas es realizado por kswapd, un proceso del sistema. Existe
una instancia de este proceso por cada nodo de memoria definido. kswapd se despierta periódicamente
y comprueba si el número de marcos de página libres en cada zona de memoria se encuentra dentro
de un determinado rango de valores. En caso afirmativo kswapd se vuelve a dormir. En caso negativo
selecciona un determinado número de marcos de página para ser incorporados en la lista de marcos
libres. El número de páginas que se seleccionan es un parámetro configurable, cuyo valor por defecto es
32. kswapd también puede ser despertado si el núcleo detecta una disminución drástica de memoria.
Para seleccionar los marcos de página cuyo contenido puede ser reemplazado Linux utiliza el algo­
ritmo para reclamar marcos de página (Page Frame Reclaiming Algorithm, PFRA) que es una variante
del algoritmo del reloj y una aproximación del algoritmo LRU.
El algoritmo PFRA trabaj a con la lista de marcos de página activos y con la lista de marcos de
página inactivos de cada zona. La lista de marcos de página activos contiene los descriptores de página
de los marcos que almacenan páginas que han sido referenciadas recientemente. Por su parte, la lista de
marcos de página inactivos contiene los descriptores de página de los marcos que almacenan páginas
que llevan algún tiempo sin ser referenciadas. Dentro de cada lista los descriptores de página de los
marcos son ordenados mediante una aproximación de la política LRU. Por ello a estas listas también se
las denomina de forma global como listas LRU.
Para decidir en que lista debe colocar un marco de página el algoritmo PFRA utiliza los indicadores
PG_r e f erenced y PG_ac t ive existentes en el campo f l ags de la estructura page asociado a un
descriptor de página. Por simplificar la notación se va a denotar a los indicadores PG_r e f erenced y
PG_a c t i ve con las letras r y a, respectivamente.
260
Ampliación de sistemas operativos
Cada vez que una página i cargada en un marco j es referenciada, el núcleo activa el indicador r
del marco, es decir, r = l. Por otra parte, si un marco pertenece a la lista de marcos de página activos
entonces a = 1 , mientras que si pertenece a la lista de marcos de página inactivos entonces a = O.
Cuando se ejecuta el algoritmo PFRA éste examina el indicador r de los descriptores de página de
los marcos de una determina zona. Si r estaba activado (r = 1) entonces lo desactiva (r = 0). Cuando
termina de examinarlos, comienza a realizar una segunda ronda. Nótese que durante el tiempo entre la
primera y la segunda comprobación de un mismo marco éste ha podido volver a ser referenciado y su
indicador r estar activado. Si durante la segunda ronda el algoritmo encuentra un marco j con r = 1
y cuyo bit r hubiera sido desactivado en la primera ronda entonces el algoritmo vuelve a desactivarlo,
activa a y coloca al marco en la lista de marcos de página activos . Luego para que un marco j ingrese en
la lista de marcos de página activos debe encontrarse con el bit r activado en dos rondas del algoritmo
PFRA.
Nótese que en función del par de valores (r, a) un marco de página puede encontrarse en alguno de
los siguientes estados:
•
Estado So: (r = O, a = 0). Un marco en este estado no ha sido referenciado recientemente y se
encuentra en la lista de marcos de página inactivos. Son los mej ores candidatos para ser seleccio­
nados para reemplazar su contenido, es decir, para ingresar en la lista de marcos libres.
•
Estado S 1 : (r = 1, a = 0). Un marco en este estado ha sido referenciado recientemente y se
encuentra en la lista de marcos de página inactivos . Puede llamar la atención que un marco que
contiene una página que ha sido recientemente referenciada se incluya en la lista de marcos de
página inactivos, esto se hace para tener en cuenta situaciones en las que un proceso referencia a
una página y no vuelve a hacerlo hasta mucho tiempo después . Obviamente dicha página no debe
figurar en la lista de marcos de página activos y puede ser sustituida.
•
Estado S 2 : (r = O, a = 1 ) . Un marco en este estado acaba de ingresar en la lista de marcos de página
activos, o ya estaba en la lista de marcos de página activos y no ha sido referenciado recientemente.
•
Estado S 3 : (r = 1 , a = 1 ) . Un marco en este estado se encuentra en la lista de marcos de página
activos y ha sido referenciado recientemente. Los marcos en este estado son los peores candidatos
para reemplazar su contenido ya que producirán fallos de página.
En definitiva si una página i es frecuentemente referenciada el estado del marco j que la contiene irá
pasando por los estados S 0 , S 1 , S 2 y S 3 . Por el contrario si una página dej a de ser referenciada, entonces
pasará del estado S 3 al estado S 2 , si se encontraba en la lista de marcos de página activos, o del estado
S 1 al estado So, si se encontraba en la lista de marcos de página activos.
También en situaciones de memoria libre muy escasa, marcos de la lista de marcos de página activos
pueden ser transferidos a la lista de marcos de página inactivos . O visto en términos de estados un marco
en el estado S 3 o S 2 puede pasar a los estados S 1 o S 0 , respectivamente. En la Figura 6. 1 3 se muestra el
diagrama de estados de un marco de página al aplicar el algoritmo PFRA 8 .
8Conviene señalar que existen otras posibles transiciones que n o han sido comentadas en e l texto ni incluidas en este
diagrama con objeto de simplificar su comprensión.
SOBUNIX: el sistema operativo Linux
261
Probabilidad de ser reemplazado
Alta
Baj a
r---------------------------------1
Memoria libre muy escasa
1
Memoria libre muy escasa
Lista de marcos inactivos
Figura 6.13 -
Lista de marcos activos
Diagrama de estados de un marco de página al aplicar el algoritmo PFRA
El algoritmo PFRA selecciona de la lista de marcos de página inactivos de una zona las páginas que
pueden ser reemplazadas. Primero escoge a los marcos en el estado So, ya que son los mej ores candidatos
para reemplazar su contenido. Cuando éstos se acaban entonces selecciona a los marcos en el estado S 1 .
6.6.
Gestión de archivos en Linux
La gestión de archivos en Linux es similar a la gestión de archivos de otros SOBUNIX descrita en
el capítulo 5 . En las siguientes secciones se describen las particularidades de Linux en relación con la
gestión de archivos. En concreto se describe la implementación que realiza Linux de la capa nodo virtual/
sistema de archivos virtual. Además se describen las características de tres de los sistemas de archivos
más conocidos desarrollados para Linux: EXT2, EXT3 y EXT4.
6.6.1.
Implementación de la capa nodo virtual/sistema de archivos virtual en Linux
Linux puede trabaj ar con diferentes tipos de sistemas de archivos : sistemas de archivos desarrollados
para Linux (EXT2, EXT3 , EXT4, ReiserFS , . . . ), sistemas de archivos desarrollados para otros SOBUNIX
(S5FS , UFS , VERITAS VxFS , . . . ), sistemas de archivos desarrollados para otros sistemas operativos no
basados en UNIX (FAT, NTFS , HPFS, HFS , . . . ), sistemas de archivos desarrollados para discos ópticos
(IS09660, UDF, . . . ), sistemas de archivos en red (NFS , Coda, AFS , CIFS , NCP, . . . ), y sistemas de archivos
especiales, que son aquellos que no consumen espacio de disco, sino que se implementan en la memoria
principal, como por ejemplo procfs ubicado en / p r o c .
262
Ampliación de sistemas operativos
Para soportar todos estos tipos de sistemas de archivos Linux utiliza la capa nodo virtual/ sistema de
archivos virtual. En Linux a esta capa se le denomina capa VFS y se implementa mediante las siguientes
estructuras de datos:
•
Objeto superbloque. Es la implementación que realiza Linux de un sistema de archivos virtual.
Es una estructura tipo sup e r_b l o c k que representa a un sistema de archivos activo. El núcleo
mantiene una lista enlazada de todos los superbloques existentes en memoria. En el caso de los
sistemas de archivos ubicados en disco, un superbloque contiene una copia del bloque de control
(superbloque) del sistema de archivos al que está asociado. Además contiene otros datos adiciona­
les, entre ellos, un puntero s_op a un array de punteros a funciones dependientes del sistema de
archivos que implementan todas las posibles operaciones sobre un superbloque: leer el superbloque
del disco, escribir el superbloque del disco, leer un nodo-i, borrar un nodo-i, etc.
•
Objeto nodo-i. Es la implementación que realiza Linux de un nodo virtual. Es una estructura tipo
inode que representa a un archivo activo. El núcleo mantiene una tabla de nodos-i con todos
los nodos-i cargados en memoria. En el caso de los sistemas de archivos ubicados en disco, un
nodo-i contiene una copia del nodo-i asociado al archivo en el disco. Además contiene otros datos
adicionales, como por ejemplo: un puntero al objeto superbloque asociado al sistema de archivos
al que pertenece el nodo-i, un contador de referencias, y un puntero i_op a un array de punteros
a funciones dependientes del sistema de archivos que implementan todas las posibles operaciones
sobre un nodo-i : crear, buscar, crear un enlace, etc.
•
Objeto entrada de directorio. Es una estructura tipo dent ry que representa a una entrada de un
directorio, es decir, a un componente de un nombre de ruta. Contiene, entre otros, los siguientes
datos: contador de referencias, puntero al objeto nodo-i asociado con el componente del nombre
de ruta, nombre del archivo, puntero al objeto entrada de directorio del directorio padre, puntero al
objeto superbloque asociado al sistema de archivos al que pertenece el archivo, y un puntero d_op
a un array de punteros a funciones dependientes del sistema de archivos que implementan todas
las posibles operaciones sobre un objeto entrada de directorios: comparar, borrar, liberar, etc.
El núcleo utiliza las estructuras dentry para implementar la caché de búsqueda de nombres en
directorios ( dent ry_c ache ) . Cada vez que tiene que analizar un nombre de ruta, comprueba si
el objeto entrada de directorio del componente que analiza se encuentra en la caché. En caso de
acierto se evita tener que acceder al disco para leer el nodo-i correspondiente. En caso de fallo
tras leer el nodo-i del disco crea un objeto entrada de directorio asociada a dicho componente
que incluye en la caché. Por ejemplo, si el núcleo ha tenido que analizar recientemente el nombre
de ruta 1 d i r l 1 archi vo l , entonces existirán en la caché un objeto entrada de directorio para el
directorio raíz 1 , otro para el directorio d i r l y otro para el archivo archi vo l .
•
Objeto archivo abierto. E s una estructura tipo f i l e que contiene l a información necesaria para
poder operar con un archivo abierto por un proceso, como por ejemplo: un contador de referencias,
el modo de apertura del archivo, el puntero de lectura/escritura, un puntero al obj eto entrada de
directorio asociados al archivo, y un puntero f_op a un array de punteros a funciones dependientes
SOBUNIX: el sistema operativo Linux
263
del sistema de archivos que implementan todas las posibles operaciones sobre un archivo: leer,
escribir, etc.
e
Ejemplo 6. 8
Supóngase que en un sistema Linux dos procesos A y B abren el mismo archivo. El núcleo crea un
objeto de archivo abierto para cada proceso (ver Figura 6. 14). Cada objeto de archivo abierto, contiene
un puntero al objeto de entrada de directorio asociada a la entrada del directorio del archivo. Dicho objeto
contiene un puntero al objeto nodo-i asociado al archivo y al objeto superbloque asociado al sistema de
archivos al que pertenece el archivo. El objeto nodo-i contiene una copia del nodo-i asociado al archivo
en el disco, el cual contiene la información necesaria para poder localizar en el disco los bloques de datos
del archivo.
s t ru c t
Objeto nodo-i
file
s t ru c t
s t ru c t
dent ry
s t ru c t
file
,' Obj etos archivos
abiertos
!
Objeto
entrada
directorio
\
:
l'
,
!'
i node
,....----l�--,
s t ru c t
!
l
B loques
O O de datos
O del archivo
sup e r_b l o c k
:,
l
l
:'
Partición de disco duro
sistema de archivos
Objeto superbloque
¡
•---------------------------------------------------------------------------------------------·
Estructuras en memoria principal
Figura 6.14 -
Estructuras de datos del Ejemplo 6.8 que implementan la capa VFS
•
6.6.2.
El sistema de archivos EXT2
La primera versión del núcleo de Linux utilizaba como sistema de archivos principal una adaptación
directa del sistema de archivos usado en MINIX. Este sistema de archivos tenía serias limitaciones en
relación al tamaño máximo de un archivo y al número de caracteres que podía tener un nombre. Por este
motivo en 1 992 se desarrolló otro sistema de archivos para sustituirlo: el sistema de archivos extendido
(EXTended filesystem, EXT). Sin embargo, el rendimiento y la funcionalidad del sistema EXT todavía
estaba lejos de las de otros sistemas de archivos comerciales. Por ello no tardó en ser mej orado y al año
siguiente se presentó el segundo sistema de archivos extendido (Second EXTended filesystem, EXT2)
que estaba basado en el sistema de archivos FFS de BSD.
264
Ampliación de sistemas operativos
Estructura de un sistema de archivos EXT2
Un sistema de archivos EXT2 cuando se crea en una partición de disco presenta una estructura
similar a la que se muestra en la Figura 6 . 1 5 . El primer bloque de la partición es el bloque de arranque
que contiene el código necesario para arrancar Linux si dicha partición se utiliza como partición activa.
El resto de la partición se divide en NG grupos de bloques. El tamaño máximo de un grupo es igual
a 8 · SB bloques, donde SB = 1 , 2 o 4 KiB es el tamaño de bloque, el cual se fija en el momento de la
creación del sistema. En cada grupo de bloques se distinguen los siguientes componentes :
•
Copia del superbloque. El superbloque ocupa un bloque y contiene información estadística y ad­
ministrativa del sistema de archivos: número mágico que identifica al sistema como de tipo EXT2,
tamaño de un bloque de datos, número total de bloques y de nodos-i, número de bloques y de
nodos-i libres, fecha y hora de la última modificación del sistema de archivos, hora y fecha del
montaje del sistema, etc.
Puesto que la información contenida en el superbloque es crítica para el funcionamiento del sis­
tema el superbloque se duplica en cada grupo de bloques en previsión de posibles errores o de
la corrupción del sistema. El núcleo normalmente trabaj a con el superbloque del primer grupo de
bloques.
•
Copia de la tabla de descriptores de grupo. Un descriptor de grupo es una estructura que datos
que describe a un grupo de bloques. Contiene la siguiente información sobre un grupo: la dirección
del bloque que contiene el mapa de bits de bloques de datos del grupo, la dirección del bloque que
contiene el mapa de bits de nodos-i del grupo, la dirección del bloque que contiene la tabla de
nodos-i del grupo, contador de bloques libres, contador de nodos-i libres y contador de directorios
existentes.
Todos los descriptores de grupos se organizan en una tabla de descriptores de grupo, la cual ocupa
varios bloques consecutivos . Al igual que sucede con el superbloque, la tabla de descriptores es
una estructura fundamental para el funcionamiento del sistema por lo que es duplicada en todos
los grupos de bloques, a continuación de la copia de superbloque. El núcleo normalmente trabaj a
con l a tabla de descriptores d e grupo ubicada e n el primer grupo d e bloques.
•
Mapa de bits de bloques de datos existentes en el grupo. Ocupa un bloque. Cada bloque de datos
existente en el grupo de bloques tiene asignado un bit en el mapa. Si el bit está desactivado significa
que el bloque está libre. Cuando el núcleo tiene que asignar bloques de datos para un archivo
consulta este mapa.
•
Mapa de bits de nodos-i existentes en el grupo. Ocupa un bloque. Su estructura y utilidad es similar
a la descrita para el mapa de bits de bloques de datos pero aplicada a los nodos-i.
•
Tabla de nodos-i existentes en el grupo. Ocupa varios bloques consecutivos. En EXT2 un nodo-i
tiene un tamaño de 1 28 bytes, luego en un bloque de la tabla se pueden almacenar SB / 1 28 nodos-i.
•
Á rea de datos. Contienen los bloques de datos de los archivos y directorios.
265
SOBUNIX : el sistema operativo Linux
Partición de disco
Grupo de bloques
o
Grupo de bloques
NG- 1
Grupo de bloques
1
���
�------�--�
- - - - - - - - - - - -
- - - - - - - - - - - - -
Mapa de bits de
nodos-i
Figura 6.15 -
Tabla
de nodos-i
� ��
Á rea de datos
Estructura en disco de un sistema de archivos EXT2
Implementación de directorios en EXT2
En un sistema de archivos EXT2 la lista de archivos y subdirectorios de un directorio se implementa
con entradas de tamaño variable. Cada entrada presenta la siguiente estructura:
•
Número de nodo-i. Es un campo de 4 bytes que contiene el número del nodo-i del archivo o
subdirectorio al que está asociada esta entrada del directorio.
•
Longitud en bytes de la entrada. Es un campo de 2 bytes que contiene la suma del tamaño de todos
los campos existentes en la entrada.
•
Longitud en bytes del nombre. Es un campo de 1 byte que contiene el tamaño en bytes de la cadena
de caracteres del nombre del archivo al que está asociada la entrada.
•
Tipo del archivo. Es un campo de 1 byte en el que se almacena un número entero positivo pequeño
que identifica el tipo del archivo: archivo regular ( 1 ), directorio (2), dispositivo modo carácter (3),
dispositivo modo bloque (4), FIFO (5), conector (6) y enlace simbólico (7).
•
Nombre del archivo. Este campo es de longitud variable y su tamaño máximo queda limitado a
256 bytes, luego la longitud máxima del nombre de un archivo es de 255 caracteres. Después del
nombre del archivo se incluye un carácter nulo \ 0 para marcar el final del nombre. Además se
incluyen tantos caracteres nulos como sea necesario hasta alcanzar una frontera de 4 bytes.
1
11
•
•
1
Las dos primeras entradas de la lista de un directorio siempre están asignadas a las entradas
que hacen referencia al propio directorio y al directorio padre, respectivamente.
11
,
1
•
1
y
266
e
Ampliación de sistemas operativos
Ejemplo 6 . 9
En la Figura 6. 1 6 se muestra un ejemplo de la implementación de un directorio en un sistema EXT2.
El directorio consta de 4 entradas : la primera asignada a la entrada
la segunda a la entrada
la
tercera asignada al archivo ordinario prueba y la cuarta asignada al directorio f o t o s . Las dos primeras
entradas tienen un tamaño de 1 2 bytes, mientras que las dos últimas tienen un tamaño de 1 6 bytes. Se
observa como el nombre de una entrada siempre termina con un carácter nulo \ O seguido de otros tantos
caracteres nulos como sea necesario hasta completar una frontera de 4 bytes.
1 • 1,
1 •
1
• 1,
1
o
Long1tud entrad a (2 b ytes
-
Longitud nombre ( 1 byte)
- Tipo de archivo ( 1 byte)
Nombre + carafteres de relleno
N° nodo-i ( 4 bytes)
•
35
12
1
2
\0 \0 \0
36
12
2
2
\0
\0
51
16
6
1
p
r
u
e
b
15
16
5
2
f
o
t
o
S
Figura 6.16 -
a \0
1
\0
\0 \0 \0
Implementación de un directorio en EXT2
•
Localización de los bloques de datos de un archivo en EXT2
Un nodo-i de un sistema EXT2, como suele ser habitual en los SOBUNIX, se asocia a un determinado
archivo y contiene, entre otros, los siguientes datos sobre el mismo: máscara de modo, UID, GID, tamaño
en bytes, fecha y hora del último acceso, fecha y hora de la última modificación de un campo del nodo-i
(excluidos los de fecha y hora), fecha y hora de la última modificación del archivo, contador de enlaces
duros, contador de bloques y localización de los bloques de datos del archivo.
Para localizar los bloques de datos del archivo su nodo-i mantiene las direcciones de los 1 2 primeros
bloques de datos del archivo, así como las direcciones de un bloque de indirección simple, un bloque de
indirección doble y un bloque de indirección triple.
Asignación de espacio en EXT2
En un sistema de archivos EXT2 el núcleo consulta los mapas de bits de los grupos de bloques para
decidir que espacio asignar. Con el objetivo de aprovechar mej or el espacio de la partición e intentar
reducir los tiempos de búsqueda en el disco el núcleo realiza la asignación de espacio siguiendo las
siguientes directrices [Tanenbaum, 2009] :
S OBUNIX: el sistema operativo Linux
267
•
Los bloques de datos de un mismo archivo se intentan alojar, siempre que sea posible, en bloques
de datos contiguos en el disco. Además cada vez que se necesita asignar un bloque para un archivo
se le preasignan por adelantado 8 bloques adicionales contiguos en previsión de que los vaya a
necesitar. Con estas medidas se pretende reducir la fragmentación externa del disco.
•
Los nodos-i de los directorios se dispersan entre los grupos de bloques existentes.
•
Un archivo se intenta aloj ar, si existe espacio, en el mismo grupo de bloques que su directorio
padre.
•
Los bloques de datos de un archivo se intentan aloj ar en el mismo grupo donde se encuentre su
nodo-i.
Otras características
Un sistema de archivos EXT2 proporciona soporte para enlaces simbólicos rápidos, los cuales se
implementan de la siguiente forma: si el nombre de ruta al que va hacer referencia el enlace simbólico
es mayor de 60 bytes entonces se almacena en los bloques de datos del archivo del enlace simbólico, en
caso contrario se almacena directamente en el nodo-i del enlace simbólico con lo que se ahorra espacio
en disco y el acceso es más rápido.
Por otra parte, EXT2 soporta archivos inmutables, que nunca pueden ser modificados (ni siquiera por
el superusuario), y archivos de solo-añadir, a los que solo se les puede ir añadiendo datos al final.
La consistencia de un sistema de archivos EXT2 suele verificarse si Linux no se ha cerrado correcta­
mente, por ejemplo debido a una falta de suministro eléctrico, o tras un número prefijados de montajes.
El programa 1 sbin/ e 2 f se k permite realizar esta verificación.
6.6.3.
El sistema de archivos EXT3
El tercer sistema de archivos extendido (Third EXTended filesystem, EXT3) es una versión mejorada
de EXT2 que fue introducida en la versión 2.4. 1 5 del núcleo de Linux liberada a finales de 200 1 . Cual­
quier sistema EXT2 puede ser convertido en un sistema EXT3 de forma fácil y sencilla sin necesidad de
formatear la partición de disco, ya que EXT3 fue diseñado pensando en ser totalmente compatible con
EXT2, de hecho utiliza la misma estructura en disco.
La principal diferencia entre EXT3 y EXT2 es que EXT3 implementa la técnica de registro por
diario (journaling), que consiste en que el sistema operativo genera un informe con las operaciones que
tiene que realizar sobre el sistema de archivos antes de realizarlas. Dicho informe se almacena en un
área reservada de la partición de disco denominada diario (joumal). Una vez que el informe ha sido
escrito en el diario se comienzan a realizar las operaciones planificadas. Cuando dichas operaciones han
sido completadas el informe se borra. Si se produce algún fallo antes de que se puedan completar todas
las operaciones planificadas, cuando se reinicia el sistema operativo éste lee el diario para comprobar si
existe un informe. En caso afirmativo se repiten una a una todas las operaciones para que el sistema de
archivos quede de nuevo en un estado consistente.
268
Ampliación de sistemas operativos
El tiempo para recuperar un sistema EXT3 , a diferencia de un sistema EXT2, ya no depende del
tamaño del sistema de archivos ni del número de archivos que contiene sino del tamaño del diario.
Otra característica importante de un sistema EXT3 , no disponible en EXT2, es que EXT3 puede
trabaj ar con fragmentos de archivos, es decir, datos de un archivo que no completan un bloque. Los
fragmentos de diferentes archivos se pueden almacenar en un mismo bloque, reduciéndose así la frag­
mentación interna.
6.6.4.
El sistema de archivos EXT4
El cuarto sistema de archivos extendido (Fourth EXTended filesystem, EXT4) es una versión me­
jorada de EXT3 cuya implementación estable fue introducida en la versión 2.6.28 del núcleo de Linux
liberada a finales de 2008. Entre las principales características de un sistema EXT4 destacan las siguien­
tes [Mathur et al. , 2007] :
•
Es plenamente compatible con EXT3 . Cualquier sistema EXT3 puede ser montado como sistema
EXT4 sin necesidad de formatear la partición de disco.
•
Incorpora el uso de extends para mejorar el rendimiento y reducir la fragmentación al trabaj ar
con archivos de gran tamaño. Un extend es un conjunto de bloques físicos contiguos. El tamaño
máximo que puede tener un extend depende del tamaño de bloque, por ejemplo con un tamaño de
bloque de 4 KiB un extend puede tener un tamaño máximo de 128 MiB .
•
Implementa comprobaciones adicionales en la técnica de registro por diario para mejorar su fiabi­
lidad.
•
Soporta la asignación de múltiples bloques para un mismo archivo en un sola operación lo que
reduce la fragmentación.
•
Implementa la técnica de reserva retrasada de espacio (Allocate-on-flush o delayed allocation) que
consiste en retrasar la asignación de espacio en el disco para realizar una operación de escritura
hasta justo el momento en que la información va a ser escrita. Nótese la diferencia con otros
sistemas de archivos donde la reserva de espacio se realiza previamente a realizar la operación de
escritura. Esta técnica se implementa de la siguiente forma: cuando se deben asignar bloques del
disco para realizar una operación de escritura el espacio necesario se resta del contador de espacio
libre del superbloque, pero no se asigna en el mapa de bits. En su lugar los datos que hay que
escribir son almacenados en buffers en la memoria principal hasta que el núcleo decide escribir
los buffers modificados en el disco. Usando esta técnica se consigue mejorar el rendimiento del
sistema y disminuir la fragmentación.
•
La comprobación del estado de un sistema EXT4 con el programa ext 2 f s c k se realiza mucho
más rápidamente ya que en EXT4 los grupos de bloques y las secciones de la tabla de nodos-i que
no están asignadas son marcadas como tales lo que permite a ext 2 f s c k saltárselas.
En general el soporte por parte del núcleo de un sistema EXT4 requiere de un menor uso del proce­
sador. Además su implementación y gestión mejora la velocidad de lectura y escritura en el disco.
SOBUNIX: el sistema operativo Linux
6. 7.
269
Resumen
El sistema operativo Linux es un SOBUNIX de código libre escrito en su primera versión por Linus
Benedict Torvalds. El acceso libre y gratuito al código fuente de Linux ha propiciado que miles de
personas en todo el mundo colaboren con Linus desinteresadamente en el desarrollo y mejora de Linux.
En Linux un proceso monohilo, un proceso ligero o un hilo del núcleo es considerado simplemente un
flujo de ejecución independiente o tarea que debe ser planificada y ejecutada. La creación de procesos
en Linux, al igual que en otros SOBUNIX, se puede realizar mediante la llamada al sistema f ork.
Además Linux dispone de la llamada al sistema e l one para crear un nuevo proceso ligero asociado al
proceso invocador de la llamada. Esta llamada es bastante potente y flexible ya que permite especificar
los recursos asociados al proceso creador que se desean que sean accedidos por el proceso ligero que es
creado. Esta llamada también permite crear un nuevo proceso de la misma forma que la llamada f o rk.
Linux es un sistema operativo de núcleo expropiable que utiliza como unidad de planificación a las
tareas. Cada tarea tiene asignada una prioridad, que desde el punto de vista del núcleo es un número
entero positivo comprendido dentro del rango de valores [0, 1 39], siendo O la prioridad más alta posible
y 1 39 la más baja. El núcleo siempre planifica a la tarea en el estado ejecutándose de mayor prioridad.
Dicha tarea será expropiada si entra en el estado ejecutándose una tarea de mayor prioridad. A las tareas
con prioridad comprendida en el rango [ 1 00, 1 39] se les considera tareas convencionales o tareas de
tiempo compartido. A las tareas con prioridad comprendida en el rango [0, 99] se les considera tareas de
tiempo real.
En Linux el tamaño del espacio de direcciones virtuales de un proceso es tres veces mayor que el
tamaño del espacio de direcciones del núcleo. Linux divide la memoria principal en nodos de memoria. El
tiempo de acceso a una posición de memoria de un determinado nodo es siempre el mismo. Obviamente
en una organización UMA existirá un único nodo de memoria, mientras que en una organización NUMA
existirá un nodo de memoria por cada memoria local de un procesador. Por otra parte, Linux considera
las particularidades de direccionamiento (tamaño de registros, líneas de direccionamiento para DMA,
etc) de cada arquitectura hardware, descomponiendo cada nodo de memoria en zonas, que son regiones
contiguas de memoria principal.
Linux soporta tablas de páginas paginadas de hasta un máximo de cuatro niveles de paginación. El
número de niveles de paginación que utiliza depende de la arquitectura del computador donde se ejecuta.
Por ejemplo en la arquitectura Intel x86 se pueden utilizar hasta dos niveles de paginación.
En Linux el asignador a nivel de página del subsistema de gestión del núcleo utiliza el algoritmo
buddy para asignar uno o varios marcos de página contiguos. Por otra parte, en Linux el asignador de la
memoria del núcleo implementa un asignador slab.
Para seleccionar los marcos de página cuyo contenido puede ser reemplazado Linux utiliza el algo­
ritmo para reclamar marcos de página o algoritmo PFRA que es una variante del algoritmo del reloj y
una aproximación del algoritmo LRU.
Los sistemas de archivos nativos de Linux más conocidos son: EXT2, EXT3 o EXT4. Además Linux
puede trabaj ar con otros tipos de sistemas de archivos . Para poder soportar diferentes tipos de sistemas
de archivos Linux utiliza la capa nodo virtual/ sistema de archivos virtual. En Linux a esta capa se le
denomina capa VFS y se implementa mediante las siguientes estructuras de datos : objeto superbloque
270
Ampliación de sistemas operativos
(implementa un sistema de archivos virtual), objeto nodo-i (implementa un nodo virtual), objeto entrada
de directorio y objeto archivo abierto.
6.8.
Lecturas recomendadas
Si se desea obtener una explicación adicional y ampliar los contenidos tratados en este capítulo se
pueden consultar, por ejemplo: [Bovet y Cesati, 2005], [Mauerer, 2008] , [Love, 20 1 0] y el capítulo 1 0
de [Tanenbaum, 2009] .
6.9.
Autoevaluación
6. 1 . ¿Qué se entiende por tarea en Linux? ¿ Y por grupo de hilos? (Respuesta en sección 6.3)
6.2. Enumerar y explicar brevemente la información contenida en una estructura task_s t ruc t de
Linux. (Respuesta en sección 6 . 3 . 1 )
6.3 . Dibujar e l diagrama de transición d e estados de las tareas e n Linux adecuadamente rotulado. Ex­
plicar brevemente el diagrama dibuj ado. (Respuesta en sección 6.3 . 1 )
6.4. Dibuj ar un diagrama, adecuadamente rotulado, donde s e representa la relación existente entre las
estructuras del núcleo de Linux asignadas a una tarea. Explicar brevemente el diagrama dibuj ado.
(Respuesta en sección 6.3 . 1 )
6. 5 . Explicar el uso y l a sintaxis de l a llamada al sistema c l on e . (Respuesta en sección 6.3 .2)
6. 6. ¿Qué función tienen los hilos del núcleo en Linux? (Respuesta en sección 6.3.3)
6.7. Dibujar un diagrama, adecuadamente rotulado, de la escala de prioridades de ejecución considera­
da por el núcleo de Linux. (Respuesta en sección 6.4)
6. 8. ¿Qué inconveniente presentaba el planificador implementado en las primeras versiones de Linux?
(Respuesta en sección 6.4. 1 )
6. 9. ¿Por qué s e caracteriza e l planificador 0( 1 ) de Linux? ¿En que versión de Linux s e introdujo?
(Respuesta en sección 6.4. 1 )
6. 10. ¿Para que s e utiliza l a estructura runqueue? ¿Qué información contiene?
(Respuesta en sección 6.4. 1 )
6. 1 1 . Explicar las políticas de planificación qué se distinguen en el planificador 0( 1 ) de Linux.
(Respuesta en sección 6.4. 1 )
6. 12. Explicar l a asignación de l a prioridad de una tarea en Linux. (Respuesta en sección 6.4. 1 )
SOBUNIX: el sistema operativo Linux
271
6. 13. Explicar las principales características del planificador utilizado a partir de la versión 2.6.23 del
núcleo de Linux. (Respuesta en sección 6.4.2)
6. 14. Explicar el funcionamiento del algoritmo CFS . (Respuesta en sección 6.4.2)
6. 15. ¿Para qué se utiliza la estructura rq? ¿Qué información contiene? (Respuesta en sección 6.4.2)
6. 16. Explicar la gestión del espacio de direcciones virtuales en Linux (Respuesta en sección 6.5 . 1 )
6. 17. Dibuj ar un diagrama, adecuadamente rotulado, de las estructuras de datos que utiliza Linux para
gestionar el espacio de direcciones virtuales de un proceso. (Respuesta en sección 6 .5 . 1 )
6. 18. Explicar l a distinción entre nodos y zonas que realiza Linux al gestionar l a memoria principal
(Respuesta en sección 6.5 .2)
6. 19. Enumerar y explicar brevemente las estructuras de datos que utiliza Linux para gestionar la me­
moria principal. (Respuesta en sección 6.5 .2)
6.20. Enumerar los tipos de tablas que el núcleo de Linux utiliza para implementar los niveles de pagi­
nación. Dibujar los campos en que se descompone una dirección virtual en Linux.
(Respuesta en sección 6.5 .2)
6. 21 . Enumerar los asignadores de memoria implementados en Linux. (Respuesta en sección 6.5 .2)
6. 22. Explicar el funcionamiento del algoritmo buddy (Respuesta en sección 6.5 .2)
6.23. ¿Qué proceso se utiliza en Linux para realizar el reemplazamiento de páginas? ¿Cuándo se ejecuta?
(Respuesta en sección 6.5 .2)
6.24. Explicar el funcionamiento del algoritmo PFRA. (Respuesta en sección 6.5 .2)
6.25 . Dibujar el diagrama de estados de un marco de página al aplicar el algoritmo PFRA.
(Respuesta en sección 6.5 .2)
6. 26. Explicar la implementación de la capa nodo virtual/sistema de archivos virtual en Linux.
(Respuesta en sección 6.6. 1 )
6. 27. Explicar la estructura de un sistema de archivos EXT2 (Respuesta en sección 6.6 .2)
6.28. Explicar la implementación de directorios en EXT2 (Respuesta en sección 6.6.2)
6. 29. ¿Qué directrices se siguen en EXT2 para asignar espacio en el disco? (Respuesta en sección 6.6.2)
6. 30. Enumerar las principales características de un sistema de archivos EXT3 .
(Respuesta en sección 6.6.3)
6. 31 . Enumerar las principales características de un sistema de archivos EXT4.
(Respuesta en sección 6.6.4)
272
Ampliación de sistemas operativos
6.10.
Ejercicios
6 . 1 Considérese el programa prog 6 1 (ver Figura 6.2) del Ejemplo 6. 1 . Contestar a los siguientes
apartados :
a ) ¿Es posible haciendo uso del comando ki l l enviar una señal a u n determinado hilo del
proceso asociado al programa prog 6 1 ?
b) Consultar el manual de ayuda, o l a bibliografía que considere necesaria, para determinar las
llamadas al sistema, las funciones de librerías o los comandos que se pueden utilizar en Linux
para enviar una señal a un determinado hilo de un proceso.
6.2 Considérese el programa prog 6 2 (ver Figura 6.4) del Ejemplo 6.3. Contestar a los siguientes
apartados :
a) ¿Qué sucede s i la llamada a l sistema c l one e s invocada únicamente con l a constante simbólica CLONE_THREAD?
b) ¿Y si se invocara con las constantes CLONE_THREAD 1 CLONE_VM?
e) ¿Y si se invocara con las constantes CLONE_THREAD 1 CLONE_S IGHAND?
d) ¿Qué conclusión se deduce del resultado de los apartados anteriores?
6 .3 Ejecutar en un sistema Linux el comando ps ax y explicar brevemente la información que muestra
en pantalla.
6.4 Ejecutar en un sistema Linux el comando t op y explicar brevemente la información que muestra
en pantalla.
6. 5 En una partición de 32 GiB se ha creado un sistema de archivos EXT2 que utiliza un tamaño de
bloque de 4 KiB . Determinar:
a) Tamaño máximo de un grupo de bloques.
b) Número de grupos de bloques en que se dividirá la partición.
e) Número de nodos-i que se pueden almacenar en un bloque.
d) Tamaño máximo que en teoría podría tener un archivo si la partición pudiera ser mayor de 32
GiB .
Capítulo 7
El sistema operativo MS -DOS
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes :
•
Conocer los orígenes del sistema operativo MS-DOS .
•
S aber cuáles son las características principales de MS-DOS .
•
Conocer la estructura de MS-DOS .
•
Saber cómo se invocan e implementan las llamadas al sistema en MS-DOS .
•
Conocer la interfaz con el usuario disponible en MS-DOS : el intérprete c omrnand . c orn.
•
Conocer los comandos básicos disponibles en c omrnand . c orn.
•
Saber cómo se implementan y controlan los procesos en MS-DOS .
•
Saber cómo se gestiona la memoria en MS-DOS .
•
Conocer la principales características de la gestión de archivos en MS-DOS .
•
Conocer la estructura y la gestión del sistema de archivos PAT.
•
Conocer la gestión de la E/ S en MS-DOS .
273
274
Ampliación de sistemas operativos
7 .l.
Introducción
MS-DOS (MicroSoft Disk Operating System, sistema operativo de disco de Microsoft) fue uno de los
sistemas operativos más utilizados en los computadores personales durante la década de los ochenta. En
la actualidad prácticamente ya no se utiliza, salvo en algunos sistemas empotrados. Pese a ello todavía
merece la pena estudiarlo ya que su diseño e implementación son relativamente simples. Además las
primeras versiones de Windows, que será objeto de estudio en el próximo capítulo, se ejecutaban sobre
este sistema operativo.
Este capítulo está dedicado al estudio del sistema operativo MS-DOS . En primer lugar se realizan
una serie de consideraciones generales acerca de MS-DOS : su cronología histórica, sus características
principales, su estructura, las llamadas al sistema, su secuencia de arranque y la interfaz con el usuario.
En segundo lugar se describe la implementación y control de procesos. En tercer lugar se estudia la
gestión de memoria. En cuarto lugar se estudia la gestión de archivos y el sistema de archivos PAT.
Finalmente se estudia la gestión de la E/ S .
Consideraciones generales sobre MS-DOS
7 .2.
721
.
.
.
Cronología histórica
A principios de los años 70 se desarrolló la tecnología de integración a gran escala (Large S cale Inte­
gration, LSI) que permitía almacenar cientos de miles de componentes electrónicos en un chip cuadrado
de silicio de aproximadamente un centímetro cuadrado. Usando esta tecnología se logró implementar el
primer microprocesador, es decir, un chip que integraba todos los componentes de un procesador. Con
la aparición del microprocesador nacieron los primeros computadores personales (Personal Computers,
PCs) que inicialmente recibieron el nombre de microcomputadores.
Desde el punto de vista de su arquitectura y tamaño los primeros microcomputadores eran pareci­
dos a los minicomputadores. Sin embargo, eran mucho más baratos, lo que hizo accesible su compra a
cualquier persona.
Uno de los primeros sistemas operativos para microcomputadores fue CP/M que se diseñó en 1 974
para ejecutarse con el microprocesador Intel 8080 de 8 bits. Este sistema operativo fue el dominante
durante cerca de cinco años.
A principios de los 80, IBM estaba buscando un sistema operativo para su línea de computadores
personales con procesadores Intel x86 de 1 6 bits. Digital Research le propuso utilizar su nuevo sistema
CP /M-86. Por su parte, Microsoft ofreció a IBM utilizar MS-DOS l. O. Este sistema operativo había
sido desarrollado por Tim Paterson con el nombre de 86-DOS para Seattle Computer Products, pero
Microsoft, que se dio cuenta de las posibilidades del mismo, se lo compró a Seattle Computer.
IBM finalmente se decantó en 1 9 8 1 por utilizar MS-DOS en sus computadores personales, baj o el
nombre de PC-DOS . Conviene señalar que aunque en sus primeras versiones PC-DOS y MS-DOS eran
idénticos, posteriormente comenzaron a existir diferencias entre ellos.
La incorporación de MS-DOS en los computadores personales de IBM hizo que este sistema ope­
rativo fuera utilizado por una multitud de usuarios y desarrolladores de software. Otros fabricantes de
El sistema operativo MS-DOS
275
computadores personales pronto se dieron cuenta que los sistemas operativos que incluían en sus compu­
tadores no podían competir, en cuanto a nivel de aceptación de los usuarios, con MS-DOS . Por ello
decidieron desarrollar sus propios sistemas operativos compatibles con MS-DOS . Así por ejemplo, Di­
gital Research en 1 988 desarrolló DR-DOS 3 . 4 1 que era compatible con MS-DOS 3 .30. Cuando Novell
compró Digital DR-DOS pasó a denominarse Novell DOS . Posteriormente Novell vendió DR-DOS a
Caldera, que durante un corto periodo de tiempo lo distribuyó, incluido su código fuente, con licencia
freeware con el nombre de OpenDOS . Otra variante de MS-DOS de código abierto es FreeDOS que
puede ser ejecutado en SOBUNIX.
Existe toda una familia de sistemas DOS : MS-DOS , PC-DOS, DR-DOS, OpenDO S , FreeDOS , etc.
Todos ellos presentan obviamente una serie de características comunes, pero también tienen sus propias
características particulares que les diferencian.
En relación con MS-DOS , miembro fundador de la familia DOS , a lo largo de la década de los
ochenta y principio de los noventa fueron apareciendo nuevas versiones compatibles con las anteriores
que fueron mej orando el sistema y añadiéndole características adicionales. La versión 6.22 lanzada en
1 994 fue la última que distribuía a MS-DOS separado del sistema operativo Windows. La última versión
de MS-DOS fue la 8.0 y se incluía con Windows Me lanzado en el año 2000.
En la actualidad MS-DOS y los restantes miembros de la familia DOS prácticamente ya no se utili­
zan, salvo en algunos sistemas empotrados. Por otra parte, conviene señalar que las versiones modernas
del sistema operativo Windows disponen del intérprete de comandos cmd . exe 1 que es una mejora del
intérprete de comandos c ommand . c om de MS-DOS .
7.2.2.
Características principales de MS-DOS
Las características principales del sistema operativo MS-DOS son:
•
Es un sistema monousuario, es decir, solo puede atender a un único usuario simultáneamente.
•
Es un sistema monotarea, es decir, solo se puede ejecutar un proceso y hasta que no termina
su ejecución no se puede ejecutar otro. Contrariamente a la creencia general MS-DOS no es un
sistema monoprogramado ya que en la memoria principal pueden estar cargados varios procesos.
•
El núcleo está escrito en lenguaje ensamblador.
•
El núcleo posee una estructura de tipo monolítica o simple.
•
No implementa un planificador de procesos. Los procesos son ejecutados en orden de creación y
hasta que no termina un proceso no se puede ejecutar otro.
•
Administra la memoria principal mediante la técnica de particionamiento dinámico.
•
Considera a los archivos como una secuencia de bits y delegan en las aplicaciones la interpretación
de los mismos.
1 A este intérprete se puede acceder, por ejemplo, a través del accesorio
Símbolo del sistema
de Windows.
276
Ampliación de sistemas operativos
•
Soporta tanto el acceso secuencial como el acceso aleatorio a los archivos .
•
E n los nombres d e archivos n o distingue entre minúsculas y mayúsculas.
•
Cada sistema de archivos presente en memoria secundaria es tratado como una unidad o volumen
lógico independiente, cada una de los cuales posee su propia estructura de directorios. MS-DOS
asigna una letra (C, D, E, . . . ) a cada unidad.
•
Dentro de cada volumen soporta una estructura de directorios de árbol de directorios. El directorio
raíz de un volumen se denota por el carácter ' \ ', que además se usa para separar los componentes
del nombre de ruta de un archivo. Para acceder al sistema de archivos de otra unidad se debe
especificar al comienzo de la ruta la letra de la unidad seguido de dos puntos, por ejemplo: e : \ .
•
En sus primeras versiones únicamente soportaba sistemas de archivos FAT. Aunque en sus últimas
versiones también pasó a soportar sistemas de archivos de discos ópticos (CD-ROM) como el ISO
9660.
•
La interfaz con el usuario es del tipo línea de comandos .
7.2.3.
Estructura del sistema operativo MS-DOS
El sistema operativo MS-DOS se descompone en las siguientes capas lógicas (ver Figura 7 . 1 ) :
•
Módulo B IOS . E s l a capa del sistema operativo encargada de comunicarse con el hardware. Contie­
ne los drivers residentes de los dispositivos de E/S (disco de arranque, pantalla, teclado, puerto de
impresión, reloj , etc) que son suministrados por defecto por el fabricante del computador. A estos
drivers se les denomina drivers residentes porque se encuentran almacenados permanentemente
en una memoria ROM. Durante el proceso de arranque del sistema estos drivers son copiados en
la memoria RAM formando parte del archivo i o . sys .
Q
Usuario
Intérprete de comandos
(COMMAND.COM)
Núcleo de DOS
MS-DOS
Módulo BIOS
Hardware
Figura 7.1 -
Estructura del sistema operativo MS-DOS
El sistema operativo MS-DOS
•
Núcleo de MS-DOS . Es una capa independiente del hardware propiedad de Microsoft Corporation
que se encarga de implementar los servicios o funciones del sistema: control de procesos, gestión
de memoria, gestión de archivos y gestión del reloj (fecha y hora). El código del núcleo de MS­
DOS se encuentra en el archivo msdo s . sys y es cargado en la memoria principal durante el
arranque del sistema.
•
Intérprete de comandos. Implementa una interfaz de línea de comandos que permite al usuario
invocar los servicios del núcleo y ejecutar programas mediante la introducción de órdenes. El
intérprete de comandos incluido en MS-DOS por defecto es c ommand . c om. Aunque un usuario
puede elegir otro intérprete compatible con MS-DOS de su elección, simplemente debe cambiar el
valor de la variable SHELL del archivo de configuración c o n f i g . sys .
724
.
277
.
.
Llamadas al sistema
En MS-DOS las llamadas al sistema son denominadas funciones del sistema y son invocadas direc­
tamente en lenguaj e ensamblador. Un programa para invocar a una función del sistema primero debe
cargar el número que identifica a la función del sistema (ver Tabla 7 . 1 ) y los parámetros de la misma
en diferentes registros. A continuación debe invocar la interrupción software int 2 lh que transfiere el
control al sistema operativo, el cual se encarga de invocar al manipulador de la interrupción.
Función del sistema
3 1H
3 9H
3 AH
3 BH
3 CH
3 DH
3 EH
3 FH
4 0H
4 1H
42H
43H
43H
4 7H
4 BH
4CH
4 DH
Tabla 7 . 1 -
Utilidad
Terminar un programa y permanecer residente en memoria
Crear directorio
Quitar directorio
Establecer directorio actual
Crear archivo
Abrir archivo
Cerrar archivo
Leer archivo
Escribir archivo
Eliminar archivo
Mover puntero d e archivo
Obtener atributos de archivo
Establecer atributos de archivo
Obtener directorio actual
Cargar y ejecutar programa (EXEC)
Terminar un programa
Obtener el código de retomo
Algunas ejemplos de funciones del sistema de MS-DOS
278
Ampliación de sistemas operativos
El manipulador de la interrupción realiza, entre otras, las siguientes acciones: salva el contenido
de los registros hardware en la pila de usuario del programa, cambia a una pila del sistema, usa el
identificador de la función para localizarla en la tabla de funciones del sistema e invoca a la función del
sistema apropiada.
Cuando termina de ejecutarse la función del sistema se devuelve el control al manipulador de la
interrupción que cambia a la pila del usuario, restaura el contenido hardware del programa que se estaba
ejecutando y le transfiere el control para que continúe su ejecución.
e
Ejemplo 7 . 1
En la Figura 7.2 se muestra a modo de ejemplo un fragmento de un programa en ensamblador [Duncan,
1988b] que permite ilustrar la invocación de llamadas al sistema en MS-DOS . En este ejemplo, se invoca
a la función del sistema 3 CH para crear y abrir el archivo prueba . txt dentro del directorio traba j o .
S i l a función del sistema s e ejecuta con éxito devuelve el manipulador (handle) del archivo, que e s el
equivalente al descriptor de archivo en los SOBUNIX.
fname db
' C : \ t raba j o \ prueba . tx t ' , O
fhand l e dw ?
man ipu l ador de l a r c h ivo
número de la func i ón
mov ah , 3 ch
xor
CX , CX
a t r i bu t o no rma l
mov dx , s eg fname
d i r e c c i ón de l nomb r e d e l archivo
mov ds , dx
mov dx , o f f s e t f name
i n t 2 lh
tran s f e r enc i a del c o n t r o l a l núc l e o de MS - DO S
jc
s a l tar en c a s o de e r r o r en l a creac i ón
error
mov fhandl e , ax
Figura 7.2 -
a lmac enar e l man i p u l ador del arch ivo
Ejemplo de invocación de una llamada al sistema en MS-DOS
•
7.2.5.
Arranque de MS-DOS
El programa de arranque de MS-DOS contenido en el primer sector de la partición del disco de
arranque de un sistema FAT en primer lugar comprueba si en dicha partición se encuentran los archivos
i o . sys y msdo s . sys . En caso negativo, muestra un mensaj e en pantalla para que el usuario cambie
el disco de arranque. En caso afirmativo, copia en la memoria principal los dos archivos 2 y transfiere el
2Dependiendo de la implementación el programa de arranque puede que solo copie en memoria el archivo i o . sys y éste
cuando comienza a ejecutarse se encarga de copiar en memoria a msdos . sys .
El sistema operativo MS-DOS
279
control a i o . sys .
El archivo i o . sys que se carga en la memoria principal queda formado por dos módulos. El primer
módulo es una copia de la BIOS . El segundo módulo es sys i n i t que es enlazado junto i o . sys y que es
invocado por el código de inicialización de la BIOS . sys i n i t es un programa propiedad de Microsoft
que se encarga de determinar la cantidad de memoria principal contigua disponible, transferirse a si
mismo a la parte alta de la memoria, e invocar a la rutina de inicialización del núcleo de MS-DOS
msdos . sys .
El núcleo de MS-DOS al inicializarse configura sus estructuras de datos y los manipuladores de las
interrupciones. A continuación invoca a cada uno de los drivers residentes existentes en la BIOS para
que determinen el estado del computador e inicialicen a los dispositivos de E/S . Finalmente devuelve
el control a sys ini t que invoca a diferentes funciones del sistema para abrir el archivo c o n f i g . sys .
Este archivo de texto, que puede ser configurado por el usuario, contiene diferentes parámetros y órdenes
de configuración del sistema, como por ejemplo la instalación de drivers instalables (ver sección 7.7.2).
Si sys ini t detecta la existencia del archivo c o n f i g . sys lo carga en memoria para procesarlo
línea a línea. Además asigna memoria para la caché de buffers de bloques de disco y para los bloques
de control de archivos. Asimismo carga en memoria los drivers instalables. Finalmente invoca a una
función del sistema para cargar en memoria y comenzar a ejecutar el intérprete de comandos, por defecto
c ommand . c om. Una vez finalizada su tarea el módulo sys i n i t se elimina de la memoria.
726
.
.
.
Interfaz con el usuario
La interfaz con el usuario que soporta MS-DOS es una interfaz de línea de comandos implementada
a través de un intérprete de comandos muy similar a los usados en los SOBUNIX. Por defecto dicho
intérprete es el programa c ommand . c om, aunque se puede utilizar cualquier otro intérprete compatible
con MS-DOS , como por ejemplo el intérprete 4DOS de JP Software. B asta con cambiar el nombre del
intérprete en la variable SHELL del archivo con f i g . sys .
Estructura de los comandos
Una orden o comando de un intérprete de MS-DOS es una cadena de caracteres que, de forma
general, tiene la siguiente estructura:
nombre_c omando arg_l arg_2 . . . arg_N / op_l / op_2 . . . / op_M
nombre_ c omando es el nombre del programa ejecutable que se desea ejecutar, arg_i i = 1 , 2, . . . , N
son los argumentos que acepta el programa y 1 op_j j = 1 , 2, . . . , M son opciones, también denomina­
dos modificadores, que permiten configurar el comportamiento del programa. Conviene señalar que los
intérpretes de MS-DOS al interpretar una orden no diferencian entre mayúsculas y minúsculas.
Si se desea obtener información sobre el significado, los argumentos y las opciones de un determi­
nado comando, se puede usar la orden:
help nombre_c omando
280
Ampliación de sistemas operativos
Comando
cd o chdi r
c opy
de l o eras e
dir
f ind
f o rma t
md o mkdir
ren o rename
type
Tabla 7.2 -
Utilidad
Cambiar el directorio de trabajo
Copiar uno o más archivos en otra ubicación
B orrar uno o más archivos
Mostrar el contenido (archivos y subdirectorios) de un directorio
B uscar una cadena de texto en uno o más archivos
Formatear partición de disco
Crear un directorio
Cambiar el nombre de uno o más archivo
Mostrar el contenido de uno o más archivos de texto
Algunos comandos básicos disponibles en el intérprete de comandos
c ommand . c om
El listado de comandos soportados por c ommand . c om es extenso. En la Tabla 7.2 se recopilan, a modo
de ejemplo, solamente algunos comandos básicos.
El intérprete c ommand . c om al igual que los intérpretes de comandos de los SOBUNIX soporta el
uso de comodines, el redireccionamiento de la E/S y el uso de tuberías.
e
Ejemplo 7 . 2
Supóngase que el directorio de trabajo actual de un usuario en MS-DOS es e : \ t rabaj o y que en dicho
directorio se encuentra alojado únicamente el archivo dat o s . txt. Si se escribe la orden
dir
en la pantalla se mostraría información sobre el contenido del directorio de trabajo:
E l vo l umen de l a un i dad e no t i ene e t i queta .
E l número de s e r i e de l vo lumen e s : 9 0 e e - E l BD
D i r e c t o r i o de e : \ trabaj o
2 0 / 04/2 012
2 0 / 04/2 012
2 0 / 04/2 012
< D I R>
11 : 47
< D I R>
11 : 47
11 : 37
4 0 0 da t o s . txt
4 0 0 byt e s
1 archivo s
2 dirs 5 7 6 . 7 1 6 . 8 0 0 bytes l i bre s
Para crear u n subdirectorio d e nombre borrador dentro del directorio d e trabajo actual s e puede usar,
por ejemplo, la orden
md borrador
Nótese que se ha utilizado el nombre de ruta relativa del subdirectorio, aunque por supuesto también se
podría haber utilizado el nombre de ruta absoluta. En dicho caso la orden hubiera sido la siguiente:
El sistema operativo MS-DOS
281
md c : \ trabaj o \ bo rrador
También se podría haber omitido la letra que designa la unidad:
md \ t rabaj o \ borrador
Se puede comprobar que dicho directorio ha sido creado usando la orden dir.
Si se desea que el directorio creado pase a ser el directorio de trabajo se puede usar la orden
cd borrador
Para copiar el archivo da t o s . txt dentro de este directorio se debe usar el comando c opy, cuya sintaxis
se puede conocer usando la orden
he lp c opy
De acuerdo con la información mostrada se deben proporcionar como argumentos de entrada del coman­
do c opy las nombres de ruta absolutas o relativas del elemento que se desea copiar y del directorio donde
se desea realizar la copia. Para este ejemplo, la orden a utilizar sería:
c opy \ t rabaj o \ dat o s . txt \ t rabaj o \ borrador
En este caso se han utilizado nombres de rutas absolutas. Obviamente para este ejemplo esta orden puede
escribirse mucho más abreviadamente teniendo en cuenta que el directorio origen es el directorio padre
del directorio destino y que el directorio destino es el directorio de trabajo actual, es decir, usando las
entradas
y ' . ':
11 •
• 11
c opy . . \ da t o s . txt .
•
Tipos de comandos
El intérprete c ommand . c om soporta tres tipos de comandos :
•
Comandos internos. S o n aquellos cuyo código d e ejecución s e incluye dentro del código del intér­
prete. Ejemplos de comandos internos son: c opy, d i r y de l .
•
Comandos externos. También denominados programas transitorios. Son aquellos cuyo código de
ejecución se encuentra en un archivo ejecutable en disco que debe ser buscado por el intérprete
y cargado en la memoria principal en una región denominada área de programas transitorios.
Ejemplos de comandos externos son: chkds k y backup .
•
Archivo de procesamiento por lotes (archivos batch) . Son archivos de texto con extensión . ba t
que contienen un listado de comandos (internos o/y externos) u otros archivos batch. También pue­
den contener sentencias propias de los lenguaj es de programación como i f o g o t o . El intérprete
va leyendo y ejecutando secuencialmente cada línea del archivo. Señalar la gran analogía existente
entre los archivos batch y los shell scripts de los intérpretes de los SOBUNIX.
282
Ampliación de sistemas operativos
Funcionamiento
El intérprete de comandos c orrunand . c om es cargado en la memoria principal durante el arranque del
sistema. El código del intérprete c orrunand . c om se estructura en dos partes:
•
Parte residente. Se carga en las direcciones bajas de memoria principal a continuación del núcleo
de MS-DOS y sus estructuras de datos y buffers. Contiene las rutinas que se encargan, entre otras,
de las siguientes tareas : atender diferentes combinaciones de teclas 3 , atender los errores críticos,
gestionar la terminación de los programas que se invocan desde el intérprete, y cargar la parte tran­
sitoria del intérprete. También en esta parte se almacena el código de los comandos internos. Esta
parte se denomina parte residente porque siempre permanece cargada en la memoria principal.
•
Parte transitoria. Se carga en las direcciones altas de la memoria principal. Contiene las rutinas
que se encargan de mostrar el apuntador en pantalla, leer las ordenes desde el teclado o desde un
archivo batch, y ejecutarlas. Esta parte se denomina parte transitoria porque puede ser eliminada
de la memoria si el programa que se va ejecutar desde el intérprete necesita usar más memoria de
la inicialmente asignada. Cuando un programa termina la parte residente del intérprete comprueba
si la parte transitoria está cargada en memoria, en caso negativo procede a cargarla.
Cuando c orrunand . com comienza a ejecutarse en primer lugar comprueba si existe en el directorio
de arranque el archivo aut o exec . bat . Este archivo contiene un conjunto de órdenes configurables por
el usuario para establecer las variables de entorno del intérprete de comandos y lanzar otros programas,
como por ejemplo, un antivirus.
Si el archivo aut o exec . bat existe entonces c orrunand . c om comienza a ejecutarlo. Una vez fina­
lizada su ejecución c orrunand . c om muestra en pantalla el apuntador y se queda a la espera de que el
usuario escriba una orden. El apuntador, por defecto es el nombre de ruta absoluta del directorio de tra­
baj o actual seguido del carácter ' > ' . Así por ejemplo si el directorio de trabajo es el directorio raíz ' \ ' de
la unidad " e : " entonces el apuntador sería "e : \ > " .
Cuando u n usuario escribe una orden, c orrunand . c om comprueba en primer lugar s i s e trata de una
orden interna. En caso afirmativo procede a ejecutarla puesto que su código ya se encuentra cargado
en memoria dentro del código del propio intérprete. En caso negativo, comprueba si se trata de una
orden externa o de un archivo batch. Para ello busca la existencia de un archivo homónimo a la orden
con extensión . c om, . exe o . ba t . Primero busca el archivo en el directorio de trabajo actual y si no
lo encuentra lo busca en los directorios especificados en la variable de entorno PATH. Si tampoco lo
encuentra en estas ubicaciones entonces muestra en la pantalla un mensaje de error. Si lo encuentra
invoca a la función del sistema 4BH (función EXEC) para que cargue el archivo en memoria y comenzar
su ejecución. Cuando el programa termine de ejecutarse el control regresa al intérprete de comandos que
vuelve a mostrar el apuntador en la pantalla.
3 Como por ejemplo [ c ontro l ] + [ e ] y [ c o n t ro l ] + [ break ] .
El sistema operativo MS-DOS
73
.
.
283
Implementación y control de procesos en MS-DOS
MS-DOS es un sistema operativo monotarea, hasta que no termina de ejecutarse un proceso no
puede comenzar a ejecutarse otro. El proceso que se ejecuta tiene un control total de los recursos de la
máquina. Su ejecución solo puede ser interrumpida por el sistema operativo para realizar el tratamiento
de las interrupciones. Esta característica simplifica enormemente el control de los procesos y elimina la
necesidad de implementar un planificador de procesos.
En MS-DOS el control de procesos es muy simple, el proceso que se está ejecutando (proceso padre)
puede crear otro proceso (proceso hijo) invocando a la función del sistema 4BH también conocida como
función EXEC. Esta función carga en memoria al proceso hijo y le transfiere el control. Mientras el pro­
ceso hijo se ejecuta el proceso padre permanece bloqueado en la memoria principal. Cuando el proceso
hijo va a terminar su ejecución invoca a una función del sistema para transferir el control de nuevo a su
proceso padre.
Cuando se crea un proceso, el sistema operativo crea las siguientes estructuras de datos asociadas al
proceso:
•
Bloque de entorno. Contiene las variables de entorno del proceso. El bloque de entorno de un pro­
ceso es inicialmente una copia del bloque de entorno de su proceso padre. Las variables de entorno
se pueden cambiar usando el comando s e t , bien directamente a través del teclado o mediante un
archivo batch.
•
Prefijo del segmento del programa (Program Segment Prefix, PSP). Contiene la información que
necesita conocer el sistema operativo para controlar la ejecución del proceso, como por ejemplo:
puntero al bloque de entorno, puntero al PSP del proceso padre, punteros a diferentes funciones
del sistema, y la tabla de manipuladores de archivos abiertos que son heredados del proceso padre.
En el PSP también se almacenan los argumentos del programa.
7.3.1.
Creación y ejecución de un proceso
La función del sistema 4 BH o función EXEC es el mecanismo existente en MS-DOS para crear y co­
menzar a ejecutar un proceso. EXEC en primer lugar intenta localizar el archivo ejecutable y comprueba
el tipo de programa que se desea ejecutar inspeccionando la cabecera del archivo ejecutable. MS-DOS
soporta dos formatos de archivos ejecutables :
•
Programas c om. Se caracterizan porque su tamaño está limitado a 64 KiB . Las regiones (código,
datos y pila) de un programa c om comparten un mismo segmento de memoria principal .
.
.
•
Programas exe. Su tamaño está limitado a la memoria principal disponible. Las regiones de un
programa exe pueden ocupar múltiples segmentos de memoria principal.
.
.
En segundo lugar EXEC asigna al nuevo proceso un bloque de entorno. A continuación asigna al
proceso un bloque de memoria en el área de programas transitorios de memoria principal (ver sección
7 .4). En este bloque carga la región de código y de datos del proceso, y crea su pila. Además crea e
284
Ampliación de sistemas operativos
inicializa el PSP del proceso. Finalmente EXEC transfiere el control al nuevo proceso para que comience
a ejecutarse.
Durante el tratamiento de la interrupción software int 2 1 H asociada a la invocación de la función
del sistema EXEC, el contexto a nivel de registros del proceso padre es almacenado en su pila. Además
la dirección de la pila es almacenada en su PSP. Cuando el proceso hijo termina, se busca la dirección del
PSP del proceso padre en el PSP del proceso hijo. Una vez encontrada se accede al PSP del padre para
localizar la dirección de su pila, restaurar su contexto hardware y continuar con la ejecución del proceso
padre.
La función del sistema EXEC dispone de un parámetro que permite especificar su comportamiento:
cargar y ejecutar, solo cargar o solo ejecutar.
732
.
.
.
Terminación de un proceso
En MS-DOS existen dos funciones del sistema que producen la terminación de un proceso: la función
4CH y la función 3 1H. La función 4CH libera la memoria principal asignada al proceso que invoca a la
función, cierra los archivos abiertos, escribe en el disco los buffers de la caché que han sido modificados
por el proceso, almacena el código de finalización o retomo en un registro, y transfiere el control al
proceso padre.
El código de finalización o retorno de un proceso de MS-DOS es similar al estatus de salida de los
procesos en los SOBUNIX. El proceso padre puede recuperar el código de finalización de su proceso
hijo invocando a la función del sistema 4 DH.
Por su parte, la función del sistema 3 1 H se limita a transferir el control al proceso padre. A un proceso
que termina mediante la invocación de esta función se le denomina proceso TSR (Termínate and Stay
Resident, terminar y permanecer residente) ya que todos sus recursos, salvo quizás el bloque asignado
en el área de programas transitorios, siguen estando asignados al proceso aunque éste haya terminado.
De forma general los procesos TSR se utilizan en MS-DOS para ejecutar drivers o manej adores de
interrupciones escritos por el usuario. Los procesos TSR se activan mediante interrupciones hardware
o software. Cuando terminan de realizar su tarea invocan a la función 3 1 H para terminar y permanecer
residentes a la espera de volver a ser invocados por otra interrupción.
7.4.
Gestión de memoria en MS-DOS
Cuando se desarrolló el sistema operativo MS-DOS los computadores personales disponían general­
mente de 64 KiB de memoria principal. Por otra parte, los procesadores 8088 y 8086 de Intel usados en
los primeros PCs de IBM en los que se iba a ejecutar MS-DOS podían direccionar hasta 1 MiB , lo cual
era un gran avance para la época. Este es el motivo por el que las primeras versiones de MS-DOS traba­
j aban considerando la existencia de 1 MiB de memoria, de los cuales solo 640 MiB podían ser utilizados
por el sistema operativo y las programas.
Posteriormente la aparición de computadores personales con mayor capacidad de memoria y de apli­
caciones software que requerían de más memoria, hizo que MS-DOS incluyera diferentes mecanismos
El sistema operativo MS-DOS
285
para poder superar el límite de los 640 MiB , entre ellos: el uso de la memoria alta (high memory), el
soporte de las especificaciones de memoria expandida (Expanded Memory Specifications, EMS) y el
soporte de las especificaciones de memoria extendida (Extended Memory Specifications, XMS) . Los
lectores interesados en conocer las características de estos mecanismos pueden consultar la referencias
que se indican en la sección 7 . 9 .
Una vez arrancado e l sistema operativo MS-DOS la memoria principal queda distribuida general­
mente de la forma que se muestra en la Figura 7 . 3 . En la parte más baj a de la memoria se almacena la
tabla de vectores de interrupción. A continuación se almacenan la tabla de las funciones de la BIOS y
la tabla de las funciones del sistema MS-DOS . En la siguiente zona de memoria se almacena el núcleo
de MS-DOS . Luego existe un área reservada para la memoria caché de buffers de disco. Por encima de
la caché se alojan los drivers instalables y la parte residente del intérprete c ommand . c oro. Justo a con­
tinuación comienza el área de programas transitorios reservada para la carga de programas invocados
1 MiB
BIOS
Libre
Tarj eta de video
640 KiB
Command.com
(transitorio)
Á rea de programas
transitorios
Command. com
(residente)
Drivers instalables
Caché de buffers
Núcleo de DOS
Tablas de funciones
DOS y BIOS
o
Figura 7.3 -
Tabla de vectores
de interrupción
Distribución de la memoria principal que realiza MS-DOS
286
Ampliación de sistemas operativos
por el usuario. A continuación se aloj a la parte transitoria del intérprete c ommand . c om hasta alcanzar
el límite de 640 KiB . Esta zona puede ser utilizada por el programa en ejecución si requiere de más
memoria. El área de memoria comprendida entre 640 KiB y 1 MiB es utilizada por la tarj eta de vídeo y
para almacenar una copia de la B IOS .
Cuando MS-DOS tiene que asignar memoria principal a un programa utiliza el espacio del área de
programas transitorios. Este área de memoria es gestionada por el sistema operativo mediante la técnica
de particionamiento dinámico. La memoria se asigna en bloques o particiones4 . El tamaño mínimo que
puede tener un bloque es 1 6 bytes, unidad denominada párrafo en MS-DOS . El tamaño máximo de una
partición queda limitado por el tamaño del área de programas transitorios.
Para implementar la técnica del particionamiento dinámico el núcleo enlaza todos los bloques de
memoria existentes formando una lista (ver Figura 7 .4). Para ello reserva los primeros cinco bytes de un
bloque, a modo de cabecera del bloque, para almacenar la siguiente información: puntero al siguiente
bloque de la lista, tamaño del bloque en párrafos, estado del bloque (libre u ocupado) y puntero al PSP
del programa al que está asignado el bloque (si éste no está libre).
Cabecera
Cabecera
Bloque 2
1
1
l1
Cabecera
Ocupado
Libre
Cabecera
B loque 3
Bloque 4
Ocupado
Libre
11
Figura 7.4 -
Lista enlazada de bloques de memoria principal mantenida en MS-DOS
MS-DOS se encarga de realizar la gestión de la memoria únicamente cuando se le solicita a través
de alguna de las siguientes funciones del sistema:
•
Función 4 8 H. Asigna un bloque de memoria. Cuando MS-DOS tiene que asignar un bloque de
memoria de tamaño S busca en la lista de bloques un bloque de tamaño igual o mayor a S . Por
defecto utiliza el algoritmo del primer ajuste (first fit) para realizar la búsqueda. Este algoritmo
comienza a buscar desde el principio de la lista y asigna el primer bloque que encuentra con un
tamaño igual o mayor a S . Este algoritmo es sencillo de implementar además mínimiza el tiempo
de búsqueda. MS-DOS también soporta el algoritmo del mejor ajuste (best fist), que busca en toda
la lista un bloque cuyo tamaño sea igual o exceda lo menos posible del tamaño S requerido, y el
algoritmo del último ajuste (last fist), busca en la lista el bloque ubicado en la direcciones más
altas de tamaño igual o mayor al tamaño S requerido. El algoritmo a utilizar se especifica como un
parámetro de la función.
4En MS-DOS un bloque o partición también recibe el nombre de arena.
287
El sistema operativo MS-DOS
•
Función 4 9 H. Libera un bloque de memoria. Cuando MS-DOS tiene que liberar un bloque intenta
fusionarlo con otros bloques libres contiguos para formar un bloque libre de mayor tamaño.
•
Función 4AH. Redimensionar un bloque de memoria. Por defecto, MS-DOS a un programa c om
le asigna el bloque de memoria libre de mayor tamaño que encuentre, aunque no lo necesite.
En el caso de un programa exe busca en la cabecera del archivo ejecutable el espacio mínimo
y máximo de memoria que el programa necesita. MS-DOS en primer lugar intenta asignarle un
bloque de tamaño igual o mayor a la máxima memoria que va a utilizar el programa. Si no existe
ninguno disponible le intenta asignar un bloque de tamaño igual o mayor a la mínima memoria.
Si tampoco existe ninguno disponible el programa no puede ejecutarse. Señalar que cuando un
programa está bien diseñado debe devolver al sistema la memoria principal que no vaya a utilizar,
para ello debe invocar a esta función del sistema.
.
.
Estas funciones pueden ser invocadas tanto por un programa de usuario como por otras funciones del
sistema. Por ejemplo la rutina que implementa la función EXEC invoca a la función 4 8 H para asignar un
bloque de memoria al proceso que se va a cargar en memoria.
7.5.
Gestión de archivos en MS-DOS
7.5.1.
Archivos
En MS-DOS la información contenida en un archivo se estructura como una secuencia lineal de
bytes. MS-DOS no interpreta dicha información, simplemente se limita a operar (leer o escribir) con ella
a nivel de byte. Es el proceso en ejecución el encargado de interpretar la información contenida en el
archivo sobre el que ha solicitado operar al sistema operativo. En MS-DOS el acceso al contenido de
un archivo se puede realizar de forma secuencial o de forma directa. MS-DOS distingue dos tipos de
archivos : archivos regulares (archivos binarios y archivos ASCII) y directorios.
El nombre de un archivo es una cadena de caracteres ASCII. La longitud máxima del nombre de
un archivo es de ocho caracteres más una extensión de tres caracteres. Por ejemplo, prueba . txt sería
un nombre de archivo válido en MS-DOS . Señalar que estos límites están impuestos por el sistema de
archivos FAT (ver sección 7.6), que es el sistema de archivos principal utilizado por MS-DOS .
La implementación de la gestión de archivos utilizada en la primera versión de MS-DOS estaba ins­
pirada en la del sistema operativo CP /M, que se basaba en el uso de una estructura de datos denominada
bloque de control del archivo (File Control Block, FCB). Un FCB es una estructura que se crea en el
espacio de direcciones del proceso y que se asocia a un archivo abierto. Cuando un proceso desea abrir o
crear una archivo, primero debe inicializar un FCB con la unidad, el nombre y la extensión del archivo.
A continuación debe invocar a una función del sistema para abrir o crear el archivo, pasándole como ar­
gumento la dirección del FCB . Si el archivo es abierto o creado con éxito, entonces MS-DOS almacena
en el FCB una copia de la información existente en la entrada del directorio asociada al archivo. En el
FCB también se almacena el puntero de lectura/ escritura. Cada vez que un proceso desea leer o escribir
un archivo debe invocar a la función del sistema apropiada pasándole como argumento la dirección del
FCB .
288
Ampliación de sistemas operativos
A partir de su versión 2.0 MS-DOS implementó un modelo de gestión de archivos similar al utilizado
en los SOBUNIX: cuando un proceso desea abrir o crear un archivo debe invocar a la función del sistema
3 DH pasándole como argumento el nombre de ruta del archivo. Si el archivo se abre o se crea con éxito
MS-DOS devuelve al proceso un manejador de archivo (file handle) de 16 bits, similar al descriptor de
archivo de los SOBUNIX. El proceso cuando invoca a una función del sistema para leer o escribir un
archivo debe pasarle como argumento su manej ador de archivo.
MS-DOS dentro del PSP de un proceso (ver Figura 7.5) mantiene una tabla de manejadores de
archivos (job handle table) 5 , similar a la tabla de descriptores de archivos de los SOBUNIX. Cada entrada
de tabla contiene la dirección de la tabla de archivo del sistema (System File Table, SFT), similar al
objeto de archivo abierto de los S OBUNIX. Una SFT es una estructura de datos que se crea en el espacio
del núcleo y que contiene toda la información que necesita conocer el sistema operativo para trabajar con
un archivo abierto, como por ejemplo: la unidad lógica donde se ubica, la dirección de su primer clusters
de datos. el tamaño del archivo, sus atributos, el modo de acceso, el puntero de lectura/escritura, etc.
MS-DOS enlaza todas las SFTs existentes en una estructura denominada tabla de archivos.
El modelo de gestión de archivos implementado en MS-DOS 2.0 para mantener la compatibilidad
con la versión anterior también soportaba el uso de FCBs. Para unificar el tratamiento de los archivos,
MS-DOS también asigna una SFT a un archivo abierto con un FCB .
Tabla de archivos
PSP de un proceso A
�
Manejador
de archivo
'l"'"�
''
'''
!
:
''
:
'''
:'
''
'
1------------------J
!
Tabla de manej adores
de archivos de un proceso A
SFT
0
+
SFT
�
SFT
•
Figura 7.5 -
Estructura de datos utilizadas en MS-DOS para gestionar los archivos
5 La traducción real al español de este término inglés sería tabla
para evitar confusiones.
tabla de manejadores de archivos
de manejadores de tareas
pero he preferido traducirla por
El sistema operativo MS-DOS
7.5.2.
289
Directorios
En su primera versión MS-DOS implementaba una estructura de directorios de un único nivel, es
decir, todos los archivos estaban contenidos en un único directorio. A partir de su versión 2.0 comenzó a
implementar una estructura de árbol de directorios, la cual posibilita la existencia de múltiples directorios
y subdirectorios. El directorio raíz se denota por el carácter \ que además se usa para separar los
componentes del nombre de ruta de un archivo.
Los bloques de datos de un directorio contienen una lista con los archivos y subdirectorios alojados
en el directorio. En dicha lista existen también dos entradas especiales : la entrada
que hace referencia
que hace referencia al directorio padre.
al propio directorio y la entrada
En cada entrada de la lista contenida en un directorio se almacena la siguiente información: el nombre
y la extensión del archivo, los atributos del archivo, el tamaño del archivo en bytes, la fecha y hora de la
última modificación, y la dirección del primer bloque de datos. El formato de una entrada de la lista de
un directorio viene impuesto por el sistema de archivos FAT.
Los atributos del archivo son una máscara de 8 bits que permiten especificar el tratamiento que
debe dar MS-DOS al archivo al que está asociada la entrada. Cada atributo tiene asignado un bit que
puede ser activado o desactivado mediante el uso del comando a t tr ib. Entre los atributos soportados
se encuentran los siguientes :
1
1,
1
11
•
•
•
1
11
•
Solo lectura. Si está activado (0000 000 1 ) significa que el archivo o subdirectorio al que está
asociada la entrada no puede ser modificado.
•
Oculto. Si está activado (0000 00 1 0) significa que la entrada no debe mostrarse en los listados del
directorio.
•
Sistema. Si está activado (0000 0 1 00) significa que la entrada está asociada a un archivo del siste­
ma, como por ejemplo i o . sys .
•
Etiqueta del volumen. Si está activado (0000 1 000) significa que la entrada no está asociada a
ningún archivo sino que contiene el nombre o etiqueta del volumen o unidad lógica.
•
Subdirectorio. Si está activado (000 1 0000) significa que la entrada está asociada a un subdirecto­
rio.
•
Archivo. Si está activado (00 1 0 0000) significa que la entrada está asociada a un archivo ordinario.
7 .5.3.
Sistemas de archivos
Cada sistema de archivos presente en memoria secundaria es tratado por MS-DOS como una unidad
o volumen lógico independiente, cada una de los cuales posee su propia estructura de directorios. MS­
DOS asigna una letra (C, D, E, . . . ) a cada unidad. El nombre de ruta de un archivo comienza por tanto
con el nombre del volumen lógico en el que está almacenado.
En sus primeras versiones MS-DOS soportaba únicamente sistemas de archivos FAT. Aunque poste­
riormente implementó la interfaz de sistemas de archivos instalables (lnstallable File System, IFS) que
290
Ampliación de sistemas operativos
le permitía soportar algunos otros sistemas de archivos, como por ejemplo, el sistema de archivos ISO
9660 de los CD-ROM.
La interfaz IFS traduce las operaciones independientes del sistema de archivos que invoca un proceso
a las funciones dependientes del sistema de archivos que las implementan. Las funciones dependientes
del sistema de archivos se implementan en un archivo ejecutable que debe ser cargado cuando se arranca
el computador. Por ejemplo, ms c dex . exe en el caso de los sistema de archivos ISO 9660 de los CD­
ROM.
7.6.
El sistema de archivos FAT
El sistema de archivos FAT, también conocido como sistema FAT- 12, fue creado por Bill Gates y
Marc McDonald en 1 977. El sistema FAT- 1 2 utiliza como unidad de asignación de espacio al cluster, el
cual está formado por varios sectores de disco contiguos. El tamaño de un cluster se fija en el momento
de la creación del sistema de archivos. Asimismo se utilizan 12 bits para direccionar un cluster, de ahí el
nombre de FAT- 12. En un sistema FAT- 1 2 el tamaño máximo de un volumen está limitado a 32 MiB .
Posteriormente a finales de los ochenta se desarrolló el sistema FAT- 1 6, el cual utilizaba 1 6 bits para
direccionar un cluster. Además soportaba un tamaño máximo de volumen de 2 GiB . El sistema FAT- 1 6
fue introducido como sistema d e archivos principal en l a versión 4 . 0 d e MS-DOS aparecida e n 1988.
La última versión aparecida de un sistema FAT, es el sistema FAT-32, el cual utiliza 32 bits para
direccionar a un cluster (realmente solo se utilizan 28 bits). Además soporta un tamaño máximo de
volumen de 4 GiB . El sistema FAT-32 fue introducido como sistema de archivos principal en la versión
OSR2 de Windows 95 aparecida en 1 996.
En las siguientes secciones se describe la estructura y gestión del sistema de archivos FAT- 12, que
fue el sistema de archivos principal de las primeras versiones de MS-DOS .
7.6.1.
Estructura de un sistema FAT
Un sistema de archivos FAT presenta la siguiente estructura en la partición de disco donde se crea
(ver Figura 7.6):
•
A rea de arranque. Se sitúa al principio de la partición. Contiene información sobre la partición de
disco sobre la que se ha creado el sistema de archivos, como por ejemplo: los bytes que ocupa un
sector, los sectores que hay en una pista, el número de sectores y los sectores que tiene un cluster.
El área de arranque también contiene información sobre la estructura del sistema de archivos:
número de tablas de asignación de archivos existentes (original y copias), los sectores que ocupa
una tabla de asignación de archivos y el número máximo de entradas del directorio raíz.
Además si se trata de la partición activa el área de arranque contiene el código necesario para
iniciar el arranque del sistema operativo.
•
Tabla de asignación de archivos. Cada entrada de esta tabla tiene un tamaño de 12 bits y contiene
información sobre el estado de un cluster del disco:
El sistema operativo MS-DOS
- ooo.
291
Indica que el cluster está libre.
- FF O - FF 6 . Indica que el cluster está reservado. Este es el caso de los clusters que se utilizan
para almacenar la lista de archivos y subdirectorios del directorio raíz.
- FF 7 . Indica que el cluster está defectuoso.
- F F 8 - FF F . Indican que se trata del último cluster de un archivo.
- Resto de valores. Indican que el cluster está asignado. En este caso el valor almacenado en
la entrada es la dirección física del siguiente cluster de datos del archivo. Recuérdese que
la entrada del directorio asociada a un archivo contiene la dirección del primer cluster del
archivo.
Señalar que las dos primeras entradas de la tabla están reservadas para codificar el tipo de disposi­
tivo donde se ha creado el sistema de archivos : disco duro o disquete.
•
Copias de la tabla de asignación de archivos. Puesto que la tabla de asignación de archivos es una
estructura crítica para el funcionamiento del sistema por motivos de seguridad se mantienen varias
copias de la misma en la partición del disco.
•
Directorio raíz. Contiene una lista de los subdirectorios y archivos existentes en dicho directorio.
Su tamaño máximo es fijo y queda establecido en el momento de la creación del sistema de archivos
en función del tamaño del disco.
•
Área de datos. Contiene los clusters de datos libres y los clusters de datos asignados a archivos y a
directorios.
Partición de disco
Á rea de datos
Figura 7.6 - Estructura
7.6.2.
de un sistema de archivos FAT
Implementación de directorios en un sistema FAT
En un sistema de archivos FAT la lista de archivos y subdirectorios de un directorio se implementa
con entradas de tamaño fijo igual a 32 bytes. En cada entrada se almacena la siguiente información (ver
Figura 7.7): nombre, extensión, atributos, hora y fecha de la última modificación, dirección del primer
cluster y tamaño.
En la lista contenida en un directorio, excepto si se trata del directorio raíz, existen dos entradas
especiales: la entrada que contiene la dirección del cluster del directorio y la entrada " . . " que contiene
la dirección del primer cluster del directorio padre. Si el directorio padre es el directorio raíz entonces
contiene la dirección O.
1 • 1
292
Ampliación de sistemas operativos
32 bytes
Nombre
Atributos
3 bytes
8 bytes
1 byte
Figura 7.7 - Estructura
7.6.3.
Tamaño
1 O bytes
2 bytes
2 bytes
2 bytes
4 bytes
de una entrada de un directorio en un sistema de archivos FAT
Localización de los clusters de datos de un archivo en un sistema FAT
En un sistema FAT la entrada asociada a un archivo en un directorio contiene, entre otros datos, la
dirección del primer cluster de datos del archivo. Para obtener la dirección del segundo cluster de datos
del archivo hay que acceder a la entrada de la tabla de asignación de archivos asociada al primer cluster,
la cual contiene la dirección del segundo cluster. Los restantes clusters del archivo se localizan de forma
semej ante ya que la entrada de la tabla de asignación de archivos asociada a un determinado cluster i de
datos de un archivo contiene la dirección de siguiente cluster i + l . En el caso de que el cluster i sea el
último del archivo entonces su entrada de la tabla de asignación de archivos contiene el valor - 1 (FFF en
hexadecimal).
e
Ejemplo 7 . 3
En la parte izquierda de la Figura 7 . 8 se ha representado la tabla de asignación de archivos de un cierto
sistema PAT. Recuérdese que la tabla tiene una entrada por cada cluster existente en la partición de disco.
Supóngase la dirección física del primer cluster (i = O) de un cierto archivo es Bp = 1 0 1 , esta información
se encuentra en la entrada del directorio que contiene al archivo. La entrada 1 0 1 de la tabla de asignación
de archivos contiene la dirección física Bp = 9 1 del segundo cluster (i = 1) del archivo. La entrada 9 1
de l a tabla de asignación de archivos contiene l a dirección física B p = 97 del tercer cluster ( i = 2 ) del
archivo. La entrada 97 de la tabla de asignación de archivos contiene la dirección física Bp = 93 del
cuarto cluster (i = 3) del archivo. Finalmente la entrada 93 de la tabla de asignación de archivos contiene
el valor - 1 que indica que este cluster es el último del archivo.
•
7.7.
Gestión de la E/S en MS-DOS
7.7. 1.
Subsistema de E/S
El subsistema de E/S de MS-DOS es muy simple debido a que se trata de un sistema operativo
monotarea. Cuando el proceso que se está ejecutando realiza una petición de E/ S ésta es inmediatamente
procesada. Hasta que no se atiende una petición el proceso no puede realizar otra.
MS-DOS no implementa ningún tipo de planificación de la E/ S ya que por su diseño no tenía nece­
sidad de ello. Si bien a partir de su versión 3 .0 empezó a implementar spooling en el uso de la impresora,
El sistema operativo MS-DOS
Tabla de asignación
de archivos
o
Clusters
o
1 1 1 1 1 1 1 1 1 1 1 1 1 1
B F- 90
1
1
1
1
2
3
) =
91
92
93
94
95
96
97
98
99 1 00 1 0 1 1 02
90
91
97
92
93
-1
94
95
96
97
93
98
99
1 00
101
91
1
1 02
1
1
1
1
Nombre archivo
1
_L
Dirección 1 cr cluster
1
Entrada asociada
al archivo en el
directorio al que
pertenece
..
1 2 bits
Figura 7.8 -
Localización del cluster de un archivo en un sistema FAT
293
294
Ampliación de sistemas operativos
el cual permitía mantener una cola de archivos a ser imprimidos.
MS-DOS también implementa la técnica de bu.ffering con el objetivo de mejorar el rendimiento de la
E/S, para ello mantiene en la memoria principal una caché de bu.ffers de bloques de disco. La caché suele
tener un tamaño de entre 30 y 40 buffers, con un tamaño de buffer de 532 bytes. Cada buffer contiene una
cabecera con información de control del buffer y los datos propiamente dichos, los cuales pueden ser de
tres tipos : datos de la tabla de asignación de archivos, datos de un directorio o datos de un archivo.
Todos los buffers existentes son organizados en una lista doblemente enlazada que es gestionada
mediante un algoritmo LRU. Cuando un buffer es utilizado es colocado al principio de la lista. De esta
forma al final de la lista están los buffers menos utilizados. Cuando hay que asignar un buffer siempre
se escoge al último de la lista. Si dicho buffer contiene un bloque de datos cuyo contenido ha sido
modificado entonces es escrito en el disco antes de reemplazar su contenido. Si el buffer contiene un
bloque de datos de la tabla de asignación de archivos que ha sido modificado entonces se actualizan
todas las copias de la tabla de asignación de archivos existentes en el disco.
7.7.2.
Drivers de dispositivos E/S
En MS-DOS se distinguen dos tipos de drivers de dispositivos de E/S : drivers residentes y drivers
instalables. Los drivers residentes se organizan en una capa de software denominada BIOS cuya parte
más primitiva es almacenada por el fabricante del computador en una memoria ROM. Durante el proceso
de arranque del sistema la BIOS es cargada en la memoria RAM j unto con el archivo i o . s y s , el cual
contiene rutinas de E/S que extienden la funcionalidad de la BIOS .
Los drivers residentes permiten al sistema operativo comunicarse con el hardware básico de la
computadora (disco de arranque, pantalla, teclado, puerto de impresión, reloj , etc). Para poder utilizar
otros dispositivos de E/ S distintos a los soportados en la B IOS , sus drivers deben ser instalados durante
el arranque del sistema. A estos drivers se les denomina drivers instalables, y son cargados en la memo­
ria principal en un área distinta de la B IOS . Señalar que un driver instalable también puede sustituir en
la memoria principal a un driver residente. De esta forma es posible utilizar versiones más actualizadas
de un determinado driver residente.
7.7.3.
Manejadores de interrupciones
MS-DOS implementa 256 manej adores de interrupción uno por cada una de las interrupciones dis­
ponibles en los procesadores de la familia Intel 80x86. Las 256 interrupciones disponibles se pueden
agrupar en tres categorías :
•
Interrupciones hardware externas. Son generadas por los controladores de E/S de los dispositivos
de E/S
•
Interrupciones hardware internas. También denominadas excepciones. Son generadas durante la
ejecución de un programa, debido a alguna condición de error, como por ejemplo, una división por
cero.
El sistema operativo MS-DOS
•
295
Interrupciones software. Son generadas por el sistema operativo y por los programas, para acceder
a las funciones del sistema y de la BIOS .
Esta arquitectura implementa interrupciones vectorizadas. La tabla de vectores de interrupción se
almacena en las direcciones más baj as de la memoria principal. Cada entrada de esta tabla está asociada
a una determinada interrupción y contiene la dirección de comienzo del manej ador de la interrupción
asociada a dicha interrupción. S eñalar que en MS-DOS algunos manej adores de interrupciones pueden
implementarse mediante procesos TSR.
78
.
.
Resumen
MS-DOS es un sistema operativo monousuario y monotarea escrito en lenguaj e ensamblador. Se
descompone en las siguientes capas lógicas : módulo BIOS , núcleo de MS-DOS e intérprete de comandos.
El módulo BIOS es la capa del sistema operativo encargada de comunicarse con el hardware. Contiene los
drivers residentes de los dispositivos de E/S (disco de arranque, pantalla, teclado, puerto de impresión,
reloj , etc) que son suministrados por defecto por el fabricante del computador. El núcleo de MS-DOS es
una capa independiente del hardware que se encarga de implementar los servicios ofunciones del sistema.
El intérprete de comandos implementa una interfaz de línea de comandos que permite al usuario invocar
los servicios del núcleo y ejecutar programas mediante la introducción de órdenes . Por defecto dicho
intérprete es el programa c ommand . c om.
MS-DOS es un sistema operativo monotarea, hasta que no termina de ejecutarse un proceso no
puede comenzar a ejecutarse otro. El proceso que se ejecuta tiene un control total de los recursos de la
máquina. Su ejecución solo puede ser interrumpida por el sistema operativo para realizar el tratamiento
de las interrupciones. Esta característica simplifica enormemente el control de los procesos y elimina la
necesidad de implementar un planificador de procesos.
En MS-DOS el control de procesos es muy simple, el proceso que se está ejecutando (proceso padre)
puede crear otro proceso (proceso hijo) invocando a la función del sistema 4 BH también conocida como
función EXEC. Esta función carga en memoria al proceso hijo y le transfiere el control. Mientras el pro­
ceso hijo se ejecuta el proceso padre permanece bloqueado en la memoria principal. Cuando el proceso
hijo va a terminar su ejecución invoca a una función del sistema para transferir el control de nuevo a su
proceso padre.
Las primeras versiones de MS-DOS trabaj an considerando la existencia de 1 MiB de memoria prin­
cipal, de los cuales solo 640 MiB podían ser utilizados por el sistema operativo y las programas. Cuando
MS-DOS tiene que asignar memoria principal a un programa utiliza el espacio del área de programas
transitorios. Este área de memoria es gestionada por el sistema operativo mediante la técnica de parti­
cionamiento dinámico.
A partir de su versión 2.0 MS-DOS implementó un modelo de gestión de archivos similar al utilizado
en los SOBUNIX: cuando un proceso desea abrir o crear un archivo debe invocar a la función del sistema
3 DH pasándole como argumento el nombre de ruta del archivo. Si el archivo se abre o se crea con éxito
MS-DOS devuelve al proceso un manejador de archivo de 1 6 bits, similar al descriptor de archivo de
296
Ampliación de sistemas operativos
los SOBUNIX. El proceso, cuando invoca a una función del sistema para leer o escribir un archivo, debe
pasarle como argumento su manej ador de archivo.
Cada sistema de archivos presente en memoria secundaria es tratado por MS-DOS como una unidad
o volumen lógico independiente, cada una de los cuales posee su propia estructura de directorios. MS­
DOS asigna una letra (C, D, E, . . . ) a cada unidad. El nombre de ruta de un archivo comienza por tanto
con el nombre del volumen lógico en el que está almacenado.
En sus primeras versiones MS-DOS soportaba únicamente sistemas de archivos PAT. Aunque poste­
riormente implementó la inteifaz IFS que le permitía soportar algunos otros sistemas de archivos, como
por ejemplo, el sistema de archivos ISO 9660 de los CD-ROM.
El sistema FAT utiliza como unidad de asignación de espacio al cluster, el cual está formado por
varios sectores de disco contiguos. Un sistema de archivos FAT presenta la siguiente estructura en la
partición de disco donde se crea: área de arranque, tabla de asignación de archivos, copias de la tabla de
asignación de archivos, directorio raíz y área de datos.
El subsistema de E/S de MS-DOS es muy simple debido a que se trata de un sistema operativo
monotarea. Cuando el proceso que se está ejecutando realiza una petición de E/ S ésta es inmediatamente
procesada. Hasta que no se atiende una petición el proceso no puede realizar otra.
7.9.
Lecturas recomendadas
Si se desea obtener una explicación adicional y ampliar los contenidos tratados en este capítulo se
pueden consultar, por ejemplo: [Duncan, 1 988b] , [Podanoffsky, 1 994] y el capítulo 14 de [McHoes y
Flynn, 20 1 0] .
7.10.
Autoevaluación
7 . 1 . Enumerar las características principales del sistema operativo MS-DOS . (Respuesta en sección 7 .2.2)
7 . 2 . Explicar la estructura del sistema operativo MS-DOS. (Respuesta en sección 7.2.3)
7 . 3 . Explicar cómo se implementan las llamadas al sistema en MS-DOS . (Respuesta en sección 7.2.4)
7 . 4 . Describir el proceso de arranque del sistema operativo MS-DOS . (Respuesta en sección 7.2.5)
7 . 5 . ¿Qué tipos de comandos soporta el intérprete c ommand . c om de MS-DOS ?
(Respuesta en sección 7.2.6)
7 . 6 . Enumerar y describir las partes en que se estructura el intérprete c ommand . c om.
(Respuesta en sección 7.2.6)
7 . 7 . Explicar el funcionamiento del intérprete c ommand . c om. (Respuesta en sección 7.2.6)
7 . 8 . Explicar la implementación y el control de procesos en MS-DOS . (Respuesta en sección 7 . 3 )
El sistema operativo MS-DOS
297
7 . 9 . Describir la creación y ejecución de procesos en MS-DOS . (Respuesta en sección 7 .3 . 1 )
7 . 10 . Describir l a terminación d e procesos en MS-DOS . (Respuesta en sección 7.3 .2)
7 . 1 1 . Dibujar un diagrama adecuadamente rotulado de la distribución de la memoria principal en MS­
DOS . Suponer que el tamaño de memoria es de 1 MiB . (Respuesta en sección 7.4)
7 . 12 . ¿Qué técnica utiliza MS-DOS para gestionar la memoria principal? Explicar su implementación.
(Respuesta en sección 7 .4)
7 . 13 . Explicar la implementación de la gestión de archivos utilizada en la primera versión de MS-DOS.
(Respuesta en sección 7 . 5 . 1 )
7 . 14 . Explicar la implementación de la gestión de archivos utilizada a partir de la versión 2.0 de MS­
DOS . (Respuesta en sección 7 .5 . 1 )
7 . 15 . Describir los posibles atributos de un archivo en MS-DOS . ¿Qué comando permite configurar los
atributos? (Respuesta en sección 7.5 .2)
7 . 16 . ¿Cuál es la utilidad de la interfaz IFS de MS-DOS ? (Respuesta en sección 7 . 5 . 3 )
7 . 17 . Describir la estructura de un sistema de archivos FAT. (Respuesta e n sección 7.6. 1 )
7 . 18 . Describir l a implementación de directorios en u n sistema de archivos FAT.
(Respuesta en sección 7 .6.2)
7 . 19 . Explicar cómo se localizan los clusters de datos de un archivo en un sistema FAT.
(Respuesta en sección 7 . 6 . 3 )
7 . 20 . Explicar cómo se implementa el buffering en MS-DOS . (Respuesta e n sección 7 . 7 . 1 )
7 . 21 . Describir los tipos de drivers que s e distinguen en MS-DOS . (Respuesta en sección 7.7 .2)
7.11.
Ejercicios
7 . 1 . Explique razonadamente cuál sería el resultado de la ejecución de las siguientes órdenes en el
intérprete de comandos c ommand . c om de MS-DOS o cmd . exe de Windows :
a ) d i r > l i s t ado . txt
b) dir
e) de l
f ind / I " l i s tado "
* .
txt
7 . 2 . Supóngase que en el directorio de trabajo actual existe el archivo tabl a . txt . ¿Qué orden se debe
escribir en el intérprete de comandos c ommand . c om de MS-DOS o cmd . exe de Windows para
conseguir que el archivo sea un archivo oculto de solo lectura?
298
Ampliación de sistemas operativos
7 . 3 En MS-DOS la cabecera de un bloque de memoria principal ocupa 5 bytes y tiene el siguiente
formato:
•
Byte O. Contiene el valor 9 O h del código ASCII si es el último bloque de la cadena de bloques
o el valor 7 7h en caso contrario.
•
B ytes 1 -2. De estos 16 bits el bit más significativo determina si el bloque está libre ( 1 ) u
ocupado (0). Los 1 5 bits restantes especifican el puntero al PSP del programa al que pertenece
el bloque.
•
B ytes 3-4. Contienen el número de parágrafos contenidos en el bloque.
Determinar toda la información posible que proporciona la siguiente cabecera de un bloque de
memoria: 7 7 0 0 0 0 0 0 0 3 h.
7 . 4 En un disco duro que utiliza un tamaño de sector de 5 1 2 bytes se desea crear un sistema de archivos
FAT- 1 2 con un tamaño de cluster de 1 6 sectores:
a) ¿Cuál sería el tamaño máximo del volumen?
b) ¿Qué tamaño tendría la tabla de asignación de archivos ?
7 . 5 Considérese u n sistema d e archivos FAT- 1 2 con u n tamaño d e cluster d e 2 KiB . Se pide:
a) Determinar el tamaño máximo de un archivo.
b) Determinar el número de entradas de directorio que caben en un cluster
e) Determinar la precisión de la hora de creación o modificación de un archivo almacenada en
una entrada de un directorio.
Capítulo 8
El s istema operativo Windows
Objetivos docentes
Los objetivos docentes de este capítulo son los siguientes :
•
Conocer el origen y la evolución del sistema operativo Windows.
•
Conocer las características principales y la estructura de Windows.
•
Conocer de forma general el funcionamiento y la implementación de la interfaz gráfica de usuario
proporcionada por Windows.
•
S aber cómo se implementan y atienden las llamadas al sistema en Windows.
•
Conocer las principales llamadas al sistema disponibles en Windows.
•
S aber cómo se implementa la seguridad y la protección de los datos de los usuarios en Windows.
•
Conocer la implementación, el control y la planificación de procesos multihilos en Windows.
•
Conocer los principales mecanismos de sincronización y de comunicación entre procesos disponi­
bles en Windows.
•
Saber cómo se realiza la administración de memoria en Windows.
•
Conocer cómo se realiza la gestión de archivos en Windows.
•
Conocer las características principales y la estructura de un sistema de archivos NTFS .
•
Saber cómo se realiza la gestión de la E/ S en Windows.
299
300
8. 1.
Ampliación de sistemas operativos
Introducción
Desde principios de los noventa hasta la actualidad Windows de Microsoft es el sistema operativo
preferido por la mayoría de los usuarios de computadores personales en todo el mundo. Sus detracto­
res cargan contra su carácter comercial, su código cerrado y sus problemas de estabilidad y seguridad.
Sin embargo, es indudable que su sencilla interfaz gráfica y el precio razonable de las máquinas que
traen instalado Windows han facilitado el acercamiento al mundo de los computadores personales de los
usuarios sin conocimientos previos de informática o programación.
Este capítulo está dedicado al estudio del sistema operativo Windows 1 • En primer lugar se realizan
una serie de consideraciones generales sobre Windows. En concreto se comenta su cronología histórica,
sus características principales, su estructura, la implementación de la API Win32, su interfaz con el
usuario, la implementación de las llamadas al sistema, el registro de Windows, su secuencia de arranque y
la seguridad en Windows. En segundo lugar se describe la implementación, el control y la planificación de
procesos multihilos en Windows. En tercer lugar se estudian los mecanismos de sincronización del núcleo
y los mecanismos de comunicación entre procesos. En cuarto lugar se estudia la gestión de memoria. En
quinto lugar se describe la gestión de archivos y el sistema de archivos NTFS , que es el sistema de
archivos principal utilizado en Windows. En sexto lugar se estudia la gestión de la E/S .
Señalar que obviamente, por motivos de espacio, este capítulo no es más que un pequeño resumen
de las características de Windows. Los lectores que deseen profundizar en su estudio pueden consultar
las referencias bibliográficas reseñadas en la sección 8. 1 O. También conviene tener presente que algunos
puntos del funcionamiento de este sistema operativo no se pueden explicar con el detalle deseado porque
Microsoft no los ha hecho públicos.
Finalmente comentar que algunos lectores echarán en falta en este capitulo la inclusión de programas
que ilustren el funcionamiento de las llamadas al sistema disponibles en Windows, tal y como se hizo al
describir los S OBUNIX en los capítulos anteriores. Esta decisión se fundamenta en el gran número de
parámetros de las funciones de la API Win32 a partir de las cuales se invocan a las llamadas al sistema
en Windows, lo que lleva a que los programas sean mucho más extensos y relativamente más difíciles de
comprender que los utilizados en los SOBUNIX.
8.2.
Consideraciones generales sobre Windows
8.2.1.
Cronología histórica
A mediados de los ochenta el sistema operativo más popular que disponía de una interfaz gráfica de
usuario basada en ventanas era el sistema Mac OS utilizado en los computadores personales Macintosh de
Apple. Influenciado por este sistema operativo Microsoft decidió dotar a su sistema operativo MS-DOS
de una GUI similar a la que bautizó con el nombre de Windows. La primera versión de Windows apareció
en el mercado en 1 985 y la segunda versión en 1 987. Estas dos primeras versiones no tuvieron mucho
1 En concreto las explicaciones de este capítulo toman como base a Windows Vista, que es el nombre comercial de Windows
NT 6.0.
El sistema operativo Windows
301
éxito. No fue hasta su versión 3 . 0 aparecida en 1 990 cuando Windows comenzó a hacerse realmente
popular.
La versión 3 . 1 de Windows aparecida en 1 992 fue la última versión de Windows que puede con­
siderarse como únicamente una GUI. Fue en 1 995 con la aparición de Windows 95, cuando Windows
adquirió la categoría de sistema operativo como tal, implementando gestión de procesos, multiprogra­
mación y gestión de la memoria virtual. Aunque si bien usaba MS-DOS para arrancar.
Uno de los principales problemas de Windows 95 era su inadecuado aislamiento entre los procesos
de usuario y el núcleo, lo que producía serios problemas de estabilidad. Las siguientes versiones de
Windows: Windows 98 aparecida en 1 998 y Windows Millennium (Windows Me) aparecida en 2000,
tampoco resolvieron el problema de la estabilidad. Además también usaban MS-DOS para arrancar.
A finales de los ochenta, en paralelo al desarrollo de Windows, Microsoft comenzó a desarrollar otro
sistema operativo nuevo basándose en los siguientes principios de diseño [Russinovich et al. , 2009] :
•
Extensibilidad. El código del sistema operativo debe poder ser modificado y extendido de forma
sencilla para poder adaptarse a las nuevas necesidades del mercado.
•
Portabilidad. El sistema operativo debe poder ser ejecutado en diferentes arquitecturas hardware.
•
Fiabilidad y robustez. Una aplicación de usuario no debe poder acceder al espacio de direcciones
del sistema operativo ni al de otras aplicaciones.
•
Compatibilidad. El sistema operativo debe de ser capaz de soportar las aplicaciones que se desarro­
llen para otros sistemas operativos como MS-DOS , OS/2 o aquellas que sigan las especificaciones
POS IX.
La primera versión de este nuevo sistema operativo apareció en 1 993 y se denominó Windows NT
2
3 . 1 . Señalar que Microsoft usó para la primera versión de NT el mismo número de versión que el de la
versión de Windows existente por aquella fecha.
Inicialmente Windows NT no tuvo mucho éxito pero a partir de su versión 4.0 aparecida en 1 996 que
incluía una GUI similar a la de Windows 95 comenzó a ganar cuota de mercado como sistema operativo
de servidores y estaciones de trabajo.
El éxito tanto técnico como comercial de la versión 5 . 0 de Windows NT aparecida en el mercado
en el 2000 bajo el nombre de Windows 2000 hizo que Microsoft dej ara de utilizar MS-DOS como base
de su sistema operativo Windows . A partir de entonces todos los sistemas operativos de Microsoft están
basados en alguna versión de Windows NT.
Con respecto a las versiones cliente de Windows, es decir, aquellas destinadas a computadores perso­
nales, en 200 1 Microsoft sacó al mercado Windows NT 5 . 1 con el nombre de Windows XP. Este sistema
es uno de los sistemas operativos de Microsoft que más tiempo ha perdurado. No sería hasta 2007 cuan­
do Microsoft sacó una nueva versión: Windows Vista, que era el nombre comercial de Windows NT 6.0
(Build 6000). Este sistema operativo recibió bastantes críticas ya que presentaba bastantes problemas.
2NT es el acrónimo del término inglés New Technology (nueva tecnología).
302
Ampliación de sistemas operativos
En cuanto a las versiones servidor de Windows, es decir, aquellas destinadas a servidores y estaciones
de trabajo, en 2003 Microsoft sacó al mercado Windows NT 5 . 2 con el nombre de Windows Server 2003 .
Cinco años más tarde, en 2008, lanzó Windows Server 2008 que era el nombre comercial de Windows
NT 6.0 (Build 600 1 ) .
E n e l momento d e escribir estas líneas las últimas versiones aparecidas de Windows son Windows 7
y Windows Server 2008 R2, aparecidas en 2009, que son los nombres comerciales de la versión cliente
y de la versión servidor, respectivamente, de Windows NT 6. 1 .
8.2.2.
Características principales de Windows
Las características principales del sistema operativo Windows son:
•
Es un sistema operativo multiprogramado y multitarea, con soporte para multiprocesamiento.
•
El núcleo está escrito en su mayor parte en lenguaj e C.
•
El núcleo posee una estructura de tipo monolítica o simple.
•
La planificación se realiza a nivel de hilos del núcleo usando un algoritmo de planificación basada
en múltiples colas de planificación y realimentación.
•
Dispone de mecanismos de sincronización y comunicación entre procesos o hilos: semáforos,
eventos, tuberías, conectores, objetos compartidos, mailslots, etc.
•
No suelen utilizar ninguna estrategia de tratamiento de interbloqueos. Dichas estrategias si se
quieren implementar deben hacerse a nivel de los programas de aplicación.
•
Administra la memoria principal e implementa la memoria virtual usando la técnica de demanda
de página.
•
Considera a los archivos como una secuencia de bits y delegan en las aplicaciones la interpretación
de los mismos.
•
Soporta tanto el acceso secuencial como el acceso aleatorio a los archivos.
•
En los nombres de archivos no distingue entre minúsculas y mayúsculas.
•
Cada sistema de archivos presente en memoria secundaria es tratado como una unidad o volumen
lógico independiente, cada una de los cuales posee su propia estructura de directorios. Windows
asigna una letra (C, D, E, . . . ) a cada unidad.
•
Dentro de cada volumen soporta una estructura de directorios de gráfica acíclica. El directorio raíz
de un volumen se denota por el carácter \ , que además se usa para separar los componentes
del nombre de ruta de un archivo. Para acceder al sistema de archivos de otra unidad se debe
especificar al comienzo de la ruta la letra de la unidad seguido de dos puntos, por ejemplo: e : \ .
'
•
'
La interfaz con el usuario es del tipo interfaz de usuario gráfica (GUI).
El sistema operativo Windows
8.2.3.
303
Estructura del sistema operativo Windows
El sistema operativo Windows consta de diversos componentes software (ver Figura 8. 1 ), unos se
ejecutan en modo usuario y otros en modo núcleo. Los componentes de Windows que se ejecutan en
modo usuario son los siguientes :
•
Procesos del sistema. Son procesos creados por el sistema operativo que se encargan de realizar
tareas que dependen del usuario interactivo que haya iniciado una sesión de trabajo en el sistema.
Ejemplos de procesos del sistema son el gestor de sesión de usuario (sms s . exe) y el proceso de
inicio de sesión (wi n l o gon . exe).
•
Procesos de servicios. También denominados servicios. Son procesos creados por el sistema ope­
rativo que se encargan de realizar diferentes tareas administrativas en modo usuario independien­
temente del usuario interactivo que haya iniciado una sesión de trabajo en el sistema. Los procesos
de servicios de Windows son similares a los procesos demonio de los SOBUNIX. Todos los proce­
sos de servicios existentes son controlados por el gestor de control de servicios ( s ervi c e s . exe)
que se encarga de iniciar, parar e interactuar con los procesos de servicio. Un ejemplo de proceso
de servicio de Windows es el spooler de impresión.
•
Aplicaciones. Son procesos asociados a archivo ejecutables de algunos de los siguientes tipos:
Windows 32 o 64 bits, Windows 3 . 1 1 6 bits, MS-DOS 16 bit o POSIX 32 bits. Algunas aplicacio­
nes son iniciadas por el propio sistema operativo cuando un usuario inicia una sesión en el sistema.
Este es el caso por ejemplo del explorador de Windows (exp l orer . exe) que implementa el escri­
torio de Windows. Otras aplicaciones, como navegadores web, gestores de correos y procesadores
Procesos
del
sistema
1
Procesos
de
servicios
Aplicaciones
1
1
Subsistemas
de
entorno
1
Modo usuario
Librerías de enlace dinámico (DLLs)
Interfaz de llamadas al sistema (ntdl l . dl l )
-----------------------------------�------------------------------
Núcleo de --Windows N T
�
Drivers
dispositivos
1
Ej ecutivo
Kernel
1
Implementación
de la GUI
Capa de abstracción del hardware (HAL)
Hardware
Figura 8.1
1
- Estructura del sistema operativo Windows
Modo núcleo
304
Ampliación de sistemas operativos
de texto, son invocadas por el propio usuario interactuando con los iconos o los menús de la GUI
de Windows.
•
Librerías de enlace dinámico. Una librería de enlace dinámico o librería DLL (Dynamic Link
Library) es un conjunto de rutinas enlazadas juntas en un archivo binario que puede ser cargado en
tiempo de ejecución dentro del espacio de direcciones de los procesos que invocan a dichas rutinas.
Las librerías DLL permiten ahorrar espacio en memoria ya que solo es necesario cargar una única
copia del código de la librería en la memoria principal. Todos los procesos que tienen enlazada la
misma librería DLL en su espacio de direcciones comparten el mismo código de la librería. Luego
las librerías DLL son el mecanismo utilizado en Windows para implementar librerías compartidas.
Una de las librerías DLL más importante es ntdl l . dl l ya que es usada por las restantes librerías
DLL. La librería ntdl l . dl l contiene todas las funciones de envoltura de las llamadas al sistema
de Windows (ver sección 8.2.6). También contiene otras funciones de apoyo, como por ejemplo:
funciones para comunicarse con el subsistema de entorno de Windows, funciones para gestionar
el montículo, etc.
Las librerías DLL no solo se ejecutan en modo usuario, algunas DLLs también pueden ser utiliza­
das en modo núcleo por el propio sistema operativo.
•
Subsistemas de entorno. En sus orígenes Windows NT soportaba tres interfaces de programación
de aplicaciones o APis : la API de Windows (API Win323 ), la API POSIX, y la API OS/2. A partir
de Windows XP la API OS/2 dejó de soportarse. Por otra parte, la API POSIX ha sido extendida
y mejorada desde Windows Vista.
El sistema operativo para implementar la funcionalidad de cada API utiliza un proceso de usuario
denominado subsistema de entorno y un conjunto de librerías DLL. El subsistema de entorno
Windows siempre se ejecuta ya que se utiliza, como se verá en la sección 8.2.5, para implementar
la GUI de Windows. Por su parte el subsistema de entorno POSIX, conocido desde Windows Vista
como subsistema para aplicaciones basadas en UNIX (Subsystem for Unix-based Applications,
SUA), solo se ejecuta si se ejecuta una aplicación que utiliza la API POSIX.
Por otra parte los componentes de Windows que se ejecutan en modo núcleo son los siguientes:
•
Capa de abstracción del hardware (Hardware Abstraction Layer, HAL). Esta capa oculta los de­
talles del hardware al resto de componentes del sistema operativo lo que facilita la portabilidad
del sistema operativo a diferentes plataformas. La capa HAL se implementa en la forma de una li­
brería DLL (ha l . dl l ) . Cada plataforma tiene asociado su librería DLL correspondiente. Cuando
un componente del sistema operativo necesita realizar una operación sobre el hardware invoca a
una función de la capa HAL la cual se encarga de traducirla a la función adecuada dependiente del
hardware.
3 Aunque denominada como API Win32 esta interfaz es válida tanto para las versiones de Windows de 32 bits como para las
versiones de 64 bits.
El sistema operativo Windows
305
•
Drivers de dispositivos. En Windows los drivers de dispositivos se implementan como módulos
que pueden ser cargados dinámicamente y que se ejecutan en modo núcleo en el contexto de un
hilo asociado a un proceso de usuario que ha iniciado una operación de E/S, en el contexto de un
hilo del sistema, o como resultado de una interrupción. Generalmente el código de un driver se en­
cuentra en un archivo con extensión . sys . A diferencia de otros sistemas operativos la mayoría de
los drivers en Windows no interaccionan directamente con el hardware sino que utilizan funciones
de la capa HAL.
•
Implementación de la GUI. La GUI de Windows (ver sección 8.2.5) es un componente tan utilizado
que para mejorar el rendimiento del sistema se ejecuta en modo núcleo.
•
Núcleo de Windows NT. Se implementa en el archivo ejecutable n t o skrnl . exe y se descompone
en dos capas :
- Ejecutivo (executive). Es la capa superior del núcleo de Windows NT. Atiende las llamadas al
sistema e implementa los servicios4 del sistema operativo: administrador de memoria, admi­
nistrador de la caché5 , administrador de E/ S , administrador de PnP (Plug-and-Play, conectar
y usar), monitor de seguridad, administrador de procesos, administrador de objetos, admi­
nistrador de configuración. El ejecutivo también se encarga de implementar las llamadas a
procedimientos locales avanzados (Advanced Local Procedure Calls, ALPCs) (ver sección
8.4.3).
- Núcleo (kernel). Es la capa inferior del núcleo de Windows NT. Se encarga del encamina­
miento de las interrupciones, excepciones y trampas, También se ocupa de la planificación y
sincronización de hilos. Además contiene las rutinas para la manipulación de objetos.
8.2.4.
Implementación de la API Win32
La API Wln32 es la interfaz de programación de aplicaciones más utilizada por las aplicaciones
de Windows. Para implementar su funcionalidad Windows utiliza el subsistema de entorno Windows
{c s r s s . exe) y centenares de librerías DLL, ubicadas en su mayoría en e : \wi ndows \ sys t em3 2 . Entre
las librerías DLL más importantes que implementan la funcionalidad de la API Win 32 se encuentran las
siguientes :
•
kerne l 3 2 . dl l . Contiene funciones que permiten acceder a la mayoría de llamadas al sistema
básicas excepto las que implementan la GUI.
•
gdi 3 2 . dl l . Contiene funciones que permiten acceder a llamadas al sistema asociadas con la GUI
para el manejo de elementos tales como fuentes, textos, colores, mapas de bits, etc.
4 Aquí la palabra servicio se refiere a las tareas que realiza el núcleo. No debe confundirse con Jos servicios de Windows que
son procesos que se ejecutan en modo usuario.
5Se trata de la caché software, denominada caché del sistema, que implementa Windows para almacenar las regiones de los
archivos usadas más recientemente.
306
Ampliación de sistemas operativos
•
u s e r 3 2 . dl l . También contiene funciones que permiten acceder a llamadas al sistema asociadas
con la GUI para el manejo de elementos como ventanas, iconos, menús, cursor, etc.
•
advap i 3 2 . dl l . Contiene funciones que permiten acceder a llamadas al sistema asociadas a tareas
de administración, registro y seguridad, entre otras.
Cuando se invoca a una función de una librería DLL pueden producirse las siguientes acciones :
•
La función realiza una cierta tarea y retorna sin necesidad de invocar ninguna llamada al sistema.
•
La función invoca a una función de la librería n tdl l . dl l para invocar a una llamada al sistema.
La librería ntdl l . dl l contiene las funciones de envoltura de las llamadas al sistema de Windows.
•
La función envía un mensaj e al subsistema de entorno al que pertenece, el cual realiza ciertas
tareas. En algunos casos el subsistema es capaz de realizar todo el trabajo en modo usuario sin ne­
cesidad de realizar una llamada al sistema. En otros debe realizar una llamada al sistema invocando
a una función de la librería n tdl l . dl l .
Finalmente comentar que las funciones de la API Win32 se caracterizan por tener nombres largos
que suelen resumir bastante bien la tarea que implementan. Por ejemplo, la función CreateProc e s s
permite crear u n proceso.
También las funciones de la API Win32 se caracterizan por tener bastantes argumentos de entrada.
Ello las dota de una mayor flexibilidad pero también complica su uso a los programadores.
8.2.5.
Interfaz con el usuario de Windows
Windows desde su concepción se caracteriza por proporcionar al usuario una interfaz gráfica. Si bien
también es posible trabajar con una interfaz de línea de comandos usando el intérprete de comandos
cmd . exe, una versión mej orada del c ommand . c om de MS-DOS .
En sus orígenes la GUI de Windows se ejecutaba en modo usuario como parte del subsistema de
Windows, pero ello afectaba bastante al rendimiento del sistema debido a los constantes cambios de
hilos y de procesos que había que realizar. A partir de Windows NT 4.0 la mayor parte de la GUI se
implementa como un conjunto de rutinas ejecutables en modo núcleo dentro del driver win3 2 k . sys .
Estas rutinas pueden ser invocadas mediante funciones de las librerías DLL que implementan la API
Win32, como por ejemplo: u s e r 3 2 . dl l y gdi 3 2 . dl l .
El driver win3 2 k . sys implementa los siguientes componentes de la GUI de Windows :
•
Sistema de ventanas. Se encarga d e controlar como s e muestran las ventanas e n l a pantalla. Además
gestiona la entrada de datos a través del teclado y el ratón, u otros dispositivos de interfaz humana,
y envía mensajes a las aplicaciones que esperan dichas entradas. También gestiona la salida en
pantalla de acuerdo con los mandatos de las aplicaciones.
•
Inteifaz de dispositivos gráficos (Graphics Device Interface, GDI). Es una librería de funciones
para creación y manipulación de gráficos (líneas, textos, figuras, etc) en dispositivos gráficos.
El sistema operativo Windows
•
307
Funciones de envoltura a DirectX. DirectX es una API que proporciona funciones para aplicacio­
nes multimedia (juegos, reproducción de video, etc). Esta API se implementa a través del driver
dxgkrn l . sys
Para interactuar con los dispositivos gráficos las rutinas del driver win3 2 k . sys utilizan a su vez
diferentes drivers, algunos de los cuales para mej orar el rendimiento interaccionan directamente con el
hardware sin necesidad de invocar funciones de la capa HAL.
8.2.6.
Llamadas al sistema en Windows
En Windows a las llamadas al sistema se les denomina servicios del sistema, para evitar confusiones
con los procesos de servicio a los que también se les denomina servicios, en todo el capítulo se utiliza el
término llamada al sistema en lugar de servicio del sistema.
Las funciones de envoltura de las llamadas al sistema de Windows se encuentran en la librería
n tdl l . dl l . Microsoft ha publicado muy poca información sobre las funciones de esta librería, por
lo que es difícil trabaj ar con ellas directamente. El acceso a las funciones de la librería ntdl l . dl l , es
decir, la invocación de llamadas al sistema, se realiza de forma indirecta a través de las funciones de las
librerías DLL que implementan las APis soportadas por Windows, las cuales están bien documentadas 6 .
En la Tabla 8. 1 se muestran algunos ejemplos de funciones de la librería kerne l 3 2 . dl l de la API
Win32 y se especifican las funciones de la librería ntdl l . dl l que son invocadas durante su ejecución.
Función de kerne l 3 2 . dl l
Función d e ntd l l . dl l
CreateF i l e
ReadF i l e
Wr i t eF i l e
C l o s eHandl e
Creat e Pro c e s s
Creat eThread
NTCreateF i l e
NTReadF i l e
NTWr i te Fi l e
NTC l o s e
NTCreateUs erPro c e s s
NTCreat eThread
Tabla 8.1
-
Tarea que realiza
Crear o abrir u n archivo y a existente
Leer archivo
Escribir archivo
Cerrar e l descriptor de u n objeto abierto
Crear u n proceso
Crear un hilo
Algunos ejemplos de funciones de la API Win32 y de sus funciones asociadas en la librería
n t dl l . dl l
El programador de aplicaciones únicamente debe conocer cuál es la función F l de l a API que necesita
invocar para realizar una cierta tarea. Si la realización de dicha tarea requiere invocar a una llamada
al sistema entonces la función Fl invocará a la función F2 apropiada de la librería ntdl l . dl l . La
función Fl antes de invocar a la función F2 quizás tenga que realizar algún procesamiento sobre los
argumentos que va a pasar a F2. Por ejemplo, si hay algún argumento de tipo carácter o cadena de
caracteres codificados en ANSI la función F2 deberá pasarlos a codificación Unicode, que es el estándar
de codificación utilizado por las llamadas al sistema de Windows.
La función de envoltura F2 de la librería n tdl l . dl l es la que se encarga de pasarle al sistema
operativo toda la información que necesita conocer para tratar la llamada al sistema: el identificador de
6www.msdn.microsoft.com
308
Ampliación de sistemas operativos
la llamada, que es un número entero positivo que la identifica de forma univoca, y los argumentos de la
llamada. Cuando ya tiene lista esta información invoca una instrucción hardware especial denominada
trampa que transfiere el control al sistema operativo.
Cuando tiene lugar una trampa asociada a una llamada al sistema se produce una conmutación de
modo usuario a modo núcleo y se guarda el contexto hardware del hilo en ejecución. A continuación se
invoca a una rutina general de tratamiento de llamadas al sistema denominada despachador de llamadas
al sistema que guarda los argumentos de la llamada al sistema en la pila del núcleo asociada al hilo en
ejecución y obtiene de un registro de la máquina el identificador de la llamada al sistema.
El despachador utiliza el identificador de la llamada para buscar en la tabla de despacho de llamadas
al sistema la dirección de inicio de la rutina de tratamiento especifica de la llamada al sistema que ha
sido invocada. Esta tabla contiene una entrada por cada llamada al sistema soportada. Cada entrada
contiene la dirección de inicio de la rutina de tratamiento asociada a dicha llamada. Una vez localizada.
el manej ador invoca a la rutina específica de tratamiento de la llamada. Dicha rutina se implementa en el
ejecutivo del núcleo (nt o s krnl . exe ) si se trata de una llamada no asociada con la GUI, o en el driver
que implementa la GUI en modo núcleo (win3 2 k . sys ) si se trata de una llamada asociada con la GUI.
Cuando finaliza la rutina de tratamiento de la rutina se devuelve el control al despachador que restaura
el contexto hardware del hilo y le transfiere el control para que continúe su ejecución en modo usuario
en el punto de retomo de la llamada al sistema.
8.2. 7.
El registro de Windows
El registro de Windows (registry) es una base de datos que recopila toda la información fundamental
relativa al hardware, al software y a los usuarios necesaria para arrancar y configurar el sistema de
acuerdo con el usuario que ha iniciado una sesión. La mayor parte del registro se almacena en el sistema
de archivos de la partición de arranque de Windows en el directorio e : \ windows \ sys t ern3 2 \ c o n f i g
en diferentes archivos denominados subárboles (hives).
El registro de Windows se implementa mediante dos tipos de elementos: las llaves y los valores. Una
llave es similar a un directorio. Mientras que un valor es similar a un archivo. Cada llave tiene asignado
un nombre y puede contener valores y otras llaves. Señalar que a una llave contenida dentro de otra llave
también se le denomina subllave. Luego una subllave es similar a un subdirectorio.
Por su parte cada valor tiene asignado un nombre, un tipo de datos y los datos propiamente dichos.
El nombre de un valor es una cadena de caracteres codificados en código Unicode. El tipo de un valor
especifica el tipo de datos que contiene el valor. Existen definidos hasta catorce tipos distintos de valo­
res, entre ellos: REG_s z cadena de caracteres codificados en Unicode, REG_B INARY número binario de
longitud arbitraria, REG_L INK enlace simbólico en Unicode y REG_DWORD entero de 32 bits.
En el nivel raíz del registro existen creadas, por defecto, seis claves raíz:
•
HKEY_USERS . Contiene los perfiles de todos los usuarios. Existe una clave por cada perfil de
usuario definido Windows. El perfil contiene las preferencias del usuario relativas al escritorio,
teclado, sonidos, software, etc.
El sistema operativo Windows
•
309
HKEY_CURRENT_USER. Enlace simbólico a la parte del registro donde se encuentran las preferen­
cias del usuario actual.
•
HKEY_CLAS SES_ROOT. Enlace simbólico a la parte del registro que mantiene la información sobre
las aplicaciones que hay que invocar en función de las extensiones de los archivos . Por ejemplo,
cuando se hace doble clic sobre un archivo con extensión . pdf el programa que gestiona la entrada
del ratón lee esta clave del registro para determinar que aplicación debe iniciar, normalmente
Adobe Reader.
•
HKEY_LOCAL_MACHINE. Contiene información sobre el hardware y el sistema operativo. Esta
información se distribuye en cinco subclaves :
- HARDWARE . Describe el hardware de la máquina especificando que controlador debe utilizarse
para cada dispositivo. Señalar que esta información no se almacena en el disco sino que es
recopilada cuando se arranca el sistema por un componente del ejecutivo, el administrador
de PnP.
SAM (Security Account Manager, administrador de cuentas de seguridad) . Contiene informa­
ción sobre las cuentas de los usuarios, como por ejemplo, sus nombres de usuario y contra­
señas.
SECURITY. Contienen información sobre la implementación de la política de seguridad: nú­
mero de veces que un usuario ha introducido una contraseña no válida, la longitud mínima
que debe tener una contraseña para considerarse como válida, etc.
SOFTWARE. Contiene información almacenada por las aplicaciones. Por ejemplo, si se tiene
instalado el navegador Firefox entonces existirá creada una subclave de nombre Mo z i l l a
donde la aplicación puede guardar toda la información que considere necesaria, por ejemplo,
su número de versión o información para desinstalar la aplicación.
SYSTEM. Contiene información necesaria para arrancar el sistema, como por ejemplo, un
listado con los drivers que hay instalar y un listado con los procesos de servicios que hay que
iniciar.
•
HKEY_CURRENT_CONF I G . Enlace simbólico a la parte del registro donde se encuentra la configu­
ración actual del hardware.
•
HKEY_PERFORMANCE_DATA. Permite acceder al estado del hardware y a los contadores que man­
tiene el sistema operativo. Esta información resulta de gran utilidad para monitorizar el rendimien­
to del sistema.
El registro de Windows puede ser accedido y manipulado por el sistema operativo, por las aplicacio­
nes y por los usuarios. Estos últimos pueden acceder al registro haciendo uso de alguno de los programas
distribuidos por Microsoft como por ejemplo: el editor del registro (regedi t . exe) 7 y el monitor de
7Conviene señalar que este programa no muestra la clave HKEY_PERFORMANCE_DATA.
310
Ampliación de sistemas operativos
procesos (pro cmon . exe ) . Es importante señalar que la manipulación del registro debe ser realizada por
usuarios y administradores expertos. Una manipulación inapropiada del registro puede provocar que el
sistema no sea capaz de arrancar y haya que instalar de nuevo todo el sistema operativo.
Por otra parte, existen varias funciones en la API Win32 que permiten a las aplicaciones acceder
y manipular el registro. Por ejemplo, la función RegQueryVa l u e Ex busca los datos de un valor den­
tro de una clave, la función RegCrea t eKeyEx crea una nueva clave dentro del registro, y la función
RegDe l e t eKey borra una clave del registro.
8.2.8.
Arranque de Windows
El arranque de Windows se implementa mediante el programa boo tmgr . exe ubicado en el direc­
torio raíz de la partición de arranque. Este programa en primer lugar comprueba el estado en que se en­
cuentra el sistema operativo. Si estaba en el estado suspendido o el estado hibernado entonces invoca al
programa winresume . exe para reanudar la ejecución del sistema. Si el sistema estaba en el estado apa­
gado entonces inicia la carga del sistema operativo mediante la invocación del programa win l o ad . exe.
winl oad . exe se encarga de cargar en la memoria principal los componentes del sistema operativo
que se ejecutan en modo núcleo: el ejecutivo y el núcleo ubicados en ntoskrnl . exe , la capa HAL
ubicada en la librería hal . dl l , el driver win3 2 k . sys que implementa la GUI, y todos los drivers ne­
cesarios de acuerdo con la información especificada en la clave SYSTEM del registro de Windows. A
continuación transfiere el control a una rutina de bajo nivel del núcleo que se encarga de inicializar todos
los componentes del sistema operativo que se ejecutan en modo núcleo. Además crea el primer proce­
so en modo usuario: el gestor de sesión de usuario ( sms s . exe ) . Este proceso se encarga de iniciar el
subsistema de entorno de Windows ( c s r s s . exe ) , cargar diferentes librerías DLL, realizar las operacio­
nes de configuración establecidas en los subárboles del registro, e iniciar al proceso de inicio de sesión
(winl ogon . exe ) .
El proceso winl ogon . exe se encarga de crear al administrador de validación ( l s a s s . exe ) y el
gestor de servicios ( s ervi c e s . exe ) . Además se encarga de realizar todas las tareas necesarias para
iniciar la sesión del usuario. El proceso l s a s s . exe se encarga de la autentificación del usuario. Si el
nombre de usuario y la contraseña introducidas coinciden con algunos de los perfiles definidos en el
registro entonces se inicia el proceso exp l orer . exe que implementa el escritorio de Windows . Por su
parte el proceso s e rvi c e s . exe se encarga de crear y controlar a los procesos de servicios de Windows.
Este proceso para saber cuáles son los servicios que debe iniciar consulta el registro.
8.2.9.
Objetos del núcleo
Un objeto del núcleo es una estructura de datos mantenida en el espacio de direcciones del núcleo de
Windows NT asociada a una determinada abstracción y gestionada por el administrador de objetos del
ejecutivo. La abstracción a la que está asociado un objeto define el tipo del objeto. Por ejemplo, el núcleo
asocia a un archivo abierto un objeto archivo, a un proceso un objeto proceso, a un hilo un obj eto hilo, a
un semáforo un objeto semáforo, a una clave del registro un objeto clave, a un driver instalado un objeto
driver, etc.
El sistema operativo Windows
311
Conviene señalar que Windows está escrito en su mayor parte en el lenguaj e de programación C,
por lo que estos objetos no deben confundirse con los obj etos utilizados en lenguaj es de programación
orientados a objetos como C + + . Los objetos implementados en Windows mediante C soportan ocultación
de datos y abstracción, pero no polimorfismo ni herencia.
Cada objeto tiene asignado un nombre codificado en Unicode, el ejecutivo mantiene un espacio de
nombres en memoria con una organización similar a una estructura de directorios de gráfica acíclica.
Windows utiliza el nombre de un objeto para localizar el objeto.
Un objeto implementado en Windows consta de dos partes : la cabecera y los datos específicos del
objeto. La cabecera contiene la información necesaria para gestionar el obj eto, como por ejemplo: su
nombre y directorio en el espacio de nombres, su descriptor de seguridad (ver sección 8.2. 1 0) y un
puntero a la estructura que implementa el tipo de obj eto. Esta información es común a todos los objetos
e independiente de su tipo.
Cada tipo de objeto definido se implementa mediante una estructura que contiene información de­
pendiente del tipo de objeto, como por ejemplo: derechos de acceso, recursos de memoria que puede
consumir y punteros a las funciones que se pueden invocar para operar (abrir, cerrar, borrar, etc) sobre
este tipo de objeto.
El administrador de objetos es el componente del ejecutivo encargado de gestionar (crear, configurar,
borrar, etc) todos los objetos del núcleo. Además proporciona una interfaz a los restantes componentes
del ejecutivo para crear y operar con los objetos.
Diferentes llamadas al sistema requieren de la creación de nuevos obj etos del núcleo o del acceso
a objetos ya existentes. Cuando un proceso invoca a una llamada al sistema que requiere de la apertura
o de la creación de un objeto del núcleo, el sistema devuelve al proceso como parámetro de retorno de
la llamada un descriptor del objeto (handle). Dicho descriptor debe ser utilizado como argumento de
entrada en las posteriores llamadas al sistema que realice dicho proceso que involucren a dicho objeto.
El sistema mantiene una tabla de descriptores (handle table) local a cada proceso. De esta forma un
mismo descriptor puede hacer referencia en dos procesos distintos a objetos distintos.
8.2.10.
Seguridad en Windows
Mecanismos de seguridad
Windows NT dispone de los siguientes mecanismos de seguridad [Tanenbaum, 2009] :
•
Inicio de sesión seguro. En Windows NT un usuario para que le aparezca la pantalla de inicio
de sesión en la que introducir su nombre usuario y su contraseña debe pulsar la combinación de
teclas [ c ontro l ] + [ a l t ] + [ supr l . El manej ador de interrupciones del teclado al detectar esta
combinación de teclas inicia al autentico programa de inicio de sesión. Los procesos de usuario no
disponen de ningún mecanismo para poder cambiar el programa al que redirecciona esta combina­
ción de teclas. Con ello se pretende evitar que un software malicioso pueda simular la ventana de
inicio de sesión para capturar la contraseña. Señalar que en algunos casos Windows NT desactiva
este mecanismo, de hecho en las versiones cliente de Windows está desactivado por defecto.
312
Ampliación de sistemas operativos
•
Control de acceso discrecional. Los propietarios de un objeto pueden especificar que otros usuarios
pueden utilizar dicho obj eto y que operaciones pueden realizar.
•
Control de acceso privilegiado. El administrador del sistema es el único que dispone de los permi­
sos necesarios para modificar los permisos establecidos por un usuario.
•
Protección del espacio de direcciones de un proceso. Cada proceso dispone de un espacio de
direcciones virtuales independiente que no puede ser accedido por otros procesos.
•
Borrado explicito de los marcos de página asignados a un proceso. Los marcos de memoria prin­
cipal asignados a las páginas de la región de pila o al montículo de un proceso se deben rellenar
inicialmente con páginas inicializadas con ceros para evitar que el proceso pueda leer la informa­
ción de las páginas contenidas en los marcos que le acaban de ser asignados.
•
Auditoría de seguridad. El administrador del sistema dispone de mecanismos para poder crear un
registro de eventos asociados con la seguridad del sistema.
Estructuras de datos utilizadas para implementar la seguridad
La implementación de la seguridad en Windows se basa principalmente en el uso de las siguientes
estructuras de datos:
•
Ficha de acceso (access token). Cuando un usuario se autentifica Windows asigna al primer pro­
ceso creado para el usuario, el proceso exp l orer . exe que implementa el escritorio, una ficha de
acceso que es heredada por todos los procesos que cree dicho proceso inicial debido a la interac­
ción del usuario con el escritorio.
Una ficha de acceso es una estructura que contiene, entre otros, los siguientes datos:
Identificador de seguridad del usuario al que pertenece el proceso. En Windows cada usuario
tiene asociado un identificador de seguridad (Security IDentifier, SID), que lo identifica de
forma univoca. El SID es un número binario largo parte del cual se genera aleatoriamente. El
SID de un proceso puede ser obtenido usando la función LookupAc count S i d.
- Identificador de seguridad del grupo de usuarios al que pertenece el proceso. Similar al SID
de usuario pero aplicado a nivel de grupo.
- Grupos. Especifica los grupos a los que pertenece el usuario. Este campo es necesario para
implementar la API POSIX.
- Lista de control de acceso discrecional. Es la lista de control de acceso asignada por defecto
a los objetos creados por el proceso.
Privilegios. Permiten proporcionar a un proceso permisos para realizar ciertas tareas reser­
vadas para el administrador, como por ejemplo apagar el computador o el acceso a ciertos
archivos.
El sistema operativo Windows
•
313
Descriptor de seguridad. En Windows cuando se crea un objeto se le asigna un descriptor de
seguridad que es una estructura de datos que especifica las operaciones que pueden realizar los
diferentes usuarios sobre el objeto. Contiene, entre otros, los siguientes datos: SID del usuario
propietario del objeto, SID del grupo propietario del objeto y un puntero a la lista de acceso
discrecional (Discretionary Access Control List, DACL) asociada al objeto. La DACL del objeto
contiene una o varias entradas. Cada entrada contiene un SID (de usuario o de grupo), el estado
asociado a dicha entrada: permitir o denegar, y el conjunto de operaciones seleccionadas sobre el
objeto.
El descriptor de seguridad de un objeto puede ser pasado como argumento de las llamadas al sistema
que producen la creación de dicho objeto. Por ejemplo la función CreateF i l e de la API Win32 que
produce la creación de un objeto archivo admite como argumento de entrada información que permite
configurar el descriptor de seguridad del archivo. Si no se suministra esta información entonces el sistema
utiliza para configurarlo la información contenida en la ficha de acceso del proceso que invoca la llamada.
También es posible usar diferentes funciones de la API Win32 para inicializar y configurar el descriptor
de seguridad de un objeto, como por ejemplo la función Ini t i a l i z e S ecuri tyDe s c r ip t o r .
Un hilo de un proceso para poder operar sobre un objeto ya creado debe primero abrirlo utilizan­
do alguna función de tipo Open. Por ejemplo para abrir un objeto archivo se debe invocar la función
OpenF i l e de la API Win32 pasándole como argumento el nombre del objeto y el conjunto de permisos
que necesita (lectura, escritura, etc). El monitor de referencia de seguridad del ejecutivo en primer lugar
consulta la ficha de acceso del proceso para determinar su SID. A continuación busca en las entradas
de la DACL del descriptor de seguridad del objeto una entrada que contenga dicho SID. Cuando la en­
cuentra comprueba si el proceso tiene concedidos todos los permisos que necesita. En caso afirmativo la
función devuelve al hilo un descriptor del objeto para que lo utilice en lugar del nombre del objeto en las
futuras funciones que operen sobre el objeto abierto.
8.3.
Implementación, control y planificación de procesos multihilos en
Windows
8.3.1.
Implementación de los procesos multihilos en Windows
Windows implementa un modelo de proceso multihilo con un hilo del núcleo por cada hilo de usuario.
Un proceso es considerado como la unidad de gestión de recursos mientras que un hilo del núcleo es
utilizado como la unidad de asignación del procesador. Todos los hilos de un proceso comparten los
recursos asociados a dicho proceso (espacio de memoria, tabla de descriptores, ficha de acceso, etc). Un
hilo se ejecuta en modo usuario hasta que invoca una llamada al sistema, entonces pasa a ser ejecutado
en modo núcleo. También existen hilos creados por el propio sistema operativo para realizar diferentes
tareas administrativas que únicamente se ejecutan en modo núcleo.
Windows utiliza varias estructuras de datos para implementar el modelo de proceso multihilo. Algu­
nas de estas estructuras son mantenidas en el espacio de direcciones virtuales del proceso, mientras que
314
Ampliación de sistemas operativos
Pila en modo
usuario
Pila en modo
usuario
¡------ - - - - - - - - - - - - -------------- ----------- ... ... ... ... .,
!1
•
PEB
------------
-
------------------
-
B loque
EPROCESS
;--
r-- -
·--
��
L ..
4 W32PROCESS
�
Tabla de
de s c r ip tores
----
L ....
TEB
- -- -
Bloque
KPROCESS
-
--
--------------- --
B loque
KTHREAD
-
-------
Bloque
- KTHREAD
Bloque
ETHREAD
B loque
ETHREAD
r-
-
TEB
!
Espacio de
direcciones
del proceso
Espacio de
direcciones
del núcleo
---
'
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _,
..
4
W32THREAD
Pila en modo
núcleo
•
-1
W32THREAD
Pila en modo
núcleo
Principales estructuras de datos mantenidas por Windows para un implementar un proceso
multihilo, en este caso de dos hilos
Figura 8.2 -
otras son mantenidas en el espacio de direcciones virtuales del núcleo. En las siguientes subsecciones se
describen las estructuras de datos asociadas a un proceso y las estructuras de datos asociadas a un hilo.
Estructuras de datos asociadas a un proceso
Windows para implementar un proceso mantiene, entre otras, las siguientes estructuras de datos (ver
Figura 8.2) :
•
Bloque de entorno del proceso (Process Environment Block, PEB). Estructura mantenida en el
espacio de direcciones del proceso que contiene, entre otros, los siguientes datos: lista de módulos
cargados (archivos . exe y . dl l ) , variables de entorno, directorio de trabaj o actual, e información
para gestionar el montículo del proceso.
•
Tabla de descriptores. Estructura de datos mantenida en el espacio de direcciones del núcleo que
contiene los descriptores de los obj etos abiertos (archivos, semáforos, etc) por el proceso.
El sistema operativo Windows
315
•
Bloque W32PROCESS . Estructura mantenida en el espacio de direcciones del núcleo que contiene
la información sobre el proceso a la que necesita acceder win3 2 k . sys . Este bloque es creado
la primera vez que un hilo del proceso invoca una llamada al sistema asociada con la GUI de
Windows.
•
Bloque KPROCES S , también denominado bloque de control del proceso (Process Control Block,
PCB). Estructura mantenida en el espacio de direcciones del núcleo que contiene los datos que
Windows necesita conocer para planificar los hilos del proceso, como por ejemplo: puntero al
directorio de páginas del proceso (ver sección 8 . 5 . 3), tiempo de ejecución en modo usuario y en
modo núcleo, procesador al que está asociado, prioridad base del proceso, cuanto asignado a un
hilo por defecto y punteros para mantener una lista de hilos del núcleo (bloques KTHREAD)
asociados al proceso.
•
Bloque EPROCESS . Estructura mantenida en el espacio de direcciones del núcleo que contiene,
entre otros, los siguientes datos relativos a un proceso: bloque KPROCESS , identificador del pro­
ceso, identificador del proceso padre, estatus de salida, fecha y hora de creación y terminación,
cuotas de uso de los recursos, información para la gestión de memoria del proceso, puntero a la
ficha de acceso, puntero a la tabla de descriptores, puntero al bloque PEB , nombre de ruta del
archivo ejecutable que contiene la imagen del proceso, clase de prioridad del proceso, puntero al
bloque W32PROCESS y puntero al objeto tarea. Señalar que una tarea Uob) en Windows es un
conjunto de procesos.
Estructuras de datos asociadas a un hilo
Windows para implementar un hilo mantiene, entre otras, las siguientes estructuras de datos (ver
Figura 8 .2):
•
Pila en modo usuario y pila en modo núcleo. Windows asigna a cada hilo de un proceso una pila
en modo usuario y una pila en modo núcleo. Un hilo utiliza su pila en modo usuario hasta que
invoca una llamada al sistema y comienza a ejecutarse en modo núcleo entonces utiliza su pila en
modo núcleo. Cuando un hilo realiza una llamada al sistema o cuando se bloquea a la espera de un
evento su contexto hardware se almacena en una estructura de datos CONTEXT que se almacena en
la pila del núcleo. El contexto hardware almacenado en la pila es restaurado para poder continuar
con la ejecución del hilo justo en el punto en el que fue interrumpida.
•
Bloque de entorno del hilo (Thread Environment B lock, TEB). Estructura mantenida en el espacio
de direcciones del proceso que contiene, entre otros, los siguientes datos: identificador del hilo,
información sobre la pila en modo usuario, y puntero al bloque PEB .
•
B loque KTHREAD. Estructura mantenida en el espacio de direcciones del núcleo que contiene los
datos que Windows necesita conocer para planificar y sincronizar la ejecución del hilo. También
mantiene un puntero a una estructura con información sobre la pila del núcleo del hilo y un puntero
al TEB del hilo.
316
Ampliación de sistemas operativos
•
B loque W32THREAD. Estructura mantenida en el espacio de direcciones del núcleo que contiene
la información sobre el hilo a la que necesita acceder win3 2 k sys . Este bloque es creado la pri­
mera vez que un hilo del proceso invoca una llamada al sistema asociada con la GUI de Windows.
.
•
8.3.2.
Bloque ETHREAD. Estructura mantenida en el espacio de direcciones del núcleo que contiene,
entre otros, los siguientes datos relativos a un hilo de un proceso: bloque KTHREAD, puntero al
bloque W32THREAD, hora y fecha de creación y terminación del hilo, identificador del proceso
al que pertenece el hilo, puntero al bloque EPROCESS de dicho proceso, y dirección de comienzo
de la rutina que implementa el hilo.
Control de procesos multihilos en Windows
Estados de un hilo
Un hilo en Windows durante su tiempo de vida puede encontrarse en algunos de los siguientes esta­
dos 8 (ver Figura 8.3):
•
Inicializado (initialized). Es el estado en que se encuentra un hilo mientras está siendo creado.
•
Preparado (ready). El hilo está a la espera de ser planificado para ejecución.
•
Ejecutándose (running). Solo puede existir un hilo en este estado por cada procesador disponible.
Un hilo entra en este estado cuando se está ejecutando en un procesador.
•
Suspendido (standby). Solo puede existir un hilo en este estado por cada procesador disponible.
Un hilo en el estado preparado pasa a este estado cuando es seleccionado por el planificador para
ser ejecutado en el procesador al que está vinculado a continuación del hilo que lo está utilizando
actualmente. Puede suceder que un hilo en el estado suspendido regrese al estado preparado sin
llegar a usar el procesador si el planificador selecciona a otro hilo más prioritario para que entre
en el estado suspendido.
•
Terminado (terminated). El hilo ha terminado su ejecución.
•
Esperando (waiting). Un hilo pasa a este estado cuando tiene que esperar por un determinado
suceso, por ejemplo que se complete una operación de E/S .
•
Transición (transition). Un hilo entra en este estado si al salir del estado esperando las páginas de
su pila del núcleo no están cargadas en la memoria principal. Cuando estas páginas sean cargadas
el hilo pasará al estado preparado.
8En realidad existen más estados de los aquí enumerados pero se ha preferido omitirlos para facilitar la comprensión del
diagrama de transición de estados.
El sistema operativo Windows
Se selecciona otro hilo
más prioritario
//
/Seleccionado
Pasa a ej ecutarse
Expropiado
Creación
317
Termina
Se produce
el evento pero
su pila del núcleo
no está cargada
en memoria
Figura 8.3
-
Diagrama de transición de estados de un hilo en Windows
Creación de procesos e hilos
Existen varias funciones en la API Win32 que permiten crear un proceso, aunque sin duda la más
conocida y utilizada es la función Cre a te Pro c e s s de la librería kerne l 3 2 . dl l . Esta función admite
hasta diez argumentos de entrada, entre ellos: el nombre del programa a ejecutar en el hilo o hilos del
nuevo proceso, un puntero a las variables de entorno, las prioridades de planificación, el directorio de
trabajo del nuevo proceso, y los indicadores para especificar los descriptores de obj etos que heredará el
nuevo proceso.
Una vez invocada una función CreatePro c e s s se realizan, entre otras, las siguientes acciones [Rus­
sinovich et al., 2009] :
l. Validar los argumentos de entrada y convertirlos al formato admitido por los argumentos de la
llamada al sistema NtCreateUserPro c e s s . A continuación invocar a esta llamada.
2. En modo núcleo la rutina de tratamiento del núcleo de esta llamada al sistema procesa los argu­
mentos, abre el archivo ejecutable que se desea ejecutar y crea un objeto sección (ver sección 8.5 .2)
para más tarde mapear el archivo dentro del espacio de direcciones virtuales del nuevo proceso.
3 . Crear un objeto proceso en el ejecutivo de Windows . La creación de este objeto requiere asignar
y configurar un bloque EPROCESS , crear la ficha de acceso inicial, crear la tabla de descripto-
318
Ampliación de sistemas operativos
res, crear el espacio de direcciones inicial del proceso (ver sección 8.5 .2), inicializar el bloque
KPROCESS, configurar el PEB y concluir la configuración del espacio de direcciones virtuales
del proceso, la cual entre otras acciones requiere mapear el archivo ejecutable dentro del espacio
del nuevo proceso.
4. Crear un objeto hilo inicial en el ejecutivo de Windows. La creación de este objeto requiere crear
e inicializar un bloque ETHREAD, crear la pila en modo usuario y en modo núcleo, configurar el
contexto hardware inicial, asignar y configurar el TEB del hilo, y configurar el bloque KTHREAD.
El nuevo hilo es puesto en el estado inicializado.
5 . Realizar una postinicialización especifica del subsistema de entorno de Windows. En este punto la
llamada al sistema NtCreateUserPro c e s s ha retornado a modo usuario y existe un nuevo pro­
ceso creado que consta de un único hilo. Sin embargo todavía es necesario realizar algunas tareas
adicionales relacionadas con el subsistema de entorno de Windows ( c s r s s . exe ) para comple­
tar la inicialización del proceso [Tanenbaum, 2009] : kerne l 3 2 . dl l en primer lugar envía un
mensaje a c s r s s . exe para comunicarle que un nuevo proceso ha sido creado y le adjunta los des­
criptores del objeto proceso y del obj eto hilo creados para que pueda duplicarlos. En segundo lugar
c s r s s . exe registra al proceso y su hilo en las tablas que mantiene con todos los procesos e hilos
Win32 existentes. En tercer lugar asigna e inicializa una estructura W3 2 PROCE S S y W3 2 THREAD.
Finalmente muestra en la pantalla un cursor con la forma de corona circular en movimiento para
indicarle al usuario que se está iniciando un programa pero que puede usar el cursor mientras tanto.
Si el proceso no realiza una llamada al sistema asociada con la GUI en los próximos segundos el
cursor vuelve a su forma habitual (una flecha). Si el proceso realiza una llamada al sistema asocia­
da con la GUI transcurrido un cierto tiempo se muestra una ventana y el cursor vuelve a su forma
original.
6. Comenzar la ejecución del hilo inicial. En este punto c s r s s . exe ha devuelto el control a la fun­
ción CreatePro c e s s que ahora invoca a la llamada al sistema NtResumeThread para pasar al
estado preparado al hilo inicial del nuevo proceso y que éste pueda ser planificado para ejecución.
Además devuelve al proceso padre los identificadores y descriptores del proceso e hilo recién crea­
dos. Si la creación se ha realizado con éxito entonces C r e a t e Proc e s s devuelve como valor de
retorno un valor distinto de cero, en caso de error devuelve cero.
Por otra parte un hilo de un proceso puede crear otro hilo dentro del mismo proceso invocando a la
función Creat eThread de la librería kerne l 3 2 . dl l . Las acciones que realiza esta función guardan
cierta analogía con las acciones anteriormente descritas para la función CreatePro c e s s pero aplica­
das a nivel de hilo. Si se desea crear un hilo dentro de un proceso distinto se puede usar la función
Creat eRemo t eThread.
Otras operaciones sobre procesos e hilos
Aparte de las funciones C r e a t e Pro c e s s y Creat eThread existen otras muchas funciones dispo­
nibles en la API Win32 para operar a nivel de procesos o de hilos, como por ejemplo:
El sistema operativo Windows
319
•
OpenPro c e s s . Abre un objeto proceso.
•
OpenThread. Abre un objeto hilo.
•
Exi tPro c e s s . Termina la ejecución de un proceso y todos sus hilos.
•
Exi tThread. Termina la ejecución de un hilo
•
Ge tCurrent Pro c e s s id. Devuelve el identificador del proceso actual.
•
GetCurrentThreadid. Devuelve el identificador del hilo actual.
•
GetExi tCodePro c e s s . Devuelve el estatus de salida de un proceso.
•
GetExi tCodeThr ead. Devuelve el estatus de salida de un hilo.
•
S l eep. Pone al hilo en el estado esperando durante un determinado periodo de tiempo expresado
en milisegundos que se debe introducir como argumento de entrada de la función.
•
Swi t chToThread. Cede el uso del procesador a otro hilo en el estado preparado.
8.3.3.
Planificación de procesos multihilos en Windows
Windows es un sistema operativo de núcleo expropiable que utiliza como unidad de planificación
a los hilos del núcleo. Windows implementa un algoritmo de planificación de tipo expropiativo basado
en múltiples colas de prioridad y realimentación. Se consideran 32 niveles de prioridad comprendidos
dentro del rango [0, 3 1 ] , siendo O la prioridad más baj a posible y 3 1 la más alta. Estos 32 niveles son
divididos en dos grupos (ver Figura 8 .4) :
•
Niveles de tiempo real. Comprende los 1 6 niveles más prioritarios, es decir, los niveles de prioridad
en el rango [ 1 6, 3 1 ] . Windows asigna estos niveles de prioridad a los hilos del núcleo asociados
a tareas críticas del sistema, como por ejemplo: la gestión de la memoria, la gestión de la caché,
etc. También un usuario con los privilegios adecuados puede hacer que un hilo de un proceso de
usuario se ejecute con un nivel de prioridad de tiempo real, aunque no es recomendable para no
interferir con las tareas del sistema. Un hilo con un nivel de prioridad de tiempo real nunca ve
modificada su prioridad durante su tiempo de vida, es decir, su prioridad se mantiene fija. Señalar
que realmente Windows no implementa las características típicas de una planificación de tiempo
real. El nombre de niveles de tiempo real se utiliza únicamente para indicar que los hilos con estos
niveles de prioridad se planifican preferentemente a los restantes niveles.
•
Niveles dinámicos. Comprende los niveles de prioridad en el rango [ 1 , 1 5 ] . En estos niveles se eje­
cutan la mayoría de los procesos de los usuarios. Un hilo con un nivel de prioridad dinámico puede
ver modificada su prioridad durante su tiempo de vida. Windows bajo determinadas circunstancias
puede incrementar durante un corto periodo de tiempo la prioridad de un hilo.
320
Ampliación de sistemas operativos
Prioridad más alta
31
�
Niveles de tiempo real
16
15
1
1
1
1
1
1
1
1
1
1
1
-
Niveles dinámicos
1
Prioridad más baj a
Figura 8.4 -
o
Nivel reservado
Niveles de prioridad definidos en Windows
El nivel de prioridad O está reservado por Windows para la ejecución del hilo de inicialización de pá­
ginas a cero (Zero page thread) (ver sección 8.5 .4). Existe una instancia de este hilo por cada procesador
existente en el computador.
Prioridad de un proceso y de un hilo
Cada proceso tiene asignado una prioridad denominada prioridad base del proceso Pbp que es fun­
ción de la clase de planificación a la que pertenezca el proceso. Se distinguen seis posibles clases de
planificación: tiempo real (real-time), alta (high), por encima de normal (above normal), normal, debajo
de normal (below normal) y ociosa (idle). La Pbp por defecto asociada a cada una de estas clases es : 24,
1 3 , 1 0, 8, 6 y 4, respectivamente. Algunos procesos del sistema tienen una Pbp ligeramente superior al
nivel por defecto. Por ejemplo el gestor de sesión tiene asociada una Pbp ligeramente superior al valor
por defecto (8) de la clase de planificación normal.
La clase de planificación, y en consecuencia la prioridad base de un proceso, es heredada por defecto
de su proceso padre. Para cambiar la clase de planificación de un proceso se puede usar por ejemplo la
función S e t P r i o r i tyC l as s .
Por s u parte, cada hilo tiene asociada dos prioridades:
•
Prioridad base del hilo Pbh · Esta prioridad es función de la clase de planificación a la que pertenece
el proceso al que está asociado el hilo y de la prioridad relativa del hilo Pr respecto a Pbp · La
prioridad relativa de un hilo puede tomar alguno de los siguientes valores : tiempo crítico (time
El sistema operativo Windows
321
critica!) P r = 1 5 , la más alta (highest) P r = 2, por encima de normal (above normal) P r = 1 ,
normal P r = O , debajo de normal (below normal) P r = - 1 , la más baja (lowest) Pr = - 2 y ociosa
(idle) P r = - 1 5.
Cuando la prioridad relativa de un hilo se configura al valor tiempo crítico ( P r = 1 5) entonces
Pbh se fij a al nivel de prioridad más alto dentro del grupo de niveles de prioridad en los que se
encuentre la Pbp de la clase de planificación a la que pertenece el proceso al que está asociado el
hilo. Luego si P r = 1 5 y el proceso al que está asociado el hilo pertenece a la clase de tiempo real
entonces Pbh = 3 1 . En el caso de que el proceso pertenezca a cualquiera de las restantes clases de
planificación entonces Pbh = 1 5 .
Por el contrario s i l a prioridad relativa de un hilo s e configura al valor ocioso (P r = - 1 5) entonces
la Pbh se fij a al nivel de prioridad más bajo dentro del grupo de niveles de prioridad en los que se
encuentre la Pbp de la clase de planificación a la que pertenece el proceso al que está asociado el
hilo. Luego si P r = - 1 5 y el proceso al que está asociado el hilo pertenece a la clase de tiempo real
entonces Pbh = 1 6. En el caso de que el proceso pertenezca a cualquiera de las restantes clases de
planificación entonces Pbh = l .
En el caso de que la prioridad relativa P r se configure con los valores: la más alta (P r = 2), por
encima de normal ( P r = 1 ) , normal (P r = 0), debajo de normal (P r = - 1 ) o la más baja ( P r = - 2 ),
entonces la prioridad base del hilo se calcula mediante la siguiente expresión:
Pbh
=
Pbp + P r
(8. 1 )
La funciones GetThreadPr i o r i ty y S e tThreadP r i o r i ty permiten obtener y configurar, res­
pectivamente, la prioridad relativa de un hilo.
•
e
Prioridad actual del hilo P a · Es la prioridad que utiliza el sistema operativo para decidir que hilo
se debe planificar en un procesador. Inicialmente Pa es igual a Pbh pero si el proceso al que perte­
nece el hilo pertenece a una clase distinta de la tiempo real el sistema operativo puede aumentar
temporalmente la Pa de un hilo dentro del rango [Pbh + 1 , 1 5] bajo determinadas circunstancias.
Ejemplo 8.1
Supóngase un proceso que consta de un hilo. El proceso tiene asociada la clase de planificación normal,
luego la prioridad base del proceso es por defecto Pbp = 8 . Supóngase además que la prioridad relativa
del hilo está configurada al valor P r = 2 (la más alta). En dicho caso la prioridad base del hilo será igual
a Pbh = Pbp + P r = 8 + 2 = 1 0 . Por su parte la prioridad actual del hilo tomará inicialmente el valor
P a = Pbh = 1 0. Posteriormente el sistema operativo puede elevar, bajo determinadas circunstancias,
temporalmente Pa a algún nivel de prioridad dentro del rango [ 1 1 , 1 5 ] .
•
Implementación y gestión de las colas de prioridad
Los hilos en el estado preparado de la misma prioridad se mantienen en una cola PIFO. Windows
mantiene un conjunto de 32 colas de hilos en el estado preparado por cada procesador existente en el
322
Ampliación de sistemas operativos
sistema. Además por cada conjunto mantiene una máscara de 32 bits denominada resumen de prepara­
dos (ready summary). A las estructuras de datos que mantiene Windows para implementar las colas de
planificación se les denomina base de datos del distribuidor (dispatcher database).
Cada bit j de un resumen de preparados está asociado a una cola j, si el bit j está activado significa
que la colaj no esta vacía. Windows examina el resumen de preparados para determinar la cola de mayor
prioridad no vacía, ya que siempre planifica para ejecutarse en un procesador al primer hilo de la cola de
prioridad más alta no vacía del conjunto de colas asociada a dicho procesador.
S i existen varios hilos en la cola de mayor prioridad entonces se aplica una algoritmo de tumo
rotatorio, es decir, cada hilo se ejecuta durante un cuanto a cuyo término pasa al final de la cola y
comienza a ejecutarse el siguiente hilo de la cola. Si solo existe un hilo en la cola de mayor prioridad,
dicho hilo va recibiendo los cuantos que vaya necesitando hasta completar su ejecución.
Si durante la ejecución de un hilo H l entra en el estado preparado un hilo de mayor prioridad H2
entonces se le expropia el procesador al hilo H l sin esperar a que termine su cuanto. H l es colocado al
principio de la cola y cuando sea planificado se ejecutará durante el tiempo de cuanto que le restaba por
ejecutar.
Sentido de análisis
Colas de hilos en el estado preparado
asociadas a la CPU 1
Prioridad
más alta
'-T-......_.-'
Resumen
de preparados
Cabecera cola
31
Cabecera cola
30
Cabecera cola
Cabecera cola
1
Prioridad
más baja
Figura 8.5 -
Windows
Cabecera cola
o
Posible estado de las colas de hilos preparados asociadas a un procesador en un sistema
El sistema operativo Windows
e
323
Ejemplo 8.2
Supóngase que el estado de las colas de hilos preparados asociadas al procesador CPU l de un sistema
Windows es el que se muestra en la Figura 8 . 5 . Se observa que no existe ningún hilo en la cola 3 1 ni en
la cola i. Por el contrario hay dos hilos en la cola 30, tres hilos en la cola 1 y un hilo en la cola O.
Para determinar cuál será el próximo hilo que va a ser planificado en CPU l Windows examina de iz­
quierda a derecha el resumen de preparados de las colas de hilos preparados de CPU l en busca de un
1 , es decir, busca la cola asociada al nivel de prioridad más alto que no esté vacía. Así, en primer lugar
examina el bit O, éste vale O ya que la cola 3 1 está vacía. A continuación examina el bit l . Como la cola
30 contiene dos hilos el bit 1 tiene el valor l . Luego se selecciona para ser planificado el hilo situado más
cerca de la cabecera de la cola 30.
•
Duración del cuanto
La duración de un cuanto depende del tipo de versión de Windows: cliente o servidor. En el caso de
una versión cliente el cuanto asignado a un hilo tiene una duración por defecto de 2 tics de reloj , mientras
que el caso de una versión servidor tiene una duración de 12 tics de reloj . La duración de un tic de reloj
depende de cada plataforma. En el caso de la arquitectura x86 un tic de reloj tiene una duración de 1 0
ms, luego l a duración d e u n cuanto e s de 20 m s e n e l caso de las versiones cliente de Windows y 1 20 ms
en el caso de las versiones servidor. Estos valores pueden ser incrementados por el administrador en un
factor de 2, 4 o 6, si así lo desea.
Windows también aumenta el cuanto del hilo asociada a la ventana que se pone en primer plano en
el escritorio de acuerdo con una cantidad especificada en el registro de Windows. Con esta medida se
pretende mejorar la interactividad con el usuario.
Estructura e invocación del planificador
El planificador de Windows, a diferencia de otros sistemas operativos, no es implementado con una
única rutina que se ejecuta dentro de un hilo especial del núcleo, sino mediante un conjunto de rutinas
denominadas de forma colectiva como distribuidor o despachador del núcleo (kernel's dispatcher). Estas
rutinas son invocadas durante la ejecución de un hilo en modo núcleo cuando se produce determinados
eventos, como por ejemplo:
•
Un hilo ha pasado al estado preparado, bien porque acaba de ser creado o porque se ha producido
el evento por el que estaba esperando, por ejemplo, que se completara una operación de E/ S .
•
U n hilo sale del estado ejecutándose porque h a terminado, h a consumido s u cuanto, cede e l uso
del procesador a otro hilo o se bloquea en espera de que se produzca un evento (entra en el estado
esperando).
•
La prioridad de un hilo es cambiada por una llamada al sistema o por el propio distribuidor del
núcleo.
324
Ampliación de sistemas operativos
•
Se cambia mediante una llamada al sistema, como por ejemplo S e tTheadAf f i n i tyMa s k, el
procesador en que debe ejecutarse un hilo. Por defecto un hilo puede ejecutarse en cualquiera de
los procesadores existentes en la máquina, pero Windows permite asociar la ejecución de un hilo
a un determinado procesador, es lo que se conoce como afinidad del procesador.
Aumento temporal de la prioridad actual de un hilo
B ajo determinadas circunstancias Windows puede aumentar temporalmente la prioridad actual Pa de
un hilo perteneciente a una clase de planificación distinta de la de tiempo real que acaba de salir del estado
esperando o que lleva mucho tiempo en el estado preparado y todavía no ha accedido al procesador. El
objetivo de este aumento de la prioridad es compensar al hilo por el tiempo que ha perdido esperando.
Al aumentar su prioridad tendrá más probabilidades de ser elegido para ser planificado.
Inicialmente la prioridad actual de un hilo es igual a su prioridad base, es decir, Pa = Phh · B aj o
determinadas circunstancias la prioridad actual s e aumenta a u n valor Phh + x comprendido dentro del
rango [Pbh + 1 , 1 5 ] . Este aumento de la prioridad actual es temporal, ya que cada vez que el hilo consume
un cuanto su prioridad actual se decrementa en una unidad, es decir, Phh + x - l. La prioridad actual dej a
de decrementarse cuando alcanza e l valor d e l a prioridad base del hilo, e s decir, Pa = Phh ·
E l valor del incremento x d e l a prioridad base de un hilo e s fijado por el sistema operativo e n función
de las circunstancias por las que el hilo pasó al estado esperando o si lleva demasiado tiempo en el estado
esperando. Entre las circunstancias que producen un aumento de la prioridad de un hilo se encuentran
las siguientes:
•
Cuando se completa una operación de E/S, se despiertan a los hilos que estaban esperando por
dicha operación, el incremento x de prioridad actual que reciben dependen del dispositivo de E/S
en el que se ha realizado la operación. Si se trata de un disco duro, un CD-ROM, un puerto paralelo
o una tarj eta de vídeo, entonces x = l. Si se trata de una operación de red entonces x = 2. Si se
trata del teclado o del ratón entonces x = 6. Finalmente si se trata de una tarj eta de sonido entonces
X = 8.
•
Cuando se despierta a un hilo que estaba esperando por un mecanismo de sincronización (ver
sección 8 .4.2) como por ejemplo un semáforo o un evento, entonces x = 2 si pertenece al proceso
que se encuentra en primer plano (foreground). En caso contrario x = l.
•
Cuando se despierta a un hilo asociado a una ventana de la GUI su prioridad se incrementa en
x = 2 con el fin de mej orar la interactividad con el usuario.
•
Si un hilo lleva en el estado preparado durante más de 4 segundos entonces configura la prioridad
actual del hilo a su máximo valor posible, es decir, Pa = 1 5 y puede ejecutarse durante cuatro
cuantos consecutivos al término de los cuales su prioridad actual se configura a su valor base
Pa = Phh · Con esta medida se pretende evitar el abandono de hilos.
El sistema operativo Windows
e
325
Ejemplo 8.3
Supóngase un hilo cuya prioridad base es Pbh = Pbp + Pr = 8 + 2 = 10. Inicialmente su prioridad actual
es Pa = 1 0. Si el hilo pasa al estado esperando en espera de que se complete una operación de E/S en
la red entonces cuando se complete la operación su prioridad actual se incrementará en x = 2 unidades,
es decir, Pa = Pbh + 2 = 10 + 2 = 12. Cuando complete un cuanto su prioridad se reducirá a Pa = 1 1 y
cuando complete un segundo cuanto su prioridad se reducirá a Pa = 1 0. Es decir, al cabo de dos cuantos
recupera su valor de prioridad actual inicial.
•
8.4.
Sincronización y comunicación entre procesos multihilos en Windows
8.4.1.
Mecanismos de sincronización usados por el sistema operativo
Windows es un sistema operativo de código reentrante que soporta multiprogramación y multiproce­
samiento simétrico. Para garantizar la exclusión mutua en el uso de las secciones críticas del código del
sistema operativo se utilizan diferentes mecanismos de sincronización, siendo los spinlocks (ver sección
3 . 3) uno de los más utilizados.
Las rutinas básicas para la manipulación de un spinlock son:
•
KeAc qu i r e SpinLock ( ) . Para adquirir (cerrar) el spinlock.
•
KeRe l ea s e SpinLo c k ( ) . Para liberar (abrir) el spinlock.
Estas rutinas son implementadas en el kernel de Windows y pueden ser invocadas por los componen­
tes de Windows que se ejecutan en modo núcleo.
8.4.2.
Mecanismos de sincronización entre procesos multihilos disponibles en Windows
Objetos del distribuidor
Otros mecanismos de sincronización disponibles en Windows son los semáforos, los semáforos bina­
rios o mutexes, y los eventos. Estos mecanismos pueden ser utilizados tanto por los propios componentes
de Windows como por los hilos de los procesos de los usuarios. Se implementan mediante objetos del
núcleo que disponen de capacidades de sincronización: objeto semáforo, objeto mutex, objeto evento,
etc. A estos objetos se les denomina de forma general como objetos del distribuidor ya que su uso puede
alterar o afectar a la planificación del hilo que se sincroniza con el obj eto.
Un objeto del distribuidor puede encontrarse en dos posibles estados: estado no señalado y estado
señalado. El estado inicial de un objeto se configura cuando es creado. Un obj eto del distribuidor se
encuentra en el estado no señalado hasta que se produce un determinado suceso que hace que pase al
estado señalado. Cuando el objeto pasa al estado señalado el sistema operativo realiza unas determinadas
acciones, que generalmente consisten en despertar a uno o varios hilos que estaban esperando por el
objeto. Una vez realizadas dichas acciones, el objeto puede retomar o no al estado no señalado. Tanto el
326
Ampliación de sistemas operativos
suceso que produce el cambio de estado del objeto como las acciones que realiza el sistema operativo
dependen de cada tipo de obj eto.
Por ejemplo, en un objeto semáforo binario o mutex cuando un hilo libera el semáforo el objeto pasa
al estado señalado. Entonces el núcleo desbloquea a uno de los hilos que se encontraban en el estado
esperando dentro de la cola del semáforo para que continúe su ejecución y devuelve al objeto al estado
no señalado.
Un hilo puede sincronizarse con un objeto del distribuidor, para ello debe invocar a alguna de las
funciones de la API Win329 pasándole como argumento el descriptor del objeto por el que desea esperar.
Por ejemplo se podría utilizar la función wa i tForS ingl eObj e c t . También se podría utilizar la función
Wa i tF o rMu l t ip l eübj e c t s si el hilo desea esperar por varios obj etos.
Cuando se atiende la llamada, el hilo pasa al estado esperando y se añade a la cola de hilos esperando
por un determinado objeto. Cuando se produzca el suceso asociado al objeto por el que espera el hilo
entonces éste será despertado. También es posible pasar como argumento de entrada de la función un
indicador para especificar que la espera debe ser cancelada si se sobrepasa una determinada cantidad de
tiempo.
Semáforos generales y binarios
Un objeto semáforo general o semáforo con contador se crea con la función Crea t e s emaphor e .
Además esta función también permite inicializarlo y fijar s u valor máximo. L a operaciones s i gna l_s em
(operación V) y wa i t_s em (operación P) se implementan con las funciones Re l ea s e S emaphore y
Wa i tForS ingl eObj e c t , respectivamente.
En el caso de un objeto semáforo binario o mutex, su creación e inicialización se realiza con la fun­
ción CreateMut ex. Mientras que las operaciones básicas s i gnal_s em y wai t_s em se implementan
con las funciones Re l ea s eMut ex y Wa i tForS ingl eObj e c t , respectivamente.
Eventos
Un objeto evento se crea con la función Creat eEvent . Esta función también permite especificar
su estado inicial: señalado o no señalado. Si la función se ejecuta con éxito devuelve el descriptor del
obj eto.
Un hilo puede esperar por un objeto evento determinado invocando a Wa i tForS ingl eObj e c t pa­
sándole como argumento el descriptor del objeto. Otro hilo para avisar que el evento se ha producido
debe invocar a S e tEvent . Las acciones que realiza esta función dependen del tipo de evento. Si se trata
de un evento de notificación entonces se desbloquean a todos los hilos que estaban esperando por el
evento y el evento permanece en el estado señalado hasta que un hilo invoca a una función Re s e tEvent
sobre el evento. En el caso de un evento de sincronización se despierta a un hilo de los que estaban
esperando por el evento y el evento es configurado al estado señalado.
9En el caso de un componente de Windows en modo núcleo éste invocaría directamente a la llamada al sistema correspon­
diente sin necesidad de usar la función de la API Win32.
El sistema operativo Windows
327
Si se invoca a la función S e t Event y no existe ningún hilo esperando en el evento entonces sim­
plemente se cambia el estado del evento a señalado. De esta forma si un hilo invoca a una función
Wa i tForS ingl eObj e c t no tendrá que esperar por el evento porque ya se habrá producido.
La función Pu l s eEvent es similar a S e t Event con la diferencia de que si no existe ningún proceso
esperando entonces el evento se pierde ya que el evento no se pone en el estado señalado.
8.4.3.
Mecanismos de comunicación entre procesos multihilos disponibles en Windows
Windows implementa diversos mecanismos de comunicación entre procesos multihilos, entre ellos :
tuberías, conectores, mailslots, llamadas a procedimientos remotos y objetos compartidos. En las si­
guientes subsecciones se describen estos mecanismos.
Tuberías
El funcionamiento de las tuberías implementadas en Windows es similar al estudiado en los SOBU­
NIX. La principal novedad de la implementación de las tuberías en Windows es que existen dos modos
de funcionamiento:
•
Modo byte. Por la tubería se transmite un fluj o no estructurado de datos (bytes) con un tamaño
máximo fijo. Este modo coincide con la implementación de las tuberías en los SOBUNIX.
•
Modo mensaje. Por la tubería se transmite un fluj o de bytes estructurado en mensaj es de un cierto
tamaño. Por ejemplo un flujo de bytes de 256 bytes puede estructurarse en dos mensaj es de 1 28
bytes cada uno.
Las tuberías sin nombre se crean con la función C r e a t e P i p e . Para leer o escribir en ellas se deben
usar las funciones ReadF i l e y wr i t eF i l e , respectivamente.
En el caso de las tuberías con nombre se crean mediante la función CreateNamedP ipe. Para
conectarse a una tubería con nombre el proceso cliente debe utilizar las funciones C r e a t eF i l e o
Cal lNamedP ipe.
Cuando un hilo deja de usar una tubería debe usar la función C l o s eHand l e para liberar los recursos
que utiliza.
Conectores
Los conectores (sockets) se crean usando la función s o c k e t . Si un hilo desea conectarse a un conec­
tor ya creado debe usar la función C onne c t . Una vez conectado si desea enviar información debe usar
la función S end, mientras que para recibir información debe usar la función Recv. Cuando se termina
de usar un conector debe cerrarlo utilizando la función C l o s e S o c k e t .
328
Ampliación de sistemas operativos
Mailslots
Los mailslots son un mecanismo de comunicación unidireccional entre procesos multihilos importa­
do del sistema operativo OS/2. Se puede utilizar tanto localmente dentro de una misma máquina como
para comunicaciones en red, aunque no operan en redes de área ancha como Internet. Los mailslots
permiten enviar un mismo mensaj e a múltiples receptores. Sus principales inconvenientes es que son
unidireccionales y que no generan de forma explicita un mensaje de confirmación de recepción del en­
vío.
Un hilo puede crear un mailslot usando la función CreateMa i l s l o t la cual devuelve un descriptor
del objeto mailslot creado. Una vez creado, otros hilos si conocen el descriptor del mailslot pueden
escribir mensajes en el mailslot usando la función Wr i t e F i l e . El propietario del mailslot puede leer los
mensajes usando la función ReadF i l e . Cuando un hilo dej a de usar un mailslot debe usar la función
C l o s eHand l e para liberar los recursos que utiliza.
Llamadas a procedimientos remotos
Las llamadas a procedimientos remotos (Remote Procedure Calls, RPCs) son un mecanismo de
comunicación entre procesos que permite a un proceso A invocar a un procedimiento implementado
en otro proceso B de la misma máquina local o de una máquina remota. El proceso B ejecuta dicho
procedimiento y devuelve el resultado al proceso A. Este mecanismo se suele implementar mediante
paso de mensaj es de acuerdo a una estructura del tipo cliente-servidor.
La capa de transporte de mensajes puede implementarse mediante conectores TCP/IP, tuberías con
nombre o llamadas a procedimientos remotos avanzados (Advanced Local Procedure Calls, ALPCs).
Las ALPCs son un mecanismo de comunicación entre procesos usado internamente por Windows que
permite el paso de mensaj es a alta velocidad. Las ALPCS se implementan en el ejecutivo de Windows.
Objetos compartidos
Algunos objetos de Windows pueden ser compartidos por varios procesos. Este es el caso de un
objeto sección que permite mapear un archivo dentro del espacio de direcciones virtuales de cada uno de
los procesos que comparten el obj eto. Los cambios que realice un proceso sobre el archivo asociado al
objeto sección dentro de su espacio de direcciones serán visibles para todos los procesos que comparten
el objeto.
8.5.
Gestión de memoria en Windows
8.5.1.
Administrador de memoria
Windows utiliza la técnica de demanda de página para administrar la memoria principal. Todas las
tareas relativas a la administración de memoria son realizadas por el administrador de memoria que es
uno de los servicios que ocupa una mayor parte del código del ejecutivo de Windows, lo que da idea de
la complejidad del mismo.
El sistema operativo Windows
329
El administrador de memoria se implementa como un conjunto de rutinas que pueden ser invocadas
dentro del contexto de los hilos de los procesos. Además también utiliza para su implementación los
siguientes hilos del sistema:
•
Gestor de configuración del equilibrio. Se encarga de invocar periódicamente o si se cumplen
determinadas circunstancias a otros hilos asociados al administrador de memoria.
•
Gestor de los conjuntos de trabajo. Se encarga de implementar las políticas generales de gestión
de memoria: reemplazamiento de páginas, gestión de los conjuntos de trabajo, envejecimiento de
páginas, etc. Es invocado por el gestor de configuración del equilibrio una vez por segundo o si la
memoria libre disminuye por debajo de un determinado límite.
•
lntercambiador de pilas de procesos o hilos. Se encarga de realizar el intercambio de procesos e
hilos dentro y fuera de la memoria principal. Este hilo es despertado por el gestor de configuración
del equilibrio o por el planificador cuando hay que realizar una operación de intercambio.
•
Escritor de páginas modificadas. Se encarga de escribir páginas modificadas en los archivos de pá­
ginas (ver sección 8 . 5 .5). Este hilo es despertado cuando el tamaño de la lista de hilos modificados
excede un determinado límite.
•
Escritor de páginas mapeadas. Se encarga de escribir páginas modificadas en los archivos que
mapean dichas páginas. Este hilo es despertado cuando el tamaño de la lista de hilos modificados
excede un determinado límite o si las páginas de un archivo han estado en esta lista durante más
de cinco minutos.
•
Hilo de puesta de páginas a cero. Se encarga de inicializar con ceros las páginas de la lista de
marcos libres y pasarlos a la lista de marcos inicializados a cero (ver sección 8.5 .4).
•
Hilo de segmento dereferenciado. Se encarga de la reducción de la caché del sistema, así como del
aumento o la disminución de tamaño de los archivos de páginas.
El administrador de memoria de Windows utiliza diferentes algoritmos y reglas heurísticas para
realizar sus tareas. Señalar que estos algoritmos y reglas no han sido hechos públicos por Microsoft.
8.5.2.
Gestión de la memoria virtual
En Windows cada proceso tiene su propio espacio de direcciones virtuales. Un proceso ejecutándose
en modo usuario únicamente puede acceder a su espacio de direcciones de usuario. Las modificaciones
que un proceso realice en su espacio no son visibles al resto de procesos salvo que las realice en una
región de memoria compartida. Por otra parte, cuando el proceso se ejecuta en modo núcleo, como por
ejemplo cuando atiende una llamada al sistema, puede acceder a todo el espacio de direcciones virtuales,
tanto al del usuario como al del sistema operativo. Conviene recordar que cuando un proceso se ejecuta
en modo núcleo en realidad se está ejecutando el sistema operativo pero en el nombre del proceso.
330
Ampliación de sistemas operativos
OxFFFFFFFF
Espacio
de
direcciones
virtuales
del sistema
operativo
O x8 0 0 0 0 0 0 0
Ox7 FFEFFFF
Reservada (64 KiB)
Espacio
de
direcciones
virtuales
del usuario
O xO O O l O O O O
OxO O O O O O O O
2 GiB
2 GiB
Reservada (64 KiB)
-
Estructura más habitual del espacio de direcciones virtuales utilizado por Windows en
arquitecturas Intel x86 de 32 bits
Figura 8.6
En Windows, al igual que en otros sistemas operativos, el tamaño y la distribución del espacio de
direcciones virtuales dependen de cada arquitectura. En la arquitectura Intel x86 de 32 bits el espacio de
direcciones virtuales tiene un tamaño máximo de 232 = 4 GiB . Windows divide este espacio en cuatro
zonas (ver Figura 8.6):
•
Espacio reservado para la captura de punteros nulos. Esta zona no es accesible por los procesos.
Tiene un tamaño de 64 KiB .
•
Espacio de direcciones del usuario. Contiene las regiones de un proceso: código, datos, montículo,
pilas de los hilos, regiones de memoria compartida y archivos mapeados en memoria. Tiene un
tamaño próximo a los 2 GiB .
•
Espacio reservado para la captura de punteros erróneos. Esta zona no es accesible por los proce­
sos. Tiene un tamaño de 64 KiB .
•
Espacio de direcciones del sistema operativo. Contiene el código y los datos de los distintos com­
ponentes del sistema operativo: HAL, ejecutivo, núcleo, drivers, etc. También contiene las tablas
El sistema operativo Windows
331
de páginas de los procesos, la caché del sistema y la reserva de memoria paginada y no paginada.
Tiene un tamaño de 2 GiB .
En esta arquitectura Windows también puede trabaj ar con un espacio de direcciones de usuario de
casi 3 GiB con lo que el espacio de direcciones del sistema operativo queda reducido a 1 GiB .
Obviamente, en las arquitecturas de 64 bits el espacio de direcciones de usuario puede ser mucho
más grande. Por ejemplo en la arquitectura AMD x64 los procesos de 32 bits pueden tener un espacio de
direcciones de usuario de casi 4 GiB . Mientras que los procesos de 64 bits pueden tener un espacio de
usuario de 8 TiB . En esta arquitectura el espacio de direcciones del sistema operativo también tiene un
tamaño de 8 TiB .
En la técnica de demanda de página el espacio de direcciones virtuales se divide en páginas cuyo
tamaño depende de la arquitectura y del sistema operativo. Windows en las arquitecturas Intel x86 y
AMD x64 suele trabaj ar con un tamaño de página de 4 KiB , aunque en determinadas circunstancias
también trabaj a con páginas grandes de 4 MiB para mejorar el rendimiento del sistema. En Windows una
página i del espacio de direcciones virtuales puede encontrarse en tres posibles estados :
•
Libre. L a página n o está siendo utilizada actualmente. Cualquier referencia a una dirección virtual
asociada a una página libre produce un fallo de página por referencia a una dirección ilegal. A este
tipo de fallos de página en Windows se les denomina violación de acceso.
•
Asignada (committed). La página está asociada a una determinada información (código, datos,
etc).
•
Reservada. Son páginas libres que se reservan para contener una determinada información. Por
ejemplo, cuando se crea la pila de usuario de un nuevo hilo se reservan varias páginas virtuales
libres contiguas en el espacio de direcciones del proceso para su implementación. De las páginas
reservadas para la pila inicialmente solo una de ellas pasa al estado asignada.
Estructuras de datos para implementar el espacio de direcciones virtuales de un proceso
El administrador de memoria de Windows cuando se crea un proceso asigna a cada región existen­
te en el espacio de direcciones virtuales de un proceso un descriptor de direcciones virtuales (Virtual
Address Descriptor, VAD) que es una estructura que contiene, entre otros, los siguientes datos:
•
Rango de direcciones virtuales reservado para la región.
•
Objeto sección. Es un obj eto del núcleo que establece la correspondencia con el almacenamiento
de respaldo de las páginas de la región en memoria secundaria (ver sección 8 . 5 .5). Este objeto
permite mapear un archivo dentro de una región del espacio de direcciones virtuales.
•
Tipo de región. La región puede ser privada para uso exclusivo para el proceso o compartida por
varios procesos .
•
Protección : solo lectura, lectura y escritura, y copiar a l escribir.
332
Ampliación de sistemas operativos
Para encontrar más rápidamente el VAD que contiene una determinada dirección virtual, todos los
VADs del espacio de direcciones de un mismo proceso son organizados en un árbol AVL.
Funciones de la API Wln32 para la gestión del espacio de direcciones virtual de un proceso
Existen diferentes funciones en la API Win32 que permiten operar sobre el espacio de direcciones
virtuales de un proceso, entre las más utilizadas se encuentran las siguientes:
•
Vi rtualAl l o c . Permite reservar o asignar una cierta región en el espacio de direcciones virtuales
de un proceso.
•
V i r tua l Fre e . Permite liberar, desasignar, o liberar y desasignar una cierta región en el espacio
de direcciones virtuales de un proceso.
•
Vi r tua l Pro t e c t . Permite cambiar los permisos de una región.
•
Vi r tua l Query. Devuelve información sobre el estado de una cierta región.
•
CreateF i l eMapp ing. Crea una objeto de archivo mapeado, que es otra forma de denominar a
un objeto sección.
•
Op enF i l eMapp ing. Abre un archivo de objeto de archivo mapeado previamente creado.
•
MapVi ewO f F i l e . Mapea parcial o totalmente un archivo en el espacio de direcciones de un pro­
ceso.
•
8.5.3.
unrnapVi ewO f F i l e . Elimina un archivo mapeado del espacio de direcciones de un proceso.
Traducción de direcciones
Windows soporta tablas de páginas paginadas de diferentes niveles. El número de niveles de pagi­
nación utilizados depende de la arquitectura hardware. Por ejemplo, en el caso de la arquitectura Intel
x86 de 32 bits Windows utiliza por defecto dos niveles de paginación. Aunque si se trabaj a en dicha
arquitectura con el modo de extensión de dirección física (Physical Address Extension, PAE) entonces
utiliza tres niveles. También en la arquitectura Intel IA-64 utiliza tres niveles de paginación. En el caso
de la arquitectura AMD x64 utiliza cuatro niveles de paginación.
e
Ejemplo 8.4
En la arquitectura Intel x86 las direcciones virtuales tienen un tamaño de 32 bits. Windows considera
que las direcciones virtuales se descomponen en tres campos (ver Figura 8.7):
•
Índice del directorio de páginas (IDP). Tiene un tamaño de 10 bits. Contiene el índice de la entrada
de la tabla de páginas de primer nivel, también denominado directorio de páginas, donde hay que
buscar el número del marco de memoria que contiene a la página que ubica a la tabla de páginas
de segundo nivel que es una tabla de páginas ordinaria.
El sistema operativo Windows
333
N° de página i
�
-------------...,
-------------
Indice directorio
de páginas (IDP)
Indice tabla
de páginas (ITP)
Desplazamiento
1 0 bits
1 0 bits
1 2 bits
Figura 8.7 -
Formato de una dirección virtual en la arquitectura x86
•
Índice de la tabla de páginas (ITP). Tiene un tamaño de 10 bits (o 9 bits si el modo PAE esta
activado) Contiene el índice de la entrada de la tabla de páginas donde hay que buscar el número
del marco de memoria que contiene a la página que ha sido referenciada.
•
Desplazamiento. Tiene un tamaño de 12 bits. Especifica el desplazamiento desde el comienzo de
la página.
Cada proceso tiene un único directorio de páginas con tantas entradas como tablas de página se requieran
para describir el espacio de direcciones virtuales del proceso. La dirección física de comienzo Dirpo del
directorio de páginas de un proceso se almacena en el bloque KPROCESS asociado al proceso. Cuando
el proceso es planificado para ejecución el registro CR3 se carga con la Dirro del directorio de páginas
del proceso.
Señalar que como el campo IDP tiene un tamaño de 10 bits entonces el número de entradas máximo que
puede tener el directorio de páginas de un proceso es 2 10 = 1 024 entradas. Windows utiliza 4 bytes para
representar a una entrada de un directorio de páginas. Luego el tamaño máximo del directorio de páginas
de un proceso es de 4 KiB .
Cada entrada de un directorio de páginas contiene la localización y el estado de una de las tablas de
páginas del proceso. Las tablas de páginas se van creando según se van necesitando por ello el número
de entradas del directorio de páginas de un proceso no suele ser muy alto.
Asimismo puesto que el campo ITP tiene un tamaño de 1 0 bits entonces el número de entradas máximo
que puede tener una tabla de páginas es también de 1 024 entradas. Tanto Windows como el hardware uti­
lizan 5 bytes para representar una entrada de una tabla de páginas, luego el tamaño máximo de una tabla
de páginas es de 32 KiB . Señalar que en una entrada de una tabla de páginas el tamaño del campo número
de marco de página es de 20 bits, luego como máximo la memoria principal se puede descomponer en
220 marcos.
Cuando el procesador referencia a una dirección virtual la traducción de dicha dirección a una dirección
física se realiza siguiendo los siguientes pasos (ver Figura 8 . 8) :
l . Se suma IDP a l a dirección Dirpo contenida e n e l registro CR3 para construir la dirección física
Dirp 1 de la entrada del directorio de páginas donde hay que buscar el número k del marco de
memoria que contiene a la página que ubica a la tabla de páginas.
334
Ampliación de sistemas operativos
2. Se accede a Dirp¡ para leer dicho número de marco k y se le suma a ITP para construir la dirección
física Dirp2 de la entrada de la tabla de páginas donde hay que buscar el número j del marco de
memoria que contiene a la página i referenciada en la dirección virtual.
3. Si la entrada está marcada como válida se accede a la memoria principal para leer el número de
marco j y poder construir la dirección física Dirp3 a la que equivale la dirección virtual referenciada
por el procesador. En caso contrario se produciría un fallo de página.
•
La traducción de una dirección virtual en una dirección física solo se realiza si referencia a una pá­
gina válida y el tipo de acceso que se pretende realizar está permitido por la protección de la página.
En caso contrario se produce un fallo de página que es atendido por el manipulador de fallos de página
de Windows (MrnAc c e s s Fau l t ( ) ) que es una rutina que se ejecuta en el contexto del hilo cuya ejecuDirección virtual
�
N° de página i
1 IDP 1
+
ITP
1
Desplazamiento
J
1
Marco j
1
•
......
DirFo
J
1
Desplazamiento
_./
Dirección Física
Registro CR3
DirFo
Directorio
de páginas
�
Marco k
ll'f ¡
}
DP
�(+
�
D1rF2
Marco k
Tabla de páginas
Marco}
I
ITP
r--
Marco}
�
DirF3
Página i
t
Desp.
'
Memoria Principal
Figura 8.8 - Traducción
Memoria Principal
Memoria Principal
de una direcciones virtual válida a direcciones físicas en la arquitectura x86
El sistema operativo Windows
335
ción produjo el fallo de página. A los fallos de página que no requieren leer la página en disco se les
denominan fallos de página suaves. En caso contrario se les denominan fallos de página duros.
Con objeto de reducir el número de fallos de página duros que produce la ejecución de un proceso,
Windows almacena la secuencia de páginas referenciadas por dicho proceso utilizando una tecnología
denominada SuperFetch. Cuando dicho proceso vuelve a ser iniciado el administrador de memoria realiza
una prepaginación de las páginas del proceso de acuerdo con la secuencia de páginas referenciadas
guardada para dicho proceso. Dichas páginas son cargadas en la lista de marcos de página en standby de
memoria principal (ver sección 8.5 .4) de tal forma que las referencias a estas páginas producen fallos de
página suaves.
8.5.4.
Gestión de la memoria física
Conjunto de trabajo
Para gestionar la memoria física Windows utiliza el concepto de conjunto de trabajo de un proceso
el cual queda definido por las páginas pertenecientes al proceso cargadas en memoria, las cuales pueden
ser referenciadas sin producir un fallo de página. El tamaño y la composición del conj unto de trabajo de
un proceso varían durante el tiempo de vida del proceso.
Windows fija un límite inferior y un límite superior para el tamaño del conjunto de trabajo de un
proceso. Cuando se inicia la ejecución de un proceso el límite inferior se configura a un valor de entre 20
y 50 páginas. Mientras que el límite superior se configura a un valor comprendido entre 45 y 345 páginas.
Estos valores iniciales dependen de la memoria física total existente, además pueden ser configurados
por el administrador del sistema.
Cuando existe suficientemente memoria libre Windows permite que un proceso pueda superar su
límite máximo. Sin embargo cuando la memoria principal libre comienza a escasear Windows comienza
a reducir el tamaño de los conjuntos de trabajo de los procesos que han superado su límite máximo.
Si con esta medida la memoria libre sigue siendo escasa entonces comienza a reducir el tamaño de los
conjuntos de trabaj o de todos procesos.
La gestión de los conjuntos de trabajo de los procesos es realizada por el gestor de los conjuntos de
trabajo que es invocado por el gestor de configuración del equilibrio una vez por segundo o si la memoria
libre disminuye por debajo de un determinado límite.
Base de datos de los números de marcos de página
La base de datos de los números de marco de página es una tabla que el administrador de memoria
de Windows mantiene para describir el estado de cada marco de página de la memoria principal. Un
marco de página puede encontrarse en alguno de los siguientes estados [Russinovich et al. , 2009] :
•
Activo o válido. El marco contiene una página que pertenece al conjunto de trabaj o de uno o varios
procesos o al conjunto de trabajo del sistema operativo.
•
Transición. Se trata de un estado temporal para un marco que contiene una página que no pertenece
al conjunto de trabaj o de un proceso ni a ninguna de las listas de páginas. Un marco se encuentra
336
Ampliación de sistemas operativos
en este estado cuando está asignado a una página sobre la que se está realizando una operación de
E/S.
•
Standby. El marco contiene una página que ha sido eliminada del conjunto de trabajo de un proceso
o ha sido prepaginada. Dicha página no ha sido modificada desde su última escritura en el disco.
•
Modificado. El marco contiene una página que ha sido eliminada del conjunto de trabajo de un
proceso y cuyo contenido ha sido modificado y debe ser escrita en el almacenamiento de respaldo.
•
Libre. El marco está libre y contiene una página con datos.
•
Inicializado a O. El marco está libre y contiene una página llena de ceros.
•
Rom. El marco contiene una página que representa a la memoria ROM.
•
Malo (bad). El marco contiene una página que ha generado un error de paridad, u otro error hard­
ware, y no puede ser utilizada. También se utiliza internamente para representar a las páginas del
sistema operativo que se encuentran en transición entre un estado y otro.
La base de datos de los números de marco de página tiene una entrada por cada marco de página en
que se descompone la memoria principal. La tabla está indexada por el número de marco de página j.
Cada entrada se implementa como una estructura de datos de tamaño fijo cuyo formato puede variar en
función de si la página contenida en el marco es compartida o privada. En cada entrada se almacenan,
entre otros, los siguientes datos: estado del marco, contador del número de entradas de tablas de página
que referencian al marco, y un puntero a la entrada de la tablas de páginas ordinarias (si es una página
privada) o prototipo (si es una página compartida) que apunta al marco.
Una tabla de página prototipo es una variante de una tabla de páginas ordinarias que Windows
utiliza para almacenar la información necesaria para traducir las referencias a una determinada región
de memoria compartida. Las entradas de las tablas de páginas que hacen referencia a una determinada
página de una región de memoria compartida poseen un puntero a la entrada adecuada de la tabla de
páginas prototipo asociada a la región de memoria compartida correspondiente.
e
Ejemplo 8.5
En la Figura 8.9 se muestra a modo de ejemplo un posible estado de las entradas k = 35 a k = 42 de la
base de datos de los números de marcos de página. La entrada k = 35 de la base de datos está asociada al
marco j = 35 de memoria principal. De acuerdo con la figura este marco se encuentra actualmente en el
estado activo lo que significa que contiene una página que actualmente pertenece al conjunto de trabajo
de un proceso. En concreto se trata de la página i = O del proceso A.
La entrada k = 37 de la base de datos está asociada al marco j = 37 de memoria principal, el cual se
encuentra actualmente en el estado modificado. Luego contiene una página que ha sido eliminada del
conjunto de trabajo de un proceso y su contenido ha sido modificado y debe ser escrita en el almacena­
miento de respaldo. En concreto se trata de la página i = 2 del proceso A.
Finalmente, la entrada k = 42 de la base de datos está asociada al marco j = 42 de memoria principal que
se encuentra actualmente en el estado activo. Se observa que dicho marco contiene una página compartida
El sistema operativo Windows
337
Base de datos de los números
de marcos de página
i
1
!
1
k=3 5
Activo
Tabla de páginas
Proceso A
-------------------------------------------------------
1111
k=3 6
k=37
k=3 8
j=6 1 v=O
i=3
p=O v= l
i=4
j=60 v=O
Modificado
-------------------------------------------------------
1111
.---
k=3 9
J
1
''
'1
k=40
k=4 1
k=42
37 m 1
i=O
i= l
i=2
j-35 v- l
Activo
----------------·
j-42 v- 1
�p
p= l
!
11
i'
1
!
1
Tabla de páginas prototipo
de una región compartida
Figura 8.9 -
o
Tabla de páginas
Proceso B
i=O
p=O v= l
1
1
Estado de la base de datos de los números de marcos de página del Ejemplo 8 . 5
y a que l a entrada p = O d e la tabla d e páginas prototipo asociada a una región d e memoria compartida
entre los procesos A y B apunta precisamente a la entrada k = 42 de la base de datos.
•
El administrador de memoria organiza las entradas de la base de datos de los números de marco
de página en cuatro listas: lista de marcos inicializados a O, lista de marcos libres, lista de marcos
modificados, y lista de marcos en standby. Cada entrada perteneciente a una lista contiene el número de
la siguiente entrada que forma parte de dicha lista.
Cuando un proceso termina su ejecución todas sus páginas privadas son colocadas en la lista de
marcos libres. Por otra parte, cuando una página dej a de pertenecer al conjunto de trabaj o de un proceso,
bien porque ha sido reemplazada o bien porque se ha reducido el tamaño del conj unto por necesidades de
memoria, si la página ha sido modificada entonces ingresa en la lista de marcos modificados. Mientras
que si no ha sido modificada ingresa en la lista de marcos en standby.
Cuando el administrador de memoria necesita asignar un marco inicializado a cero, por ejemplo,
para la región de pila o el montículo de un proceso, entonces selecciona un marco de la lista de marcos
inicializados a cero. Si esta lista está vacía entonces selecciona un marco de la lista de marcos libres y
antes de asignarlo lo inicializa a cero. Si la lista de marcos libres también está vacía entonces selecciona
338
Ampliación de sistemas operativos
a un marco de la lista de marcos en standby y antes de asignarlo lo inicializa a cero.
Existe un hilo denominado hilo de puesta de página a cero que se encarga de inicializar a cero las
páginas que se encuentran en la lista de marcos libres y pasarlas a la lista de marcos inicializados a cero.
Existen varias instancias de este hilo, una por cada procesador disponible. Este hilo se ejecuta con la
prioridad más baj a posible (prioridad 0), en consecuencia solo se ejecuta cuando no existe ningún otro
hilo en el estado preparado.
Por otra parte, cuando el administrador de memoria necesita asignar un marco de memoria que no
requiere estar inicializado a cero entonces primero lo intenta obtener de la lista de marcos libres. Si dicha
lista está vacía entonces lo intenta obtener de la lista de marcos inicializados a cero. Finalmente si esta
lista también está vacía entonces acude a la lista de marcos en standby.
En la Figura 8 . 1 0 se resumen las posibles transiciones entre las listas de marcos de páginas .
Fallo de página
inicializada a cero
Lista de marcos
inicializados a cero
,
....
Fallo de página duro
Conjuntos de trabajos
de los procesos
Fallo de página
suave
Fallo de página
suave
Lista de marcos
libres
Lista de marcos
en standby
�
Lista de marcos
modificados
Paginas seleccionadas para ser remplazadas
Figura 8.10 -
8.5.5.
Transiciones entre las listas de marcos de páginas
Respaldo de páginas en memoria secundaria
Las regiones del espacio de direcciones virtuales de un proceso se pueden clasificar en dos tipos:
regiones generadas mediante el mapeado de un determinado archivo (código y datos inicializados) y
regiones anónimas no generadas mediante ningún mapeado (pila y montículo).
El sistema operativo Windows
339
El almacenamiento de respaldo en memoria secundaria de las páginas pertenecientes a regiones ge­
neradas mediante el mapeado de un archivo es el propio archivo en disco. Para las páginas pertenecientes
a regiones anónimas o copias privadas de páginas marcadas como copiar al escribir, Windows utiliza
como almacenamiento de respaldo los archivos de páginas (page files) que son archivos cuyos bloques
de datos almacenan páginas de los procesos o del sistema operativo.
Windows soporta hasta 1 6 archivos de páginas. El tamaño máximo de un archivo de páginas varía
en función de la arquitectura. Por ejemplo, en la arquitectura Intel x86 sin uso del modo PAE el tamaño
máximo de un archivo de páginas es de 4,095 MiB . Mientras que si se usa el modo PAE el tamaño
máximo es 1 6 TiB . Cuando se arranca el sistema el proceso gestor de sesión accede al registro para leer
la lista de los archivos de página que hay que abrir.
Cuando una página de una región anónima es asignada Windows reserva para ella espacio en un
archivo de páginas. Sin embargo la localización exacta de la página dentro del archivo no se asigna por
adelantado sino una vez que la página es escrita en el archivo.
Los marcos de página que contienen páginas modificadas que han sido seleccionadas para ser inter­
cambiadas fuera de memoria principal se encuentran dentro de la lista de marcos de página modificados.
Estas páginas modificadas deben ser escritas en su almacenamiento de respaldo correspondiente. Existen
dos hilos del sistema encargados de realizar esta tarea:
•
Escritor de páginas modificadas. Se encarga de escribir páginas modificadas en los archivos de
páginas. Este hilo es despertado cuando el tamaño de la lista de hilos modificados excede un
determinado límite.
•
Escritor de páginas mapeadas. Se encarga de escribir páginas modificadas en los archivos que
mapean dichas páginas. Este hilo es despertado cuando el tamaño de la lista de hilos modificados
excede un determinado límite o si las páginas de un archivo han estado en esta lista durante más
de cinco minutos.
Una vez que una página modificada ha sido escrita en su almacenamiento de respaldo el marco que
la contiene pasa de la lista de marcos modificados a la lista de marcos en standby.
8.6.
Gestión de archivos en Windows
8.6.1.
Funciones de la API Win32 asociadas a la gestión de archivos y directorios
Existen varias funciones en la API Win32 asociadas a la gestión de archivos y directorios, entre las
funciones más conocidas se encuentran las siguientes :
•
CreateF i l e . Permite crear un archivo nuevo o abrir uno ya creado. Si se ejecuta correctamente
se crea un objeto archivo cuyo descriptor (handle) es devuelto al proceso que ha invocado a esta
función.
•
C l o s eHand l e . Cierra el archivo asociado al descriptor pasado como argumento de entrada.
340
Ampliación de sistemas operativos
•
De l e t eF i l e . Borra un archivo cuyo nombre de ruta debe ser pasado como parámetro de entrada.
Su funcionamiento es similar a la función unl ink de los SOBUNIX.
•
ReadF i l e . Lee una determinada cantidad de bytes de un archivo y los almacena en una determina
posición de memoria.
•
Wr i t eF i l e . Lee una determinada cantidad de bytes de una determinada posición de memoria y
los escribe en un archivo.
•
S e tF i l e P o inter. Configura a una determina posición el puntero de lectura/escritura de un ar­
chivo.
•
Ge t F i l eAttribu t e s . Devuelve los atributos de un archivo: si es un archivo o un directorio, si
está encriptado, si está comprimido, si está oculto, si es un enlace simbólico, etc.
•
CreateDi r e c to ry. Crea un directorio nuevo cuyo nombre de ruta debe ser introducido como
argumento de entrada.
•
Remove D i r e c t o ry. Elimina un directorio vacío cuyo nombre de ruta debe ser introducido como
argumento de entrada.
•
8.6.2.
S e tCurrentDi r e c t o ry. Cambia el directorio de trabaj o actual.
Sistemas de archivos
Cada sistema de archivos presente en memoria secundaria es tratado por Windows como una unidad o
volumen lógico independiente, cada una de los cuales posee su propia estructura de directorios. Windows
asigna una letra (C, D, E, . . . ) a cada unidad. El nombre de ruta de un archivo comienza por tanto con el
nombre del volumen lógico en el que está almacenado.
Las versiones modernas de Windows cuando se instalan en una partición de disco crean un sistema de
archivos principal de tipo NTFS (ver sección 8 .7). Aparte de NTFS Windows también soporta sistemas
de archivos CDFS , UFS , FAT 1 2, FAT 1 6, FAT32 y extFAT. Para interactuar con un determinado tipo de
sistema de archivos, el gestor de E/S (ver sección 8 . 8) invoca al driver del sistema de archivos (File
System Driver, FSD) correspondiente. Por ejemplo, para los sistemas de archivos NTFS utiliza el FSD
nt f s . sys , para el sistema CDFS utiliza el FSD c d f s . sys , etc.
El sector de arranque de cada partición con un sistema de archivos soportado por Windows contiene
la información necesaria para que el FSD asociado a dicho tipo de sistema de archivos pueda identificar
y localizar los metadatos y datos almacenados en el volumen. S eñalar que el FSD no accede al disco
directamente sino que invoca al gestor del volumen que a su vez invoca al driver del disco correspondiente
Por otra parte, cuando un proceso intenta acceder (leer o escribir) a alguna parte del archivo que no
está cargada en memoria entonces el gestor de memoria invoca al gestor de E/S que en función de donde
está localizado el archivo invoca al FSD adecuado para que realice la operación solicitada.
El sistema operativo Windows
8. 7.
341
El sistema de archivos NTFS
El sistema de archivos NTFS (New Technology File System, sistema de archivos de tecnología nue­
va) fue desarrollado a mediados de los noventa para ser el sistema de archivos principal de Windows
NT. Se trata de un sistema de archivos bastante versátil diseñado para cumplir con las necesidades de
almacenamiento y recuperación de datos de altas prestaciones necesarias en las estaciones de trabajo y
servidores de las empresas.
8.7.1.
Características principales
Un sistema de archivos NTFS presenta, entre otras, las siguientes características :
•
La unidad básica de asignación de espacio es el cluster. Un cluster es un conjunto contiguo de
sectores de disco. El tamaño en bytes de un cluster es una potencia de dos comprendida dentro
del rango [5 1 2 bytes, 64 KiB] . El tamaño se define en el momento de la creación del sistema de
archivos en función del tamaño de la partición. Por ejemplo si la partición tiene un tamaño mayor
de 32 GiB el tamaño de un cluster se fij a a 64 KiB . En este caso si un sector tiene un tamaño de
5 1 2 bytes entonces un cluster constará de 1 28 sectores contiguos.
Cada cluster tiene asignada una dirección de 64 bits, con lo que teóricamente el tamaño máximo
de una partición NTFS es de 2 64 clusters. Actualmente Windows limita el tamaño de una dirección
de un cluster a 32 bits lo que para un tamaño de cluster de 64 KiB permite que el tamaño máximo
de una partición sea ligeramente inferior a 256 TiB .
En Windows el flujo de datos de un archivo se descompone en M clusters virtuales contiguos,
mientras que una partición de disco se descomponen en P clusters lógicos contiguos. En ambos
casos los clusters se numeran comenzando en O. Si se utiliza Bv para denotar a una número de
cluster virtual de un archivo y BL para denotar a un número de cluster lógico de una partición,
entonces Bv puede tomar valores enteros comprendidos entre O y M l. Mientras que BL puede
tomar valores enteros comprendidos entre O y P - l .
-
•
Toda l a información contenida e n u n sistema de archivos NTFS s e estructura e n archivos. Los da­
tos almacenados en un volumen NTFS , incluidos los metadatos del propio sistema de archivos, se
estructuran en archivos. Esta estructuración simplifica la localización, mantenimiento y protección
de los datos.
•
Un archivo (o un directorio) consiste de múltiples flujos de bytes. A diferencia de otros sistemas
de archivos donde un archivo es implementado como una secuencia lineal de bytes, en NTFS un
archivo (o un directorio) consiste de múltiples flujos de bytes de tamaño variable. Cada flujo de
bytes representa a un atributo del archivo. Entre los atributos de un archivo soportados en un
sistema NTFS se encuentran los siguientes:
- Información estándar ( $ STANDARD_INFORMAT I ON) . Este atributo especifica si el archivo
es de solo lectura o de lectura-escritura, si es un archivo o un directorio, la fecha y hora de
342
Ampliación de sistemas operativos
creación del archivo, la fecha y hora de la última modificación del archivo, y el contador de
enlaces duros.
- Nombre del archivo ( $ F I L E_NAME).
- Descriptor de seguridad ( $ SECURITY_DESCRI PTOR) . Este atributo se mantiene por compatibilidad con las versiones anteriores de NTFS . La versión actual de NFTS almacena los
descriptores de seguridad de todos los archivos en el archivo de metadatos $ S e cur e.
- Datos ( $ DATA). Contiene los datos del archivo (o directorio).
- Identificador del objeto ( $ OBJECT_I D). Es un identificador de 64 bytes, siendo los 1 6 bytes menos significativos únicos de cada volumen. Existen funciones de la API Win32 que
permiten abrir un archivo por su identificador de objeto en lugar de usar su nombre.
- Raíz índice. ( $ INDEX_ROOT). Se utiliza para implementar directorios (ver sección 8.7.3).
- Asignación índice. ( $ INDEX_ALLOCATI ON) . Se utiliza para implementar directorios.
- Mapa de bits. ( $ B I TMAP). Se utiliza para implementar directorios.
Cada atributo tiene la siguiente estructura: código numérico del tipo atributo y valor del atributo.
También es posible poner un nombre a un atributo, el cual se almacena después del valor del atri­
buto. El uso del nombre de un atributo resulta de utilidad cuando un archivo tiene varios atributos
de un mismo tipo. Por ejemplo un archivo puede tener varios atributos datos o varios atributos
nombre.
•
Un archivo puede constar de múltiples flujos de datos. En NTFS un archivo consta por defecto
de un único atributo datos que no tiene nombre. Adicionalmente es posible definir otros atributos
datos asignándole a cada uno un nombre. Luego en NTFS un archivo puede contener múltiples
flujos de datos de diferentes tamaños. Cada fluj o de datos adicional puede ser accedido de la
siguiente forma:
nombre de l archivo : nombre de l f lu j o
Por ejemplo, supóngase un archivo prueba . txt que consta de dos flujos de datos: uno el flujo de
datos por defecto sin nombre y otro definido adicionalmente de nombre par t e 2 . Para trabaj ar con
el flujo por defecto simplemente se referencia al nombre del archivo, mientras que para trabaj ar
con el flujo con nombre habría que referenciarlo de la siguiente forma: prueba . txt : part e2 .
•
Los nombres de los archivos se codifican en código Unicode. Ello permite utilizar en los nombres
de los archivos caracteres diferentes del alfabeto latino. Un sistema NTFS es capaz de distinguir
entre caracteres en mayúsculas o en minúsculas en los nombres de archivos, luego Prueba . txt
y prueba . txt son nombres de archivos diferentes en NTFS . Sin embargo Windows no hace uso
de esta propiedad salvo cuando ejecuta funciones asociadas a la API POSIX. En la API Win32 no
se distingue entre mayúsculas y minúsculas a la hora de interpretar los nombres de los archivos,
aunque si respeta el que se usen mayúsculas en los nombres, es decir, que no las cambia cuando
almacena el nombre.
El sistema operativo Windows
343
•
Un nombre de archivo puede tener una extensión máxima de 255 caracteres.
•
Implementa una estructura de directorios de gráfica acíclica con soporte de enlaces duros y de
enlaces simbólicos. Los enlaces duros solo se pueden realizar a archivos dentro de un mismo vo­
lumen. Además no es posible realizar enlaces duros a directorios. Estas restricciones no se aplican
en el caso de los enlaces simbólicos. Por motivos de seguridad únicamente el administrador del
sistema tiene los privilegios necesarios para crear enlaces simbólicos. Por su parte un enlace duro
puede ser creado por cualquier usuario siempre que tenga los derechos de acceso oportunos sobre
el archivo al que apunta con el enlace duro.
Para crear un enlace duro se puede usar el comando rnkl ink con la opción / H . También se puede
utilizar la función C r e a t eHardL ink de la API Win32. La creación de un enlace simbólico se
puede realizar usando el comando rnkl i nk o la función Creat eSyrnbo l i c L i nk de la API Win32.
Los enlaces simbólicos son implementados en NTFS mediante un mecanismo de redirecciona­
miento denominado puntos de reanálisis. Un punto de reanálisis (reparse points) es un archivo o
un directorio que tiene un bloque de datos denominado datos de reanálisis asociado con él. Un
dato de reanálisis es un dato definido por el usuario sobre el estado o localización del archivo o
el directorio. Cuando NTFS encuentra un punto de reanálisis durante el análisis de un nombre de
ruta, se produce un error y se devuelve el dato de reanálisis al gestor de obj etos que reinicia la
operación de análisis teniendo en cuenta el dato de reanálisis encontrado. Los puntos de reanálisis
también son utilizados en NTFS para el montaj e del sistema de archivos.
•
Recuperación. Un sistema de archivos NTFS puede ser recuperado y devuelto a un estado con­
sistente si se producen fallos en el sistema o en el disco. Conviene aclarar que lo que se recupera
es el estado de las estructuras de datos del sistema de archivos no los contenidos de los archivos.
Para poder recuperar el sistema de archivos se realiza un almacenamiento redundante de los datos
críticos del sistema. Además las operaciones que pueden cambiar el estado del sistema se imple­
mentan mediante transacciones atómicas. Una transacción atómica se realiza completamente o no
se realiza. Cada transacción se registra en el archivo de registro (log file) antes de realizarse sobre
el volumen. De esta forma si se produce un fallo se consulta el archivo de registro para saber que
transacciones estaban pendientes para rehacerlas o deshacerlas. De esta forma siempre se garantiza
que el sistema de archivos se encuentra en un estado consistente.
•
Registro por diario Uournaling). NTFS soporta diferentes mecanismos para registrar los cambios
que se producen en los archivos y directorios almacenados en un volumen NTFS . Esta información
resulta de gran utilidad para determinadas aplicaciones, como por ejemplo los gestores de copias
de seguridad. Uno de estos mecanismos es el diario de cambios (change j ournal) que es un archivo
especial (interno del sistema NTFS) que puede ser leído por las aplicaciones.
•
Soporte de cuotas. NTFS dispone de mecanismos para fiscalizar y limitar el espacio en disco
disponible para cada usuario.
344
Ampliación de sistemas operativos
•
Compresión. NTFS permite crear archivos en modo comprimido, para ello se debe introducir el
argumento adecuado en la función CreateF i l e . El proceso de compresión es realizado por el
driver del sistema NTFS cuando el archivo es escrito en el disco. Cuando un proceso solicita leer un
archivo almacenado en modo comprimido el driver descomprime el archivo. Tanto la compresión
como la descompresión son actividades totalmente invisibles al proceso que no se percata de su
realización.
•
Encriptación. NTFS también permite crear archivos encriptados . El procedimiento de encriptación
y desencriptación es realizado por el driver de encriptación del sistema de archivos o driver EFS
(Encryption File System). Solo los usuarios autorizados pueden ver el contenido de un archivo
encriptado. Generalmente la encriptación se aplica marcando un directorio con este atributo de tal
forma que todos los archivos que se aloj an en el directorio (y los nuevos que se creen en él) son
encriptados de manera automática. Tanto la encriptación como la desencriptación son actividades
totalmente invisibles al proceso que no se percata de su realización.
8. 7 2
.
.
Estructura en el disco de un sistema NTFS
Un sistema de archivos NTFS presenta la siguiente estructura en la partición de disco donde se crea
[Stallings, 2005] (ver Figura 8 . 1 1 ) :
Partición de disco
Tabla de
archivos maestra
Figura 8.11
Á rea de datos de los archivos
- Estructura en el disco de un sistema de archivos NTFS
•
Á rea de arranque. Se sitúa al principio de la partición y puede ocupar hasta 1 6 sectores consecuti­
vos. Contiene información sobre la estructura del volumen y las estructuras de datos del sistema de
archivos, como por ejemplo la dirección física de comienzo de la tabla de archivos maestra. Si se
trata de la partición activa entonces el área de arranque también contiene el programa de arranque
o cargador de Windows.
•
Tabla de archivos maestra (Master File Table, MFT). Es la estructura de datos más importante
de un sistema NTFS . Contiene información sobre los atributos de todos los archivos y directorios
existentes en el volumen.
•
A rchivos del sistema. Es un área de aproximadamente 1 MiB de tamaño donde se alojan archivos
cuyos clusters de datos contienen metadatos del sistema de archivos.
•
Á rea de datos de los archivos. Se utiliza para almacenar los valores de los atributos de un archivo
o directorio que por su tamaño no pueden ser almacenados en la MFT.
El sistema operativo Windows
345
Tabla de archivos maestra
Cada fila de la MFT se implementa mediante una estructura de datos denominada registro de archivo
(file record) que tiene un tamaño fijo de 1 KiB . Esta estructura contiene los atributos de un archivo o
un directorio. Por cada atributo se almacena una cabecera y el valor del atributo. Luego un registro de
archivo puede verse como una sucesión de pares (cabecera de atributo, valor de atributo).
Si el valor de un atributo ocupa mucho espacio entonces no puede ser contenido en un registro de
archivo de la MFT y se le debe asociar uno o más grupos de clusters en el área de datos de la partición.
A cada grupo de clusters en el área de datos asociado al valor de un atributo se le denomina serie (run)
o extensión. La cabecera del atributo contiene la información necesaria para localizar las series del valor
del atributo en la partición.
A un atributo cuyo valor se almacena completamente en la MFT se le denomina atributo residente,
en caso contrario se le denomina atributo no residente. Algunos atributos siempre son, por definición,
residentes. Este es el caso, por ejemplo, de la información estándar y del nombre del archivo. Otros
atributos serán residentes o no en función de su tamaño. Este es el caso, por ejemplo, del atributo datos
del archivo.
La cabecera de un atributo indica si el atributo es residente o no residente. Además para el caso de
un atributo residente la cabecera contiene también la longitud del atributo y el desplazamiento a partir
del comienzo de la cabecera donde comienza el valor del atributo. En el caso de atributos no residentes
la cabecera contiene la siguiente información por cada serie: número de cluster virtual del archivo Bv de
inicio de la serie, número de cluster lógico de la pattición BL de inicio de la serie y número de clusters
que ocupa la serie.
Cada archivo o directorio existente en el volumen, incluida la propia MFT, tiene asignado al menos
un registro de archivo en la MFT. A dicho registro se le denomina registro de archivo base. Si el archivo
contiene tantos atributos (o sus cabeceras ocupan mucho espacio) que no pueden almacenarse en un único
registro de archivo de la MFT entonces se le asigna un segundo registro de archivo para poder mantener
toda la información del archivo. Si con un segundo registro tampoco es suficiente se le asignará un tercer
registro, y así sucesivamente hasta poder acomodar toda la información sobre los atributos de un archivo
(o directorio).
Para localizar en que registro de archivo se encuentra cada atributo en el registro de archivo base se
añade un atributo denominado lista de atributos que contiene el nombre y código de cada uno de los
atributos del archivo y la referencia de archivo del registro de archivo de la MFT donde se encuentra
localizado el atributo.
La referencia del archivo es un identificador de 64 bits que se construye en función de la entrada k
(k = O, 1 , 2, 3 , . . . , 248 1 ) que ocupa el archivo en la MFT. Este identificador consta de dos campos: el
número de secuencia y el número de archivo. El número de secuencia ocupa los 16 bits más significativos
y es un contador que se incrementa cada vez que dicha entrada es reutilizada. Por su parte el número de
archivo ocupa los restantes 48 bits y codifica el índice k de la entrada.
La referencia de un archivo puede cambiar durante el tiempo de vida de un archivo, es decir, un
archivo bajo determinadas circunstancias puede ser movido de una entrada k a otra entrada h de la MFT.
La referencia de un archivo guarda cierta analogía con el número de nodo-i de los SOBUNIX.
-
346
Ampliación de sistemas operativos
1 KiB
Atributo
Atributo
información estándar nombre de archivo
Cabecera
Figura 8.12 -
Atributo datos
Valor
.
Estado del registro de archivo de la MFf asociado al archivo prueba txt del Ejemplo
8.6
1 KiB
Atributo
Atributo
información estándar nombre de archivo
1111
Fila 65
de la MFT
---- 1
225
1
1
226
1
2
227
1
3
228
Primera serie de datos
Figura 8.13 - Estado del
8.6
IJo llll
Alumnos.dat
o
1 --- - 1
Atributo datos
1
5
4
316
1
IJo
- -
Localización de
las series
1- - - -
- - - - - - - ·
:...
Bv
BL
N
o
225
4
4
316
2
Área de datos
de la partición
317
Segunda serie de datos
.
registro de archivo de la MFf asociado al archivo Alumno s da t del Ejemplo
El sistema operativo Windows
e
347
Ejemplo 8.6
En la Figura 8 . 1 2 se muestra el estado de un registro de archivo (fila 5 1 ) de la MFf asociado a un archivo
de nombre prueba . txt cuyos atributos están contenidos en su totalidad en el registro.
Por el contrario en la Figura 8 . 1 3 se muestra el estado de un registro de archivo (fila 65) de la MFf
asociado a un archivo de nombre Al urnn o s . da t cuyo atributos datos tiene un tamaño que ha requerido
almacenarlo en dos series de 4 y 2 clusters contiguos respectivamente del área de datos de la partición.
La primera serie está asociada a los 4 primeros clusters virtuales de datos del archivo (Bv = O, 1 , 2, 3)
y ocupa los clusters lógicos BL = 225 a BL = 228 de la partición. Por su parte, la segunda serie está
asociada a los dos últimos clusters virtuales de datos del archivo (Bv = 4, 5) que ocupan los clusters
BL = 3 1 6 y BL = 3 1 7 de la partición.
•
Archivos del sistema
El nombre de los archivos del sistema empieza con el carácter $ . Algunos ejemplos de archivos del
sistema son:
•
Espejo de la MFf ( $MFTM i r r ). Este archivo contiene por motivos de seguridad una copia de las
33 primeras filas de la MFf.
•
Archivo registro ( $ L o g F i l e ). Contiene un listado de las transacciones atómicas a realizar sobre el
sistema de archivos . Se mantiene para poder recuperar el estado del volumen en caso de fallo.
•
Tabla de definición de atributos ($AttrDe f). Esta tabla define los atributos de los archivos sopor­
tados en el volumen. Además establece si los atributos se pueden indexar para realizar búsquedas
o si se pueden recuperar durante una operación de recuperación del sistema.
•
Mapa de bits de los clusters del volumen ( $ B i tMap ) . El estado de un bit del mapa determina el
estado (libre o asignado) de un determinado cluster del volumen.
El área de arranque también se implementa como un archivo del sistema (archivo $Boot), pero a
diferencia del resto de archivos del sistema se ubica siempre al principio de la partición. También la
propia MFf se implementa como un archivo del sistema (archivo $MFT) que se ubica a continuación del
área de arranque.
Los 33 primeros registros de archivos de la MFf (filas O a 32) están reservadas para los archivos del
sistema. El archivo de la MFf ( $ MFT) tiene asignada la fila O, el archivo espej o de la MFf ( $ MFTMirr )
tiene asignada la fila 1 , al archivo registro ( $LogF i l e ) la fila 2, el archivo de la tabla �e definición de
atributos ($At t rDe f ) la fila 4, el directorio raíz ( \ ) la fila 5, el archivo del mapa de bits de los clusters
del volumen ( $ B i tMap ) la fila 6 y el archivo del sector de arranque ( $ B o o t ) la fila 7.
348
Ampliación de sistemas operativos
8. 7 .3.
Estructura de un directorio en NTFS
Cada directorio (al igual que cada archivo) definido en una partición de NTFS tiene asignado al
menos un registro de archivo en la MFf. El registro de archivo asociado a un directorio contiene (ver
Figura 8 . 14 ), aparte del atributo información estándar y nombre del archivo (directorio en este caso),
un atributo denominado raíz índice cuyo valor es una lista de las entradas del directorio. Cada entrada
del directorio consta de una parte de longitud fija y otra de longitud variable. La parte de longitud fija
almacena, entre otros datos, la referencia del archivo (o subdirectorio) en la MFf y la longitud del
nombre del archivo (o subdirectorio). La parte de la entrada del directorio de longitud variable se utiliza
para almacenar el nombre del archivo o subdirectorio.
Si un directorio contiene muchas entradas entonces parte de las entradas se almacenan en el atributo
índice raíz y el resto de entradas se almacenan en series en el área de datos. A las series que contienen
entradas de directorios se les denomina bu.ffers índices. En este caso se añade en el registro de archivo
base del directorio un atributo denominado asignación índice que contiene la información necesaria para
localizar los buffers índices en la partición. También se añade un atributo denominado Mapa de bits que
permite establecer que entradas en los buffers índices están libres y cuales ocupadas.
En el caso de directorios con muchas entradas en vez de mantener una lista se implementa un árbol­
B 10 con objeto de acelerar la gestión del directorio: realización de búsquedas e inserción de nuevas
entradas.
e
Ejemplo 8.7
En la Figura 8 . 1 4 se muestra el estado de un registro de archivo (fila 80) de la MFf asociado a un di­
rectorio de nombre F o t o s . Se observa que este directorio, de acuerdo con el valor de su atributo raíz
índice, consta de tres entradas. En cada entrada se almacenará información sobre un archivo o subdirec­
torio. Puesto que el número de entradas es pequeño se pueden almacenar en su totalidad en el registro de
archivo base y no ha sido necesario utilizar buffers índices.
l KiB
�1
Atributo
Atributo
información estándar Nombre archivo
Fil• 8
de la MFT
!f
Cabecera
Figura 8.14 - Estructura de
�
\
11
Valor
Fotos
Atributo
Raíz índice
1 1 t 1 1 1_-_-_-_-_-j
Entrada
del directorio
un registro de archivo en la MFf asociado a un directorio con pocas entradas
•
10Un árbol-B es una estructura de datos del tipo árbol binario de búsqueda [Cormen et al . , 2009].
El sistema operativo Windows
8. 7 4
.
.
349
Localización de archivos en un sistema NTFS
Cuando un proceso crea un nuevo archivo o abre un archivo ya existente debe introducir como ar­
gumento de entrada de la función Create F i l e de la API Win 32 el nombre de ruta del archivo. Dicha
ruta debe ser analizada componente a componente. Si la ruta es correcta cada componente contiene la
referencia de archivo del siguiente componente.
e
Ejemplo 8.8
Supóngase que para abrir el archivo
C : \ Fo t o s \ p l aya . j pg
un proceso ha invocado a la función CreateF i l e . El análisis de la ruta comienza en el directorio raíz
( \ ) del volumen C que recuérdese tiene asignado el registro de archivo 5 de la MFT. S e buscaría en el
atributo índice raíz del directorio raíz una entrada cuyo nombre coincida con F o t o s .
S i existe dicha entrada, entonces se lee l a referencia d e archivo del directorio \ Fo t o s l a cual apunta
al registro de archivo asociado a dicho directorio. Supóngase que se trata del registro de archivo 80. A
continuación se accede al atributo raíz índice de dicho registro de archivo en busca de una entrada que
contenga el nombre p l aya . j pg .
De nuevo, si existe dicha entrada, se lee la referencia de archivo del archivo e : \ Fo t o s \ p l aya . j pg
la cual apunta finalmente al registro de archivo asociado al archivo que se desea abrir. Supóngase, por
ejemplo, que se trata del registro de archivo 95 .
•
Si un archivo se crea o se abre correctamente se le asigna un objeto archivo cuyo descriptor es
devuelto al proceso que invocó a la función CreateF i l e de la API Win 32. El objeto archivo contiene
un puntero a una estructura de datos que depende del tipo de sistema de archivos (FAT, NTFS , etc). En
el caso de un sistema de archivos NTFS esta estructura se denomina bloque de control del flujo (Stream
Control Block, SCB). Existe un S CB por cada atributo de un archivo. Cada SCB contiene la información
necesaria poder localizar a un determinado atributo. El obj eto archivo apunta al SCB del atributo del
archivo que se desea leer o escribir.
Todos los SCB de un determinado archivo apuntan a una estructura denominada bloque de control
del archivo (File Control Block, FCB ) que, entre otros datos, contiene la referencia del archivo al que
está asociado la cual permite localizar el registro base del archivo en la MFT.
e
Ejemplo 8.9
En la Figura 8. 1 5 se muestran las estructuras de datos necesarias para poder implementar una operación
solicitada por un proceso sobre el fluj o de datos sin nombre (atributo datos) de un archivo perteneciente
a un sistema de archivos NTFS .
•
350
Ampliación de sistemas operativos
Tabla de descriptores (handles)
asociada a un proceso
Bloque de control
de fluj o (SCB)
Objeto archivo
---+
Atributo
Datos
Tabla de archivos
Maestra (MFT)
�
Bloque de control
del archivo (FCB)
Figura 8.15 -
Estructuras de datos del Ejemplo 8.9
Subsistema de E/S en el ejecutivo
Administrador
de E/S
Administrador
de PnP
:
._
Drivers
Administrador
de potencia
Tratamiento
de interrupciones en el
núcleo
i
HAL
;
Hardware
Figura 8.16 - Componentes
E/S.
de Windows que se ejecutan en modo núcleo encargados de la gestión de la
El sistema operativo Windows
8.8.
351
Gestión de E/S en Windows
La gestión de la E/S en Windows involucra a diferentes componentes del sistema operativo que se
ejecutan en modo núcleo (ver Figura 8 . 1 6): el subsistema de E/S, los drivers de dispositivos y las rutinas
de tratamiento de las interrupciones. En las siguientes secciones se describe como se implementan estos
componentes en Windows.
8.8.1.
Subsistema de E/S
El subsistema de E/ S de Windows se implementa mediante los siguientes componentes del ejecutivo:
•
Administrador de E/S . Es el componente central del subsistema de E/S. Se encarga de atender
las peticiones de E/S realizadas por las aplicaciones de los usuarios y el resto de componentes
del ejecutivo. Además define y soporta la interfaz de trabajo con los drivers. Más en detalle el
administrador de E/S se encarga de la realización, entre otras, de las siguientes tareas :
- Asignar a cada petición de E/ S una estructura de datos denominada paquete de petición de
E/S (1/0 Request Packet, IRP) que contiene toda la información que necesita conocer el
subsistema para procesar la petición.
- Invocar al driver adecuado. El administrador de E/S cuando invoca un driver para realizar una
determinada operación le pasa su IRP correspondiente. Asimismo cuando el driver termina de
realizar la operación solicitada modifica adecuadamente el IRP y se lo envía al administrador
de E/ S para que proceda a completar la petición o se la pase a otro driver.
- Asignar a cada driver que se carga en el sistema un objeto driver e invocar a la rutina de
inicialización del driver que rellena los atributos del objeto con los puntos de entrada del
driver. Un punto de entrada es la dirección de comienzo de una rutina del driver.
- Proporcionar rutinas comunes que pueden ser invocadas por los drivers. Por ejemplo una
rutina para interactuar con el controlador de DMA, una rutina para invocar a otros drivers,
una rutina para solicitar buffers de E/ S, etc.
•
Administrador de PnP. Se encarga de detectar la conexión o desconexión de dispositivos de E/S
en el computador. Cuando el administrador de PnP detecta que se ha conectado un dispositivo
entonces se encarga de cargar el driver apropiado.
•
Administrador de potencia. Se encarga de gestionar el consumo de energía de los componentes
hardware del computador.
Estos componentes del ejecutivo de Windows para realizar sus tareas trabajan estrechamente con los
drivers de los dispositivos. En el registro de Windows se almacena una descripción de los dispositivos de
E/S existentes en el computador así como la información necesaria para la inicialización y configuración
de los drivers de dichos dispositivos.
352
Ampliación de sistemas operativos
8.8.2.
Drivers de dispositivos en Windows
De forma general los drivers de dispositivos usados en Windows se pueden descomponer en dos
grandes categorías : los drivers que se ejecutan en modo usuario y los drivers que se ejecutan en modo
núcleo. Ejemplos de drivers de Windows que se ejecutan en modo usuario son por ejemplo los drivers de
dispositivos virtuales que se utilizan para emular aplicaciones de 1 6 bits de MS-DOS y los drivers de las
impresoras del subsistema Windows.
Los drivers que se ejecutan en modo núcleo se pueden clasificar en las siguientes categorías [Russi­
novich et al. , 2009] :
•
Drivers de sistemas de archivos. Un driver de un sistema de archivos atiende las peticiones de E/ S
sobre un determinado tipo de sistema de archivos. Por ejemplo el driver nt f s . sys atiende las
peticiones de E/S sobre los sistemas NTFS .
•
Drivers PnP. Son drivers que trabaj an en colaboración con el administrador de PnP y el adminis­
trador de potencia.
•
Drivers no PnP. Son drivers no asociados a ningún dispositivo hardware que extienden la funcio­
nalidad del sistema operativo. Ejemplos de drivers no PnP son los drivers que se utilizan para el
soporte de los diferentes protocolos de red.
Otra posible clasificación de los drivers proviene del modelo de drivers de Windows (Windows Driver
Model, WDM) establecido por Microsoft, que proporciona a los programadores las especificaciones
que debe cumplir un driver para funcionar correctamente en Windows. De acuerdo con este modelo se
distinguen tres tipos de drivers [Russinovich et al. , 2009] :
•
Drivers de bus. Gestionan buses físicos o lógicos. Se encargan de detectar e informar al adminis­
trador de PnP de los dispositivos que se encuentran conectados a los buses. También se encargan
de controlar y configurar el consumo de energía de los buses. Microsoft proporcionan drivers de
bus para los tipos de buses más comunes : PCI, PnPISA, SCSI, USB and FireWire. Aunque si lo
desean los programadores pueden escribir sus propios drivers de bus.
•
Drivers de función. Un driver de función es el driver principal de un dispositivo ya que es el que
más información contiene sobre el funcionamiento de un determinado dispositivo y el que accede
propiamente al mismo. Este tipo de drivers suelen ser escritos por el fabricante del dispositivo.
•
Drivers de filtro. Son drivers opcionales que se utilizan para añadir alguna funcionalidad o modi­
ficar el comportamiento de un dispositivo o de otro driver.
Se observa que en el WDM cada tipo de driver (bus, función o filtro) se encarga de realizar una
tarea muy específica. Con este reparto de tareas se pretende simplificar la escritura de los drivers a los
programadores. Puesto que Microsoft proporciona drivers de buses y como los drivers de filtros son
opcionales, los programadores únicamente tienen que concentrarse en escribir bien el driver de función
de un determinado dispositivo.
El sistema operativo Windows
353
En Windows es común que una petición de E/ S requiera de la ejecución de varios drivers. El subsis­
tema de E/S se encarga de invocar al primer driver necesario para realizar una determinada tarea. Dicho
driver puede que requiera invocar a otro driver, para ello debe utilizar alguna función proporcionada por
el administrador de E/S .
e
Ejemplo 8.10
Supóngase que un hilo de un proceso de usuario ha invocado a la función Wr i t e F i l e de la API Win32
para escribir en un determinado archivo. Los argumentos de entrada de esta función son, entre otros,
los siguientes : el manej ador del archivo, el número de bytes a escribir, el buffer donde se encuentran
aloj ados los datos a escribir, y el desplazamiento medido en bytes desde el comienzo del archivo donde
se escribirán los bytes. Dicha función invoca a la llamada al sistema NtWr i t eF i l e que al ser atendida
por el ejecutivo produce que se invoque al administrador de E/ S . É ste a su vez invoca al driver del sistema
de archivos al que pertenece al archivo, por ejemplo si es un sistema NTFS al driver n t f s . sys . Este
driver traduce el desplazamiento en bytes relativo al comienzo del archivo en un desplazamiento en bytes
relativo al comienzo del volumen. Entonces pasa esta información mediante el administrador de E/S al
driver de disco. Este driver traduce esta posición lógica en una posición física y se comunica con el disco
para escribir los datos en el disco.
•
Cuando se carga un driver el administrador de E/S le asigna un objeto driver. Además invoca a la
rutina de inicialización del driver que rellena los atributos del objeto con los puntos de entrada del driver.
También crea un objeto dispositivo por cada dispositivo que controla dicho driver. Un objeto dispositivo
Objeto driver
,...
Función Read
Función Write
Función Ioctl
�
__.
_.
......
Código del driver cargado
en memoria princip al
Objeto
dispositivo
1
Figura 8.17 -
__.
Obj eto
dispositivo
1
Relación entre un objeto driver y sus objetos dispositivos asociados
354
Ampliación de sistemas operativos
es un objeto que representa y contiene información sobre un determinado dispositivo físico o lógico en
el sistema.
Todos los objetos dispositivos asociados a un determinado driver son organizados en una lista (ver
Figura 8 . 17). El objeto driver contiene un puntero al comienza de su lista de objetos dispositivos. Además
cada obj eto dispositivo contiene un puntero al objeto driver que lo controla.
Cuando el administrador de E/S recibe una petición de E/S sobre un determinado dispositivo con­
sulta el objeto dispositivo asociado a dicho dispositivo para obtener la dirección del objeto driver que
controla al dispositivo. Entonces accede al objeto driver para obtener el punto de entrada de la función
del driver que implementa la operación que se requiere realizar sobre el dispositivo y le pasa como ar­
gumento el IRP que contiene la información sobre la operación a realizar. Cuando el driver termina de
realizar la operación solicitada modifica adecuadamente el IRP y se lo envía al administrador de E/S
para que proceda a completar la petición o se la pase a otro driver.
8.8.3.
Gestión de interrupciones en Windows
Niveles de petición de interrupción
En Windows la gestión de las interrupciones se implementa en el núcleo. Éste prioriza la atención
de las interrupciones asignando a cada tipo de interrupción una prioridad denominada nivel de petición
de interrupción (lnterrupt Request Level, IRQL) que es un número entero positivo comprendido en el
rango [0, N] . El valor de N depende de cada arquitectura. Por ejemplo en la arquitectura Intel x86 N=3 1 ,
mientras que en las arquitecturas AMD x64 e Intel IA64 N= 1 5 .
Cuanto mayor e s e l valor del IRQL de una interrupción mayor e s s u prioridad, luego e l nivel de
prioridad de interrupción más alto corresponde a IRQL=N.
Asimismo el nivel de prioridad de interrupción más baj o corresponde a IRQL=O. A este nivel se le
denomina nivel pasivo y no está asociado a ningún tipo de interrupción sino que es el nivel de prioridad
asignado a la ejecución normal de los hilos tanto en modo núcleo como en modo usuario.
e
Ejemplo 8.1 1
E n la arquitectura Intel x86 Windows distingue 3 2 niveles de petición de interrupción. E l nivel más
prioritario es IRQL=3 1 que está asignado a la ejecución de la rutina del núcleo KeBugChec kEx ( ) , la
cual es invocada cuando se detecta una inconsistencia irrecuperable que podría corromper el sistema.
El siguiente nivel, IRQL=30, se asigna a interrupciones asociadas a un fallo de potencia. El nivel
IRQL=29 se asigna a interrupciones usadas para implementar la comunicación entre procesadores. El
reloj del sistema es atendido con un nivel IRQL=28. El nivel IRQL=27 se reserva para la implementa­
ción del perfil del núcleo, un mecanismo de medida del comportamiento del sistema.
Los dispositivos hardware tienen asignado un nivel IRQL comprendido dentro del rango [3, 26] . Los
niveles IRQL= l e IRQL=2 están reservados para las interrupciones software. Mientras que el IRQL=O,
es el nivel pasivo.
•
El sistema operativo Windows
355
Supóngase que se está ejecutando un hilo H l en modo usuario con IRQL=O y llega una interrupción
1 1 con un nivel IRQL=h. Entonces se produce una conmutación de modo usuario a modo núcleo y
se almacena el contexto hardware del hilo en un marco de su pila del núcleo asociada para que pueda
continuarse con su ejecución una vez finalizado el tratamiento de la interrupción y si no existe un hilo más
prioritario. A continuación el flujo de control se transfiere a un manipulador general de interrupciones
que identifica la interrupción que se ha producido, eleva el nivel de prioridad del procesador al valor
IRQL=h e invoca a la rutina especifica de tratamiento de la interrupción 1 1 .
Nótese que al elevar el nivel de prioridad de un procesador al valor IRQL=h todas las interrupciones
con IRQL::; h quedan bloqueadas (enmascaradas) en dicho procesador. Un interrupción con IRQL=k
con k < h no será atendida hasta que el nivel de prioridad del procesador sea configurado por debajo de
k.
Por otra parte, si mientras se está ejecutando la rutina de tratamiento de 1 1 con IRQL=h llega una
interrupción 12 con IRQL=p, con p > h, entonces se eleva el nivel de prioridad del procesador al valor
p, se guarda el contexto hardware de la rutina de tratamiento de 1 1 , y comienza a ejecutarse la rutina
de tratamiento de 12. Cuando esta rutina se complete entonces el nivel de prioridad del procesador se
reducirá de nuevo al valor h, y se continuará con la ejecución de la rutina de tratamiento de 1 1 .
Interrupciones software generadas por el sistema operativo
Aunque el hardware es la principal fuente de interrupciones, el sistema operativo también puede
generar interrupciones. En este caso se trata de interrupciones software las cuales tienen asignado los
niveles de petición de interrupción IRQL= 1 e IRQL=2. Entre las principales causas que producen que
Windows genere una interrupción software se encuentran las siguientes :
•
Llamadas a procedimientos asíncronos (Asynchronous Procedure Call, APC). Una APC es un
mecanismo que permite ejecutar un determinado código de una aplicación o del propio sistema
operativo en el contexto de un determinado hilo, es decir, dentro de un determinado espacio de
direcciones. Se distinguen dos tipos de APCs:
- APCs en modo núcleo. Se caracterizan porque para ser ejecutadas no requieren el permiso del
hilo en cuyo contexto desean ser ejecutados. Son utilizadas por los componentes del ejecutivo
de Windows para realizar aquellas tareas que requieren ser completadas en el contexto de un
determinado hilo, como por ejemplo suspender o terminar un determinado hilo.
- APCs en modo usuario. Se caracterizan porque para ser ejecutadas requieren el permiso
del hilo en cuyo contexto desean ser ejecutados . Diferentes funciones de la API Win 32
utilizan APCs en modo usuario. Por ejemplo la función ReadF i l eEx permite al hilo que la
invoca especificar la rutina que debe ser ejecutada cuando la operación de lectura solicitada
se complete.
Una APC se describe mediante un objeto del núcleo denominado objeto APC. Las APCs que se
encuentran a la espera de ser ejecutados residen en una cola APC gestionada por el núcleo. Existe
una cola APC por cada hilo. Cada vez que el núcleo inserta un objeto APC en la cola APC de
356
Ampliación de sistemas operativos
un hilo genera una interrupción software asociada al APC con un IRQL= l . Cuando el hilo es
planificado para ser ejecutado en primer lugar se ejecutan las interrupciones software asociados a
las APCs que tenga en su cola.
•
Llamadas a procedimientos aplazados (Deferred Procedure Call, DPC). Una DPC es una función
que implementa una tarea del sistema cuya ejecución puede ser aplazada hasta completar la tarea
actual. Las DPC proporcionan al sistema operativo la capacidad de generar una interrupción y
ejecutar una determinada función del sistema en modo núcleo. El núcleo utiliza DPCs para repla­
nificar el procesador después de que el cuanto de un hilo ha expirado. Los drivers utilizan DPCs
para completar peticiones de E/ S .
Una DPC s e describe mediante u n obj eto del núcleo denominado objeto DPC. Las DPCs que se
encuentran a la espera de ser ejecutados residen en una cola DPC gestionada por el núcleo. Existe
una cola DPC por cada procesador. El núcleo cada vez que inserta un objeto DPC en la cola DPC de
un procesador genera una interrupción software con IRQL=2. Cuando el IRQL de un procesador
cae por debajo del valor IRQL=2 entonces se comienzan a ejecutar las DPCs existentes en la cola
DPC de dicho procesador.
8.9.
Resumen
Windows de Microsoft es un sistema multiprogramado y multitarea, con soporte para multiprocesa­
miento. Consta de diversos componentes software, algunos de los cuales (procesos de servicios, procesos
del sistema, aplicaciones, librerías DLL y subsistemas de entorno) se ejecutan en modo usuario, mientras
que otros (capa HAL, drivers de dispositivos, GUI, núcleo y ejecutivo) se ejecutan en modo núcleo.
En Windows a las llamadas al sistema se les denomina servicios del sistema. Las funciones de envol­
tura de las llamadas al sistema de Windows se encuentran en la librería ntdl l . dl l . Microsoft ha pu­
blicado muy poca información sobre las funciones de esta librería, por lo que es difícil trabaj ar con ellas
directamente. El acceso a las funciones de la librería ntdl l . dl l , es decir, la invocación de llamadas al
sistema, se realiza de forma indirecta a través de las funciones de las librerías DLL que implementan las
APis soportadas por Windows, las cuales si están bien documentadas.
Windows implementa un modelo de proceso multihilo con un hilo del núcleo por cada hilo de usua­
rio. Existen varias funciones en la API Win32 que permiten crear un proceso, aunque sin duda la más
conocida y utilizada es la función C r e a t e Pro c e s s de la librería kerne l 3 2 . dl l . Por otra parte un hilo
de un proceso puede crear otro hilo dentro del mismo proceso invocando a la función Crea t eThread.
Windows es un sistema operativo de núcleo expropiable que utiliza como unidad de planificación a
los hilos del núcleo. Windows implementa un algoritmo de planificación de tipo expropiativo basado en
múltiples colas de prioridad y realimentación. Se consideran 32 niveles de prioridad comprendidos dentro
del rango [0, 3 1 ] , siendo O la prioridad más baj a posible y 3 1 la más alta. Estos 32 niveles son divididos
en dos grupos : niveles de tiempo real y niveles dinámicos. Los niveles de tiempo real comprenden los
16 niveles más prioritarios, es decir, los niveles de prioridad en el rango [ 1 6, 3 1 ] . Windows asigna estos
niveles de prioridad a los hilos del núcleo asociados a tareas críticas del sistema, como por ejemplo:
El sistema operativo Windows
357
la gestión de la memoria, la gestión de la caché, etc. Los niveles dinámicos comprenden los niveles de
prioridad en el rango [ 1 , 1 5 ] . En estos niveles se ejecutan la mayoría de los procesos de lo usuarios.
Windows para garantizar la exclusión mutua en el uso de las secciones críticas del código del sistema
operativo utiliza principalmente spinlocks. Otros mecanismos de sincronización disponibles en Windows
son los semáforos, los semáforos binarios o mutexes, y los eventos. Estos mecanismos pueden ser utili­
zados tanto por los propios componentes de Windows como por los hilos de los procesos de los usuarios.
Windows también implementa diversos mecanismos de comunicación entre procesos multihilos: tube­
rías, conectores, mailslots, llamadas a procedimientos remotos, obj etos compartidos, etc.
Windows utiliza la técnica de demanda de página para administrar la memoria principal. Todas las
tareas relativas a la administración de memoria son realizadas por el administrador de memoria que es
uno de los servicios que ocupa una mayor parte del código del ejecutivo de Windows, lo que da idea de
la complejidad del mismo.
Para gestionar la memoria física Windows utiliza el conjunto de trabajo de un proceso el cual queda
definido por las páginas pertenecientes al proceso cargadas en memoria que pueden ser referenciadas sin
producir un fallo de página. El tamaño y la composición del conjunto de trabajo de un proceso varían
durante el tiempo de vida del proceso.
Cada sistema de archivos presente en memoria secundaria es tratado por Windows como una unidad o
volumen lógico independiente, cada una de los cuales posee su propia estructura de directorios. Windows
asigna una letra (C, D, E, . . . ) a cada unidad. El nombre de ruta de un archivo comienza por tanto con el
nombre del volumen lógico en el que está almacenado.
Existen varias funciones en la API Win32 asociadas a la gestión de archivos, entre las funciones
más conocidas se encuentran las siguientes : CreateF i l e , De l e t eF i l e , C l o s eHandl e , ReadF i l e y
Wr i t eF i l e .
Las versiones modernas d e Windows cuando s e instalan e n una partición d e disco crean u n sistema
de archivos principal de tipo NTFS . Aparte de NTFS Windows también soporta sistemas de archivos
CDFS , UFS , FAT 1 2, FAT 1 6, FAT32 y extFAT. Para interactuar con un determinado tipo de sistema de
archivos, el gestor de E/ S invoca al driver del sistema de archivos correspondiente.
El sistema de archivos NTFS fue desarrollado a mediados de los noventa para ser el sistema de
archivos principal de Windows NT. Este sistema de archivos presenta, entre otras, las siguientes caracte­
rísticas: la unidad básica de asignación de espacio es el cluster, toda información contenida en un sistema
de archivos se estructura en archivos, un archivo (o un directorio) consiste de múltiples flujos de bytes,
un archivo puede constar de múltiples flujos de datos, un nombre de archivo puede tener una extensión
máxima de 255 caracteres, los nombres se codifican en código Unicode, implementa una estructura de
directorios de gráfica acíclica con soporte de enlaces duros y enlaces simbólicos, posibilidad de recupe­
ración del sistema, registro por diario, soporte de cuotas, compresión y encriptación.
Un sistema de archivos NTFS presenta la siguiente estructura en la partición de disco donde se crea:
área de arranque, tabla de archivos maestra, archivos del sistema, área de datos de los archivos. La tabla
de archivos maestra es la estructura de datos más importante de un sistema NTFS . Contiene información
sobre los atributos de todos los archivos y directorios existentes en el volumen. Por su parte los archivos
del sistema son archivos cuyos clusters de datos contienen metadatos del sistema de archivos.
358
Ampliación de sistemas operativos
El administrador de E/S es el componente central del subsistema de E/ S de Windows. Se encarga de
atender las peticiones de E/S realizadas por las aplicaciones de los usuarios y el resto de componentes
del ejecutivo. Además define y soporta la interfaz de trabajo con los drivers.
8.10.
Lecturas recomendadas
Si se desea obtener una explicación adicional de los contenidos tratados en este capítulo se pueden
consultar, por ejemplo: el capítulo 1 1 de [Tanenbaum, 2009] y el libro [Russinovich et al. , 2009] .
Asimismo para obtener una descripción detallada del uso de las funciones de la API Win 32 apare­
cidas en este capítulo se puede consultar los libros [Richter y Nasarre, 2007] y [Hart, 20 1 0] . También se
puede consultar la librería MSDN (www . msdn . mi c ro s o f t . c om) .
8.11.
Autoevaluación
8.1. Enumerar las características principales del sistema operativo Windows. (Respuesta en sección 8 .2.2)
8.2. Dibujar un diagrama adecuadamente rotulado de la estructura del sistema operativo Windows.
Comentar brevemente cada uno de sus componentes. (Respuesta en sección 8 .2.3)
8.3. ¿Qué es la API Win32? Comentar algunas de las librerías DLL que implementan la funcionalidad
de la API. (Respuesta en sección 8.2.4)
8.4. Explicar las acciones que pueden producirse cuando se invoca a una función de una librería DLL.
(Respuesta en sección 8 .2.4)
8.5. Explicar la implementación de la interfaz con el usuario de Windows. (Respuesta en sección 8 .2.5)
8.6. Explicar cómo se invocan y el tratamiento de las llamadas al sistema en Windows.
(Respuesta en sección 8.2.6)
8.7. ¿Qué es el registro de Windows ? ¿Cómo se implementa? ¿Quién puede acceder al registro?
(Respuesta en sección 8.2.7)
8.8. ¿Qué son los objetos del núcleo? ¿Cómo se implementan? ¿Quién se encarga de gestionarlos?
(Respuesta en sección 8.2.9)
8.9. Explicar qué es el identificador de un objeto y para qué se utiliza. (Respuesta en sección 8.2.9)
8.10. Enumerar y comentar brevemente los mecanismos de seguridad disponibles en Windows NT.
(Respuesta en sección 8.2. 1 0)
8.11. Enumerar y comentar brevemente las estructuras de datos utilizadas en Windows para implementar
la seguridad. (Respuesta en sección 8.2. 1 0)
El sistema operativo Windows
359
8.12. Describir la implementación de los procesos multihilos en Windows. (Respuesta en sección 8 .3 . 1 )
8.13. Dibujar un diagrama, adecuadamente rotulado, con las principales estructuras d e datos mantenidas
por Windows para implementar un proceso multihilo que conste de dos hilos. Explicar brevemente
la utilidad de cada una de las estructuras que aparezcan en el diagrama. (Respuesta en sección 8 .3 . 1 )
8.14. Dibujar el diagrama de transición de estados d e u n hilo en Windows. (Respuesta e n sección 8 . 3 .2)
8.15. Explicar la creación de procesos e hilos en Windows. (Respuesta en sección 8 . 3 .2)
8.16. Dibujar un diagrama, adecuadamente rotulado, con los niveles de prioridad definidos en Windows.
(Respuesta en sección 8 . 3 . 3 )
8.17. Describir las prioridades asociadas a u n proceso o a u n hilo e n Windows.
(Respuesta en sección 8 . 3 . 3 )
8.18. Describir l a implementación y la gestión d e las colas d e prioridad e n Windows .
(Respuesta e n sección 8 . 3 . 3 )
8.19. Explicar l a duración d e u n cuanto e n Windows . (Respuesta en sección 8 . 3 . 3 )
8.20. Describir la estructura y la invocación del planificador de Windows. (Respuesta en sección 8 . 3 . 3 )
8.21. Explicar el objetivo y las circunstancias bajo las cuales Windows aumenta temporalmente la prio­
ridad actual de un hilo. (Respuesta en sección 8 . 3 .3)
8.22. Describir los mecanismos de sincronización utilizados por Windows. (Respuesta en sección 8 .4. 1 )
8.23. Describir los mecanismos d e sincronización entre procesos multihilos disponibles e n Windows.
(Respuesta en sección 8 .4.2)
8.24. Describir los mecanismos de comunicación entre procesos multihilos disponibles en Windows.
(Respuesta en sección 8.4.3)
8.25. Explicar la implementación del administrador de memoria de Windows. (Respuesta en sección 8 . 5 .2)
8.26. Explicar la gestión de la memoria virtual en Windows. (Respuesta en sección 8 . 5 .2)
8.27. Describir la traducción de direcciones en Windows. (Respuesta en sección 8 . 5 . 3 )
8.28. Describir el uso que hace Windows del concepto de conjunto de trabajo de un proceso. (Respuesta
en sección 8 . 5 .4)
8.29. ¿Qué es la base de datos de los números de marcos de página? ¿En que posibles estados puede
encontrarse un marco de página? (Respuesta en sección 8 . 5 .4)
8.30. Dibujar un diagrama adecuadamente rotulado con las transiciones entre las listas de marcos de
página definidas en Windows. Explicar el diagrama dibujado. (Respuesta en sección 8 . 5 .4)
360
Ampliación de sistemas operativos
8.31. ¿Qué son los archivos de páginas? (Respuesta en sección 8.5 .5)
8.32. Enumerar diez funciones de la API Win32 disponibles para la gestión de archivos y directorios en
Windows (Respuesta en sección 8.6. 1 )
8.33. Explicar el tratamiento que realiza Windows de los diferentes sistemas de archivos existentes en la
memoria secundaria. (Respuesta en sección 8.6.2)
8.34. Enumerar y comentar las características principales de un sistema de archivos NTFS .
(Respuesta en sección 8.7. 1 )
8.35. Explicar la estructura en disco que presenta u n sistema de archivos NTFS .
(Respuesta en sección 8.7.2)
8.36. Describir la implementación de la tabla de archivos maestra. (Respuesta en sección 8.7 .2)
8.37. Enumerar algunos ejemplos de archivos del sistema. (Respuesta en sección 8.7 .2)
8.38. Explicar la estructura de un directorio en un sistema de archivos NTFS . (Respuesta en sección 8.7.3)
8.39. Explicar la localización de archivos en un sistema de archivos NTFS . (Respuesta en sección 8.7.4)
8.40. Describir la implementación del subsistema de E/S en Windows . (Respuesta en sección 8 . 8 . 1 )
8.41. Explicar qué es un driver de sistema de archivos, un driver PnP y un driver no PnP.
(Respuesta en sección 8 . 8 .2)
8.42. Explicar los tipos de drivers que se distinguen de acuerdo con el modelo WDM.
(Respuesta en sección 8.8 .2)
8.43. Dibujar un diagrama adecuadamente rotulado que ilustre la relación entre un objeto driver y sus
obj etos dispositivos asociados. Explicar la interacción del administrador de E/S con estos objetos.
(Respuesta en sección 8 . 8 .2)
8.44. Explicar cómo se gestionan las interrupciones en Windows. (Respuesta en sección 8 . 8 . 3 )
8.45. Explicar qué son y cómo se gestionan las llamadas a procedimientos remotos ¿Qué tipos se distin­
guen? (Respuesta en sección 8 . 8 . 3 )
8.46. Explicar qué son y cómo se gestionan las llamadas a procedimientos aplazados.
(Respuesta en sección 8 . 8 . 3 )
El sistema operativo Windows
8.12.
361
Ejercicios
8.1. En un sistema Windows una cierta aplicación está implementada como un proceso monohilo.
Supuesto que dicho proceso tiene asociada la clase de planificación alta y que la prioridad relativa
del hilo está configurada al valor debajo de normal determinar:
a) La prioridad base del proceso.
b) La prioridad base del hilo.
e) La prioridad actual del hilo.
8.2. Supóngase que en un cierto sistema Windows existen dos volúmenes C y D de tipo NTFS, y que
el volumen de trabajo actual es el volumen D. Explicar el significado de las siguientes órdenes del
intérprete cmd . exe :
a) mkl i nk / h en l a c e l . txt \ t rabaj o \ l i s t ado . txt
b) mkl i nk /d f o t o s C : \ imagene s \ f o t o s \ camara
8.3. Diseñar en el intérprete cmd . ex e de Windows un ejemplo que ilustre que un archivo en NTFS
puede constar de múltiples flujos de datos.
8.4. En un volumen NTFS un cierto archivo consta de 10 clusters virtuales (Bv = O, 1, . . . , 9) los cuales
se encuentran almacenados en los siguientes clusters lógicos BL: 6 1 , 62, 63, 90, 9 1 , 92, 93, 85, 86
y 1 1 2. Determinar la información relativa a la localización de las series del atributo de datos del
archivo que se almacena en la entrada asociada al archivo en la MFT del volumen.
8.5. El proceso de compresión de un archivo en un sistema NTFS es el siguiente: primero se aplica
el algoritmo de compresión sobre los 16 primeros clusters virtuales del archivo, si el resultado de
la compresión se puede almacenar en menos de 16 cluster lógicos, entonces los clusters virtuales
comprimidos se escriben en el disco, a ser posible en una única serie. Si el resultado de la compre­
sión ocupa 16 clusters entonces los clusters se almacenan sin comprimir en el disco en una única
serie, si es posible. A continuación se repite el análisis con los siguientes 16 clusters virtuales
del archivo, y así sucesivamente hasta analizar todos los clusters virtuales. Supóngase un cierto
archivo cuyos datos ocupan 48 clusters virtuales. Los primeros 16 clusters virtuales han podido
ser comprimidos en una serie de 8 cluster lógicos contiguos, la dirección del primer cluster lógico
de la serie es BL = 40. Los siguientes 1 6 clusters virtuales no han podido ser comprimidos y se
han almacenado en una serie de 16 cluster lógicos contiguos, la dirección del primer cluster lógico
de la serie es BL = 50. Finalmente los últimos 16 clusters virtuales han podido ser comprimidos
en serie de ocho clusters lógicos contiguos, la dirección del primer cluster lógico de la serie es
BL = 95. Determinar la información relativa a la localización de las series del atributo de datos del
archivo que se almacena en la entrada asociada al archivo en la MFT del volumen NTFS .
8.6 Realizar una búsqueda en Internet sobre las herramientas software disponibles para analizar el
funcionamiento y el rendimiento del sistema operativo Windows.
Apéndice A
Soluci ones completas de los ej erci cios
A.l.
Soluciones ejercicios capítulo 1
Solución Ejercicio 1.1
a) Para visualizar la ruta absoluta del directorio de trabaj o actual se debe escribir la orden
pwd
b) Para visualizar un listado del contenido del directorio de trabajo actual que permita diferenciar
entre archivos y directorios se puede escribir la orden
ls
-
ls
-1
F
También se podría usar la orden
e) Para visualizar un listado que únicamente contenga los nombres de los archivos que acaban con la
1
1
1
1
letra o o con la letra t se debe escribir la orden
l s * [ ot ]
d) Para mover al subdirectorio f o t o s los archivos da t o s y f o t o smu l se debe escribir la orden
mv da t o s f o t o smu l f o t o s
e ) Para hacer que e l directorio f o t o s pase a ser e l directorio d e trabajo actual se debe escribir la
orden
cd f o t o s
363
364
Ampliación de sistemas operativos
Solución Ejercicio 1.2
a) Esta orden ordena ( s o r t ) por orden alfabético las líneas del archivo fA y escribe el resultado en
el archivo fB.
b) Esta orden almacena en el archivo asd el resultado de la orden ls 1 que genera un listado largo
de los archivos del directorio de trabajo incluyendo tamaño, permisos, propietario, permisos, etc.
Si el archivo asd no existe se crea. Si el archivo ya existe se eliminará su contenido y se remplazará
por la salida de la orden l s - l .
-
,
e) Esta orden almacena en el archivo wer t 2 3 el resultado de l a orden l s - i , que genera un listado
largo de los archivos del directorio de trabajo mostrando en la primera columna el número de
nodo-i de cada archivo. Si el archivo wer t 2 3 no existe se crea. Si el archivo ya existe, la salida de
la orden l s - i se añade a partir del final del archivo.
d) Esta orden muestra en la pantalla el contenido del archivo prueba . txt ubicado en el directorio
de trabaj o inicial. Señalar que el nombre de ruta del archivo especificado en esta orden hace uso
del comodín tilde ' � ' el cual sustituye al nombre de ruta absoluta ( / home o /us ers) del directorio
que contiene los directorios de trabajo de todos los usuarios. Si se utiliza en la forma 1 entonces
hace referencia al nombre de ruta absoluta del directorio de trabajo inicial del usuario.
11
�
11
Por lo tanto supuesto, por ejemplo, que el directorio de trabaj o inicial del usuario que invoca
esta orden es / home / j o s erna entonces la orden propuesta expandiendo el comodín tilde sería
equivalente a
mo re / home / j o s ema / prueba . txt
e) Esta orden copia los archivos par t epr imera y par t e s egunda en el directorio traba j o . Señalar que la orden hace uso del comodín llaves { c adl , c ad2 , . . . , cadN } el cual expande una
palabra por cada una de las cadenas de caracteres cadj j = 1 , . ,N incluidas dentro de las llaves.
11
11
.
.
Solución Ejercicio 1.3
a) Se puede usar por ejemplo el comando
c a t / e t c / she l l s
b) S e puede usar por ejemplo el comando
where i s bash
También se podría usar el comando loca t e bash o el comando whi ch bash.
e) Se puede visualizar el valor de la variable de entorno SHELL:
Soluciones completas de los ejercicios
365
echo $ SHELL
Si estamos usando el intérprete bash se mostrará en pantalla un mensaj e similar a
/ b i n / bash
d) Se puede visualizar el valor de la variable del intérprete BASH_VERSION:
echo $ BASH_VERS I ON
e) En bash existen definidas diferentes variables especiales, entre las más utilizadas se encuentran
las siguientes:
•
$ ? . Contiene el estatus de salida del último comando ejecutado por bash. El estatus de sa­
lida de un comando es un valor entero positivo pequeño que éste devuelve cuando finaliza.
Como regla general se suele considerar que si el estatus de salida es igual a O entonces el
comando se ha ejecutado con éxito, mientras que si es igual a 1 entonces se ha producido al­
gún error. También se pueden devolver otros valores distintos, de acuerdo con algún criterio
prestablecido por el programador. El comando exi t permite especificar el valor del estatus
de salida.
•
$ $. Contiene el PID del proceso que implementa el intérprete.
•
$ ! . Contiene el PID del proceso asociado al último comando que fue ejecutado en segundo
plano por el intérprete.
•
$ o . Contiene la cadena de caracteres asociada al nombre del shell script que se está ejecutan­
do actualmente en el intérprete.
•
$ # . Contiene una cadena de caracteres con el número de argumentos de entrada del shell
script o la función.
•
$ * . Contiene los argumentos de entrada del shell script o función. Se suele utilizar en los
bucles f or.
•
$ i . Con i
=
1, 2, 3 , . . . , 9 contiene la cadena de caracteres asociada al argumento i-ésimo de
entrada del shell script que se está ejecutando actualmente.
f) La sustitución de comandos permite usar la salida de un comando como si fuese el valor de una
variable. En bash esto se consigue de la siguiente forma:
$ ( c omando )
Por ejemplo la orden D I R = $ ( pwd ) almacena en la variable D I R la salida del comando pwd el cual
muestra el nombre de ruta del directorio de trabaj o actual.
Otra forma de implementar la sustitución de comandos es entrecomillando el comando con acentos
graves :
366
Ampliación de sistemas operativos
' c omando '
Luego la orden DIR= ' pwd ' es equivalente a DIR= $ ( pwd ) .
g) En bash una cadena de caracteres entrecomillada con comillas dobles, " c adena " , es analizada por
el intérprete en busca de comandos que deban ser sustituidos o caracteres que deban ser expandi­
dos. Por ejemplo, supuesto que en el directorio de trabaj o actual existe el archivo s c r ip t l . sh
que contiene 78 palabras entonces la orden
echo " N º pa l abras = $ ( wc -w s c r ip t l . sh ) "
produce la siguiente salida en la pantalla:
Nº palabras = 7 8 s c r i p t l . sh
Por el contrario, una cadena de caracteres entrecomillada con comillas simples, 'c adena', no es
analizada por el intérprete. Por ejemplo, la orden
echo ' N º pa l abras = $ ( wc -w s c r i p t l . sh ) '
genera la siguiente salida en la pantalla:
Nº pa l abras = $ ( wc -w s c r i p t l . sh )
h) En bash l a introducción de datos desde el teclado se consigue usando la orden read. Por ejemplo,
la orden:
read -p " Introduce tu nombr e : " nombre
muestra en la pantalla el mensaj e In tradu c e tu nombre y se queda a la espera de que el usuario
introduzca por el teclado una cadena de caracteres y pulse la tecla de retomo de carro. Cuando esto
suceda la cadena introducida se almacenará en la variable nombre .
i) Los operadores lógicos disponibles en b a s h son:
•
El && E2 . Realiza la operación AND lógica entre El y E2.
•
El
•
1 1 E2 . Realiza la operación O R lógica entre E l y E2.
! E l . Realiza la operación NOT lógica sobre E l .
Los operadores de comparación de cadenas disponibles en bash son:
•
A = B. Comprueba si las cadenas A y B son iguales.
Soluciones completas de los ejercicios
•
A ! = B. Comprueba si las cadenas A y B son distintas.
•
A
•
A > B. Comprueba s i l a cadena A es mayor lexicográficamente que l a cadena B .
•
- n A . Comprueba s i l a cadena A e s n o nula y tiene una longitud mayor d e cero.
•
- z A. Comprueba si la cadena A tiene una longitud igual a cero.
<
367
B . Comprueba si la cadena A es menor lexicográficamente que la cadena B .
Finalmente los operadores de comparación de números enteros disponibles en bash son:
e
X
-lt
y.
Comprueba si x es menor que y.
e
X
-le
y.
Comprueba s i x es menor o igual a y.
e
X
- eq
y.
Comprueba si x es igual a y.
e
X
-ne
y.
Comprueba si x es distinto de y.
e
X
-ge
y.
Comprueba si x es mayor o igual a y.
e
X
-gt
y.
Comprueba si x es mayor que y.
j) Algunos de los operadores de comparación de atributos de archivos disponibles en bash son:
•
-a archivo. Comprueba si el archivo existe.
•
- e archivo . Comprueba si el archivo existe.
•
-
•
- s archivo. Comprueba si el archivo existe y no está vacío.
f archivo. Comprueba si el archivo existe y es un archivo regular.
k) El operador [ expre s i ón J evalúa la expresión incluida en su interior. Esta es la forma más
habitual de realizar la evaluación de condiciones en las sentencias condicionales. También se puede
utilizar el comando t e s t .
1 ) S e puede usar el comando l e t operac i ón o e l doble paréntesis ( ( operac i ón ) ) . Las siguien­
tes líneas ilustran la realización de operaciones aritméticas con enteros:
X=2 ; Y = 3 ;
l e t Z l =X+Y
Z 2 = $ ( ( X+Y ) )
echo $ Z l $ Z 2
También se podría usar e l comando expr.
m) En bash una sentencia condicional de tipo i f tiene la siguiente sintaxis :
368
Ampliación de sistemas operativos
i f c ondi c i ón1
then
s ent enc i as 1
e l i f c ondi c i on2
then
s entenc i a s 2
e l i f c ondi c i on3
then
s ent enc i a s 3
else
s entenc i a s 4
fi
L a sentencia condicional anterior s e puede escribir también d e la siguiente forma:
i f c ondi c i ón1 ; then
s ent enc i a s 1
e l i f c ondi c i on2 ; then
s ent enc i a s 2
e l i f c ondi c i on3 ; then
s entenc i a s 3
e l se
s ent enc i a s 4
fi
Las siguientes líneas muestran un ejemplo de sentencia condicional d e tipo i f en bash:
X = 2 ; Y= 5 ;
i f [ $ X - l e $Y l ; then
echo X = $ X e s menor o i gual a Y= $Y
el se
e cho X=$X e s mayor a Y= $ Y
fi
n ) E n bash u n bucle whi l e tiene la siguiente sintaxis :
whi l e [ c ondi c i ón
do
s ent enc i a s
done
Un bucle unt i l tiene una sintaxis similar, simplemente hay que cambiar whi l e por un ti l. Las
siguientes líneas muestran un ejemplo de bucle whi l e :
Soluciones completas de los ejercicios
369
COLOR= " ve rde "
whi l e [ $ COLOR ! = " ro j o "
do
echo " Incorrec t o "
read -p " Introdu c e un c o l or : " COLOR
done
echo " C orrec t o "
o) En bash un bucle f o r se implementa de forma diferente a otros lenguajes de programación, como
por ejemplo C. Su sintaxis es la siguiente:
f o r var i ab l e [ in l i s t a ]
do
s ent enc i a s que u s an $var i ab l e
done
Las siguientes líneas muestran un ejemplo de bucle f o r :
for i in $ ( l s ) ;
do
echo " i t em : $ i "
done
El siguiente ejemplo ilustra una implementación del bucle for más similar a la usada en C:
for i in $ ( seq 1 1 0 ) ;
do
echo " i = $ i "
done
p) En bash la sentencia c a s e presenta la siguiente sintaxis :
c a s e c adena i n
patron1 )
s en t enc i as 1 ; ;
pat ron2 )
s ent enc i a s 2 ; ;
esac
Las siguientes líneas muestran un ejemplo de uso de c a s e :
370
Ampliación de sistemas operativos
Z=2
case $ Z
1 ) echo
echo
2 ) echo
echo
3 ) echo
echo
* ) echo
echo
e s ae
in
Uno
A¡ ¡
Dos
B
Tres
e¡ ¡
Cua l qu i e r o t r o va l o r
Otros ¡ ¡
'
'
q) El siguiente ejemplo ilustra cómo se declara y se invoca en bash una función con parámetros de
entrada que devuelve un valor de salida
#Dec l arac i ón de una func i ón asd que rec ibe dos argument o s de entrada :
func t i on asd {
echo " pr imer parame t r o = $ 1 , segundo parame t r o = $ 2 "
re turn 3
# Invo c a c i ón de l a fun c i ón c on l o s paráme t r o s Ho l a
a s d Ho l a Mundo
echo " $ ? " #Vi sual i z ac i ón de l c ódigo de s a l i da
y
Mundo
Señalar que para devolver un cierto valor desde una función se debe usar el comando r e turn. El
valor devuelto hace las veces de estatus de salida.
Solución Ejercicio 1.4
El shell script de la Figura l. 7 en primer lugar muestra en el dispositivo de salida estándar, por defecto
la pantalla, el mensaje
Introduc e una cadena :
En segundo lugar invoca al comando read para leer una cadena de caracteres desde el dispositivo de
entrada estándar, por defecto el teclado. La cadena leída se almacena en la variable CADENA. En tercer
lugar define una variable LONG I TUD a la que le asigna la salida del comando
echo $ CADENA 1 wc
-e
Este comando, mediante el uso de una tubería ( 1 ) , pasa l a cadena contenida en l a variable CADENA como
entrada del comando wc - e , el cual cuenta el número de caracteres que contiene la cadena.
A continuación mientras el valor de LONGITUD sea mayor que O se ejecuta un bucle whi l e en el que
se realizan las siguientes acciones en cada iteración del bucle: en primer lugar se define una variable x
como la unión de la cadena de caracteres x y la unión de la cadena de caracteres que resulta de eliminar
Soluciones completas de los ejercicios
371
(comando cut) LONGITUD caracteres de la variable CADENA. En segundo lugar se decrementa en una
unidad el valor de LONG I TUD.
Cuando se sale del bucle whi l e se imprime en la pantalla el valor de la variable x la cual contiene la
cadena CADENA escrita al revés.
En definitiva este shell script solicita al usuario una cadena de caracteres y la muestra en pantalla
escrita al revés.
Solución Ejercicio 1.5
El shell script de la Figura 1 . 8 en primer lugar comprueba si el número de argumentos de entrada ( $ #)
del shell script es mayor que cero. En caso negativo muestra en el dispositivo de salida unos mensajes
para indicar que se ha producido un error al especificar los argumentos e invoca al comando exi t para
terminar la ejecución del script y devolver como estatus de salida el valor l.
Por el contrario, si se cumple la condición entonces ejecuta un bucle f o r tantas veces como argu­
mentos de entrada ( $ * ) se le hayan pasado al shell script. En cada iteración del bucle se realizan las
siguientes acciones : en primer lugar se ejecuta el comando mv para mover el archivo cuyo nombre ha
sido pasado como argumento del script al directorio . / pap e l era el cual debe estar creado antes de
ejecutar el shell script. Nótese que si no es así el efecto del comando mv es el del cambiar el nombre
del archivo pasado como argumento por el nombre de pape l era. Señalar que los posibles mensajes de
error que pueda generar este comando son redireccionados (2 >) al dispositivo nulo, el cual actúa como
un sumidero.
En segundo lugar se comprueba el estatus de salida ( $ ? ) del comando mv. En función de su valor se
muestra un determinado mensaj e en el dispositivo de salida estándar.
Cuando se termina de ejecutar el bucle f o r se ejecuta el comando exi t para terminar la ejecución
del script y devolver como estatus de salida el valor O.
En definitiva este shell script mueve los archivos pasados como argumentos de entrada a un directorio
previamente creado en el directorio de trabajo denominado pap e l era. Es decir, implementa una especie
de papelera de reciclaje.
# ! / b i n / bash
#
CONT= O
wh i l e
[
$ C ONT - l e 6 0
]
do
date
CONT = $ ( ( $ CONT + 1 ) )
s l e ep 1
done
Figura A.l
- Solución del Ejercicio 1 .6
372
Ampliación de sistemas operativos
Solución Ejercicio 1.6
En la Figura A. l se muestra el código de un shell script para el intérprete bash que muestra la fecha
y la hora del sistema cada segundo durante un minuto.
Solución Ejercicio 1.7
En la Figura A.2 se muestra el código de un shell script para el intérprete bash que muestra el día de
la semana que fue ayer.
# ! / b i n / ba s h
#
HOY= $ ( da t e + %w }
AYER= $ ( ( $ HOY - 1 } }
# da t e + %w devuelve e l d í a de l a s emana en f o rma t o nurne r l c o ,
# c o n va l o r e s c omprend i d o s e n t r e O
# En e s t e c a s o ,
( domingo }
y 6
( s ábado } .
ayer t ornará va l o r e s entre - 1 y 5 .
# HOY a lmac ena el nume r o de d i a para hoy .
# AYER a l ma c e n a e l va l o r de HOY
echo
meno s
l.
" Ayer fue "
c a s e $AYER i n
-1}
echo
0}
echo
" S abado " ; ;
" Domingo 11 ; ;
11 Lune s .. ; ;
1}
echo
2}
echo " Ma r t e s u
3}
echo
" Mi e rc o l e s " ; ;
4}
echo
5}
*}
echo
" Jueves u ; ;
11 V i e rne S 11 j j
echo
" Inde f i n i do " ; ;
; ;
esac
Figura A.2 -
Solución del Ejercicio 1 .7
Solución Ejercicio 1.8
La función de librería sys t em cuya declaración es
# inc lude < s td l i b . h>
int sys t em ( c ons t char * C adena ) ;
resulta útil para ejecutar desde un programa una orden del intérprete de comandos. Esta función invoca
un intérprete de comandos para que ejecute la orden c adena y regresa después de que la orden se haya
terminado de ejecutar. Si la invocación al intérprete falla el valor devuelto por sys t em es 1 27. Si se
puede invocar al intérprete de comandos pero se produce algún error en la ejecución de la orden el valor
Soluciones completas de los ejercicios
373
devuelto es - 1 . Si el comando se ejecuta correctamente, la función devuelve el estatus de salida de la
orden. En la Figura A.3 se muestra un pequeño programa escrito en C que ilustra el uso de esta función.
# i nc lude < s t dl ib . h>
ma i n ( )
{
i n t s a l i da ;
s a l i da = sys t em ( " \ n echo $ PATH \ n " ) ;
p r i n t f ( " \ n S a l i da= %d \ n " , s a l i da ) ;
Figura A.3 -
Solución del Ejercicio 1 . 8
Solución Ejercicio 1.9
a) La máscara de modo 6644 en octal equivale a la máscara de modo binaria 11 O 11 O 1 O O 1 O O
que indica que los bits S_I SUID, S_I SGID están activados, que el propietario del archivo tiene
permiso de lectura y escritura, y que el grupo propietario de archivo y el resto de usuarios tienen
permiso de lectura sobre el archivo.
b) La máscara de modo simbólica asociada a este archivo es : - rwS r - S r - -
e) La máscara de modo simbólica - rwx r - - - - T es equivalente a la máscara de modo binaria
001 111 100 000
que en octal es 1 7 4 o . Luego un posible comando a utilizar es:
chmod 1 7 4 0 r e s u l tados
Solución Ejercicio 1.10
El enunciado del problema afirma que s 0 7 pertenece al usuario Wo l f (UID=50 1 , GID=202). Asi­
mismo su máscara de modo simbólica es - rwxrw- rwx, cuyo significado es el siguiente:
•
El propietario del archivo (Wo l f ) puede leer, escribir y ejecutar el archivo. Además este archivo
tiene su bit S_I SUI D desactivado.
•
Los usuarios del grupo propietario del archivo, por defecto GID=202, pueden leer y escribir el
archivo, pero no pueden ejecutarlo. Además este archivo tiene su bit S_I SGID desactivado.
•
El resto de usuarios pueden leer, escribir o ejecutar el archivo. Además este archivo tiene su bit
s I SVTX desactivado.
374
Ampliación de sistemas operativos
Una vez explicado el significado de la máscara de modo simbólica es posible contestar a lo que pide en
el enunciado:
a) De acuerdo con la máscara de modo simbólica el propietario del archivo (Wo l f) tiene permiso de
ejecución sobre su archivo s 0 7 . Al proceso A que se crea en el sistema asociado a la ejecución de
s 0 7 se le asigna UID=50 1 y EUID=50 1 . Al ejecutar el proceso A en primer lugar se invoca a la
llamada al sistema getuid para asignar el valor del UID del proceso a la variable u [ o ] , en este
caso u [ O ] = 5 0 1 . Luego se invoca a la llamada al sistema g e t e u i d para asignar el valor del EUID
del proceso a la variable u [ 1 J , en este caso u [ 1 J = 5 o l .
A continuación se invoca a l a llamada al sistema s e tu i d para asignar al UID y al EUID del
proceso el valor de u [ 1 ] . Como el EUID del proceso A no es el del superusuario y el valor de
u [ 1 ] coincide con el valor del UID del proceso A entonces solamente el EUID del proceso A se
configura con el valor de u [ 1 ] . En resumen el resultado de esta llamada al sistema es configurar el
EUID del proceso A al valor EUID=50 1 , valor que por otra parte ya tenía sin necesidad de haber
ejecutado esta llamada al sistema. Cómo s e tu i d se ha ejecutado con éxito entonces se asigna el
valor O a la variable u [ 2 J
•
Luego se comprueba si el valor de u [ 2 J es igual O. Cómo la comprobación es positiva se invoca a
la función anfitriona al pasándole como argumento la dirección de memoria de la función huésped
a2 .
La primera acción que se realiza al ejecutar la función a l es invocar a la función huésped a2
pasándole como argumento el valor inicial de la variable u, que es 30,4. Se comienza a ejecutar
la función a2 . La primera acción asociada a a2 es ejecutar un bucle 4 veces dentro del cual se
multiplica el valor de la variable a por 0.5. El resultado de la multiplicación se asigna a la variable
a A continuación se muestran los valores que toma la variable a en cada iteración del bucle:
•
(h = - 1 ) a = 0,5
*
•
(h = O) a = 0,5
*
1 5,2 = 7,6
•
(h = 1 ) a = 0,5
*
7,6 = 3,8
•
(h = 2) a = 0,5
*
3 , 8 = 1 ,9
30,4 = 1 5 ,2
Finalizado el bucle se ejecuta la instrucción re turn ( a ) con lo que la función a2 finaliza devol­
viendo 1 ,9 como valor de salida que es asignado a la variable u de la función a l . A continuación
se ejecuta la instrucción r e turn ( u ) de la función al con lo que finaliza devolviendo el valor 1 ,9
como valor de salida que es asignado a la variable z del código principal.
Por último se imprime en pantalla el mensaje
[501 , 501 ,
y el proceso A finaliza su ejecución.
o,
1 . 90 ]
Soluciones completas de los ejercicios
375
b) El usuario Fox no pertenece al grupo de Wo l f ya que sus GID son distintos. De acuerdo con la
máscara de modo simbólica tiene permiso de ejecución sobre s o 7 . Al proceso A que se crea en
el sistema asociado a la ejecución de s 0 7 se le asigna UID=502 y EUID=502. El funcionamiento
del proceso A es similar al descrito en el caso anterior, con la diferencia de que en este caso el
mensaj e que aparece en pantalla es
[ 502 , 502 ,
A.2.
o,
1 . 90]
Soluciones ejercicios capítulo 2
Solución Ejercicio 2.1
Al escribir la orden j 0 9 4 se comienza a ejecutar el programa j 0 9 . Supóngase que a la ejecución
de dicho programa se le asocia el proceso A, cuyo PID= 1 1 20 según el enunciado. En primer lugar se
comprueba si el número de argumentos con que ha sido invocado j o 9 es distinto de dos. Conviene
recordar que el nombre del programa cuenta como argumento. Puesto que j o 9 4 tiene dos argumentos
la condición del i f no se cumple y se pasan a ejecutar las sentencias del e l s e .
En segundo lugar s e invoca a la función d e librería a t o i que convierte e l segundo argumento ( ' 4 ' ) de
la invocación de j o 9 a número entero y lo almacena en la variable a.
En tercer lugar se ejecuta un bucle whi l e cuya condición para que se ejecute una iteración es que
la llamada al sistema f o rk devuelva el valor O y que la variable b no tome el valor a. Recuérdese que
f o rk crea un proceso hijo y devuelve O para el proceso hijo y el PID del hijo al proceso padre.
La evaluación de esta condición da como resultado la creación de un hijo B con PID= 1 1 2 1 , que al
cumplir que f o rk le ha devuelto O y que b es distinta de 4 ejecuta el contenido del bucle. El proceso
padre A no ejecuta el bucle ya que fork no le ha devuelto un O sino 1 1 2 1 , por lo que ejecuta una llamada
al sistema wa i t y se queda a la espera de que su proceso hijo B termine.
El proceso B muestra en pantalla el mensaj e
Mens a j e 1 [ 1 1 2 1 ]
e incrementa en una unidad el valor de la variable b que ahora toma el valor l. A continuación evalúa
la condición del bucle que da como resultado la creación de un hijo C con PID= 1 1 22, que al cumplir
que fork le ha devuelto O y que b es distinto de 4 ejecuta el contenido del bucle. El proceso padre B no
ejecuta el bucle ya que f ork no le ha devuelto un O sino 1 1 22, por lo que ejecuta una llamada al sistema
wa i t y se queda a la espera de que su proceso hijo C termine.
El proceso C muestra en pantalla el mensaj e
Mens a j e 1 [ 1 1 2 2 ]
e incrementa en una unidad el valor de la variable b que ahora toma el valor 2. A continuación evalúa
la condición del bucle que da como resultado la creación de un hijo D con PID= 1 1 23, que al cumplir
que f o rk le ha devuelto O y que b es distinto de 4 ejecuta el contenido del bucle. El proceso padre C no
376
Ampliación de sistemas operativos
ejecuta el bucle ya que f o rk no le ha devuelto un O sino 1 1 23, por lo que ejecuta una llamada al sistema
wa i t y se queda a la espera de que su proceso hijo D termine.
El proceso D muestra en pantalla el mensaj e
Mens a j e 1 [ 1 1 2 3 ]
e incrementa en una unidad el valor de la variable b que ahora toma el valor 3 . A continuación evalúa
la condición del bucle que da como resultado la creación de un hijo E con PID= 1 1 24, que al cumplir
que f ork le ha devuelto O y que b es distinto de 4 ejecuta el contenido del bucle. El proceso padre D no
ejecuta el bucle ya que f ork no le ha devuelto un O sino 1 1 24, por lo que ejecuta una llamada al sistema
wa i t y se queda a la espera de que su proceso hijo E termine.
El proceso E muestra en pantalla el mensaje
Mens a j e 1 [ 1 1 2 4 ]
e incrementa en una unidad el valor de la variable b que ahora toma el valor 4. A continuación evalúa la
condición del bucle que da como resultado la creación de un hijo F con PID= 1 1 25 , sin embargo como b
es igual 4 no ejecuta el contenido del bucle sino que ejecuta la llamada al sistema wa i t , pero como F no
tiene hijos no se suspende sino que imprime en pantalla el mensaj e
Mens a j e 2 [ 1 1 2 5 ] = 1 1 2 4
y finaliza.
Por su parte el proceso padre E tampoco ejecuta el bucle porque para él fork no ha devuelto un O
sino 1 1 25, y además b=4 por lo que ejecuta una llamada al sistema wa i t y se queda a la espera de que
su proceso hijo F termine. Como éste ya ha finalizado imprime en pantalla el mensaje
Mensaj e 2 [ 1 1 2 4 ] = 1 1 2 3
y finaliza.
Puesto que su hijo E ya ha terminado se despierta al proceso D que imprime en pantalla el mensaje
Mensaj e 2 [ 1 1 2 3 ] = 1 1 2 2
y finaliza.
Como su hijo D ya ha terminado se despierta al proceso C que imprime en pantalla el mensaj e
Mensaj e 2 [ 1 1 2 2 ] = 1 1 2 1
y finaliza.
A continuación puesto que su hijo C ya ha terminado se despierta al proceso B que imprime en
pantalla el mensaje
Mens a j e 2 [ 1 1 2 1 ] = 1 1 2 0
y finaliza.
Finalmente como su hijo B ya ha terminado se despierta al proceso A que imprime en pantalla el
mensaj e
Mensaj e 2 [ 1 1 2 0 ] = 1 0 0 0
y finaliza.
Soluciones completas de los ejercicios
377
Solución Ejercicio 2.2
1) Al escribir la orden j O 7 se comienza a ejecutar el programa j O 7 al que se le asocia, de acuerdo con
el enunciado, un proceso A cuyo PID es 789. Al ejecutar el proceso A en primer lugar se ejecuta
la llamada al sistema s i gnal que asigna el manej ador func a las señales del tipo S I GSUR l . En
segundo lugar, se asigna a la variable u el resto que resulta de dividir u entre 2, es decir, se le
asigna el valor 15 %2 = l.
En tercer lugar se crea, mediante la invocación de la llamada al sistema f o rk, un proceso hijo B
del proceso padre A. El PID de este proceso es, de acuerdo al enunciado, igual a 790. Luego en
este punto del programa se tienen dos procesos el padre A y el hijo B . Es el planificador del núcleo
el que decidirá qué proceso A o B se ejecuta en primer lugar.
Cuando se planifica para ejecución el proceso A, la llamada al sistema fork le devuelve el PID
del proceso hijo creado, es decir, 790. En consecuencia no se cumple la condición que evalúa el i f
por lo que se ejecuta la llamada al sistema exi t que finaliza el proceso A y devuelve a su proceso
padre (el interprete de comandos) un estatus de salida igual a l.
Cuando se planifica para ejecución el proceso B , la llamada al sistema fork le devuelve el valor
O. En consecuencia se cumple la condición que evalúa el i f por lo que se ejecuta la llamada al
sistema execv que invoca al programa ex2 . La primera acción del programa ex2 es invocar a la
llamada al sistema pau s e que hace que el proceso B se quede a la espera de recibir una señal que
no ignore o que no tenga bloqueada.
2) Para responder adecuadamente a este apartado se debe recordar que durante la ejecución de la
llamada al sistema execv se carga en memoria el nuevo ejecutable (ex2 ) reemplazando las re­
giones de código, datos y pila de usuario del proceso asociado al ejecutable actual (j 0 7 ) . Además
el núcleo borra en el área-u asociada al proceso A las direcciones de los manej adores de señales
y establece las acciones por defecto para cada tipo de señal . En el caso de la señal S I GUSRl su
acción asignada por defecto es terminar el proceso.
Al ejecutar la orden ki l l - S I GUSRl 7 9 0 se envía una señal S I GUSRl al proceso con PID igual
a 790, es decir, al proceso B . Este proceso no tiene establecido un manej ador para este tipo de
señales luego se ejecuta la acción por defecto, en consecuencia el proceso B finaliza.
Solución Ejercicio 2.3
1) Al escribir la orden s O S & se comienza a ejecutar el programa s O S en segundo plano. Supóngase
que a la ejecución de dicho programa se le asocia el proceso A, por el enunciado se sabe que su
PID es 1 035.
Al ejecutar el proceso A en primer lugar se invoca a la llamada al sistema s i gna l para especificar
que cuando el proceso reciba la señal S I GUSRl la acción que debe realizar el núcleo es la acción
por defecto asociada a dicha señal, es decir, terminar el proceso. En segundo lugar se invoca a la
llamada al sistema f o r k para crear un proceso hij o B , cuyo PID sería1 036. Como f ork devuelve
378
Ampliación de sistemas operativos
el PID del proceso hijo al padre, entonces no se cumple la condición i f y se invoca a la llamada
al sistema wa i t que suspende la ejecución del proceso A hasta que finalice su proceso hijo B .
Asimismo cuando el proceso hijo B sea planificado invocará a l a llamada al sistema s i gna l para
especificar que cuando reciba una señal S I GUSR1 se debe ignorar. A continuación invoca a la
llamada al sistema pau s e que hace que el proceso B quede a la espera de una señal que no ignore
o que no tenga bloqueada.
2) Al escribir la orden ki l l - S I GUSR1 1 0 3 6 se envía una señal S I GUSR1 al proceso con PID 1 036,
es decir, al proceso hijo B. Dicha señal es ignorada por el proceso.
3) Finalmente al escribir la orden ki l l - S IGUSR2 1 0 3 6 se envía ahora una señal S IGUSR2 al
proceso B . Como no se ha especificado ninguna acción para esta señal se ejecuta la acción por
defecto, que es terminar el proceso B . Así internamente el núcleo invoca a la rutina exi t ( ) siendo
el estatus de salida para el proceso padre A el número asociado a dicha señal, cuyo valor depende
de cada SOBUNIX y que lo vamos a denotar por NS . Puesto que el proceso B ha finalizado,
obviamente ya no se ejecuta la sentencia exi t ( 5 ) .
El núcleo devuelve al proceso A el PID 1 036 del proceso hij o y el estatus de salida NS. Así el
proceso A imprime en pantalla el mensaje
1 0 3 6 NS
y finaliza.
Solución Ejercicio 2.4
Al escribir la orden m O 9 se comienza a ejecutar el programa m O 9 . Supóngase que a la ejecución de
dicho programa se le asocia el proceso A, cuyo PID=2045 según el enunciado.
El proceso A hace una llamada al sistema fork para crear un proceso hijo (proceso B) al cual se le
asigna, de acuerdo con el enunciado, PID= 2046. La llamada al sistema fork devuelve O al proceso hijo
y 2046 al proceso padre. Estos valores se almacenan en la variable a del padre y del hijo, respectivamente.
Depende del planificador qué proceso se ejecuta después del f o rk, el padre A o el hijo B . Supóngase
que se ejecuta primero el proceso hij o B . Entonces entra en un bucle whi l e infinito, en cada pasada del
bucle se realizan las siguientes acciones : en primer lugar se realiza una operación binaria XOR ( a = a " 1 O),
es decir, a = a EB 1 0 = a· 1 0 + a · 10, entre la variable a, que contiene el valor O en la primera pasada del
bucle, y el número 10, almacenando el resultado en a.
En segundo lugar se invoca a la llamada al sistema ra i s e que envía al proceso B la señal S I GCHLD,
la acción por defecto asociada a esta señal es ignorarla, por lo que el proceso B no se ve perturbado por
dicha señal. Esta llamada al sistema devuelve un O si se ejecuta con éxito y - 1 en caso contrario. Se va a
suponer que se ejecuta con éxito.
En tercer lugar se imprime en pantalla el mensaje
Mensaj e 1 [ 2 0 4 6 ] : 0 : 1 0
Soluciones completas de los ejercicios
379
si se trata de una iteración impar del bucle, o el mensaje
Mensaje 1 [2046]: 0: O
si se trata de iteración par.
En cuarto lugar invoca a la llamada al sistema s 1 eep que suspende la ejecución del proceso B durante
4 segundos.
Cuando se planifica el proceso padre A invoca a la llamada al sistema sleep que suspende su ejecu­
ción durante 16 segundos. Cuando reanuda su ejecución invoca a la llamada al sistema kill para enviar
la señal SIGUSR1 al proceso hijo B. Esta señal tiene establecida como acción por defecto la terminación
del proceso que la recibe.
A continuación el proceso A invoca a la llamada al sistema sleep que suspende su ejecución du­
rante 3 segundos. Finalmente invoca a la llamada al sistema kill para enviar la señal SIGUSR2 a su
proceso padre, que es el intérprete de comandos (PID=2000). Esta señal tiene establecida como acción
por defecto la terminación del proceso que la recibe. Por lo que el intérprete de comandos desde donde
se invocó al programa m O 9 termina y se cierra su ventana.
Debe tenerse en cuenta que durante los 16 segundos que duerme el proceso padre A al proceso hijo
B le da tiempo a mostrar por pantalla los siguientes cuatro mensajes antes de que se cierre la ventana del
intérprete de comandos:
Mensaje
Mensaje
Mensaje
Mensaje
1
1
1
1
[2046]:
[2046]:
[2046]:
[2046]:
0:
o:
o:
o:
10
o
10
o
Solución Ejercicio 2.5
1) Al escribir la orden s09R 1 & se comienza a ejecutar el programa s09R en segundo plano. Su­
póngase que a la ejecución de dicho programa se le asocia el proceso A, por el enunciado se sabe
que su PID es 245.
Al ejecutar el proceso A en primer lugar invoca a la llamada al sistema signal para especificar
que cuando el proceso reciba la señal SIGUSR1 la acción que debe realizar el núcleo es ejecutar la
función fl. En segundo lugar invoca otra vez a la llamada signal para especificar que cuando el
proceso reciba la señal SIGUSR2 la acción que debe realizar el núcleo es ejecutar la la acción por
defecto asociada a dicha señal, es decir, terminar el proceso.
En tercer lugar invoca a la función atoi para pasar de carácter ASCII a número entero el primer
argumento de entrada (b [1]) del programa. Luego en la variable d se almacena el valor l.
En cuarto lugar comprueba si el número de argumento de entradas a es igual a 2 y si además d es
igual a l. Ambas condiciones en este caso se cumplen, ya que conviene recordar que el nombre
del programa cuenta como argumento de entrada. Por lo tanto se invoca a la llamada al sistema
sigsetrnask para bloquear la recepción de las señales SIGUSRl. Señalar que sigrnask es una
macro que permite configurar el valor de un determinado bit de la máscara de señales bloqueadas.
380
Ampliación de sistemas operativos
Si la llamada se ejecuta con éxito en la variable e se almacena la máscara de señales bloqueadas
que se tenía especificada antes de ejecutar esta llamada al sistema.
A continuación se invoca a la llamada al sistema sigblock para añadir nuevas señales a la másca­
ra de señales bloqueadas. En este caso se bloquea la recepción de las señales SIGUSR2. Finalmente
se invoca a la llamada al sistema pause y el proceso A entra en el estado dormido a la espera de
recibir una señal que no ignore y que no tenga bloqueada.
2) Al escribir la orden kill -SIGUSR1 245 se envía una señal SIGUSR1 al proceso con PID 245,
es decir, al proceso A. De acuerdo con el apartado anterior la recepción de señales SIGUSR1 está
bloqueada por el proceso luego el núcleo no le despierta.
3) Igual que el apartado anterior pero aplicado a las señales SIGUSR2.
Solución Ejercicio 2.6
La respuesta a este ejercicio depende de la salida que muestre por la pantalla el comando ps -j. Por
ejemplo se va a suponer que la salida es:
PID
3 9 68
63 82
63 3 9
PGID
3968
6382
63 3 9
SID
3968
3968
3968
TTY
pts /2
pts /2
pts /2
TIME
0:01
0:00
12:46
CMD
bash
ps
prog27
a) SID=3968. El proceso líder de la sesión es aquél cuyo PID coincide con el valor del SID, en este
caso el proceso con PID=3968 asociado al intérprete de comandos bash.
b) Se observa que existen tres grupos de procesos, cuyos PGID son: 3968. 6382 y 6339. En este caso
cada grupo consta de un único proceso.
A.3.
Soluciones ejercicios capítulo 3
Solución Ejercicio 3.1
En un sistema BSD4.3 el rango de prioridades [0, 49] está reservado para la ejecución de un proceso
en modo núcleo. Además el sistema BSD4.3 es de núcleo no expropiable, ello significa que si un proceso
está ejecutándose en modo núcleo éste continuará usando el procesador hasta que termine su ejecución,
se lo ceda voluntariamente a otro proceso o entre en el estado dormido a la espera de que se produzca
algún evento. En consecuencia el cuanto de ejecución de un proceso ejecutándose en modo núcleo es
infinito.
Por otra parte, un algoritmo de planificación de turno rotatorio con un cuanto de ejecución infinito es
equivalente a un algoritmo PIFO. Luego éste sería el algoritmo de planificación que se estaría aplicando
de forma efectiva sobre las colas asociadas al rango de prioridades [0, 49].
Soluciones completas de los ejercicios
381
Solución Ejercicio 3.2
En el intervalo [0, 100) ms se ejecuta el proceso A. Durante este intervalo la rutina de tratamiento de
la interrupción recalcula la prioridad del proceso A en t = 40 ms y en t = 80 ms. En t = 40 ms el campo
p_cpu del proceso A toma el valor 4, luego sustituyendo valores en (3. 1) y operando se obtiene que el
valor de la prioridad en modo usuario p_usrpri del proceso A en t = 40 ms es:
p_usrpri = PUSER+
¡u + 2·p_nice = 50+ � + 2·20 = 9 1
p_
De forma análoga en t = 8 0 ms el valor de la prioridad en modo usuario del proceso A es:
p_usrpri = 50+
� + 2·20 = 92
En t = 100 ms el campo p_cpu del proceso A toma el valor 10 y finaliza el cuanto asignado al
proceso A. Se invoca entonces a la rutina roundrobin ( ) para planificar al siguiente proceso de la cola,
en este caso el proceso B.
En el intervalo [ 100, 200) ms se ejecuta el proceso B. Durante este intervalo la rutina de tratamiento
de la interrupción recalcula la prioridad del proceso A en t = 140 ms y en t = 180 ms. En t = 140 ms el
campo p_cpu del proceso B toma el valor 4, luego el valor de la prioridad en modo usuario p_usrpri
del proceso B en t = 140 ms es:
p_usrpri = 50+
� + 2·20 = 91
De forma análoga !!n t = 180 ms el valor de la prioridad en modo usuario del proceso B es:
p_usrpri = 50+
� + 2·20 = 92
En t = 200 ms el campo p_cpu del proceso A toma el valor 10 y finaliza el cuanto asignado al
proceso B. Se invoca entonces a la rutina roundrobin ( ) para planificar al siguiente proceso de la cola,
en este caso el proceso C.
En el intervalo [200, 300) ms se ejecuta el proceso B. Durante este intervalo la rutina de tratamiento
de la interrupción recalcula la prioridad del proceso A en t = 240 ms y en t = 280 ms. En t = 240 ms el
campo p_cpu del proceso e toma el valor 4, luego el valor de la prioridad en modo usuario p_usrpri
del proceso e en t = 140 ms es:
p_usrpri = 50+
� + 2·20 = 91
De forma análoga en t = 280 ms el valor de la prioridad en modo usuario del proceso e es:
p_usrpri = 50+
� + 2·20 = 92
382
Ampliación de sistemas operativos
La ejecución de los procesos A, B y C se va alternando en la forma descrita hasta llegar a t = 1000
ms. El proceso A se ejecuta en los intervalos [300, 400), [600, 700) y [900, 1000) ms. Al terminar estos
tres cuantos de ejecución el valor del campo p_cpu del proceso A es igual a 40.
El proceso B se ejecuta en los intervalos [400, 500) y [700, 800) ms. Al terminar estos dos cuantos
de ejecución el valor del campo p_cpu del proceso B es igual a 30.
Por su parte el proceso C se ejecuta en los intervalos [500, 600) y [800, 900) ms. Al terminar estos
dos cuantos de ejecución el valor del campo p_cpu del proceso B es igual a 30.
En t = 1000 ms se invoca a la rutina schedcpu ( ) que en primer lugar multiplica el valor del campo
p_cpu de todos los procesos por el factor de decadencia, que de acuerdo con el enunciado es igual a 0,5.
Se tiene por tanto que p_cpu= 0,5·40 = 20 para el proceso A y p_cpu= 0,5·30 = 15 para los procesos
B y C.
En segundo lugar la rutina schedcpu ( ) recalcula la prioridad en modo usuario de cada proceso.
Para el proceso A se obtiene
O
p_usrpri = 50+
+ 2·20 = 95
�
Mientras que para los procesos B y C se obtiene
p_usrpri =
50+ � + 2·20 = 93
Por último la rutina schedcpu ( ) mueve a los procesos de la cola i = 22 asociada al rango de
prioridades [88, 9 1] en la que habían sido colocados al ser creados y los coloca en la cola i = 23 que está
asociada al rango de prioridades [92, 95]. Señalar que si no llega al sistema otro proceso más prioritario,
el proceso B será el próximo proceso en ser planificado.
Solución Ejercicio 3.3
Puesto que ts_cpupri = 1 la fila de la tabla de despacho que hay que consultar, cuando se produzca
alguno de los eventos que generan un cambio de prioridad, es la fila segunda asociada al nivel de prioridad
(PRIORITY LEVEL) 1.
a) Si el proceso consume su cuanto asignado entonces el valor de ts_cpupri se actualiza con el
valor de ts_tqexp de la segunda fila. Luego ts_cpupri =O. Como ts_upri = 14 entonces el
nuevo valor de la prioridad en modo usuario de acuerdo con (3.3) y (3.4) será ts_umdpri = 14.
Por lo tanto la prioridad en modo usuario del proceso se reduce de 15 a 14.
b) Si el proceso ha estado esperando para poder consumir su cuanto más de 5 segundos entonces el
valor de ts_cpupri se actualiza con el valor de ts_lwait de la segunda fila. Luego ts_cpupri
= 1 1. Como ts_upri = 14 entonces el nuevo valor de la prioridad en modo usuario de acuerdo
con (3.3) y (3.4) será ts_umdpri = 25. Luego la prioridad en modo usuario del proceso aumenta.
e) Si el hilo es despertado, cuando regresa a modo usuario el valor de ts_cpupri se actualiza con el
valor de ts_slpret de la segunda fila. Luego ts_cpupri = 1 1. Como ts_upri = 14 entonces
383
Soluciones completas de los ejercicios
el nuevo valor de la prioridad en modo usuario de acuerdo con (3.3) y (3.4) será ts_umdpri
En conclusión la prioridad en modo usuario del proceso aumenta.
=
25.
Solución Ejercicio 3.4
Al escribir la orden j1 o se comienza a ejecutar el programa j1 o. Supóngase que a la ejecución de
dicho programa se le asocia el proceso A. En primer lugar se le asigna el valorO a los elementos sem_flg
del array de estructuras z de tipo sembuf. Conviene recordar que las estructuras de tipo sembuf se
utilizan para especificar las operaciones que se desean realizar sobre un conjunto de semáforos. Los
elementos sem_flg permiten pasar indicadores a la llamada al sistema semop.
En segundo lugar se invoca a la llamada al sistema ftok para crear una llave numérica de 32 bits
que permite controlar el acceso a una instancia de un mecanismo IPC. Supuesto que se ejecuta con éxito
en y, que es una variable del tipo predefinido key_t, se almacenará la llave creada. En caso de error en
y se almacenará el valor (key_t) -l.
En tercer lugar se comprueba, si se ha producido algún error en la ejecución de la llamada al sistema
ftok. En dicho caso se ejecuta la función printf que muestra por pantalla el mensaje
mensaje wert
y se invoca a la llamada al sistema exit para terminar la ejecución del proceso A, devolviendo como
estatus de salida para su proceso padre el valor 3.
Si ftok se ha ejecutado con éxito entonces se invoca a la llamada al sistema semget para obtener
o crear un conjunto de dos semáforos. Si la llamada se ejecuta con éxito entonces en x se almacenará
el identificador entero del conjunto de 2 semáforos asociados a la llave y. Si no existe un conjunto de
semáforos asociado a dicha llave se crea (IPC_CREAT) uno nuevo con permisos de lectura y escritura
para el propietario (0600).
Después se invoca a la llamada al sistema semctl para inicializar con el valorO todos los semáforos
(SETALL) del conjunto de semáforos con identificador x.
A continuación se invoca a la llamada al sistema fork para crear un proceso hijo (proceso B). Esta
llamada devuelveO al proceso hijo y el PID del hijo al proceso padre. El proceso que se ejecute primero
(padre o hijo) dependerá del planificador. Supongamos que se ejecuta primero el proceso hijo B, entonces
tras asignar el valorO al elemento sem_num y el valor 1 al elemento sem_op de la estructura z [ O l invoca
a la llamada semop para realizar una operación signal_sem sobre el semáforoO del conjunto x. Como
el semáforoO de x había sido inicializado aO tras realizar esta operación toma el valor l.
A continuación el proceso B tras asignar el valor 1 al elemento sem_num y el valor -1 al elemento
sem_op de la estructura z [1] invoca a la llamada semop para realizar una operación wait_sem sobre el
semáforo 1 del conjunto x. Como el semáforo 1 de x había sido inicializado aO, el proceso B se bloquea
en espera de que algún otro proceso realice una operación signal_sem sobre este semáforo.
Por su parte el proceso padre A, invoca de nuevo a la llamada al sistema fork para crear otro proceso
hijo (proceso C). Esta llamada devuelve O al proceso hijo y el PID del hijo al proceso padre. El proceso
que se ejecute primero (padre o hijo) dependerá del planificador. Supongamos que se ejecuta primero
el proceso padre A, éste como no tiene más instrucciones para ejecutar finaliza. Se ejecuta entonces el
384
Ampliación de sistemas operativos
hijo C que invoca a la llamada al sistema sleep y suspende su ejecución durante dos segundos. Cuando
despierta tras asignar el valorO al elemento sem_num y el valor -1 al elemento sem_op de la estructura
z [ O J invoca a la llamada semop para realizar una operación wait_sem sobre el semáforoO del conjunto
x. Como el semáforoO de x había sido puesto a 1 por el proceso B, esta operación pone aO el semáforo
O. A continuación el proceso C ejecuta la función printf que muestra por pantalla el mensaje
mensaje fgh
Posteriormente el proceso C tras asignar el valor 1 al elemento sem_num y el valor 1 al elemento
sem_op de la estructura z [1] invoca a la llamada semop para realizar una operación sobre el semáforo
1 del conjunto x. Como resultado de esta operación pone el semáforo 1 aO y despierta al proceso B que
estaba bloqueado en el semáforo. Qué proceso se ejecuta (B o C) depende del planificador. Supuesto
que se ejecuta el C, éste simplemente finaliza. Entonces se planifica el proceso B que ejecuta la función
printf, muestra por pantalla el mensaje
mensaje asd
y finaliza.
Solución Ejercicio 3.5
Al escribir la orden sl O sistemas_operativos_2 se comienza a ejecutar el programa sl O. Su­
póngase que a la ejecución de dicho programa se le asocia el proceso A.
En primer lugar se comprueba que el número de parámetros (b) introducidos por la línea de comandos
al invocar a s1 O es igual a 2. La comprobación es positiva los dos parámetros introducidos son s1 O y
sistemas_operativos_2.
En segundo lugar se invoca a la llamada al sistema pipe para crear una tubería sin nombre y se
comprueba si se ha producido algún error, es decir, devuelve el valor -l. Si pipe (pdf) se ha ejecutado
con éxito entonces se crea una tubería sin nombre y en pdf se habrán almacenado dos descriptores de
archivos. Para leer de la tubería hay que usar el descriptor almacenado en pdf [ O J , mientras que para
escribir hay que usar el descriptor almacenado en pdf [1] .
Si se produjese algún error durante la ejecución de pipe entonces se imprimiría en pantalla el mensaje
El: [mensaje]
donde [mensaje J hace referencia al mensaje asociado al identificador de error contenido en la variable
errno. A continuación se invocaría a la llamada al sistema exit para terminar la ejecución del proceso
A.
Si pipe se ha ejecutado con éxito entonces se invoca a la llamada al sistema fork para crear un
proceso hijo (proceso B). Esta llamada devuelve el valorO al proceso hijo y el PID de hijo al proceso
padre. Dicho valor, en cualquier caso, se almacena en la variable a. Será el planificador el que decida
que proceso se ejecuta a continuación el padre o el hijo.
Supongamos que se ejecuta primero el proceso padre hasta finalizar y luego el proceso hijo. Primero
cierra el archivo con descriptor pdf [ O J (asociado a las operaciones de lectura en la tubería) ya que
Soluciones completas de los ejercicios
385
no lo va usar. En segundo lugar invoca a la llamada al sistema write para escribir en el archivo con
descriptor pdf [1] (asociado a las operaciones de escritura en la tubería) los diez primeros bytes del
segundo parámetro introducido por la línea de órdenes, es decir, escribe en la tubería sistemas_o. En
tercer lugar cierra el archivo con descriptor pdf [1] , ya que no va escribir más en la tubería. En cuarto
lugar escribe en pantalla el texto
Mensaje
Y finalmente invoca a la llamada al sistema exit para finalizar.
A continuación se ejecuta el proceso hijo. En primer lugar cierra el archivo con descriptor pdf [1]
ya que no va escribir en la tubería. En segundo lugar ejecuta un bucle while, en cada pasada del bucle
se lee un byte de la tubería y se escribe en la pantalla. El bucle finaliza cuando ya no quedan más bytes
por leer en la tubería. En la pantalla se habrá mostrado el siguiente texto
sistemas o
En tercer lugar escribe en la pantalla un salto de línea. En cuarto lugar, cierra el archivo con descriptor
pdf [1] ya que no va a leer más en la tubería. En quinto lugar muestra en pantalla el texto
Mensaje
Y finalmente invoca a la llamada al sistema exit para finalizar.
Señalar que si se hubiese planificado el proceso hijo antes que el padre éste se hubiera quedado
bloqueado al intentar leer en una tubería vacía. Solo cuando el proceso padre escriba en la tubería el
proceso hijo será desbloqueado. En dicho momento será el planificador el que decida si se continúa con
la ejecución del padre o con la del hijo.
De acuerdo con la explicación anterior y dependiendo del orden de planificación de los procesos en
la pantalla se pueden llegar a visualizar dos posibles trazas de ejecución:
•
Traza 1:
Mensaje
sistema_o
Mensaje
•
Traza 2:
sistema_o
Mensaje
Mensaje
386
Ampliación de sistemas operativos
Solución Ejercicio 3.6
Al escribir la orden j08a & se comienza a ejecutar el programa j08a en segundo plano. Supóngase
que a la ejecución de dicho programa se le asocia el proceso A.
Al ejecutar el proceso A en primer lugar se invoca a la función de librería malloc para reservar
memoria para almacenar 9 caracteres. Si la función se ejecuta con éxito entonces en b se almacena un
puntero a la zona de memoria reservada. En caso contrario devuelve NULL.
En segundo lugar, se ejecuta nueve veces un bucle for. En cada ejecución del bucle se asigna el
carácter nulo 1\ o a los elementosO a 8 de la cadena de caracteres apuntada por el puntero b.
1
En tercer lugar se invocaría a la llamada al sistema mknod para crear en el directorio actual una
tubería con nombre o archivo PIFO de nombre asd con permisos de lectura y escritura para todos los
usuarios.
En cuarto lugar, se invocaría a la llamada al sistema open para abrir el archivo PIFO asd con permi­
sos de lectura y escritura para todos los usuarios. Si la llamada al sistema se ejecuta con éxito se almacena
el descriptor del archivo en la variable enterar.
En quinto lugar, se invocaría a la llamada al sistema read para leer 7 bytes del archivo PIFO asd y
copiarlos en el array de caracteres b. Puesto que la tubería está vacía (ya que no se disponen de datos que
hagan suponer lo contrario) el proceso A se bloqueará hasta que otro proceso escriba en la tubería.
Al escribir la orden j08b se comienza a ejecutar el programa j08b en primer plano. Supóngase que
a la ejecución de dicho programa se le asocia el proceso B.
En primer lugar el proceso B invoca a la llamada al sistema open para abrir el archivo asd con
permisos de lectura y escritura para todos los usuarios. Si la llamada al sistema se ejecuta con éxito se
almacena el descriptor del archivo en la variable entera r. Se va a suponer en lo que resta que se ha
podido abrir el archivo asd.
En segundo lugar invoca a la llamada al sistema wri te para escribir los 8 bytes de la cadena de
caracteres b en el archivo asd. Finalmente, el proceso B invoca a la llamada al sistema close para
cerrar el archivo y el proceso B finaliza.
Por otra parte, puesto que la tubería ya contiene datos el núcleo despierta al proceso A, cuando éste
vuelva a ser planificado para ejecución se podrá completar la llamada al sistema read, es decir, leer
7 bytes del archivo PIFO asd y copiarlos en el array de caracteres b. A continuación, se ejecutará la
función de librería printf que mostrará en la pantalla
Texto 1
Después se invocará a la llamada al sistema e lose para cerrar el archivo asd, Finalmente se invocará
a la llamada al sistema unlink para eliminar el archivo PIFO asd y el proceso A finalizará.
Conviene señalar que dependiendo del orden de planificación de los procesos, podría suceder que al
escribir el proceso B en la tubería se despertase al proceso A y esté fuese planificado para ser ejecutado
hasta su finalización. Una vez finalizado el proceso A se continuaría con la ejecución del proceso B.
Soluciones completas de los ejercicios
A.4.
387
Soluciones ejercicios capítulo 4
Solución Ejercicio 4.1
La modificación pedida consiste simplemente en cambiar MAP_SHARED por MAP_ PRIVATE en la
llamada al sistema mmap. Se puede comprobar que con este cambio el mapeado del archivo textol.txt
pasa a ser de tipo privado y en consecuencia las modificaciones que realice el proceso sobre el archivo no
pueden ser visualizadas por lo procesos que mapeen este archivo en su espacio de direcciones. Además
dichas modificaciones no son trasladadas al archivo en el disco duro. En consecuencia cuando finaliza la
ejecución del proceso asociado al programa prog42 el contenido del archivo sigue siendo el mismo.
Solución Ejercicio 4.2
La solución de este ejercicio depende del SOBUNIX y de la arquitectura del computador que se
utilicen. En este caso se ha utilizado OpenSolaris sobre una máquina virtual Oracle V M VirtualBox.
a) Supóngase que al ejecutar el comando prog42 & se ha creado un proceso A con PID=6659.
Supóngase además que cuando aparece en pantalla el mensaje
PID=6659 duerme 20 s
y se ejecuta el comando pmap 6659 aparece en la pantalla la salida que se muestra en la Figura
A.4.
Este comando muestra información sobre el espacio de direcciones virtuales del proceso A. La pri­
mera fila contiene el PID del proceso y el nombre de ruta relativa del programa que está ejecutando
6659:
prog42
08046000
8K rwx--
08050000
4K r-x--
/export/home/josema/prog43
08060000
8K rwx--
/export/home/josema/prog43
D1E30000
24K rwx--
D1E40000
1280K r-x--
D1F80000
28K rwx--
/usr/lib/libc/libc_hwcap1.so.1
D1F87000
8K rwx--
/usr/lib/libc/libc_hwcap1.so.1
D1F90000
4K rwx--
D1FAOOOO
4K rw---
[ anon ]
D1FBOOOO
4K rw---
[ anon ]
D1FBFOOO
180K r-x--
/lib/ld.so.1
D1FFCOOO
8K rwx--
/lib/ld.so.1
4K rwx--
/lib/ld.so.1
D1FFEOOO
total
[ stack l
[ anon ]
/usr/lib/libc/libc_hwcap1.so.1
[ anon l
1564K
Figura A.4- Salida del comando pmap 6659 del apartado a) del Ejercicio 4.2
388
Ampliación de sistemas operativos
el proceso. La última fila contiene el tamaño total en KiB del espacio de direcciones virtuales del
proceso, en este caso 1564 KiB. Cada una de las restantes filas contiene la siguiente información
sobre una determinada región del espacio de direcciones virtuales del proceso: dirección virtual de
inicio de la región, tamaño de la región en KiB, permisos de acceso y nombre de ruta absoluto del
archivo que se mapea en dicha región.
Por otra parte, se observa que en el espacio de direcciones virtuales del proceso A existen las
siguientes regiones: pila, código, datos, y librerías compartidas. Además existen definidas varias
regiones de memoria anónima [ anon ] , estas regiones serán utilizadas, por ejemplo, para alber­
gar las copias de las páginas de las regiones que hayan sido configuradas con un mapeado de tipo
de privado.
b) Supóngase además que cuando aparece en pantalla el mensaje
PID=6659 vuelve a dormir otros 20 s
y se ejecuta el comando pmap 6659 aparece en la pantalla la salida que se muestra en la Figura
A.5. Se observa que el tamaño del espacio del proceso A ha crecido en 8 KiB pasándose a ser
ahora de 1572 KiB. Estos 8 KiB adicionales provienen de la región de montículo ( [ heap l) que
se ha creado para albergar la reserva de memoria realizada con la función malloc.
6659:
prog42
08046000
8K rwx--
08050000
4K r-x--
/export/home/josema/prog43
08060000
8K rwx--
/export/home/josema/prog43
08062000
8K rwx--
D1E30000
24K rwx--
[ stack l
[ heap l
D1E40000
1280K r-x--
[ anon l
/usr/lib/libc/libc_hwcap1.so.1
D1F80000
28K rwx--
/usr/lib/libc/libc_hwcap1.so.1
D1F87000
8K rwx--
/usr/lib/libc/libc_hwcap1.so.1
D1F90000
4K rwx--
D1FA0000
4K rw---
[ anon l
[ anon l
[ a non l
!lib/ld. so.1
D1FB0000
4K rw---
D1FBFOOO
180K r-x--
D1FFC000
8K rwx--
!lib/ld.so.1
D1FFEOOO
4K rwx--
/lib/ld. so.1
total
1572K
Figura A.S- Salida del comando pmap 6659 del apartado b) del Ejercicio 4.2
Solución Ejercicio 4.3
El comando vmstat 5 2 finaliza su ejecución transcurridos 5·2 = 10 s y durante este tiempo mues­
tra cada 5 segundos información sobre el estado de la memoria y sobre ciertos eventos del sistema (carga
Soluciones completas de los ejercicios
389
de CPU, paginación, número de cambios de contexto, interrupciones de dispositivo, llamadas del sis­
tema, etc). Señalar que la información mostrada depende de la implementación que se realiza de este
comando en cada SOBUNIX.
Por ejemplo, supóngase que este comando se ejecuta en un sistema OpenSolaris y que la salida que
se muestra en la pantalla es la siguiente:
kthr
page
memory
r b w
swap
fau1ts
disk
cpu
free
re
o o o 391292 39676
2
7
o
o
1 2792 6 1 -2
o
o
241
283
220 12
4 85
1 o
9
80
o
o
o 1656 o 3
o
o
254
352
241 98
2
o 334500 36728
mf pi po fr de sr sO s1
o
in
sy
es us sy id
o
Señalar que existen dos líneas de datos numéricos, la primera línea se muestra cuando se lanza la
orden y la segunda línea cuando transcurren 5 s.
Si se ejecuta la orden man vmstat se puede conocer el significado de la información que se mues­
tra en cada columna de la salida. kthr contiene información sobre el número de hilos del núcleo en
diferentes estados, memory contiene información sobre el uso de memoria, page contiene información
sobre fallos de página y paginación, disk informa sobre el número de operaciones en disco por segundo,
faul ts informa sobre la tasa de trampas e interrupciones y cpu informa sobre el porcentaje promedio
de uso de los procesadores.
A.5.
Soluciones ejercicios capítulo 5
Solución Ejercicio 5.1
a) Esta llamada al sistema abre el archivo datos.txt con permisos de lectura y escritura (O_RDWR).
Además sitúa el puntero de lectura/escritura al final del archivo (o_APPEND).
b) Esta llamada al sistema abre el archivo prueba con permiso de solo lectura (o_RDONLY). Si el
archivo no estaba ya creado lo crea (o_CREAT) con la máscara de modo octal 0600.
Solución Ejercicio 5.2
La llamada al sistema o el comando unlink eliminan un enlace duro, es decir, una entrada de un
directorio. En este caso como el archivo únicamente tenía un enlace duro la aplicación de esta llamada
al sistema produce la eliminación del archivo.
Solución Ejercicio 5.3
En la Figura A.6 se muestra el código C del programa ejstat que hace uso de la llamada al sistema
stat para mostrar algunos de los atributos del archivo cuyo nombre de ruta debe pasarse como argu­
mento de entrada del programa. Por ejemplo si en un intérprete de comandos de un SOBUNIX se escribe
la orden
390
Ampliación de sistemas operativos
ejstat texto1.txt
en la pantalla aparecerían algunos de los atributos del archivo con nombre de ruta relativa texto1.txt,
supuesto que dicho archivo existe en el directorio de trabajo actual.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
main(int argc, char *argv[ ] )
{
struct stat buffer;
int r;
if(argc==2)
{
r = stat(argv[l ] , &buffer);
if(r==-1) printf("\nError al ejecutar la llamada stat\n");
else
printf("\n**Información sobre el archivo
printf("Número nodo-i =
%s**\n", argv[l ] );
%:1. \n",buffer.st_ino);
printf("Número de enlaces duros =
printf("UID del propietario =
%:1.\n", buffer.st_nlink);
%:1.\n", buffer.st_uid);
printf("GID del grupo propietario =
printf("Tamaño en bytes =
%:1.\n", buffer.st_gid);
%:1.\n", buffer.st_size);
printf("Fecha y hora del último acceso =
%s\n",ctime(&buffer.st_atime));
Figura A.6- Código C del programa ejstat
Solución Ejercicio 5.4
Al escribir la orden j1o 25 wert.txt se comienza a ejecutar el programa j1o. Supóngase que a
la ejecución de dicho programa se le asocia el proceso A. En primer lugar se comprueba que el número
de parámetros (np) introducidos por la línea de comandos al invocar a j10 es igual a 3. La comprobación
es positiva los tres parámetros introducidos son j10, 25 y wert.txt.
En segundo lugar se invoca a la función atoi para convertir a número entero el segundo paráme­
tro (25) introducido por la línea de comandos. Dicho número se almacena en la posición de memoria
asociada a la variable entera x.
A continuación se invoca a la función malloc para reservar N bytes de memoria de forma dinámica
para x& (x-1) elementos de tipo carácter. x& (x-1) es el resultado de realizar la operación AND a nivel
Soluciones completas de los ejercicios
39 1
de bit entre x y x-1. Puesto que x= 25 = 1100 12 y x-1= 24 = 110002 , el resultado de la operación
AND es 1 1000 = 24.
Posteriormente se ejecuta un bucle for mientras la variable h sea menor o igual (x& (x-1) ) -2, es
decir, menor o igual a 22. En cada ejecución del bucle se asigna el carácter nulo '\o' al elemento h de la
cadena de caracteres apuntada por el puntero L.
Luego se invoca a la llamada al sistema open para abrir un archivo ya existente para leer y escribir.
El nombre del fichero es el tercer parámetro (pe [2 l ) de la orden introducida en la línea de comandos, es
decir, wert.txt. Supuesto que la llamada se ejecuta con éxito en la variable a se almacena el descriptor
del fichero.
A continuación se llama a la función try, que primero invoca a la llamada al sistema read para
leer los 15 primeros bytes (byte O a byte 14) del fichero wert.txt y almacenarlos en un espacio de
memoria cuya primera dirección está apuntada por el puntero L. A continuación muestra por pantalla los
15 caracteres leídos. De acuerdo con el contenido del fichero wert.txt mostrado en la Figura 5. 12 y
puesto que cada carácter ocupa 1 byte en la pantalla se muestra el siguiente texto:
"El sistema oper"
Cuando la función try finaliza se invoca la llamada al sistema lseek para desplazar 25 bytes a
partir de un determinado origen el puntero de lectura/escritura asociado al fichero con descriptor a. El
origen para realizar el desplazamiento queda establecido por el valor del resto de la división entera de 25
entre 2. Como el resto de dicha división es 1 lseek avanza 25 bytes desde la posición actual del puntero
de lectura/escritura. Como dicho puntero después de la última lectura se quedó apuntando al byte 15
entonces si lseek se ejecuta con éxito queda apuntando al byte 40.
A continuación se vuelve a llamar a la función try, que primero invoca a la llamada al sistema read
para leer los 15 bytes del fichero wert.txt a partir de la posición actual del puntero de lectura/escritura
(byte 40) y almacenarlos en un espacio de memoria cuya primera dirección está apuntada por el puntero
L. A continuación muestra por pantalla los 15 caracteres leídos. De acuerdo con el contenido del fichero
wert.txt y puesto que cada carácter ocupa 1 byte en la pantalla se muestra el siguiente texto:
"multiusuario y "
Finalmente, se invoca la llamada al sistema exit para finalizar la ejecución del proceso A devol­
viendo como estatus de salida para su proceso padre el valor 3.
Solución Ejercicio 5.5
El comando df proporciona información sobre la utilización del espacio en disco en los diferentes
sistemas de archivos montados en el sistema. Cuando se invoca sin opciones la primera columna de la
salida que se muestra en pantalla muestra el nombre de la partición tal como aparece en el directorio
1 dev, la segunda columna la capacidad total de la partición expresada en número de bloques de 1 KiB,
la tercera columna el número de bloques utilizados, la cuarta el número de bloques libres, la quinta
columna el porcentaje de bloques utilizados con respecto al número total de bloques y la sexta columna
el nombre de ruta del punto de montaje del sistema de archivos.
392
Ampliación de sistemas operativos
Señalar que el valor que se muestra en la tercera columna, es decir, el número de bloques utilizados
no incluye los bloques reservados por el núcleo para optimizar el funcionamiento de las rutinas que
operan sobre el disco. Típicamente el número de bloques reservados suele ser el 10% del total, aunque
este valor puede ser modificado.
A continuación se muestra, a modo de ejemplo, una posible salida del comando df:
Filesystem
1k-blocks
Used Available Use% Mount
/dev/hda2
2949060
2102856
696400
/dev/hda1
23302
2593
19506
75% 1
12% /boot
Aprovechando este ejemplo se puede comprobar que el número de bloques utilizados que se muestra
en la columna Used no incluye los bloques reservados por el núcleo. Por ejemplo para la partición
1 dev /hda2 se comprueba que 2102856+ 696400 = 2799256 que es menor que 2949060. El número de
bloques reservados por el núcleo en esta partición es igual a 2949060 - 2799256 = 149804, es decir, un
5,079% del número total de bloques.
Solución Ejercicio 5.6
El nodo-i de un archivo en un sistema UFS contiene, entre otros datos, la localización de los bloques
de datos del archivo. En concreto contiene 15 direcciones de bloques de disco de 32 bits cada. Las 12
primeras direcciones son las de los 12 primeros bloques de datos del archivo, también denominados
bloques directos. Las tres direcciones restantes localizan a un bloque de indirección simple, un bloque
de indirección doble y un bloque de indirección triple, respectivamente. En el caso de usar un tamaño de
bloque de 8 KiB, en un bloque pueden almacenarse
8 KiB
32 bits/dirección
3
21 bytes
. ,
1 .
4 bytes d1recc10n
=
.
11 .
2 direcciOnes
Con lo que el tamaño máximo de un archivo en teoría podría ser de
A.6.
Soluciones ejercicios capítulo 6
Solución Ejercicio 6.1
a) No es posible, el comando kill solo se puede usar para enviar señales a procesos no a hilos. El
envío de una determinada señal con kill afecta a todos los hilos del proceso no a un hilo concreto.
b) Para enviar señales a un hilo en Linux se puede usar la llamada al sistema tgkill o la función
pthread_kill de la librería Pthreads.
Soluciones completas de los ejercicios
393
Solución Ejercicio 6.2
a) Al contrario de lo que podría pensarse la invocación de la llamada al sistema clone con este bit
únicamente activado hace que la llamada no se ejecute con éxito y devuelva el valor -l.
b) Igual que el apartado anterior.
e) Igual que el apartado anterior.
d) La conclusión que se deduce es que si se desea usar la llamada al sistema clone para crear un
nuevo proceso ligero es necesario invocarla con los tres bits
CLONE_THREAD f CLONE_VM f CLONE_SIGHAND
activados.
Solución Ejercicio 6.3
Este comando en un sistema Linux muestra la siguiente información por cada proceso existente
en el sistema: identificador del proceso ( PID) , terminal de control (TTY) , información sobre su estado
(STAT ) , tiempo de uso del procesador (TIME) y nombre de ruta del programa (COMMAND ) cuya ejecución
ha generado el proceso. Señalar que en el caso de los hilos del núcleo en (COMMAND ) se muestra entre
corchetes el nombre de la rutina del núcleo que ejecuta.
A modo de ejemplo ilustrativo a continuación se reproducen las tres primeras líneas que muestra este
comando al ser ejecutado en un determinado sistema Linux:
PID TTY
STAT
TIME COMMAND
1 ?
Ss
0:00 /sbin/init
2 ?
S
0:00 [kthreadd)
3 ?
S
0:05 [ksoftirqd/O J
Solución Ejercicio 6.4
El comando top muestra información que se actualiza cada pocos segundos sobre el consumo de
recursos (memoria, CPU, etc) que realizan los procesos existentes en el sistema.
La salida por pantalla del comando top puede dividirse en dos partes (ver Figura A.7): la cabecera
y el listado de procesos. La cabecera consta de cinco líneas. En la primera línea se muestra, entre otras
datos, el tiempo que lleva arrancado el sistema, el número de usuarios conectados y la carga promedio.
En la segunda línea se muestra el número de tareas existentes en el sistema en los diferentes estados.
En la tercera línea se muestra información sobre el consumo de CPU. En la cuarta línea se muestra
información sobre el consumo de memoria. Finalmente en la quinta línea se muestra información sobre
el consumo de espacio en el área de intercambio.
El listado de procesos muestra varios datos sobre los procesos que se están ejecutando en el sistema,
entre ellos: su PID, el nombre del usuario al que está asociado, su prioridad, su consumo de CPU,
394
Ampliación de sistemas operativos
su consumo de memoria, su tiempo de ejecución y el nombre de ruta del programa cuyo código está
ejecutando el proceso. Señalar que el listado muestra ordenados a los procesos según su consumo de
CPU lo que puede resultar muy útil al administrador del sistema para detectar a aquellos procesos que
realizan un consumo excesivo de CPU.
top - 16:42:06 up 6 days,
Tasks: 168 total,
Cpu(s): 98.7%us,
7:11,
2 users,
load average: 11.06, 10.97, 9.16
4 running, 163 sleeping,
1.3%sy,
0.0%ni,
O.O%id,
O stopped,
O.O%wa,
1 zombie
O.O%hi,
Mero:
508000k total,
469740k used,
38260k free,
Swap:
522236k total,
44048k used,
478188k free,
O.O%si,
131824k cached
PID USER
PR
NI
VIRT
RES
SHR S
!!CPU
!IMEM
19330 josema
20
O
1700
248
196 R 17.6
0.0
4:10.24 ejemplo6_2
TIME+
COMMAND
19340 josema
20
O
1700
248
196 R 17.6
0.0
4:03.86 ejemplo6_2
19183 josema
20
O 10132
296
232 R
9.0
0.1
4:14.83 ejemplo6_1
19226 josema
20
O 10132
276
216 S
9.0
0.1
3:24.67 ejemplo6_1
19313 josema
20
O 10132
276
216 S
9.0
0.1
2:07.49 ejemplo6_1
19126 josema
20
O 10132
280
216 S
8.6
0.1
11:10.58 ejemplo6_1
19146 josema
20
O 10132
276
216 S
8.6
0.1
5:25.16 ejemplo6_1
19195 josema
20
O 10132
276
216 S
8.6
0.1
3:47.49 ejemplo6_1
19251 josema
20
O 10132
280
216 S
8.6
0.1
2:43.87 ejemplo6_1
20
O 76488
46m 7236 S
1.7
9.4
6:05.50 Xorg
1061 root
O.O%st
19184k buffers
1502 josema
20
O 95040
14m
10m S
1.0
3.0
1:37.97 gnome-terminal
1407 josema
20
O 73308
26m 6784 S
0.3
5.4
11:59.43 ubuntuone-syncd
19363 root
20
O
O
O S
0.3
0.0
0:00.32 kworker/0:1
19428 josema
20
O
2632 1168
864 R
0.3
0.2
0:00.03 top
20
O
3040 1648 1192 S
0.0
0.3
0:00.69 init
1 root
O
Figura A.7- Posible salida del comando top en un sistema Linux
Solución Ejercicio 6.5
a) La estructura de un sistema de archivos EXT2 establece que el mapa de bits de bloques de da­
tos existente en un grupo de bloques ocupa un único bloque. El tamaño de un bloque de 4 KiB
expresado en bits es igual a 32768 bits. Cada bit describe el estado de un bloque del grupo de
bloques, luego en un grupo de bloques pueden existir como máximo 32768 bloques de datos, o
equivalentemente 32 Kibloques.
Multiplicando por el tamaño de un bloque se obtiene finalmente que el tamaño máximo de un
grupo de bloques es igual a
4 (KiB/bloque)·32 Kibloques
=
128 MiB
b) El número de grupos de bloques en que se divide una partición se puede obtener dividiendo el
Soluciones completas de los ejercicios
395
tamaño de la partición por el tamaño de un grupo de bloques determinado en el apartado anterior:
32 GiB
_
128 (MiB/grupo)
- 256 grupos
e) El número de nodos-i que se pueden almacenar en un bloque se determina dividiendo el tamaño
de un bloque por el tamaño de un nodo-i, el cual de acuerdo a la sección 6.6.2 es igual a 128 bytes:
4 (KiB/bloque)
128 (B/nodo)
_
- 32 (nodos/bloque)
d) El nodo-i de un archivo en un sistema EXT2 contiene, entre otros datos, la localización de los
bloques de datos del archivo. En concreto contiene 15 direcciones de bloques de disco de 32 bits
cada. Las 12 primeras direcciones son las de los 12 primeros bloques de datos del archivo, también
denominados bloques directos. Las tres direcciones restantes localizan a un bloque de indirección
simple, un bloque de indirección doble y un bloque de indirección triple, respectivamente. En el
caso de usar un tamaño de bloque de 4 KiB, en un bloque pueden almacenarse
4 KiB
32 bits/dirección
212 bytes
--=---- =
---
4 bytes/dirección
210 direcciones
Con lo que el tamaño máximo de un archivo en teoría podría ser de
A.7.
Soluciones ejercicios capítulo 7
Solución Ejercicio 7.1
a) Esta orden almacena en el archivo listado. txt la salida del comando dir, el cual muestra
información sobre el contenido (archivos y subdirectorios) del directorio de trabajo actual. Señalar
que si el archivo no estaba creado entonces con esta orden se crea. Por otra parte si el archivo ya
estaba creado la información se almacena desde el comienzo del archivo por lo que su contenido
previo se borra.
b) Esta orden utiliza una tubería' 1' para pasar la salida del comando dir como entrada del comando
find 1 I listado El comando dir muestra información sobre el contenido (archivos y sub­
directorios) del directorio de trabajo actual. Por su parte el comando find 1 I 1 istado busca
en la entrada pasada aquellas líneas que contengan la cadena "listado" sin discriminar entre
mayúsculas y minúsculas (opción /I). Si encuentra alguna línea que contenga la palabra buscada
la muestra en la pantalla.
11
11•
11
11
e) Esta orden borra en el directorio de trabajo actual todos los archivos con la extensión . txt.
396
Ampliación de sistemas operativos
Solución Ejercicio 7.2
Se debe escribir la orden
attrib +R +H tabla.txt
Solución Ejercicio 7.3
El byteO de la cabecera del bloque tiene el valor 7 7 lo que significa que no es el último bloque de la
cadena de bloques de memoria. Los bytes 1 y 2 contienen el valor O O o O lo que significa que es un bloque
ocupado y que su puntero al bloque PSP esO. Finalmente los bytes 3 y 4 contienen el valor 0003 lo que
significa que el bloque contiene tres parágrafos.
Solución Ejercicio 7.4
a) En un sistema FAT- 12 se utilizan 12 bits para direccionar un cluster, luego el número total de
clusters que puede tener un volumen es 212 . Multiplicando el número de clusters por el tamaño de
un cluster y por el tamaño de un sector se obtiene el tamaño del volumen:
25
212 (clusters)·24 (sectores/cluster)-29 (bytes/sector) = 2 bytes = 32 MiB
b) En un sistema FAT- 12 la tabla de asignación de archivos tiene una entrada por cada cluster exis­
tente en el volumen, luego de acuerdo con el apartado anterior tendrá 212 entradas. Por otra parte
cada entrada debe ser capaz de almacenar la dirección de un cluster luego debe tener un tamaño
mínimo de 12 bits. El tamaño de la tabla de asignación de archivos de un sistema FAT- 12 se obtiene
multiplicando el número de entradas de la tabla por el tamaño de una entrada:
2
12
(entradas)· 12 (bits/entrada) = 48 Kib = 6 KiB
Solución Ejercicio 7.5
a) En un sistema de archivos FAT- 12 se utilizan 12 bits para especificar la dirección de un cluster.
Luego el espacio posible de direcciones consta de 212 = 4096 direcciones. Sin embargo, no todas
las direcciones se encuentran disponibles para especificar los siguientes clusters donde se alojan los
datos de un archivo. De acuerdo con la sección 7.6. 1 siete direcciones (FFO- FF6) están reservadas
para clusters utilizados por estructuras del sistema de archivos, una dirección (FF7) está reservada
para especificar que un cluster está defectuoso, una dirección (000) está reservada para especificar
que un cluster está libre y 8 direcciones (FF8-FFF) están reservadas para especificar el final de un
archivo o directorio.
Luego hay un total de 17 direcciones reservadas, lo que dejaría un total de 4096 - 17 = 4079
direcciones disponibles para especificar los siguientes clusters donde se alojan los datos de un
archivo.
Soluciones completas de los ejercicios
397
Por lo tanto, un archivo como máximo puede ocupar 4080 clusters, el cluster del primer bloque,
que se direcciona en la entrada del directorio asociada al archivo, y 4079 en la FAT. Como cada
bloque ocupa 2 KiB, el tamaño máximo que puede tener un archivo es:
4080·2 KiB = 8 160 KiB = 7,97 MiB
b) En un sistema FAT- 12 una entrada de un directorio ocupa 32 bytes. El número de entradas de
directorio que caben en un cluster de 2 KiB se calcula de la siguiente forma:
2 (KiB/cluster)
211 (bytes/cluster)
= s
= 64 (entradas/cluster)
32 (bytes/entrada)
2 (bytes/entrada)
e) El número de segundos que tiene un día se calcula de la siguiente forma:
24 (horas/dia)·60 (minutos/hora)·60 (segundos/minuto)
=
86400 segundos
En la sección 7.6.2 se indica que el campo hora de una entrada de un directorio tiene un tamaño de
2 bytes = 16 bits, con los cuales se pueden codificar 216 = 65536 segundos. La precisión se puede
determinar de la siguiente forma:
ceil
A.S.
( �����)
= ceil(l,32) = 2 segundos
Soluciones ejercicios capítulo 8
Solución Ejercicio 8.1
a) La prioridad base de un proceso Pbp es función de la clase de planificación a la que pertenece el
proceso. Por defecto la prioridad base de un proceso que pertenece a la clase de planificación alta
es Pbp = 13.
b) La prioridad base de un hilo Pbh es función de la clase de planificación a la que pertenece el proceso
al que está asociado el hilo y de la prioridad relativa del hilo Pr respecto a Pbp· Cuando la prioridad
relativa Pr se configura al valor debajo de normal (Pr = - 1) entonces la prioridad base del hilo se
calcula mediante la siguiente expresión:
Pbh = Pbp+ Pr
Sustituyendo valores en la expresión anterior y operando se obtiene finalmente que
Pbh = 13 - 1 = 12
e) Por defecto la prioridad actual del hilo Pa es igual a la prioridad base del hilo Pbh· Luego de
acuerdo con el apartado anterior Pa=12.
398
Ampliación de sistemas operativos
Solución Ejercicio 8.2
a) Esta orden crea en el directorio de trabajo actual un enlace duro de nombre enlacel. txt al
archivo \trabajo\listado.txt.
b) Esta orden crea en el directorio de trabajo actual un enlace simbólico de nombre fotos al direc­
torio e: \imagenes\fotos\camara.
Solución Ejercicio 8.3
La siguiente secuencia de órdenes en un intérprete cmd.exe de Windows permite ilustrar que un
archivo en NTFS puede constar de múltiples flujos de datos:
echo Este es el primer flujo de datos del archivo > prueba.txt
echo Este es el segundo flujo de datos > prueba.txt:flujo2.txt
notepad prueba.txt
notepad prueba.txt:flujo2.txt
Solución Ejercicio 8.4
La información relativa a la localización de las series del atributo de datos del archivo que se al­
macena en la entrada asociada al archivo en la MFT del volumen es la que se muestra en la siguiente
tabla:
Cluster Virtual Bv
Cluster Lógico BL
Número de clusters N
o
3
7
9
61
90
85
1 12
3
4
2
1
Solución Ejercicio 8.5
La información relativa a la localización de las series del atributo de datos del archivo que se al­
macena en la entrada asociada al archivo en la MFT del volumen es la que se muestra en la siguiente
tabla:
Cluster Virtual Bv
Cluster Lógico BL
Número de clusters N
o
8
16
32
40
40
o
50
95
o
8
8
16
8
8
Soluciones completas de los ejercicios
399
Señalar que las entradas con BL = O indican que los clusters virtuales correspondientes no tienen
asignado espacio físico puesto que han desaparecido al ser comprimidos. Windows necesita mantener
esta información para poder realizar la descompresión del archivo.
Solución Ejercicio 8.6
Entre las herramientas software más conocidas para analizar el funcionamiento y el rendimiento del
sistema operativo Windows se encuentran las siguientes:
•
•
•
Herramientas que se distribuyen conjuntamente con Windows. Como el administrador de tareas,
el monitor de recursos y el control de servicios.
Herramientas de depuración para Windows (debugging tools for Windows) de Microsoft. Como el
depurador del núcleo o la lista de tareas.
Herramientas de Windows Sysinternals. Como el explorador de procesos y el monitor de procesos.
Bibliografía
[Bach,
1986] J. M. Bach, The Design of the UNIX Operating System, Prentice-Hall, 1986.
[Bonwick, 1994] J. Bonwick. The Slab Allocator: An Object-Caching Kernel Memory Allocator,
Proceedings of the Summer 1994 USEN/X Technicaleonference, Jun. 1994, pp. 87-94.
[Bovet y Cesati,
O'Reilly, 2005.
[Cooper,
2005] D. P. Bovet y M. Cesati, Understanding the Linux Kernel (3rd Edition),
2002] J. Cooper, Special Edition Using MS-DOS 6. 22 (3rd Edition), Que, 2002.
[Cormen et al.,
2009] T. H. Cormen, C. E. Leiserson, R. L. Rivest y C. Stein, Introduction to
Algorithms (9th Edition), MIT Press, 2009.
[Díaz et al., 201 1] J. M. Díaz, D. Chaos, R. Muñoz y J. Aranda, Fundamentos Básicos de los
Sistemas Operativos, Sanz y Torres, 20 11.
[Dijkstra, 1965] E. Dijkstra, "Co-operating Sequential Processes", Programming Languages, Aca­
demic Press, 1965.
[Duncan,
1988.
1988] R. Duncan, MS-DOS Encyclopedia: Versions 1. 0 Through 3. 2, Microsoft Press,
[Duncan, 1988b] R. Duncan, Advanced MS-DOS Programming: The Microsoft Guide for As­
sembly Language ande Programmers, Microsoft Press, 1988.
[Gottfried,
[Hart,
2005] B. S. Gottfried, Programación ene (2° Edición), McGraw-Hill, 2005.
2010] J. M. Hart, Windows System Programming (4th Edition) (Addison-Wesley Microsoft
Technology Series), Addison-Wesley, 2010.
[Kemighan y Ritchie,
Prentice Hall, 199 1.
1991] B. W. Kernighan y D. Ritchie, El Lenguaje de Programación e,
[Love, 2010] R. Love. Linux Kernel Development (3rd Edition), Addison-Wesley Educational Pu­
blishers Inc, 20 10.
401
402
Ampliación de sistemas operativos
[Love et al.,
2005] P. Love, J. Merlino, C. Zimmerman, J. C. Reed y P. Weinstein. Beginning Unix
(Programmer to Programmer), Wiley, 2005.
[Márquez,
2004] F. Márquez, UNIX. Programación Avanzada (3° Edición), Ra-Ma, 2004.
[Mathur et al., 2007] A. Mathur, M. Cao, S. Bhattacharya, A. Dilger, A. Tomas y L. Vivier, " The
New ext4 Filesystem: Current Status And Future Plans", Proceedings of the Linux Symposium,
vol.2, pp.2 1-33, junio 2007, Ottawa, Ontario (Canada).
[Mauerer,
2008.
2008] W. Mauerer, Professional Linux Kernel Architecture, John Wiley & Sons Ltd,
[McDougall y Mauro,
Hall, 2006.
[McHoes y Flynn,
2006] R. McDougall y J. Mauro, Solaris Internals, 2nd Edition, Prentice
2010] A. McHoes e l. M. Flynn, Understanding Operating Systems (6th Edi­
tion), Course Technology, 20 10.
[Podanoffsky,
1994] M. Podanoffsky, Dissecting DOS: A Code-Level Look at the DOS Operating
System, Addison-Wesley, 1994.
[Richter y Nasarre,
2007] J. M. Richter y C. Nasarre, Windows via C/C++ (Pro - Developer),
Microsoft Press, 2007.
[Ritchie y Thompson,
1974] D. M. Ritchie y K. Thompson, "The UNIX Timesharing System",
Communications of the Association for Computing Machinery, vol. 17, pp. 365-375, julio 1974.
[Russinovich et al.,
2009] M. Russinovich, D. A. Solomon y A. Ionescu, Windows@ Internals:
Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer), Microsoft
Press, 2009.
[Silberschatz et. al, 2002] A. Silberschatz, P. B. Galvin y G. Gagne, Sistemas Operativos (6a
Edición), Limusa Wiley, 2002.
[Stallings, 2005] W. Stallings, Sistemas Operativos: Aspectos Internos y Principios de Diseño (5a
Edición), Pearson Educación, 2005.
[Tanenbaum,
2009] A. S. Tanenbaum, Sistemas Operativos Modernos (3° Edición), Pearson­
Prentice Hall, 2009.
[Vahalia,
1995] U. Vahalia, UNIX Internals: The New Frontiers, Prentice Hall, 1995.
,
Indice alfabético
A
Á rea
Administrador
de memoria, 328
de objetos, 3 1 1
Afinidad del procesador, 324
de intercambio, 174
de programas transitorios, 28 1, 286
de usuario, 5 1
Arena, 286
Array
de descriptores de página, 253
de referencias a estructuras anon, 157
Asignación índice, 348
Asignador
a nivel de página, 172
de la memoria del núcleo, 172, 178
slab, 179, 258
Atributo
no residente, 345
residente, 345
Atributos del archivo, 189, 289
AIX, 4, 5
Alarm, 68
Alarmas, 68
Algoritmo
buddy, 254, 257
CFS, 248
del último ajuste, 286
del mejor ajuste, 286
del primer ajuste, 286
del reloj con dos manecillas, 169
LRU, 169, 18 1
PFRA, 259
Alias, 13
Almquist shell, 8
Apuntador, 14
Á rbol
de directorios, 289
rojo-negro, 249
Archivo
binario, 188
de registro, 343
mapeado en memoria, 149
ordinario, 188
regular, 188
de páginas, 339
de solo-añadir, 267
inmutables, 267
B
Base de datos del distribuidor, 322
Bind, 224
BIOS, 276
Bit pegajoso, 28
Bloque
de arranque, 264
de control del archivo, 287, 349
de control del flujo, 349
de control del proceso, 3 15
EPROCESS, 315
ETHREAD, 3 16
KPROCESS, 315
KTHREAD, 3 15
W32PROCESS, 315
403
404
Ampliación de sistemas operativos
W32THREAD, 3 16
Bloques buddies, 258
Bloques directos, 2 10, 392, 395
Bonus, 247
Bourne shell, 8
Bourne-Again shell, 8
Brk, 145
BSD, 3
BSD 4.3, 96
Buffering, 294
Buffers índices, 348
Clone, 239
Clase, 193
CloseHandle, 339
Cluster, 290, 341
Código
de finalización o retorno, 284
reentrante, 1 10
Colas
de prioridad, 95
de mensajes, 1 19, 124
de tareas activas, 243
hash, 2 12
e
Com, 283
e shell, 8
Comando
Caché
externo, 14
de búsqueda de nombres en directorios, 262
interno, 14
de buffers de bloques de disco, 2 19, 294
Command.com, 279
de nombres en directorios, 208
Comodines, 11
de páginas, 220
Conectores, 135, 222
del sistema, 305
Conjunto de trabajo de un proceso, 335
Callouts, 96
Connect, 224
Cambios de contexto, 94
Contexto hardware salvado, 5 1
Canal
Copiar a l escribir, 62, 148, 156, 160
de dormir, 1 16
Copy_process(), 240
de espera, 1 16
CP/M, 274
Capa
Creat, 192
anónima, 157
Create, 198
H AT, 164
CreateDirectory, 340
nodo virtual/sistema de archivo virtual, 24, 202 CreateFile, 339
swapfs, 174
Credenciales, 50
V FS, 262
Cuotas, 68, 10 1
Cerrojo, 1 1 1
D
Cerrojo
exclusivo, 1 13
Datagrama, 223
lector 1 escritor, 1 13
Dato de reanálisis, 343
mutex, 1 13
DeleteFile, 340
Chdir, 196
Demanda de página, 328
Chown, 28
Demonio de páginas, 170
Clases de planificación, 95, 247
Descriptor
de archivo, 24, 190
Claves raíz, 308
Cliente X, 19
de direcciones virtuales, 33 1
Índice alfabético
de grupo, 264
de nodo, 254
de página, 253
de zona, 254
del objeto, 3 1 1
del proceso, 234
Despachador de llamadas al sistema, 308
Despertar, 1 16
Df, 201
Diario, 267
Diario de cambios, 343
Directorio
de páginas, 332
de páginas global, 256
Dispadmin, 103
Dispositivo
cero, 2 16
nulo, 2 16
Distribuciones de Linux, 233
Distribuidor o despachador del núcleo, 323
DLL, 304
Do_fork(), 240
Dormir, 116
Driver
del dispositivo, 2 16, 220
del segmento, 153
del sistema de archivos, 340
instalable, 279, 294
residente, 276, 294
Dup, 19 1
Dup2, 19 1
E
EGID, 32
Enlaces
duros, 197, 343
simbólicos, 198
simbólicos rápidos, 267
Entorno, 60
Entorno
de escritorio, 2 1
del proceso, 16
Entradas de tamaño variable, 265
Env, 16
Ermo, 23
Escáner de paginas, 170
Espacio de nombres, 3 1 1
Estado
de un proceso, 50
no señalado, 325
señalado, 325
Estatus de salida, 63, 365
EUID, 32
Eventos, 325, 326
Excepciones, 68, 294
Exe, 283
Exec, 51, 54, 60, 159
Exit, 63, 159
Exit(), 64
Export, 16
EXT, 263
EXT2, 263
EXT3, 267
EXT4, 268
Extend, 268
Extensión de dirección física, 332
F
Factor de decadencia, 96
Fallo
de página, 144, 163, 165, 334
de página duro, 335
de página suaves, 335
de protección, 162
Fcntl, 194
FFS, 202
PIFOs, 135
Fork, 56, 159, 160, 239
Fragmentos de archivos, 268
FreeBSD, 4
Fsck, 20 1
Ftok, 1 19, 126
405
406
Ampliación de sistemas operativos
Función de envoltura o redireccionamiento, 22
Funciones del sistema, 277
G
Gestor
de archivos, 22
de control de servicios, 303
de los conjuntos de trabajo, 335
de ventanas, 22
GetFileAttributes, 340
Getpgid, 79
Getpgrp, 79
Getpid, 58
Getppid, 58
Getsid, 80
GID, 25
GNU, 4
Grupo
de hilos, 234
de procesos, 79
propietario, 28
H
Hilo de puesta de página a cero, 338
Hilos, 46
Hilos
de control, 46
de usuario, 47
del núcleo, 47, 240
HP-UX, 4, 5
1
Identificador de grupo, 25
de grupo de hilos, 236
de grupo de tareas, 235
de grupo efectivo, 32
de la clase de planificación, 100
de sesión, 80
de tarea, 235
de usuario, 25
de usuario efectivo, 32
del grupo de procesos, 79
del hilo, 235
del proceso, 50
numérico del proceso ligero, 82
Identificadores
efectivos, 32
reales, 26
Init, 64
Instrucción comprobar y configurar, 1 1 1
Intérprete de comandos, 7 , 279
Interfaz
de línea de comandos, 279
IFS, 289
Inversión de prioridad, 99
Ipcrm, 128, 133
Ipcs, 128, 133
Issig(), 73
J
Joumal, 267
K
Kill, 68, 71
Kom shell, 8
L
Ladrón de páginas, 170
Latencia de despacho, 103
Libe, 22
Librería
e estándar, 22
de enlace dinámico, 304
de hilos, 47, 76
Líder
de la sesión, 80
del grupo, 79
Link, 198
Linux, 4, 5, 232
Lista
de atributos, 345
de marcos de página activos, 259
de marcos de página inactivos, 259
de marcos de página libres, 167
Índice alfabético
de marcos en standby, 337
de marcos inicializados aO, 337
de marcos libres, 337
de marcos modificados, 337
de nodos-im libres, 212
de procesos, 236
de tareas, 236
Listas LRU, 259
Listen, 224
Llamadas
a procedimientos locales avanzados, 305
a procedimientos remotos, 328
a procedimientos remotos avanzados, 328
al sistema, 22
Llave, 308
Llave IPC, 119
Lockf, 194
Ls, 189
Lseek, 24, 148, 193
LSI, 274
M
Mac OS X, 4, 5
Mailslots, 328
Malloc, 145
Manejador
de archivo, 288
de fallos de página, 165
de la interrupción, 216, 222
de la señal, 69
de llamadas al sistema, 22
Mapa de intercambio, 174
Marcos bloqueados, 167
Máscara
de modo, 27
simbólica, 29
Mecanismos IPC, 119
Memoria
anónima, 156
compartida, 119, 129
local, 252
MINIX, 4, 5
Mkdir, 197, 198
Mkfifo, 135
Mkfs, 200
Mknod, 135
Mmap, 149
MMU, 161
Mnttab, 200
Modelo de drivers de Windows, 352
Modificadores, 279
Monitor
de procesos, 3 10
de referencia de seguridad, 3 13
Monotarea, 283
Montículo, 146
Mount, 200
MS-DOS, 274
Msgctl, 126
Msgget, 125
Msgrcv, 125
Msgsnd, 125
Mtab, 200
MULTICS, 2
Munmap, 150
Mutex, 113
Mutexes, 325
N
NetBSD, 4
Netware, 4
Nice, 95, 97, 242, 246
Nivel
de petición de interrupción, 354
de prioridad de la interrupción, 221
pasivo, 354
Nodo
índice, 204
sombra, 219
virtual, 24, 191, 203
Nodo-im, 212
Nodos de memoria, 252
407
408
Ampliación de sistemas operativos
NTFS, 341
Número
de archivo, 345
Número
de dispositivo, 2 18
de dispositivo mayor, 2 17
de dispositivo menor, 217
de secuencia, 345
o
Objeto
anónimo, 153
de archivo abierto, 24, 190
de archivo mapeado, 332
de datos, 152
del núcleo, 3 1O
dispositivo, 353
driver, 35 1, 353
sección, 328
Objetos del distribuidor, 325
Open, 24, 34, 148, 190, 193
OpenBSD, 4
OpenServer, 4
OpenSolaris, 4
p
Página anónima, 155
Paginación por demanda, 144
Paquete de petición de E/S, 35 1
Parámetros de planificación, 243
Párrafo, 286
Particionamiento dinámico, 286
Passwd, 32
Pause, 69
PEB, 3 14
PGID, 79
PID, 50
Pila
de usuario, 5 1, 146
del núcleo, 51, 53, 234, 238
Pipe, 134
Planificador
central, 247, 248
de memoria, 17 1
0(1), 242
Pmap, 8 1, 147
POSIX, 5
Primer plano, 14
Priocntl, 95, 105
Prioridad
actual del hilo, 321
base del hilo, 320
base del proceso, 320
de usuario, 105
dinámica, 245, 247
en modo usuario, 105
estática, 245
relativa del hilo, 320
Procesadores virtuales, 47
Proceso, 46
Proceso
hijo, 56
inicial, 64
intercambiador, 171
monohilo, 47
multihilo, 47
padre, 56
TSR, 284
del sistema, 240
ligero, 47
Procfs, 50
Programa
de acceso, 33
de login, 33
transitorio, 28 1
Protocolo X, 20
Prstat, 83
Ps, 8 1-83
Pseudodispositivos, 216
Pseudoterminales, 79
Psig(), 73
Índice alfabético
Pthreads, 47, 76
Ptrace, 234
Punto
de montaje, 200
de reanálisis, 343
R
Raíz índice, 348
Read, 23, 148, 193
ReadFile, 340
Readv, 224
Recv, 224
Recvfrom, 224
Recvmsg, 224
Redireccionamiento de la E/S, 12
Reemplazamiento de páginas, 168
Referencia del archivo, 345
Región de texto, 145
Regiones de memoria compartida, 146
Registro
de archivo, 345
de archivo base, 345
de estado del procesador, 222
por diario, 2 10, 267
RemoveDirectory, 340
Rename, 209
Reserva retrasada de espacio, 268
Resumen de preparados, 322
Rmdir, 197
Root, 25
Runqueue, 243
S
S5FS, 202
S_ISGID, 28
S_ISUID, 28
S_ISV TX, 28
Símbolo del sistema, 275
Sbrk, 145
Sched_setparam, 242
Sched_setscheduler, 242
Sched_yield, 245
SCO Xenix, 3
Señales, 67, 1 19, 133
Secciones, 9
Segmento, 152
Segundo plano, 14
Semáforo
binario, 1 13, 325
con contador, 114
general, 114
Semáforos, 119, 120, 325
Semctl, 12 1
Semget, 120
Semop, 120
Send, 224
Sendmsg, 224
Sendsig(), 73
Sendto, 224
Serie, 345
Servicios, 303
Servicios del sistema, 307
Servidor X, 19
Sesión, 80
Set, 15
SetCurrentDirectory, 340
SetFilePointer, 340
Setpgid, 80
Setpgrp, 80
Setpriority, 242, 246
Setsid, 80
Shell, 7
Shell script, 17
Shmat, 129
Shmctl, 130
Shmdt, 130
Shmget, 129
SID, 80
Sigaction, 69
Sigblock, 69
Sigmask, 69
409
410
Ampliación de sistemas operativos
Signal, 69
T
Sigpause, 69
Tabla
de archivo del sistema, 288
de archivos, 288
de colas de mensajes, 125
de descriptores, 3 1 1
d e descriptores de archivos, 24, 190
de descriptores de grupo, 264
de despacho, 103
de despacho de llamadas al sistema, 308
de llamadas al sistema, 22
de manejadores de archivos, 288
de montaje, 200
de nodos-i, 262
de página, 16 1
de página prototipo, 336
de procesos, 49
de conmutación, 22 1
Tarea, 233
Tareas
convencionales, 241
de tiempo compartido, 241
de tiempo real, 242
Task_struct, 234
TEB, 3 15
TENEX C shell, 8
Terminal serie, 79
Terminales emulados, 79
TGID, 236
Thread_info, 234
Tipo
del mensaje, 124
del objeto, 3 10
Top, 393
Trabajo, 14
Trampa, 22, 308
Transacciones atómicas, 343
Tuberías, 13, 1 19, 134
Tuberías
con nombre, 135
Sigsend, 68
Sigsetmask, 69
Sigsuspend, 69
Sigvec, 69
Sistema
buddy, 179
de archivos de procesos, 8 1
de archivos extendido, 263
de archivos virtual, 202, 206
de paginación, 172
de ventanas, 19
X Window, 19
Socket, 222
Solaris, 4, 5, 99
Source, 17
Spinlocks, 1 1 1, 325
Spooling, 292
Stat, 193, 194
STREAMS, 132, 135
Strsignal, 73
SUA, 304
Subárboles, 308
Subintérprete, 18
Subllave, 308
Subsistema
de administración de memoria, 144
de E/S, 2 16, 2 19, 35 1
de entorno, 304
SunOS, 4
Superbloque, 209
SuperFetch, 335
Superusuario, 25
SUS, 5
Swapfs, 174
Symlink, 198
Syscall(), 22
System V, 3
Índice alfabético
sin nombre, 134
Turno rotatorio, 245
Turnstile, 117
Type, 14
u
UID, 25
Umount, 200
Unalias, 13
Unidad de gestión de memoria, 144
UnixWare, 4
Unlink, 199
Unset, 16
V
Valor amable, 97, 246
Variable
de entorno, 16, 60
del intérprete de comandos, 15
V fork, 62, 239
V FS, 202
Violación de acceso, 33 1
V M, 152
w
Wait, 65
Wait3, 65
Wait4, 65, 234, 235
Waitid, 65
Waitpid, 65, 234, 235
Widgets, 2 1
Widgets toolkits, 2 1
Windows, 300
Windows NT, 30 1
W rite, 23, 148, 193
W riteFile, 340
W ritev, 224
X
X Toolkit Intrinsics, 2 1
Xenix, 3
Xlib, 20
z
Z shell, 8
ZFOD, 156
Zona roja, 177
Zonas, 253
411
Descargar