<div dir="ltr">Hi Ben,<div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 24, 2016 at 10:44 PM, Ben Coman <span dir="ltr"><<a href="mailto:btc@openinworld.com" target="_blank">btc@openinworld.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="">On Thu, Feb 25, 2016 at 3:06 AM, Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>> wrote:<br>
><br>
><br>
> On Wed, Feb 24, 2016 at 7:23 AM, Ben Coman <<a href="mailto:btc@openinworld.com">btc@openinworld.com</a>> wrote:<br>
>><br>
>> Just sharing a passing thought so I don't forget it before I have time<br>
>> to think more deeply on it.<br>
>><br>
>> Several parts of Pharo (like SHTextStyler) are designed to have a<br>
>> background process running, and when new input arrives that process is<br>
>> killed so another can be immediately started - and sometimes we seem<br>
>> to end up with large amounts of zombie processes.<br>
>><br>
>> As I poke around Process>>terminate, I wonder if a different approach<br>
>> would be to have a Process>>restart. I see there is Context>>restart.<br>
>><br>
>> The starting the background process might look like...<br>
>><br>
>> stylingProcess := [ [ "do stuff with nextData". self suspend ]<br>
>> repeat ] forkAt: 30.<br>
>><br>
>> and the code in the main morphic priority 40 thread might look like...<br>
>><br>
>> sylingProcess suspend.<br>
>> nextData := 'blah'.<br>
>> sylingProcess restart.<br>
><br>
><br>
> Hi Ben, so I'm assuming restart differs from resume. Am I right in thinking<br>
> it cuts back the process to the "start"? Is the start the block from which<br>
> the process was spawned, the argument to fork or forkAt:?<br>
<br>
</span>Thats right. Essentially like Exception>>retry, to do something like this...<br>
<br>
restart := false.<br>
workAvailable := Semaphore new.<br>
process :=<br>
[ [ Transcript crShow: 'At the start'.<br>
work := 0.<br>
[ work := work + 1.<br>
Transcript crShow: 'working on ' , work printString.<br>
1 second wait.<br>
work>8 ifTrue:<br>
[ [Transcript crShow: 'Work complete.'] fork.<br>
workAvailable wait.<br>
restart := true.<br>
].<br>
restart ifTrue: [self error].<br>
work<br>
] repeat.<br>
] on: Error do: [:err| restart := false. err retry].<br>
] newProcess name:'My Restartable Worker'.<br>
process resume.<br>
<br>
"later do..."<br>
restart := true.<br>
"or after work complete..."<br>
workAvailable signal.<br>
<br>
"later still do..."<br>
process terminate<br>
<br>
...except being able to interrupt the process anytime,<br>
i.e. not needing to wait to get to "restart ifTrue: [self error]."<br></blockquote><div><br></div><div>It can be built simply above signalException:. So...</div><div><br></div><div>Process class methods for instance creation</div><div>forBlock: aBlockClosure priority: anInteger </div><div><span class="" style="white-space:pre">        </span>"Answer an instance of me that has suspended aContext at priority anInteger."</div><div><br></div><div><span class="" style="white-space:pre">        </span><primitive: 19> "Simulation guard"</div><div><span class="" style="white-space:pre">        </span>| newProcess |</div><div><span class="" style="white-space:pre">        </span>(newProcess := self new)</div><div><span class="" style="white-space:pre">                </span>suspendedContext:</div><div><span class="" style="white-space:pre">                        </span>[[[newProcess result: aBlockClosure value.</div><div><span class="" style="white-space:pre">                        </span> false]</div><div><span class="" style="white-space:pre">                        </span><span style="white-space:pre">        </span><span class="" style="white-space:pre">        </span>on: ProcessRestart</div><div><span class="" style="white-space:pre">                        </span><span style="white-space:pre">        </span><span class="" style="white-space:pre">        </span>do: [:ex| true]]</div><div><span class="" style="white-space:pre">                                </span>whileTrue.</div><div><span class="" style="white-space:pre">                        </span>"Since control is now at the bottom there is no need to terminate (which</div><div><span class="" style="white-space:pre">                        </span> runs unwinds) since all unwinds have been run. Simply suspend.</div><div><span class="" style="white-space:pre">                        </span> Note that we must use this form rather than e.g. Processor suspendActive</div><div><span class="" style="white-space:pre">                        </span> so that isTerminated answers true. isTerminated requires that if there is a</div><div><span class="" style="white-space:pre">                        </span> suspended context it is the bottom-most, but using a send would result in</div><div><span class="" style="white-space:pre">                        </span> the process's suspendedContext /not/ being the bottom-most."</div><div><span class="" style="white-space:pre">                        </span> newProcess suspend] asContext;</div><div><span class="" style="white-space:pre">                </span>priority: anInteger.</div><div><span class="" style="white-space:pre">        </span>^newProcess</div><div> </div><div>Process methods for process state change</div><div>restart</div><div><span style="white-space:pre">        self signalException: </span>ProcessRestart<br></div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">btw, The requirement for the fork in "[Transcript crShow: 'Work<br>
complete.'] fork"<br>
is strange. Without it the semaphore does not wait, which seems a bug.<br></blockquote><div><br></div><div>Is there a missing yield somewhere?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
btw2, I needed to hack OCUndeclaredVariableWarning>>defaultAction to<br>
stop the transcript being polluted by unknown playground variables. No<br>
warranty on whether this is suitable to be permanent...<br>
className = 'UndefinedObject' ifFalse: [<br>
self methodNode selector ifNotNil: [self crTrace: className,<br>
'>>', selector, ' ']<br>
ifNil: [self traceCr:''].<br>
self traceCr: '(' , varName , ' is Undeclared1) '.<br>
].<br>
<span class=""><br>
<br>
<br>
<br>
On Thu, Feb 25, 2016 at 2:56 AM, Max Leske <<a href="mailto:maxleske@gmail.com">maxleske@gmail.com</a>> wrote:<br>
> Fast spawning processes are very hard to debug (e.g. in the process browser).<br>
<br>
</span>This is exactly the use case I was thinking of. Often they've been<br>
and gone before you even know they are there. Having a permanent<br>
process aids discoverability of system background functionality.<br>
<br>
cheers -ben<br>
<br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>