summaryrefslogtreecommitdiff
path: root/doc/developer
diff options
context:
space:
mode:
Diffstat (limited to 'doc/developer')
-rw-r--r--doc/developer/library.rst1
-rw-r--r--doc/developer/locking.rst73
-rw-r--r--doc/developer/subdir.am1
-rw-r--r--doc/developer/workflow.rst22
4 files changed, 97 insertions, 0 deletions
diff --git a/doc/developer/library.rst b/doc/developer/library.rst
index 7cd493ccc4..a904a4e778 100644
--- a/doc/developer/library.rst
+++ b/doc/developer/library.rst
@@ -11,6 +11,7 @@ Library Facilities (libfrr)
rcu
lists
logging
+ locking
hooks
cli
modules
diff --git a/doc/developer/locking.rst b/doc/developer/locking.rst
new file mode 100644
index 0000000000..aee05aae06
--- /dev/null
+++ b/doc/developer/locking.rst
@@ -0,0 +1,73 @@
+Locking
+=======
+
+FRR ships two small wrappers around ``pthread_mutex_lock()`` /
+``pthread_mutex_unlock``. Use ``#include "frr_pthread.h"`` to get these
+macros.
+
+.. c:function:: frr_with_mutex(pthread_mutex_t *mutex)
+
+ Begin a C statement block that is executed with the mutex locked. Any
+ exit from the block (``break``, ``return``, ``goto``, end of block) will
+ cause the mutex to be unlocked::
+
+ int somefunction(int option)
+ {
+ frr_with_mutex(&my_mutex) {
+ /* mutex will be locked */
+
+ if (!option)
+ /* mutex will be unlocked before return */
+ return -1;
+
+ if (something(option))
+ /* mutex will be unlocked before goto */
+ goto out_err;
+
+ somethingelse();
+
+ /* mutex will be unlocked at end of block */
+ }
+
+ return 0;
+
+ out_err:
+ somecleanup();
+ return -1;
+ }
+
+ This is a macro that internally uses a ``for`` loop. It is explicitly
+ acceptable to use ``break`` to get out of the block. Even though a single
+ statement works correctly, FRR coding style requires that this macro always
+ be used with a ``{ ... }`` block.
+
+.. c:function:: frr_mutex_lock_autounlock(pthread_mutex_t *mutex)
+
+ Lock mutex and unlock at the end of the current C statement block::
+
+ int somefunction(int option)
+ {
+ frr_mutex_lock_autounlock(&my_mutex);
+ /* mutex will be locked */
+
+ ...
+ if (error)
+ /* mutex will be unlocked before return */
+ return -1;
+ ...
+
+ /* mutex will be unlocked before return */
+ return 0;
+ }
+
+ This is a macro that internally creates a variable with a destructor.
+ When the variable goes out of scope (i.e. the block ends), the mutex is
+ released.
+
+ .. warning::
+
+ This macro should only used when :c:func:`frr_with_mutex` would
+ result in excessively/weirdly nested code. This generally is an
+ indicator that the code might be trying to do too many things with
+ the lock held. Try any possible venues to reduce the amount of
+ code covered by the lock and move to :c:func:`frr_with_mutex`.
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 1fc593e566..557a41c51f 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -31,6 +31,7 @@ dev_RSTFILES = \
doc/developer/index.rst \
doc/developer/library.rst \
doc/developer/lists.rst \
+ doc/developer/locking.rst \
doc/developer/logging.rst \
doc/developer/maintainer-release-build.rst \
doc/developer/memtypes.rst \
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 07c43ac2de..3c6887fbac 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -767,6 +767,28 @@ ways that can be unexpected for the original implementor. As such debugs
ability to turn on/off debugs from the CLI and it is expected that the
developer will use this convention to allow control of their debugs.
+Custom syntax-like block macros
+-------------------------------
+
+FRR uses some macros that behave like the ``for`` or ``if`` C keywords. These
+macros follow these patterns:
+
+- loop-style macros are named ``frr_each_*`` (and ``frr_each``)
+- single run macros are named ``frr_with_*``
+- to avoid confusion, ``frr_with_*`` macros must always use a ``{ ... }``
+ block even if the block only contains one statement. The ``frr_each``
+ constructs are assumed to be well-known enough to use normal ``for`` rules.
+- ``break``, ``return`` and ``goto`` all work correctly. For loop-style
+ macros, ``continue`` works correctly too.
+
+Both the ``each`` and ``with`` keywords are inspired by other (more
+higher-level) programming languages that provide these constructs.
+
+There are also some older iteration macros, e.g. ``ALL_LIST_ELEMENTS`` and
+``FOREACH_AFI_SAFI``. These macros in some cases do **not** fulfill the above
+pattern (e.g. ``break`` does not work in ``FOREACH_AFI_SAFI`` because it
+expands to 2 nested loops.)
+
Static Analysis and Sanitizers
------------------------------
Clang/LLVM and GCC come with a variety of tools that can be used to help find