X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=CODING_STYLE;h=00643032032b4a6259ee24494ebcce2142e6a61a;hp=e19294412425b7feb87c4dfe7507957a73552ec0;hb=7c1b422919819e9e7af4652b52d5f122a090ce53;hpb=45df8656ebb1b0559a75993d1508fc61c2d39829;ds=sidebyside diff --git a/CODING_STYLE b/CODING_STYLE index e19294412..006430320 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -1,5 +1,13 @@ +- 8ch indent, no tabs, except for files in man/ which are 2ch indent, + and still no tabs -- 8ch indent, no tabs +- We prefer /* comments */ over // comments, please. This is not C++, after + all. (Yes we know that C99 supports both kinds of comments, but still, + please!) + +- 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. @@ -15,7 +23,7 @@ - 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 +- 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". @@ -23,14 +31,14 @@ more than one cause, it *really* should have "int" as return value for the error code. -- Don't bother with error checking whether writing to stdout/stderr +- 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's OK to log with DEBUG level + 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's no excuse. In program code, you can use +- 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 @@ -38,14 +46,14 @@ lookups involve synchronously talking to services that we would need to start up -- Don't synchronously talk to any other service from PID 1, due to +- 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's probably only OK if you either + 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!) @@ -54,7 +62,7 @@ doing something wrong! - Stay uniform. For example, always use "usec_t" for time - values. Don't usec mix msec, and usec and whatnot. + 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! @@ -74,9 +82,20 @@ { } - But it's OK if you don't. + But it is OK if you do not. + +- Single-line "if" blocks should not be enclosed in {}. Use this: -- Don't write "foo ()", write "foo()". + 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. @@ -102,7 +121,8 @@ no speed benefit, and on calls like printf() "float"s get promoted to "double"s anyway, so there is no point. -- Don't invoke functions when you allocate variables on the stack. Wrong: +- Do not mix function invocations with variable definitions in one + line. Wrong: { int a = foobar(); @@ -123,11 +143,17 @@ backwards! - Think about the types you use. If a value cannot sensibly be - negative, don't use "int", but use "unsigned". - -- Don't 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. + negative, do not use "int", but use "unsigned". + +- 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 generic byte, we generally prefer the + unsigned variant "uint8_t". Do not use types based on "short". They + *never* make sense. Use ints, longs, long longs, all in + unsigned+signed fashion, and the fixed size types + uint8_t/uint16_t/uint32_t/uint64_t/int8_t/int16_t/int32_t and so on, + as well as size_t, but nothing else. Do not use kernel types like + u32 and so on, leave that to the kernel. - Public API calls (i.e. functions exported by our shared libraries) must be marked "_public_" and need to be prefixed with "sd_". No @@ -140,7 +166,7 @@ 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 shouldn't expect these checks to fail, + 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. @@ -152,7 +178,7 @@ 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". Everytime a + 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 @@ -167,3 +193,186 @@ 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 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. + +- 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. This also applies to + sockets. Effectively this means that all invocations to: + + a) open() must get O_CLOEXEC passed + b) socket() and socketpair() must get SOCK_CLOEXEC passed + c) recvmsg() must get MSG_CMSG_CLOEXEC set + d) F_DUPFD_CLOEXEC should be used instead of F_DUPFD, and so on + +- We never use the POSIX version of basename() (which glibc defines it in + libgen.h), only the GNU version (which glibc defines in string.h). + The only reason to include libgen.h is because dirname() + is needed. Everytime you need that please immediately undefine + basename(), and add a comment about it, so that no code ever ends up + using the POSIX version! + +- Use the bool type for booleans, not integers. One exception: in public + headers (i.e those in src/systemd/sd-*.h) use integers after all, as "bool" + is C99 and in our public APIs we try to stick to C89 (with a few extension). + +- When you invoke certain calls like unlink(), or mkdir_p() and you + know it is safe to ignore the error it might return (because a later + call would detect the failure anyway, or because the error is in an + error path and you thus couldn't do anything about it anyway), then + make this clear by casting the invocation explicitly to (void). Code + checks like Coverity understand that, and will not complain about + ignored error codes. Hence, please use this: + + (void) unlink("/foo/bar/baz"); + + instead of just this: + + unlink("/foo/bar/baz"); + +- Don't invoke exit(), ever. It is not replacement for proper error + handling. Please escalate errors up your call chain, and use normal + "return" to exit from the main function of a process. If you + fork()ed off a child process, please use _exit() instead of exit(), + so that the exit handlers are not run. + +- Please never use dup(). Use fcntl(fd, F_DUPFD_CLOEXEC, 3) + instead. For two reason: first, you want O_CLOEXEC set on the new fd + (see above). Second, dup() will happily duplicate your fd as 0, 1, + 2, i.e. stdin, stdout, stderr, should those fds be closed. Given the + special semantics of those fds, it's probably a good idea to avoid + them. F_DUPFD_CLOEXEC with "3" as parameter avoids them. + +- When you define a destructor or unref() call for an object, please + accept a NULL object and simply treat this as NOP. This is similar + to how libc free() works, which accepts NULL pointers and becomes a + NOP for them. By following this scheme a lot of if checks can be + removed before invoking your destructor, which makes the code + substantially more readable and robust. + +- Related to this: when you define a destructor or unref() call for an + object, please make it return the same type it takes and always + return NULL from it. This allows writing code like this: + + p = foobar_unref(p); + + which will always work regardless if p is initialized or not, and + guarantees that p is NULL afterwards, all in just one line. + +- Use alloca(), but never forget that it is not OK to invoke alloca() + within a loop or within function call parameters. alloca() memory is + released at the end of a function, and not at the end of a {} + block. Thus, if you invoke it in a loop, you keep increasing the + stack pointer without ever releasing memory again. (VLAs have better + behaviour in this case, so consider using them as an alternative.) + Regarding not using alloca() within function parameters, see the + BUGS section of the alloca(3) man page. + +- Use memzero() or even better zero() instead of memset(..., 0, ...) + +- Instead of using memzero()/memset() to initialize structs allocated + on the stack, please try to use c99 structure initializers. It's + short, prettier and actually even faster at execution. Hence: + + struct foobar t = { + .foo = 7, + .bar = "bazz", + }; + + instead of: + + struct foobar t; + zero(t); + t.foo = 7; + t.bar = "bazz"; + +- When returning a return code from main(), please preferably use + EXIT_FAILURE and EXIT_SUCCESS as defined by libc. + +- The order in which header files are included doesn't matter too + much. systemd-internal headers must not rely on an include order, so + it is safe to include them in any order possible. + However, to not clutter global includes, and to make sure internal + definitions will not affect global headers, please always include the + headers of external components first (these are all headers enclosed + in <>), followed by our own exported headers (usually everything + that's prefixed by "sd-"), and then followed by internal headers. + Furthermore, in all three groups, order all includes alphabetically + so duplicate includes can easily be detected. + +- 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 such expression by + using "for (;;)". + +- Never use the "off_t" type, and particularly avoid it in public + APIs. It's really weirdly defined, as it usually is 64bit and we + don't support it any other way, but it could in theory also be + 32bit. Which one it is depends on a compiler switch chosen by the + compiled program, which hence corrupts APIs using it unless they can + also follow the program's choice. Moreover, in systemd we should + parse values the same way on all architectures and cannot expose + off_t values over D-Bus. To avoid any confusion regarding conversion + and ABIs, always use simply uint64_t directly. + +- Commit message subject lines should be prefixed with an appropriate + component 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. + +- Avoid leaving long-running child processes around, i.e. fork()s that + are not followed quickly by an execv() in the child. Resource + management is unclear in this case, and memory CoW will result in + unexpected penalties in the parent much much later on. + +- Don't block execution for arbitrary amounts of time using usleep() + or a similar call, unless you really know what you do. Just "giving + something some time", or so is a lazy excuse. Always wait for the + proper event, instead of doing time-based poll loops. + +- To determine the length of a constant string "foo", don't bother + with sizeof("foo")-1, please use strlen("foo") directly. gcc knows + strlen() anyway and turns it into a constant expression if possible. + +- If you want to concatenate two or more strings, consider using + strjoin() rather than asprintf(), as the latter is a lot + slower. This matters particularly in inner loops. + +- Please avoid using global variables as much as you can. And if you + do use them make sure they are static at least, instead of + exported. Especially in library-like code it is important to avoid + global variables. Why are global variables bad? They usually hinder + generic reusability of code (since they break in threaded programs, + and usually would require locking there), and as the code using them + has side-effects make programs intransparent. That said, there are + many cases where they explicitly make a lot of sense, and are OK to + use. For example, the log level and target in log.c is stored in a + global variable, and that's OK and probably expected by most. Also + in many cases we cache data in global variables. If you add more + caches like this, please be careful however, and think about + threading. Only use static 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 + below. + +- If you parse a command line, and want to store the parsed parameters + in global variables, please consider prefixing their names with + "arg_". We have been following this naming rule in most of our + tools, and we should continue to do so, as it makes it easy to + identify command line parameter variables, and makes it clear why it + is OK that they are global variables.