Coding Style and Conventions

Naming Conventions

Unlike desktop operating systems, where applications are written in user-space and drivers are used to cross the boundary between kernel and user space, all applications in the Zephyr Kernel are written in kernel space. Applications are linked with the kernel, creating a shared and common namespace.

To ensure proper execution of both kernel and applications, it makes sense to divide the namespace into kernel and application subspaces. This is achieved by restricting the kernel’s global symbols and macros to a well-defined set of name prefixes. These prefixes apply both to public symbols, which applications can reference, and to private symbols, which only the kernel itself is permitted to reference. Symbols that do not begin with a kernel namespace prefix are available to applications with a few exceptions. See Exceptions to the Namespace for details.

Prefix Description Example
_ Denotes a private symbol. _k_signal_event
atomic_ Denotes an atomic operation. atomic_inc
device_ Denotes an API relating to devices and their initialization. device_get_binding
fiber_ Denotes an operation invoked by a fiber; typically a microkernel operation. fiber_event_send
irq_ Denotes an IRQ management operation. irq_disable
isr_ Denotes an operation called by an Interrupt Service Routine; typically a microkernel operation. isr_event_send
k_ Microkernel-specific function. k_memcpy
k_do_ Microkernel-specific functions indicating essential operation within the kernel space. Do not use these functions unless absolutely necessary. k_do_event_signal
nano_ Denotes an operation provided by the nanokernel; typically used in a microkernel system, not just a nanokernel system. nano_fifo_put
sys_ Catch-all for APIs that do not fit into the other namespaces. sys_write32
task_ Denotes an operation invoked by a task; typically a microkernel operation. task_send_event

If your additional symbol does not fall into the above classification, consider renaming it.

Exceptions to the Namespace

Some kernel APIs use well-known names that lack prefixes. A few examples are:

  • ntohl
  • open
  • close
  • read
  • write
  • ioctl
In rare cases a few global symbols do not use the normal kernel prefixes;
kernel_version_get() is one such example.

Subsystem Naming Conventions

Generally, any sub-system can define its own naming conventions for symbols. However, these should be implemented with their own namespace prefix (for example, bt\_ for BlueTooth, or net\_ for IP). This limits possible clashes with applications. Following this prefix convention with subsystems keeps a consistent interface for all users.

Minimize Include Paths

The current build system uses a series of defs.objs files to define the common pieces for a given subsystem. For example, common defines for x86 architecture are located under $ROOT/arch/x86, with platform-specific defines underneath it, like $ROOT/arch/x86/platform/ia32. Be careful to not add all possible include paths to the defs.obj files. Too many default paths can cause problems when more than one file has the same name. The only include paths into $vBASE/include should be $vBASE/include itself, and the header files should be included with:

#include <subdirectory/header.h>.

For example, if you have two files, include/pci.h and include/drvers/pci.h, and have set both -Iinclude/drivers and -Iinclude for your compile, then any code using

#include <pci.h> becomes ambiguous, while
#include <drivers/pci.h>

is not. Not having -Iinclude/drivers forces users to use the second form which is more explicit.

Return Codes

Zephyr uses the standard codes in errno.h for all APIs.

As a general rule, 0 indicates success; a negative errno.h code indicates an error condition. The table below shows the error code conventions based on device driver use cases, but they can also be applied to other kernel components.

Code Meaning
0 Success.
-EIO General failure.
-ENOTSUP Operation is not supported or operation is invalid.
-EINVAL Device configuration is not valid or function argument is not valid.
-EBUSY Device controller is busy.
-EACCES Device controller is not accessible.
-ENODEV Device type is not supported.
-EPERM Device is not configured or operation is not permitted.
-ENOSYS Function is not implemented.

Coding Style

Use this coding guideline to ensure that your development complies with the project’s style and naming conventions.

In general, follow the Linux kernel coding style, with the following exceptions:

  • Add braces to every if and else body, even for single-line code blocks. Use the --ignore BRACES flag to make checkpatch stop complaining.
  • Use hard tab stops. Set the tab width 8 spaces. Break lines at 80 characters. If you are trying to align comments after declarations, use spaces instead of tabs to align them.
  • Use C89-style single line comments, /* */. The C99-style single line comment, //, is not allowed.
  • Use /**  */ for any comments that need to appear in the documentation.

Checking for Conformity Using Checkpatch

The Linux kernel GPL-licensed tool checkpatch is used to check coding style conformity. Checkpatch is available in the scripts directory. To invoke it when committing code, edit your .git/hooks/pre-commit file to contain:

#!/bin/sh

set -e exec

exec git diff --cached | ${ZEPHYR_BASE}/scripts/checkpatch.pl - || true