Return from process

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Return from process

Luca Bruno aka Lethalman
Hello,
the following goes segmentation fault:

[^'test'] fork!

Bye.

--
http://lethalman.blogspot.com - Thoughts about computer technologies


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Return from process

Paolo Bonzini
Luca Bruno wrote:
> Hello,
> the following goes segmentation fault:
>
> [^'test'] fork!
Aha, this was a tough one. :-)  I was quite hesitant to muddle with the
unwind code, but the regression tests are pretty good for that area so
here it is.

The VM changes are relatively simple.  The Process changes are too, you
just need one more #ensure: there; there was also some debugging code in
ProcessorScheduler that I had forgotten, I removed it...

It is quite mysterious instead why you need to execute the exception
handler blocks with #valueAndResumeOnUnwind rather than #value.  The
reason is that when you do [^'test'] in a process the context executing
#on:do: would be disabled; then #badReturnError raises an exception,
this one terminates the process, and you would miss the termination
raised by exception handler.

st> [^'foo'] fork!
Object: 'foo' error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>#signal
SystemExceptions.BadReturn class(Exception class)>>#signal
String(Object)>>#badReturnError
BlockClosure>>#ensure:

:-)

Paolo

2006-11-03  Paolo Bonzini  <[hidden email]>

        * kernel/BlkClosure.st: Mark #on:do: contexts as unwinding
        * kernel/ProcSched.st: Remove debug code.
        * kernel/Process.st: Wrap process not only
        in an #on:do:, but also in an #ensure: block.

        * tests/exceptions.st: Test exception raising within a process.

        * libgst/interp.c: Check if we hit the bottom of the stack in
        disable_non_unwind_contexts, and percolate a return value of true
        through unwind_to up to unwind_method.  Otherwise return false from
        both disable_non_unwind_contexts and unwind_to.


--- orig/kernel/BlkClosure.st
+++ mod/kernel/BlkClosure.st
@@ -198,7 +198,7 @@
     <exceptionHandlerSearch: BlockClosure exceptionHandlerSearchBlock
  reset: BlockClosure exceptionHandlerResetBlock>
     active := 0.
-    ^self value
+    ^self valueAndResumeOnUnwind
 !
 
 on: e1 do: b1 on: e2 do: b2
@@ -210,7 +210,7 @@
     <exceptionHandlerSearch: BlockClosure exceptionHandlerSearchBlock
  reset: BlockClosure exceptionHandlerResetBlock>
     active := 0.
-    ^self value
+    ^self valueAndResumeOnUnwind
 !
 
 on: e1 do: b1 on: e2 do: b2 on: e3 do: b3
@@ -223,7 +223,7 @@
     <exceptionHandlerSearch: BlockClosure exceptionHandlerSearchBlock
  reset: BlockClosure exceptionHandlerResetBlock>
     active := 0.
-    ^self value
+    ^self valueAndResumeOnUnwind
 !
 
 on: e1 do: b1 on: e2 do: b2 on: e3 do: b3 on: e4 do: b4
@@ -236,7 +236,7 @@
     <exceptionHandlerSearch: BlockClosure exceptionHandlerSearchBlock
  reset: BlockClosure exceptionHandlerResetBlock>
     active := 0.
-    ^self value
+    ^self valueAndResumeOnUnwind
 !
 
 on: e1 do: b1 on: e2 do: b2 on: e3 do: b3 on: e4 do: b4 on: e5 do: b5
@@ -249,7 +249,7 @@
     <exceptionHandlerSearch: BlockClosure exceptionHandlerSearchBlock
  reset: BlockClosure exceptionHandlerResetBlock>
     active := 0.
-    ^self value
+    ^self valueAndResumeOnUnwind
 !
 
 ifError: aBlock


--- orig/kernel/ProcSched.st
+++ mod/kernel/ProcSched.st
@@ -80,7 +80,6 @@
 
 terminateActive
     "Terminate the active process"
-    Smalltalk backtrace.
     self activeProcess terminate
 !
 


