Está en la página 1de 38

SISTEMAS OPERATIVOS

UNIVERSIDAD DE SONSONATE
Ing. Daro Cristian Arias Jaco
Implementación de Llamadas al
Sistema en MINIX
Llamadas al sistema
• Una llamada al sistema es la forma en que un programa
solicita un servicio al kernel
• La estructura de llamadas es la interfaz entre el sistema
operativo y sus programas de aplicación

• Hay 3 tipos de llamadas en MINIX


• Una llamada de sistema es como un programa solicita un
servicio a un servidor y/o driver
• Una llamada de kernel es como un servidor o driver solicita
un servicio al kernel
• Message/IPC/Trap en MINIX es usado para
intercomunicación de procesos
Llamadas al sistema vs llamadas al kernel

• Kernel calls
• Funciones a bajo nivel proporcionadas por las tareas de
sistema para permitir a los drivers y servers hacer su trabajo
• e.j. leer un puerto de hardware para IO
• System calls
• Las llamadas de sistema de POSIX son llamadas de alto
nivel definidas por el estándar POSIX, y están disponibles
para los programas de usuario en la capa 4
• Ejemplo: read, fork, unlink…
• Los programas de usuario solo contienen llamadas de
sistema POSIX
Servidores
• Reincarnation Server (RS): responsable de la
fiabilidad de todo el sistema operativo
• Datastore Server (DS): Proporciona un
almacenamiento persistente del estado del
servidor en memoria
• Virtual Memory Server (VM): responsable de
manejar el mapeo de memoria física y virtual
• Process Management Server (PM):
responsable de crear, destruir y administrar
los procesos
Servidores
• Virtual File System Server (VFS): responsable
de proporcionar una interface unificada para
todos los sistemas de archivos en el sistema
• Peripheral Component Interconnect Server
(PCI): Permite a los drivers de los dispositivos
acceder a dispositivos en el bus PCI
• Internet Network Server (INET): Responsable
de la implementación de los protocolos de red
Drivers (Controladores)
• Terminal Driver (TTY): es responsable de la operación de la
consola
• Teclado/pantalla
• Serial: cable serial
• Pseudo: OpenSSH
• Disk Driver: El driver de disco se encarga de la
lectura/escritura de bloques de disco desde y hacia el disco(s)
local
• Memory Driver: El driver del dispositivo memoria es usado
durante la carga de MINIX para servir como un sistema inicial.
Contiene archivos de configuración y programas necesarios
para iniciar MINIX
• Network Driver: MINIX soporta varios tipos de tarjetas de red.
Cada tipo esta implementado en un driver de dispositivo de red
Intercomunicación de procesos
• Es manejada por el kernel
• Un proceso envía un destinatario y un
mensaje al kernel, el cual copia el mensaje al
proceso destino
• Un proceso debe estar esperando por el
mensaje para poder recibirlo
• send
• receive
• sendrec (los procesos de usuario solo pueden
usar este)
Organización de archivos en MINIX 3

• usr/src/kernel – capa 4 (planificación, mensajes y IO)


