> Marcus Holland-Moritz <mhx-...@gmx.net> writes:
> >> Core perl uses magic macro to set errno
> >> which IIRC does back convert to native error code
> >> on VMS and Win32 ?
> >
> >Yes, but there's no way (that I could see) to set the PV slot
> >in $! to a user-defined string. You can assign any number to
> >$!, but that's almost useless:
> >
> > mhx@r2d2 ~ $ perl -e '$!=4711;print"$!\n"'
> > Unknown error 4711
> >
> >Furthermore, the whole concept of Errno and %! wouldn't work.
>
> So you have to set errno to one of the known values,
> and have a resonable idea what message you get.
Exactly. :)
> So:
> EINVAL
> EBADF
> EAGAIN
> EWOULDBLOCK
>
> yeild fairly generic messages.
> Linux has a lot of exotic ones but they ain't portable.
You could probably check which keys are in %! at Makefile.PL time,
and use more specific messages where available. But I don't think
that would help very much.
--
Digital circuits are made from analog parts.
-- Don Vonada
So what we are supposed to do if we want to keep the idimatic perl working?
Consider:
open my $fh, "</tmp/bar" or die "$!";
now if I want to implement a perlio layer, I want this to work just the same:
open my $fh, "<:mylayer" or die "$!";
How do I set $! then? perlio doesn't provide a framework to set $!, just
return codes.
At the moment the only option is to croak. But that totally breaks idiomatic
perl, making the API kludgy as you need to eval {} every statement if you want
to trap the error yourself.
Or is introducing a new $! variable like DBI::errstr a better way? It works
for DBI since it provides a new API. Whereas with perlio the API doesn't
change from the core API, but error handling is totally different.
can't we attach a different magic to $!, which will override ERRNO magic, if
the former exists?
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:st...@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
Just set errno on failure, and indicate the failure through the return code.
> At the moment the only option is to croak. But that totally breaks idiomatic
> perl, making the API kludgy as you need to eval {} every statement if you want
> to trap the error yourself.
No, croaking is not the only option. Each of the functions that define a
PerlIO layer have return codes that indicate failure (see perldoc perlio).
If you use the SETERRNO macro before returning with the failure code, your
$! will be properly set. (That, I guess, is the theory; I haven't implemented
a PerlIO layer myself yet.)
> Or is introducing a new $! variable like DBI::errstr a better way? It works
> for DBI since it provides a new API. Whereas with perlio the API doesn't
> change from the core API, but error handling is totally different.
I guess that you can handle PerlIO layers quite good with errno.
If you have an API where the exising error codes are not sufficient,
you can choose between croaking and introducing your own error variable.
> can't we attach a different magic to $!, which will override ERRNO magic, if
> the former exists?
Then you would also have to provide an interface to register your
error codes with Errno and %!, for consistency.
--
Zoidberg: So many memories, so many strange fluids gushing out
of patients' bodies....
Yes, but my error messages have nothing in common with the common errno set.
Remember that perlio layer may not work with files or OS at all. And seeting
EGENERIC has little help for the user.
>>Or is introducing a new $! variable like DBI::errstr a better way? It works
>>for DBI since it provides a new API. Whereas with perlio the API doesn't
>>change from the core API, but error handling is totally different.
>
>
> I guess that you can handle PerlIO layers quite good with errno.
> If you have an API where the exising error codes are not sufficient,
> you can choose between croaking and introducing your own error variable.
that's exactly where I'm now. And any of these solutions suck as they break
the API users are familiar with, suddenly making the familiar
open/read/print/close API behave incorrectly.
Most people will continue writing:
open my $fh, "<:mylayer" or die "$!";
and if I choose to use my own error variable, it won't be used. So the croak
seems to be the safest solution, but it makes the code kludgy.
>>can't we attach a different magic to $!, which will override ERRNO magic, if
>>the former exists?
>
>
> Then you would also have to provide an interface to register your
> error codes with Errno and %!, for consistency.
Me? that's why I ask perl to give me that interface and I'll supply the error
messages.
I hope others can see that there is a clear problem with the perl core with
regard to perlio layers and error handling, and not really *my* specific problem.
[...]
> > Then you would also have to provide an interface to register your
> > error codes with Errno and %!, for consistency.
>
> Me? that's why I ask perl to give me that interface and I'll supply the error
> messages.
Not specifically you ;-)
The "you" was mainly me thinking that this has to be done "somehow"
by "someone".
> I hope others can see that there is a clear problem with the perl core with
> regard to perlio layers and error handling, and not really *my* specific problem.
Of course, this is a general problem - not only yours - and needs a
general solution, if any.
--
pension:
A federally insured chain letter.
But presumably you also want
unless (open my $fh, "<:mylayer")
{
if ($! == EPERM)
{
}
}
to work as well. So $! should be an errno.
>
>How do I set $! then? perlio doesn't provide a framework to set $!, just
>return codes.
It doesn't need to. $! is just errno and there are already Perl API
macros for setting errno.
e.g. (from perlio.c)
/* Call the callback or fail, and return failure. */
#define Perl_PerlIO_or_fail(f, callback, failure, args) \
if (PerlIOValid(f)) { \
PerlIO_funcs *tab = PerlIOBase(f)->tab; \
if (tab && tab->callback) \
return (*tab->callback) args; \
SETERRNO(EINVAL, LIB_INVARG); \
} \
else \
SETERRNO(EBADF, SS_IVCHAN); \
return failure
>
>At the moment the only option is to croak.
No you can like any other IO library code set errno.
>But that totally breaks idiomatic
>perl, making the API kludgy as you need to eval {} every statement if you want
>to trap the error yourself.
>
>Or is introducing a new $! variable like DBI::errstr a better way? It works
>for DBI since it provides a new API. Whereas with perlio the API doesn't
>change from the core API, but error handling is totally different.
>
>can't we attach a different magic to $!, which will override ERRNO magic, if
>the former exists?
But idiomatic perl assumes $! is errno.
Obviously I didn't suggest to take errno away, I've suggested to optionaly
hang MORE magic to it. And if that extra magic is found to be used instead of
the errno one.
>>How do I set $! then? perlio doesn't provide a framework to set $!, just
>>return codes.
>
>
> It doesn't need to. $! is just errno and there are already Perl API
> macros for setting errno.
>
> e.g. (from perlio.c)
>
> /* Call the callback or fail, and return failure. */
> #define Perl_PerlIO_or_fail(f, callback, failure, args) \
> if (PerlIOValid(f)) { \
> PerlIO_funcs *tab = PerlIOBase(f)->tab; \
> if (tab && tab->callback) \
> return (*tab->callback) args; \
> SETERRNO(EINVAL, LIB_INVARG); \
> } \
> else \
> SETERRNO(EBADF, SS_IVCHAN); \
> return failure
and where exactly do I set my custom error message in this setup?
>>At the moment the only option is to croak.
>
>
> No you can like any other IO library code set errno.
See above
>>But that totally breaks idiomatic
>>perl, making the API kludgy as you need to eval {} every statement if you want
>>to trap the error yourself.
>>
>>Or is introducing a new $! variable like DBI::errstr a better way? It works
>>for DBI since it provides a new API. Whereas with perlio the API doesn't
>>change from the core API, but error handling is totally different.
>>
>>can't we attach a different magic to $!, which will override ERRNO magic, if
>>the former exists?
>
> But idiomatic perl assumes $! is errno.
I'm talking about the stringified version of idiomatic $! usage, which is used
in 99.999% cases in the code that I've seen.
I think you are better off just setting errno to the closest match (but
trying to keep to the normal set of errors a given function would return)
and *also* setting a separate error variable. And document it.
$! _IS_ errno. You get those _numbers_. Perl then stringifies it for you.
Even if you could set the string it would not be compatible
with legacy code which does numeric comparison or uses %!
>
>I hope others can see that there is a clear problem with the perl core with
>regard to perlio layers and error handling, and not really *my* specific problem.
I can see there is a problem with using errno values for error reporting
from libraries. But that isn't really *perl's* specific problem ;-)
That said Win32 manages to map its errors to the "common" set most
of the time, so I think there will be an errno for most IO-oid errors.
What would be the possible closest match in case of the :Apache perlio layer,
which may fail to read() and the error would be: "failed to read because of
the currupted bucket brigade" or similar.
> (but
> trying to keep to the normal set of errors a given function would return)
> and *also* setting a separate error variable. And document it.
I think that practice could be misleading and impractical. What's the point of
setting an error code that doesn't match the real error. A separate error
variable, similar to $DBI::errstr seems to be the only option so far, but once
people will try to write:
read $fh, my $foo, 10 or die "$newerr";
and they will write this a lot, they will try to write that when not using my
perlio layer.
Besides there could be code that should be given a filehandle and it should
read off it, regardless the layers used inside. How will it know to use $! or
$newerr? what if this is a generic library?
That's why I've chosen perlio to demonstrate the problem.
no, but perl has magic! Since $! knows to call strerror when $! is
stringified, why can't we attach extra magic which can contain a pv with a
custom error or a CV to be called on stringification. So by default that
callback can call strerror(), but a user could override it. Of course every
time perl sets $! it should wipe away any overriden magic.
Do I talk nonsense?
I am not sure that it's such a good idea to have custom messages
in $!. It decouples errno and strerror(). Most people (me at least) are
expecting to see the operating system's error string.
After all, there is always the opportunity to create one's own
PVIV with errno in the IV slot and any message so desired in PV.
Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
FWIW I agree with this.
> After all, there is always the opportunity to create one's own
> PVIV with errno in the IV slot and any message so desired in PV.
You can even use Scalar::Util::dualvar() for this purpose.
Depending what that means one of these might suit:
#define ENOSR 63 /* Out of streams resources */
#define EILSEQ 84 /* Illegal byte sequence */
#define EPROTO 71 /* Protocol error */
#define ENODATA 61 /* No data available */
But NORMALY perl does NOT set error (aka $!) libc does.
How do we arrange for readdir() to clear the magic on $!?
e.g. do a read on one of your layers it sets magical $! to "bucket empty"
Notice fail, fallback to some other scheme which uses readdir()
readdir fails and sets errno
User looks at $! ans sees YOUR magic as OS has no way of changing that.
One way I can see to fix this would be to clear magic every time you make
a system call (or called C/XS code which might make a system call).
A better scheme might be to set errno to -1 (say) which means look
in something else ( _perhaps_ $^E could be reused, but we probably
need yet another special variable for "library supplied error message.
>
>Do I talk nonsense?
I think so, but try
thanks Nick, I didn't know that it wasn't perl who was setting $!.
> A better scheme might be to set errno to -1 (say) which means look
> in something else ( _perhaps_ $^E could be reused, but we probably
> need yet another special variable for "library supplied error message.
Aha. So let's say we keep the $! stringification code to call strerror if
errno != -1. But if it is -1, to expect PV being set already? What happens if
I just set errno to -1, set PV to my custom message and set PVOK. Will it
still call strerror, without looking at the cached value? If it does, can we
change the behavior not call strerror but to use whatever is in the PV slot if
errno == -1?
>>[...] but once
>>people will try to write:
>>
>> read $fh, my $foo, 10 or die "$newerr";
>>
>>and they will write this a lot, they will try to write that when not using my
>>perlio layer.
>>
>>Besides there could be code that should be given a filehandle and it should
>>read off it, regardless the layers used inside. How will it know to use $! or
>>$newerr? what if this is a generic library?
>>
>>
sub newerr::FETCH{ $newerr // "$!" // $@ } # but do this in XS of
course
--
david...@pay2send.com.
Include phrase "cat and buttered toast" to get through my filter
I don't think you'll be able to use the PV slot of a magic variable.
The right way to do this is probably to have a macro that sets a
PL_alterrormsg variable to the string error and errno to -1, then
change Perl_magic_get (look for case '!':) to set the PV from
PL_alterrormsg variable if errno == -1.
Not sure how to make sure PL_alterrormsg gets allocated and freed
as necessary. Perhaps make it an SV.
That sounds good to me. Can we have it?
Go right ahead :)
I'm not actually convinced this is any better than returning a generic
error (EIO?) and setting a separate variable with more info.
Even in C, each of the error codes is fairly generic and the message
doesn't necessarily apply to the particular error; you have to look at
the man page for the function that failed to see what that error means
from that function.
Another approach would be to objectify $! ala
http://dev.perl.org/perl6/rfc/151.pod
/me turns around trying to see who Yitzchak is pointing to ;)
> I'm not actually convinced this is any better than returning a generic
> error (EIO?) and setting a separate variable with more info.
>
> Even in C, each of the error codes is fairly generic and the message
> doesn't necessarily apply to the particular error; you have to look at
> the man page for the function that failed to see what that error means
> from that function.
If C was as easy as perl we won't be be at this forum right now. So if can
make things better/flexible in perl I fail to see why the inertia should kick in.
> Another approach would be to objectify $! ala
> http://dev.perl.org/perl6/rfc/151.pod
Interesting, but that won't be feasible for perl5, as it'll break any older
code I believe.
My €0.02 is that I still think setting errno to best fit is
preferable - but this is up to Pumpkings.
I haven't still heard a compelling argument in favor of changing the
current $!/errno situation. Using an external $errstr to give complementary
info if needed seems preferrable. Has Hugo an opinion on this ?
(I'll have to reread that thread, though. Or catch me on IRC --)
Nor have I. $! is errno, and errno is set by the OS (or whatever hunk
of short-duration personal OS emulation you're using at the moment).
--
Chip Salzenberg - a.k.a. - <ch...@pobox.com>
"I wanted to play hopscotch with the impenetrable mystery of existence,
but he stepped in a wormhole and had to go in early." // MST3K
Inertia isn't all bad. Without it, our universe as we know it couldn't
exist. With a feature as old and used by as much code as $! -- and
which is, in addition, a direct window to errno, a feature with an even
longer pedegree (what, 30 years by now) -- inertia is a Good Thing.
Furthermore, consider %!. That's a new feature related to errno that
increased convenience and portability without breaking either $! or the
notional connection of *! with errno.
There's lots of room in %main:: for experimental new features that
aren't about access to errno. You don't have to play with *!.
I quite liked the -1/string idea, but in general I think the point was
well made (by NIS I think) that you should do what the OS does - pick a
best-fit errno and document what it means in this context.
The trouble is that error codes and error strings are used by both humans
and by programs, and their needs are quite different. If you have one code
that can be associated with many different strings, a program needs to
check the string rather than relying on the code, and then it will break
as soon as you introduce some localisation, or correct a misspelling.
I guess it might be possible to have the best of both worlds by allowing
the altstring approach for any errno < 0, but it doesn't feel like a very
clean approach.
Hugo
And strerror gives a locale-dependent answer, that's why it should not
be relied upon.
I think that problem should be left to the system designers. If they can't use
$! and resort to using a custom $strerr, you have exactly the same problem of
matching error messages. So it does not make things any worse.
Now to give you a concrete existing example of this problem, take for example
CGI.pm. It reads from STDIN and writes to STDOUT and doesn't really want to
have tons of conditionals on how to handle IO error. Under mod_perl 2.0, STDIN
and STDOUT are overriden to :Apache layer handles interfacing the Apache
internals (which use bucket brigades as a data carrier and resemble nothing at
all close to the IO as you know it at the syscall level). CGI.pm doesn't know
that. It just read()s, write()s from those filehandles. Now if it wants to
check read(), write() failures and obviously it'll use $!, and if the :Apache
layer cannot set $! to a proper error message, users won't be able to figure
out what the problem is, left wondering what could have gone wrong.
> I guess it might be possible to have the best of both worlds by allowing
> the altstring approach for any errno < 0, but it doesn't feel like a very
> clean approach.
Do you have any other 'cleaner approach' ideas?
Why can't it? The "proper" value would be the integer version of the
local system error constant (presumably something simple and portable
like EINTR, EBADF, or EPIPE). The string value follows naturally...
$ perl -MPOSIX=EINTR -le '$!=EINTR; print $!'
Interrupted system call
I don't.
$i = $!; something else; $j = $!;
if ($i == $j) { the same thing happened? }
$! is errno, and that's visible to C code. The normal operation of a
Perl program is going to set errno to -1? <timon> And everyone's OK
with that? </timon>
Negative $! isn't $! any more.
If it logs "$!" while using the :Apache layer, which can't set $! to a
sensible error, CGI.pm (or any other lib) will fail to tell the user the exact
error message.
The :Apache layer does *not* run any system calls, and no system error makes
sense in many situations.
Please give some examples there are lots of errno values to choose from...
What if C<setnewerr($)> was to schedule a copy of itself for deletion at
the exit of the caller's (the caller of the routine, not the function)
scope? That
would be complicated and still vulnerable to masking $! set after
$newerr is set.
( fancyio and traditionalio )or die $newerr; # this case cannot work
# have to do it this way instead
fancyio or die $newerr;
traditionalio or die $newerr;
$! would still be masked if the failure was due to something that sets it
instead of something that sets $newerr. Maybe all code that sets $newerr
would be required to set newerr to $!, if it is going to set $newerr at all,
and $newerr falls back to $! when $newerr has been cleared or not set.
Alternatively, any code that might set $newerr must clear $newerr on
entry, and then return a failure indication immediately after setting it.
And $@ remains left completely out of the $!/$newerr interaction.
package errstr;
use vars qw/$newerr/;
sub import{ tie ${caller().'::errstr'} => 'errstr' }
sub TIESCALAR {return bless \$newerr}
sub FETCH { return $newerr || "$!" }
sub STORE { $newerr = $_[1] }
1;
__END__
Well that's a simple proposal that answers Stas Bekman's point, in
http://groups.google.com/groups?selm=4047B131.9040104%40stason.org
>I think that practice could be misleading and impractical. What's the point of
>setting an error code that doesn't match the real error. A separate error
>variable, similar to $DBI::errstr seems to be the only option so far, but once
>people will try to write:
>
> read $fh, my $foo, 10 or die "$newerr";
>
>and they will write this a lot, they will try to write that when not using my
>perlio layer.
>
>Besides there could be code that should be given a filehandle and it should
>read off it, regardless the layers used inside. How will it know to use $! or
>$newerr? what if this is a generic library?
>
$errstr might be a better name for it than $newerr, and if the above
package becomes widely
adopted (a standard, even) $DBI::errstr might get tied to it as well as
other packages (such as Net::FTP)
that provide their own error variables. To use errstr, your package
would repackage your legacy
error variable as $errstr::newerr -- by tieing it -- and also you want
to set the error variable to
undef or '' whenever you enter code that might set the error variable.
--
david...@pay2send.com.
Include phrase "perl"
Decisions have consequences. When the ":Apache" layer designers
decided that a layer was a Good Idea, they also subjected themselves
to limitations imposed by pretending to be a simple I/O channel. One
of those limitations is that you have to report your errors in the
same way a real I/O channel would.
Live by the emulation, die by the emulation.
Shirley a new language feature would be spelled with the caret.
Too bad $^E is taken. ${^Error} perhaps.
(This should not be construed as support for the feature, just an
observation about naming policy.)
For something not dissimilar - Win32/VMS native error code...
The numeric aspect of $! is errno, and there is no proposal to change
that. Notice that you can already set errno to values outside the range
the OS knows about both in C code and in perl:
zen% perl -we '$!=-1; printf "<%d> <%s>\n", $!, $!'
<-1> <Unknown error 4294967295>
zen% perl -we 'use Inline C => "void seterr() { errno = -1; }"; seterr(); printf "<%d> <%s>\n", $!, $!'
<-1> <Unknown error 4294967295>
zen%
.. so the question is only whether it would be more useful than not to
provide an extension of strerror() to allow the programmer to provide
a meaningful customised error message in such cases.
Despite what your short quote above implies, I am by no means convinced
that it would be, but I certainly believe that making it easier to provide
informative error messages would be a useful thing to do.
Hugo