5 ; To generate a printable version of this document, please type
6 ; cd ../doc/style; make
11 Motivation and intended audience
12 ================================
14 This document is meant as a quick reference to a number of guidelines
15 meant for existing and especially new Fiasco kernel developers.
18 How to follow these rules: Metarules
19 ====================================
21 This document does not differentiate between strict rules and ``soft''
22 guidelines. Also, when browsing the source code, you will notice a
23 large number of deviations from these rules (because most rules are
24 younger than the current kernel code). In this sense, all rules are
27 However, as the master guideline, when writing new code, please ensure
28 that the number of rule violations does not grow. (In the future, we
29 might even enforce this property automatically when someone is
33 Programming language, dialect, and subset
34 #########################################
36 Fiasco has been written in C++. However, it uses C++ in a special
37 dialect supported by the Preprocess tool [Hohmuth: Preprocess]. In
38 effect, programmers do not need to write C++ header files, and do not
39 need to declare (member) functions -- Preprocess automates these
42 We use some features of Preprocess for configuration
43 management---please refer to Section [Configuration-specific source code].
45 Preprocess lacks support for the following C++ features, which
46 therefore cannot be used in Fiasco source code (but can be used in
47 third-party source code used, i.e., can be included, by Fiasco):
49 * Name spaces --- use static class interfaces or global or static free
50 functions instead (Section [Singletons])
51 * Nested classes --- use forward-declared ``private classes'' instead
53 '#if' on file top level, except for
55 Preprocess' configuration features instead (Section
56 [Configuration-specific source code])
58 Some features of C++ are explicitly disallowed because Fiasco contains
59 no run-time support for them:
62 * Run-time type identification and dynamic_cast
64 These features are always disabled on the compiler command line.
66 On the other hand, templates are allowed. However, please keep in
67 mind that Fiasco's source code needs to be interpreted not only by the
68 latest version of GCC, but also by at least the two preceding stable
69 versions of GCC, _and_ ---more significantly---by the VFiasco project's
70 semantics compiler, which is a custom compiler _we_ (in a broader
71 sense of we) have to maintain. Therefore, using advanced tricks such
72 as expression templates or partial specialization is strongly
76 Source-code organization and directory structure
77 ################################################
82 Fiasco consists of a number of subsystems; among them:
84 :KERNEL: The kernel proper. This is the part that implements the L4
87 :ABI: ABI-specific definitions, mostly type definitions and accessor
90 :JDB: The built-in kernel debugger.
92 :BOOT: The bootstrapper. This part sets up virtual memory, copies the
93 kernel to its standard virtual-address-space location (0xf0001000),
96 Subsystems are defined in the Modules file, which is the main
97 configuration file for Fiasco's build system. Please refer to
98 the build-system documentation [README] for more information on this
104 Subsystems usually reside in their own directory under src (the
105 exception being those subsystems which do not contain any source code,
106 but which exist only for maintenance purposes).
108 Inside each (source-code) subsystem directory such as kern, the
109 directory layout is as follows:
111 :kern/: Source files shared for all Fiasco-supported
114 :kern/shared/: Source files shared by more than one, but not
117 :kern/ia32, kern/ia64, kern/ux, and so on: Source files that are
118 specific for only one architecture.
120 Currently, hardware architectures is the only configuration dimension
121 that motivates moving a source file into a subdirectory. In other
122 words, source files pertaining to a particular configuration option
123 (other than hardware architecture), but not another, are located in
124 one of the mentioned directories.
129 Usually, source files belong to exactly one module, consisting of one
130 main C++ class plus, optionally, public utility functions, small
131 interface classes for exchanging data with the main class, and private
132 auxiliary classes and functions. A module can be comprised of
133 multiple source files. These source files all start with the name of
134 the module's main class, in all lower case (e.g., for class
135 Thread_state, file names start with the string "thread_state"). When
136 multiple source files implement one module, each file name (except for
137 the main file's) add a submodule-specific suffix, separated with a
138 dash (-). For example:
141 * kern/thread-ipc.cpp
143 Fiasco's build system mandates that all source files (of all
144 subsystems) have different names, even if they reside in different
145 directories. To make file names different, our naming convention is
146 to add architecture-configuration strings to the file names, separated
147 by dashes (-). For example:
150 * kern/shared/thread-ia32-ux.cpp
151 * kern/ia64/thread-ia64.cpp
153 Occasionally, it is useful to separate configuration-specific code
154 into a source file of its own (see Section
155 [Configuration-specific source code]). In this case, the file name
156 contains the configuration string as a suffix, separated by dashes
160 * kern/thread-v2x0.cpp
161 * kern/ia32/thread-ia32-smas.cpp
164 Header files and the C++ preprocessor
165 =====================================
167 As Preprocess assumes the task of writing header files, programmers
168 should not add new header files. The exception to this rule is that
169 header files are required when defining constants that are needed by
170 both assembly code and C++ code.
172 When using header files, these files must be protected from multiple
173 inclusions using include-file guards, as in the following example for
174 the file config_gdt.h:
176 ! #ifndef CONFIG_GDT_H
177 ! #define CONFIG_GDT_H
182 Configuration management
183 ########################
185 The configuration tool
186 ======================
188 The interactive configuration tool is started using "make menuconfig".
189 The tool creates two files, intended for inclusion in C++ code and in
192 :globalconfig.h: This file defines a preprocessor symbol for each
193 _enabled_ configuration option.
195 :globalconfig.out: This file defines a Make variable for set _each_
196 configuration option. Variables for enables options are set to "y",
197 those for disabled options are set to "n".
199 Adding new configuration options
200 --------------------------------
202 Help texts for configuration options in the rules file (rules.cml) are
203 sorted by order in which the options appear in the menu defined at the
204 bottom of the file. New configuration options must add such a help text
205 describing what the config option does. After a new config option
206 has been added, define under which conditions the config option should
207 be suppressed, if any. It is generally a good idea to suppress config
208 options for architectures and configurations where the option is
209 meaningless. Options which can be suppressed for certain configurations
210 usually require consistency rules to ensure they are not left in an
211 undefined state from a previous selection.
213 An example suppression rule is:
214 ! when UX suppress SERIAL
215 The corresponding consistency rule is:
216 ! require UX implies (SERIAL == n)
218 This ensures that 'SERIAL' is set to "n" when someone had previously chosen
219 'IA32' and 'SERIAL' set to "y" and then changes the architecture to 'UX'.
221 Do not forget to update the configuration templates in the directory
222 src/templates after modifying configuration options.
227 This class defines boot-time and constant configuration variables for
230 The constant variables can be derived from options the configuration
231 tool has written to globalconfig.h. As a special exception, '#ifdef'
234 Boot-time configuration variables can be derived from the kernel's
235 command line (class Cmdline).
237 Configuration-specific source code
238 ==================================
240 Single or multiple source files
241 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
243 Source code that is specific to one or a single combination of
244 configuration options can reside in a separate file or in the same
245 file as code for other configuration options. The decision of which
246 works better is in the developer's discretion. Developers should try
247 to combine logically cohesive code fragments in one source file, even
248 if the fragments are mutually exclusive.
250 Conditional compilation
251 ~~~~~~~~~~~~~~~~~~~~~~~
253 Using preprocessor constants and '#ifdef' for conditional compilation
254 is only allowed for source code passed to the assembler (assembly
255 files and header files meant to be included in assembly code). In C++
256 source code, this style is discouraged, and Preprocess does not even
257 support it (for top-level conditional compilation).
259 Configuration-specific C++ code blocks are labeled using Preprocess'
260 configuration-tag feature with 'IMPLEMENTATION' and 'INTERFACE'
263 This feature is available only on file top level. Conditional
264 compilation inside function or class blocks is not allowed. Instead,
265 programmers have the following options:
267 :For class definitions:
268 Use Preprocess' 'EXTENSION' feature to extend class data with
269 configuration-specific contents.
271 :For function definitions:
272 # Create a Boolean constant in class Config that depends on the
273 configuration option ('#ifdef' is allowed there; see Section
274 [Class Config]), and use the normal C++ 'if' statement to
275 conditionalize the code. We rely on the C++ compiler's optimizer
277 # Factor out configuration-specific functions with a common
281 Compile-time polymorphism
282 =========================
284 Many configurable aspects of Fiasco are implemented as a set of
285 (member) functions that implement a given interface in a specific way.
286 However, unlike typical C++ programs, Fiasco usually does not define
287 these interfaces as abstract base classes and then derives
288 configuration-specific subclass implementations from them. We have
289 deemed the overhead of virtual-function calls as too high in many
292 Instead, in Fiasco these interfaces are not declared as virtual
293 functions, but as nonvirtual functions. These functions are then
294 defined in configuration-specific 'IMPLEMENTATION' sections, which can
295 be combined in one file or spread across multiple files (see Section
296 [Configuration-specific source code]). Preprocess assists in this
297 kind of compile-time polymorphism by allowing configuration-specific
298 inline functions and private member functions.
300 These interfaces do not need to be split out into separate classes.
301 It is often useful to have a part of a class interface that is
302 implemented in a configuration-specific way.
304 Usually, Preprocess assumes the task of copying (member-) function
305 declarations into a module's public header file, and this is our
306 preferred usage. However, for interfaces that are implemented in a
307 configuration-specific source-code block, we make an exception: The
308 ``public'' interface (i.e., the interface used by generic client code,
309 which not necessarily needs consist of only public member functions)
310 can be declared and documented in the 'INTERFACE' section of the
311 corresponding module. To prevent Preprocess from adding another
312 declaration, the definition needs to add the 'IMPLEMENT' directive.
313 The prerequisite is that the interface is implemented in an
314 'IMPLEMENTATION' section that depends on _more_ configuration options
315 than the 'INTERFACE' section containing the declaration. For example:
323 ! * Static initalization of the interrupt controller.
325 ! static void init();
329 ! IMPLEMENTATION[i8259]:
335 ! pic_init(0x20,0x28);
338 Maintainer-mode configuration
339 =============================
341 Fiasco's build process can be instrumented with a number of checks
342 that ensure some of the rules defined in this document. Fiasco
343 developers should enable this option in the interactive configuration
344 tool; the option is called 'MAINTAINER_MODE' (``Do additional checks
347 The checks enabled by this option include:
348 * Checking for mutual or circular dependencies between modules (see
349 Section [Dependency management])
350 * Checking for use of deallocated initialization data after
354 Dependency management
355 #####################
357 Fiasco has been designed to be configurable and robust. A
358 precondition for achieving these properties is that modules and
359 subsystems can be removed from the kernel and tested in isolation,
360 which in turn depends on the absence of mutual or circular
361 dependencies between modules and subsystems.
363 Therefore, as a rule, these dependencies must be avoided. Please
364 consult [Lakos: Large-scale C++ Software Design] for standard methods to
365 resolve circular dependencies.
367 The current dependency graph can be generated in text or graphics form
368 using "make DEPS" and "make DEPS.ps".
371 Source-code style and indentation
372 #################################
377 In general, Fiasco developers despise the ugly
378 MixedCapsNamingConvention made popular by Java. If you really must
379 use such names, please go hack some Java project, not Fiasco. In
380 Fiasco, words in multi-word identifier names are generally separated
381 with underscores, with the sequencing words starting with a lowercase
382 letter or a digit (the only exception being preprocessor symbols).
391 In particular, the conventions are as follows:
393 * Type names (class names, typedef names, enum names) all start with a
394 capital letter. Examples: 'Thread', 'Jdb', 'Boot_info'
396 * Function names (both member functions and free functions) start with
397 a lowercase letter. Examples: 'fpage_map()', 'ipc_send_regs()'
399 * Nonstatic member variables start with an underscore (_). Examples:
400 '_mode', '_ready_time'
402 * Other variables (including static member variables, global and local
403 variables, function-argument names) start with a lower-case letter.
404 Examples: 'preempter', 'cpu_lock'
406 * Enumeration constants start with a capital letter. Examples:
407 'Thread_ready', 'Page_writable'
409 The Fiasco architecture board has declared that having the same
410 naming convention for types and constants is not confusing.
412 * Preprocessor-symbol identifiers are all-uppercase and start with a
413 letter. As with all other identifiers, multiple words are separated
414 using underscores. Examples: 'THREAD_BLOCK_SIZE', 'CONFIG_IA32_486'
416 Please note that preprocessor constants are deprecated and allowed
417 only in assembly files and header files meant to be included in
418 assembly code (see Section [Constant definitions]).
420 (For file-naming conventions refer to Section [Source-file naming].)
425 All comments must be in English. American / Aussie / Kiwi English are
426 OK, too, but Pidgin English or Denglisch are not.
431 Please document at least all interfaces of all classes that are meant
432 for client-code use. These interfaces usually include all public and
433 protected member functions and all nonstatic free functions, but
434 possibly more if there is a private interface implemented by
435 configuration-specific code.
437 The interface documentation belongs to the function definition, except
438 if configuration-specific functions (with the 'IMPLEMENT' directive)
439 are declared in an 'INTERFACE' section. In the that case, the
440 documentation belongs to the declaration.
442 Please use Doxygen's Javadoc-like style (the style using '@' instead
443 of backslashes) to document your interfaces. Fiasco's documentation
444 is generated using Doxygen's auto-brief feature, so '@brief'
445 directives are unnecessary [Heesch: Doxygen Manual].
450 The style of multi-line comments is not prescribed, but please be
451 consistent within one source file. All of the following forms are
454 ! /** The foo function.
455 ! * This function frobnifies its arguments.
459 ! * The foo function.
460 ! * This function frobnifies its arguments.
463 ! /** The foo function.
464 ! This function frobnifies its arguments.
467 Marking incomplete code
468 ~~~~~~~~~~~~~~~~~~~~~~~
470 Please use the token 'XXX' inside a comment to mark broken or
479 Singleton objects (classes that will be instantiated only once) should
480 be implemented as static class interfaces instead of a normal
481 instantiable class in order to save kernel-stack space (the this
482 pointer does not need to be passed to these classes). However,
483 developers should use normal classes when it is foreseeable that the
484 class needs to be instantiated multiple times in the future, for
485 instance to support SMP machines.
490 Constants should generally only be defined in enumerations.
491 Preprocessor constants are discouraged except for source code passed
492 to the assembler (assembly files and header files meant to be included
495 In C++ code, preprocessor constants must not be used for conditional
496 compilation using '#ifdef' and friends (see Section
497 [Conditional compilation]).
502 When implementing a binary interface that has been specified in terms
503 of bits of machine words (such as the L4 ABI or a device interface),
504 it is a bad idea to implement the interface using bit-field types,
505 unless the interface is architecture-specific. The reason is that the
506 assignment of bit-field members to bit offsets is both
507 compiler-dependent and architecture-dependent. If bit fiddling is
508 required, please define a class that wraps an integral type (such as
509 'unsigned') and manipulate the bits using bit-and and bit-or
512 Bit-field structures are OK when the exact order of bits in the type's
513 memory representation does not matter.
521 Use assertions generously.
523 Fiasco supports two kinds of runtime assertions: 'assert' and 'check'.
524 Both cause a kernel panic when their argument evaluates to false.
526 The first, 'assert', works just like 'assert' in standard C. It can
527 be removed from the build by defining the preprocessor symbol 'NDEBUG'
528 and therefore must not include code that has side effects.
530 When side effects are desired, use 'check' instead of assert. The
531 contents of this macro are not optimized away with 'NDEBUG' -- only
532 the error-checking code is.
537 * Endless loops are programmed like this:
542 * Sometimes a private inline function is desired, for example if it
543 needs to be wrapped by a stub that is callable from assembly code.
544 In this case, use 'inline NOEXPORT' to avoid having to specify a
545 lengthy 'NEEDS[]' directive for the inline function:
549 ! asm_callable_stub (Thread* t)
554 ! PRIVATE inline NOEXPORT
555 ! Thread::do_stuff ()
560 * Macros are discouraged. Use inline functions instead.
562 * If you really, absolutely have to define a macro, please make sure
563 it can be used as single-statement blocks after 'if', 'else', and
564 the like, by wrapping it like this:
566 ! #define foo(x) do { /* your stuff */ } while (0)
568 Rules for spacing, bracing, and indentation
569 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571 If not specified more precisely in this standard, the GNU Coding
572 Conventions for spacing and bracing apply ([GNU Coding Standards],
575 * The tabulator size is 8. A tabulator can always be replaced with
576 spaces that lead to the next tab stop.
578 * The maximum line length is 80. If a code line becomes longer than
579 80 characters, it must be broken into shorter lines. If line length
580 becomes excessive, developers should factor out utility functions.
582 * The indentation increment is 2 spaces.
584 * In function definitions, put both the return type and the function
585 signature on a line by themselves. Example:
589 ! Preemption::set_preempter (Receiver *preempter)
594 * Put whitespace before each opening parenthesis, except if it is
595 preceded by another opening parenthesis. Put whitespace after each
596 closing parenthesis, except if it is followed by another closing
597 parenthesis or a comma or semicolon. As a special exception, you do
598 not need to put a space between a function name and the
599 function-call operator.
601 ! a = f (b(), sin ((x + y) * z));
603 * Do not wrap the argument to the 'return' statement into parentheses.
605 * Opening and closing braces ('\{', '\}', including the form '\};')
606 always reside on a line of their own. The braces are indented for
607 nested code blocks, but not for type and function definitions. The
608 braced content is always indented with respect to the braces.
610 Goto labels are back-indented 1 space, class-access specifiers
611 (public, protected, private) are back-indented 2 spaces.
618 ! Thread_invalid, Thread_running
628 ! if (receiver()->ipc_try_lock (this) == 0)
634 As an exception, if a function definition fits into a single line,
635 the whole function can be defined in one line. This style can aid
636 readability when defining many small functions in a row.
638 * Curly braces around single-statement code blocks for 'if', 'while',
639 'do', and 'for' are optional, except if the control expression(s) of
640 these statement spans more than one line, the statement following it
643 * Spacing inside expressions is not prescribed. Please do something
644 sensible to save us from adding more rules to this document.
648 ; Y Directory organization
650 ; Y Naming: Classes, methods, constants
652 ; Y No exceptions, no RTTI
654 ; Y Singleton objects as static class interfaces, to save stack space
656 ; Y no preprocessor variables -- use enums
658 ; Y IMPLEMENT nur für definitionen in spezielleren Subsections
660 ; Y config class vs configuration management
662 ; Y header files: unusally not. otherwise, multi-inc protection
666 ; Y Max. 80 Zeichen pro Zeile
670 ; Y Doxygen: Bei deklarierten Memberfunktionen (mit IMPLEMENT
671 ; implementiert) kommt die Doku vor die Deklaration
673 ; Y Member-Vars: _member_name
674 ; Klassen: Class_name
675 ; Konstanten: Constant_name
679 ; Y wann eigenes Quellfile, wann mehrere IMPLEMENTATION-Sections in
682 ; Y Funktionname an Zeilenbeginn, Name/Parameter auf einer Zeile
684 ; Y Rückgabetyp auf Extra-Zeile
686 ; Y Einrücke-Standards
689 ; Y Endlosschleife: for (;;)
691 ; Y Makros: use do {} while (0); (else-kompatibel)
693 ; Y Use inline NOEXPORT für lokale Inlines (ohne NEEDS)
695 ; - kleine Interfaces erwünscht -- minimiere PUBLIC
699 ; Y Konstanten als enums
701 ; Y cyclic dependencies,
705 ; - boolean return values -- bool vs Mword, maybe a new type Bool?
707 ; - "Thread*" t vs "Thread *t"
709 ; - Style of CVS commit messages
711 ; - Code duplication avoidance
713 ; - C++ default parameters -- discouraged?
715 ; - Passing structures as const structure&
717 ; - Makeconf.local: the place to set CC, CXX
719 ; - Sort IMPLEMENTATION[xyz] sections alphabetically: ARM vor IA32 vor
720 ; UX, V2 vor V4 vor X0 bzw. V2,X0 vor V4.
722 ; - declaration/IMPLEMENT are not for documentation purposes, which
723 ; would not work anyway; use the files in auto/ or Doxygen.
725 ; ----------------------------------------------------------------------
729 ; Was mir am Anfang nicht klar war:
731 ; Y Namenskonvention, member mit _foo, Klassen mit Grossbuchstaben
732 ; beginnen & co, Namen allg.
734 ; Y Comments englisch only
736 ; Y Klammersetzung!! Auch wo man Klammern weglassen soll!
738 ; - IMPLEMENT vs PUBLIC, PRIVATE, PROTECTED
740 ; Erwaehnenswert waere noch fuer Neuanfaenger
744 ; - vieleicht Waechter-Style:
758 ; Y Vieleicht sollten wir die maximale Einruecktiefe begrenzen. Ich bin fuer
759 ; 3-4. Ich weis das vieles im Code noch nicht so ist, aber man kann ja mal
762 ; - Generic vs Arch.-spezifische Sachen, zB im generic kein regs()->ecx &
768 ; Bis vor kurzen habe ich noch die #define Version genommen.
769 ; Macht sich aber richtig ******* beim schreiben.
770 ; Habe jetzt mein Zeug auf .macro umgestellt, sieht erheblich freundlicher
773 ; Ein paar hinweise allg zu Assembler, wann man lieber
774 ; Funktionen/gemeinsamen Code sollte und wann Makros.
778 ;ispell-local-dictionary: "american"
780 ;comment-start-skip: "; *"
783 ; LocalWords: accessor Hohmuth tex pdflatex README Preprocess GCC polymorphism
784 ; LocalWords: nonvirtual instantiable NDEBUG Doxygen's Doxygen XXX Javadoc cpp
785 ; LocalWords: NOEXPORT Metarules ifdef