[squeak-dev] Re: [Pharo-project] #ensure: issues

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Thu Mar 4 07:37:28 UTC 2010


2010/3/4 Levente Uzonyi <leves at elte.hu>:
> On Thu, 4 Mar 2010, Igor Stasenko wrote:
>
>> 2010/3/4 Levente Uzonyi <leves at elte.hu>:
>>>
>>> On Thu, 4 Mar 2010, Igor Stasenko wrote:
>>>
>>>> On 4 March 2010 01:56, Nicolas Cellier
>>>> <nicolas.cellier.aka.nice at gmail.com> wrote:
>>>>>
>>>>> 2010/3/4 Levente Uzonyi <leves at elte.hu>:
>>>>>>
>>>>>> On Thu, 4 Mar 2010, Nicolas Cellier wrote:
>>>>>>
>>>>>>> 2010/3/3 Levente Uzonyi <leves at elte.hu>:
>>>>>>>>
>>>>>>>> On Wed, 3 Mar 2010, Andreas Raab wrote:
>>>>>>>>
>>>>>>>>> On 3/3/2010 2:07 PM, Levente Uzonyi wrote:
>>>>>>>>>>
>>>>>>>>>> On Wed, 3 Mar 2010, Igor Stasenko wrote:
>>>>>>>>>>>
>>>>>>>>>>> i don't get it. Just before that, you said: ' I'd expect it to be
>>>>>>>>>>> evaluated no matter what happens.' ?
>>>>>>>>>>> But now you saying that it may not be executed in some conditions
>>>>>>>>>>> (when user pressing abandon button, causing process to be
>>>>>>>>>>> terminated).
>>>>>>>>>>
>>>>>>>>>> It's simple: don't terminate process X from another process if
>>>>>>>>>> process
>>>>>>>>>> X
>>>>>>>>>> is executing a termiation block (aka #ensure: block). Or if you
>>>>>>>>>> terminate it, make sure that the execution of the block will
>>>>>>>>>> continue
>>>>>>>>>> somehow (I don't care how).
>>>>>>>>>
>>>>>>>>> You're missing Igors point which is that in his example the halt /
>>>>>>>>> Transcript *was* in the ensure block and as a result you're
>>>>>>>>> contradicting
>>>>>>>>> yourself here. Let's go back to Igor's example:
>>>>>>>>>
>>>>>>>>> [self boom ] ensure: [ self halt. Transcript show: 'boom']
>>>>>>>>>
>>>>>>>>> The halt is inside the ensure block. If you terminate the process
>>>>>>>>> from
>>>>>>>>> the
>>>>>>>>> debugger, it would be logical from your statement that the
>>>>>>>>> Transcript
>>>>>>>>> message would be executed - after all it's " executing a termiation
>>>>>>>>> block
>>>>>>>>> (aka #ensure: block)" and so it can't be terminated by your
>>>>>>>>> reasoning.
>>>>>>>>> However, when Igor was pointing this out you replied with "I didn't
>>>>>>>>> say
>>>>>>>>> that. I said evaluate it the same way as normal code." which is
>>>>>>>>> inconsistent
>>>>>>>>> with the other statement.
>>>>>>>>
>>>>>>>> That shows my lack of knowledge about how the debugger works.
>>>>>>>>
>>>>>>>>>
>>>>>>>>>> I think every user of #ensure: expects that the termination blocks
>>>>>>>>>> are
>>>>>>>>>> executed even if the process which is executing the receiver of
>>>>>>>>>> #ensure:
>>>>>>>>>> is terminated. And it actually happens in all but this case.
>>>>>>>>>
>>>>>>>>> The question of terminating processes is always tricky. I don't
>>>>>>>>> think
>>>>>>>>> that
>>>>>>>>> your proposal would actually work in practice - it could easily
>>>>>>>>> result
>>>>>>>>> in
>>>>>>>>> processes that cannot be terminated due to a simple bug in an
>>>>>>>>> ensure
>>>>>>>>> block.
>>>>>>>>> Personally, I'd rather say that the more useful behavior would be
>>>>>>>>> something
>>>>>>>>> along the lines of saying that process termination either skips the
>>>>>>>>> current
>>>>>>>>> ensure block (assuming there's a bug and it should get the heck out
>>>>>>>>> of
>>>>>>>>> it
>>>>>>>>> but try to evaluate the remaining ones) or that there need to be
>>>>>>>>> two
>>>>>>>>> terminations - one that is 'soft' and won't allow ensure blocks to
>>>>>>>>> be
>>>>>>>>> skipped and one that is 'hard' (kill -9 hard) and just ignores all
>>>>>>>>> the
>>>>>>>>> ensure blocks.
>>>>>>>>
>>>>>>>> I'm only saying that normal usage (aka #terminate) shouldn't do
>>>>>>>> unexpected
>>>>>>>> things like this.
>>>>>>>> If you read the comment of Process >> #terminate, you may assume
>>>>>>>> that
>>>>>>>> #ensure: and #ifCurtailed: blocks will be excuted even if you use
>>>>>>>> #terminate, but that's not true.
>>>>>>>>
>>>>>>>> "Stop the process that the receiver represents forever.  Unwind to
>>>>>>>> execute
>>>>>>>> pending ensure:/ifCurtailed: blocks before terminating."
>>>>>>>>
>>>>>>>>
>>>>>>>> Levente
>>>>>>>>
>>>>>>>
>>>>>>> The only way I see to solve your problem would be to execute the
>>>>>>> unwind block in another process...
>>>>>>> Quite technical and costly !
>>>>>>
>>>>>> It's our problem. Just look at the senders of #ensure: and imagine
>>>>>> what
>>>>>> will
>>>>>> happen if the termination block is not evaluated.
>>>>>> I think there's another way (though it might be my lack of knowledge
>>>>>> again).
>>>>>> After suspending the process which is about to be terminated we can
>>>>>> check if
>>>>>> it's executing a termination block. It it's not, we are safe to
>>>>>> continue
>>>>>> the
>>>>>> termination, otherwise we can do something else which ensures that the
>>>>>> termination block is evaluated.
>>>>>>
>>>>>
>>>>> Maybe...
>>>>> Unfortunately, you did not tell how you will distinguish well behaved
>>>>> unwind-blocks from Igor's example...
>>>>>
>>>>
>>>> Yes, then what prevents me from writing:
>>>>
>>>> [ [ ] ensure: [ self doCrazyThings ] ] fork.
>>>
>>> What prevents you from writing: Object superclass: Object. ?
>>> Nothing, but you don't do that, do you?
>>>
>> So, why at all, you care about using #ensure: then? If you putting
>> everything up to the hands of developer,
>> then obviously you won't need to use this message, because you always
>> know that you're running a reliable code which
>> will always let you to run your things in the end. :)
>>
>>>>
>>>> and now given assumption that any code which placed inside ensure
>>>> block should always run to the end, without chances being terminated,
>>>> will have ill side effects.
>>>
>>> You can terminate it (maybe not the usual way).
>>>
>> that's the point. Why do we need two (or more) ways to terminate a
>> process?
>>
>>>> The #ensure: means, that interpreter will have a chance to enter that
>>>> block eventually, but it should not mean that it will keep running the
>>>> code there until normal or non-local return from that block.
>>>
>>> Then it doesn't ensure anything at all, so it should be called
>>> #tryToEvaluateThisToo:.
>>>
>> in fact, this is the actual behavior :)
>> If i press the power button on your PC, or plug out the power cord,
>> any #ensure: blocks will have no chances to run either way.
>> So, relying on something, which is not reliable is a fallacy :)
>
> Here's a simple example (replace file with any external resource):
> My process opened a file, a termination block will close it if it's
> evaluated. If I send #terminate to the process I expect my file to be
> closed, so I won't leak a file descriptor.
> If the file can't be closed (aka the termination block raised an error) then
> there's a serious problem. It doesn't really matter what happens then.
>
> But I don't have to try to convince you anymore, because Andreas is about to
> solve the issue.
>

Could you use this workaround :

myProcess :=
    [[file := myFile open.
    self doSomething.
    file close] ifCurtailed:: [file close]]
        newProcess.
myProcess fork.

The main danger then is if you send  myProcess terminate while
doSomething triggered an Error.
This is still possible but reduces the level of probability.

Nicolas

>
> Levente
>
>>
>>>
>>> Levente
>>>
>>>> Othewise, you losing a way to terminate unwanted, ill-behaved process.
>>>>
>>>>> Nicolas
>>>>>
>>>>>>
>>>>>> Levente
>>>>>>
>>>>>>>
>>>>>>> Nicolas
>>>>>>>
>>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>>  - Andreas
>>>>>>>>>
>>>>
>>>> --
>>>> Best regards,
>>>> Igor Stasenko AKA sig.
>>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>> --
>> Best regards,
>> Igor Stasenko AKA sig.
>>
>
>
>
>



More information about the Squeak-dev mailing list