Error handling in JSUS programs

 

Syntax:

num = errno([errno])

str = strerror([errno|string])

t/f = aa([level])

 

Synopsis:

The JavaScript Unix Shell (JSUS) encapsulates most of the C language runtime library for Unix and is therefore highly dependent on the error handling facilities provided by that library. In general, C library functions return errors in the form of an irregular result (-1, null pointer) together with a more specific error code passed in a global variable called errno (typically an int). The C/C++ programmer usually has to include a significant amount of code to check the value of errno after each system call. This is both cumbersome and error prone and it is also incompatible with the exception handling built into the JavaScript language (the try, catch and throw statements).

Any JSUS JavaScript program may choose to handle all runtime errors itself, by passing the -a9 option to JSUS at startup. In this case, all errors are passed back to the program for analysis. On error, every JSUS function returns null and the errno() function can be used to inspect the global variable. An integer value can also be passed to errno to set the value of the global variable (for use elsewhere in the program). The strerror() function can be used to obtain a short string explaining the meaning assigned to the current global errno value. Since this is reset to zero by all functions other than these two, it is a good idea to save the value returned by errno(). This (or any other integer) may optionally be passed to strerror() to obtain a description for any given error number.

However, since most runtime errors are unrecoverable, and are usually caused by programmer error, JSUS prefers to throw all errors to the JavaScript exception handler. This is achieved with an "autothrow" level of -a1 (the default). If there are no try-catch blocks, this causes the error to be caught by JSUS itself, which then aborts the program, while printing diagnostic information on stderr. Thus, during testing, JSUS programs typically fail hard and early making it easier for programmers to correct their errors. For special cases, individual errors may be caught by the program using a try block containing the target function, but this is rarely necessary because JSUS also handles most trivial errors automatically.

Certain errors are not really errors at all but simply indicate that a particular function cannot produce a result, for some fairly common reason. For example, if a program attempts to read beyond the end of file, get() cannot return any data but there is no reason to panic and end the program. In these clearly defined cases, JSUS always returns a null (and errno may be set) regardless of the autothrow level. Other errors may sometimes be serious and sometimes trivial, depending on the situation. JSUS is designed to handle these cases by providing support for intermediate throw levels, between -a1 and -a9, where some groups of errors are handled by the program and some by autothrow.

Currently, only -a3 is defined, mainly for the use of server programs. It passes only the EINTR error to the program and autothrows all others. This "error" occurs when a function is interrupted by a system signal. For example, server programs typically spend a great deal of time waiting for a get() to complete on a socket or pipe and this may need to be interrupted in order to shut the program down. Or, a program may simply wait() for a signal from another program. The -a3 level allows programs to gracefully intercept these signals, by testing for an errno() of 4 (the integer value of EINTR).

The EINTR error is also given special handling by the strerror() function. In most cases this function returns a message string in the format: "[99] error message" — where 99 is replaced by the actual error number. As a special case, if the last function ended with EINTR, strerror() returns a string with nothing but the name of the signal, in upper case, (e.g. "SIGTERM").

The autothrow level (sometimes called auto-abort) can also be modified dynamically while running the program, using the aa() function. Its sole argument is the abort level, specified as an integer between 1 and 9. This becomes the new throw level and remains in effect until changed or until the program ends. However, if this argument is omitted, the abort level is raised to 9, for the next JSUS function call only. Any error which occurs during that function is returned immediately to the program for special processing. For the next function after that, the throw level is returned to its former value. This is often easier than coding a try-catch block.

Finally, strerror() offers one more feature to aid in program debugging. It may be passed a string which is stored internally by JSUS and whose last value is printed only if the program terminates abnormally and only if the program is run with the -d (debug) option. This can be useful during testing to capture certain complex program states, such as intermediate call stacks, but does nothing at all when the program is operating normally.

 

See also:

Running JavaScript programs in JSUS.