Should You Program in the Kernel?

If you are thinking of writing code for the kernel environment, think carefully. Programming in the kernel can be a difficult and dangerous task. And often there is a way to accomplish what you want to do without touching the kernel.

Software that resides in the kernel tends to be expensive. Kernel code is "wired" into physical memory and thus cannot be paged out by the virtual memory system. As more code is put into the kernel, less physical memory is available to user-space processes. Consequently, paging activity will probably intensify, thereby degrading system performance.

Kernel code is also inherently destabilizing, much more so than application code. The kernel environment is a single process, and this means that there is no memory protection between your extension or driver and anything else in the kernel. Access memory in the wrong place and–boom– the entire system can grind to a halt, a victim of a kernel panic. Moreover, because kernel code usually provides services to numerous user-space clients, any inefficiencies in the code can be propagated to those clients, thereby affecting the system globally.

Finally, kernel software is a real pain to write. There are subtleties to grapple with unknown in the realm of application development. And because the tools for kernel development are in an early stage of maturity, bugs in kernel code are harder to find than in user-space software.

With all this in mind, the message is clear. It is in everyone's best interest to put as little code as possible into the kernel. And any code that ends up in the kernel should be honed and rigorously tested.


When Code Should Reside In the Kernel

A handful of situations warrant loading a driver or extension into the kernel environment:

If the software you are writing does not match any of these criteria, it probably doesn't belong in the kernel. If your software is a driver for a disk, a network controller, or a keyboard, it should reside in the kernel. If it is an extension to the file system, it should live in the kernel. If, on the other hand, it is used only now and then by a single user-space program, it should be loaded by the program and reside within it. Drivers for printers and scanners fall into this latter category.

Alternatives to Kernel-Resident Code

Apple provides a number of technologies that might let you accomplish what you want to do and stay out of the kernel. First are the higher-level APIs that give you some hardware-level access. For example, the CFNetwork and POSIX networking APIs are a powerful resource for many networking capabilities and Core Graphics (Quartz) enables you to do some fairly low-level things with the graphics subsystem.

Second, and just as important, is the "device interface" technology of the I/O Kit framework. Using a plug-in architecture, this technology makes it possible for your application to interact with the kernel to access most hardware. In addition, you can–with a little help from the I/O Kit–use POSIX APIs to access serial, storage, or network devices.