ERROR(9) ERROR(9)
NAME
error, nexterror, poperror, waserror - error handling
functions
SYNOPSIS
void error(char*)
void nexterror(void)
#define poperror() (up->nerrlab--)
#define waserror() (setlabel(&up->errlab[up->nerrlab++]))
DESCRIPTION
The kernel handles error conditions using non-local gotos,
similar to setjmp(2), but using a stack of error labels to
implement nested exception handling. This simplifies many
of the internal interfaces by eliminating the need for
returning and checking error codes at every level of the
call stack, at the cost of requiring kernel routines to
adhere to a strict discipline.
Each process has in its defining kernel Proc structure a
stack of labels, NERR (currently 64) elements deep. A ker-
nel function that must perform a clean up or recovery action
on an error makes a stylised call to waserror, nexterror and
poperror:
if(waserror()){
/* recovery action */
nexterror();
}
/* normal action */
poperror();
When called in the normal course of events, waserror regis-
ters an error handling block by pushing its label onto the
stack, and returns zero. The return value of waserror
should be tested as shown above. If non-zero (true), the
calling function should perform the needed error recovery,
ended by a call to nexterror to transfer control to the next
location on the error stack. Typical recovery actions
include deallocating memory, unlocking resources, and reset-
ting state variables.
Within the recovery block, after handling an error condi-
tion, there must normally be a call to nexterror to transfer
control to any error recovery lower down in the stack. The
main exception is in the outermost function in a process,
which must not call nexterror (there being nothing further
Page 1 Plan 9 (printed 11/5/25)
ERROR(9) ERROR(9)
on the stack), but calls pexit (see kproc(9)) instead, to
terminate the process.
When the need to recover a particular resource has passed, a
function that has called waserror must remove the corre-
sponding label from the stack by calling poperror. This must
be done before returning from the function; otherwise, a
subsequent call to error will return to an obsolete activa-
tion record, with unpredictable but unpleasant consequences.
Error copies the given error message, which is limited to
ERRMAX bytes, into the Proc.errstr of the current process,
enables interrupts by calling spllo (native only), and
finally calls nexterror to start invoking the recovery pro-
cedures currently stacked by waserror. The file
/sys/src/9/port/error.h offers a wide selection of prede-
fined error messages, suitable for almost any occasion. The
message set by the most recent call to error can be obtained
within the kernel by examining up->error and in an applica-
tion, by using the `%r' directive of print(2).
A complex function can have nested error handlers. A
waserror block will follow the acquisition of a resource,
releasing it on error before calling nexterror, and a
poperror will precede its release in the normal case. For
example:
void
outer(Thing *t)
{
qlock(t);
if(waserror()){ /* A */
qunlock(t);
nexterror();
}
m = mallocz(READSTR, 0);
if(m == nil)
error(Enomem); /* returns to A */
if(waserror()){ /* B */
free(m);
nexterror(); /* invokes A */
}
inner(t);
poperror(); /* pops B */
free(m);
poperror(); /* pops A */
qunlock(t);
}
void
inner(Thing *t)
{
Page 2 Plan 9 (printed 11/5/25)
ERROR(9) ERROR(9)
if(t->bad)
error(Egreg); /* returns to B */
t->valid++;
}
SOURCE
/sys/src/9/port/proc.c
CAVEATS
The description above has many instances of should, will,
must and must not.
SEE ALSO
panic(9), kproc(9), splhi(9)
Page 3 Plan 9 (printed 11/5/25)