113 lines · 3.9 KB · Text
RawDownload
= error,  nexterror,  poperror, waserror: error handling functions     void  error(char*)     void  nexterror(void)     void  poperror(void)     int   waserror(void) The kernel handles error conditions  using  non-local  gotos,similar  to  setjmp/longjmp  in  ANSI C, but using a stack oferror labels to implement nested  exception  handling.   Thissimplifies many of the internal interfaces by eliminating theneed for returning and checking error codes at every level ofthe  call  stack, at the cost of requiring kernel routines toadhere to a strict discipline. Each kernel process (see kproc(10.2))  has  in  its  definingProc structure a stack of labels, currently 32 elements deep.A kernel function that must perform a clean  up  or  recoveryaction on an error makes a stylised call to waserror, nexter‐ror 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 thestack, and returns zero.  The return value of waserror shouldbe  tested  as  shown above.  If non-zero (true), the callingfunction should perform the needed error recovery, ended by acall to nexterror to transfer control to the next location onthe error stack.  Typical recovery actions include deallocat‐ing  memory,  unlocking  resources, and resetting state vari‐ables. Within the recovery block, after handling an error condition,there  must  normally be a call to nexterror to transfer con‐trol to any error recovery lower down in the stack.  The mainexception  is  in  the outermost function in a process, whichmust not call nexterror (there being nothing further  on  thestack),  but calls pexit (see kproc(10.2)) instead, to termi‐nate the process. When the need to recover a particular resource has passed,  afunction that has called waserror must remove the correspond‐ing label from the stack by calling poperror.  This  must  bedone  before returning from the function; otherwise, a subse‐quent call to error will return  to  an  obsolete  activationrecord, with unpredictable but unpleasant consequences. Error  copies  the  given  error message, which is limited toERRMAX bytes, into the Osenv.errstr of the  current  process,enables  interrupts  by  calling  spllo  (native  only),  andfinally calls nexterror to start invoking the recovery proce‐dures    currently    stacked   by   waserror.    The   files/os/port/error.h and /emu/port/error.h offer a wide selectionof  predefined  error messages, suitable for almost any occa‐sion.  The message set by the most recent call to  error  canbe obtained within the kernel by examining up->env->error andin an application, by using the directive of sys-print(2). A complex function can have nested error handlers.  A  waser‐ror  block will follow the acquisition of a resource, releas‐ing it on error before calling nexterror, and a poperror willprecede 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);           if(waserror()){     /* B */               free(m);               nexterror();    /* invokes A */           }           inner(t);           poperror();         /* pops B */           free(m);           poperror();         /* pops A */           qunlock(t);       }        void       inner(Thing *t)       {           if(t->bad)               error(Egreg);   /* error() call returns to B */           t->valid++;       } == source/os/port/proc.c/emu/port/main.c == caveatsThe  description  above  has  many instances of should, will,must and must not. == see ALSOpanic(10.2)