Mailing List Archive

G_KEEPERR status?
What is the current status if the G_KEEPERR flag?

If it has been finalised and is going to make it into 5.002, I would
quite like to include it in perlcall.pod.

Can you tell I'm in a "get things tidied up for 5.002" mode today? :-)

Paul
Re: G_KEEPERR status? [ In reply to ]
On Wed, 11 Oct 1995 17:38:01 -0000, Paul Marquess wrote:
>What is the current status if the G_KEEPERR flag?
>
>If it has been finalised and is going to make it into 5.002, I would
>quite like to include it in perlcall.pod.
>
>Can you tell I'm in a "get things tidied up for 5.002" mode today? :-)
>
>Paul
>

This is my pumpkin (slightly stale, because I haven't revisited this for
some time, I'm afraid).

I cleaned up the tentative patch I sent for it, and then decided the
problem is thornier than it seems. With the patch I currently have,
the G_KEEPERR flag induces appending to $@ rather than overwriting it,
but this doesn't work all that well with DESTROY because the main
error message might get pushed behind. Consider this:

package Demo;
sub new { bless {}}
sub DESTROY { die "fuz" }
sub foo {
my($self) = @_;
$self = $self->new() unless (ref $self);
my(@other) = (); # 1
for (1..2) { push @other, $self->new(); } # 2
my($a1) = $self->new(); # 3
my($a2) = $self->new(); # 4
die "foo";
}
package main;
eval { @a = Demo->foo() };
print $@ if $@;
__END__
fuz at - line 3.
(also) fuz at - line 3.
(also) foo at - line 11.
(also) fuz at - line 3.
(also) fuz at - line 3.
(also) fuz at - line 3.

That's the result from applying the patch appended. [.Tim and Tye will
notice, I didn't put in any code to check for duplicates with a %@ hash yet
:-(] I don't like the above behavior a whole lot because it simply rolls all
the error messages in the sequence they were received, and ends up with the
errors in a less useful order in many situations. This is unavoidable even
if the duplicates are removed, because the code inside the G_KEEPERR call
has no way to find out it is inside a G_KEEPERR call.

Ideally I would like control over background errors--errors generated from
from perl code execution that the user has no control over (where it gets
executed, I mean), like DESTROYs, and turn the display of such errors on or
off, or even display them differently with indentation/prefix etc.


BOTTOM-LINE:

We need the 'flags' argument to perl_call_sv() to become part of the execution
context. I am not sure where exactly this should be added, though.

This patch is better than not having the functionality at all, but I am
not too proud of the result.

- Sarathy.
gsar@engin.umich.edu
---------------------------------------8<-------------------------------------
*** perl.c.dist Thu Jun 22 18:38:28 1995
--- perl.c Tue Sep 5 21:46:14 1995
***************
*** 671,677 ****

cLOGOP->op_other = op;
markstack_ptr--;
! pp_entertry();
markstack_ptr++;

restart:
--- 671,693 ----

cLOGOP->op_other = op;
markstack_ptr--;
! /* we're trying to emulate pp_entertry() here */
! {
! register CONTEXT *cx;
! I32 gimme = GIMME;
!
! ENTER;
! SAVETMPS;
!
! push_return(op->op_next);
! PUSHBLOCK(cx, CXt_EVAL, stack_sp);
! PUSHEVAL(cx, 0, 0);
! eval_root = op; /* Only needed so that goto works right. */
!
! in_eval = 1;
! if (!(flags & G_KEEPERR))
! sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");
! }
markstack_ptr++;

restart:
***************
*** 716,722 ****
if (op)
run();
retval = stack_sp - (stack_base + oldmark);
! if (flags & G_EVAL)
sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");

cleanup:
--- 732,738 ----
if (op)
run();
retval = stack_sp - (stack_base + oldmark);
! if ((flags & G_EVAL) && !(flags & G_KEEPERR))
sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");

cleanup:
*** sv.c.dist Tue Sep 5 21:54:45 1995
--- sv.c Tue Sep 5 18:55:15 1995
***************
*** 2123,2129 ****
PUSHMARK(SP);
PUSHs(&ref);
PUTBACK;
! perl_call_sv((SV*)destructor, G_DISCARD|G_EVAL);
del_XRV(SvANY(&ref));
}
LEAVE;
--- 2129,2135 ----
PUSHMARK(SP);
PUSHs(&ref);
PUTBACK;
! perl_call_sv((SV*)destructor, G_DISCARD|G_EVAL|G_KEEPERR);
del_XRV(SvANY(&ref));
}
LEAVE;
*** pp_ctl.c.dist Tue Sep 5 21:52:09 1995
--- pp_ctl.c Wed Sep 13 21:09:30 1995
***************
*** 946,952 ****

