0b6f0c70db
this change adds some of the kernel manpages from 9legacy, fixed and updated to match the changes in 9front.
172 lines
3.8 KiB
Plaintext
172 lines
3.8 KiB
Plaintext
.TH ERROR 9
|
|
.SH NAME
|
|
error, nexterror, poperror, waserror \- error handling functions
|
|
.SH SYNOPSIS
|
|
.ta \w'\fL#define 'u
|
|
.B
|
|
void error(char*)
|
|
.PP
|
|
.B
|
|
void nexterror(void)
|
|
.sp 0.1
|
|
.PP
|
|
.B
|
|
#define poperror() (up->nerrlab--)
|
|
.PP
|
|
.B
|
|
#define waserror() (setlabel(&up->errlab[up->nerrlab++]))
|
|
.SH DESCRIPTION
|
|
The kernel handles error conditions using non-local gotos,
|
|
similar to
|
|
.IR 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.
|
|
.PP
|
|
Each process has in its defining kernel
|
|
.B Proc
|
|
structure a stack of labels,
|
|
.B NERR
|
|
(currently 64) elements deep.
|
|
A kernel function that must perform a clean up or recovery action on an error
|
|
makes a stylised call to
|
|
.IR waserror ,
|
|
.IR nexterror
|
|
and
|
|
.IR poperror :
|
|
.IP
|
|
.EX
|
|
.DT
|
|
if(waserror()){
|
|
/* recovery action */
|
|
nexterror();
|
|
}
|
|
/* normal action */
|
|
poperror();
|
|
.EE
|
|
.PP
|
|
When called in the normal course of events,
|
|
.I waserror
|
|
registers an error handling block by pushing its label onto the stack,
|
|
and returns zero.
|
|
The return value of
|
|
.I 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
|
|
.I nexterror
|
|
to transfer control to the next location on the error stack.
|
|
Typical recovery actions include deallocating memory, unlocking resources, and
|
|
resetting state variables.
|
|
.PP
|
|
Within the recovery block,
|
|
after handling an error condition, there must normally
|
|
be a call to
|
|
.I 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
|
|
.I nexterror
|
|
(there being nothing further on the stack), but calls
|
|
.I pexit
|
|
(see
|
|
.IR kproc (9))
|
|
instead,
|
|
to terminate the process.
|
|
.PP
|
|
When the need to recover a particular resource has passed,
|
|
a function that has called
|
|
.I waserror
|
|
must
|
|
remove the corresponding label from the stack by calling
|
|
.IR poperror .
|
|
This
|
|
must
|
|
be done before returning from the function; otherwise, a subsequent call to
|
|
.I error
|
|
will return to an obsolete activation record, with unpredictable but unpleasant consequences.
|
|
.PP
|
|
.I Error
|
|
copies the given error message, which is limited to
|
|
.B ERRMAX
|
|
bytes, into the
|
|
.B Proc.errstr
|
|
of the current process,
|
|
enables interrupts by calling
|
|
.I spllo
|
|
.RI ( native
|
|
only),
|
|
and finally calls
|
|
.I nexterror
|
|
to start invoking the recovery procedures currently stacked by
|
|
.IR waserror .
|
|
The file
|
|
.B /sys/src/9/port/error.h
|
|
offers a wide selection of predefined error messages, suitable for almost any occasion.
|
|
The message set by the most recent call to
|
|
.I error
|
|
can be obtained within the kernel by examining
|
|
.B up->error
|
|
and in an application, by using the
|
|
.L %r
|
|
directive of
|
|
.IR print (2).
|
|
.PP
|
|
A complex function can have nested error handlers.
|
|
A
|
|
.I waserror
|
|
block will follow the acquisition of a resource, releasing it
|
|
on error before calling
|
|
.I nexterror,
|
|
and a
|
|
.I poperror
|
|
will precede its release in the normal case.
|
|
For example:
|
|
.IP
|
|
.EX
|
|
.DT
|
|
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);
|
|
}
|
|
.sp 1v
|
|
void
|
|
inner(Thing *t)
|
|
{
|
|
if(t->bad)
|
|
error(Egreg); /* returns to B */
|
|
t->valid++;
|
|
}
|
|
.EE
|
|
.SH SOURCE
|
|
.B /sys/src/9/port/proc.c
|
|
.SH CAVEATS
|
|
The description above has many instances of
|
|
.IR should ,
|
|
.IR will ,
|
|
.I must
|
|
and
|
|
.IR "must not" .
|
|
.SH SEE ALSO
|
|
.IR panic (9),
|
|
.IR kproc (9),
|
|
.IR splhi (9)
|