• usr/src/drivers – capa 3 (drivers de dispositivos para discos,
consola, impresor, otros dispositivos)
• usr/src/servers – capa 2 (Administración de procesos,
sistema de archivos, otros servidores)
• usr/scr/lib – código fuente de las librerías de procedimientos
(open, read, etc)
• usr/scr/include – toda clase de archivos de cabecera
• Cada directorio tiene su propio Makefile
Llamadas al sistema (POSIX)
Llamadas al sistema (POSIX)
Ejemplo de llamada al sistema
Execve
• En el caso más general, execve tiene tres parámetros:
el nombre del archivo que se va a ejecutar, un
apuntador al arreglo de argumentos y un apuntador al
arreglo del entorno. En breve describiremos estos
parámetros. Se proporcionan varias rutinas de
biblioteca incluyendo a execl, execv, execle y execve,
para permitir la omisión de los parámetros o para
especificarlos de varias formas.
• En este caso utilizaremos el nombre exec para
representar la llamada al sistema que se invoca
mediante cada una de estas rutinas.
Ejemplo
• Consideremos el caso de un comando tal como
• cp archivo1 archivo2
• que se utiliza para copiar archivo1 a archivo2. Una vez
que el shell se ha bifurcado mediante fork, el proceso
hijo localiza y ejecuta el archivo cp y le pasa los
nombres de los archivos de origen y destino.
• El programa principal de cp (y el programa principal de
la mayoría de los otros programas en C) contienen la
siguiente declaración:
• main(argc, argv, envp)
main(argc, argv, envp)
• En donde argc es una cuenta del número de elementos en
la línea de comandos, incluyendo el nombre del programa.
Para el ejemplo anterior, argc es 3. El segundo parámetro,
argv, es un apuntador a un arreglo. El elemento i de ese
arreglo es un apuntador a la i-ésima cadena en la línea de
comandos. En nuestro ejemplo, argv[0] apuntaría a la
cadena “cp”, argv[1] apuntaría a la cadena “archivo1” y
argv[2] apuntaría a la cadena “archivo2”. El tercer parámetro
de main, envp, es un apuntador al entorno, un arreglo de
cadenas que contiene asignaciones de la forma nombre =
valor que se utilizan para pasar información, tal como el tipo
de terminal y el nombre del directorio de inicio, a los
programas
• Si exec parece complicado, no se desanime; es
(en sentido semántico) la más compleja de
todas las llamadas al sistema POSIX. Todas las
demás son mucho más simples.
• Como ejemplo de una llamada simple considere
a exit, que los procesos deben utilizar cuando
terminan su ejecución.
• Tiene un parámetro, el estado de exit (0 a 255),
que se devuelve al padre mediante statloc en la
llamada al sistema waitpid.
La API Win32 de Windows
• Windows y UNIX difieren de una manera fundamental en
sus respectivos modelos de programación.
• Un programa de UNIX consiste en código que realiza una
cosa u otra, haciendo llamadas al sistema para realizar
ciertos servicios.
• En contraste, un programa de Windows es por lo general
manejado por eventos. El programa principal espera a que
ocurra cierto evento y después llama a un procedimiento
para manejarlo.
• Los eventos comunes son las teclas que se oprimen, el
ratón que se desplaza, un botón de ratón que se oprime o
un CD-ROM que se inserta. Después, los manejadores se
llaman para procesar el evento, actualizar la pantalla y
actualizar el estado interno del programa
La API Win32 de Windows
• Desde luego que Windows también tiene
llamadas al sistema. Con UNIX, hay casi
una relación de uno a uno entre las
llamadas al sistema (por ejemplo, read) y
los procedimientos de biblioteca (por
ejemplo, read) que se utilizan para invocar
las llamadas al sistema.
• POSIX tiene aproximadamente 100
llamadas a procedimientos.
La API Win32 de Windows
• Con Windows, la situación es bastante distinta. Para
empezar, las llamadas a la biblioteca y las llamadas al
sistema están muy desacopladas. Microsoft ha definido un
conjunto de procedimientos conocidos como API Win32
(Application Program Interface, Interfaz de programación de
aplicaciones) que los programadores deben utilizar para
obtener los servicios del sistema operativo.
• Al desacoplar la interfaz de las llamadas actuales al
sistema, Microsoft retiene la habilidad de modificar las
llamadas al sistema en el tiempo (incluso de versión en
versión) sin invalidar los programas existentes.
Ejercicios
• En el siguiente ejercicio implementaremos una
nueva llamada de sistema en MINIX como parte
del servidor administrador de procesos (PM)
• La llamada consistirá en el Servidor PM
imprimiendo un mensaje y veremos como
agregarla a la librería de C para que este
disponible para programas de usuario
• El ejemplo inicialmente es simple para
comprender la estructura de las llamadas al
sistema
Pasos
• Para Implementar un llamada de sistema en MINIX necesitamos
completar los siguientes pasos
• 1. En /usr/src/servers/pm/table.c agregar la entrada a la tabla/array de
llamadas al sistema del servidor PM. Esto mapea un numero de
llamada (la posición del array) a la rutina/función en C que se
implementará
• 2. En /usr/src/include/minix/callnr.h agregar la definición de un numero
de llamada para la entrada de la tabla agregada en el paso 1
• 3. En /usr/src/servers/pm/proto.h definir el prototipo de la función de la
llamada al sistema
• 4. En /usr/src/servers/pm/ crear un archivo C que contenga la
implementación de la función definida en proto.h
• 5. En /usr/src/servers/pm/Makefile agregar el nombre del archivo C a
la lista de SRCS a compilar con el Servidor PM
1. Agregar la entrada a la tabla del servidor PM

• El archivo /usr/src/servers/pm/table.c incluye un vector llamado


call_vec para almacenar las llamadas al sistema
• Hay una entrada en la tabla por cada llamada de Sistema y la
posición en la tabla es el numero de la llamada de sistema
• Para agregar una llamada de Sistema al servidor PM,
reemplazaremos una de las entradas “unused” (sin usar) en la
tabla. Para este ejercicio, usaremos la entrada 110
• Reemplazar la línea:
• no_sys, /* 110 = unused */
• con:
• do_printmsg, /* 110 = printmsg */
2. Definir el numero de la llamada al sistema

• En el archivo /usr/src/include/minix/callnr.h se verá una lista de


definiciones de macros como la siguiente:
• #define EXIT 1
• #define FORK 2
• #define READ 3
• Esta definiciones de macros son el numero de la llamada y el
símbolo que puede ser usado en el lugar del numero de la
llamada.
• Solo necesitamos agregar la siguiente línea
• #define PRINTMSG 110
• Ahora podemos usar PRINTMSG como el nombre de la llamada al
Sistema y mapear el numero correspondiente, 110, a la entrada
do_printmsg en /usr/src/servers/pm/table.c
3. Definir el prototipo de la llamada al sistema

• Los usuarios de la llamada que estamos


creando necesitan el prototipo de la función
para que esta pueda ser invocada con
do_printmsg. El prototipo debe ser definido en
/usr/src/servers/pm/proto.h. Lo abrimos para ver
un numero de definiciones de funciones. La
agregaremos justo después de la lista de las
definiciones de misc.c
• Agregamos la siguiente definición int
do_printmsg(void);
4. Implementando la llamada al sistema

• Ahora deberemos proporcionar una implementación para la


función de la llamada al sistema do_printmsg. La
implementación inicial simplemente imprimirá un mensaje
• En /usr/src/servers/pm, agregar un nuevo archivo C
(do_printmsg.c) con el siguiente código:
• #include <stdio.h>
• int do_printmsg()
• { printf(“Mi llamada de sistema ha sido
llamada\n”);
• return 0;
• }
5. Incluir la llamada al sistema en la compilación del servidor PM

• Ahora se necesita asegurar que la nueva llamada al sistema


es compilada con el servidor PM
• Par incluirla necesitamos incluir el nombre del archivo
creado en el paso 4 al Makefile del servidor PM
• /usr/src/servers/pm/Makefile
• Simplemente agregamos el nombre del archivo de C a la
lista SRCS para compilar, como sigue:
• SRCS= main.c forkexit.c break.c exec.c time.c
alarm.c \ signal.c utility.c table.c getset.c
misc.c \ profile.c schedule.c do_printmsg.c
Compilar la llamada al sistema
• Si los pasos han sido correctos podemos compilar la llamada al
sistema e incluirla en la imagen de carga de MINIX siguiendo los
siguientes pasos
• En /usr/src/releasetools
• escribir:
• # make services
• If you do not clean/delete object (.o) files, subsequent make
services commands will take less time.
• 2. Luego escribe
• # make install
• 3. Luego reinicia con reboot
• Si lo anterior se ejecuta con éxito ya tenemos una nueva llamada
en MINIX. Aun no tenemos una librería interfaz de nivel de usuario
syscall function

• Es una función para invocar llamadas


al sistema con argumentos
específicos. Es útil, por ejemplo, para
invocar llamadas que no tienen su
respectiva función dentro de las
librerías de C
Probar la llamada al sistema
• Habiendo compilado la nueva llamada al sistema y
reiniciado, podemos usar el siguiente programa para testear
• #include <lib.h> // provides _syscall and
message
• #include <stdio.h>
• int main(void) {
• message m;
• // Minix uses message to pass parameters to a
system call
• _syscall(PM_PROC_NR, PRINTMSG, &m);
• }
¿Cómo pasar parámetros a una llamada al
sistema?

