Skip to content

Latest commit

 

History

History
230 lines (166 loc) · 9.59 KB

coding.md

File metadata and controls

230 lines (166 loc) · 9.59 KB

Coding convention

The chapter presents coding convention used in the implementation files of Phoenix-RTOS.

File label

Each operating system source file is marked with label with the following structure.

/*
 * Phoenix-RTOS
 *
 * Operating system kernel
 *
 * pmap - machine dependent part of VM subsystem (ARM)
 *
 * Copyright 2014-2015 Phoenix Systems
 * Copyright 2005-2006 Pawel Pisarczyk
 * Author: Pawel Pisarczyk, Radoslaw F. Wawrzusiak, Jacek Popko
 *
 * This file is part of Phoenix-RTOS.
 *
 * %LICENSE%
 */

Main label blocks are separated with empty line. The first label block informs that file is the part of Phoenix-RTOS operating system. In next block the information about the operating system module is provided. In this example, the file belongs to operating system kernel. Third label block describes the file functionality. In presented example label, the file implements pmap interface - the hardware dependent part of memory management subsystem for managing the MMU or MPU (part of HAL). Fourth label block presents copyright notices and authors of the file. Newest copyrights are located on the top. Copyrights are associated with dates informing about the development periods separated with comas. In the example label the file was developed in years 2014-2015 and in the earlier period of 2005-2006. Presented file has three authors sorted according to the importance of their contribution. All names are presented. Next block contains the information that file belongs to the operating system project. The %LICENSE% macro is used to inject the license conditions.

Labels in each file should be constructed according to presented rules. Modification of these rules is not allowed.

Indentation

Code indentation is based on tabulator. It is not allowed to make indentation with space character. The source code used for development tests (e.g. printf debug) should be entered without indentation. The following code presents correctly formatted code with one line (lib_printf) entered for debug purposes. The inserted line should be removed in the final code.

int main(void)
{
    _hal_init();
    hal_consolePrint(ATTR_BOLD, "Phoenix-RTOS microkernel v. " VERSION "\n");
    _vm_init(&main_common.kmap, &main_common.kernel);
    _proc_init(&main_common.kmap, &main_common.kernel);
    _syscalls_init();
lib_printf("DEBUG: starting first process...\n");
    /* Start init process */
    proc_start(main_initthr, NULL, (const char *)"init");
    /* Start scheduling, leave current stack */
    hal_cpuEnableInterrupts();
    hal_cpuReschedule();
    return 0;
}

Source files

Separate source files should be created for each operating system module. Source files are grouped in directories which names correspond to the names of subsystems.

Functions

Functions should be short and not too complex in terms of logic. The function should do one thing only. Functions should be separated with two newline characters.

Function names

Function names should be created according to the following schema [_]<subsystem>_<functionality> where <subsystem> is the name of subsystem or file to which function belongs and <functionality> is the brief sentence explaining the implemented functionality. The subsystem name should be a one word without the underline characters. The functionality could be expressed using many words but without the underlines. In such case camelCase should be used.

For example function for kernel space memory allocation could be named vm_kmalloc(). Function for creating a new thread could be named proc_threadCreate().

The underline character at the start of the function name means that function is not synchronized and its usage by two parallel threads demands the external synchronization. Good example of such function is the internal function for adding the node to the red-black tree or the internal function for adding the item to the list.

Functions used internally in C file should be declared as static. Functions used only inside the selected subsystem could be named with the name of the module instead of the name of subsystem. Functions exported outside the subsystem must be named with subsystem name only.

Function length

Function should be not longer than 200 lines of code and not shorter than 10 lines of code.

Variables

Variable should be named with one short words without the underline characters. If one word is not enough for variable name than use camelCase. When defining a variable assign it a value, do no assume that is't value is zero.

Local variables

Local variables should be defined before the function code according to ANSI C 89 standard. The stack usage and number of local variables should be minimized. Static local variables are not allowed.

