43 " |
45 " |
44 ! |
46 ! |
45 |
47 |
46 documentation |
48 documentation |
47 " |
49 " |
48 Exception and its subclasses implement the same protocal as Signal. |
50 Exception and its subclasses implement the same protocol as Signal. |
49 So class based exceptions may be implemented as subclasses of Exception. |
51 So class based exceptions may be implemented as subclasses of Exception. |
50 |
52 |
51 Instances of Exception are passed to a Signal handling block as argument. |
53 Instances of Exception are passed to a Signal handling block as argument. |
52 The handler block may perform various actions by sending corresponding messages |
54 The handler block may perform various actions by sending corresponding messages |
53 to the exception object. The following actions are possible: |
55 to the exception object. The following actions are possible: |
54 |
56 |
55 reject - dont handle this signal; |
57 reject - don't handle this signal; |
56 another handler will be searched for, |
58 another handler will be searched for, |
57 upper in the calling hierarchy |
59 upper in the calling hierarchy |
58 |
60 |
59 proceed - return from the Signal>>raise, with nil as value |
61 proceed - return from the Signal>>raise, with nil as value |
60 |
62 |
61 proceedWith:val - same, but return val from Signal>>raise |
63 proceedWith:val - same, but return val from Signal>>raise |
62 |
64 |
63 return - return from the Signal>>handle:do:, with nil as value |
65 return - return from the Signal>>handle:do:, with nil as value |
64 |
66 |
65 returnWith:val - same, but return val from Signal>>handle:do: |
67 returnWith:val - same, but return val from Signal>>handle:do: |
66 (this is also the handlers default, |
68 (this is also the handlers default, |
67 if it falls through; taking the handlerBlocks value |
69 if it falls through; taking the handlerBlocks value |
68 as return value) |
70 as return value) |
69 |
71 |
70 restart - restart the Signal>>handle:do:, after repairing |
72 restart - restart the Signal>>handle:do:, after repairing |
71 |
73 |
72 Via the Exception object, the handler can also query the state of execution: |
74 Via the Exception object, the handler can also query the state of execution: |
73 where the Signal was raised, where the handler is, the signal which caused |
75 where the Signal was raised, where the handler is, the signal which caused |
74 the error and the errorString passed when the signal was raised. Also, an optional |
76 the error and the errorString passed when the signal was raised. Also, an optional |
75 parameter can be passed - the use is signal specific.: |
77 parameter can be passed - the use is signal specific. |
76 |
78 |
77 [instance variables:] |
79 [instance variables:] |
78 signal <Signal> the signal which caused the exception |
80 signal <Signal> the signal which caused the exception |
79 |
81 |
80 parameter <Object> a parameter (if any) which was passed when raising |
82 parameter <Object> a parameter (if any) which was passed when raising |
81 the signal (only if raised with #raiseWith:aParameter) |
83 the signal (only if raised with #raiseWith:aParameter) |
82 |
84 |
83 errorString <String> an errorString |
85 errorString <String> an errorString |
84 (usually the signals own errorString, but sometimes |
86 (usually the signals own errorString, but sometimes |
85 changed explicitely in #raiseWith:errorString:) |
87 changed explicitely in #raiseWith:errorString:) |
86 |
88 |
87 suspendedContext <Context> the context in which the raise occured |
89 suspendedContext <Context> the context in which the raise occured |
88 |
90 |
89 handlerContext <Context> the context of the handler (if any) |
91 handlerContext <Context> the context of the handler (if any) |
90 |
92 |
91 resumeBlock <Block> private to the exception; needed to perform resume action |
93 resumeBlock <Block> private to the exception; needed to perform resume action |
92 |
94 |
93 rejectBlock <Block> private to the exception; needed to perform reject action |
95 rejectBlock <Block> private to the exception; needed to perform reject action |
94 |
96 |
95 In case of an unhandled signal raise, Exceptions EmergenyHandler will be evaluated. |
97 In case of an unhandled signal raise, Exceptions EmergenyHandler will be evaluated. |
96 The default emergeny handler will enter the debugger. |
98 The default emergeny handler will enter the debugger. |
97 |
99 |
98 For applications, which do not want Debuggers to come up, other handlers are |
100 For applications, which do not want Debuggers to come up, other handlers are |
99 possible. |
101 possible. |
100 For example, to get the typical C++ behavior, use: |
102 For example, to get the typical C++ behavior, use: |
101 Exception emergencyHandler:[:ex | Smalltalk exitWithCoreDump] |
103 Exception emergencyHandler:[:ex | Smalltalk exitWithCoreDump] |
102 |
104 |
103 |
105 |
104 [Class variables:] |
106 [Class variables:] |
105 EmergencyHandler <Block> this block is evaluated, if no handler was defined |
107 EmergencyHandler <Block> this block is evaluated, if no handler was defined |
106 for a signal (i.e. this one is responsible for the |
108 for a signal (i.e. this one is responsible for the |
107 unhandled exception debugger). |
109 unhandled exception debugger). |
108 Having this being a block allows to globally catch |
110 Having this being a block allows to globally catch |
109 these errors - even when no enclosing handler-scope |
111 these errors - even when no enclosing handler-scope |
110 around the erronous code exists. |
112 around the erronous code exists. |
111 (as the catch/through does). |
113 (as the catch/through does). |
112 |
114 |
113 RecursiveExceptionSignal |
115 RecursiveExceptionSignal |
114 <Signal> raised when within a handler for some signal, |
116 <Signal> raised when within a handler for some signal, |
115 the same signal is raised again. |
117 the same signal is raised again. |
116 |
118 |
117 |
119 |
118 [see also:] |
120 [see also:] |
119 Signal SignalSet QuerySignal |
121 Signal SignalSet QuerySignal |
120 Context Block |
122 Context Block |
121 Object DebugView |
123 Object DebugView |
122 (``Exception handling and signals'': programming/exceptions.html) |
124 (``Exception handling and signals'': programming/exceptions.html) |
123 |
125 |
124 [author:] |
126 [author:] |
125 Claus Gittinger |
127 Claus Gittinger |
126 " |
128 " |
127 ! |
129 ! |
128 |
130 |
129 examples |
131 examples |
130 " |
132 " |
676 The handler may decide how to react to the signal by sending |
701 The handler may decide how to react to the signal by sending |
677 a corresponding message to the exception (see there). |
702 a corresponding message to the exception (see there). |
678 If the signal is not raised, return the value of evaluating |
703 If the signal is not raised, return the value of evaluating |
679 aBlock." |
704 aBlock." |
680 |
705 |
|
706 thisContext markForHandle. |
681 ^ aBlock value "the real logic is in Exception>>doRaise" |
707 ^ aBlock value "the real logic is in Exception>>doRaise" |
682 |
708 |
683 " |
709 " |
684 Object messageNotUnderstoodSignal handle:[:ex | |
710 Object messageNotUnderstoodSignal handle:[:ex | |
685 'oops' printNL. |
711 'oops' printNL. |
686 ex return |
712 ex return |
687 ] do:[ |
713 ] do:[ |
688 123 size open |
714 123 size open |
689 ] |
715 ] |
690 " |
716 " |
691 |
717 |
692 " |
718 " |
693 |num| |
719 |num| |
694 |
720 |
695 num := 0. |
721 num := 0. |
696 Number divisionByZeroSignal handle:[:ex | |
722 Number divisionByZeroSignal handle:[:ex | |
697 'oops' printNL. |
723 'oops' printNL. |
698 ex return |
724 ex return |
699 ] do:[ |
725 ] do:[ |
700 123 / num |
726 123 / num |
701 ] |
727 ] |
702 " |
728 " |
703 |
729 |
704 "Modified: / 2.3.1998 / 14:28:26 / stefan" |
|
705 "Created: / 23.7.1999 / 14:06:13 / stefan" |
730 "Created: / 23.7.1999 / 14:06:13 / stefan" |
|
731 "Modified: / 25.7.1999 / 19:44:05 / stefan" |
706 ! |
732 ! |
707 |
733 |
708 handle:handleBlock from:anObject do:aBlock |
734 handle:handleBlock from:anObject do:aBlock |
709 "evaluate the argument, aBlock. |
735 "evaluate the argument, aBlock. |
710 If the receiver-signal is raised during evaluation, |
736 If the receiver-signal is raised during evaluation, |
1184 action |
1211 action |
1185 "perform a action for the signal if it hasn't been catched |
1212 "perform a action for the signal if it hasn't been catched |
1186 We arrive here, if either no handler was found, or none of the |
1213 We arrive here, if either no handler was found, or none of the |
1187 handlers did a return (i.e. every handler rejected or fell through). |
1214 handlers did a return (i.e. every handler rejected or fell through). |
1188 |
1215 |
1189 The default is to evaluate the signal's handlerBlock. |
1216 The default is to evaluate the signal's handlerBlock or the |
|
1217 per process handler (if its the noHandlerSignal). |
|
1218 Finally fall back to Exceptions emergencyHandler, which is always |
|
1219 available and enters the debugger. |
1190 Subclasses may redefine this." |
1220 Subclasses may redefine this." |
1191 |
1221 |
1192 |block noHandlerSignal msg| |
1222 |block noHandlerSignal msg| |
1193 |
1223 |
1194 " |
1224 " |
1195 try per signal handler |
1225 try per signal handler |
1196 " |
1226 " |
1197 (block := signal handlerBlock) isNil ifTrue:[ |
1227 (block := signal handlerBlock) isNil ifTrue:[ |
1198 "/ |
1228 "/ |
1199 "/ if its a querySignal, ignore it |
1229 "/ if its a querySignal, ignore it |
1200 "/ |
1230 "/ |
1201 signal isQuerySignal ifTrue:[^ nil]. |
1231 signal isQuerySignal ifTrue:[^ nil]. |
1202 |
1232 |
1203 "/ |
1233 "/ |
1204 "/ if it is not the NoHandlerSignal, raise it ... |
1234 "/ if it is not the NoHandlerSignal, raise it ... |
1205 "/ passing the receiver as parameter. |
1235 "/ passing the receiver as parameter. |
1206 "/ |
1236 "/ |
1207 signal ~~ (noHandlerSignal := Signal noHandlerSignal) ifTrue:[ |
1237 signal ~~ (noHandlerSignal := Signal noHandlerSignal) ifTrue:[ |
1208 noHandlerSignal notNil ifTrue:[ |
1238 noHandlerSignal notNil ifTrue:[ |
1209 handlerContext notNil ifTrue:[ |
1239 handlerContext notNil ifTrue:[ |
1210 msg := 'unhandled (rejected)' |
1240 msg := 'unhandled (rejected)' |
1211 ] ifFalse:[ |
1241 ] ifFalse:[ |
1212 msg := 'unhandled' |
1242 msg := 'unhandled' |
1213 ]. |
1243 ]. |
1214 msg := msg , ' exception: (' , self errorString , ')'. |
1244 msg := msg , ' exception: (' , self errorString , ')'. |
1215 ^ noHandlerSignal |
1245 ^ noHandlerSignal |
1216 raiseRequestWith:self |
1246 raiseRequestWith:self |
1217 errorString:msg |
1247 errorString:msg |
1218 in:self suspendedContext |
1248 in:self suspendedContext |
1219 ]. |
1249 ]. |
1220 "/ |
1250 "/ |
1221 "/ mhmh - an error during early startup; noHandlerSignal is |
1251 "/ mhmh - an error during early startup; noHandlerSignal is |
1222 "/ not yet defined. |
1252 "/ not yet defined. |
1223 "/ |
1253 "/ |
1224 ^ MiniDebugger enterWithMessage:self errorString |
1254 ^ MiniDebugger enterWithMessage:self errorString |
1225 ]. |
1255 ]. |
1226 |
1256 |
1227 " |
1257 " |
1228 mhmh - smells like trouble - there is no handler and |
1258 mhmh - smells like trouble - there is no handler and |
1229 no per-signal handler block. |
1259 no per-signal handler block. |
1230 Look for either a per-process emergencyHandlerBlock |
1260 Look for either a per-process emergencyHandlerBlock |
1231 or the global emergencyHandler (from Exception) ... |
1261 or the global emergencyHandler (from Exception) ... |
1232 " |
1262 " |
1233 Processor notNil ifTrue:[ |
1263 Processor notNil ifTrue:[ |
1234 "care for signal during startup (Processor not yet created)" |
1264 "care for signal during startup (Processor not yet created)" |
1235 block := Processor activeProcess emergencySignalHandler. |
1265 block := Processor activeProcess emergencySignalHandler. |
1236 ]. |
1266 ]. |
1237 block isNil ifTrue:[ |
1267 block isNil ifTrue:[ |
1238 block := Exception emergencyHandler. |
1268 block := Exception emergencyHandler. |
1239 block isNil ifTrue:[ |
1269 block isNil ifTrue:[ |
1240 "care for error during startup (Exception not yet initialized)" |
1270 "care for error during startup (Exception not yet initialized)" |
1241 ^ MiniDebugger enterWithMessage:self errorString |
1271 ^ MiniDebugger enterWithMessage:self errorString |
1242 ]. |
1272 ]. |
1243 ]. |
1273 ]. |
1244 ]. |
1274 ]. |
1245 "... and call it" |
1275 "... and call it" |
1246 ^ block value:self. |
1276 ^ block value:self. |
1247 |
1277 |
1248 "Created: / 23.7.1999 / 14:38:03 / stefan" |
1278 "Created: / 23.7.1999 / 14:38:03 / stefan" |
1249 "Modified: / 23.7.1999 / 14:41:36 / stefan" |
1279 "Modified: / 25.7.1999 / 20:11:12 / stefan" |
1250 ! |
1280 ! |
1251 |
1281 |
1252 mayProceed |
1282 mayProceed |
1253 "return true, if the exception handler is allowed to proceed |
1283 "return true, if the exception handler is allowed to proceed |
1254 the execution where the exception occured. |
1284 the execution where the exception occured. |
1445 |
1459 |
1446 "/ is nil a valid originator? If so, we need an extra |
1460 "/ is nil a valid originator? If so, we need an extra |
1447 "/ instanceVariable to record the originator setting. |
1461 "/ instanceVariable to record the originator setting. |
1448 |
1462 |
1449 originator isNil ifTrue:[ |
1463 originator isNil ifTrue:[ |
1450 originator := suspendedContext homeReceiver |
1464 originator := suspendedContext homeReceiver |
1451 ]. |
1465 ]. |
1452 |
1466 |
1453 theSignal := signal. |
1467 theSignal := signal. |
1454 theSignal isSignal ifFalse:[ |
1468 theSignal isSignal ifFalse:[ |
1455 self halt:'unexpected non-Signal in calling context'. |
1469 self halt:'unexpected non-Signal in calling context'. |
1456 ]. |
1470 ]. |
1457 |
1471 |
1458 "/ 'search handler for: ' print. theSignal displayString printCR. |
1472 "/ 'search handler for: ' print. theSignal displayString printCR. |
1459 |
1473 |
1460 inHandler := false. |
1474 inHandler := false. |
1461 c := thisContext sender sender. "the raise/raiseRequest-context" |
1475 c := thisContext sender sender. "the raise/raiseRequest-context" |
1462 "the signal raise context" |
1476 "the signal raise context" |
1463 |
1477 |
1464 "/ since the exceptionHandler is evaluated onTop of the |
1478 "/ since the exceptionHandler is evaluated onTop of the |
1465 "/ contextChain, we must skip active handlers before searching. |
1479 "/ contextChain, we must skip active handlers before searching. |
1466 "/ otherwise, we get into trouble, when re-raising an exception |
1480 "/ otherwise, we get into trouble, when re-raising an exception |
1467 "/ from within a handler (which would lead to re-executing the |
1481 "/ from within a handler (which would lead to re-executing the |
1473 "/ in most cases ... |
1487 "/ in most cases ... |
1474 |
1488 |
1475 firstHandler := nil. |
1489 firstHandler := nil. |
1476 |
1490 |
1477 [c notNil] whileTrue:[ |
1491 [c notNil] whileTrue:[ |
1478 firstHandler isNil ifTrue:[ |
1492 firstHandler isNil ifTrue:[ |
1479 c := c findNextContextWithSelector:#doRaise or:#'handle:do:' or:#'handle:from:do:'. |
1493 c := c findNextContextWithSelector:#doRaise or:#'handle:do:' or:#'handle:from:do:'. |
1480 ] ifFalse:[ |
1494 ] ifFalse:[ |
1481 c := c findNextContextWithSelector:#doRaise or:nil or:nil. |
1495 c := c findNextContextWithSelector:#doRaise or:nil or:nil. |
1482 ]. |
1496 ]. |
1483 c notNil ifTrue:[ |
1497 c notNil ifTrue:[ |
1484 (c selector == #doRaise) ifTrue:[ |
1498 (c selector == #doRaise) ifTrue:[ |
1485 |
1499 |
1486 ex1 := c receiver. |
1500 ex1 := c receiver. |
1487 |
1501 |
1488 ((ex1 class == self class) |
1502 ((ex1 class == self class) |
1489 or:[ex1 species == self species]) ifTrue:[ |
1503 or:[ex1 species == self species]) ifTrue:[ |
1490 (ex1 signal == theSignal) ifTrue:[ |
1504 (ex1 signal == theSignal) ifTrue:[ |
1491 h := ex1 handlerContext. |
1505 h := ex1 handlerContext. |
1492 h notNil ifTrue:[ |
1506 h notNil ifTrue:[ |
1493 r := h receiver. |
1507 r := h receiver. |
1494 (r notNil and:[r accepts:theSignal]) ifTrue:[ |
1508 (r notNil and:[r accepts:theSignal]) ifTrue:[ |
1495 activeHandlers isNil ifTrue:[ |
1509 activeHandlers isNil ifTrue:[ |
1496 activeHandlers := OrderedCollection new |
1510 activeHandlers := OrderedCollection new |
1497 ]. |
1511 ]. |
1498 |
1512 |
1499 lastHandler := h. |
1513 lastHandler := h. |
1500 activeHandlers add:lastHandler. |
1514 activeHandlers add:lastHandler. |
1501 inHandler := true. |
1515 inHandler := true. |
1502 c := lastHandler. |
1516 c := lastHandler. |
1503 ] |
1517 ] |
1504 ] |
1518 ] |
1505 ] |
1519 ] |
1506 ] |
1520 ] |
1507 ] ifFalse:[ |
1521 ] ifFalse:[ |
1508 "/ must be a #handle:do context ... |
1522 "/ must be a #handle:do context ... |
1509 firstHandler := c. |
1523 firstHandler := c. |
1510 ] |
1524 ] |
1511 ] |
1525 ] |
1512 ]. |
1526 ]. |
1513 |
1527 |
1514 "/ now, start searching for a handler, |
1528 "/ now, start searching for a handler, |
1515 "/ start search above the last active handler. |
1529 "/ start search above the last active handler. |
1516 "/ Or start with the first handle:do: context, if one |
1530 "/ Or start with the first handle:do: context, if one |
1520 |
1534 |
1521 "/ lastHandler notNil ifTrue:[ |
1535 "/ lastHandler notNil ifTrue:[ |
1522 "/ theContext := lastHandler. |
1536 "/ theContext := lastHandler. |
1523 "/ theContext := lastHandler findNextContextWithSelector:#'handle:do:' or:#'handle:from:do:' or:nil. |
1537 "/ theContext := lastHandler findNextContextWithSelector:#'handle:do:' or:#'handle:from:do:' or:nil. |
1524 "/ ] ifFalse:[ |
1538 "/ ] ifFalse:[ |
1525 theContext := firstHandler. |
1539 theContext := firstHandler. |
1526 "/ ]. |
1540 "/ ]. |
1527 |
1541 |
1528 [theContext notNil] whileTrue:[ |
1542 [theContext notNil] whileTrue:[ |
1529 (theContext selector == #'handle:do:' |
1543 (theContext selector == #'handle:do:' |
1530 or:[(theContext argAt:2) == originator]) |
1544 or:[(theContext argAt:2) == originator]) |
1531 ifTrue:[ |
1545 ifTrue:[ |
1532 (activeHandlers notNil |
1546 (activeHandlers notNil |
1533 and:[activeHandlers includesIdentical:theContext]) ifTrue:[ |
1547 and:[activeHandlers includesIdentical:theContext]) ifTrue:[ |
1534 "/ 'skip activeHandler: ' print. theContext displayString printCR. |
1548 "/ 'skip activeHandler: ' print. theContext displayString printCR. |
1535 |
1549 |
1536 ] ifFalse:[ |
1550 ] ifFalse:[ |
1537 " |
1551 " |
1538 if this is the Signal>>handle:do: context |
1552 if this is the Signal>>handle:do: context |
1539 or a SignalSet>>handle:do: context with self in it, |
1553 or a SignalSet>>handle:do: context with self in it, |
1540 call the handler |
1554 call the handler |
1541 " |
1555 " |
1542 r := theContext receiver. |
1556 r := theContext receiver. |
1543 (r notNil and:[r accepts:signal]) ifTrue:[ |
1557 (r notNil and:[r accepts:signal]) ifTrue:[ |
1544 "call the handler" |
1558 "call the handler" |
1545 |
1559 |
1546 conArg1 := theContext argAt:1. |
1560 conArg1 := theContext argAt:1. |
1547 |
1561 |
1548 handlerContext := theContext. |
1562 handlerContext := theContext. |
1549 |
1563 |
1550 self doCallHandler:conArg1. |
1564 self doCallHandler:conArg1. |
1551 |
1565 |
1552 "/ if the handler rejects, we arrive here |
1566 "/ if the handler rejects, we arrive here |
1553 "/ continue search for another handler |
1567 "/ continue search for another handler |
1554 ]. |
1568 ]. |
1555 ] |
1569 ] |
1556 ]. |
1570 ]. |
1557 theContext := theContext findNextContextWithSelector:#'handle:do:' or:#'handle:from:do:' or:nil. |
1571 theContext := theContext findNextContextWithSelector:#'handle:do:' or:#'handle:from:do:' or:nil. |
1558 ]. |
1572 ]. |
1559 |
1573 |
1560 activeHandlers := nil. |
1574 activeHandlers := nil. |
1561 |
1575 |
1562 " |
1576 " |
1564 handlers did a return (i.e. every handler rejected or fell through). |
1578 handlers did a return (i.e. every handler rejected or fell through). |
1565 " |
1579 " |
1566 |
1580 |
1567 ^ self action |
1581 ^ self action |
1568 |
1582 |
|
1583 "Modified: / 9.11.1997 / 14:48:44 / cg" |
|
1584 "Modified: / 23.7.1999 / 14:40:12 / stefan" |
|
1585 "Created: / 25.7.1999 / 20:13:19 / stefan" |
|
1586 ! |
|
1587 |
|
1588 doCallHandler:aHandler |
|
1589 "call the handler proper - needed an extra method |
|
1590 to have a separate returnContext for the rejectBlock. |
|
1591 (which is historical, and actually no longer needed)" |
|
1592 |
|
1593 |val| |
|
1594 |
|
1595 rejectBlock := [^ self]. "this will return on reject" |
|
1596 |
|
1597 thisContext markForRaise. |
|
1598 |
|
1599 val := aHandler value:self. |
|
1600 " |
|
1601 handler fall through - is just like a returnWith:blocks-value |
|
1602 " |
|
1603 rejectBlock := nil. |
|
1604 self returnWith:val |
|
1605 |
|
1606 "Modified: / 26.7.1999 / 14:41:55 / stefan" |
|
1607 ! |
|
1608 |
|
1609 doRaise |
|
1610 "search through the context-calling chain for a handle-context |
|
1611 to the raising signal, a parent of it, or a SignalSet which includes |
|
1612 the raising signal. |
|
1613 If found, ask the receiver for the handler and evaluate |
|
1614 it with the receiver exception as argument. |
|
1615 If no handler is found, perform the default #action method. |
|
1616 |
|
1617 ATTENTION: the code below depends on being called by #raise or |
|
1618 #raiseRequest for proper operation (it skips the sending context)." |
|
1619 |
|
1620 |theContext handler |
|
1621 theSignal c ex1 activeHandlers inHandler |
|
1622 lastHandler h r firstHandler| |
|
1623 |
|
1624 |
|
1625 "/ is nil a valid originator? If so, we need an extra |
|
1626 "/ instanceVariable to record the originator setting. |
|
1627 |
|
1628 originator isNil ifTrue:[ |
|
1629 originator := suspendedContext homeReceiver |
|
1630 ]. |
|
1631 |
|
1632 theSignal := signal. |
|
1633 theSignal isSignal ifFalse:[ |
|
1634 self halt:'unexpected non-Signal in calling context'. |
|
1635 ]. |
|
1636 |
|
1637 "/ 'search handler for: ' print. theSignal displayString printCR. |
|
1638 |
|
1639 inHandler := false. |
|
1640 c := thisContext sender sender. "the raise/raiseRequest-context" |
|
1641 "the signal raise context" |
|
1642 |
|
1643 "/ since the exceptionHandler is evaluated on top of the |
|
1644 "/ contextChain, we must skip active handlers before searching. |
|
1645 "/ otherwise, we get into trouble, when re-raising an exception |
|
1646 "/ from within a handler (which would lead to re-executing the |
|
1647 "/ same handler) |
|
1648 "/ the code below collects active handlers ... |
|
1649 |
|
1650 "/ on the fly, look for the first handle - context, |
|
1651 "/ and remember it (as firstHandler) to avoid walking the context chain twice |
|
1652 "/ in most cases ... |
|
1653 |
|
1654 firstHandler := nil. |
|
1655 |
|
1656 [c notNil] whileTrue:[ |
|
1657 firstHandler isNil ifTrue:[ |
|
1658 c := c findSpecialHandle:true raise:true. |
|
1659 ] ifFalse:[ |
|
1660 c := c findSpecialHandle:false raise:true. |
|
1661 ]. |
|
1662 c notNil ifTrue:[ |
|
1663 (c isRaiseContext) ifTrue:[ |
|
1664 ex1 := c receiver. |
|
1665 ((ex1 class == self class) |
|
1666 or:[ex1 species == self species]) ifTrue:[ |
|
1667 (ex1 signal == theSignal) ifTrue:[ |
|
1668 h := ex1 handlerContext. |
|
1669 h notNil ifTrue:[ |
|
1670 activeHandlers isNil ifTrue:[ |
|
1671 activeHandlers := OrderedCollection new |
|
1672 ]. |
|
1673 |
|
1674 lastHandler := h. |
|
1675 activeHandlers add:lastHandler. |
|
1676 inHandler := true. |
|
1677 c := lastHandler. |
|
1678 ] |
|
1679 ] |
|
1680 ] |
|
1681 ] ifFalse:[ |
|
1682 "/ must be a handle context ... |
|
1683 firstHandler := c. |
|
1684 ] |
|
1685 ] |
|
1686 ]. |
|
1687 |
|
1688 "/ now, start searching for a handler, |
|
1689 "/ start search above the last active handler. |
|
1690 "/ Or start with the first handle context, if one |
|
1691 "/ was found as a side effect of the previous handler search. |
|
1692 "/ If nil, then there is no handler and we can directly proceed |
|
1693 "/ to the unhandled code below. |
|
1694 |
|
1695 "/ lastHandler notNil ifTrue:[ |
|
1696 "/ theContext := lastHandler. |
|
1697 "/ theContext := lastHandler findNextHandleContext |
|
1698 "/ ] ifFalse:[ |
|
1699 theContext := firstHandler. |
|
1700 "/ ]. |
|
1701 |
|
1702 [theContext notNil] whileTrue:[ |
|
1703 " |
|
1704 ask the Signal instance/Exception class for the handler. |
|
1705 nil is returned, if the signal is not accepted |
|
1706 " |
|
1707 |
|
1708 r := theContext receiver. |
|
1709 (r notNil and:[(handler := r handlerForSignal:signal |
|
1710 context:theContext |
|
1711 originator:originator) notNil] |
|
1712 ) ifTrue:[ |
|
1713 (activeHandlers notNil |
|
1714 and:[activeHandlers includesIdentical:theContext]) ifTrue:[ |
|
1715 "/ 'skip activeHandler: ' print. theContext displayString printCR. |
|
1716 |
|
1717 ] ifFalse:[ |
|
1718 "call the handler" |
|
1719 |
|
1720 handlerContext := theContext. |
|
1721 self doCallHandler:handler. |
|
1722 |
|
1723 "/ if the handler rejects, we arrive here |
|
1724 "/ continue search for another handler |
|
1725 ]. |
|
1726 ]. |
|
1727 theContext := theContext findSpecialHandle:true raise:false. |
|
1728 ]. |
|
1729 |
|
1730 activeHandlers := nil. |
|
1731 |
|
1732 " |
|
1733 we arrive here, if either no handler was found, or none of the |
|
1734 handlers did a return (i.e. every handler rejected or fell through). |
|
1735 " |
|
1736 |
|
1737 ^ self action |
|
1738 |
1569 "Created: / 12.5.1996 / 15:09:39 / cg" |
1739 "Created: / 12.5.1996 / 15:09:39 / cg" |
1570 "Modified: / 9.11.1997 / 14:48:44 / cg" |
1740 "Modified: / 9.11.1997 / 14:48:44 / cg" |
1571 "Modified: / 23.7.1999 / 14:40:12 / stefan" |
1741 "Modified: / 26.7.1999 / 14:50:50 / stefan" |
1572 ! ! |
1742 ! ! |
1573 |
1743 |
1574 !Exception methodsFor:'raising'! |
1744 !Exception methodsFor:'raising'! |
1575 |
1745 |
1576 raise |
1746 raise |