]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - docs/CODING_STYLE.md
man: fix typo
[thirdparty/systemd.git] / docs / CODING_STYLE.md
index ac35dc38d56f037e70838644d1be4c7735b23fcf..8f687e66623ef4e6addc52683a6e2d324272282c 100644 (file)
@@ -70,6 +70,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   ```
 
 - Do not write `foo ()`, write `foo()`.
+
 - `else` blocks should generally start on the same line as the closing `}`:
   ```c
   if (foobar) {
@@ -117,7 +118,24 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   compatibility. Since we typically want to allow adding new enum values to an
   existing enum type with later API versions, please use the
   `_SD_ENUM_FORCE_S64()` macro in the enum definition, which forces the size of
-  the enum to be signed 64bit wide.
+  the enum to be signed 64-bit wide.
+
+- Empty lines to separate code blocks are a good thing, please add them
+  abundantly. However, please stick to one at a time, i.e. multiple empty lines
+  immediately following each other are not OK. Also, we try to keep function
+  calls and their immediate error handling together. Hence:
+
+  ```c
+  /* → empty line here is good */
+  r = some_function(…);
+  /* → empty line here would be bad */
+  if (r < 0)
+          return log_error_errno(r, "Some function failed: %m");
+  /* → empty line here is good */
+  ```
+
+- In shell scripts, do not use whitespace after the redirection operator
+  (`>some/file` instead of `> some/file`, `<<EOF` instead of `<< EOF`).
 
 ## Code Organization and Semantics
 
@@ -194,7 +212,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   variables if you are sure that thread-safety doesn't matter in your
   case. Alternatively, consider using TLS, which is pretty easy to use with
   gcc's `thread_local` concept. It's also OK to store data that is inherently
-  global in global variables, for example data parsed from command lines, see
+  global in global variables, for example, data parsed from command lines, see
   below.
 
 - Our focus is on the GNU libc (glibc), not any other libcs. If other libcs are
@@ -209,8 +227,9 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   the point where they can be initialized. Avoid huge variable declaration
   lists at the top of the function.
 
-  As an exception, `r` is typically used for a local state variable, but should
-  almost always be declared as the last variable at the top of the function.
+  As an exception, `int r` is typically used for a local state variable, but
+  should almost always be declared as the last variable at the top of the
+  function.
 
   ```c
   {
@@ -278,7 +297,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   t.bar = "bazz";
   ```
 
-- To implement an endless loop, use `for (;;)` rather than `while (1)`.  The
+- To implement an endless loop, use `for (;;)` rather than `while (1)`. The
   latter is a bit ugly anyway, since you probably really meant `while
   (true)`. To avoid the discussion what the right always-true expression for an
   infinite while loop is, our recommendation is to simply write it without any
@@ -328,6 +347,21 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   which will always work regardless if `p` is initialized or not, and
   guarantees that `p` is `NULL` afterwards, all in just one line.
 
+## Common Function Naming
+
+- Name destructor functions that destroy an object in full freeing all its
+  memory and associated resources (and thus invalidating the pointer to it)
+  `xyz_free()`. Example: `strv_free()`.
+
+- Name destructor functions that destroy only the referenced content of an
+  object but leave the object itself allocated `xyz_done()`. If it resets all
+  fields so that the object can be reused later call it `xyz_clear()`.
+
+- Functions that decrease the reference counter of an object by one should be
+  called `xyz_unref()`. Example: `json_variant_unref()`. Functions that
+  increase the reference counter by one should be called `xyz_ref()`. Example:
+  `json_variant_ref()`
+
 ## Error Handling
 
 - Error codes are returned as negative `Exxx`. e.g. `return -EINVAL`. There are
@@ -514,7 +548,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
 ## Types
 
 - Think about the types you use. If a value cannot sensibly be negative, do not
-  use `int`, but use `unsigned`.
+  use `int`, but use `unsigned`.  We prefer `unsigned` form to `unsigned int`.
 
 - Use `char` only for actual characters. Use `uint8_t` or `int8_t` when you
   actually mean a byte-sized signed or unsigned integers. When referring to a
@@ -574,12 +608,21 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   i.e.  file system objects that are supposed to be regular files whose paths
   were specified by the user and hence might actually refer to other types of
   file system objects. This is a good idea so that we don't end up blocking on
-  'strange' file nodes, for example if the user pointed us to a FIFO or device
+  'strange' file nodes, for example, if the user pointed us to a FIFO or device
   node which may block when opening. Moreover even for actual regular files
   `O_NONBLOCK` has a benefit: it bypasses any mandatory lock that might be in
   effect on the regular file. If in doubt consider turning off `O_NONBLOCK`
   again after opening.
 
+- These days we generally prefer `openat()`-style file APIs, i.e. APIs that
+  accept a combination of file descriptor and path string, and where the path
+  (if not absolute) is considered relative to the specified file
+  descriptor. When implementing library calls in similar style, please make
+  sure to imply `AT_EMPTY_PATH` if an empty or `NULL` path argument is
+  specified (and convert that latter to an empty string). This differs from the
+  underlying kernel semantics, where `AT_EMPTY_PATH` must always be specified
+  explicitly, and `NULL` is not accepted as path.
+
 ## Command Line
 
 - If you parse a command line, and want to store the parsed parameters in
@@ -670,7 +713,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
 - Do not use `basename()` or `dirname()`. The semantics in corner cases are
   full of pitfalls, and the fact that there are two quite different versions of
   `basename()` (one POSIX and one GNU, of which the latter is much more useful)
-  doesn't make it bette either. Use path_extract_filename() and
+  doesn't make it better either. Use path_extract_filename() and
   path_extract_directory() instead.
 
 - Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size
@@ -682,7 +725,68 @@ SPDX-License-Identifier: LGPL-2.1-or-later
 ## Committing to git
 
 - Commit message subject lines should be prefixed with an appropriate component
-  name of some kind. For example "journal: ", "nspawn: " and so on.
+  name of some kind. For example, "journal: ", "nspawn: " and so on.
 
 - Do not use "Signed-Off-By:" in your commit messages. That's a kernel thing we
   don't do in the systemd project.
+
+## Commenting
+
+- The best place for code comments and explanations is in the code itself. Only
+  the second best is in git commit messages. The worst place is in the GitHub
+  PR cover letter. Hence, whenever you type a commit message consider for a
+  moment if what you are typing there wouldn't be a better fit for an in-code
+  comment. And if you type the cover letter of a PR, think hard if this
+  wouldn't be better as a commit message or even code comment. Comments are
+  supposed to be useful for somebody who reviews the code, and hence hiding
+  comments in git commits or PR cover letters makes reviews unnecessarily
+  hard. Moreover, while we rely heavily on GitHub's project management
+  infrastructure we'd like to keep everything that can reasonably be kept in
+  the git repository itself in the git repository, so that we can theoretically
+  move things elsewhere with the least effort possible.
+
+- It's OK to reference GitHub PRs, GitHub issues and git commits from code
+  comments. Cross-referencing code, issues, and documentation is a good thing.
+
+- Reasonable use of non-ASCII Unicode UTF-8 characters in code comments is
+  welcome. If your code comment contains an emoji or two this will certainly
+  brighten the day of the occasional reviewer of your code. Really! 😊
+
+## Threading
+
+- We generally avoid using threads, to the level this is possible. In
+  particular in the service manager/PID 1 threads are not OK to use. This is
+  because you cannot mix memory allocation in threads with use of glibc's
+  `clone()` call, or manual `clone()`/`clone3()` system call wrappers. Only
+  glibc's own `fork()` call will properly synchronize the memory allocation
+  locks around the process clone operation. This means that if a process is
+  cloned via `clone()`/`clone3()` and another thread currently has the
+  `malloc()` lock taken, it will be cloned in locked state to the child, and
+  thus can never be acquired in the child, leading to deadlocks. Hence, when
+  using `clone()`/`clone3()` there are only two ways out: never use threads in the
+  parent, or never do memory allocation in the child. For our uses we need
+  `clone()`/`clone3()` and hence decided to avoid threads. Of course, sometimes the
+  concurrency threads allow is beneficial, however we suggest forking off
+  worker *processes* rather than worker *threads* for this purpose, ideally
+  even with an `execve()` to remove the CoW trap situation `fork()` easily
+  triggers.
+
+- A corollary of the above is: never use `clone()` where a `fork()` would do
+  too. Also consider using `posix_spawn()` which combines `clone()` +
+  `execve()` into one and has nice properties since it avoids becoming a CoW
+  trap by using `CLONE_VFORK` and `CLONE_VM` together.
+
+- While we avoid forking off threads on our own, writing thread-safe code is a
+  good idea where it might end up running inside of libsystemd.so or
+  similar. Hence, use TLS (i.e. `thread_local`) where appropriate, and maybe
+  the occasional `pthread_once()`.
+
+## Tests
+
+- Use the assertion macros from `tests.h` (`ASSERT_GE()`, `ASSERT_OK()`, ...) to
+  make sure a descriptive error is logged when an assertion fails. If no assertion
+  macro exists for your specific use case, please add a new assertion macro in a
+  separate commit.
+
+- When modifying existing tests, please convert the test to use the new assertion
+  macros from `tests.h` if it is not already using those.