Whole document tree
    

Whole document tree

A Common Error Description Library for UNIX: Coding Conventions
[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.5 Coding Conventions

The following conventions are just some general stylistic conventions to follow when writing robust libraries and programs. Conventions similar to this are generally followed inside the UNIX kernel and most routines in the Multics operating system. In general, a routine either succeeds (returning a zero error code, and doing some side effects in the process), or it fails, doing minimal side effects; in any event, any invariant which the library assumes must be maintained.

In general, it is not in the domain of non user-interface library routines to write error messages to the user's terminal, or halt the process. Such forms of "error handling" should be reserved for failures of internal invariants and consistancy checks only, as it provides the user of the library no way to clean up for himself in the event of total failure.

Library routines which can fail should be set up to return an error code. This should usually be done as the return value of the function; if this is not acceptable, the routine should return a "null" value, and put the error code into a parameter passed by reference.

Routines which use the first style of interface can be used from user-interface levels of a program as follows:

 
{
    if ((code = initialize_world(getuid(), random())) != 0) {
        com_err("demo", code,
                "when trying to initialize world");
        exit(1);
    }
    if ((database = open_database("my_secrets", &code))==NULL) {
        com_err("demo", code,
                "while opening my_secrets");
        exit(1);
    }
}

A caller which fails to check the return status is in error. It is possible to look for code which ignores error returns by using lint; look for error messages of the form "foobar returns value which is sometimes ignored" or "foobar returns value which is always ignored."

Since libraries may be built out of other libraries, it is often necessary for the success of one routine to depend on another. When a lower level routine returns an error code, the middle level routine has a few possible options. It can simply return the error code to its caller after doing some form of cleanup, it can substitute one of its own, or it can take corrective action of its own and continue normally. For instance, a library routine which makes a "connect" system call to make a network connection may reflect the system error code ECONNREFUSED (Connection refused) to its caller, or it may return a "server not available, try again later," or it may try a different server.

Cleanup which is typically necessary may include, but not be limited to, freeing allocated memory which will not be needed any more, unlocking concurrancy locks, dropping reference counts, closing file descriptors, or otherwise undoing anything which the procedure did up to this point. When there are a lot of things which can go wrong, it is generally good to write one block of error-handling code which is branched to, using a goto, in the event of failure. A common source of errors in UNIX programs is failing to close file descriptors on error returns; this leaves a number of "zombied" file descriptors open, which eventually causes the process to run out of file descriptors and fall over.

 
{
    FILE *f1=NULL, *f2=NULL, *f3=NULL;
    int status = 0;

    if ( (f1 = fopen(FILE1, "r")) == NULL) {
        status = errno;
        goto error;
    }

    /*
     * Crunch for a while
     */

    if ( (f2 = fopen(FILE2, "w")) == NULL) {
        status = errno;
        goto error;
    }

    if ( (f3 = fopen(FILE3, "a+")) == NULL) {
        status = errno;
            goto error;
    }

    /*
     * Do more processing.
     */
    fclose(f1);
    fclose(f2);
    fclose(f3);
    return 0;

error:
    if (f1) fclose(f1);
    if (f2) fclose(f2);
    if (f3) fclose(f3);
    return status;
}


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Philippe Troin on September, 23 2003 using texi2html