[libbsd 10/22] Update CONTRIBUTING.rst

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Jun 24 06:33:38 UTC 2022


Add porting advice.  Explain file descriptor tradeoffs in CONTRIBUTING.rst.

Update #4475.
---
 CONTRIBUTING.rst | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 04593cf6..19abb766 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -463,6 +463,24 @@ In general, provide empty header files and do not guard includes.
 For new code use
 `STYLE(9) <http://www.freebsd.org/cgi/man.cgi?query=style&apropos=0&sektion=9>`_.
 
+Porting Advice
+==============
+
+In FreeBSD there is a kernel and user space separation.  The kernel is invoked
+by applications through system calls.  These system calls are usually
+implemented by associated ``kern_*()`` functions.  For example, the
+``select()`` system call is implemented by ``kern_select()``.  In RTEMS, there
+is no kernel and user space separation.  The system call functions should be
+added directly after the associated ``kern_*()`` function.  The associated
+``kern_*()`` function should be made static.  This allows the compiler to
+remove the function call.  It may also reduce the need for stack variables in
+favour of registers for parameters.  Placing the system calls directly to the
+kernel implementation helps the linker to only include code needed by the
+application and works well with the linker set based LibBSD initialization.  It
+also helps during FreeBSD baseline updates since changes in the kernel
+implementation may be indicated through merge conflicts and this may highlight
+fixes in the porting code.
+
 Automatically Generated FreeBSD Files
 =====================================
 
@@ -677,6 +695,67 @@ If you get undefined references to ``_bsd_sysctl_*`` symbols, then you have to
 locate and add the associated system control node, see
 `SYSCTL(9) <http://www.freebsd.org/cgi/man.cgi?query=SYSCTL_DECL&sektion=9>`_.
 
+File Descriptor Tradeoffs
+=========================
+
+In POSIX systems, individual objects (for example files, sockets, kqueues) are
+usually referenced by file descriptors at API level.  A file descriptor is an
+integer.  One of the jobs of an API level function is checking that a file
+descriptor is valid, mapping it to internal data structures and operations, and
+checking that the operation is allowed.  This procedure is done for every call
+of an API level function, so it should be done quickly.  File descriptors are a
+process-specific resource.
+
+In RTEMS, there is only one process (with multiple threads), so the file
+descriptor is simply used as an index into a global array
+(``rtems_libio_iops``) of file control blocks (``rtems_libio_t``).  Firstly, a
+file descriptor is checked that it is in the range of the array.  The size of
+the array is defined by the application configuration
+(``CONFIGURE_MAXIMUM_FILE_DESCRIPTORS``, ``rtems_libio_number_iops``).
+Secondly, it is checked that the referenced file control block is open.  If one
+of the two checks fails, then an ``EBADF`` error is indicated.  Closed file
+control blocks are queued in a FIFO.  If a new file control block is needed it
+is dequeued from the FIFO.  Since files can be opened and closed, file
+descriptors are recycled after a while.  Using a file descriptor after it was
+closed is a software error.  This error may be indicated by an ``EBADF`` error
+status.  However, if the file descriptor is already reused, then a different
+file object is wrongly used.  To increase the time until a file descriptor is
+recycled, the list of closed file descriptors is organized as a FIFO.  File
+descriptors may be closed while an operation with the file object is in
+progress on another thread.  To avoid destroying the file object while it is
+still in use, the file close operation is performed only if the file object is
+no longer used by a thread.  If it is still in use, then the ``EBUSY`` error is
+indicated by the ``close()`` call.  This is accomplished by a reference count
+located in the file control block.  Since the file control blocks are
+statically allocated we do not need to consider a garbage collection of file
+control blocks.  The reference count is incremented by the
+``rtems_libio_iop_hold()`` function and decremented by the
+``rtems_libio_iop_drop()`` function.
+
+In FreeBSD, the situation is a bit more complicated, since it supports
+processes and dynamic file descriptor limits.  The file descriptor to file
+control block mapping starts with the thread pointer (``curthread``), which is
+used to get the process structure, which is used to get the file descriptor
+table (``struct filedesc``):
+
+.. code-block:: c
+
+    struct thread *td = curthread;
+    struct filedesc *fdp = td->td_proc->p_fd;
+
+Then ``fget_unlocked()`` is used to map the file descriptor to a
+``struct file`` pointer using ``fdp``.  This function takes into account that
+the file table is dynamically allocated and may be reallocated.  It also deals
+with the file reference count.  A file is closed when the reference count
+drops from one to zero.
+
+For LibBSD we have the option to use the FreeBSD file descriptor handling on
+top of the RTEMS file descriptor handling.  The benefit of using the FreeBSD
+file descriptor handling is that this may result in less RTEMS-specific code
+modifications in some areas.  This is a general goal of the LibBSD development.
+However, there is also a significant runtime overhead involved as outlined
+above, especially for socket operations.
+
 Issues and TODO
 ===============
 
-- 
2.35.3



More information about the devel mailing list