[squeak-dev] Improving a Process termination procedure

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

[squeak-dev] Improving a Process termination procedure

Igor Stasenko
There are a potential of having incorrect behavior , when terminating
a preempted or waiting process:

with introduction of ProcessLocalVariable, it is essential that
context unwinding procedure should be performed only
for currently active process.

Here the proposal how to ensure this:

if terminating process is not active process we should do the following:

suspendedContext := proc suspendedContext.
currentProces := Processor activeProcess.
proc suspendedContext:  [  Processor activeProcess
terminateFromContext: suspendedContext. Processor switchToProcess:
currentProcess ] asContext.
Processor switchToProcess: proc.

here #switchToProcess: is explicit switch (bypassing scheduling logic).

If we don't care about immediate termination of process and getting
back to process who initiated termination as soon as possible, then
simply do:
process terminateSoon.

which can be implemented as:

Process>>terminateSoon
| termContext |
termContext := suspendedContext.
suspendedContext := [  self terminateFromContext: termContext. self
suspend ] asContext.
Processor yield.



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Improving a Process termination procedure

Igor Stasenko
Another improvement would be to marry the process termination with
exception handling,
and nicely signal ProcessTerminatedException.
This offers many practical benefits, since then we could write:

[ ... ] on: ProcessTerminatedException do: [:ex |
   "oh man we're been terminated"
].

But i'm not expert in exception handling.
Can someone give me a sample, how to signal such exception in potential
#terminateFromContext: method?

2009/5/1 Igor Stasenko <[hidden email]>:

> There are a potential of having incorrect behavior , when terminating
> a preempted or waiting process:
>
> with introduction of ProcessLocalVariable, it is essential that
> context unwinding procedure should be performed only
> for currently active process.
>
> Here the proposal how to ensure this:
>
> if terminating process is not active process we should do the following:
>
> suspendedContext := proc suspendedContext.
> currentProces := Processor activeProcess.
> proc suspendedContext:  [  Processor activeProcess
> terminateFromContext: suspendedContext. Processor switchToProcess:
> currentProcess ] asContext.
> Processor switchToProcess: proc.
>
> here #switchToProcess: is explicit switch (bypassing scheduling logic).
>
> If we don't care about immediate termination of process and getting
> back to process who initiated termination as soon as possible, then
> simply do:
> process terminateSoon.
>
> which can be implemented as:
>
> Process>>terminateSoon
> | termContext |
> termContext := suspendedContext.
> suspendedContext := [  self terminateFromContext: termContext. self
> suspend ] asContext.
> Processor yield.
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Improving a Process termination procedure

Julian Fitzell-2
On Fri, May 1, 2009 at 3:11 AM, Igor Stasenko <[hidden email]> wrote:
> Another improvement would be to marry the process termination with
> exception handling,
> and nicely signal ProcessTerminatedException.

Which is pretty much what VW does, I think.

> This offers many practical benefits, since then we could write:
>
> [ ... ] on: ProcessTerminatedException do: [:ex |
>   "oh man we're been terminated"
> ].
>
> But i'm not expert in exception handling.
> Can someone give me a sample, how to signal such exception in potential
> #terminateFromContext: method?

Seems like you would just do "ProcessTerminatedException signal" as
long as the receiver was the active process. If not the active
process, you would have to replace the suspended context with a new
context that will signal the exception as soon as the process is next
run.

The strange thing about this implementation is that you can write code
that actually prevents your process from being terminated. I'm not
saying that's a bad thing (maybe it's even a good thing for certain
pieces of code) but it certainly changes the semantics of #terminate a
little. :) And that being the case, the name
ProcessTerminatedException is a bit misleading because it implies that
the process already *has* been terminated. TerminateProcessException,
TerminateProcessRequest, or just TerminateProcess would be more
accurate.

Julian

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Improving a Process termination procedure

Igor Stasenko
2009/5/1 Julian Fitzell <[hidden email]>:

> On Fri, May 1, 2009 at 3:11 AM, Igor Stasenko <[hidden email]> wrote:
>> Another improvement would be to marry the process termination with
>> exception handling,
>> and nicely signal ProcessTerminatedException.
>
> Which is pretty much what VW does, I think.
>
>> This offers many practical benefits, since then we could write:
>>
>> [ ... ] on: ProcessTerminatedException do: [:ex |
>>   "oh man we're been terminated"
>> ].
>>
>> But i'm not expert in exception handling.
>> Can someone give me a sample, how to signal such exception in potential
>> #terminateFromContext: method?
>
> Seems like you would just do "ProcessTerminatedException signal" as
> long as the receiver was the active process. If not the active
> process, you would have to replace the suspended context with a new
> context that will signal the exception as soon as the process is next
> run.
>
> The strange thing about this implementation is that you can write code
> that actually prevents your process from being terminated. I'm not
> saying that's a bad thing (maybe it's even a good thing for certain
> pieces of code) but it certainly changes the semantics of #terminate a
> little. :)

I'm now almost done implementing it.
Its behavior will be different than regular exception handling.
What it will do is:
1. find handler context, if any
2. rewind the stack up to handler context
3. evaluate the handler block (note, that any flow control methods
like "pass, return .. will be simply ignored")
4. repeat from (1) until there are no contexts on stack

so, this all is to ensure, that
a) stack is rewounded
b) all   [... ] on: TerminateProcess  do: [ .. ]  during rewinding is handled

> And that being the case, the name
> ProcessTerminatedException is a bit misleading because it implies that
> the process already *has* been terminated. TerminateProcessException,
> TerminateProcessRequest, or just TerminateProcess would be more
> accurate.
>
Thanks for a better name. I will rename it to 'TerminateProcess'.

> Julian
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Improving a Process termination procedure

Andreas.Raab
In reply to this post by Igor Stasenko
Igor Stasenko wrote:
> Another improvement would be to marry the process termination with
> exception handling,
> and nicely signal ProcessTerminatedException.
> This offers many practical benefits, since then we could write:
>
> [ ... ] on: ProcessTerminatedException do: [:ex |
>    "oh man we're been terminated"
> ].

A simpler and more robust alternative that I talked to Eliot about
yesterday is to simply have another indirection for activeProcess, i.e.,

ProcessorScheduler>>activeProcess
   "Answers the currently active process"
   ^activeProcess currentProcess

Process>>currentProcess
   "If I am pretending to be another process, answer it.
   Otherwise answer self"
   currentProcess ifNil:[^self].
   "Pass the request on since we could be debugging unwind issues"
   ^currentProcess currentProcess

Why is this advantageous? Several reasons:

a) It is not only useful for termination, but also for debugging. The
debugger can provide the currently suspended process and simulated code
will pick up the "right" identity (as the above illustrates this way you
would be able to debug unwind blocks and have the code pick up the
bindings from the process being terminated in the debugger :)

b) There is no question about either priority, what the terminated
process status is when exiting #terminate etc. as it is within the
calling process execution context (otherwise the terminating process
might never complete if it has a low priority).

c) It rules out a whole class of errors that can happen if you rely on
exception handling being implemented "correctly" in the users code. For
example, there are several places that handle Exception instead of
Error, Halt (or whatever they really should handle). Handling
ProcessTermination "accidentally" is obviously error prone and I don't
think user code should have a choice of handling it (there are perfectly
good ways to implement such a feature yourself if you really need it and
there is no good reason for user code by default to deny termination;
not even accidentally).

d) Error handling occurs in the calling process. That's important
because often termination is something done as a last resort and it is
not unusal to have different error handlers when you terminate a process
compared to the error handlers that you need when you run it normally.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Improving a Process termination procedure

Igor Stasenko
2009/5/2 Andreas Raab <[hidden email]>:

