Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
September 2014
- 1227 messages
Update of AgileVisualization.com
by Alexandre Bergel
Dear All,
AgileVisualization.com , the book about Roassal, has been updated with a new chapter.
The HTML versions of the chapter are also online.
Agile Visualization is written using Pillar and Skeleton. Thanks Damien Cassou and Yuriy Tymchuk (Uko) for these wonderful frameworks.
I am also looking for contributors. I know that some of you guys have done wonderful things with Roassal. Sharing your knowledge with the rest of us would be fantastic. You may even get paid to write a chapter :-) Get in touch with me for more info.
Cheers,
Alexandre
--
_,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
Alexandre Bergel http://www.bergel.eu
^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
Sept. 24, 2014
Re: [Pharo-dev] Objective-C (was "deployment components")
by Craig Latta
> > > Actually, I am fine with the prefixes. Objective-C also works like
> > > that and well, it hasn't exactly hampered its community to scale.
> >
> > I think Objective-C might have had one or two other forces behind
> > it to compensate. :)
>
> Sure. But not when it was at NeXT.
Eh? Sure it did: Steve Jobs and his team, the same force behind
NeXT's reverse takeover of Apple.
-C
--
Craig Latta
netjam.org
+31 6 2757 7177 (SMS ok)
+ 1 415 287 3547 (no SMS)
Sept. 24, 2014
Re: [Pharo-dev] Nautilus roadmap / icons
by Nicolai Hess
2014-09-24 18:14 GMT+02:00 phil(a)highoctane.be <phil(a)highoctane.be>:
> In
> https://github.com/pharo-project/pharo-workingRoadmaps/blob/master/Cleaning…
>
> I see that you want to remove history, text/bytecode icons
>
> Why ?
>
> I am using those.
>
> Phil
>
My main concern is, cleaning up the code.
I don't want to change the functionality or appearance. But some users
suggest
to remove the icons and history. I would, if possible change this to a
plugin.
But if that does not work (history panel). I would keep it.
Sept. 24, 2014
Re: [Pharo-dev] [Vm-dev] re: deployment components (was "The Dilemma: Building a Futuristic GUI for Ephestos")
by Eliot Miranda
Hi Torsten,
On Wed, Sep 24, 2014 at 1:16 AM, Torsten Bergmann <astares(a)gmx.de> wrote:
>
> Craig Latta wrote:
> >Right, there's no need for anyone to use UUIDs when referring to
> >classes in Smalltalk expressions.
>
> Yes, exactly this. We still use regular names for the classes - but for
> the tools
> they have a distinguishable ID.
> Best is to use a UUID for the ID as it is unique from the beginning. So if
> you
> create a class "Foo" and I create one both are unqique by ID - even when
> using
> the same name.
>
But this doesn't cope with the fact that I can take a copy of your class,
modify my copy by adding or changing a method, etc, and hence derive two
different versions of the class with the same UUID. If a class is defined
by what it is (its methods, instance variables, superclass, etc) then it
doesn't need a UUID. Its own form uniquely (and reliably) identifies it.
If you use UUIDs then is the UUID modified every time some modification is
made to it?
The "rest" is implemeting tooling support. When you write "Foo" in a
> workspace
> then the workspace either already has a naming context to resolve the name
> (see [1]
> or could provide you with a selection if there is more than one.
> Internally you could
> bind to the right class by using the ID.
>
That's what namespaces do.
> I hate prefixing the classes as we now do, I want to name the classes
> "Instruction"
> not "IRInstruction" in Opal or "AJInstruction" in AsmJIT, especially since
> "IR" and "AJ"
> do not really tell you anything. Smalltalk names should be understandable.
> Additionally
> we should have meaningfull (and also unique) names also for namespaces.
>
Agreed.
Also the current three/two letter prefixing of classes that is used in
> Squeak or Pharo
> only scales well for small communities...
>
It's horrible. Crappy. But we're in the process of transitioning to
namespaces and that will change things.
> When there are things I like in Java then it is the fact to use reverse
> domains
> for namespaces. It is easy, understandable and I could also easily check
> if there
> is a web location.
>
> This way a namespace "org.apache.maven" gives you something meaningful, I
> can even
> visit http://maven.apache.org/. Allows the community to easily scale with
> thousands of
> classes without having clashes.
>
> Think of "org.pharo.asmjit.Instruction" vs "org.pharo.opal.Instruction"
>
You should read the Newspeak stuff on namepsaces. This explicit wiring is
horrible. It doesn't allow us to mix and match as we want to.
> So you additionally need better and meaningful namespaces THAT SCALE AND
> ARE EASY TO UNDERSTAND
> combined with real packages (as objects, as Pharo already has).
>
+1.
Then we also need ABIA (Around, beginner, inner, after messages),
I don't see what this has to do with distribution and you haven't given any
rationale for it. For me super is enough. One can synthesize all the
others using it (except I guess inner; can you give me an example of
inner?). In any case one can synthesise code via editing without needing
new VM machinery. So I'm most dubious about this.
I *do* recall discussing and sketching with David Leibs something of this
flavour for loading packages. For example deploying some Smalltalk
component/service might require modification of some core method, e.g.
add/remove dependents, and that the edit would be better expressed as a
pattern where the existing method is filled out in an element of a template
of the replacement to be loaded. This is to do with being able to define
finer-grained overrides, and have them removed after. IMO this is more
general, powerful and easier to manage than using new VM machinery.
> multiple method
> categories,
What's the rationale here? Arguably we have this now but there are bugs in
ClassOrganizer and the tools. But it is something you could write tests
for and fix now. But it seems kind of trivial and beside the point of
deployment. Can you explain why it is important?
> selector namespaces, possibility for visibility (like private methods, see
> [2]),
>
agreed. These, at least in theory, are a very nice way of insulating
extensions.
> unified annotations for classes/methods/variables and a few other
> ingredients from my
> personal wishlist and it may shape a different new future...
>
Annotations indeed. But I think first-class slots are more important no?
And the Pharo folks have a working system which we can use.
> The interesting part is not to add all kind of stuff to Smalltalk - the
> interesting
> part is what is the most minimalistic system to allow for something
> extensible
> and still flexible (even within the meta-system) so that one can bootstrap
> things on top.
>
Right. So ABIA seems over the top. What does one *really* need? You talk
of "my personal wishlist" and at the same time of "the most minimalistic
system". This reads to me as "my personal grab bag" and "the most
minimalistic system". Decide :-).
>
> Bye
> T.
>
> [1] http://vimeo.com/75391990
> [2] http://smalltalkhub.com/#!/~CamilleTeruel/PrivateMethods
>
--
best,
Eliot
Sept. 24, 2014
Re: [Pharo-dev] I'm confused about Process>>isTerminated
by Eliot Miranda
On Wed, Sep 24, 2014 at 9:14 AM, Esteban Lorenzano <estebanlm(a)gmail.com>
wrote:
> is a SLICE in the Pharo40Inbox.
> A SLICE is just a meta MCZ (A package who defines dependences).
>
Cool, and /thanks/, but there should be a direct pointer to it from the
Fogbugz page so it's easy to get to, no?
> Url to get it is:
>
> http://smalltalkhub.com/mc/Pharo/Pharo40Inbox/main
>
> then just browse for the issue number: 14064
>
> It will be called: SLICE-Issue-14064-SomethingElse
>
> you can merge it without problems, but take into a account that the issue
> needs a preload and a postload (scripts to execute before and after the
> merge).
>
> Preload:
>
> DangerousClassNotifier disable.
>
>
> Postload:
>
> DangerousClassNotifier enable.
>
>
>
>
> On 24 Sep 2014, at 18:08, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>
>
>
> On Wed, Sep 24, 2014 at 2:58 AM, Max Leske <maxleske(a)gmail.com> wrote:
>
>> Iâve opened an issue on phogbugz:
>> https://pharo.fogbugz.com/f/cases/14064/Improvements-to-checking-terminatio…
>> and created a slice. Iâd be grateful if you could take a look. There are
>> three new tests that not only test #isTerminating but a lot of other
>> expectations (like running the unwind blocks) too.
>>
>
> excuse the stupid question but where's the source?
> - How do I download a file containing the slice? (a change set, .cs file?)
> - How do I view the slice in the browser?
>
>
>>
>> Cheers,
>> Max
>>
>>
>> On 22.09.2014, at 18:30, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>
>> Hi Max,
>>
>> phhh, that editor truncated my reply (that's my excuse and I'm
>> sticking to it), so...
>>
>> On Mon, Sep 22, 2014 at 4:57 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>
>>> Hi Eliot,
>>>
>>> Thanks a lot for those explanations.
>>>
>>> On 18.09.2014, at 20:53, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>
>>> Hi Max,
>>>
>>> phhh, time zone differences suck ;-)
>>>
>>> On Thu, Sep 18, 2014 at 3:50 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>>
>>>> Hi Eliot,
>>>>
>>>> On 18.09.2014, at 01:18, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>>
>>>> Hi Max,
>>>>
>>>> On Wed, Sep 17, 2014 at 1:59 PM, Max Leske <maxleske(a)gmail.com> wrote:
>>>>
>>>>> Hi Eliot
>>>>>
>>>>>
>>>>> On 16.09.2014, at 20:18, Eliot Miranda <eliot.miranda(a)gmail.com>
>>>>> wrote:
>>>>>
>>>>> Hi Max,
>>>>>
>>>>> On Tue, Sep 16, 2014 at 11:05 AM, Max Leske <maxleske(a)gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Hi
>>>>>>
>>>>>> As always when I want to check if a process has died I get very
>>>>>> confused by #isTerminated and Iâm wondering if I just donât get how itâs
>>>>>> supposed to work or if there are others that share my confusion.
>>>>>>
>>>>>> Old implementation:
>>>>>>
>>>>>> isTerminated
>>>>>>
>>>>>> self isActiveProcess ifTrue: [^ false].
>>>>>> ^suspendedContext isNil
>>>>>> or: ["If the suspendedContext is the bottomContext it is
>>>>>> the block in Process>>newProcess.
>>>>>> If so, and the pc is greater than the startpc, the
>>>>>> bock has alrteady sent and returned
>>>>>> from value and there is nothing more to do."
>>>>>> suspendedContext isBottomContext
>>>>>> and: [ suspendedContext pc > suspendedContext
>>>>>> startpc ] ]
>>>>>>
>>>>>>
>>>>>> Pharo 4 implementation:
>>>>>>
>>>>>> isTerminated
>>>>>> self isActiveProcess ifTrue: [^ false].
>>>>>> ^suspendedContext isNil
>>>>>> or: ["If the suspendedContext is the bottomContext it is the
>>>>>> block in Process>>newProcess.
>>>>>> If so, and the pc is greater than the startpc, the
>>>>>> bock has alrteady sent and returned
>>>>>> from value and there is nothing more to do.â
>>>>>> suspendedContext isBottomContext
>>>>>> and: [ suspendedContext isDead not
>>>>>> â<âââââââââââââââââââââââââ new"
>>>>>> and: [ suspendedContext pc > suspendedContext
>>>>>> startpc ] ] ]
>>>>>>
>>>>>>
>>>>>> The old implementation would break if the suspended context was dead
>>>>>> (i.e. the pc was nil) because the send of #> would produce an MNU.
>>>>>> The new implementation doesnât fix that, even though it looks like it
>>>>>> at first glance: if the pc is nil, the #> send will still happen -> MNU.
>>>>>>
>>>>>
>>>>> Off the top of my head it would seem that it should be isDead or: []
>>>>> not isDead not and:
>>>>>
>>>>> isTerminated
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is the
>>>>> block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the
>>>>> bock has alrteady sent and returned
>>>>> from value and there is nothing more to do.â
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext isDead
>>>>> or: [ suspendedContext pc >
>>>>> suspendedContext startpc ] ] ]
>>>>>
>>>>>
>>>>> Phew. Glad you see that the same way.
>>>>>
>>>>> isDead
>>>>>> ^ pc isNil
>>>>>>
>>>>>
>>>>> and maybe (suspendedContext pc ifNil: [true] ifNotNil: [:pc| pc >
>>>>> suspendedContext startpc]) is more obvious.
>>>>>
>>>>> Anyway, neither implementation will reliably tell me if the process
>>>>>> has been terminated:
>>>>>> - an inactive process will be suspended when #terminate is sent and
>>>>>> report that it has not been terminated (#isSuspended -> true, #isTerminated
>>>>>> -> false)
>>>>>>
>>>>>
>>>>> except that it *hasn't* been terminated, it is merely in the process
>>>>> of termination. It isn't terminated until all unwind blocks have run,
>>>>> right?
>>>>>
>>>>>
>>>>> True. Easy to forget when you can just kill -9 on the console⦠:)
>>>>>
>>>>>
>>>>>
>>>>>> - a properly terminated process will raise an MNU (although
>>>>>> apparently not always�)
>>>>>>
>>>>>
>>>>> but that's a bug the change I suggested will fix.
>>>>>
>>>>>
>>>>>> - all the states in between: no clue
>>>>>>
>>>>>> I would like to know two things:
>>>>>> 1. how can I check if a process has already *received* a #terminate?
>>>>>> (I would then assume that the process will die eventually)
>>>>>>
>>>>>
>>>>> I don't think you can without putting a critical section around
>>>>> terminate and adding some process-specific variable that is set when you
>>>>> send terminate. termination is not instantaneous (unwind blocks have to be
>>>>> run), so it is potentially interruptible.
>>>>>
>>>>>
>>>>> Iâve thought about this a bit. I wouldnât really care if I donât get a
>>>>> correct answer about the termination status immediately but I want to have
>>>>> it before the process terminates. In case of something like the following:
>>>>>
>>>>> ([ 10 seconds asDelay wait ] forkAt: 11) terminate
>>>>>
>>>>> it can (potentially) take a very long time for the process to
>>>>> terminate. So if I have to poll 3 or 4 times thatâs ok but I donât want to
>>>>> wait for minutes.
>>>>> One solution would be to take your idea of the variable, but without
>>>>> the critical block:
>>>>>
>>>>> terminate
>>>>> "Stop the process that the receiver represents forever. Unwind to
>>>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>>
>>>>> | ctxt unwindBlock oldList |
>>>>> terminating := true. â<âââââââââââââââââââââââââââââââââââ changed"
>>>>> self isActiveProcess
>>>>> ifTrue: [
>>>>> ctxt := thisContext.
>>>>> [ ctxt := ctxt findNextUnwindContextUpTo: nil.
>>>>> ctxt isNil ] whileFalse:
>>>>> [ (ctxt tempAt: 2) ifNil:
>>>>> [ ctxt tempAt: 2 put: nil.
>>>>> unwindBlock := ctxt tempAt: 1.
>>>>> thisContext terminateTo: ctxt.
>>>>> unwindBlock value ]].
>>>>> thisContext terminateTo: nil.
>>>>> self suspend ]
>>>>> ifFalse: [
>>>>> "Always suspend the process first so it doesn't accidentally get woken
>>>>> up"
>>>>> oldList := self suspend.
>>>>> suspendedContext ifNotNil:[
>>>>> "Figure out if we are terminating the process while waiting in
>>>>> Semaphore>>critical:
>>>>> In this case, pop the suspendedContext so that we leave the ensure:
>>>>> block inside
>>>>> Semaphore>>critical: without signaling the semaphore."
>>>>> (oldList class == Semaphore and:[
>>>>> suspendedContext method == (Semaphore compiledMethodAt: #critical:)])
>>>>> ifTrue:[
>>>>> suspendedContext := suspendedContext home.].
>>>>> "If we are terminating a process halfways through an unwind, try
>>>>> to complete that unwind block first."
>>>>> (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [ :outer |
>>>>> (suspendedContext findContextSuchThat: [ :c | c closure == (outer
>>>>> tempAt: 1)])
>>>>> ifNotNil: [ :inner |
>>>>> "This is an unwind block currently under evaluation"
>>>>> suspendedContext runUntilErrorOrReturnFrom: inner ]].
>>>>> ctxt := self popTo: suspendedContext bottomContext.
>>>>> ctxt == suspendedContext bottomContext ifFalse: [
>>>>> self debug: ctxt title: 'Unwind error during termination']] ].
>>>>>
>>>>>
>>>>>
>>>>> isTerminating
>>>>> ^ terminating ifNil: [ ^ false ]
>>>>>
>>>>>
>>>>> With this small modification I can run the example from above and
>>>>> immediately see that it will die eventually.
>>>>>
>>>>> Iâm aware that one process might not see the change to the variable
>>>>> immediately but as I said, I wouldnât really care.
>>>>>
>>>>>
>>>>> What do you think?
>>>>>
>>>>
>>>> Yes that looks good. But given that branches are atomic (ifTrue: is
>>>> not a send) why not do
>>>>
>>>> Process>>initialize
>>>> terminating := false.
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to
>>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> terminating
>>>> ifTrue: [self error: 'Process is already terminated, or being
>>>> terminated']
>>>> ifFalse: [terminating := true].
>>>> self isActiveProcess
>>>> ifTrue:
>>>> ...
>>>>
>>>> ?
>>>>
>>>> I would suggest a status inst var, as in
>>>>
>>>> Process>>initialize
>>>> status := nil
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to
>>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> status == #terminating
>>>> ifTrue: [self error: 'Process is already terminated, or being
>>>> terminated']
>>>> ifFalse: [status := terminating].
>>>> self isActiveProcess
>>>> ifTrue:
>>>> ...
>>>>
>>>> but the temptation then is to have lots of different status values and
>>>> I'm leery of introducing that kind of complication without a strong
>>>> justification.
>>>>
>>>>
>>>>
>>>> Iâve worked a bit on an implementation along your suggestions. I wrote
>>>> a test which looks like this:
>>>>
>>>> testIsTerminated
>>>> | proc |
>>>> proc := [ Semaphore new wait ] forkAt: 30.
>>>> self deny: proc isSuspended.
>>>> self deny: proc isTerminating.
>>>> self deny: proc isTerminated.
>>>> proc terminate.
>>>> self deny: proc isTerminated.
>>>> self assert: proc isSuspended.
>>>> self assert: proc isTerminating.
>>>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].
>>>> â<âââââââââââ ???"
>>>>
>>>> self assert: proc isTerminated.
>>>> self assert: proc isTerminating
>>>>
>>>> The test works AFAICT (apart from the loopâ¦) but I want to also have a
>>>> check after the process has terminated. Is there some reliable way to wait
>>>> for a process to die? I tried something like this for example:
>>>>
>>>> proc run.
>>>> self assert: proc isTerminated.
>>>>
>>>> But that locks up the active process (obviously) until I interrupt it
>>>> manually. If there is such a way, I could also add a method that lets a
>>>> process x wait for the completion of a process y for example (or not,
>>>> depending on how difficult it is :) )
>>>>
>>>
>>> I can't see anything to do other than waiting. One thing is to run the
>>> process at as close to user priority as possible, so I would say
>>>
>>> proc := [ Semaphore new wait ] forkAt: Processor activePriority - 1.
>>>
>>> Another important thing is that you're not giving your process a chance
>>> to run before you test for it not terminating. So adding a yield after the
>>> first set of asserts and then repeating them is good:
>>>
>>> started := false. proc := [ started := true. Semaphore new wait ]
>>> forkAt: 30.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>> (Delay forMilliseconds: 10) wait. self assert: started.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>> Another thing might be to boost its priority to make sure it finishes
>>> (except that that'll probably have no effect because IIRC right now the
>>> terminator runs the termination). So you could say
>>>
>>> proc terminate.
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>>
>>> process priority: Processor activePriority + 1.
>>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].
>>>
>>> Further I'd want to test that unwind blocks have been run so I'd say
>>>
>>> testIsTerminated
>>> | proc started unwound terminator |
>>> unwound := false. proc := [ started := true. [Semaphore new wait]
>>> ensure: [terminator := Processor activeProcess.
>>> unwound := true] ]
>>> forkAt: Processor activePriority - 1.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>> (Delay forMilliseconds: 10) wait. "Alloc proc to run; there shouldnt
>>> be too much else going on so this delay should suffice"
>>>
>>> self assert: started.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>> proc terminate.
>>> proc priority: Processor activePriority + 1. "This may have no effect;
>>> termination may be executed by the terminator rather than the terminatee;
>>> ys, this is a bug"
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>> (Delay forMilliseconds: 10) wait. "Allow proc to terminate; there
>>> shouldnt be too much else going on so this delay should suffice"
>>>
>>> self assert: proc isTerminated.
>>> self assert: proc isTerminating.
>>> self assert: unwound.
>>> self assert: terminator == proc. "But this should be made an expected
>>> failure; I don't know how to do that in SUnitâ¦"
>>>
>>>
>>> From your comments I expected this last statement to fail but actually
>>> it doesnât. I guess thatâs a good sign (?).
>>>
>>>
>>> and google's mail text editor *SUCKS*!!!!
>>>
>>>
>>> lol :p
>>>
>>> I noticed something else regarding terminated processes that have never
>>> run and Iâm not sure if thatâs not a bug:
>>> When I suspend a process (that has never run) that is not the active
>>> process, I can reliably reproduce that the entire #terminate method is
>>> being executed. The processâ suspendedContext is the bottom context (as it
>>> should be). However, the pc is equal to the startpc, since that process
>>> never had a chance to to anything. The result is that #isTerminated will
>>> answer false, even though the process is technically terminated.
>>> One side effect of this is that itâs impossible to do something like â[
>>> proc isTerminated ] whileFalse: [ 1 second asDelay wait ].â because that
>>> will not terminate for all processes. Luckily those processes can be
>>> garbage collected regardless of what #isTerminated says.
>>>
>>> One obvious fix would be to set the pc of the suspendedContext to nil
>>> but Iâm not sure thatâs a good idea.
>>>
>>> What do you think?
>>>
>>
>> I think that's fine.
>>
>> Cheers,
>>> Max
>>>
>>> Cheers,
>>> Max
>>> Cheers,
>>> Max
>>>
>>>> 2. how can I check if a process is *actually* dead? (in case a âhalf
>>>> deadâ process will still unwind or whatever)
>>>>
>>>
>>> see above.
>>>
>>> What would be necessary to make those tests (or better ones) possible
>>>> (rewrite the whole process implementation?)?
>>>>
>>>> Cheers,
>>>> Max
>>>
>>> --
>>> best,
>>> Eliot
>>> --
>>> best,
>>> Eliot
>>> --
>>> best,
>>> Eliot
>>>
>>> --
>> best,
>> Eliot
>>
>>
>>
>
>
> --
> best,
> Eliot
>
>
>
--
best,
Eliot
Sept. 24, 2014
Re: [Pharo-dev] Gitfiletree github diff
by Thierry Goubier
Le 24/09/2014 17:50, Yuriy Tymchuk a écrit :
> I open monticello browser, select my package, and I have associated
> github repository⦠Wait. Maybe it is not gitfiletreeâs error because
> that repository is installed with metacello github magic. But yes, wen I
> clock on âchangesâ button I get the error.
If it is a github: installed repository, then it should be a filetree:
repository.
Could it be an error linked with an https:// repository?
Thierry
> Uko
>
>> On 24 Sep 2014, at 17:10, Thierry Goubier <thierry.goubier(a)gmail.com
>> <mailto:thierry.goubier@gmail.com>> wrote:
>>
>> Hi Uko,
>>
>> where do you get that error? From inside Pharo? Or when browsing on
>> github?
>>
>> Thierry
>>
>> 2014-09-24 16:48 GMT+02:00 Yuriy Tymchuk <yuriy.tymchuk(a)me.com
>> <mailto:yuriy.tymchuk@me.com>>:
>>
>> Hi,
>>
>> I use gitfiletree and when I want to see changes with my github
>> repo, I get: "SSL Exception: decrypt failed [code:-5]â. But only
>> first time, all other times it works well. Any ideas where can be
>> the problem?
>>
>> Uko
>>
>>
>
Sept. 24, 2014
Nautilus roadmap / icons
by phil@highoctane.be
In
https://github.com/pharo-project/pharo-workingRoadmaps/blob/master/Cleaning…
I see that you want to remove history, text/bytecode icons
Why ?
I am using those.
Phil
Sept. 24, 2014
Re: [Pharo-dev] I'm confused about Process>>isTerminated
by Esteban Lorenzano
is a SLICE in the Pharo40Inbox.
A SLICE is just a meta MCZ (A package who defines dependences).
Url to get it is:
http://smalltalkhub.com/mc/Pharo/Pharo40Inbox/main
then just browse for the issue number: 14064
It will be called: SLICE-Issue-14064-SomethingElse
you can merge it without problems, but take into a account that the issue needs a preload and a postload (scripts to execute before and after the merge).
Preload:
DangerousClassNotifier disable.
Postload:
DangerousClassNotifier enable.
On 24 Sep 2014, at 18:08, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>
>
> On Wed, Sep 24, 2014 at 2:58 AM, Max Leske <maxleske(a)gmail.com> wrote:
> Iâve opened an issue on phogbugz: https://pharo.fogbugz.com/f/cases/14064/Improvements-to-checking-terminatio…
> and created a slice. Iâd be grateful if you could take a look. There are three new tests that not only test #isTerminating but a lot of other expectations (like running the unwind blocks) too.
>
> excuse the stupid question but where's the source?
> - How do I download a file containing the slice? (a change set, .cs file?)
> - How do I view the slice in the browser?
>
>
> Cheers,
> Max
>
>
> On 22.09.2014, at 18:30, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>
>> Hi Max,
>>
>> phhh, that editor truncated my reply (that's my excuse and I'm sticking to it), so...
>>
>> On Mon, Sep 22, 2014 at 4:57 AM, Max Leske <maxleske(a)gmail.com> wrote:
>> Hi Eliot,
>>
>> Thanks a lot for those explanations.
>>
>> On 18.09.2014, at 20:53, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>
>>> Hi Max,
>>>
>>> phhh, time zone differences suck ;-)
>>>
>>> On Thu, Sep 18, 2014 at 3:50 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>> Hi Eliot,
>>>
>>> On 18.09.2014, at 01:18, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>
>>>> Hi Max,
>>>>
>>>> On Wed, Sep 17, 2014 at 1:59 PM, Max Leske <maxleske(a)gmail.com> wrote:
>>>> Hi Eliot
>>>>
>>>>
>>>> On 16.09.2014, at 20:18, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>>
>>>>> Hi Max,
>>>>>
>>>>> On Tue, Sep 16, 2014 at 11:05 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>>>> Hi
>>>>>
>>>>> As always when I want to check if a process has died I get very confused by #isTerminated and Iâm wondering if I just donât get how itâs supposed to work or if there are others that share my confusion.
>>>>>
>>>>> Old implementation:
>>>>>
>>>>> isTerminated
>>>>>
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the bock has alrteady sent and returned
>>>>> from value and there is nothing more to do."
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext pc > suspendedContext startpc ] ]
>>>>>
>>>>>
>>>>> Pharo 4 implementation:
>>>>>
>>>>> isTerminated
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the bock has alrteady sent and returned
>>>>> from value and there is nothing more to do.â
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext isDead not â<âââââââââââââââââââââââââ new"
>>>>> and: [ suspendedContext pc > suspendedContext startpc ] ] ]
>>>>>
>>>>>
>>>>> The old implementation would break if the suspended context was dead (i.e. the pc was nil) because the send of #> would produce an MNU.
>>>>> The new implementation doesnât fix that, even though it looks like it at first glance: if the pc is nil, the #> send will still happen -> MNU.
>>>>>
>>>>> Off the top of my head it would seem that it should be isDead or: [] not isDead not and:
>>>>>
>>>>> isTerminated
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the bock has alrteady sent and returned
>>>>> from value and there is nothing more to do.â
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext isDead
>>>>> or: [ suspendedContext pc > suspendedContext startpc ] ] ]
>>>>
>>>> Phew. Glad you see that the same way.
>>>>
>>>>> isDead
>>>>> ^ pc isNil
>>>>>
>>>>> and maybe (suspendedContext pc ifNil: [true] ifNotNil: [:pc| pc > suspendedContext startpc]) is more obvious.
>>>>>
>>>>> Anyway, neither implementation will reliably tell me if the process has been terminated:
>>>>> - an inactive process will be suspended when #terminate is sent and report that it has not been terminated (#isSuspended -> true, #isTerminated -> false)
>>>>>
>>>>> except that it *hasn't* been terminated, it is merely in the process of termination. It isn't terminated until all unwind blocks have run, right?
>>>>
>>>> True. Easy to forget when you can just kill -9 on the console⦠:)
>>>>
>>>>>
>>>>> - a properly terminated process will raise an MNU (although apparently not always�)
>>>>>
>>>>> but that's a bug the change I suggested will fix.
>>>>>
>>>>> - all the states in between: no clue
>>>>>
>>>>> I would like to know two things:
>>>>> 1. how can I check if a process has already *received* a #terminate? (I would then assume that the process will die eventually)
>>>>>
>>>>> I don't think you can without putting a critical section around terminate and adding some process-specific variable that is set when you send terminate. termination is not instantaneous (unwind blocks have to be run), so it is potentially interruptible.
>>>>
>>>> Iâve thought about this a bit. I wouldnât really care if I donât get a correct answer about the termination status immediately but I want to have it before the process terminates. In case of something like the following:
>>>>
>>>> ([ 10 seconds asDelay wait ] forkAt: 11) terminate
>>>>
>>>> it can (potentially) take a very long time for the process to terminate. So if I have to poll 3 or 4 times thatâs ok but I donât want to wait for minutes.
>>>> One solution would be to take your idea of the variable, but without the critical block:
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> terminating := true. â<âââââââââââââââââââââââââââââââââââ changed"
>>>> self isActiveProcess
>>>> ifTrue: [
>>>> ctxt := thisContext.
>>>> [ ctxt := ctxt findNextUnwindContextUpTo: nil.
>>>> ctxt isNil ] whileFalse:
>>>> [ (ctxt tempAt: 2) ifNil:
>>>> [ ctxt tempAt: 2 put: nil.
>>>> unwindBlock := ctxt tempAt: 1.
>>>> thisContext terminateTo: ctxt.
>>>> unwindBlock value ]].
>>>> thisContext terminateTo: nil.
>>>> self suspend ]
>>>> ifFalse: [
>>>> "Always suspend the process first so it doesn't accidentally get woken up"
>>>> oldList := self suspend.
>>>> suspendedContext ifNotNil:[
>>>> "Figure out if we are terminating the process while waiting in Semaphore>>critical:
>>>> In this case, pop the suspendedContext so that we leave the ensure: block inside
>>>> Semaphore>>critical: without signaling the semaphore."
>>>> (oldList class == Semaphore and:[
>>>> suspendedContext method == (Semaphore compiledMethodAt: #critical:)]) ifTrue:[
>>>> suspendedContext := suspendedContext home.].
>>>>
>>>> "If we are terminating a process halfways through an unwind, try to complete that unwind block first."
>>>> (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [ :outer |
>>>> (suspendedContext findContextSuchThat: [ :c | c closure == (outer tempAt: 1)])
>>>> ifNotNil: [ :inner |
>>>> "This is an unwind block currently under evaluation"
>>>> suspendedContext runUntilErrorOrReturnFrom: inner ]].
>>>> ctxt := self popTo: suspendedContext bottomContext.
>>>> ctxt == suspendedContext bottomContext ifFalse: [
>>>> self debug: ctxt title: 'Unwind error during termination']] ].
>>>>
>>>>
>>>>
>>>> isTerminating
>>>> ^ terminating ifNil: [ ^ false ]
>>>>
>>>>
>>>> With this small modification I can run the example from above and immediately see that it will die eventually.
>>>>
>>>> Iâm aware that one process might not see the change to the variable immediately but as I said, I wouldnât really care.
>>>>
>>>>
>>>> What do you think?
>>>>
>>>> Yes that looks good. But given that branches are atomic (ifTrue: is not a send) why not do
>>>>
>>>> Process>>initialize
>>>> terminating := false.
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> terminating
>>>> ifTrue: [self error: 'Process is already terminated, or being terminated']
>>>> ifFalse: [terminating := true].
>>>> self isActiveProcess
>>>> ifTrue:
>>>> ...
>>>>
>>>> ?
>>>>
>>>> I would suggest a status inst var, as in
>>>>
>>>> Process>>initialize
>>>> status := nil
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> status == #terminating
>>>> ifTrue: [self error: 'Process is already terminated, or being terminated']
>>>> ifFalse: [status := terminating].
>>>> self isActiveProcess
>>>> ifTrue:
>>>> ...
>>>>
>>>> but the temptation then is to have lots of different status values and I'm leery of introducing that kind of complication without a strong justification.
>>>
>>>
>>> Iâve worked a bit on an implementation along your suggestions. I wrote a test which looks like this:
>>>
>>> testIsTerminated
>>> | proc |
>>> proc := [ Semaphore new wait ] forkAt: 30.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>> proc terminate.
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>>
>>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ]. â<âââââââââââ ???"
>>>
>>> self assert: proc isTerminated.
>>> self assert: proc isTerminating
>>>
>>> The test works AFAICT (apart from the loopâ¦) but I want to also have a check after the process has terminated. Is there some reliable way to wait for a process to die? I tried something like this for example:
>>>
>>> proc run.
>>> self assert: proc isTerminated.
>>>
>>> But that locks up the active process (obviously) until I interrupt it manually. If there is such a way, I could also add a method that lets a process x wait for the completion of a process y for example (or not, depending on how difficult it is :) )
>>>
>>> I can't see anything to do other than waiting. One thing is to run the process at as close to user priority as possible, so I would say
>>>
>>> proc := [ Semaphore new wait ] forkAt: Processor activePriority - 1.
>>>
>>> Another important thing is that you're not giving your process a chance to run before you test for it not terminating. So adding a yield after the first set of asserts and then repeating them is good:
>>>
>>> started := false. proc := [ started := true. Semaphore new wait ] forkAt: 30.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>> (Delay forMilliseconds: 10) wait. self assert: started.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>>
>>> Another thing might be to boost its priority to make sure it finishes (except that that'll probably have no effect because IIRC right now the terminator runs the termination). So you could say
>>>
>>> proc terminate.
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>>
>>> process priority: Processor activePriority + 1.
>>>
>>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].
>>>
>>> Further I'd want to test that unwind blocks have been run so I'd say
>>>
>>> testIsTerminated
>>> | proc started unwound terminator |
>>> unwound := false. proc := [ started := true. [Semaphore new wait]
>>> ensure: [terminator := Processor activeProcess.
>>> unwound := true] ]
>>> forkAt: Processor activePriority - 1.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>> (Delay forMilliseconds: 10) wait. "Alloc proc to run; there shouldnt be too much else going on so this delay should suffice"
>>>
>>> self assert: started.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>>
>>> proc terminate.
>>> proc priority: Processor activePriority + 1. "This may have no effect; termination may be executed by the terminator rather than the terminatee; ys, this is a bug"
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>>
>>> (Delay forMilliseconds: 10) wait. "Allow proc to terminate; there shouldnt be too much else going on so this delay should suffice"
>>>
>>> self assert: proc isTerminated.
>>> self assert: proc isTerminating.
>>> self assert: unwound.
>>> self assert: terminator == proc. "But this should be made an expected failure; I don't know how to do that in SUnitâ¦"
>>
>> From your comments I expected this last statement to fail but actually it doesnât. I guess thatâs a good sign (?).
>>
>>>
>>> and google's mail text editor *SUCKS*!!!!
>>
>> lol :p
>>
>> I noticed something else regarding terminated processes that have never run and Iâm not sure if thatâs not a bug:
>> When I suspend a process (that has never run) that is not the active process, I can reliably reproduce that the entire #terminate method is being executed. The processâ suspendedContext is the bottom context (as it should be). However, the pc is equal to the startpc, since that process never had a chance to to anything. The result is that #isTerminated will answer false, even though the process is technically terminated.
>> One side effect of this is that itâs impossible to do something like â[ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].â because that will not terminate for all processes. Luckily those processes can be garbage collected regardless of what #isTerminated says.
>>
>> One obvious fix would be to set the pc of the suspendedContext to nil but Iâm not sure thatâs a good idea.
>>
>> What do you think?
>>
>> I think that's fine.
>>
>> Cheers,
>> Max
>>> Cheers,
>>> Max
>>> Cheers,
>>> Max
>>> 2. how can I check if a process is *actually* dead? (in case a âhalf deadâ process will still unwind or whatever)
>>>
>>> see above.
>>>
>>> What would be necessary to make those tests (or better ones) possible (rewrite the whole process implementation?)?
>>>
>>> Cheers,
>>> Max
>>> --
>>> best,
>>> Eliot
>>> --
>>> best,
>>> Eliot
>>> --
>>> best,
>>> Eliot
>> --
>> best,
>> Eliot
>
>
>
>
> --
> best,
> Eliot
Sept. 24, 2014
Re: [Pharo-dev] I'm confused about Process>>isTerminated
by Eliot Miranda
On Wed, Sep 24, 2014 at 2:58 AM, Max Leske <maxleske(a)gmail.com> wrote:
> Iâve opened an issue on phogbugz:
> https://pharo.fogbugz.com/f/cases/14064/Improvements-to-checking-terminatio…
> and created a slice. Iâd be grateful if you could take a look. There are
> three new tests that not only test #isTerminating but a lot of other
> expectations (like running the unwind blocks) too.
>
excuse the stupid question but where's the source?
- How do I download a file containing the slice? (a change set, .cs file?)
- How do I view the slice in the browser?
>
> Cheers,
> Max
>
>
> On 22.09.2014, at 18:30, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>
> Hi Max,
>
> phhh, that editor truncated my reply (that's my excuse and I'm sticking
> to it), so...
>
> On Mon, Sep 22, 2014 at 4:57 AM, Max Leske <maxleske(a)gmail.com> wrote:
>
>> Hi Eliot,
>>
>> Thanks a lot for those explanations.
>>
>> On 18.09.2014, at 20:53, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>
>> Hi Max,
>>
>> phhh, time zone differences suck ;-)
>>
>> On Thu, Sep 18, 2014 at 3:50 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>
>>> Hi Eliot,
>>>
>>> On 18.09.2014, at 01:18, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>
>>> Hi Max,
>>>
>>> On Wed, Sep 17, 2014 at 1:59 PM, Max Leske <maxleske(a)gmail.com> wrote:
>>>
>>>> Hi Eliot
>>>>
>>>>
>>>> On 16.09.2014, at 20:18, Eliot Miranda <eliot.miranda(a)gmail.com> wrote:
>>>>
>>>> Hi Max,
>>>>
>>>> On Tue, Sep 16, 2014 at 11:05 AM, Max Leske <maxleske(a)gmail.com> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> As always when I want to check if a process has died I get very
>>>>> confused by #isTerminated and Iâm wondering if I just donât get how itâs
>>>>> supposed to work or if there are others that share my confusion.
>>>>>
>>>>> Old implementation:
>>>>>
>>>>> isTerminated
>>>>>
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is
>>>>> the block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the
>>>>> bock has alrteady sent and returned
>>>>> from value and there is nothing more to do."
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext pc > suspendedContext startpc
>>>>> ] ]
>>>>>
>>>>>
>>>>> Pharo 4 implementation:
>>>>>
>>>>> isTerminated
>>>>> self isActiveProcess ifTrue: [^ false].
>>>>> ^suspendedContext isNil
>>>>> or: ["If the suspendedContext is the bottomContext it is the
>>>>> block in Process>>newProcess.
>>>>> If so, and the pc is greater than the startpc, the
>>>>> bock has alrteady sent and returned
>>>>> from value and there is nothing more to do.â
>>>>> suspendedContext isBottomContext
>>>>> and: [ suspendedContext isDead not
>>>>> â<âââââââââââââââââââââââââ new"
>>>>> and: [ suspendedContext pc > suspendedContext startpc
>>>>> ] ] ]
>>>>>
>>>>>
>>>>> The old implementation would break if the suspended context was dead
>>>>> (i.e. the pc was nil) because the send of #> would produce an MNU.
>>>>> The new implementation doesnât fix that, even though it looks like it
>>>>> at first glance: if the pc is nil, the #> send will still happen -> MNU.
>>>>>
>>>>
>>>> Off the top of my head it would seem that it should be isDead or: []
>>>> not isDead not and:
>>>>
>>>> isTerminated
>>>> self isActiveProcess ifTrue: [^ false].
>>>> ^suspendedContext isNil
>>>> or: ["If the suspendedContext is the bottomContext it is the
>>>> block in Process>>newProcess.
>>>> If so, and the pc is greater than the startpc, the
>>>> bock has alrteady sent and returned
>>>> from value and there is nothing more to do.â
>>>> suspendedContext isBottomContext
>>>> and: [ suspendedContext isDead
>>>> or: [ suspendedContext pc > suspendedContext
>>>> startpc ] ] ]
>>>>
>>>>
>>>> Phew. Glad you see that the same way.
>>>>
>>>> isDead
>>>>> ^ pc isNil
>>>>>
>>>>
>>>> and maybe (suspendedContext pc ifNil: [true] ifNotNil: [:pc| pc >
>>>> suspendedContext startpc]) is more obvious.
>>>>
>>>> Anyway, neither implementation will reliably tell me if the process has
>>>>> been terminated:
>>>>> - an inactive process will be suspended when #terminate is sent and
>>>>> report that it has not been terminated (#isSuspended -> true, #isTerminated
>>>>> -> false)
>>>>>
>>>>
>>>> except that it *hasn't* been terminated, it is merely in the process of
>>>> termination. It isn't terminated until all unwind blocks have run, right?
>>>>
>>>>
>>>> True. Easy to forget when you can just kill -9 on the console⦠:)
>>>>
>>>>
>>>>
>>>>> - a properly terminated process will raise an MNU (although apparently
>>>>> not always�)
>>>>>
>>>>
>>>> but that's a bug the change I suggested will fix.
>>>>
>>>>
>>>>> - all the states in between: no clue
>>>>>
>>>>> I would like to know two things:
>>>>> 1. how can I check if a process has already *received* a #terminate?
>>>>> (I would then assume that the process will die eventually)
>>>>>
>>>>
>>>> I don't think you can without putting a critical section around
>>>> terminate and adding some process-specific variable that is set when you
>>>> send terminate. termination is not instantaneous (unwind blocks have to be
>>>> run), so it is potentially interruptible.
>>>>
>>>>
>>>> Iâve thought about this a bit. I wouldnât really care if I donât get a
>>>> correct answer about the termination status immediately but I want to have
>>>> it before the process terminates. In case of something like the following:
>>>>
>>>> ([ 10 seconds asDelay wait ] forkAt: 11) terminate
>>>>
>>>> it can (potentially) take a very long time for the process to
>>>> terminate. So if I have to poll 3 or 4 times thatâs ok but I donât want to
>>>> wait for minutes.
>>>> One solution would be to take your idea of the variable, but without
>>>> the critical block:
>>>>
>>>> terminate
>>>> "Stop the process that the receiver represents forever. Unwind to
>>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>>
>>>> | ctxt unwindBlock oldList |
>>>> terminating := true. â<âââââââââââââââââââââââââââââââââââ changed"
>>>> self isActiveProcess
>>>> ifTrue: [
>>>> ctxt := thisContext.
>>>> [ ctxt := ctxt findNextUnwindContextUpTo: nil.
>>>> ctxt isNil ] whileFalse:
>>>> [ (ctxt tempAt: 2) ifNil:
>>>> [ ctxt tempAt: 2 put: nil.
>>>> unwindBlock := ctxt tempAt: 1.
>>>> thisContext terminateTo: ctxt.
>>>> unwindBlock value ]].
>>>> thisContext terminateTo: nil.
>>>> self suspend ]
>>>> ifFalse: [
>>>> "Always suspend the process first so it doesn't accidentally get woken
>>>> up"
>>>> oldList := self suspend.
>>>> suspendedContext ifNotNil:[
>>>> "Figure out if we are terminating the process while waiting in
>>>> Semaphore>>critical:
>>>> In this case, pop the suspendedContext so that we leave the ensure:
>>>> block inside
>>>> Semaphore>>critical: without signaling the semaphore."
>>>> (oldList class == Semaphore and:[
>>>> suspendedContext method == (Semaphore compiledMethodAt: #critical:)])
>>>> ifTrue:[
>>>> suspendedContext := suspendedContext home.].
>>>> "If we are terminating a process halfways through an unwind, try to
>>>> complete that unwind block first."
>>>> (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [ :outer |
>>>> (suspendedContext findContextSuchThat: [ :c | c closure == (outer
>>>> tempAt: 1)])
>>>> ifNotNil: [ :inner |
>>>> "This is an unwind block currently under evaluation"
>>>> suspendedContext runUntilErrorOrReturnFrom: inner ]].
>>>> ctxt := self popTo: suspendedContext bottomContext.
>>>> ctxt == suspendedContext bottomContext ifFalse: [
>>>> self debug: ctxt title: 'Unwind error during termination']] ].
>>>>
>>>>
>>>>
>>>> isTerminating
>>>> ^ terminating ifNil: [ ^ false ]
>>>>
>>>>
>>>> With this small modification I can run the example from above and
>>>> immediately see that it will die eventually.
>>>>
>>>> Iâm aware that one process might not see the change to the variable
>>>> immediately but as I said, I wouldnât really care.
>>>>
>>>>
>>>> What do you think?
>>>>
>>>
>>> Yes that looks good. But given that branches are atomic (ifTrue: is
>>> not a send) why not do
>>>
>>> Process>>initialize
>>> terminating := false.
>>>
>>> terminate
>>> "Stop the process that the receiver represents forever. Unwind to
>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>
>>> | ctxt unwindBlock oldList |
>>> terminating
>>> ifTrue: [self error: 'Process is already terminated, or being
>>> terminated']
>>> ifFalse: [terminating := true].
>>> self isActiveProcess
>>> ifTrue:
>>> ...
>>>
>>> ?
>>>
>>> I would suggest a status inst var, as in
>>>
>>> Process>>initialize
>>> status := nil
>>>
>>> terminate
>>> "Stop the process that the receiver represents forever. Unwind to
>>> execute pending ensure:/ifCurtailed: blocks before terminating."
>>>
>>> | ctxt unwindBlock oldList |
>>> status == #terminating
>>> ifTrue: [self error: 'Process is already terminated, or being
>>> terminated']
>>> ifFalse: [status := terminating].
>>> self isActiveProcess
>>> ifTrue:
>>> ...
>>>
>>> but the temptation then is to have lots of different status values and
>>> I'm leery of introducing that kind of complication without a strong
>>> justification.
>>>
>>>
>>>
>>> Iâve worked a bit on an implementation along your suggestions. I wrote a
>>> test which looks like this:
>>>
>>> testIsTerminated
>>> | proc |
>>> proc := [ Semaphore new wait ] forkAt: 30.
>>> self deny: proc isSuspended.
>>> self deny: proc isTerminating.
>>> self deny: proc isTerminated.
>>> proc terminate.
>>> self deny: proc isTerminated.
>>> self assert: proc isSuspended.
>>> self assert: proc isTerminating.
>>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].
>>> â<âââââââââââ ???"
>>>
>>> self assert: proc isTerminated.
>>> self assert: proc isTerminating
>>>
>>> The test works AFAICT (apart from the loopâ¦) but I want to also have a
>>> check after the process has terminated. Is there some reliable way to wait
>>> for a process to die? I tried something like this for example:
>>>
>>> proc run.
>>> self assert: proc isTerminated.
>>>
>>> But that locks up the active process (obviously) until I interrupt it
>>> manually. If there is such a way, I could also add a method that lets a
>>> process x wait for the completion of a process y for example (or not,
>>> depending on how difficult it is :) )
>>>
>>
>> I can't see anything to do other than waiting. One thing is to run the
>> process at as close to user priority as possible, so I would say
>>
>> proc := [ Semaphore new wait ] forkAt: Processor activePriority - 1.
>>
>> Another important thing is that you're not giving your process a chance
>> to run before you test for it not terminating. So adding a yield after the
>> first set of asserts and then repeating them is good:
>>
>> started := false. proc := [ started := true. Semaphore new wait ]
>> forkAt: 30.
>> self deny: proc isSuspended.
>> self deny: proc isTerminating.
>> self deny: proc isTerminated.
>> (Delay forMilliseconds: 10) wait. self assert: started.
>> self deny: proc isSuspended.
>> self deny: proc isTerminating.
>> self deny: proc isTerminated.
>>
>> Another thing might be to boost its priority to make sure it finishes
>> (except that that'll probably have no effect because IIRC right now the
>> terminator runs the termination). So you could say
>>
>> proc terminate.
>> self deny: proc isTerminated.
>> self assert: proc isSuspended.
>> self assert: proc isTerminating.
>>
>> process priority: Processor activePriority + 1.
>> [ proc isTerminated ] whileFalse: [ 1 second asDelay wait ].
>>
>> Further I'd want to test that unwind blocks have been run so I'd say
>>
>> testIsTerminated
>> | proc started unwound terminator |
>> unwound := false. proc := [ started := true. [Semaphore new wait]
>> ensure: [terminator := Processor activeProcess.
>> unwound := true] ]
>> forkAt: Processor activePriority - 1.
>> self deny: proc isSuspended.
>> self deny: proc isTerminating.
>> self deny: proc isTerminated.
>> (Delay forMilliseconds: 10) wait. "Alloc proc to run; there shouldnt be
>> too much else going on so this delay should suffice"
>>
>> self assert: started.
>> self deny: proc isSuspended.
>> self deny: proc isTerminating.
>> self deny: proc isTerminated.
>> proc terminate.
>> proc priority: Processor activePriority + 1. "This may have no effect;
>> termination may be executed by the terminator rather than the terminatee;
>> ys, this is a bug"
>> self deny: proc isTerminated.
>> self assert: proc isSuspended.
>> self assert: proc isTerminating.
>> (Delay forMilliseconds: 10) wait. "Allow proc to terminate; there
>> shouldnt be too much else going on so this delay should suffice"
>>
>> self assert: proc isTerminated.
>> self assert: proc isTerminating.
>> self assert: unwound.
>> self assert: terminator == proc. "But this should be made an expected
>> failure; I don't know how to do that in SUnitâ¦"
>>
>>
>> From your comments I expected this last statement to fail but actually it
>> doesnât. I guess thatâs a good sign (?).
>>
>>
>> and google's mail text editor *SUCKS*!!!!
>>
>>
>> lol :p
>>
>> I noticed something else regarding terminated processes that have never
>> run and Iâm not sure if thatâs not a bug:
>> When I suspend a process (that has never run) that is not the active
>> process, I can reliably reproduce that the entire #terminate method is
>> being executed. The processâ suspendedContext is the bottom context (as it
>> should be). However, the pc is equal to the startpc, since that process
>> never had a chance to to anything. The result is that #isTerminated will
>> answer false, even though the process is technically terminated.
>> One side effect of this is that itâs impossible to do something like â[
>> proc isTerminated ] whileFalse: [ 1 second asDelay wait ].â because that
>> will not terminate for all processes. Luckily those processes can be
>> garbage collected regardless of what #isTerminated says.
>>
>> One obvious fix would be to set the pc of the suspendedContext to nil but
>> Iâm not sure thatâs a good idea.
>>
>> What do you think?
>>
>
> I think that's fine.
>
> Cheers,
>> Max
>>
>> Cheers,
>>> Max
>>>
>>> Cheers,
>>>> Max
>>>>
>>>>> 2. how can I check if a process is *actually* dead? (in case a âhalf
>>>>> deadâ process will still unwind or whatever)
>>>>>
>>>>
>>>> see above.
>>>>
>>>> What would be necessary to make those tests (or better ones) possible
>>>>> (rewrite the whole process implementation?)?
>>>>>
>>>>> Cheers,
>>>>> Max
>>>>
>>>> --
>>>> best,
>>>> Eliot
>>>>
>>> --
>>> best,
>>> Eliot
>>>
>>> --
>> best,
>> Eliot
>>
>> --
> best,
> Eliot
>
>
>
--
best,
Eliot
Sept. 24, 2014
[pharo-project/pharo-core] 18c33b: 30858
by GitHub
Branch: refs/heads/3.0
Home: https://github.com/pharo-project/pharo-core
Commit: 18c33b2573dbb03c9826acfa5d04edcc63540ab7
https://github.com/pharo-project/pharo-core/commit/18c33b2573dbb03c9826acfa…
Author: Jenkins Build Server <board(a)pharo-project.org>
Date: 2014-09-24 (Wed, 24 Sep 2014)
Changed paths:
A Collections-Strings.package/String.class/instance/converting/substrings_.st
A ScriptLoader30.package/ScriptLoader.class/instance/pharo - scripts/script120.st
A ScriptLoader30.package/ScriptLoader.class/instance/pharo - updates/update30858.st
M ScriptLoader30.package/ScriptLoader.class/instance/public/commentForCurrentUpdate.st
Log Message:
-----------
30858
14034 add to Pharo3: substrings:
https://pharo.fogbugz.com/f/cases/14034
http://files.pharo.org/image/30/30858.zip
Sept. 24, 2014