errsv = GvSV(gv_fetchpv("@",TRUE, SVt_PV));
/* As destructors may produce errors we set $@ at the last moment */
- sv_setpv(errsv, ""); /* clear $@ before destroying */

cxix = dopoptoeval(cxstack_ix);
if (cxix >= 0) {
--- 946,951 ----
***************
*** 968,974 ****

LEAVE;

! sv_insert(errsv, 0, 0, message, strlen(message));
if (optype == OP_REQUIRE)
DIE("%s", SvPVx(GvSV(gv_fetchpv("@",TRUE, SVt_PV)), na));
return pop_return();
--- 967,980 ----

LEAVE;

! if (SvTRUE(errsv)) {
! SV *tmpstr = newSVpv("\t(also) ", 0);
! sv_catpv(tmpstr, message);
! sv_catsv(errsv, tmpstr);
! SvREFCNT_dec(tmpstr);
! }
! else
! sv_insert(errsv, 0, 0, message, strlen(message));
if (optype == OP_REQUIRE)
DIE("%s", SvPVx(GvSV(gv_fetchpv("@",TRUE, SVt_PV)), na));
return pop_return();
*** cop.h.dist Sun Mar 12 22:25:47 1995
--- cop.h Tue Sep 5 18:14:17 1995
***************
*** 231,233 ****
--- 231,234 ----
#define G_DISCARD 2 /* Call FREETMPS. */
#define G_EVAL 4 /* Assume eval {} around subroutine call. */
#define G_NOARGS 8 /* Don't construct a @_ array. */
+ #define G_KEEPERR 16 /* Append errors to $@ rather than overwriting it */
Re: G_KEEPERR status? [ In reply to ]
On Wed, 11 Oct 1995 17:38:01 -0000, Paul Marquess wrote:
>What is the current status if the G_KEEPERR flag?
>
>If it has been finalised and is going to make it into 5.002, I would
>quite like to include it in perlcall.pod.
>
>Can you tell I'm in a "get things tidied up for 5.002" mode today? :-)
>
>Paul
>

This is my pumpkin (slightly stale, because I haven't revisited this for
some time, I'm afraid).

I cleaned up the tentative patch I sent for it, and then decided the
problem is thornier than it seems. With the patch I currently have,
the G_KEEPERR flag induces appending to $@ rather than overwriting it,
but this doesn't work all that well with DESTROY because the main
error message might get pushed behind. Consider this:

package Demo;
sub new { bless {}}
sub DESTROY { die "fuz" }
sub foo {
my($self) = @_;
$self = $self->new() unless (ref $self);
my(@other) = (); # 1
for (1..2) { push @other, $self->new(); } # 2
my($a1) = $self->new(); # 3
my($a2) = $self->new(); # 4
die "foo";
}
package main;
eval { @a = Demo->foo() };
print $@ if $@;
__END__
fuz at - line 3.
(also) fuz at - line 3.
(also) foo at - line 11.
(also) fuz at - line 3.
(also) fuz at - line 3.
(also) fuz at - line 3.

That's the result from applying the patch appended. [.Tim and Tye will
notice, I didn't put in any code to check for duplicates with a %@ hash yet
:-(] I don't like the above behavior a whole lot because it simply rolls all
the error messages in the sequence they were received, and ends up with the
errors in a less useful order in many situations. This is unavoidable even
if the duplicates are removed, because the code inside the G_KEEPERR call
has no way to find out it is inside a G_KEEPERR call.

Ideally I would like control over background errors--errors generated from
from perl code execution that the user has no control over (where it gets
executed, I mean), like DESTROYs, and turn the display of such errors on or
off, or even display them differently with indentation/prefix etc.


BOTTOM-LINE:

We need the 'flags' argument to perl_call_sv() to become part of the execution
context. I am not sure where exactly this should be added, though.

This patch is better than not having the functionality at all, but I am
not too proud of the result.

- Sarathy.
gsar@engin.umich.edu
---------------------------------------8<-------------------------------------
*** perl.c.dist Thu Jun 22 18:38:28 1995
--- perl.c Tue Sep 5 21:46:14 1995
***************
*** 671,677 ****

cLOGOP->op_other = op;
markstack_ptr--;
! pp_entertry();
markstack_ptr++;

restart:
--- 671,693 ----

cLOGOP->op_other = op;
markstack_ptr--;
! /* we're trying to emulate pp_entertry() here */
! {
! register CONTEXT *cx;
! I32 gimme = GIMME;
!
! ENTER;
! SAVETMPS;
!
! push_return(op->op_next);
! PUSHBLOCK(cx, CXt_EVAL, stack_sp);
! PUSHEVAL(cx, 0, 0);
! eval_root = op; /* Only needed so that goto works right. */
!
! in_eval = 1;
! if (!(flags & G_KEEPERR))
! sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");
! }
markstack_ptr++;

restart:
***************
*** 716,722 ****
if (op)
run();
retval = stack_sp - (stack_base + oldmark);
! if (flags & G_EVAL)
sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");

cleanup:
--- 732,738 ----
if (op)
run();
retval = stack_sp - (stack_base + oldmark);
! if ((flags & G_EVAL) && !(flags & G_KEEPERR))
sv_setpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),"");