--- orig/kernel/Process.st
+++ mod/kernel/Process.st
@@ -307,13 +310,18 @@
     activePriority := Processor activePriority.
     closure := [
  [
-    self setPriorityFrom: activePriority to: aPriority suspend: aBoolean.
-    aBlockClosure value ]
-
-    on: SystemExceptions.ProcessBeingTerminated
-    do: [ :sig | sig return ].
+    [
+ self setPriorityFrom: activePriority to: aPriority suspend: aBoolean.
+        aBlockClosure value
+    ]
+        on: SystemExceptions.ProcessBeingTerminated
+
+        "If we terminate in the handler, the 'ensure' blocks are not
+         evaluated.  Instead, if the handler returns, the unwinding
+         is done properly."
+        do: [ :sig | sig return ].
 
- self primTerminate
+ ] ensure: [ self primTerminate ] .
     ].
 
     "Start the Process immediately so that we get into the


--- orig/libgst/interp.c
+++ mod/libgst/interp.c
@@ -484,7 +484,7 @@
    or an unwind method.  In this case the non-unwind contexts between
    the unwind method and the returnContextOOP must be removed from the
    chain.  */
-static void unwind_to (OOP returnContextOOP);
+static mst_Boolean unwind_to (OOP returnContextOOP);
 
 /* Arrange things so that all the non-unwinding contexts up to
    returnContextOOP aren't executed.  For block contexts this can
@@ -493,7 +493,7 @@
    from them!  For this reason, method contexts are flagged as
    disabled and unwind_context takes care of skipping them when
    doing a local return.  */
-static void disable_non_unwind_contexts (OOP returnContextOOP);
+static mst_Boolean disable_non_unwind_contexts (OOP returnContextOOP);
 
 /* Called to handle signals that are not passed to the Smalltalk
    program, such as interrupts or segmentation violation.  In the
@@ -1120,12 +1120,11 @@
       return (false);
     }
 
-  unwind_to (newContext->parentContext);
-  return (true);
+  return unwind_to (newContext->parentContext);
 }
 
 
-void
+mst_Boolean
 unwind_to (OOP returnContextOOP)
 {
   OOP oldContextOOP, newContextOOP;
@@ -1148,15 +1147,16 @@
       /* Check if we got to an unwinding context (#ensure:).  */
       if UNCOMMON (CONTEXT_FLAGS (newContext) & MCF_IS_UNWIND_CONTEXT)
         {
+  mst_Boolean result;
   _gst_this_context_oop = oldContextOOP;
 
   /* _gst_this_context_oop is the context above the
      one we return to.   We only unwind up to the #ensure:
      context.  */
-  disable_non_unwind_contexts (returnContextOOP);
+  result = disable_non_unwind_contexts (returnContextOOP);
 
   unwind_context ();
-  return;
+  return result;
  }
 
       /* This context cannot be deallocated in a LIFO way.  We must
@@ -1191,9 +1191,10 @@
   _gst_self = newContext->receiver;
 
   SET_THIS_METHOD (newContext->method, GET_CONTEXT_IP (newContext));
+  return (true);
 }
 
-void
+mst_Boolean
 disable_non_unwind_contexts (OOP returnContextOOP)
 {
   OOP oldContextOOP, newContextOOP, *chain;
@@ -1218,6 +1219,12 @@
    collect more context objects.  */
         oldContext->parentContext = _gst_nil_oop;
 
+      if (IS_NIL (newContextOOP))
+ {
+  *chain = newContextOOP;
+  return (false);
+ }
+
       if (newContextOOP == returnContextOOP)
  {
   *chain = newContextOOP;
@@ -1255,6 +1262,7 @@
     }
 
   *chain = newContext->parentContext;
+  return (true);
 }
 
 


--- orig/tests/exceptions.ok
+++ mod/tests/exceptions.ok
@@ -160,3 +160,11 @@
 Execution begins...
  error: did not understand #goodness:
 returned value is nil
+
+Execution begins...
+ error: return from a dead method context
+returned value is Process new "<0>"
+
+Execution begins...
+ error: test
+returned value is Process new "<0>"


--- orig/tests/exceptions.st
+++ mod/tests/exceptions.st
@@ -146,3 +146,9 @@
 
 "used to go in an infinite loop"
 [ self halt ] on: 1 do: [ :ex | 'blah' printNl ]!
+
+"Test error handling within a process."
+[^'test'] fork!
+
+"Test error handling within a process."
+[self error: 'test'] fork!




_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk