macOS no ejecuta dos kernels: así combina XNU las arquitecturas Mach y BSD

Debajo de Finder, Safari, Terminal y cualquier aplicación que se ejecute en un Mac está XNU, el kernel de macOS. A menudo se explica como una combinación de Mach y BSD, lo que puede llevar a una conclusión equivocada: el ordenador no mantiene dos kernels independientes funcionando simultáneamente. XNU es un único kernel híbrido que integra componentes procedentes de Mach y BSD dentro del mismo espacio de direcciones del kernel, una arquitectura que Apple mantiene desde los orígenes de Mac OS X.

Las claves de XNU en 30 segundos

  • macOS utiliza un único kernel híbrido llamado XNU, no dos kernels ejecutándose simultáneamente.
  • Mach aporta mecanismos como tareas, hilos, memoria virtual y comunicación entre procesos mediante IPC.
  • BSD proporciona buena parte de la interfaz Unix, incluidos procesos POSIX, sistema de archivos, sockets y numerosas llamadas al sistema.
  • Ambos componentes funcionan dentro del mismo espacio del kernel para evitar el coste de una arquitectura de microkernel pura.
  • El propio código abierto de XNU permite observar tablas específicas para Mach traps y llamadas Unix.

La distinción no es simplemente académica. Entender cómo se organiza XNU ayuda a interpretar perfiles de rendimiento, mecanismos IPC (Inter-Process Communication), servicios XPC, problemas de planificación, trazas y determinados kernel panics.

También permite explicar por qué macOS puede comportarse como un sistema Unix desde el punto de vista de un desarrollador mientras conserva conceptos procedentes de Mach bajo esa interfaz.

Apple describe oficialmente XNU como un kernel basado en el diseño del microkernel Mach pero que incorpora funcionalidades BSD. La propia compañía advierte de que XNU no es técnicamente una implementación de microkernel, precisamente porque buena parte de esas piezas están integradas directamente dentro del kernel por razones de rendimiento.

Mach y BSD viven dentro del mismo kernel

Mach nació en la Universidad Carnegie Mellon durante los años ochenta y planteaba una arquitectura basada fuertemente en comunicación mediante mensajes.

Conceptos como tasks, threads, ports y messages continúan siendo importantes dentro de XNU.

Una task representa, simplificando, un entorno de ejecución con su espacio de direcciones y recursos asociados. Los threads son las unidades que ejecutan instrucciones dentro de ese contexto.

Los Mach ports funcionan como endpoints de comunicación y constituyen una pieza básica del sistema IPC.

El código actual de XNU conserva claramente esta arquitectura. Su tabla de Mach traps incluye operaciones relacionadas con memoria virtual, puertos, semáforos, tareas, temporizadores y mensajería. Entre ellas aparecen mach_msg_trap, mach_msg2_trap, thread_self_trap, task_self_trap, semaphore_wait_trap o diferentes operaciones sobre Mach ports.

La implementación actual muestra además cómo XNU sigue evolucionando.

El código de Apple marca mach_msg_trap() como una interfaz que terminará desapareciendo de macOS y presenta mach_msg2_trap() como su alternativa moderna, con soporte para mensajes vectorizados y Control-Flow Integrity (CFI).

BSD aporta otra parte de la personalidad que observa normalmente un desarrollador.

Las interfaces Unix relacionadas con procesos, descriptores de archivos, sockets, señales y buena parte de POSIX proceden de esta parte de la arquitectura.

Por eso una aplicación puede utilizar llamadas familiares como read(), open() o close() sin necesitar conocer la infraestructura Mach que existe en otros niveles del sistema.

Por qué Apple no utiliza un microkernel Mach puro

Una implementación clásica de microkernel intenta mantener dentro del kernel únicamente los mecanismos mínimos y desplazar numerosos servicios a procesos separados en espacio de usuario.

La separación tiene ventajas arquitectónicas, pero introduce costes.

Si diferentes componentes necesitan comunicarse continuamente mediante mensajes atravesando fronteras de protección, aumenta el número de cambios de contexto y operaciones IPC.

Apple explica que precisamente este problema de rendimiento influyó en la arquitectura de XNU.