cleanup:
*** sv.c.dist Tue Sep 5 21:54:45 1995
--- sv.c Tue Sep 5 18:55:15 1995
***************
*** 2123,2129 ****
PUSHMARK(SP);
PUSHs(&ref);
PUTBACK;
! perl_call_sv((SV*)destructor, G_DISCARD|G_EVAL);
del_XRV(SvANY(&ref));
}
LEAVE;
--- 2129,2135 ----
PUSHMARK(SP);
PUSHs(&ref);
PUTBACK;
! perl_call_sv((SV*)destructor, G_DISCARD|G_EVAL|G_KEEPERR);
del_XRV(SvANY(&ref));
}
LEAVE;
*** pp_ctl.c.dist Tue Sep 5 21:52:09 1995
--- pp_ctl.c Wed Sep 13 21:09:30 1995
***************
*** 946,952 ****

errsv = GvSV(gv_fetchpv("@",TRUE, SVt_PV));
/* As destructors may produce errors we set $@ at the last moment */
- sv_setpv(errsv, ""); /* clear $@ before destroying */

cxix = dopoptoeval(cxstack_ix);
if (cxix >= 0) {
--- 946,951 ----
***************
*** 968,974 ****

LEAVE;

! sv_insert(errsv, 0, 0, message, strlen(message));
if (optype == OP_REQUIRE)
DIE("%s", SvPVx(GvSV(gv_fetchpv("@",TRUE, SVt_PV)), na));
return pop_return();
--- 967,980 ----

LEAVE;

! if (SvTRUE(errsv)) {
! SV *tmpstr = newSVpv("\t(also) ", 0);
! sv_catpv(tmpstr, message);
! sv_catsv(errsv, tmpstr);
! SvREFCNT_dec(tmpstr);
! }
! else
! sv_insert(errsv, 0, 0, message, strlen(message));
if (optype == OP_REQUIRE)
DIE("%s", SvPVx(GvSV(gv_fetchpv("@",TRUE, SVt_PV)), na));
return pop_return();
*** cop.h.dist Sun Mar 12 22:25:47 1995
--- cop.h Tue Sep 5 18:14:17 1995
***************
*** 231,233 ****
--- 231,234 ----
#define G_DISCARD 2 /* Call FREETMPS. */
#define G_EVAL 4 /* Assume eval {} around subroutine call. */
#define G_NOARGS 8 /* Don't construct a @_ array. */
+ #define G_KEEPERR 16 /* Append errors to $@ rather than overwriting it */
Re: G_KEEPERR status? [ In reply to ]
From: Gurusamy Sarathy <gsar@engin.umich.edu>
>
> On Wed, 11 Oct 1995 17:38:01 -0000, Paul Marquess wrote:
> >What is the current status if the G_KEEPERR flag?
> >
> >If it has been finalised and is going to make it into 5.002, I would
> >quite like to include it in perlcall.pod.
> >
> >Can you tell I'm in a "get things tidied up for 5.002" mode today? :-)
> >
> >Paul
> >
>
> This is my pumpkin (slightly stale, because I haven't revisited this for
> some time, I'm afraid).
...
> BOTTOM-LINE:
>
> We need the 'flags' argument to perl_call_sv() to become part of the execution
> context. I am not sure where exactly this should be added, though.
>
> This patch is better than not having the functionality at all, but I am
> not too proud of the result.

I guess you are saying that G_KEEPERR isn't finalised.

In that case I'll not do anything with perlcall.pod for now.

Paul
Re: G_KEEPERR status? [ In reply to ]
> From: Gurusamy Sarathy <gsar@engin.umich.edu>
>
> Paul Marquess wrote:
> >What is the current status if the G_KEEPERR flag?
>
> I cleaned up the tentative patch I sent for it, and then decided the
> problem is thornier than it seems. With the patch I currently have,
> the G_KEEPERR flag induces appending to $@ rather than overwriting it,
> but this doesn't work all that well with DESTROY because the main
> error message might get pushed behind.

> Tim and Tye will notice, I didn't put in any code to check for duplicates
> with a %@ hash yet :-(

> BOTTOM-LINE:
>
> We need the 'flags' argument to perl_call_sv() to become part of the execution
> context. I am not sure where exactly this should be added, though.
>
> This patch is better than not having the functionality at all, but I am
> not too proud of the result.

The key point being "better than not having the functionality at all".
I'd like to see this (with the removal of duplicates) in Perl5.002.
It is important for debuging object code.

Any chance you could add in the removal of duplicates and repost it?

Tim.

p.s. Can't you simply get the text from the original die into $@ earlier?
Re: G_KEEPERR status? [ In reply to ]
On Sat, 14 Oct 1995 00:15:02 BST, Tim Bunce wrote:
>
>> From: Gurusamy Sarathy <gsar@engin.umich.edu>
>>
>> This patch is better than not having the functionality at all, but I am
>> not too proud of the result.
>
>The key point being "better than not having the functionality at all".
>I'd like to see this (with the removal of duplicates) in Perl5.002.
>It is important for debuging object code.
>
>Any chance you could add in the removal of duplicates and repost it?
>

If you think this is OK for 5.002, I guess I will, sometime monday.

>Tim.
>
>p.s. Can't you simply get the text from the original die into $@ earlier?
>

The problem is making out which is the original perl die() inside the
pp_die() and its support code. There's no way now for pp_die() to tell
if it is being called from inside a G_KEEPERR call. A simple way to
get around this would be to use a global flag (like in_eval). Perhaps
that's what I will do.

- Sarathy.
gsar@engin.umich.edu
Re: G_KEEPERR status? [ In reply to ]
> From: Gurusamy Sarathy <gsar@engin.umich.edu>
>
> On Sat, 14 Oct 1995 00:15:02 BST, Tim Bunce wrote:
> >
> >> From: Gurusamy Sarathy <gsar@engin.umich.edu>
> >>
> >> This patch is better than not having the functionality at all, but I am
> >> not too proud of the result.
> >
> >The key point being "better than not having the functionality at all".
> >I'd like to see this (with the removal of duplicates) in Perl5.002.
> >It is important for debuging object code.
> >
> >Any chance you could add in the removal of duplicates and repost it?
>
> If you think this is OK for 5.002, I guess I will, sometime monday.

I think so. Obviously Larry will have the last word.

> >p.s. Can't you simply get the text from the original die into $@ earlier?
>
> The problem is making out which is the original perl die() inside the
> pp_die() and its support code. There's no way now for pp_die() to tell
> if it is being called from inside a G_KEEPERR call. A simple way to
> get around this would be to use a global flag (like in_eval). Perhaps
> that's what I will do.

I don't think you'll need to. I'll try to explain what I meant.
I've not actually tried this and you may have already been down
this road....

Here's a cut down version of die_where:

die_where(message)
char *message;
{
if (in_eval) {
I32 cxix;
SV *errsv;

errsv = GvSV(gv_fetchpv("@",TRUE, SVt_PV));

/* As destructors may produce errors we set $@ at the last moment */
A: sv_setpv(errsv, ""); /* clear $@ before destroying */

cxix = dopoptoeval(cxstack_ix);
if (cxix >= 0) {
if (cxix < cxstack_ix)
B: dounwind(cxix);
B: POPBLOCK(cx,curpm);
B: POPEVAL(cx);
B: LEAVE;

C: sv_insert(errsv, 0, 0, message, strlen(message));

A long time ago errsv used to be set at point A. This meant that any die's
which occurred through point B (via object destruction) overwrote errsv.

A (not quite so) long time ago I wrote a patch which changed the
behaviour to what it is now. Effectively the messages from nested
die's are stored in char *message on the C stack as die_where gets
reentered from point B. When it unwinds the sv_insert's take effect.

It fixed the immediate problem but was not ideal. (I think at the time
DESTROY was not implemented via perl_call_sv(..., G_EVAL)).

I suspect that now with the advent of G_KEEPERR you could simply delete
the sv_insert at C and change the sv_setpv at A to be sv_cat.
Hence my comment 'get the text from the original die into $@ earlier'
(e.g., before the objects get destroyed and mess with your control flow).

On the other hand I may be wrong :-)

Tim.

p.s. Are we agreed that using GvHV("@") as a hash to avoid duplicates
avoids the need to display the errors in reverse order? I hope so.

p.p.s. Larry, would you be happy if Gurusamy's patch created an errgv
'global' to avoid all the wasteful gv_fetchpv("@")'s ?
I count 12, many in places where efficiency is important.
Re: G_KEEPERR status? [ In reply to ]
: p.p.s. Larry, would you be happy if Gurusamy's patch created an errgv
: 'global' to avoid all the wasteful gv_fetchpv("@")'s ?
: I count 12, many in places where efficiency is important.

Okay by me.

Larry
Re: G_KEEPERR status? [ In reply to ]
On Sun, 15 Oct 1995 19:31:28 BST, Tim Bunce wrote:
>
>Here's a cut down version of die_where:
>
>die_where(message)
>char *message;
>{
> if (in_eval) {
> I32 cxix;
> SV *errsv;
>
> errsv = GvSV(gv_fetchpv("@",TRUE, SVt_PV));
>
> /* As destructors may produce errors we set $@ at the last moment */
>A: sv_setpv(errsv, ""); /* clear $@ before destroying */
>
> cxix = dopoptoeval(cxstack_ix);
> if (cxix >= 0) {
> if (cxix < cxstack_ix)
>B: dounwind(cxix);
>B: POPBLOCK(cx,curpm);
>B: POPEVAL(cx);
>B: LEAVE;
>
>C: sv_insert(errsv, 0, 0, message, strlen(message));
>
[...]
>
>I suspect that now with the advent of G_KEEPERR you could simply delete
>the sv_insert at C and change the sv_setpv at A to be sv_cat.
>Hence my comment 'get the text from the original die into $@ earlier'
>(e.g., before the objects get destroyed and mess with your control flow).
>
>On the other hand I may be wrong :-)

Thanks for taking the time to illuminate all this, Tim. I had considered
this as a possibility before, but there is still no way to _treat_ the
G_KEEPERR error message differently (like prepending a special string to it
etc). The other possibility I had in mind was to use the additional bits in
in_eval to store G_KEEPERR status (yyerror() already uses one more bit). I
think that might give us the cleanest way for inner code to check call
context and do other things to the error message. So, I think I will add
both (your suggestion because it is the cleanest way to handle die_where())
tonight, most likely.

[.NOTE: In all of my examples much destruction also happens in the FREETMPS
call back in perl_call_sv() when die() longjmps into it (i.e. not
necessarily at point B). This was the reason why the above code was broken
in the first place.]

>
>p.s. Are we agreed that using GvHV("@") as a hash to avoid duplicates
> avoids the need to display the errors in reverse order? I hope so.

Yes, I am sticking to keeping the order straight.

>
>p.p.s. Larry, would you be happy if Gurusamy's patch created an errgv
> 'global' to avoid all the wasteful gv_fetchpv("@")'s ?
> I count 12, many in places where efficiency is important.
>

This was already done in my copy. In summary, yes, I think I have a handle
on how to go about fixing it, but I need to find those couple of hours :-)

- Sarathy.
gsar@engin.umich.edu
Re: G_KEEPERR status? [ In reply to ]
> From: Gurusamy Sarathy <gsar@engin.umich.edu>
>
> On Sun, 15 Oct 1995 19:31:28 BST, Tim Bunce wrote:
> >
> >Here's a cut down version of die_where:
> >
> >die_where(message)
> >char *message;
> >{
> > if (in_eval) {
> > I32 cxix;
> > SV *errsv;
> >
> > errsv = GvSV(gv_fetchpv("@",TRUE, SVt_PV));
> >
> > /* As destructors may produce errors we set $@ at the last moment */
> >A: sv_setpv(errsv, ""); /* clear $@ before destroying */
> >
> > cxix = dopoptoeval(cxstack_ix);
> > if (cxix >= 0) {
> > if (cxix < cxstack_ix)
> >B: dounwind(cxix);
> >B: POPBLOCK(cx,curpm);
> >B: POPEVAL(cx);
> >B: LEAVE;
> >
> >C: sv_insert(errsv, 0, 0, message, strlen(message));
> >
> [...]
> >
> >I suspect that now with the advent of G_KEEPERR you could simply delete
> >the sv_insert at C and change the sv_setpv at A to be sv_cat.
> >Hence my comment 'get the text from the original die into $@ earlier'
> >(e.g., before the objects get destroyed and mess with your control flow).
> >
> >On the other hand I may be wrong :-)
>
> Thanks for taking the time to illuminate all this, Tim. I had considered
> this as a possibility before, but there is still no way to _treat_ the
> G_KEEPERR error message differently (like prepending a special string to it etc).

Just sv_catpv the special string ("\talso ") to errsv before sv_cat'ing message
if SvTRUE(errsv).

> The other possibility I had in mind was to use the additional bits in
> in_eval to store G_KEEPERR status (yyerror() already uses one more bit).

I don't see a _need_ to store it.

> I think that might give us the cleanest way for inner code to check call
> context and do other things to the error message.

The (DESTROY etc) code can check and manipulate $@ since it now gets
updated early.

> So, I think I will add
> both (your suggestion because it is the cleanest way to handle die_where())
> tonight, most likely.
>
> [.NOTE: In all of my examples much destruction also happens in the FREETMPS
> call back in perl_call_sv() when die() longjmps into it (i.e. not
> necessarily at point B). This was the reason why the above code was broken
> in the first place.]

Ah. Okay.

> >p.s. Are we agreed that using GvHV("@") as a hash to avoid duplicates
> > avoids the need to display the errors in reverse order? I hope so.
>
> Yes, I am sticking to keeping the order straight.

Great.

> >p.p.s. Larry, would you be happy if Gurusamy's patch created an errgv
> > 'global' to avoid all the wasteful gv_fetchpv("@")'s ?
> > I count 12, many in places where efficiency is important.
> >
>
> This was already done in my copy. In summary, yes, I think I have a handle
> on how to go about fixing it, but I need to find those couple of hours :-)

Wonderful. Thanks.

Tim.