void *_kmalloc_alloc(u8 hdridx, u8 idx)
{
    void *b;
    vm_zone_t *z = kmalloc_common.sizes[idx];
    b = _vm_zalloc(z, NULL);
    kmalloc_common.allocsz += (1 << idx);
    if (idx == hdridx)
            kmalloc_common.hdrblocks--;
    if (z->used == z->blocks) {
            _vm_zoneRemove(&kmalloc_common.sizes[idx], z);
            _vm_zoneAdd(&kmalloc_common.used, z);
    }
    return b;
}

Global variables

Global variables should be used only is their absolutely necessary. You should avoid using globally initialised variables. If they are used, global variables can only be placed in common structures. The structure should be named after the system module that implements it, followed by _common. Example notation is shown below.

struct {
    spinlock_t spinlock;
} pmap_common;

Operators

One space character should be used after and before the following binary and ternary operators:

=  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :

No space should be used after the following unary operators:

&  *  +  -  ~  ! 

The sizeof and typeofare treated as functions and are to be used with accordance to the following notation:

sizeof(x)  
typeof(x)

In case of increment ++ and decrement -- operators following rules should be applied. If they are postfix, no space should be used before the operator. If they are prefix, no space should be used after the operator.

Conditional expressions

Notation of conditional expression is presented below.

if (expr)
  line 1  
if (expr0) {
  line 1
  ...
}
else if (expr1) {
  line 1
  ...
}
else {
  line 1
  ...
}

A space should be used after a keyword of the conditional instruction. Opening and closing braces should be used only if the body of the conditional instruction is longer than one line. The opening brace should be put in the same line as the keyword of the conditional instruction. The closing brace should be placed after the last line of the conditional istruction in a new line.

Type definition

New types can only be defined if it is absolutely necessary.

Comments

When the C programming language is used only C language comments should be used. It means that only /* */ are allowed and // are not to be used at all. A two line comment is presented below.

/*
 * line 1
 * line 2
 */

One line comment should look like the following example.

/* comment */

All comments should be brief and placed only in essential parts of the code. Comments are not the place to copy parts of the specifications. Nor are they the place to express programmers novel writing skills.

The use of any kind of documentation generator (e.g. doxygen) is strictly forbidden.

Preprocessor

The header with the `#include" preprocessing directive should be placed after the label. The example header notation is shown below.

#include "pmap.h"
#include "spinlock.h"
#include "string.h"
#include "console.h"
#include "stm32.h

It is advised not to use MACROS in the code.

It is not advised to use preprocessor conditionals like #if or `ifdef'. The use of preprocessing conditionals makes it harder to follow the code logic. If it is absolute necessary to use preprocessing conditionals, they ought to be formatted as the following example.

#ifndef NOMMU
    process->mapp = &process->map;
    process->amap = NULL;
    vm_mapCreate(process->mapp, (void *)VADDR_MIN, process_common.kmap->start);
    /* Create pmap */
    p = vm_pageAlloc(SIZE_PAGE, PAGE_OWNER_KERNEL | PAGE_KERNEL_PTABLE);
    vaddr = vm_mmap(process_common.kmap, process_common.kmap->start, p, 1 << p->idx, NULL, 0, 0);
    pmap_create(&process->mapp->pmap, &process_common.kmap->pmap, p, vaddr);
#else
    process->mapp = process_common.kmap;
    process->amap = NULL;
    process->lazy = 1;
#endif

Operating system messages

Following notation for operating system messages should be applied. Message should start from a subsystem name, which should be followed by colon and a message body. An example is shown below.

lib_printf("main: Starting syspage programs (%d) and init\n", syspage->progssz);

Miscellaneous

The goto statement shall not be used. The main goal of this prohibition is the minimalization of the spaghetti code generation and the prevention of the linear programming usage.

To better understand our position please read the famous Dijkstra article.

https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

In our opinion usage of goto increases the chaos in the source code and absolutely brings no value like minimalization of the number of lines of code. Is also encourages programmers to poor code structurization.