Version 9 (modified by walt, 16 months ago)

--

NOTE: add sections on Makefile structure and CVS branch conventions

Specific PVFS issues

Copyright information

Copyright information at the top of source code in PVFS should include the University of Chicago. (The University of Chicago is affiliated with Argonne National Lab, where several key PVFS developers are located).

/*
 * (C) 2001 Clemson University and The University of Chicago. *
 * See COPYING in top-level directory.
 */

Function commenting

See the section on Doxygen comment formatting All program entities such as functions, structs, global variables, typedefs, etc. should have a special comment just before them in the code starting with a double asterisk as shown:

/** Brief description
 *
 *  Detailed description.
 */
struct foo {
};

Files should have a comment block that using the same format and the command \file

/** \file These are functions that do ...
 *
 *  This is the full description
 */

Function naming

Interface functions and global variables in PVFS should use a standard naming convention for clarity. Here are a few guidelines:

  • The letters "PVFS" should only be prepended to functions and global variables that exist as part of an application level interface. Some examples would be PVFS_open and PVFS_read. For clarity, do not use this naming scheme for interfaces internal to PVFS.
  • Well defined internal PVFS interfaces should use the prefix "PINT" (this is short for "PVFS interface"). This should then be followed by an identifier for the interface, and then a description of what the particular function does. Some examples are PINT_flow_alloc, PINT_flow_free, and PINT_flow_post.
  • There are exceptions to the above rule. For example, well defined interfaces that exist within a very distinct module of PVFS may use a different prefix. Examples include the method functions within the BMI layer of PVFS communications have names such as METH_tcp_send and METH_tcp_recv.
  • Any variables that are globally visible should follow the rules listed above as well. This naming convention is for both functions and global variables.

Brackets and Indentation

PVFS code should adhere to the guidelines presented in the  General Guide. In addition, PVFS code should be indented with 4 spaces, no tabs. Brackets should be on a line by themselves and matching brackets should be indented evenly.

int somefunc(int arg)
{
    int a;
    for (a = 0; a < 10; a++)
    {
        float b;
        b = a * arg;
        if (b < 2 * arg)
        {
            printf("WOW!\n");
        }
    }
}

If long lines become heavily indented they can be broken across multiple lines, which case they should be indented by at least 8 spaces, or more if it allows the code to line up naturally.

    /* this is fine */
    some_log_var_name = (struct some_big_type *)malloc(some_important number 
            * some_other_number * sizeof(struct some_big_type));
    /* this may be better */
    some_log_var_name = (struct some_big_type *)malloc(some_important number 
                        * some_other_number * sizeof(struct some_big_type));

If you use vim, a comment block at the end of each file can automatically set parameters such as tab stop and autoexpand tabs that help keep the code in the proper format. Note that these are overridden if you have the same parameter set in your .vimrc file.

Function definitions with more than one argument should have each argument on a line by itself, with each argument indented the same and a comment documenting the argument that adheres to the Doxygen formats.

PVFS_object_ref *PVSF_find_an _object (PVFS_fs_id id,    /**< file system id of the object */
                                       char *name,       /**< string with name of the object */
                                       PVFS_attr_t attr, /**< attributes of the object */
                                       PVFS_hints *hints /**< User supplied hints */
                                      )
{
...
}

Error logging with Gossip

Gossip is a simple library for logging both errors and debugging messages. It allows you to send logging messages to either stderr, syslog, or a text file.Gossip uses a debug mask to determine which messages get logged. You may specify a mask level with each debugging call. These messages can then be toggled on or off depending on what the global mask value is. This allows you to turn debugging on or off just for specific parts of your software at run time. The global mask may be made up of several individual mask values logially or'd together in order to enable logging for multiple parts of your software simultaneously. Gossip also allows you to send error messages. These are similar to debugging messages, except that they get logged regardless of the mask value and whether debugging is turned on or off. These error messages should only be used in situations in which a critical error should be recorded.

The following is a list of functions provided in the Gossip library:

  • gossip_enable_stderr(): Directs logging messages to stderr.
  • gossip_enable_file(filename, mode): Directs logging messages to a specified file. The arguments are the same as those taken by the fopen() function.
  • gossip_enable_syslog(priority): Directs logging to syslog. The priority argument is the same as that given to the syslog() function.
  • gossip_set_debug_mask(debug_on, mask): Turns debugging messages on or off and specifies the mask value to use if turned on.
  • gossip_disable(): Gracefully shuts down the Gossip logging facilities.
  • gossip_debug(mask, format, ...): Logs a debugging message. Uses the same format syntax as the printf() function call. It will only print if debugging is turned on and the mask value matches the global mask specified with gossip_set_debug_mask().
  • gossip_ldebug(mask, format, ...): Same as above, except that it prepends each message with the file name and line number of the source code that invoked it.
  • gossip_err(format, ...): Logs error messages. These will print regardless of the mask and whether debugging is turned on or off.
  • gossip_lerr(format, ...): Same as above, except that it prepends each message with the file name and line number of the source code that invoked it.

Examples of how to use Gossip can be found in the gossip/examples directory of the Gossip source code. This code can be found in the pvfs2/src/common/gossip directory within the PVFS 2 source tree.

Similarly, run-time client debugging information can be gathered by using environment variables before running the client application. The default client logging method is to set the variable PVFS2_DEBUGMASK to values such as client,network. Many of the supported client debugging masks overlap the server masks that can be verified using pvfs2-set-debugmask. By default, setting PVFS2_DEBUGMASK emits debugging information to stderr, often intermixed with the client program output. If you'd like to redirect client debugging to a file, set the PVFS2_DEBUGFILE environment variable to a valid file name. This causes all debug information specified by the PVFS2_DEBUGMASK to be stored in the file specified, no longer intermixing the output with the client program. The file specified in the PVFS2_DEBUGFILE environment variable will be appended if it already exists. Another influential environment variable that can be used to trigger kmod logging messages is PVFS2_KMODMASK. By setting values of this variable to file, inode prior to starting pvfs2-client-core daemon, verbose kmod subsystem error diagnostics are written to the system ring buffer and eventually to the kernel logs. One could also set the kmod diagnostic level when the kernel module is loaded like so, insmod pvfs2.ko module_parm_debug_mask=<diagnostic level>. The diagnostic level will be a bitwise OR of values specified in pvfs2-debug.h. For more information on setting the kernel or client debug mask, see doc/pvfs2-logging.txt in the PVFS source tree.

Suggested error handling

Traditional application error handling with errno

Most unix system calls set a global variable called errno when an error condition occurs. Since this is a global variable, it is overwritten everytime a system call is made. This means that it must be checked immediately following the failure of the system call in question. The errno values correspond to to various error conditions, wuch as bad file descriptor or permission denied. One can print out a textual description of these error values using the perror() or strerror() functions. More information about the use of errno can be found in the man pages for errno, perror, and and strerror.

The use of errno in this manner is fine for small applications, but becomes more tedious when building larger software projects. The problem is that you must store the error value somewhere when passing the error back through multiple abstraction layers. This tends to cause confusion in large projects.

 Back to Developer Guidelines

Back to OrangeFS Main Page