X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=CODING_STYLE;h=0b1f809e79717812c0fdd007e1ef5786a5f4e916;hp=9341b48d4103a19b6b75c206c58c508a60e8a5ec;hb=06c1c4f98c0d0b4c93e58d75ed5a08d722ec4de3;hpb=19c5f19d69bb5f520fa7213239490c55de06d99d diff --git a/CODING_STYLE b/CODING_STYLE index 9341b48d4..0b1f809e7 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -1,27 +1,197 @@ - - 8ch indent, no tabs -- structs in MixedCase, variables, functions in lower_case +- Don't break code lines too eagerly. We do *not* force line breaks at + 80ch, all of today's screens should be much larger than that. But + then again, don't overdo it, ~140ch should be enough really. + +- Variables and functions *must* be static, unless they have a + prototype, and are supposed to be exported. + +- structs in MixedCase (with exceptions, such as public API structs), + variables + functions in lower_case. -- the destructors always unregister the object from the next bigger +- The destructors always unregister the object from the next bigger object, not the other way around -- to minimize strict aliasing violations we prefer unions over casting +- To minimize strict aliasing violations, we prefer unions over casting -- for robustness reasons destructors should be able to destruct +- For robustness reasons, destructors should be able to destruct half-initialized objects, too -- error codes are returned as negative Exxx. i.e. return -EINVAL. There - are some exceptions: for constructors its is OK to return NULL on - OOM. For lookup functions NULL is fine too for "not found". +- Error codes are returned as negative Exxx. e.g. return -EINVAL. There + are some exceptions: for constructors, it is OK to return NULL on + OOM. For lookup functions, NULL is fine too for "not found". + + Be strict with this. When you write a function that can fail due to + more than one cause, it *really* should have "int" as return value + for the error code. + +- Do not bother with error checking whether writing to stdout/stderr + worked. + +- Do not log errors from "library" code, only do so from "main + program" code. (With one exception: it is OK to log with DEBUG level + from any code, with the exception of maybe inner loops). + +- Always check OOM. There is no excuse. In program code, you can use + "log_oom()" for then printing a short message, but not in "library" code. - Do not issue NSS requests (that includes user name and host name - lookups) from the main daemon as this might trigger deadlocks when - we those lookups involve synchronously talking to services that we - would need to start up. + lookups) from PID 1 as this might trigger deadlocks when those + lookups involve synchronously talking to services that we would need + to start up + +- Do not synchronously talk to any other service from PID 1, due to + risk of deadlocks + +- Avoid fixed-size string buffers, unless you really know the maximum + size and that maximum size is small. They are a source of errors, + since they possibly result in truncated strings. It is often nicer + to use dynamic memory, alloca() or VLAs. If you do allocate fixed-size + strings on the stack, then it is probably only OK if you either + use a maximum size such as LINE_MAX, or count in detail the maximum + size a string can have. (DECIMAL_STR_MAX and DECIMAL_STR_WIDTH + macros are your friends for this!) + + Or in other words, if you use "char buf[256]" then you are likely + doing something wrong! + +- Stay uniform. For example, always use "usec_t" for time + values. Do not mix usec and msec, and usec and whatnot. + +- Make use of _cleanup_free_ and friends. It makes your code much + nicer to read! + +- Be exceptionally careful when formatting and parsing floating point + numbers. Their syntax is locale dependent (i.e. "5.000" in en_US is + generally understood as 5, while on de_DE as 5000.). + +- Try to use this: + + void foo() { + } + + instead of this: + + void foo() + { + } + + But it is OK if you do not. + +- Single-line "if" blocks should not be enclosed in {}. Use this: + + if (foobar) + waldo(); + + instead of this: + + if (foobar) { + waldo(); + } + +- Do not write "foo ()", write "foo()". + +- Please use streq() and strneq() instead of strcmp(), strncmp() where applicable. + +- Please do not allocate variables on the stack in the middle of code, + even if C99 allows it. Wrong: + + { + a = 5; + int b; + b = a; + } + + Right: + + { + int b; + a = 5; + b = a; + } + +- Unless you allocate an array, "double" is always the better choice + than "float". Processors speak "double" natively anyway, so this is + no speed benefit, and on calls like printf() "float"s get promoted + to "double"s anyway, so there is no point. + +- Do not invoke functions when you allocate variables on the stack. Wrong: + + { + int a = foobar(); + uint64_t x = 7; + } + + Right: + + { + int a; + uint64_t x = 7; + + a = foobar(); + } + +- Use "goto" for cleaning up, and only use it for that. i.e. you may + only jump to the end of a function, and little else. Never jump + backwards! + +- Think about the types you use. If a value cannot sensibly be + negative, do not use "int", but use "unsigned". + +- Do not use types like "short". They *never* make sense. Use ints, + longs, long longs, all in unsigned+signed fashion, and the fixed + size types uint32_t and so on, as well as size_t, but nothing else. + +- Public API calls (i.e. functions exported by our shared libraries) + must be marked "_public_" and need to be prefixed with "sd_". No + other functions should be prefixed like that. + +- In public API calls, you *must* validate all your input arguments for + programming error with assert_return() and return a sensible return + code. In all other calls, it is recommended to check for programming + errors with a more brutal assert(). We are more forgiving to public + users then for ourselves! Note that assert() and assert_return() + really only should be used for detecting programming errors, not for + runtime errors. assert() and assert_return() by usage of _likely_() + inform the compiler that he should not expect these checks to fail, + and they inform fellow programmers about the expected validity and + range of parameters. + +- Never use strtol(), atoi() and similar calls. Use safe_atoli(), + safe_atou32() and suchlike instead. They are much nicer to use in + most cases and correctly check for parsing errors. + +- For every function you add, think about whether it is a "logging" + function or a "non-logging" function. "Logging" functions do logging + on their own, "non-logging" function never log on their own and + expect their callers to log. All functions in "library" code, + i.e. in src/shared/ and suchlike must be "non-logging". Every time a + "logging" function calls a "non-logging" function, it should log + about the resulting errors. If a "logging" function calls another + "logging" function, then it should not generate log messages, so + that log messages are not generated twice for the same errors. + +- Avoid static variables, except for caches and very few other + cases. Think about thread-safety! While most of our code is never + used in threaded environments, at least the library code should make + sure it works correctly in them. Instead of doing a lot of locking + for that, we tend to prefer using TLS to do per-thread caching (which + only works for small, fixed-size cache objects), or we disable + caching for any thread that is not the main thread. Use + is_main_thread() to detect whether the calling thread is the main + thread. + +- Command line option parsing: + - Do not print full help() on error, be specific about the error. + - Do not print messages to stdout on error. + - Do not POSIX_ME_HARDER unless necessary, i.e. avoid "+" in option string. -- Do not access any directories outside of /etc/, /dev, /lib from the - init daemon to avoid deadlocks with the automounter. +- Do not write functions that clobber call-by-reference variables on + failure. Use temporary variables for these cases and change the + passed in variables only on success. -- Don't synchronously talk to any other service, due to risk of - deadlocks. +- When you allocate a file descriptor, it should be made O_CLOEXEC + right from the beginning, as none of our files should leak to forked + binaries by default. Hence, whenever you open a file, O_CLOEXEC must + be specified, right from the beginning.