En lugar de ejecutar BSD como un servidor completamente separado sobre un Mach mínimo, la funcionalidad BSD se incorporó al kernel junto con Mach. De esta forma ambos pueden interactuar dentro del mismo espacio de direcciones.

Por eso describir XNU como «Mach con BSD encima» puede servir como primera aproximación histórica, pero resulta incompleto para explicar la implementación actual.

No existen un kernel Mach y otro BSD independientes que deban intercambiar mensajes para cada operación.

Existe XNU.

Dentro de XNU conviven subsistemas con orígenes, abstracciones e interfaces diferentes.

Esta decisión es precisamente lo que convierte a XNU en un kernel híbrido.

Qué ocurre realmente cuando una aplicación llama a read()

Aquí aparece otro matiz importante respecto a algunas explicaciones habituales de macOS.

Una llamada como:

read(fd, buffer, size);

no necesita convertirse automáticamente en un mensaje Mach para que un hipotético servidor BSD separado la procese.

La llamada entra en la interfaz Unix de XNU y puede atravesar componentes BSD, VFS y los subsistemas correspondientes del kernel. Mach proporciona infraestructuras fundamentales utilizadas por el conjunto del sistema, pero BSD y Mach no están separados mediante una frontera de espacio de usuario que cada syscall deba atravesar.

Esta diferencia es precisamente una de las razones por las que Apple fusionó ambas arquitecturas.

XNU sí distingue entre llamadas Unix y Mach traps.

El propio código fuente contiene una tabla específica denominada mach_trap_table. Apple advierte en ella de que determinados números están reservados para Unix, mientras el resto de entradas corresponden a las diferentes operaciones Mach.

Entre estas últimas se encuentra mach_msg2_trap, utilizada para la comunicación mediante mensajes, además de operaciones sobre memoria, puertos y sincronización.

Esto significa que un proceso macOS puede interactuar con el kernel a través de diferentes familias de interfaces dependiendo de la operación realizada.

Pero no significa que cada syscall BSD tenga que convertirse posteriormente en un mensaje Mach.

Mach IPC sigue muy presente en un Mac moderno

Aunque un desarrollador pueda trabajar durante años exclusivamente con POSIX, los mecanismos de comunicación heredados de Mach continúan teniendo mucha importancia dentro de macOS.

El ejemplo más evidente es el sistema de mensajes.

mach_msg2_trap() permite enviar y recibir mensajes mediante la infraestructura IPC del kernel. El código abierto de XNU muestra cómo procesa información sobre los puertos remoto y local, opciones de envío y recepción, tamaños y otros parámetros de la operación.

Sobre estas primitivas se han construido mecanismos de más alto nivel.

Un desarrollador de aplicaciones normalmente no necesita llamar directamente a Mach IPC. Frameworks y servicios del sistema proporcionan abstracciones más cómodas para comunicación entre procesos.

Esta separación es deliberada.

Una aplicación convencional debería poder trabajar con archivos, sockets, procesos e hilos sin necesitar conocer los detalles internos de Mach. El hecho de que macOS sea un sistema certificado Unix y proporcione APIs POSIX permite mantener buena parte de esa portabilidad.

Sin embargo, cuando el diagnóstico baja de nivel, empiezan a aparecer términos que no son habituales en Linux.

mach_msg, Mach ports, tasks, Mach exceptions o diferentes primitivas de sincronización pueden aparecer en trazas, herramientas de análisis y registros del sistema.

Por qué macOS y Linux pueden comportarse diferente

Linux y XNU han llegado a resolver muchos de los mismos problemas mediante arquitecturas diferentes.

Linux se suele clasificar como un kernel monolítico modular. Sus subsistemas de memoria, procesos, red, archivos, drivers y planificación forman parte de una arquitectura concebida principalmente alrededor del propio kernel Linux.

XNU arrastra una genealogía diferente.

Su organización combina conceptos de Mach, BSD y otros componentes desarrollados posteriormente por Apple. Esta historia se refleja todavía en sus APIs y estructuras internas.

Eso no significa que una arquitectura sea necesariamente más rápida o mejor que la otra.

