[XS] direct access to the perl stack in XS code

  • Thread starter Rainer Weikusat
  • Start date

R

Rainer Weikusat

I finally grew somewhat tired of the Sys::Syslog code which does too
many weird things it shouldn't be doing (such as interfacing with the
Windows event log :->) in Perl code, including downright stupid things
such as using run-time translated strings for the priority constants
and things which change the 'global' execution environment (bad thing
for a routine supposed to generate diagnostic output). I've had a look
at Unix::Syslog but don't quite like that, either, because of 'weird
things' in the XS code ('hand-written' constant access functions,
mapping constants to names with for loops) and things written in Perl
which could equally well be implemented in C (message formatting).

Since this should really be an exercise in non-coding aka "just call
the C library routines and assume anything else is someone else's
business" and I had an otherwise spare Sunday evening in front of me,
I thought I could just run h2xs on the syslog.h file and see where
that would get me. Things never turning out to be quite as beautiful
as they should, some code does need to be written for that, in
particular, there's no (sane) way to invoke a C 'variadic
format-string function' with an a priori unknown set of arguments
which came from perl.

Perlapi(1) documents a function named
sv_vsetpvfn which seemed suitable for the formatting part which can
either work with a va_list or an array of SVs. At first, I thought of
copying the arguments on the stack into an array but then, it occurred
to me that the perl stack really ought to be such an array, already
laying in front of my feet and ready to be used. The code I'm
presently using for syslog which seems to be working fine is

void
syslog(__pri, __fmt, ...)
int __pri
char * __fmt
INIT:
char *msg;
SV *msg_sv;
bool dummy;
CODE:
if (items > 2) {
msg_sv = sv_newmortal();
sv_vsetpvfn(msg_sv, __fmt, sv_len(ST(1)), NULL,
PL_stack_base + ax + 2, items - 2,
&dummy);
msg = SvPV_nolen(msg_sv);
} else {
msg = __fmt;
}
syslog(__pri, "%s", msg);

Is there, excluding aesthetic/ philosophic aspects, a reason why I shouldn't be
doing this?
 
Ad

Advertisements

R

Rainer Weikusat

Ben Morrow said:
Quoth Rainer Weikusat <[email protected]>:
[syslog(3)]
there's no (sane) way to invoke a C 'variadic format-string
function' with an a priori unknown set of arguments
which came from perl.

No. This is because there's no (standard) way to invoke a variadic C
function with a dynamic argument list.

Even if there was, the code would need to interpret the format string
in order to determine the types of the arguments which need to be
passed to the C library routine and convert the 'Perl values' as
required. Which would then interpret the format string again. That's
not particularly sane.
The only problem with using this is that is will not handle %m. You will
need to run through the format list, replace %m with %s, and insert
strerror into the argument list.

If I cared that much about %m, I would change the formatting function
to deal with it :)[*]. Otherwise, there's again the need to scan the
format string twice and then either copy it a couple of times (what
the existing syslog modules do) or do an arbitrary number of 'in the
middle of an array' inserts. Omitting some features which can't be
supported easily is better than providing them with the help of a
quick and bad implementation punishing everyone.

[*] I'm not yet using a forked perl and don't plan to start doing so
unless I encounter a much more serious obstacle.

[...]
void
syslog(__pri, __fmt, ...)
int __pri
char * __fmt
INIT:
char *msg;
SV *msg_sv;
bool dummy;
CODE:
if (items > 2) {
msg_sv = sv_newmortal();
sv_vsetpvfn(msg_sv, __fmt, sv_len(ST(1)), NULL,

Calling sv_len here separately from the SvPV done by the typemap means
the format argument will be stringified twice.
Thanks.

[...]

Instead you should take a SV* argument, and use SvPV to retrieve string
value and length in one go. (I don't think you can reasonably use the
length(s) XS feature here.)
PL_stack_base + ax + 2, items - 2,

I would probably write this &ST(2), but as you like.

Some people like to pretend that 'C arrays' were something they're not
really hard. That leads to expressions like &a[n] or even (as in this
case) &a[n + m]. That's by definition the same as &*(a + n + m), that
is a + n + m plus some kind of "jump to the left, then, jump quickly to
the right and pretend you didn't move at all" prefix ...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top