¿Qué es un sistema operativo?
"Un sistema operativo es como un buen mesero: si lo notás, está fallando." — anónimo, sistemas operativos.
Qué vas a aprender en este capítulo
Vas a entender qué es un sistema operativo (SO) y qué problemas resuelve. Vas a aprender la diferencia entre kernel (el corazón del SO) y todo lo demás (shell, librerías, aplicaciones). Vas a ver qué pasa cuando ejecutás ls en la terminal — y qué cambia entre eso y ejecutar print("hola") en Python. Y vas a conocer la historia: por qué los SO modernos son como son, y por qué Unix dominó tanto que sin él no existiría hoy ni Linux ni macOS ni Android.
1.1 La idea: el mesero invisible
💡 Intuición
Imaginate un restaurante caótico. Cien clientes pidiendo distintos platos al mismo tiempo. Un solo cocinero. Sin orden, sería el desastre absoluto: el cocinero ignoraría a unos, atendería tres veces a otros, los platos saldrían fríos, las cuentas mal hechas.
Ahora imaginá lo mismo con un buen mesero entre el cliente y la cocina:
- El mesero recibe los pedidos en orden.
- Decide qué pasa primero al cocinero.
- Lleva la cuenta separada de cada mesa.
- Si dos clientes piden lo mismo, los dos quedan satisfechos.
- Si un cliente quiere modificar su pedido, el mesero lo coordina.
- Si alguien intenta robar comida ajena, el mesero lo bloquea.
Eso es exactamente un sistema operativo. La cocina es el hardware (CPU, memoria, disco). Los clientes son los programas. El mesero — el SO — coordina todo, oculta el caos, y le entrega a cada programa la ilusión de ser el único cliente del restaurante.
Un sistema operativo es la capa de software entre el hardware y las aplicaciones. Su trabajo es administrar recursos, dar abstracciones útiles, y proteger a unos programas de otros.
Sin SO, cada programa tendría que saber qué CPU tenés, qué memoria, qué disco, qué impresora — y entenderse con todos los demás programas. Imposible. El SO le dice a cada programa: "yo me encargo, vos solo decime qué necesitás".
📜 Historia
Los primeros computadores (1940s-50s) no tenían sistema operativo. Cargabas tu programa en cinta perforada, lo ejecutabas, recogías el resultado en papel, y le tocaba al siguiente. Una máquina servía un programa por turno. Si tu programa fallaba, perdías el turno.
En 1956, GM y IBM crearon el primer sistema por lotes (batch monitor) para el IBM 704: un programita pequeño que cargaba programas en orden, los ejecutaba uno tras otro y descargaba resultados sin intervención humana. Fue el primer "sistema operativo".
En los 60 llegó la multiprogramación: dos programas en RAM al mismo tiempo, alternándose en la CPU. Multics (MIT, Bell Labs y GE, 1965) intentó hacerlo a gran escala — fue ambicioso, complejo, lento, parcialmente exitoso.
En 1969, Ken Thompson y Dennis Ritchie, frustrados con Multics, escribieron una versión más simple en una PDP-7 que tenían tirada en Bell Labs. Lo llamaron UNICS (un chiste sobre Multics) — después Unix.
Unix tenía:
- Un kernel pequeño y simple.
- Un shell para interactuar.
- Archivos como bytes (sin estructura impuesta).
- "Todo es un archivo" — incluso dispositivos.
- Pipes para combinar programas.
Esa filosofía — herramientas chicas que se combinan — definió la informática. Linux, macOS, BSD, Android, iOS son todos descendientes de Unix. Windows es un primo lejano (su ancestro VMS comparte autores con Windows NT).
Para aprender SO bien hoy, estudiar Unix es estudiar el 90% del territorio.
1.2 Las tres funciones del SO
📐 Fundamento
Todo SO hace tres cosas:
1. Gestor de recursos
Hay un solo CPU (o pocos). Hay 16 GB de RAM. Hay un disco. Hay decenas de programas que quieren todo eso al mismo tiempo. El SO decide quién obtiene qué y por cuánto tiempo.
- CPU: divide el tiempo en pedacitos (cuantos) y rota entre programas.
- Memoria: asigna regiones a cada programa, y le da la ilusión de tener más con memoria virtual.
- Disco: gestiona archivos, permisos, espacio.
- Dispositivos: colas para impresora, GPU, red, etc.
2. Capa de abstracción
El hardware es horrible de programar. Tu disco SSD habla en bloques de 512 bytes; tu impresora en comandos PostScript; tu placa de red en frames Ethernet. Si cada programa tuviera que saber esos detalles, programar sería imposible.
El SO te da abstracciones simples:
- Archivo: una secuencia de bytes con nombre. (Por debajo, son bloques fragmentados en distintos lugares del disco.)
- Proceso: un programa en ejecución. (Por debajo, son páginas de memoria, descriptores, registros guardados.)
- Socket de red: una "tubería" entre dos máquinas. (Por debajo, son paquetes IP, fragmentación, retransmisión.)
Tu programa pide open("archivo.txt") y listo — no le importa si está en SSD, HDD, NVMe, USB o red.
3. Aislamiento y seguridad
Sin SO, un programa podría leer la memoria de otro, sobrescribirla, robar contraseñas, dañar archivos del SO. Con SO:
- Cada proceso tiene su propio espacio de memoria, aislado del resto.
- Los permisos de archivos restringen quién lee/escribe qué.
- Los modos de ejecución (user/kernel) impiden que un programa común haga cosas peligrosas.
- Las llamadas al sistema son la única puerta para acceder al hardware — el SO valida cada una.
Sin esa función, internet no existiría: confiar en código ajeno (un sitio web, un email) sería suicida.
1.3 Anatomía: kernel, shell, syscalls
📐 Fundamento
El sistema operativo no es una sola cosa. Tiene varias capas. De adentro hacia afuera:
+----------------------------------+
| Aplicaciones (Firefox, VLC) | ← modo usuario
+----------------------------------+
| Bibliotecas (libc, glibc) | ← modo usuario
+----------------------------------+
| Llamadas al sistema (syscalls) | ← frontera
+----------------------------------+
| Kernel (gestor de recursos) | ← modo kernel
+----------------------------------+
| Drivers de dispositivos | ← modo kernel
+----------------------------------+
| Hardware (CPU, RAM, disco) |
+----------------------------------+
Kernel
El kernel es el corazón del SO. Es un programa que se carga al iniciar la computadora y queda corriendo siempre, en una región protegida de memoria.
Funciones del kernel:
- Gestionar procesos (crear, destruir, planificar).
- Gestionar memoria (asignar, proteger, paginar).
- Gestionar archivos (sistemas de archivos, permisos).
- Comunicarse con dispositivos (vía drivers).
- Servir las llamadas al sistema (syscalls).
Lo que NO es el kernel: las aplicaciones, el shell, las bibliotecas estándar, el navegador. Todos eso son programas de usuario que corren encima del kernel.
Shell
El shell es un intérprete de comandos. Es un programa más que corre encima del kernel — confundir shell con kernel es uno de los errores más comunes de principiantes.
Cuando abrís una terminal y escribís ls, lo que pasa es:
- El shell (bash, zsh, fish) recibe el texto.
- Identifica que querés ejecutar
ls. - Pide al kernel crear un nuevo proceso (
fork). - Carga el programa
/bin/ls(exec). - El proceso
lsse ejecuta y muestra los archivos. - El shell espera (
wait) a que termine. - Recibe el control de vuelta y muestra el prompt.
Distintos shells son distintos programas. Bash, Zsh, Fish, PowerShell — son intercambiables. Tu computadora puede tener varios instalados.
Syscalls (llamadas al sistema)
Es la interfaz por la que un programa común le pide al kernel que haga algo. Son las únicas puertas autorizadas:
| Syscall (POSIX) | Para qué |
|---|---|
read(fd, buf, n) |
Leer de un archivo |
write(fd, buf, n) |
Escribir |
open(path, flags) |
Abrir un archivo |
close(fd) |
Cerrar |
fork() |
Crear un proceso hijo |
exec(path, args) |
Reemplazar el proceso actual con otro programa |
wait(pid, status) |
Esperar a que un proceso termine |
mmap(addr, len, ...) |
Mapear memoria |
socket(...) |
Crear endpoint de red |
kill(pid, sig) |
Enviar señal a un proceso |
Cuando llamás print("hola") en Python, eso eventualmente llama a write(1, "hola\n", 5) (syscall write) — el kernel toma el control, escribe los bytes en la terminal, y devuelve el control.
Las llamadas a syscalls son CARAS. Implican:
- Cambiar de modo usuario a modo kernel (un cambio costoso de contexto).
- Validar parámetros.
- Hacer el trabajo.
- Volver a modo usuario.
Por eso optimizaciones como buffering (juntar varios write en uno solo) son tan valiosas. Es la razón por la que escribir 1000 caracteres uno por uno con write es 100× más lento que escribir los 1000 de una.
1.4 Modo usuario vs modo kernel
📐 Fundamento
La CPU moderna tiene (al menos) dos modos de ejecución:
| Modo | Quién corre | Qué puede hacer |
|---|---|---|
| Usuario | Aplicaciones, shell, librerías | Aritmética, leer/escribir su propia memoria, llamar syscalls |
| Kernel (a.k.a. supervisor, ring 0) | Solo el kernel | TODO: acceder hardware, modificar tablas de página, ejecutar instrucciones privilegiadas |
Por qué dos modos. Si todos los programas pudieran hacer todo, un programa malicioso (o con un bug) podría:
- Escribir directamente al disco y borrar el SO.
- Apagar la computadora.
- Leer la memoria de otros programas.
- Reprogramar el reloj.
La separación hace que un programa común NO puede hacer esas cosas. Si lo intenta, la CPU le dispara una excepción y el kernel lo termina (matá a Java con kill -9 cuando se cuelga — eso pasa por una excepción).
Cómo se cambia de modo. El modo usuario solo puede cambiar a kernel mediante:
- Llamadas al sistema (syscall) — voluntario y controlado.
- Excepciones (división por cero, acceso a memoria inválida) — involuntario.
- Interrupciones (un dispositivo avisa que terminó) — externo.
En cualquiera de los tres casos, el control salta a una dirección fija del kernel, que decide qué hacer.
Ver los modos en Linux. El comando time muestra cuánto tiempo gastaste en cada modo:
$ time find /usr -name "*.txt" > /dev/null
real 0m2.453s
user 0m0.521s ← tiempo en modo usuario
sys 0m1.873s ← tiempo en modo kernel
find recorre archivos: la mayoría del trabajo (leer directorios) es del kernel. Si un programa pasa mucho tiempo en sys, probablemente hace muchas syscalls — buen punto para optimizar.
1.5 Arquitecturas de kernel
📐 Fundamento
Hay varias formas de organizar un kernel. Los dos extremos:
Monolítico
Todo el kernel — gestión de procesos, memoria, archivos, drivers, red — está en un solo bloque ejecutándose en modo kernel.
- ✅ Rápido. Llamadas internas son llamadas a función directas.
- ✅ Simple de implementar.
- ❌ Un bug en un driver puede tumbar todo el sistema.
- ❌ Difícil de mantener cuando crece (Linux tiene ~30 millones de líneas de código).
Ejemplos: Linux, MS-DOS, FreeBSD.
Microkernel
Solo lo esencial corre en modo kernel: planificación, memoria, IPC. Todo lo demás (drivers, sistemas de archivos, red) corre como procesos de usuario que se comunican con el microkernel mediante mensajes.
- ✅ Aislamiento. Si el driver de impresora se cae, no se cae el kernel.
- ✅ Fácil de extender y verificar (kernels chicos formalmente).
- ❌ Más lento — paso de mensajes entre procesos es caro.
- ❌ Más complejo de diseñar bien.
Ejemplos: MINIX 3, L4, QNX (lo usa BlackBerry, autos).
Híbrido
Mezcla de los dos: un núcleo pequeño con varios subsistemas privilegiados.
Ejemplos: Windows NT (incluye XP, Vista, 7, 10, 11), macOS (XNU = Mach + BSD).
El gran debate
En 1992, Andrew Tanenbaum (creador de MINIX) y Linus Torvalds (creador de Linux) tuvieron un debate público en Usenet sobre si Linux era "obsoleto" por ser monolítico. Tanenbaum favorecía el microkernel; Linus prefería la simplicidad y velocidad del monolítico. Ganó la historia: Linux ganó adopción masiva. El debate sigue vivo: la academia ama microkernels, la industria usa monolíticos.
1.6 Cómo arranca una computadora
🛠️ En la práctica
Cuando prendés tu computadora, esto pasa en orden:
- POST (Power-On Self-Test). El firmware (BIOS o UEFI) en una ROM revisa el hardware: RAM ok, disco ok, teclado ok.
- Bootloader. El firmware busca un programa cargador (GRUB en Linux, Windows Boot Manager) en el disco y lo ejecuta.
- Carga del kernel. El bootloader carga el archivo del kernel (en Linux es
/boot/vmlinuz-...) en memoria y le pasa el control. - Kernel se inicia. Detecta hardware, carga drivers, monta el sistema de archivos raíz.
- Init. El kernel ejecuta el primer proceso de usuario (PID 1, históricamente
init, hoysystemden Linux). - Init lanza servicios. Servicios de fondo (cron, syslog, sshd, redes), después el gestor de login (GDM, SDDM, login en consola).
- Login. Vos te logueás. Se ejecuta tu shell o tu escritorio gráfico (GNOME, KDE).
Todo esto pasa en segundos. Y cada paso construye encima del anterior.
Comando útil: dmesg muestra los mensajes que el kernel imprimió al arrancar:
$ dmesg | head
[ 0.000000] Linux version 6.6.0 ...
[ 0.001234] CPU: Intel(R) Core(TM) i5-...
[ 0.234567] EFI: ...
Es como leer el diario de cuando despertó tu computadora.
1.7 Tipos de SO
| Tipo | Características | Ejemplos |
|---|---|---|
| Sistemas batch | Ejecutan trabajos en lote, sin interacción | OS/360 (1960s) |
| Time-sharing | Varios usuarios comparten una máquina | Unix original |
| Personal | Un usuario, una máquina | Windows, macOS, Ubuntu |
| Tiempo real (RTOS) | Garantizan respuesta en plazo | VxWorks, FreeRTOS (en autos, aviones) |
| Embebidos | Recursos limitados, propósito específico | RTOS chicos, microcontroladores |
| Distribuidos | Una "vista" de muchas máquinas | Plan 9 |
| Móviles | Optimizado para batería, táctil | Android, iOS |
| Servidor | Multi-usuario, alto throughput | Linux (Ubuntu Server, CentOS), Windows Server |
Aunque parezcan distintos, comparten la mayoría de los conceptos: procesos, hilos, memoria, archivos. Lo que cambia es el énfasis: un RTOS prioriza respuesta predecible, un SO de servidor maximiza throughput, un SO móvil cuida batería.
1.8 Aplicación práctica: medir el costo de una syscall
🛠️ En la práctica
Programa simple en C que mide cuánto tarda una syscall trivial (getpid) frente a una llamada de función normal:
#include <stdio.h>
#include <unistd.h>
#include <time.h>
int main() {
int n = 1000000;
struct timespec a, b;
long fake;
/* 1. Llamada de función normal (no syscall) */
clock_gettime(CLOCK_MONOTONIC, &a);
for (int i = 0; i < n; i++) fake = i;
clock_gettime(CLOCK_MONOTONIC, &b);
printf("Loop normal: %.2f ns/iter\n",
(b.tv_nsec - a.tv_nsec) / 1.0);
/* 2. Syscall: getpid devuelve el PID actual */
clock_gettime(CLOCK_MONOTONIC, &a);
for (int i = 0; i < n; i++) (void)getpid();
clock_gettime(CLOCK_MONOTONIC, &b);
printf("getpid syscall: %.2f ns/iter\n",
(b.tv_nsec - a.tv_nsec) / 1.0);
return 0;
}
Resultados típicos (en una máquina moderna):
Loop normal: 1.0 ns/iter
getpid syscall: 50.0 ns/iter
Una syscall trivial es ~50× más cara que una operación común. Por eso conviene agrupar trabajo: en vez de 1000 syscalls de 1 byte, una sola de 1000 bytes.
Nota: Linux moderno hace que
getpidsea súper rápida vía vDSO (un truco que evita el cambio de modo). Para una syscall "real" comoread(0, ...)el costo es mayor. La lección no cambia.
1.9 Resumen visual
| Concepto | Una línea |
|---|---|
| Sistema operativo | Software entre hardware y aplicaciones que gestiona recursos. |
| Kernel | Núcleo del SO; corre en modo privilegiado. |
| Shell | Intérprete de comandos. Es un programa, no el SO. |
| Syscall | Puerta autorizada de un programa al kernel. |
| Modo usuario | Limitado, donde corren las apps. |
| Modo kernel | Privilegiado, donde corre el kernel. |
| Monolítico | Todo el kernel en un bloque (Linux). |
| Microkernel | Kernel mínimo + servicios separados (MINIX). |
1.10 Ejercicios
✏️ Ejercicio 1.1 — Identificar capas
Para cada acción, identificá si está en modo usuario o modo kernel:
a. Sumar dos números en un programa Python.
b. Escribir un texto a un archivo.
c. Calcular el factorial recursivamente.
d. Crear un nuevo proceso con fork().
e. Mostrar la pantalla.
f. Renderizar JavaScript en el navegador.
Solución
a. Usuario.
b. Kernel (cuando llama write). El intermedio (el cálculo del texto) es usuario.
c. Usuario, salvo si imprime.
d. Kernel — fork es syscall.
e. Kernel — accede al hardware del display.
f. Mayormente usuario (V8, JIT). Pero las syscalls (DOM, red, archivos) son kernel.
✏️ Ejercicio 1.2 — Distinción shell vs kernel
Decí si cada uno es shell, kernel, biblioteca, o aplicación:
a. Bash
b. Linux
c. libc
d. Firefox
e. systemd
f. zsh
g. ps (/bin/ps)
Solución
a. Shell. b. Kernel (estrictamente; "Linux" coloquialmente refiere a la distro entera, pero el kernel se llama Linux). c. Biblioteca. d. Aplicación. e. Es PID 1, el primer proceso usuario; coloquialmente "init system". Tecnicalmente, aplicación del lado del usuario. f. Shell (alternativo a bash). g. Aplicación (un binario que pregunta al kernel sobre procesos).
✏️ Ejercicio 1.3 — Cuenta las syscalls
En Linux, la herramienta strace te muestra todas las syscalls que hace un programa. Ejecutá:
$ strace -c ls 2>&1 | tail -20
¿Cuáles syscalls aparecen más? ¿Qué hacen?
Solución
Resultado típico:
% time calls syscall
------ ---------- -----------
25.00 8 openat
18.75 5 write
12.50 3 read
10.42 2 stat
...
- openat: abrir un archivo (en este caso, varias bibliotecas y el directorio).
- write: escribir el listado en stdout.
- read: leer entradas del directorio.
- stat: obtener info de cada archivo (tamaño, permisos, timestamps).
Notá cuántas más hay de las que esperarías para un comando "simple" como ls. Eso es lo que hace el kernel cuando el SO trabaja por vos.
✏️ Ejercicio 1.4 — Arquitectura
Un equipo discute si reescribir su SO de un kernel monolítico a un microkernel. Listá:
a. Tres ventajas del cambio. b. Tres desventajas. c. ¿En qué tipo de proyecto el cambio sería buena idea? ¿En cuál no?
Solución
Ventajas:
- Aislamiento de fallos (un driver caído no tira el SO).
- Fácil de verificar formalmente (kernel chico).
- Modularidad — cargar/descargar drivers sin reiniciar.
Desventajas:
- Pérdida de rendimiento por paso de mensajes IPC.
- Mayor complejidad de implementación.
- Mayor uso de memoria (varios procesos en lugar de un kernel monolítico).
Bueno para: software crítico (autos, aviones, marcapasos) — la confiabilidad importa más que la velocidad. Sistemas embebidos.
Malo para: SO de uso general donde la velocidad es prioritaria (servidores, escritorios). Por eso Linux y Windows siguen siendo monolítico/híbrido.
1.11 Para profundizar
- Tanenbaum & Bos, Modern Operating Systems (4ª edición). Estándar absoluto del área.
- Silberschatz, Galvin, Gagne, Operating System Concepts. El "dinosaur book", con dibujos.
- Linux From Scratch (LFS). Tutorial para construir tu propia distro desde cero — la mejor forma de entender qué hay adentro.
- Documentación oficial de Linux: https://www.kernel.org/doc/html/latest/
- Próximo capítulo: Procesos e hilos — cómo el SO ejecuta múltiples programas a la vez.
Definiciones nuevas: sistema operativo, kernel, shell, syscall, modo usuario, modo kernel, kernel monolítico, microkernel, bootloader, init.