Para la mayoría del software, la diferencia queda deliberadamente oculta por APIs de más alto nivel. Un programa escrito en C puede llamar a read() tanto en Linux como en macOS y obtener prácticamente la misma abstracción.

Las diferencias empiezan a importar cuando se trabaja con IPC, profiling, seguridad, virtualización, debugging de bajo nivel o componentes específicos de Darwin.

También aparecen al analizar código del propio kernel.

Apple continúa publicando el código fuente de XNU, lo que permite consultar directamente cómo están implementadas estas interfaces en lugar de depender únicamente de diagramas históricos del funcionamiento de Mac OS X.

Las herramientas de tracing tampoco muestran siempre toda la historia

Herramientas como dtruss, basada en DTrace, han sido tradicionalmente útiles para observar llamadas realizadas por los procesos.

Un ejemplo clásico sería:

sudo dtruss -f cat /etc/hosts

Una traza puede mostrar operaciones conocidas por cualquier desarrollador Unix: apertura del archivo, consulta de atributos, lectura y cierre.

Pero una aplicación puede utilizar simultáneamente interfaces de más bajo nivel que no encajan en esa misma visión POSIX.

Esto hace que comprender las diferentes familias de interfaces de XNU resulte útil al investigar comportamientos relacionados con IPC o componentes del sistema.

Hay además una dificultad adicional en los Mac modernos: las posibilidades de DTrace están condicionadas por los mecanismos de seguridad del sistema y no todos los ejemplos históricos funcionan necesariamente de la misma forma en versiones actuales de macOS.

Por eso conviene evitar asumir que una receta antigua de dtrace permitirá observar cualquier Mach trap en un sistema moderno sin considerar versión de macOS, arquitectura y configuración de seguridad.

XNU es una fusión, no dos kernels compitiendo

La forma más precisa de entender la arquitectura de macOS es evitar dos extremos.

Decir simplemente que «macOS es Unix» explica correctamente su compatibilidad desde el punto de vista del usuario y del desarrollador, pero cuenta poco sobre su arquitectura interna.

Afirmar que un Mac «ejecuta dos kernels a la vez» va demasiado lejos en la dirección contraria.

XNU es un único kernel híbrido.

Mach aporta algunas de sus abstracciones fundamentales para memoria, ejecución e IPC. BSD aporta gran parte de la personalidad Unix que encuentran las aplicaciones. Apple integró ambas piezas dentro del mismo espacio del kernel para conservar esas características sin asumir el coste de mantener BSD como un servidor externo propio de una arquitectura de microkernel pura.

Esa mezcla lleva más de dos décadas debajo de macOS y continúa siendo visible en el código actual de XNU.

Para un desarrollador que únicamente necesita open(), read() y sockets, puede seguir siendo un detalle invisible. Para quien analiza IPC, depura componentes del sistema o intenta entender una traza profunda de macOS, conocer dónde termina la interfaz Unix y dónde empiezan las abstracciones Mach ayuda a interpretar mejor lo que realmente está haciendo el sistema.

Preguntas frecuentes

¿macOS ejecuta realmente dos kernels al mismo tiempo?

No. macOS utiliza un único kernel híbrido llamado XNU. Este integra componentes y conceptos procedentes de Mach y BSD dentro del mismo espacio de direcciones del kernel.

¿Qué significa XNU?

El nombre se interpreta tradicionalmente como «X is Not Unix». XNU proporciona, sin embargo, buena parte de la infraestructura sobre la que macOS ofrece su entorno Unix.

¿Qué aporta Mach al kernel de macOS?

Mach proporciona conceptos y mecanismos relacionados con tareas, hilos, memoria virtual, puertos, comunicación IPC y otras primitivas internas utilizadas por XNU.

¿Qué aporta BSD a XNU?

BSD proporciona buena parte de la interfaz Unix utilizada por las aplicaciones, incluyendo procesos POSIX, señales, sockets, sistema de archivos virtual y numerosas llamadas al sistema.

encuentra artículos

newsletter

Recibe toda la actualidad del sector tech y cloud en tu email de la mano de RevistaCloud.com.

Suscripción boletín

LO ÚLTIMO