• A continuación veremos como usar los


mensajes de MINIX para pasar
parámetros a una llamada de sistema. En
lugar de solo imprimir una cadena con un
mensaje, modificaremos la llamada para
que acepte un numero entero como
parámetro e imprimir el mensaje junto con
este.
MINIX Messages
• Un mensaje es una estructura (struct)
• Hay 7 tipo de mensajes numerados del 1-8, el 6 esta obsoleto
• Todos comparten los siguientes campos:
• Int m_source /*emisorr*/
• int m_type /*tipo del mensaje; e.g. el numero de la llamada al
sistema*/
• Los otros campos dependen de cual de los 7 formatos es usado
• La función _syscall(who, syscallnr, &m) pone el syscallnr en
m.m_type de manera automática, así que en general las funciones
de nivel de usuario no tienen que llenar ni el tipo ni la fuente
Message type 1
• Un mensaje es un estructura definida en
/usr/src/include/minix/ipc.h. La estructura
contiene la unión de los tipos de mensajes
• Para nuestro propósito solo estamos
interesados en mensajes del tipo 1 (mess_1).
Este tiene campos miembros que nos permiten
pasar hasta 3 enteros como parámetro o hasta
3 punteros
Cómo funciona el paso de
mensajes?
• La declaración:
• message m; // Minix uses message to pass parameters to a
• system call
• Declara un mensaje, la dirección del mensaje en el proceso que lo
llama es pasado al kernel (como resultado de la llamada de
syscall)
• El kernel entonces copia el mensaje al proceso receptor final (PM
en este caso). En el proceso que recibe, el mensaje esta
disponible como una variable global m_in. Eso significa que, el
mensaje esta disponible como m_in en el cuerpo de la función
do_printmsg. En la implementación actual aun no hemos
establecido valores a los campos del mensaje ni tampoco los
usamos en el proceso receptor.
Pasar parámetros a través de un
mensaje
• Para pasar un parámetro de un numero entero, se debe
asignar a un campo del mensaje (en este caso el archivo
ipc.h ayuda a conocer los miembros de mess_1)
• Por ejemplo:
• m.m1_i1 = 10;
• Esto pasaría 10 como el primer parámetro entero en un
campo del mensaje a la llamada al sistema
• Ahora modificaremos el código del programa para realizar
las pruebas
Código nuevo de prueba
• #include <lib.h> // provides _syscall and message
• #include <stdio.h>
• #include <stdlib.h> // provides atoi
• int main(int argc, char **argv) {
• if (argc < 2)
• exit(1); // expecting at least 1 integer parameter to test program
• int i = atoi(argv[1]);
• message m; // Minix uses message to pass parameters to a system call
• m.m1_i1 = i; // set first integer of message to i
• _syscall(PM_PROC_NR, PRINTMSG, &m);
• /* _syscall leads to the system server identified by PM_PRO_NR (the
PM
• * server process) invoking the function identified by call number
• * PRINTMSG with parameters in the message copied to address &m
• */
• }
Modificando el archivo de la llamada

• La implementación modificada de
/usr/src/servers/pm/do_printmsg.c es:
• #include <stdio.h>
• #include "pm.h" // provides global variables such as m_in
• int do_printmsg() {
• int i = m_in.m1_i1; /* m_in is a global variable set to PM's
• * incoming message,
• * So m_in.m1_i1 is the integer parameter set in our
• * test program above.
• */
• printf(“MI llamada ha sido llamada, mi entero es %d\n", i);
• return 0;
• }
Correr la prueba
• En /usr/src/releasetools digitar: #make
services
• Luego digitar:
• #make install Luego reboot
• (para corer la nueva version de minix)
• Recompilar el archivo de prueba y
ejecutarlos así:
• # ./a.out 10
TAREA

• Implementar una llamada la sistema


para que retorne el PID (Process ID)
y el PPID (Parent Process ID)
• Verificar su funcionalidad a través de
las funciones nativas getpid() y
getppid()

También podría gustarte