|
From: <tim...@en...> - 2007-06-04 09:43:47
|
>> On Saturday 02 June 2007 14:00, Timothée Lecomte wrote:
>>>
>>> So, I conclude that any code executed conditionally to !setjmp(...), if
>>> not changing the stack, could be put before the call to setjmp and give
>>> exactly the same behaviour. In other words:
>>>
>>> if(!setjmp(...))
>>> {
>>> /* setjmp returns direclty */
>>> code_that_does_not_change_the_stack();
>>> }
>>> else
>>> {
>>> /* coming back from longjmp */
>>> }
>>>
>>> is strictly equivalent to:
>>>
>>> code_that_does_not_change_the_stack();
>>> if(setjmp(...))
>>> {
>>> /* coming back from longjmp */
>>> }
>>>
>>> Am I right ?
>>
>> I'm not certain, but I don't think this is correct.
>>
>> For one thing, SETJMP actually translates to sigsetjmp(env,
>> save_signals).
>> So both the stack and the signal state must remain unchanged.
>>
>
> More precisely, it's the signal mask, i.e.signals that we may have chosen
> to block using sigprocmask. There's no such call in interrupt_setup().
>
>
>> For another, consider what happens if there is an error return from
>> the initialization code.
>>
>> Here's the actual code:
>>
>> if (!SETJMP(command_line_env, 1)) {
>> /* first time */
>> interrupt_setup();
>> get_user_env();
>> init_loadpath();
>> ...
>> } else {
>> /* come back here from int_error() */
>>
>> But interrupt_setup() presumably changes the signal-handling state,
>> so it cannot be moved ahead of SETJMP without changing the environment
>> restored after longjmp().
>
> Well, no, it doesn't change the signal _mask_, so it can be moved ahead of
> setjmp.
>
>
>>
>> And if something inside init_loadpath() attempted an error return
>> via longjmp() then you would get an infinite loop if you move the
>> call ahead of SETJMP. I don't think init_loadpath() in fact can
>> trigger this, but it's something you have to worry about in general.
>>
>
> You're right, I missed that part: I have to verify that the calls I move
> are not calling int_error() or bail_to_command_line, which would trigger a
> longjmp.
I've gone through the calls that I was going to move.
The following calls for sure do not call int_error() or
bail_to_command_line():
interrupt_setup()
get_user_env()
init_loadpath()
init_locale()
reset_command()
init_color()
init_fit()
history code including read_history()
I've not gone through the whole reset_command() calls, because it's quite
big, but I am going to assume that it doesn't call int_error(), otherwise
it sounds like a serious coding error ! 'reset' should obviously always
succeed.
There is one offender in these initialization calls that may use
int_error(): it's load_rcfile(). It parses '.gnuplot' (or 'gnuplot.ini',
depending on the platform). Obviously this should only be done once, and I
guess it's a good thing that it doesn't make gnuplot exit if there's an
error in this file.
In order to achieve the cleanup I've looking for, I can move load_rcfile
below in the code, and add a static TBOOLEAN in it so that it only gets
executed once.
Modified patch attached.
Best regards,
Timothée |