handle error in consumer, pass info to producer,
authormartin
Thu, 01 Feb 2001 18:54:53 +0100
changeset 956 d62d8a6f3ba0
parent 955 97f0f14a61f4
child 957 88d941cdbe8f
handle error in consumer, pass info to producer, and raise exception there.
OperationQueue.st
--- a/OperationQueue.st	Thu Feb 01 14:32:24 2001 +0100
+++ b/OperationQueue.st	Thu Feb 01 18:54:53 2001 +0100
@@ -8,7 +8,7 @@
 !
 
 Object subclass:#OperationInQueue
-	instanceVariableNames:'operation operationPerformedSema operationResult'
+	instanceVariableNames:'operation operationPerformedSema operationResult exception'
 	classVariableNames:''
 	poolDictionaries:''
 	privateIn:OperationQueue
@@ -115,9 +115,17 @@
 
     theOperation := opInQ operation.
     Object abortSignal handle:[:ex |
+        Transcript showCR:'operation aborted'.
         opInQ operationResult:nil.
     ] do:[
         Object errorSignal handle:[:ex |
+            |ex2|
+
+            Transcript showCR:'operation error: ', ex errorString.
+
+            ex2 := ex shallowCopy.
+            ex2 suspendedContext:(self copyContextChain:ex suspendedContext).
+            opInQ exception:ex2.
             opInQ operationResult:nil.
         ] do:[
             rslt := theOperation value.
@@ -161,6 +169,32 @@
     ] valueUninterruptably
 ! !
 
+!OperationQueue methodsFor:'debugging support'!
+
+copyContextChain:aContext
+    "dequeue the next order, evaluate it and wake up waiters"
+
+    |copy|
+
+    copy := aContext shallowCopy.
+    aContext sender notNil ifTrue:[
+        copy setSender:(self copyContextChain:aContext sender)
+    ].
+    ^ copy
+!
+
+linkContextChain:aConsumerChain
+    "for debugging - concatenate aConsumerChain to my own context chain (to make debugging easier)"
+
+    |c|
+
+    c := aConsumerChain.
+    [c sender notNil and:[c methodHome selector ~~ #fetchNextOperationAndExecute]] whileTrue:[
+        c := c sender.
+    ].
+    c setSender:(thisContext sender).
+! !
+
 !OperationQueue methodsFor:'initialization'!
 
 initializeLock
@@ -186,11 +220,10 @@
      If a similar order is already in the queue, wait for that one to finish.
      If asynchronous is true, do not wait (but also: do not return a return value)"
 
-    |myOpInQ|
+    |myOpInQ ex|
 
     queueLock critical:[
         "/ operation already in queue ?
-
         queue withAccessLockedDo:[
             myOpInQ := nil.
             queue do:[:eachOpInQ |
@@ -219,7 +252,13 @@
 
     "/ wait for the operation to finish
     myOpInQ operationPerformedSema wait.
+    (ex := myOpInQ exception) notNil ifTrue:[
+        "/ trick: makes calling chain look as if the error happended here
+        "/ (in reality, it happended in the consumer-process).
+        self linkContextChain:ex suspendedContext.
 
+        ^ ex signal raiseErrorString:('asyncronous operation error:' , ex errorString) in:ex suspendedContext
+    ].
     "/ now, the operation has been performed - return its result
     ^ myOpInQ operationResult
 ! !
@@ -234,6 +273,18 @@
 
 !OperationQueue::OperationInQueue methodsFor:'accessing'!
 
+exception
+    "return the value of the instance variable 'exception' (automatically generated)"
+
+    ^ exception
+!
+
+exception:something
+    "set the value of the instance variable 'exception' (automatically generated)"
+
+    exception := something.
+!
+
 operation
     "return the value of the instance variable 'operation' (automatically generated)"
 
@@ -273,5 +324,5 @@
 !OperationQueue class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/OperationQueue.st,v 1.4 2000-12-15 15:55:35 martin Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/OperationQueue.st,v 1.5 2001-02-01 17:54:53 martin Exp $'
 ! !