Coding guidelines

TSLoad agents are written in C, while server is written in Python. This document covers guidelines for agent code. Coding style was inspired by Solaris mostly.These rules are not strict, but recommended and followed by most of the code of TSLoad.

Basic coding guidelines

Line length. There are no limits for line lengths. Common, we live in an era of Full HD displays. But also note that long lines makes code hard to comprehend.

Indentation. four character block indent using tabs with additional spaces where needed.

        json_set_parser_error(parser, JSON_END_OF_BUFFER,
                              "Unexpected end of buffer while parsing %s",
                              (is_array)? "ARRAY": "OBJECT");
 

Curly braces. TSLoad code follows 1TBS style with a small exception: else keyword is put onto new line

Pointer declaration. Put asterisk sign (*) closer to a type. If you want to make several pointers, declare them one per line.

Spaces. Surround operators like < and = with spaces. Do not put spaces around braces. Put single space after commas as punctuation rules require.

Return value checking. It is OK to put assignment of return value variable to a function call result and check it in one if:

    if ((dladm_status = hi_net_sol_dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
        hi_net_dprintf("hi_net_probe: dladm open failed: %d\n", dladm_status);
        return HI_PROBE_ERROR;
    }
 

ifdefs. Avoid ifdefs in function bodies: use PLATAPI where possible or create separate subsets of functions.

goto. It is OK to use goto keyword in one case: you need to cleanup before you will return error code.

Error handling. Preferable way to handle errors is to return int that represents error code. For functions returning pointers it should be NULL. Each subsystem defines its own subset error codes using macro-definitions starting with NAME_OK = 0, and following NAME_ERR_... values that are negative. For subsystems which save error messages or additional data for errors, there should exist thread-local errno structure and API for accessing it.

Source tree organization

Each component of TSLoad: library or a binary consists of smaller pieces called subsystems. Usually front-end of such subsystem is a data structure and operations applicable to it (which could be recognized as class). Subsystem is defined in main header file placed under agent/include/<library subdirectory>/<subsystem name>.h. It can also place its implementation details into separate header located in agent/<path-to-component>/include/<subsystem name>.h. Platform-independent implementation is placed into source file agent/<path-to-component>/<subsystem name>.c, while its platform-specific code (both headers and sources) is placed in plat subdirectory: agent/<path-to-component>/plat/<platform-name>/<subsystem name>.[ch].

For example, threads implementation consists of the following files:

Source structure

Structure of main header goes as follows:

Structure for source files is similiar:

Naming conventions

Because C doesn't support namespaces, which is actually useful feature and allows to distinguish functions and types, we "emulate" it by using prefixes: each name should begin with subsystem name. Subsystem name may be abbreviated or shortened. Naming conventions are similiar to GNU C.

Types

All types names should be lower-cased with underscores.

Macro names

Generally speaking, macros should be named upper-cased with underscores, but there are couple exceptions for it

Function names

All function names should be lower-cased. Function name consists of several components that are separated by underscores:

There are some conventions for operation names:

Variable names

Global variable names lower-cased with underscores with a subsystem prefix.

There are no clear rules for local variable or arguments naming, but there are several recommendations:

Comments

Since TSLoad agent is written in C and even simple actions require multiple syntax constructions, it is recommended to comment such actions.

  /* 7 chars are enough to store thousands + suffix + space + null-term */
  ...
        if(length > (size - 8))
            return 0;
  

        /* Somebody allocating or freeing page now, wait on mutex than return
         * last allocated heap page. If last_heap_page will be freed, page
         * would be set to NULL, and we loop again */
  

        if(errno == ENOTSUP) {
                /* In Solaris 10, psets may be disabled if pools are not configured.  */
                return SCHED_NOT_SUPPORTED;
        }