Skip to content

Tema 3: Llamadas al Sistema (System Calls)

📝 Resumen Ejecutivo

Esta sesión establece la base de la interacción entre el software de usuario y el núcleo (kernel) del Sistema Operativo. Se explora cómo las aplicaciones utilizan APIs (POSIX/Win32) para solicitar servicios como gestión de procesos, manipulación de ficheros y comunicación. Además, se profundiza en la implementación práctica en lenguaje C (Linux) y se ofrece una taxonomía detallada para clasificar los distintos tipos de llamadas al sistema.


🔑 Conceptos Clave

  • System Call (Syscall): Mecanismo mediante el cual un programa solicita un servicio al kernel del SO.
  • [cite_start]API (Application Programming Interface): Capa de abstracción que facilita al programador el uso de syscalls sin conocer los detalles del hardware.
  • [cite_start]POSIX: Estándar de API utilizado en sistemas Linux y macOS.
  • [cite_start]Win32/Win64: API estándar para sistemas Windows.
  • [cite_start]PID (Process ID): Identificador único numérico asignado a cada proceso.
  • Fork: Llamada al sistema fundamental para crear un nuevo proceso (clonación).
  • [cite_start]Socket: Punto final de comunicación para el intercambio de datos entre procesos (TCP/UDP).
  • Pipe (|): Mecanismo IPC que redirige la salida de un proceso a la entrada de otro.

📘 Desarrollo del Temario

1. Concepto y Necesidad de las Llamadas al Sistema

Las aplicaciones de usuario no acceden directamente al hardware. [cite_start]Si un programador tuviera que gestionar manualmente las señales eléctricas del disco duro o la memoria, "cualquier pequeña aplicación ocuparía miles de líneas de código".

  • [cite_start]Función: Proporcionan una interfaz sencilla para acceder a la funcionalidad del núcleo.
  • Analogía: Funcionan como un framework. Nosotros nos apoyamos en las funcionalidades que ofrece el SO para no tener que "reinventar la rueda" en cada programa.
  • [cite_start]Implementación: Los SO modernos ofrecen APIs (como libc en Linux) que envuelven las instrucciones de bajo nivel (ensamblador/traps) en funciones de alto nivel.

Ejemplo de Abstracción: Cuando usas printf("Hola") en C, no escribes directamente en la memoria de vídeo. [cite_start]Por debajo, la librería invoca una llamada al sistema (como write en Linux) que gestiona la salida a la consola.


2. Administración de Procesos (Idea Clave 2)

[cite_start]Todo programa en ejecución es un proceso gestionado por el SO. La gestión se realiza mediante syscalls específicas, siendo la más importante en Unix/Linux el fork().

La función fork()

[cite_start]Esta función crea un proceso nuevo (hijo) que es una copia exacta del proceso actual (padre), compartiendo el mismo código pero con distinto PID.

¡OJO AL DATO! (Punto crítico de examen) La distinción entre padre e hijo se hace mediante el valor de retorno de fork():

  • Al Padre: fork() le devuelve el PID del hijo (un número entero \(> 0\)).
  • [cite_start]Al Hijo: fork() le devuelve 0.

Código de Ejemplo analizado en clase:

#include <unistd.h>
#include <stdio.h>

int main() {
    int pid = fork(); // Se clona el proceso aquí

    if (pid != 0) {
        // Bloque del PADRE
        printf("Soy el padre %d\n", getpid());
    } else {
        // Bloque del HIJO
        printf("Soy el hijo %d\n", getpid()); // Devuelve 0
    }
    return 0;
}
  • Comportamiento: Ambos procesos se ejecutan de forma concurrente (casi simultánea). El orden de salida no siempre está garantizado, depende del planificador del SO.

3. Administración de Ficheros (Idea Clave 3)

El manejo de archivos requiere syscalls para abrir, leer, escribir y cerrar flujos de datos.

  • [cite_start]Flujo estándar: fopen (abrir) fgets/fputs (leer/escribir) fclose (liberar recursos).
  • Modos de apertura:
    • Lectura: Abre un fichero existente.
    • [cite_start]Escritura/Append (ios_base::app): Añade contenido al final sin borrar lo anterior.