> Igor Stasenko wrote:
>>
>> Another improvement would be to marry the process termination with
>> exception handling,
>> and nicely signal ProcessTerminatedException.
>> This offers many practical benefits, since then we could write:
>>
>> [ ... ] on: ProcessTerminatedException do: [:ex |
>>   "oh man we're been terminated"
>> ].
>
> A simpler and more robust alternative that I talked to Eliot about yesterday
> is to simply have another indirection for activeProcess, i.e.,
>
> ProcessorScheduler>>activeProcess
>  "Answers the currently active process"
>  ^activeProcess currentProcess
>
> Process>>currentProcess
>  "If I am pretending to be another process, answer it.
>  Otherwise answer self"
>  currentProcess ifNil:[^self].
>  "Pass the request on since we could be debugging unwind issues"
>  ^currentProcess currentProcess
>
> Why is this advantageous? Several reasons:
>
> a) It is not only useful for termination, but also for debugging. The
> debugger can provide the currently suspended process and simulated code will
> pick up the "right" identity (as the above illustrates this way you would be
> able to debug unwind blocks and have the code pick up the bindings from the
> process being terminated in the debugger :)
>
> b) There is no question about either priority, what the terminated process
> status is when exiting #terminate etc. as it is within the calling process
> execution context (otherwise the terminating process might never complete if
> it has a low priority).
>
in new scheduler i switching to it explicitly, so that it will be
terminated asap.
For old one, i boosting its priority to maximum.

Speaking about priority, i would care just about a single solid rule:
- ensure that a process/context which is sends #terminate (to other
process or to itself) , doesn't having a chance to regain control
before terminate request is fully complete.

But also there could be the case, that sender don't really cares, when
required process should terminate - its just want it to be terminated
eventually. For this i propose adding a #terminateSoon message to
Process protocol.

> c) It rules out a whole class of errors that can happen if you rely on
> exception handling being implemented "correctly" in the users code. For
> example, there are several places that handle Exception instead of Error,
> Halt (or whatever they really should handle). Handling ProcessTermination
> "accidentally" is obviously error prone and I don't think user code should
> have a choice of handling it (there are perfectly good ways to implement
> such a feature yourself if you really need it and there is no good reason
> for user code by default to deny termination; not even accidentally).
>

Right. But its more a social problem. Nothing stops your from putting
a rewind block which
taking thisContext and flying away to a high sky.
We providing an implementation which works unless its abused (as
everything else in smalltalk).

> d) Error handling occurs in the calling process. That's important because
> often termination is something done as a last resort and it is not unusal to
> have different error handlers when you terminate a process compared to the
> error handlers that you need when you run it normally.
>

Andreas, i thought about it just today morning (what a coincidense?
:). Really, its not a problem to create a proxy object which pretends
to be a Process. What i like in smalltalk , is breaking the dogmas
which often seem scary & dangerous , but in reality just a taints from
a C world. After all - everything is objects, right? :)
But its hard to measure the cost of adding such pretender and possible
side effects.
There are multiple problematic places which treating Processes mostly
as a dummy state holder (suspendedContext/list) both in VM and image
side.
Of course, i can wipe/remix everything in Process and still make it
able to run with new scheduler. But this having a cost of losing
backward compatibility.
Or... write a code which migrating instances NewProcess <-->
OldProcess, so then i could switch between them easily (but still this
is a pain in the ass ;) ).

This is what i planning to do for Delays, since i made AdvancedDelay
to be a subclass of Object , because its having 1 less ivar:
delayDuration resumptionTime waitingProcess.
I almost done writing new delays..
   - it don't needs to have own high-priority process, mainly because
of cooperation with new scheduler (its reusing interruptProcess to do
all atomic stuff).
  - new Delays no longer needs a semaphore, because it can control
resume/suspend by itself, as well as can be passed to primitive which
signals it - because primitive which fetching even signals from VM is
simply fills an array with integers. Scheduler free to interpret them
as it likes to (as an index in special/external objects array or
somewhere else).
With this new primitive i really consider about unification and
- remove ExternalSemaphoreTable, and keep this array as an ivar in Processor
- in VM, unify all places as well, by removing all references to
'semaphore' and replacing them with more abstract thing - signals.
 VM simply doesn't needs to know, what signal means and who is behind
it - for VM its just an integer value, nothing more. It simply fills
an array with these integers and let Processor handle them.

This, of course related to a well-known objects from special objects
table, which is 'known to be a semaphore'.
They could be just a normally 1-based indexed, and scheduler will
reserve these slots for appropriate objects i.e.:

TheLowSpaceSemaphore := 1.
ProcessSignalingLowSpace := 2.
etc..

and add a convenienve methods, like:

Processor>>registerLowSpaceHandler: anObject
   signalHandlers at: TheLowSpaceSemaphore put: anObject



P.S a bit long post...

> Cheers,
>  - Andreas
>

--
Best regards,
Igor Stasenko AKA sig.