error 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. .TH ERROR 9
  2. .SH NAME
  3. error, nexterror, poperror, waserror \- error handling functions
  4. .SH SYNOPSIS
  5. .ta \w'\fLchar* 'u
  6. .B
  7. void error(char*)
  8. .PP
  9. .B
  10. void nexterror(void)
  11. .PP
  12. .B
  13. void poperror(void)
  14. .PP
  15. .B
  16. int waserror(void)
  17. .SH DESCRIPTION
  18. The kernel handles error conditions using non-local gotos,
  19. similar to
  20. .IR setjmp (2),
  21. but using a stack of error labels to implement nested exception handling.
  22. This simplifies many of the internal interfaces by eliminating the need
  23. for returning and checking error codes at every level of the call stack,
  24. at the cost of requiring kernel routines to adhere to a strict discipline.
  25. .PP
  26. Each process has in its defining kernel
  27. .B Proc
  28. structure a stack of labels,
  29. .B NERR
  30. (currently 64) elements deep.
  31. A kernel function that must perform a clean up or recovery action on an error
  32. makes a stylised call to
  33. .IR waserror ,
  34. .IR nexterror
  35. and
  36. .IR poperror :
  37. .IP
  38. .EX
  39. .DT
  40. if(waserror()){
  41. /* recovery action */
  42. nexterror();
  43. }
  44. /* normal action */
  45. poperror();
  46. .EE
  47. .PP
  48. When called in the normal course of events,
  49. .I waserror
  50. registers an error handling block by pushing its label onto the stack,
  51. and returns zero.
  52. The return value of
  53. .I waserror
  54. should be tested as shown above.
  55. If non-zero (true), the calling function should perform the needed
  56. error recovery, ended by a call to
  57. .I nexterror
  58. to transfer control to the next location on the error stack.
  59. Typical recovery actions include deallocating memory, unlocking resources, and
  60. resetting state variables.
  61. .PP
  62. Within the recovery block,
  63. after handling an error condition, there must normally
  64. be a call to
  65. .I nexterror
  66. to transfer control to any error recovery lower down in the stack.
  67. The main exception is in the outermost function in a process,
  68. which must not call
  69. .I nexterror
  70. (there being nothing further on the stack), but calls
  71. .I pexit
  72. (see
  73. .IR kproc (9))
  74. instead,
  75. to terminate the process.
  76. .PP
  77. When the need to recover a particular resource has passed,
  78. a function that has called
  79. .I waserror
  80. must
  81. remove the corresponding label from the stack by calling
  82. .IR poperror .
  83. This
  84. must
  85. be done before returning from the function; otherwise, a subsequent call to
  86. .I error
  87. will return to an obsolete activation record, with unpredictable but unpleasant consequences.
  88. .PP
  89. .I Error
  90. copies the given error message, which is limited to
  91. .B ERRMAX
  92. bytes, into the
  93. .B Proc.error
  94. of the current process,
  95. enables interrupts by calling
  96. .I spllo
  97. .RI ( native
  98. only),
  99. and finally calls
  100. .I nexterror
  101. to start invoking the recovery procedures currently stacked by
  102. .IR waserror .
  103. The file
  104. .B /sys/src/9/port/error.h
  105. offer a wide selection of predefined error messages, suitable for almost any occasion.
  106. The message set by the most recent call to
  107. .I error
  108. can be obtained within the kernel by examining
  109. .B up->error
  110. and in an application, by using the
  111. .L %r
  112. directive of
  113. .IR sys-print (2).
  114. .PP
  115. A complex function can have nested error handlers.
  116. A
  117. .I waserror
  118. block will follow the acquisition of a resource, releasing it
  119. on error before calling
  120. .I nexterror,
  121. and a
  122. .I poperror
  123. will precede its release in the normal case.
  124. For example:
  125. .IP
  126. .EX
  127. .DT
  128. void
  129. outer(Thing *t)
  130. {
  131. qlock(t);
  132. if(waserror()){ /* A */
  133. qunlock(t);
  134. nexterror();
  135. }
  136. m = mallocz(READSTR, 0);
  137. if(m == nil)
  138. error(Enomem);
  139. if(waserror()){ /* B */
  140. free(m);
  141. nexterror(); /* invokes A */
  142. }
  143. inner(t);
  144. poperror(); /* pops B */
  145. free(m);
  146. poperror(); /* pops A */
  147. qunlock(t);
  148. }
  149. .sp 1v
  150. void
  151. inner(Thing *t)
  152. {
  153. if(t->bad)
  154. error(Egreg); /* error() call returns to B */
  155. t->valid++;
  156. }
  157. .EE
  158. .SH SOURCE
  159. .B /sys/src/9/port/proc.c
  160. .SH CAVEATS
  161. The description above has many instances of
  162. .IR should ,
  163. .IR will ,
  164. .I must
  165. and
  166. .IR "must not" .
  167. .SH SEE ALSO
  168. .IR panic (9)