Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

Introducción a los sistemas operativos

¡Hola, Habr! Quiero presentar a su atención una serie de artículos traducidos sobre una literatura que me parece interesante: OSTEP. Este material examina a fondo el funcionamiento de los sistemas operativos similares a Unix, es decir, el manejo de procesos, varios planificadores, memoria y otros componentes similares que conforman un sistema operativo moderno. Puede ver el origen de todos los materiales aquí aquí. Por favor, tengan en cuenta que la traducción se realizó de manera no profesional (bastante libre), pero espero haber mantenido el sentido general.

Los trabajos de laboratorio sobre este tema se pueden encontrar aquí:

Otras partes:

Y también pueden visitar mi canal en Telegram =)

¡Alarma! ¡hay un laboratorio para esta lección! mira github

API del proceso

Consideremos el ejemplo de creación de un proceso en un sistema UNIX. Se realiza a través de dos llamadas al sistema. fork() y exec().

Llamada a fork()

Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

Veamos el programa que realiza la llamada a fork(). El resultado de su ejecución será el siguiente.

Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

En primer lugar, ingresamos a la función main() y mostramos una cadena en pantalla. La cadena contiene el identificador del proceso que originalmente se llama PID o identificador de proceso. Este identificador se utiliza en UNIX para hacer referencia al proceso. La siguiente instrucción será la llamada a fork(). En ese momento, se crea una copia casi exacta del proceso. Para el sistema operativo, parece que hay 2 copias de un mismo programa en ejecución, que a su vez saldrán de la función fork(). El proceso hijo recién creado (en relación con el proceso padre que lo creó) ya no se ejecutará desde la función main(). Se debe recordar que el proceso hijo no es una copia exacta del proceso padre, en particular tiene su propio espacio de direcciones, registros propios, su propio puntero a las instrucciones ejecutables y así sucesivamente. Por lo tanto, el valor devuelto al invocador de la función fork() será diferente. En particular, el proceso padre recibirá como retorno el valor PID del proceso hijo, mientras que el hijo obtendrá un valor igual a 0. A partir de estos códigos de retorno, se pueden distinguir los procesos y hacer que cada uno de ellos realice su tarea. Cabe señalar que la ejecución de este programa no está estrictamente definida. Después de dividirse en 2 procesos, el sistema operativo comienza a supervisarlos y también a planificar su trabajo. En un procesador de un solo núcleo, uno de los procesos, en este caso, el padre, continuará su trabajo, y luego el control pasará al proceso hijo. En un nuevo lanzamiento, la situación puede ser diferente.

Llamada a wait()

Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

Veamos el siguiente programa. En este programa, debido a la presencia de la llamada wait() el proceso padre siempre esperará la finalización del trabajo del proceso hijo. En este caso, obtendremos una salida de texto en pantalla estrictamente definida.

Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

Llamada a exec()

Sistemas Operativos: Tres Piezas Simples. Parte 3: API de Procesos (traducción)

Veamos la llamada exec()Esta llamada al sistema es útil cuando queremos ejecutar un programa completamente diferente. Aquí invocaremos execvp() para iniciar el programa wc, que es un programa de conteo de palabras. ¿Qué ocurre cuando se llama a exec()? A esta llamada se le pasan como argumentos el nombre del archivo ejecutable y algunos parámetros. Después, se cargan el código y los datos estáticos de este archivo ejecutable, sobrescribiendo su propio segmento de código. Las otras áreas de memoria, como la pila y el montón se reinicializan. Posteriormente, el sistema operativo simplemente ejecuta el programa, pasándole un conjunto de argumentos. Así, no hemos creado un nuevo proceso; simplemente hemos transformado el programa actualmente en ejecución en otro programa en ejecución. Después de realizar la llamada a exec() en el proceso hijo, parece que el programa original nunca se inició.

Esta complejidad en el arranque es absolutamente normal para el shell de Unix y permite que este shell ejecute código después de la llamada fork(), pero antes de la llamada exec(). Un ejemplo de tal código podría ser la configuración del entorno del shell según las necesidades del programa que se va a ejecutar, antes de su lanzamiento directo.

Shell — es simplemente un programa de usuario. Muestra una línea de invitación y espera a que escribas algo. En la mayoría de los casos, si escribes el nombre de un programa, el shell encontrará su ubicación, invocará el método fork(), y luego, para crear un nuevo proceso, llamará a uno de los tipos de exec() y esperará su ejecución utilizando la llamada wait(). Cuando el proceso hijo finaliza, el shell regresa de la llamada wait() y muestra nuevamente la línea de invitación, esperando la entrada del siguiente comando.

La separación de fork() & exec() permite al shell hacer lo siguiente, por ejemplo:
wc file > new_file.

En este ejemplo, la salida del programa wc se redirige a un archivo. La forma en que el shell logra esto es bastante simple: al crear el proceso hijo antes de la llamada exec(), el shell cierra el flujo de salida estándar y abre el archivo new_file, de este modo, toda la salida del programa que se ejecute posteriormente wc será redirigida al archivo en lugar de a la pantalla.

Unix pipe se implementan de manera similar, con la diferencia de que utilizan la llamada pipe(). En este caso, el flujo de salida del proceso se conectará a la cola pipe, ubicada en el núcleo, a la que también se unirá el flujo de entrada de otro proceso.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster