Delay in a Process and sending #terminate

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

Delay in a Process and sending #terminate

Holger Freyther
Hi all,

I have made the following observation and wonder if this is a bug or such.

$ a := [[(Delay forSeconds: 300) wait] ensure: ['Terminated' printNl]] fork.
$ a terminate
Process(nil at userSchedulingPriority, ready to run)
$ a terminate
'Terminated'
Process(nil at userSchedulingPriority, terminated)


To work around such sticky processes I have decided to use a [proc
isTerminated] whileFalse: [proc terminate] construct.

regards
        holger


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

Re: Delay in a Process and sending #terminate

Holger Freyther
On 12/18/2010 11:38 AM, Holger Hans Peter Freyther wrote:
> Hi all,

>
> To work around such sticky processes I have decided to use a [proc
> isTerminated] whileFalse: [proc terminate] construct.
>

Sometimes I am also ending up with this backtrace.


Object: nil error: did not understand #goodness:
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
UndefinedObject(Object)>>doesNotUnderstand: #goodness: (SysExcept.st:1407)
optimized [] in BlockClosure class>>exceptionHandlerSearchBlock (BlkClosure.st:16)
[] in MessageNotUnderstood(Exception)>>instantiateNextHandlerFrom:
(ExcHandling.st:340)
MethodContext(ContextPart)>>scanBacktraceForAttribute:do: (ContextPart.st:449)
MessageNotUnderstood(Exception)>>instantiateNextHandlerFrom: (ExcHandling.st:342)
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
UndefinedObject(Object)>>doesNotUnderstand: #>= (SysExcept.st:1407)
optimized [] in Delay class>>startDelayLoop (Delay.st:166)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:728)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:537)
SortedCollection>>last (SortCollect.st:121)
Delay class>>activeDelay (Delay.st:78)
Delay class>>handleDelayRequestor (Delay.st:104)
optimized [] in Delay class>>runDelayProcess (Delay.st:124)
[] in BlockClosure>>ifCurtailed: (BlkClosure.st:287)
BlockClosure>>ensure: (BlkClosure.st:269)
BlockClosure>>ifCurtailed: (BlkClosure.st:273)
Delay class>>runDelayProcess (Delay.st:120)
optimized [] in Delay class>>startDelayLoop (Delay.st:168)
[] in Process>>onBlock:at:suspend: (Process.st:392)
BlockClosure>>on:do: (BlkClosure.st:193)
[] in Process>>onBlock:at:suspend: (Process.st:393)
BlockClosure>>ensure: (BlkClosure.st:269)
[] in Process>>onBlock:at:suspend: (Process.st:370)
[] in BlockClosure>>asContext: (BlkClosure.st:179)
BlockContext class>>fromClosure:parent: (BlkContext.st:68)

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

Re: Delay in a Process and sending #terminate

Holger Freyther
On 12/18/2010 11:59 AM, Holger Hans Peter Freyther wrote:
> On 12/18/2010 11:38 AM, Holger Hans Peter Freyther wrote:
>> Hi all,
>
>>
>> To work around such sticky processes I have decided to use a [proc
>> isTerminated] whileFalse: [proc terminate] construct.
>>

and one more related question. Is there something about Semaphores and
terminated processes? I have no good test case yet but I think.

A:
[
        [ ] ensure: [
                mutex critical: ['Sometimes never entered' printNl. allProcesses remove:
Processor activeProcess].
        ]
] fork

B:
mutex criticial: [allProcesses do: [:each | each terminate ]].



I think sometimes this statement will not executed when the process is being
terminated. What I am trying to do is to have a cleanup handler for processes.
E.g. to make a process remove itself from a list of processes.


Is there a better way to achieve this goal?

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

Re: Delay in a Process and sending #terminate

Paolo Bonzini-2
In reply to this post by Holger Freyther
On 12/18/2010 11:38 AM, Holger Hans Peter Freyther wrote:
> $ a := [[(Delay forSeconds: 300) wait] ensure: ['Terminated' printNl]] fork.
> $ a terminate
> Process(nil at userSchedulingPriority, ready to run)
> $ a terminate
> 'Terminated'
> Process(nil at userSchedulingPriority, terminated)

Not a bug, it won't happen when you run the program outside the REPL (or
if the REPL let processes run in the background.

> To work around such sticky processes I have decided to use a [proc
> isTerminated] whileFalse: [proc terminate] construct.

It's enough to do

proc terminate. [proc isTerminated] whileFalse: [Processor yield]

For example:

st> Eval [
    proc := [[(Delay forSeconds: 300) wait]
       ensure: ['Terminated' printNl]] fork.
    proc terminate.
    [proc isTerminated] whileFalse: [Processor yield].
    proc
]
'Terminated'
Process(nil at userSchedulingPriority, terminated)

The reason is that termination is a non-trivial operation which involves
sending the ProcessBeingTerminated exception.  It also may cause a
context switch.

Paolo

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

Re: Delay in a Process and sending #terminate

Paolo Bonzini-2
In reply to this post by Holger Freyther
On 12/18/2010 12:31 PM, Holger Hans Peter Freyther wrote:

> A:
> [
> [ ] ensure: [
> mutex critical: ['Sometimes never entered' printNl. allProcesses remove:
> Processor activeProcess].
> ]
> ] fork
>
> B:
> mutex criticial: [allProcesses do: [:each | each terminate ]].
>
> I think sometimes this statement will not executed when the process is being
> terminated. What I am trying to do is to have a cleanup handler for processes.
> E.g. to make a process remove itself from a list of processes.

This should work.  It may be that you're not waiting long enough.

mutex := Semaphore forMutualExclusion.
allProcesses := IdentitySet new.
i := 0.
p := [ :x |
       [ (Delay forMilliseconds: x) wait ] ensure: [
               mutex critical: [i := i + 1.
                 allProcesses remove: Processor activeProcess].
       ]
].

1000 timesRepeat: [
     (allProcesses add: (p newProcessWith: {Random between: 300 and:
1000}))
         resume ].
(Delay forMilliseconds: 450) wait.
mutex critical: [allProcesses do: [:each | each terminate ]].
(Delay forMilliseconds: 2000) wait.
i printNl.

If you change the final "2000" you indeed get an output that is less
than 1000.

That said, this reproduces the other bug in Delay, so thanks. :)

Paolo

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

Re: Delay in a Process and sending #terminate

Paolo Bonzini-2
In reply to this post by Holger Freyther
On 12/20/2010 11:06 AM, Holger Hans Peter Freyther wrote:

> On 12/18/2010 08:00 PM, Paolo Bonzini wrote:
>
>>
>> Aha, I could now reproduce what you meant, but it's not a bug.  The problem is
>> that if you're already in the #ensure: block, or in the #critical: block,
>> #terminate will be able to unwind it.  So, #ensure: is fundamentally
>> incompatible with #terminate (at least as it is implemented now).  I have to
>> think more about it.
>
> I assume it is the same for sending any message? I have moved from terminate
> to send a simple Notification/Exception. But as it is mostly implemented the
> same way, I face the same issue?

I think ProcessBeingTerminated is different, but it has the problem that
it is more akin to #ifCurtailed: than to #ensure:.

It would be interesting to see what other dialects do.  But it is better
to think of #terminate as a very bad idea in general :) and rethink
processes to implement *interruption* rather than termination.

Another possibility in your case is to implement the processes
collection using a wrapper, so that iteration will filter out processes
that have terminated.

I'm also thinking of moving #queueInterrupt: to a primitive or something
like that so that it's not preemptable/interruptible.  This means that
instead of removing itself from the collection, a terminating process
could *atomically* ask another process to do the removal.

Paolo

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