Lección Práctica (El error del buffer): En la clase se demostró que al leer un fichero, el tamaño del buffer (variable donde guardas los datos) es crítico.

  • Si declaras char cadena[20], solo leerás los primeros 19 caracteres + el carácter nulo.
  • Para leer líneas completas, debes asegurar que el buffer sea suficiente (ej. char cadena[100]).

Nota técnica sobre saltos de línea:

  • \n (Line Feed): Salto de línea estándar en Unix/Linux.
  • \r (Carriage Return): Retorno de carro. Windows suele usar la combinación \r\n.

4. Comunicación entre Procesos (IPC) (Idea Clave 4)

Los procesos a menudo necesitan coordinarse o intercambiar datos. Existen varios modelos:

A. Modelo Cliente-Servidor

  • Servidor: Proceso pasivo. [cite_start]Espera una petición (syscall listen / accept).
  • Cliente: Proceso activo. [cite_start]Inicia la comunicación (connect).
  • [cite_start]Sockets: Es el concepto abstracto que permite este intercambio.
    • [cite_start]TCP: Orientado a conexión, fiable, garantiza el orden de llegada (bidireccional).
    • [cite_start]UDP: Datagramas, no orientado a conexión, no fiable (puede perder paquetes o llegar desordenado).

B. Tuberías (Pipes)

Permiten encadenar la salida de un proceso con la entrada de otro.

Ejemplo en consola Linux: cat fichero.txt | grep "Hola" Aquí, el pipe | conecta la salida de cat (mostrar archivo) directamente a la entrada de grep (buscar texto), filtrando el resultado.

C. Memoria Compartida / Ficheros

Procesos que leen/escriben en un mismo espacio de memoria o fichero. Útil para procesos batch que esperan que un fichero cambie de estado para actuar.


5. Clasificación de Llamadas al Sistema (Taxonomía)

Basado en el documento "SOA4.docx" explicado al final de la clase.

Esta sección es vital para preguntas teóricas de clasificación.

[cite_start]1. Por Función (Lo más habitual)

  • Control de procesos: fork, exit, wait.
  • Gestión de ficheros: open, read, write.
  • Gestión de dispositivos: ioctl.
  • Información: getpid, time.
  • Comunicación: socket, pipe.

[cite_start]2. Por Semántica de Ejecución

  • Sincrónicas: El proceso se bloquea hasta que la llamada termina (ej. leer de disco).
  • Asincrónicas: La llamada retorna inmediatamente y la operación sigue en segundo plano (no bloquea).
  • Idempotentes: Si repites la llamada, el resultado es el mismo (ej. leer un dato estático).
  • Destructivas: La llamada altera o borra el estado (ej. unlink borra un fichero).

[cite_start]3. Por Modelo de Kernel

  • Monolítico (Linux): Llamadas directas al kernel (muchas syscalls).
  • Microkernel: Las "llamadas" son mensajes IPC a servidores que corren en espacio de usuario.

🧠 Preguntas de Autoevaluación

  1. En el código int pid = fork();, ¿qué valor tendrá la variable pid si estamos dentro del proceso hijo?

    • Respuesta: Tendrá el valor 0. (Si fuera el padre, tendría el PID del hijo, ej. 8833).
  2. ¿Cuál es la principal diferencia entre un Socket TCP y un Socket UDP?

    • Respuesta: TCP es orientado a conexión y fiable (garantiza entrega y orden), mientras que UDP es por datagramas, no orientado a conexión y no garantiza ni orden ni entrega.
  3. ¿Qué ocurre si una llamada al sistema es "sincrónica y bloqueante"?

    • Respuesta: El proceso que realiza la llamada detiene su ejecución y espera (se bloquea) hasta que el sistema operativo completa la tarea y devuelve el control.
  4. Si ejecuto el comando ps aux | grep root, ¿qué mecanismo de IPC estoy utilizando y para qué?

    • Respuesta: Estoy utilizando un Pipe (tubería) para pasar la lista de todos los procesos (salida de ps) al comando de filtrado (grep) para ver solo los del usuario root.
  5. Verdadero o Falso: Las APIs como POSIX obligan al programador a conocer los detalles físicos del hardware.

    • Respuesta: Falso. El objetivo de la API es proporcionar una capa de abstracción para que el programador no necesite conocer los detalles del hardware.