Exception.st
changeset 2208 cc55b9f5b47e
parent 2204 0ec2bd49dd82
child 2219 0e7ba134fa8d
equal deleted inserted replaced
2207:ee6d4213b9df 2208:cc55b9f5b47e
    38 "
    38 "
    39     Instances of Exception are passed to a Signal handling block as argument.
    39     Instances of Exception are passed to a Signal handling block as argument.
    40     The handler block may perform various actions by sending corresponding messages
    40     The handler block may perform various actions by sending corresponding messages
    41     to the exception object. The following actions are possible:
    41     to the exception object. The following actions are possible:
    42 
    42 
    43         reject          - dont handle this signal;
    43 	reject          - dont handle this signal;
    44                           another handler will be searched for, 
    44 			  another handler will be searched for, 
    45                           upper in the calling hierarchy
    45 			  upper in the calling hierarchy
    46 
    46 
    47         proceed         - return from the Signal>>raise, with nil as value
    47 	proceed         - return from the Signal>>raise, with nil as value
    48 
    48 
    49         proceedWith:val - same, but return val from Signal>>raise
    49 	proceedWith:val - same, but return val from Signal>>raise
    50 
    50 
    51         return          - return from the Signal>>handle:do:, with nil as value
    51 	return          - return from the Signal>>handle:do:, with nil as value
    52 
    52 
    53         returnWith:val  - same, but return val from Signal>>handle:do:
    53 	returnWith:val  - same, but return val from Signal>>handle:do:
    54                           (this is also the handlers default, 
    54 			  (this is also the handlers default, 
    55                            if it falls through; taking the handlerBlocks value
    55 			   if it falls through; taking the handlerBlocks value
    56                            as return value)
    56 			   as return value)
    57 
    57 
    58         restart         - restart the Signal>>handle:do:, after repairing
    58 	restart         - restart the Signal>>handle:do:, after repairing
    59 
    59 
    60     Via the Exception object, the handler can also query the state of execution:
    60     Via the Exception object, the handler can also query the state of execution:
    61     where the Signal was raised, where the handler is, the signal which caused
    61     where the Signal was raised, where the handler is, the signal which caused
    62     the error and the errorString passed when the signal was raised. Also, an optional
    62     the error and the errorString passed when the signal was raised. Also, an optional
    63     parameter can be passed - the use is signal specific.:
    63     parameter can be passed - the use is signal specific.:
    64 
    64 
    65     [instance variables:]
    65     [instance variables:]
    66         signal           <Signal>     the signal which caused the exception
    66 	signal           <Signal>     the signal which caused the exception
    67 
    67 
    68         parameter        <Object>     a parameter (if any) which was passed when raising
    68 	parameter        <Object>     a parameter (if any) which was passed when raising
    69                                       the signal (only if raised with #raiseWith:aParameter)
    69 				      the signal (only if raised with #raiseWith:aParameter)
    70 
    70 
    71         errorString      <String>     an errorString 
    71 	errorString      <String>     an errorString 
    72                                       (usually the signals own errorString, but sometimes
    72 				      (usually the signals own errorString, but sometimes
    73                                        changed explicitely in #raiseWith:errorString:)
    73 				       changed explicitely in #raiseWith:errorString:)
    74 
    74 
    75         suspendedContext <Context>    the context in which the raise occured
    75 	suspendedContext <Context>    the context in which the raise occured
    76 
    76 
    77         handlerContext   <Context>    the context of the handler (if any)
    77 	handlerContext   <Context>    the context of the handler (if any)
    78 
    78 
    79         resumeBlock      <Block>      private to the exception; needed to perform resume action
    79 	resumeBlock      <Block>      private to the exception; needed to perform resume action
    80 
    80 
    81         rejectBlock      <Block>      private to the exception; needed to perform reject action
    81 	rejectBlock      <Block>      private to the exception; needed to perform reject action
    82 
    82 
    83     In case of an unhandled signal raise, Exceptions EmergenyHandler will be evaluated. 
    83     In case of an unhandled signal raise, Exceptions EmergenyHandler will be evaluated. 
    84     The default emergeny handler will enter the debugger.
    84     The default emergeny handler will enter the debugger.
    85 
    85 
    86     For applications, which do not want Debuggers to come up, other handlers are
    86     For applications, which do not want Debuggers to come up, other handlers are
    87     possible.
    87     possible.
    88     For example, to get the typical C++ behavior, use:
    88     For example, to get the typical C++ behavior, use:
    89         Exception emergencyHandler:[:ex | Smalltalk exitWithCoreDump]
    89 	Exception emergencyHandler:[:ex | Smalltalk exitWithCoreDump]
    90 
    90 
    91 
    91 
    92     [Class variables:]
    92     [Class variables:]
    93         EmergencyHandler <Block>    this block is evaluated, if no handler was defined
    93 	EmergencyHandler <Block>    this block is evaluated, if no handler was defined
    94                                     for a signal (i.e. this one is responsible for the
    94 				    for a signal (i.e. this one is responsible for the
    95                                     unhandled exception debugger).
    95 				    unhandled exception debugger).
    96                                     Having this being a block allows to globally catch
    96 				    Having this being a block allows to globally catch
    97                                     these errors - even when no enclosing handler-scope
    97 				    these errors - even when no enclosing handler-scope
    98                                     around the erronous code exists.
    98 				    around the erronous code exists.
    99                                     (as the catch/through does).
    99 				    (as the catch/through does).
   100 
   100 
   101         RecursiveExceptionSignal
   101 	RecursiveExceptionSignal
   102                          <Signal>   raised when within a handler for some signal,
   102 			 <Signal>   raised when within a handler for some signal,
   103                                     the same signal is raised again.
   103 				    the same signal is raised again.
   104 
   104 
   105 
   105 
   106     [see also:]
   106     [see also:]
   107         Signal  SignalSet QuerySignal
   107 	Signal  SignalSet QuerySignal
   108         Context Block
   108 	Context Block
   109         Object DebugView
   109 	Object DebugView
   110         (``Exception handling and signals'': programming/exceptions.html)
   110 	(``Exception handling and signals'': programming/exceptions.html)
   111 
   111 
   112     [author:]
   112     [author:]
   113         Claus Gittinger
   113 	Claus Gittinger
   114 "
   114 "
   115 !
   115 !
   116 
   116 
   117 examples
   117 examples
   118 "
   118 "
   124     Some commonly used (useful) emergency handlers are provided in the
   124     Some commonly used (useful) emergency handlers are provided in the
   125     'useful handlers' section; try them to learn more
   125     'useful handlers' section; try them to learn more
   126     (especially, the mailingHandler is fun).
   126     (especially, the mailingHandler is fun).
   127 
   127 
   128     Define a handler:
   128     Define a handler:
   129                                                                 [exBegin]
   129 								[exBegin]
   130         Exception emergencyHandler:(Exception abortingEmergencyHandler)
   130 	Exception emergencyHandler:(Exception abortingEmergencyHandler)
   131                                                                 [exEnd]
   131 								[exEnd]
   132 
   132 
   133 
   133 
   134     try some exception (for demonstration, in some other process):
   134     try some exception (for demonstration, in some other process):
   135                                                                 [exBegin]
   135 								[exBegin]
   136         [
   136 	[
   137             #(1 2 3) at:4
   137 	    #(1 2 3) at:4
   138         ] fork.
   138 	] fork.
   139                                                                 [exEnd]
   139 								[exEnd]
   140 
   140 
   141     cleanup:
   141     cleanup:
   142                                                                 [exBegin]
   142 								[exBegin]
   143         Exception emergencyHandler:nil
   143 	Exception emergencyHandler:nil
   144                                                                 [exEnd]
   144 								[exEnd]
   145 
   145 
   146 
   146 
   147     A handler which dumps information to a file (watch the file 'errorTrace.stx'):
   147     A handler which dumps information to a file (watch the file 'errorTrace.stx'):
   148                                                                 [exBegin]
   148 								[exBegin]
   149         Exception emergencyHandler:(Exception dumpingEmergencyHandler)
   149 	Exception emergencyHandler:(Exception dumpingEmergencyHandler)
   150                                                                 [exEnd]
   150 								[exEnd]
   151 
   151 
   152     A handler which sends you mail:
   152     A handler which sends you mail:
   153                                                                 [exBegin]
   153 								[exBegin]
   154         Exception emergencyHandler:(Exception mailingEmergencyHandler)
   154 	Exception emergencyHandler:(Exception mailingEmergencyHandler)
   155                                                                 [exEnd]
   155 								[exEnd]
   156 "
   156 "
   157 ! !
   157 ! !
   158 
   158 
   159 !Exception class methodsFor:'initialization'!
   159 !Exception class methodsFor:'initialization'!
   160 
   160 
   215 
   215 
   216     "
   216     "
   217      set it up, when called the first time
   217      set it up, when called the first time
   218     "
   218     "
   219     EmergencyHandler isNil ifTrue:[
   219     EmergencyHandler isNil ifTrue:[
   220         EmergencyHandler := [:ex |
   220 	EmergencyHandler := [:ex |
   221             "
   221 	    "
   222              sending it to the signal allows per-signal specific
   222 	     sending it to the signal allows per-signal specific
   223              debuggers to be implemented in the future
   223 	     debuggers to be implemented in the future
   224              (for example, segv in primitive code could show things 
   224 	     (for example, segv in primitive code could show things 
   225               on the C-level ..)
   225 	      on the C-level ..)
   226             "
   226 	    "
   227             (ex signal) enterDebuggerWith:ex message:(ex errorString).
   227 	    (ex signal) enterDebuggerWith:ex message:(ex errorString).
   228         ]
   228 	]
   229     ].
   229     ].
   230 
   230 
   231     ^ EmergencyHandler
   231     ^ EmergencyHandler
   232 
   232 
   233     "Modified: 15.1.1997 / 20:50:37 / cg"
   233     "Modified: 15.1.1997 / 20:50:37 / cg"
   241 
   241 
   242     "ST-80 behavior of first showing a notifier:
   242     "ST-80 behavior of first showing a notifier:
   243      (I prefer to get right into the debugger, though)
   243      (I prefer to get right into the debugger, though)
   244 
   244 
   245      Exception
   245      Exception
   246         emergencyHandler:
   246 	emergencyHandler:
   247             [:ex | self errorNotify:ex errorString ]
   247 	    [:ex | self errorNotify:ex errorString ]
   248     "
   248     "
   249 
   249 
   250     "ST-X behavior of going right into the debugger:
   250     "ST-X behavior of going right into the debugger:
   251 
   251 
   252      Exception
   252      Exception
   253         emergencyHandler:nil
   253 	emergencyHandler:nil
   254     "
   254     "
   255 
   255 
   256     "automatically aborting current operation, on error:
   256     "automatically aborting current operation, on error:
   257      (may be useful for end-user apps; make certain, 
   257      (may be useful for end-user apps; make certain, 
   258       you have abortSignal handlers at appropriate places)
   258       you have abortSignal handlers at appropriate places)
   259 
   259 
   260      Exception
   260      Exception
   261         emergencyHandler:
   261 	emergencyHandler:
   262             [:ex | Object abortSignal raise. ex return. ]
   262 	    [:ex | Object abortSignal raise. ex return. ]
   263     "
   263     "
   264 
   264 
   265     "finally, traditional language system behavior; dump core ;-)
   265     "finally, traditional language system behavior; dump core ;-)
   266 
   266 
   267      Exception
   267      Exception
   268         emergencyHandler:
   268 	emergencyHandler:
   269             [:ex | Smalltalk exitWithCoreDump. ]
   269 	    [:ex | Smalltalk exitWithCoreDump. ]
   270     "
   270     "
   271 
   271 
   272     "Modified: 15.1.1997 / 20:49:06 / cg"
   272     "Modified: 15.1.1997 / 20:49:06 / cg"
   273 ! !
   273 ! !
   274 
   274 
   278     "return a block (usable as an emergency handler), 
   278     "return a block (usable as an emergency handler), 
   279      which aborts after showing a warnBox.
   279      which aborts after showing a warnBox.
   280      This is useful for endUser applications"
   280      This is useful for endUser applications"
   281 
   281 
   282     ^ [:ex | self warn:'Error: ' , ex errorString.
   282     ^ [:ex | self warn:'Error: ' , ex errorString.
   283              AbortSignal raise 
   283 	     AbortSignal raise 
   284       ]
   284       ]
   285 
   285 
   286     "test with (try a few halts or CTRL-C's):
   286     "test with (try a few halts or CTRL-C's):
   287      Exception emergencyHandler:(Exception abortingEmergencyHandler)
   287      Exception emergencyHandler:(Exception abortingEmergencyHandler)
   288     "
   288     "
   303      This is useful, for endUser application, which are still being
   303      This is useful, for endUser application, which are still being
   304      debugged (i.e. the programmers may have a look at the traceFile
   304      debugged (i.e. the programmers may have a look at the traceFile
   305      from time to time).
   305      from time to time).
   306 
   306 
   307      Notice:
   307      Notice:
   308          The code below is just an example; you may want to change the
   308 	 The code below is just an example; you may want to change the
   309          name of the error-file in your application
   309 	 name of the error-file in your application
   310          (but please: copy the code; do not modify here)"
   310 	 (but please: copy the code; do not modify here)"
   311 
   311 
   312     ^ [:ex | 
   312     ^ [:ex | 
   313              |str printedException|
   313 	     |str printedException|
   314 
   314 
   315              ex signal == Signal noHandlerSignal ifTrue:[
   315 	     ex signal == Signal noHandlerSignal ifTrue:[
   316                 printedException := ex parameter.
   316 		printedException := ex parameter.
   317              ] ifFalse:[
   317 	     ] ifFalse:[
   318                 printedException := ex
   318 		printedException := ex
   319              ].
   319 	     ].
   320 
   320 
   321              "/ user interruption is handled specially:
   321 	     "/ user interruption is handled specially:
   322              "/ allow user to choose between proceeding or aborting
   322 	     "/ allow user to choose between proceeding or aborting
   323              "/ but never dump that information to the file.
   323 	     "/ but never dump that information to the file.
   324 
   324 
   325              printedException signal == Object userInterruptSignal ifTrue:[
   325 	     printedException signal == Object userInterruptSignal ifTrue:[
   326                   (self confirm:'abort current action ?') ifTrue:[
   326 		  (self confirm:'abort current action ?') ifTrue:[
   327                       AbortSignal raise
   327 		      AbortSignal raise
   328                   ].
   328 		  ].
   329                   ex proceed
   329 		  ex proceed
   330              ].
   330 	     ].
   331 
   331 
   332              "/
   332 	     "/
   333              "/ dump it to 'errorTrace.stx'
   333 	     "/ dump it to 'errorTrace.stx'
   334              "/
   334 	     "/
   335              str := 'errorTrace.stx' asFilename appendingWriteStream.
   335 	     str := 'errorTrace.stx' asFilename appendingWriteStream.
   336 
   336 
   337              str nextPutLine:('******************************* '
   337 	     str nextPutLine:('******************************* '
   338                               , AbsoluteTime now printString
   338 			      , AbsoluteTime now printString
   339                               , ' *******************************').
   339 			      , ' *******************************').
   340              str cr.
   340 	     str cr.
   341 
   341 
   342              str nextPutLine:('** Error: ' , printedException errorString).
   342 	     str nextPutLine:('** Error: ' , printedException errorString).
   343              str nextPutLine:('** Signal: ' , printedException signal printString).
   343 	     str nextPutLine:('** Signal: ' , printedException signal printString).
   344              str nextPutLine:('** Parameter: ' , printedException parameter printString).
   344 	     str nextPutLine:('** Parameter: ' , printedException parameter printString).
   345              str nextPutLine:('** Process: ' , Processor activeProcess printString).
   345 	     str nextPutLine:('** Process: ' , Processor activeProcess printString).
   346              str nextPutLine:('** Backtrace:').
   346 	     str nextPutLine:('** Backtrace:').
   347              str cr.
   347 	     str cr.
   348         
   348         
   349              printedException suspendedContext fullPrintAllOn:str.
   349 	     printedException suspendedContext fullPrintAllOn:str.
   350              str cr.
   350 	     str cr.
   351              str cr.
   351 	     str cr.
   352              str close.
   352 	     str close.
   353 
   353 
   354              self warn:printedException errorString.
   354 	     self warn:printedException errorString.
   355              AbortSignal raise 
   355 	     AbortSignal raise 
   356       ]
   356       ]
   357 
   357 
   358     "test with (try a few halts or CTRL-C's):
   358     "test with (try a few halts or CTRL-C's):
   359      Exception emergencyHandler:(Exception dumpingEmergencyHandler)
   359      Exception emergencyHandler:(Exception dumpingEmergencyHandler)
   360     "
   360     "
   373      which shows a warnBox and optionally mails a stackBacktrace to a maintainer.
   373      which shows a warnBox and optionally mails a stackBacktrace to a maintainer.
   374      This is useful, for endUser application, which are still being
   374      This is useful, for endUser application, which are still being
   375      debugged (i.e. the programmers may have a look at the errors).
   375      debugged (i.e. the programmers may have a look at the errors).
   376 
   376 
   377      Notice: the stuff here is a demonstration only; it should be modified
   377      Notice: the stuff here is a demonstration only; it should be modified
   378              for your particular environment ...
   378 	     for your particular environment ...
   379              ... but please: copy the code and modify there;
   379 	     ... but please: copy the code and modify there;
   380              leave the stuff below as it is."
   380 	     leave the stuff below as it is."
   381 
   381 
   382     ^ [:ex | 
   382     ^ [:ex | 
   383             |str printedException doMail emergencyMailReceiver pipe|
   383 	    |str printedException doMail emergencyMailReceiver pipe|
   384 
   384 
   385             ex signal == Signal noHandlerSignal ifTrue:[
   385 	    ex signal == Signal noHandlerSignal ifTrue:[
   386                printedException := ex parameter.
   386 	       printedException := ex parameter.
   387             ] ifFalse:[
   387 	    ] ifFalse:[
   388                printedException := ex
   388 	       printedException := ex
   389             ].
   389 	    ].
   390 
   390 
   391              "/ user interruption is handled specially:
   391 	     "/ user interruption is handled specially:
   392              "/ allow user to choose between proceeding or aborting
   392 	     "/ allow user to choose between proceeding or aborting
   393              "/ but never dump that information to the file.
   393 	     "/ but never dump that information to the file.
   394 
   394 
   395              printedException signal == Object userInterruptSignal ifTrue:[
   395 	     printedException signal == Object userInterruptSignal ifTrue:[
   396                   (self confirm:'abort current action ?') ifTrue:[
   396 		  (self confirm:'abort current action ?') ifTrue:[
   397                       AbortSignal raise
   397 		      AbortSignal raise
   398                   ].
   398 		  ].
   399                   ex proceed
   399 		  ex proceed
   400              ].
   400 	     ].
   401 
   401 
   402             "/ somehow get the name of the guy to receive the mail
   402 	    "/ somehow get the name of the guy to receive the mail
   403             "/ you have to implement that yourself.
   403 	    "/ you have to implement that yourself.
   404 
   404 
   405             "/ emergencyMailReceiver := OneOfYourClass getEmergencyMailReceiver.
   405 	    "/ emergencyMailReceiver := OneOfYourClass getEmergencyMailReceiver.
   406             emergencyMailReceiver := OperatingSystem getLoginName.
   406 	    emergencyMailReceiver := OperatingSystem getLoginName.
   407 
   407 
   408             emergencyMailReceiver isNil ifTrue:[
   408 	    emergencyMailReceiver isNil ifTrue:[
   409                 self warn:(printedException errorString 
   409 		self warn:(printedException errorString 
   410                            , '\\No mailing to service people possible.') withCRs.
   410 			   , '\\No mailing to service people possible.') withCRs.
   411                 doMail := false.
   411 		doMail := false.
   412             ] ifFalse:[
   412 	    ] ifFalse:[
   413                 doMail := self confirm:(printedException errorString 
   413 		doMail := self confirm:(printedException errorString 
   414                                         , '\\Mail error information to the service people (' 
   414 					, '\\Mail error information to the service people (' 
   415                                         , emergencyMailReceiver , ') ?') withCRs
   415 					, emergencyMailReceiver , ') ?') withCRs
   416             ].
   416 	    ].
   417             doMail ifTrue:[
   417 	    doMail ifTrue:[
   418                 str := '' writeStream.
   418 		str := '' writeStream.
   419 
   419 
   420                 str nextPutLine:('Error notification from '
   420 		str nextPutLine:('Error notification from '
   421                                 , OperatingSystem getLoginName
   421 				, OperatingSystem getLoginName
   422                                 , '@'
   422 				, '@'
   423                                 , OperatingSystem getHostName).
   423 				, OperatingSystem getHostName).
   424                 str cr.
   424 		str cr.
   425 
   425 
   426                 str nextPutLine:('Time: ' , AbsoluteTime now printString).
   426 		str nextPutLine:('Time: ' , AbsoluteTime now printString).
   427                 str nextPutLine:('Error: ', printedException errorString).
   427 		str nextPutLine:('Error: ', printedException errorString).
   428                 str nextPutLine:('Signal: ', printedException signal printString).
   428 		str nextPutLine:('Signal: ', printedException signal printString).
   429                 str nextPutLine:('Parameter: ', printedException parameter printString).
   429 		str nextPutLine:('Parameter: ', printedException parameter printString).
   430                 str nextPutLine:('Process: ', Processor activeProcess printString).
   430 		str nextPutLine:('Process: ', Processor activeProcess printString).
   431                 str nextPutLine:'Backtrace:'.
   431 		str nextPutLine:'Backtrace:'.
   432                 str cr.
   432 		str cr.
   433 
   433 
   434                 printedException suspendedContext fullPrintAllOn:str.
   434 		printedException suspendedContext fullPrintAllOn:str.
   435                 str cr;cr.
   435 		str cr;cr.
   436 
   436 
   437                 str close.
   437 		str close.
   438 
   438 
   439                 pipe := PipeStream 
   439 		pipe := PipeStream 
   440                             writingTo:'mail ', emergencyMailReceiver.
   440 			    writingTo:'mail ', emergencyMailReceiver.
   441                 pipe notNil ifTrue:[
   441 		pipe notNil ifTrue:[
   442                     pipe nextPutLine:'Subject: automatic error report'.
   442 		    pipe nextPutLine:'Subject: automatic error report'.
   443                     pipe nextPutAll:str contents.
   443 		    pipe nextPutAll:str contents.
   444                     pipe cr.
   444 		    pipe cr.
   445                     pipe close.
   445 		    pipe close.
   446                 ]
   446 		]
   447              ].
   447 	     ].
   448 
   448 
   449              AbortSignal raise 
   449 	     AbortSignal raise 
   450       ]
   450       ]
   451 
   451 
   452     "test with (try a few halts or CTRL-C's):
   452     "test with (try a few halts or CTRL-C's):
   453      Exception emergencyHandler:(Exception mailingEmergencyHandler)
   453      Exception emergencyHandler:(Exception mailingEmergencyHandler)
   454     "
   454     "
   626      ATTENTION: the code below depends on being called by #raise or
   626      ATTENTION: the code below depends on being called by #raise or
   627      #raiseRequest for proper operation (it skips the sending context)."
   627      #raiseRequest for proper operation (it skips the sending context)."
   628 
   628 
   629     |con block noHandlerSignal any msg sel conArg1
   629     |con block noHandlerSignal any msg sel conArg1
   630      theSignal c ex1 activeHandlers inHandler rejected
   630      theSignal c ex1 activeHandlers inHandler rejected
   631      lastHandler h|
   631      lastHandler h raiseReceiver|
   632 
   632 
   633     con := thisContext sender.  "the raise/raiseRequest-context"
   633     con := thisContext sender.  "the raise/raiseRequest-context"
   634     con := con sender.          "the signal raise context"
   634     con := con sender.          "the signal raise context"
   635 
   635 
   636     theSignal := con receiver.
   636     theSignal := con receiver.
   637     theSignal isSignal ifFalse:[
   637     theSignal isSignal ifFalse:[
   638         self halt:'unexpected non-Signal in calling context'.
   638 	self halt:'unexpected non-Signal in calling context'.
   639     ].
   639     ].
   640 
   640 
   641 "/ 'search handler for: ' print. theSignal displayString printCR.
   641 "/ 'search handler for: ' print. theSignal displayString printCR.
   642 
   642 
   643     inHandler := false.
   643     inHandler := false.
   649     "/ from within a handler (which would lead to re-executing the
   649     "/ from within a handler (which would lead to re-executing the
   650     "/ same handler)
   650     "/ same handler)
   651     "/ the code below collects active handlers ...
   651     "/ the code below collects active handlers ...
   652 
   652 
   653     [c notNil] whileTrue:[
   653     [c notNil] whileTrue:[
   654         sel := c selector.
   654 	c := c findContextWithSelector:#doRaise or:nil.
   655         sel == #doRaise ifTrue:[
   655 	c notNil ifTrue:[
   656             ex1 := c receiver.
   656 
   657             ex1 species == self species ifTrue:[
   657 	    ex1 := c receiver.
   658                 c := c sender.
   658 	    ((ex1 class == self class)
   659                 (c notNil and:[c receiver == ex1]) ifTrue:[
   659 	    or:[ex1 species == self species]) ifTrue:[
   660                     c := c sender.
   660 		c := c sender.
   661                     c notNil ifTrue:[
   661 		(c notNil and:[c receiver == ex1]) ifTrue:[
   662                         "/ the common case (really ?) first
   662 		    c := c sender.
   663                         (c receiver == theSignal) ifTrue:[
   663 		    c notNil ifTrue:[
   664                             (c selector startsWith:'raise') ifTrue:[
   664 
   665                                 h := ex1 handlerContext.
   665 			"/ the common case (really ?) first
   666                                 h notNil ifTrue:[
   666 			((raiseReceiver := c receiver) == theSignal) ifTrue:[
   667                                     activeHandlers isNil ifTrue:[
   667 			    (c selector startsWith:'raise') ifTrue:[
   668                                         activeHandlers := OrderedCollection new
   668 				h := ex1 handlerContext.
   669                                     ].
   669 				h notNil ifTrue:[
   670                             
   670 				    activeHandlers isNil ifTrue:[
   671                                     lastHandler := h.
   671 					activeHandlers := OrderedCollection new
   672                                     activeHandlers add:lastHandler.
   672 				    ].
   673                                     inHandler := true.
   673 
   674                                     c := lastHandler.
   674 				    lastHandler := h.
   675 "/ 'skip over active handler: ' print. c displayString printCR.
   675 				    activeHandlers add:lastHandler.
   676                                 ]
   676 				    inHandler := true.
   677                             ]
   677 				    c := lastHandler.
   678                         ] ifFalse:[
   678 				]
   679                             c receiver isSignal ifTrue:[
   679 			    ]
   680                                 (c selector startsWith:'raise') ifTrue:[
   680 			] ifFalse:[
   681                                     h := ex1 handlerContext.
   681 			    raiseReceiver isSignal ifTrue:[
   682                                     h notNil ifTrue:[
   682 				(c selector startsWith:'raise') ifTrue:[
   683                                         (h receiver accepts:theSignal) ifTrue:[
   683 				    h := ex1 handlerContext.
   684 
   684 				    h notNil ifTrue:[
   685                                         activeHandlers isNil ifTrue:[
   685 					(h receiver accepts:theSignal) ifTrue:[
   686                                             activeHandlers := OrderedCollection new
   686 
   687                                         ].
   687 					    activeHandlers isNil ifTrue:[
   688                                         lastHandler := h.
   688 						activeHandlers := OrderedCollection new
   689                                         activeHandlers add:lastHandler.
   689 					    ].
   690                                         inHandler := true.
   690 					    lastHandler := h.
   691                                         c := lastHandler.
   691 					    activeHandlers add:lastHandler.
   692 "/ 'skip2 over active handler: ' print. h displayString printCR.
   692 					    inHandler := true.
   693                                         ]
   693 					    c := lastHandler.
   694                                     ]    
   694 					]
   695                                 ]    
   695 				    ]    
   696                             ]    
   696 				]    
   697                         ]
   697 			    ]    
   698                     ]
   698 			]
   699                 ]
   699 		    ]
   700             ].
   700 		]
   701         ].
   701 	    ].
   702         c := c sender.
   702 	    c := c sender.
       
   703 	]
   703     ].
   704     ].
   704 
   705 
       
   706     "/ now, start searching for a handler,
       
   707     "/ start search above the last active handler
       
   708 
   705     lastHandler notNil ifTrue:[
   709     lastHandler notNil ifTrue:[
   706 "/        'skip over last active handler: ' print. lastHandler displayString printCR.
   710 	con := lastHandler sender.
   707         con := lastHandler sender.
       
   708     ].
   711     ].
   709 
   712 
   710     any := false.
   713     any := false.
   711     [con notNil] whileTrue:[
   714     [con notNil] whileTrue:[
   712         con isBlockContext ifFalse:[
   715 	con isBlockContext ifFalse:[
   713 
   716 
   714             "/ new behavior:
   717 	    sel := con selector.
   715             (activeHandlers notNil
   718 
   716              and:[activeHandlers includesIdentical:con]) ifTrue:[
   719 	    ((sel == #'handle:do:') 
   717                 'skip activeHandler: ' print. con displayString printCR.
   720 	    or:[((sel == #'handle:from:do:') 
   718 
   721 		and:[(con argAt:2) == originator])]) ifTrue:[
   719             ] ifFalse:[
   722 
   720                 sel := con selector.
   723 		"/ new behavior:
   721 
   724 		(activeHandlers notNil
   722                 ((sel == #'handle:do:') 
   725 		 and:[activeHandlers includesIdentical:con]) ifTrue:[
   723                 or:[((sel == #'handle:from:do:') 
   726 		    'skip activeHandler: ' print. con displayString printCR.
   724                     and:[(con argAt:2) == originator])]) ifTrue:[
   727 
   725                     "
   728 		] ifFalse:[
   726                      if this is the Signal>>handle:do: context
   729 		    "
   727                      or a SignalSet>>handle:do: context with self in it,
   730 		     if this is the Signal>>handle:do: context
   728                      call the handler
   731 		     or a SignalSet>>handle:do: context with self in it,
   729                     "
   732 		     call the handler
   730                     (con receiver accepts:signal) ifTrue:[
   733 		    "
   731                         "call the handler"
   734 		    (con receiver accepts:signal) ifTrue:[
   732 
   735 			"call the handler"
   733                         conArg1 := con argAt:1.
   736 
   734 
   737 			conArg1 := con argAt:1.
   735                         handlerContext := con.
   738 
   736                         any := true.
   739 			handlerContext := con.
   737 
   740 			any := true.
   738                         self doCallHandler:conArg1.
   741 
   739 
   742 			self doCallHandler:conArg1.
   740                         "if the handler rejects, we arrive here"
   743 
   741                         "continue search for another handler"
   744 			"if the handler rejects, we arrive here"
   742                         rejected := true.
   745 			"continue search for another handler"
   743                     ].
   746 			rejected := true.
   744                 ]
   747 		    ].
   745             ]
   748 		]
   746         ].
   749 	    ]
   747         con := con sender
   750 	].
       
   751 	con := con sender
   748     ].
   752     ].
   749 
   753 
   750     activeHandlers := nil.
   754     activeHandlers := nil.
   751 
       
   752 "/    (inHandler "and:[rejected ~~ true]") ifTrue:[
       
   753 "/        "
       
   754 "/         mhmh - an error while in a handler
       
   755 "/         here, we do not fall back to the noHandlerSignal/staticHandler
       
   756 "/         (makes debugging easier)
       
   757 "/
       
   758 "/         Should we ?
       
   759 "/        "
       
   760 "/        ((signal == RecursiveExceptionSignal)
       
   761 "/        or:[RecursiveExceptionSignal isNil]) ifTrue:[
       
   762 "/            "
       
   763 "/             ... either while handling RecursiveExceptionSignal
       
   764 "/             or at startup when RecursiveExceptionSignal is not yet
       
   765 "/             created -
       
   766 "/             - go immediately into the debugger.
       
   767 "/            "
       
   768 "/            ^ self enterDebuggerWith:self
       
   769 "/                             message:'recursive signal raise'
       
   770 "/        ].
       
   771 "/        ^ RecursiveExceptionSignal 
       
   772 "/            raiseRequestWith:self 
       
   773 "/                 errorString:('recursive signal raise: (' , errorString , ')')
       
   774 "/    ].
       
   775 
   755 
   776     "
   756     "
   777      we arrive here, if either no handler was found, or none of the
   757      we arrive here, if either no handler was found, or none of the
   778      handlers did a return (i.e. every handler rejected or fell through).
   758      handlers did a return (i.e. every handler rejected or fell through).
   779     "
   759     "
   780     "
   760     "
   781      try per signal handler
   761      try per signal handler
   782     "
   762     "
   783     (block := signal handlerBlock) isNil ifTrue:[
   763     (block := signal handlerBlock) isNil ifTrue:[
   784         "/
   764 	"/
   785         "/ if its a querySignal, ignore it
   765 	"/ if its a querySignal, ignore it
   786         "/
   766 	"/
   787         signal isQuerySignal ifTrue:[^ nil].
   767 	signal isQuerySignal ifTrue:[^ nil].
   788 
   768 
   789         "/
   769 	"/
   790         "/ if it is not the NoHandlerSignal, raise it ...
   770 	"/ if it is not the NoHandlerSignal, raise it ...
   791         "/ passing the receiver as parameter.
   771 	"/ passing the receiver as parameter.
   792         "/
   772 	"/
   793         signal ~~ (noHandlerSignal := Signal noHandlerSignal) ifTrue:[
   773 	signal ~~ (noHandlerSignal := Signal noHandlerSignal) ifTrue:[
   794             noHandlerSignal notNil ifTrue:[
   774 	    noHandlerSignal notNil ifTrue:[
   795                 any ifTrue:[
   775 		any ifTrue:[
   796                     msg := 'unhandled (rejected)'
   776 		    msg := 'unhandled (rejected)'
   797                 ] ifFalse:[
   777 		] ifFalse:[
   798                     msg := 'unhandled'
   778 		    msg := 'unhandled'
   799                 ].
   779 		].
   800                 msg := msg , ' exception: (' , errorString , ')'.
   780 		msg := msg , ' exception: (' , errorString , ')'.
   801                 ^ noHandlerSignal 
   781 		^ noHandlerSignal 
   802                       raiseRequestWith:self 
   782 		      raiseRequestWith:self 
   803                            errorString:msg
   783 			   errorString:msg
   804                                     in:self suspendedContext
   784 				    in:self suspendedContext
   805             ].
   785 	    ].
   806             "/
   786 	    "/
   807             "/ mhmh - an error during early startup; noHandlerSignal is
   787 	    "/ mhmh - an error during early startup; noHandlerSignal is
   808             "/ not yet defined.
   788 	    "/ not yet defined.
   809             "/
   789 	    "/
   810             ^ MiniDebugger enterWithMessage:errorString
   790 	    ^ MiniDebugger enterWithMessage:errorString
   811         ].
   791 	].
   812 
   792 
   813         "
   793 	"
   814          mhmh - smells like trouble - there is no handler and
   794 	 mhmh - smells like trouble - there is no handler and
   815          no per-signal handler block.
   795 	 no per-signal handler block.
   816          Look for either a per-process emergencyHandlerBlock 
   796 	 Look for either a per-process emergencyHandlerBlock 
   817          or the global emergencyHandler (from Exception) ...
   797 	 or the global emergencyHandler (from Exception) ...
   818         "
   798 	"
   819         Processor notNil ifTrue:[ 
   799 	Processor notNil ifTrue:[ 
   820             "care for signal during startup (Processor not yet created)"
   800 	    "care for signal during startup (Processor not yet created)"
   821             block := Processor activeProcess emergencySignalHandler.
   801 	    block := Processor activeProcess emergencySignalHandler.
   822         ].
   802 	].
   823         block isNil ifTrue:[
   803 	block isNil ifTrue:[
   824             block := Exception emergencyHandler.
   804 	    block := Exception emergencyHandler.
   825             block isNil ifTrue:[
   805 	    block isNil ifTrue:[
   826                 "care for error during startup (Exception not yet initialized)"
   806 		"care for error during startup (Exception not yet initialized)"
   827                 ^ MiniDebugger enterWithMessage:errorString
   807 		^ MiniDebugger enterWithMessage:errorString
   828             ].
   808 	    ].
   829         ].
   809 	].
   830     ].
   810     ].
   831     "... and call it"
   811     "... and call it"
   832     ^ block value:self.
   812     ^ block value:self.
   833 
   813 
   834     "Created: 12.5.1996 / 15:09:39 / cg"
   814     "Created: 12.5.1996 / 15:09:39 / cg"
   836 !
   816 !
   837 
   817 
   838 raise
   818 raise
   839     "actually raise a non-proceedable exception.
   819     "actually raise a non-proceedable exception.
   840      CAVEAT:
   820      CAVEAT:
   841          For now, in ST/X all signals are proceedable."
   821 	 For now, in ST/X all signals are proceedable."
   842 
   822 
   843     resumeBlock := [:value | ^ value].
   823     resumeBlock := [:value | ^ value].
   844     ^ self doRaise
   824     ^ self doRaise
   845 
   825 
   846     "Modified: 12.5.1996 / 15:09:47 / cg"
   826     "Modified: 12.5.1996 / 15:09:47 / cg"
   869 ! !
   849 ! !
   870 
   850 
   871 !Exception class methodsFor:'documentation'!
   851 !Exception class methodsFor:'documentation'!
   872 
   852 
   873 version
   853 version
   874     ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.45 1997-01-18 18:37:26 cg Exp $'
   854     ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.46 1997-01-20 11:52:22 cg Exp $'
   875 ! !
   855 ! !
   876 Exception initialize!
   856 Exception initialize!