| .. _posix_details: |
| |
| Implementation Details |
| ###################### |
| |
| In many ways, Zephyr provides support like any POSIX OS; API bindings are provided in the C |
| programming language, POSIX headers are available in the standard include path, when configured. |
| |
| Unlike other multi-purpose POSIX operating systems |
| |
| - Zephyr is not "a POSIX OS". The Zephyr kernel was not designed around the POSIX standard, and |
| POSIX support is an opt-in feature |
| - Zephyr apps are not linked separately, nor do they execute as subprocesses |
| - Zephyr, libraries, and application code are compiled and linked together, running similarly to |
| a single-process application, in a single (possibly virtual) address space |
| - Zephyr does not provide a POSIX shell, compiler, utilities, and is not self-hosting. |
| |
| .. note:: |
| Unlike the Linux kernel or FreeBSD, Zephyr does not maintain a static table of system call |
| numbers for each supported architecture, but instead generates system calls dynamically at |
| build time. See `System Calls <syscalls>`_ for more information. |
| |
| Design |
| ====== |
| |
| As a library, Zephyr's POSIX API implementation makes an effort to be a thin abstraction layer |
| between the application, middleware, and the Zephyr kernel. |
| |
| Some general design considerations: |
| |
| - The POSIX interface and implementations should be part of Zephyr's POSIX library, and not |
| elsewhere, unless required both by the POSIX API implementation and some other feature. An |
| example where the implementation should remain part of the POSIX implementation is |
| ``getopt()``. Examples where the implementation should be part of separate libraries are |
| multithreading and networking. |
| |
| - When the POSIX API and another Zephyr subsystem both rely on a feature, the implementation of |
| that feature should be as a separate Zephyr library that can be used by both the POSIX API and |
| the other library or subsystem. This reduces the likelihood of dependency cycles in code. When |
| practical, that rule should expand to include macros. In the example below, ``libposix`` |
| depends on ``libzfoo`` for the implementation of some functionality "foo" in Zephyr. If |
| ``libzfoo`` also depends on ``libposix``, then there is a dependency cycle. The cycle can be |
| removed via mutual dependency, ``libcommon``. |
| |
| .. graphviz:: |
| :caption: Dependency cycle between POSIX and another Zephyr library |
| |
| digraph { |
| node [shape=rect, style=rounded]; |
| rankdir=LR; |
| |
| libposix [fillcolor="#d5e8d4"]; |
| libzfoo [fillcolor="#dae8fc"]; |
| |
| libposix -> libzfoo; |
| libzfoo -> libposix; |
| } |
| |
| .. graphviz:: |
| :caption: Mutual dependencies between POSIX and other Zephyr libraries |
| |
| digraph { |
| node [shape=rect, style=rounded]; |
| rankdir=LR; |
| |
| libposix [fillcolor="#d5e8d4"]; |
| libzfoo [fillcolor="#dae8fc"]; |
| libcommon [fillcolor="#f8cecc"]; |
| |
| libposix -> libzfoo; |
| libposix -> libcommon; |
| libzfoo -> libcommon; |
| } |
| |
| - POSIX API calls should be provided as regular callable C functions; if a Zephyr |
| `System Call <syscalls>`_ is needed as part of the implementation, the declaration and the |
| implementation of that system call should be hidden behind the POSIX API. |