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 driver and anything else in the kernel. Access memory in the wrong place and 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 that are unknown in the realm of application development. And 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
Alternatives to Kernel-Resident Code
A handful of situations warrant loading a driver or extension into the kernel environment:
The software is used by the kernel environment itself.
User-space programs will frequently use the software.
The software needs to respond directly to primary interrupts (those delivered by the CPU's interrupt controller).
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.
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, Open Transport is a powerful resource for many networking capabilities, and Quartz Compositor 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. Through a plug-in architecture, this technology makes it possible for your application to interact with the kernel to access hardware. In addition, you can—with a little help from the I/O Kit—use POSIX APIs to access serial, storage, or network devices. See “Controlling Devices From Outside the Kernel” for a summary of device interfaces and see the document Accessing Hardware From Applications for a full discussion of this technology.
Note: Objective-C does not provide device-level I/O services. However, in your Cocoa application, you can call the C APIs for device-level functionality that the I/O Kit and BSD provide. Note that you can view the man pages that document BSD and POSIX functions and tools at Mac OS X Man Pages.
Last updated: 2007-05-17