Sistemas operativos modernos
bio, la información acerca de los descriptores de archivo puede guardarse en la estructura de usuario y traerse a la memoria sólo cuando el proceso esté en la memoria y pueda ejecutarse. La información contenida en la estructura de usuario incluye lo siguiente: 1. Registros de máquina. Cuando una interrupción de sistema causa un salto al kemel, se guardan aquí los registros de máquina (incluidos los de punto flotante, si se usan). 2. Estado de llamada al sistema. Información acerca de la llamada al sistema actual, in cluidos los parámetros y resultados. 3. Tabla de descriptores de archivo. Cuando se emite una llamada al sistema en la que in terviene un descriptor de archivo, este último se usa como índice para consultar esta tabla y localizar la estructura de datos en memoria (nodo-i) correspondiente a este archivo. 4. Contabilidad. Apuntador a una tabla que lleva el control del usuario y el tiempo de CPU consumido por el proceso. Algunos sistemas también mantienen aquí límites pa ra la cantidad de tiempo de CPU que puede consumir un usuario, el tamaño máximo de su pila, el número de marcos de página que puede ocupar y otras cosas. 5. Pila del kernel. Una pila fija, ufilizada por la parte de kernel del proceso. Teniendo en mente el uso de estas tablas, es fácil explicar cómo se crean procesos en UNIX. Cuando se ejecuta una llamada al sistema fork, el proceso invocador salta al kemel y bus ca una ranura libre en la tabla de procesos para que la use el hijo. Si encuentra una, copia en ese lugar (la entrada del hijo en la tabla de procesos) toda la información contenida en la entrada del padre. Luego, el proceso padre asigna memoria para los segmentos de datos y de pila del hijo y crea en ella copias exactas de los segmentos de datos y de pila del padre. La estructura de usua rio (que suele guardarse adyacente al segmento de pila) se copia junto con la pila. El segmen to de texto puede copiarse o compartirse, ya que es de sólo lectura. Ahora el hijo está listo para ejecutarse. Cuando el usuario teclea un comando, digamos Is, en la terminal, el shell crea un nuevo proceso bifurcando un clon de sí mismo. Luego el nuevo shell invoca a exec para sobrescribir su memoria con el contenido del archivo ejecutable Is. En la figura 10-9 se muestran los pasos que se dan. El mecanismo para crear un nuevo proceso en realidad es muy sencillo. Se crea una nueva ranura en la tabla de procesos y una nueva área de usuario para el proceso hijo, y se llenan en buena parte con los datos del padre. Se asigna un PID al hijo, se prepara su mapa de memoria y se le otorga acceso compartido a los archivos de su padre. Luego se preparan sus registros y es tá listo para ejecutarse. En principio, debe prepararse una copia completa del espacio de direcciones, pues la semán tica de fork estipula que ei padre y el hijo no comparten memoria. Sin embargo, copiar memo ria es costoso, por lo que todos los sistemas UNIX modernos hacen trampa: dan al hijo sus propias tablas de páginas, pero hacen que ésas apunten a las páginas del padre, sólo que marca das como de sólo lectura. Cada vez que el hijo intenta escribir en una página, hay un fallo de
RkJQdWJsaXNoZXIy MjI4NDcx