Conceptos básicos

Llamadas al sistema (System Calls)

La interfaz entre el espacio de usuario y el kernel. Diferencia entre APIs de librería y syscalls reales. El costo del cambio de contexto.

Llamadas al sistema (System Calls)

La gran mentira de C
Cuando escribes printf("Hola"), tu programa no está imprimiendo nada. Tu programa no tiene permiso para tocar la pantalla. printf es solo un intermediario burocrático que rellena un formulario y se lo entrega al kernel.

El sistema operativo es un club privado (Kernel Mode) y tus programas son clientes esperando en la puerta (User Mode). La única forma de pedir una bebida, usar el baño o salir, es a través de una lista estricta de peticiones permitidas: la Interfaz de Llamadas al Sistema.

Una System Call (o syscall) es la forma programática en la que un programa solicita un servicio al kernel.


Libc vs. Syscall: La diferencia técnica

Es vital distinguir entre una Función de Librería y una Llamada al Sistema.

1. Función de librería (User Space)

  • Son parte del lenguaje (ej. stdio.h en C).
  • Corren completamente en modo usuario.
  • Son portables (el mismo código funciona en Windows y Linux).
  • Ejemplo: fopen(), printf(), memcpy().

2. Llamada al sistema (Kernel Space)

  • Son la entrada al sistema operativo.
  • Ejecutan una instrucción de trap para saltar a modo kernel.
  • Son específicas del OS (la syscall read de Linux no es igual a ReadFile de Windows).
  • Ejemplo: open(), write(), brk().

El flujo real: Tu código llama a printf (Librería) $\to$ printf formatea el texto y llama a write (Syscall wrapper) $\to$ write ejecuta la instrucción de CPU SYSCALL $\to$ El Kernel toma el control, habla con el driver de video y pone el píxel en la pantalla.


Anatomía de una syscall

¿Qué ocurre físicamente en el procesador cuando invocas una syscall como read()? No es un JMP normal a una función.

1. Preparación de registros

El programa (o la librería C) coloca el número de la syscall en un registro específico (ej. RAX en x86-64). También coloca los argumentos en otros registros (RDI, RSI, etc.).

2. La instrucción trampolín

Se ejecuta una instrucción especial de la CPU: INT 0x80 (en sistemas viejos) o SYSCALL (en modernos). Esto dispara una Excepción (Trap).

3. Cruce de frontera (Mode Switch)

El hardware cambia el Bit de Modo de 1 (User) a 0 (Kernel). La CPU salta a la dirección del manejador de syscalls del kernel.

4. Ejecución privilegiada

El kernel verifica que los argumentos sean seguros (ej. que no intentes leer memoria que no es tuya) y ejecuta la operación.

5. Retorno

El kernel coloca el resultado (o código de error) en un registro, ejecuta la instrucción SYSRET y la CPU vuelve a modo usuario.


El costo del rendimiento (Overhead)

Hacer una llamada al sistema no es gratis. Es mucho más lento que una llamada a una función normal dentro de tu programa.

Cada vez que haces una syscall, ocurre un Cambio de Contexto (Context Switch):

  1. Se deben guardar los registros del usuario.
  2. Se invalida parte de la caché de la CPU y la TLB (Translation Lookaside Buffer).
  3. Se cambia el mapa de memoria.
Consejo de optimización
Si quieres leer un archivo de 1GB, **nunca** hagas `read` byte por byte en un bucle (`10^9` syscalls). Lee en bloques grandes (ej. 4KB o 64KB) para amortizar el costo del cruce de frontera. Esto es lo que hacen `fread` o `BufferedReader` internamente.

Clasificación POSIX

Aunque cada SO tiene sus propios nombres, el estándar POSIX (Portable Operating System Interface) define un conjunto común que sistemas como Linux y macOS respetan.

CategoríaEjemplos ClaveDescripción
Control de Procesosfork(), exec(), exit(), wait()Crear, ejecutar y terminar programas.
Gestión de Archivosopen(), read(), write(), close()Manipular datos persistentes.
Gestión de Dispositivosioctl(), read(), write()Configurar hardware (ej. cambiar resolución).
Mantenimiento de Infogetpid(), time(), sleep()Obtener datos del sistema o del proceso.
Comunicacionespipe(), shmget(), mmap()IPC (Inter-Process Communication).

Herramienta indispensable: strace

¿Cómo sabes qué syscalls está haciendo un programa cerrado (como ls o tu propio ejecutable)?

En Linux, existe una herramienta mágica llamada strace.

# Muestra todas las syscalls que hace el comando 'ls'
strace ls

Verás una salida como esta:

execve("/usr/bin/ls", ["ls"], ...) = 0
mmap(NULL, 8192, ...) = 0x7f...
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|...) = 3
getdents64(3, ...) = 2048
write(1, "archivo.txt\n", 12) = 12
close(3) = 0

Es una excelente forma de depurar por qué tu código falla sin mirar el código fuente.