Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: ModPerl: Dev

[patch]avoid closing fd 0/1

 

 

ModPerl dev RSS feed   Index | Next | Previous | View Threaded


torsten.foertsch at gmx

Mar 30, 2010, 10:10 AM

Post #1 of 13 (2446 views)
Permalink
[patch]avoid closing fd 0/1

Hi,

the patch below is a raw fix for the "mod_perl closes apache's stdin and/or
stdout"-bug, see also

http://www.gossamer-threads.com/lists/modperl/modperl/94921

Previously the code did something similar to

open SAVEFH, '<&STDIN';
close STDIN;
...
open STDIN, '<&SAVEFH';

The idea is to change that into

open SAVEFH, '<&='.fileno(STDIN);
close STDIN;
...
open STDIN, '<&='.fileno(SAVEFH);

This avoids calling dup().

This is the first time I do something Perl-IO-related in C. So, please review!
One thing that I don't understand is the difference between IoIFP and IoOFP.
Why does perl need 2 such structures to hold 1 file handle?

Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net
Attachments: modperl_io.patch (8.34 KB)


fred at redhotpenguin

Mar 30, 2010, 10:25 AM

Post #2 of 13 (2365 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

2010/3/30 Torsten Förtsch <torsten.foertsch [at] gmx>:
> Hi,
>
> the patch below is a raw fix for the "mod_perl closes apache's stdin and/or
> stdout"-bug, see also
>
>  http://www.gossamer-threads.com/lists/modperl/modperl/94921

Posting a copy of the patch inline for the archives. Thanks for
putting this together Torsten.

Index: src/modules/perl/modperl_io.c
===================================================================
--- src/modules/perl/modperl_io.c (revision 929182)
+++ src/modules/perl/modperl_io.c (working copy)
@@ -104,28 +104,39 @@
sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
}

-MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
{
- dHANDLE("STDIN");
- int status;
+ dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
+ int status, fileno;
GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();
+ SV *gsv;
+ IO *io;

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

/* if STDIN is open, dup it, to be restored at the end of response */
if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
+ IoTYPE(io=GvIO(handle)) != IoTYPE_CLOSED &&
+ (fileno=PerlIO_fileno(IoIFP(io))) >= 0) {
handle_save = gv_fetchpv(Perl_form(aTHX_
"Apache2::RequestIO::_GEN_%ld",
(long)PL_gensym++),
- TRUE, SVt_PVIO);
+ GV_ADD, SVt_PVIO);
+ if (!GvSV(handle_save)) GvSV(handle_save) = newSV(0);
+ gsv=GvSV(handle_save);

- /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
- status = do_open(handle_save, "<&STDIN", 7, FALSE,
- O_RDONLY, 0, Nullfp);
+ /* open my $oldout, "<&=".fileno(STDIN) or die "Can't dup
STDIN: $!"; */
+ SvUPGRADE(gsv, SVt_PV);
+ SvGROW(gsv, 20);
+ sv_setpvf(gsv, mode == O_RDONLY ? "<&=%d" : ">&=%d", fileno);
+
+ status = do_open(handle_save, SvPVX(GvSV(handle_save)),
+ SvCUR(GvSV(handle_save)), FALSE, mode, 0, Nullfp);
+
if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!", TRUE));
+ Perl_croak(aTHX_ "Failed to dup STD%s: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

/* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
@@ -135,105 +146,41 @@
}

sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
- 0, Nullfp, sv, 1);
+ status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
+ 9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
+ Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

- MP_TRACE_o(MP_FUNC, "end");
-
- return handle_save;
-}
-
-/* XXX: refactor to merge with the previous function */
-MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
-{
- dHANDLE("STDOUT");
- int status;
- GV *handle_save = (GV*)Nullsv;
- SV *sv = sv_newmortal();
-
- MP_TRACE_o(MP_FUNC, "start");
-
- /* if STDOUT is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
-
- /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
- status = do_open(handle_save, ">&STDOUT", 8, FALSE,
- O_WRONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!", TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDOUT must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
+ if (mode == O_WRONLY) {
+ /* XXX: shouldn't we preserve the value STDOUT had before it was
+ * overridden? */
+ IoFLUSH_off(handle); /* STDOUT's $|=0 */
}

- sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
- 0, Nullfp, sv, 1);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
- }
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");

- MP_TRACE_o(MP_FUNC, "end");
-
- /* XXX: shouldn't we preserve the value STDOUT had before it was
- * overridden? */
- IoFLUSH_off(handle); /* STDOUT's $|=0 */
-
return handle_save;
-
}

-MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
+MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
{
- GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
+ return modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
+}

- MP_TRACE_o(MP_FUNC, "start");
-
- /* close the overriding filehandle */
- do_close(handle_orig, FALSE);
-
- /*
- * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
- * close STDIN_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
-
- MP_TRACE_o(MP_FUNC, "restoring STDIN");
-
- if (do_open9(handle_orig, "<&", 2, FALSE,
- O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
-
- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
-
- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
+/* XXX: refactor to merge with the previous function */
+MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+{
+ return modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
}

-MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
+static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
{
- GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
+ GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
+ FALSE, SVt_PVIO);

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
@@ -242,7 +189,8 @@
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
- if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
+ if (mode == O_WRONLY &&
+ GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}
@@ -251,16 +199,15 @@
do_close(handle_orig, FALSE);

/*
- * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
- * close STDOUT_SAVED;
+ * open STDIN, "<&=$FD_SAVED" or die "Can't dup STDIN_SAVED: $!";
*/
if (handle != (GV*)Nullsv) {
SV *err = Nullsv;

- MP_TRACE_o(MP_FUNC, "restoring STDOUT");
+ MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ?
"IN" : "OUT");

- if (do_open9(handle_orig, ">&", 2, FALSE,
- O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
+ if (do_open(handle_orig, SvPVX(GvSV(handle)), SvCUR(GvSV(handle)),
+ FALSE, mode, 0, NULL) == 0) {
err = get_sv("!", TRUE);
}

@@ -269,9 +216,21 @@
GvNAME(handle), GvNAMELEN(handle), G_DISCARD);

if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
+ Perl_croak(aTHX_ "Failed to restore STD: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", err);
}
}

- MP_TRACE_o(MP_FUNC, "end");
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
}
+
+MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_RDONLY);
+}
+
+MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_WRONLY);
+}
+



>
> Previously the code did something similar to
>
>  open SAVEFH, '<&STDIN';
>  close STDIN;
>  ...
>  open STDIN, '<&SAVEFH';
>
> The idea is to change that into
>
>  open SAVEFH, '<&='.fileno(STDIN);
>  close STDIN;
>  ...
>  open STDIN, '<&='.fileno(SAVEFH);
>
> This avoids calling dup().
>
> This is the first time I do something Perl-IO-related in C. So, please review!
> One thing that I don't understand is the difference between IoIFP and IoOFP.
> Why does perl need 2 such structures to hold 1 file handle?
>
> Torsten Förtsch
>
> --
> Need professional modperl support? Hire me! (http://foertsch.name)
>
> Like fantasy? http://kabatinte.net
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe [at] perl
> For additional commands, e-mail: dev-help [at] perl
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


fred at redhotpenguin

Mar 30, 2010, 11:08 AM

Post #3 of 13 (2366 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

Torsten can you post a breakdown of each part in the patch so those of
us who can't grok all of it (I'm one of them!) can get a handle (no
pun intended) on what each part does?

2010/3/30 Fred Moyer <fred [at] redhotpenguin>:
> 2010/3/30 Torsten Förtsch <torsten.foertsch [at] gmx>:
>> Hi,
>>
>> the patch below is a raw fix for the "mod_perl closes apache's stdin and/or
>> stdout"-bug, see also
>>
>>  http://www.gossamer-threads.com/lists/modperl/modperl/94921
>
> Posting a copy of the patch inline for the archives.  Thanks for
> putting this together Torsten.
>
> Index: src/modules/perl/modperl_io.c
> ===================================================================
> --- src/modules/perl/modperl_io.c       (revision 929182)
> +++ src/modules/perl/modperl_io.c       (working copy)
> @@ -104,28 +104,39 @@
>     sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
>  }
>
> -MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
> +static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
>  {
> -    dHANDLE("STDIN");
> -    int status;
> +    dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
> +    int status, fileno;
>     GV *handle_save = (GV*)Nullsv;
>     SV *sv = sv_newmortal();
> +    SV *gsv;
> +    IO *io;
>
> -    MP_TRACE_o(MP_FUNC, "start");
> +    MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");
>
>     /* if STDIN is open, dup it, to be restored at the end of response */
>     if (handle && SvTYPE(handle) == SVt_PVGV &&
> -        IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
> +        IoTYPE(io=GvIO(handle)) != IoTYPE_CLOSED &&
> +       (fileno=PerlIO_fileno(IoIFP(io))) >= 0) {
>         handle_save = gv_fetchpv(Perl_form(aTHX_
>                                            "Apache2::RequestIO::_GEN_%ld",
>                                            (long)PL_gensym++),
> -                                 TRUE, SVt_PVIO);
> +                                 GV_ADD, SVt_PVIO);
> +       if (!GvSV(handle_save)) GvSV(handle_save) = newSV(0);
> +       gsv=GvSV(handle_save);
>
> -        /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
> -        status = do_open(handle_save, "<&STDIN", 7, FALSE,
> -                         O_RDONLY, 0, Nullfp);
> +        /* open my $oldout, "<&=".fileno(STDIN) or die "Can't dup
> STDIN: $!"; */
> +       SvUPGRADE(gsv, SVt_PV);
> +       SvGROW(gsv, 20);
> +       sv_setpvf(gsv, mode == O_RDONLY ? "<&=%d" : ">&=%d", fileno);
> +
> +        status = do_open(handle_save, SvPVX(GvSV(handle_save)),
> +                        SvCUR(GvSV(handle_save)), FALSE, mode, 0, Nullfp);
> +
>         if (status == 0) {
> -            Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!", TRUE));
> +           Perl_croak(aTHX_ "Failed to dup STD%s: %" SVf,
> +                      mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
>         }
>
>         /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
> @@ -135,105 +146,41 @@
>     }
>
>     sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
> -    status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
> -                      0, Nullfp, sv, 1);
> +    status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
> +                     9, FALSE, mode, 0, Nullfp, sv, 1);
>     if (status == 0) {
> -        Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
> +        Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
> +                  mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
>     }
>
> -    MP_TRACE_o(MP_FUNC, "end");
> -
> -    return handle_save;
> -}
> -
> -/* XXX: refactor to merge with the previous function */
> -MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
> -{
> -    dHANDLE("STDOUT");
> -    int status;
> -    GV *handle_save = (GV*)Nullsv;
> -    SV *sv = sv_newmortal();
> -
> -    MP_TRACE_o(MP_FUNC, "start");
> -
> -    /* if STDOUT is open, dup it, to be restored at the end of response */
> -    if (handle && SvTYPE(handle) == SVt_PVGV &&
> -        IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
> -        handle_save = gv_fetchpv(Perl_form(aTHX_
> -                                           "Apache2::RequestIO::_GEN_%ld",
> -                                           (long)PL_gensym++),
> -                                 TRUE, SVt_PVIO);
> -
> -        /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
> -        status = do_open(handle_save, ">&STDOUT", 8, FALSE,
> -                         O_WRONLY, 0, Nullfp);
> -        if (status == 0) {
> -            Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!", TRUE));
> -        }
> -
> -        /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
> -         * have file descriptors, so STDOUT must be closed before it can
> -         * be reopened */
> -        do_close(handle, TRUE);
> +    if (mode == O_WRONLY) {
> +        /* XXX: shouldn't we preserve the value STDOUT had before it was
> +        * overridden? */
> +        IoFLUSH_off(handle); /* STDOUT's $|=0 */
>     }
>
> -    sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
> -    status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
> -                      0, Nullfp, sv, 1);
> -    if (status == 0) {
> -        Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
> -    }
> +    MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");
>
> -    MP_TRACE_o(MP_FUNC, "end");
> -
> -    /* XXX: shouldn't we preserve the value STDOUT had before it was
> -     * overridden? */
> -    IoFLUSH_off(handle); /* STDOUT's $|=0 */
> -
>     return handle_save;
> -
>  }
>
> -MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
> +MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
>  {
> -    GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
> +    return modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
> +}
>
> -    MP_TRACE_o(MP_FUNC, "start");
> -
> -    /* close the overriding filehandle */
> -    do_close(handle_orig, FALSE);
> -
> -    /*
> -     * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
> -     * close STDIN_SAVED;
> -     */
> -    if (handle != (GV*)Nullsv) {
> -        SV *err = Nullsv;
> -
> -        MP_TRACE_o(MP_FUNC, "restoring STDIN");
> -
> -        if (do_open9(handle_orig, "<&", 2, FALSE,
> -                     O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
> -            err = get_sv("!", TRUE);
> -        }
> -
> -        do_close(handle, FALSE);
> -        (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
> -                        GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
> -
> -        if (err != Nullsv) {
> -            Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
> -        }
> -    }
> -
> -    MP_TRACE_o(MP_FUNC, "end");
> +/* XXX: refactor to merge with the previous function */
> +MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
> +{
> +    return modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
>  }
>
> -MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
> +static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
>  {
> -    GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
> +    GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
> +                                FALSE, SVt_PVIO);
>
> -    MP_TRACE_o(MP_FUNC, "start");
> +    MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");
>
>     /* since closing unflushed STDOUT may trigger a subrequest
>      * (e.g. via mod_include), resulting in potential another response
> @@ -242,7 +189,8 @@
>      * level STDOUT is attempted to be closed. To prevent this
>      * situation always explicitly flush STDOUT, before reopening it.
>      */
> -    if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
> +    if (mode == O_WRONLY &&
> +       GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
>         (PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
>         Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
>     }
> @@ -251,16 +199,15 @@
>     do_close(handle_orig, FALSE);
>
>     /*
> -     * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
> -     * close STDOUT_SAVED;
> +     * open STDIN, "<&=$FD_SAVED" or die "Can't dup STDIN_SAVED: $!";
>      */
>     if (handle != (GV*)Nullsv) {
>         SV *err = Nullsv;
>
> -        MP_TRACE_o(MP_FUNC, "restoring STDOUT");
> +        MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ?
> "IN" : "OUT");
>
> -        if (do_open9(handle_orig, ">&", 2, FALSE,
> -                     O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
> +        if (do_open(handle_orig, SvPVX(GvSV(handle)), SvCUR(GvSV(handle)),
> +                   FALSE, mode, 0, NULL) == 0) {
>             err = get_sv("!", TRUE);
>         }
>
> @@ -269,9 +216,21 @@
>                         GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
>
>         if (err != Nullsv) {
> -            Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
> +           Perl_croak(aTHX_ "Failed to restore STD: %" SVf,
> +                      mode == O_RDONLY ? "IN" : "OUT", err);
>         }
>     }
>
> -    MP_TRACE_o(MP_FUNC, "end");
> +    MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
>  }
> +
> +MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
> +{
> +    modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_RDONLY);
> +}
> +
> +MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
> +{
> +    modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_WRONLY);
> +}
> +
>
>
>
>>
>> Previously the code did something similar to
>>
>>  open SAVEFH, '<&STDIN';
>>  close STDIN;
>>  ...
>>  open STDIN, '<&SAVEFH';
>>
>> The idea is to change that into
>>
>>  open SAVEFH, '<&='.fileno(STDIN);
>>  close STDIN;
>>  ...
>>  open STDIN, '<&='.fileno(SAVEFH);
>>
>> This avoids calling dup().
>>
>> This is the first time I do something Perl-IO-related in C. So, please review!
>> One thing that I don't understand is the difference between IoIFP and IoOFP.
>> Why does perl need 2 such structures to hold 1 file handle?
>>
>> Torsten Förtsch
>>
>> --
>> Need professional modperl support? Hire me! (http://foertsch.name)
>>
>> Like fantasy? http://kabatinte.net
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe [at] perl
>> For additional commands, e-mail: dev-help [at] perl
>>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


torsten.foertsch at gmx

Mar 30, 2010, 11:35 AM

Post #4 of 13 (2360 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Tuesday 30 March 2010 20:08:00 Fred Moyer wrote:
> Torsten can you post a breakdown of each part in the patch so those of
> us who can't grok all of it (I'm one of them!) can get a handle (no
> pun intended) on what each part does?
>
Best I think if you look at the patch result. Previously there were 2
very similar sets of functions modperl_io_perlio_{override,restore}_std{in,out}
and a XXX-comment suggesting merging of these 2 sets. Now, there is
one override-function and one restorer.

I use the SV slot of the GV to remember the open string to be used by the
restorer. Now, I think I could avoid that and use Perl_form + fileno in the
restorer. But the SV slot can be used for example to store $|-ness of the
handle. This would eliminate the other XXX-comment.

Much more interesting for me is is the IO-redirecting stuff correct? And related,
in which cases do IFP and OFP of a handle differ or do they differ or rather in
which cases do fileno(IFP) differ from fileno(OFP)?

static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
{
dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
int status, fileno;
GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();
SV *gsv;
IO *io;

MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

/* if STDIN is open, dup it, to be restored at the end of response */
if (handle && SvTYPE(handle) == SVt_PVGV &&
IoTYPE(io=GvIO(handle)) != IoTYPE_CLOSED &&
(fileno=PerlIO_fileno(IoIFP(io))) >= 0) {
handle_save = gv_fetchpv(Perl_form(aTHX_
"Apache2::RequestIO::_GEN_%ld",
(long)PL_gensym++),
GV_ADD, SVt_PVIO);
if (!GvSV(handle_save)) GvSV(handle_save) = newSV(0);
gsv=GvSV(handle_save);

/* open my $oldout, "<&=".fileno(STDIN) or die "Can't dup STDIN: $!"; */
SvUPGRADE(gsv, SVt_PV);
SvGROW(gsv, 20);
sv_setpvf(gsv, mode == O_RDONLY ? "<&=%d" : ">&=%d", fileno);

status = do_open(handle_save, SvPVX(GvSV(handle_save)),
SvCUR(GvSV(handle_save)), FALSE, mode, 0, Nullfp);

if (status == 0) {
Perl_croak(aTHX_ "Failed to dup STD%s: %" SVf,
mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

/* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
* have file descriptors, so STDIN must be closed before it can
* be reopened */
do_close(handle, TRUE);
}

sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

if (mode == O_WRONLY) {
/* XXX: shouldn't we preserve the value STDOUT had before it was
* overridden? */
IoFLUSH_off(handle); /* STDOUT's $|=0 */
}

MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");

return handle_save;
}

MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
{
return modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
}

/* XXX: refactor to merge with the previous function */
MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
{
return modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
}

static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
{
GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
FALSE, SVt_PVIO);

MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
* handler call, which may try to close STDOUT too. We will
* segfault, if that subrequest doesn't return before the the top
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
if (mode == O_WRONLY &&
GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}

/* close the overriding filehandle */
do_close(handle_orig, FALSE);

/*
* open STDIN, "<&=$FD_SAVED" or die "Can't dup STDIN_SAVED: $!";
*/
if (handle != (GV*)Nullsv) {
SV *err = Nullsv;

MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ? "IN" : "OUT");

if (do_open(handle_orig, SvPVX(GvSV(handle)), SvCUR(GvSV(handle)),
FALSE, mode, 0, NULL) == 0) {
err = get_sv("!", TRUE);
}

do_close(handle, FALSE);
(void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
GvNAME(handle), GvNAMELEN(handle), G_DISCARD);

if (err != Nullsv) {
Perl_croak(aTHX_ "Failed to restore STD: %" SVf,
mode == O_RDONLY ? "IN" : "OUT", err);
}
}

MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
}

MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
{
modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_RDONLY);
}

MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
{
modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_WRONLY);
}



Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


torsten.foertsch at gmx

Mar 31, 2010, 7:43 AM

Post #5 of 13 (2354 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Tuesday 30 March 2010 19:10:36 Torsten Förtsch wrote:
> Previously the code did something similar to
>
> open SAVEFH, '<&STDIN';
> close STDIN;
> ...
> open STDIN, '<&SAVEFH';
>
> The idea is to change that into
>
> open SAVEFH, '<&='.fileno(STDIN);
> close STDIN;
> ...
> open STDIN, '<&='.fileno(SAVEFH);
>
This one is much simpler. It swaps the SvANY pointer of the handle to
be saved with the SvANY pointer of a newly allocated GvIO.

I believe the IoFLUSH_off in the override function can be omitted since
this is standard for a new handle.

Since the whole XPVIO structure is saved this way all information about
the original handle is preserved including IFP, OFP, TYPE and even a
possible format or $., $%, $= etc.

Now, the 2 functions look this way:

static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
{
dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
int status;
GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();
IO *srcio, *destio;
void *tmp;

MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

if (handle && SvTYPE(handle) == SVt_PVGV &&
IoTYPE(srcio=GvIO(handle)) != IoTYPE_CLOSED) {
handle_save = gv_fetchpv(Perl_form(aTHX_
"Apache2::RequestIO::_GEN_%ld",
(long)PL_gensym++),
GV_ADD, SVt_PVIO);

destio=GvIO(handle_save);

tmp=SvANY(destio);
SvANY(destio)=SvANY(srcio);
SvANY(srcio)=tmp;
}

sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

if (mode != O_RDONLY) {
IoFLUSH_off(handle); /* STDOUT's $|=0 */
}

MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");

return handle_save;
}

static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
{
GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
FALSE, SVt_PVIO);

MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
* handler call, which may try to close STDOUT too. We will
* segfault, if that subrequest doesn't return before the the top
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
if (mode != O_RDONLY &&
GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}

/* close the overriding filehandle */
do_close(handle_orig, FALSE);

if (handle != (GV*)Nullsv) {
IO *srcio, *destio;
void *tmp;

MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ? "IN" : "OUT");

srcio=GvIO(handle);
destio=GvIO(handle_orig);

tmp=SvANY(destio);
SvANY(destio)=SvANY(srcio);
SvANY(srcio)=tmp;

(void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
}

MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
}

Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net
Attachments: modperl_io.patch (7.91 KB)


torsten.foertsch at gmx

Mar 31, 2010, 7:59 AM

Post #6 of 13 (2360 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Wednesday 31 March 2010 16:43:04 Torsten Förtsch wrote:
> I believe the IoFLUSH_off in the override function can be omitted since
> this is standard for a new handle.
>
This appears to be true. This is now the final version of the patch. Are there
any objections against applying it to trunk?

Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net
Attachments: modperl_io.patch (7.83 KB)


fred at redhotpenguin

Mar 31, 2010, 8:55 AM

Post #7 of 13 (2356 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

2010/3/31 Torsten Förtsch <torsten.foertsch [at] gmx>:
> On Wednesday 31 March 2010 16:43:04 Torsten Förtsch wrote:
>> I believe the IoFLUSH_off in the override function can be omitted since
>> this is standard for a new handle.
>>
> This appears to be true. This is now the final version of the patch. Are there
> any objections against applying it to trunk?

I was able to review some of what you posted yesterday but still
haven't had enough time to digest the changes. It would make it much,
much easier if you submitted the patches inline for review so that
others can comment inline.

http://perl.apache.org/docs/2.0/devel/help/help.html#Submitting_Patches

"Note that we prefer the patches inlined into an email. This makes
easier to comment on them."

Can you repost the latest patch inline so that interested parties can
add comments and understand what is going on in there? I know that
only a few people understand the innards of mod_perl with XS magic,
but just getting it out there will help with that and the more eyes on
the code the better.

>
> Torsten Förtsch
>
> --
> Need professional modperl support? Hire me! (http://foertsch.name)
>
> Like fantasy? http://kabatinte.net
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe [at] perl
> For additional commands, e-mail: dev-help [at] perl
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


torsten.foertsch at gmx

Apr 1, 2010, 7:34 AM

Post #8 of 13 (2345 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Wednesday 31 March 2010 17:55:47 Fred Moyer wrote:
> Can you repost the latest patch inline so that interested parties can
> add comments and understand what is going on in there? I know that
> only a few people understand the innards of mod_perl with XS magic,
> but just getting it out there will help with that and the more eyes on
> the code the better.
>
Let me explain what the patch does. As mentioned before the previous code did
something like this:

open SAVEFH, '<&STDIN';
close STDIN;
...
open STDIN, '<&SAVEFH';

This code opens SAVEFH on a different file descriptor. Before STDIN is closed
fileno(SAVEFH)!=fileno(STDIN). Later, when STDIN is restored from STDIN it is
still the same file but it is not necessarily bound to file descriptor 0. This
is the heart of the problem.

My first solution replaced the dup() by an fdopen(). Thus, the file descriptor
remains the same.

open SAVEFH, '<&='.fileno(STDIN);
close STDIN;
...
open STDIN, '<&='.fileno(SAVEFH);

But in Perl there is more data related to a file handle save for the file
descriptor. There are flags like $|, integer values like $. or $=, even GVs.

Both of the approaches above destroy that information.

After studying Reini Urban's and Gisle Aas' illguts document:
http://rurban.xarch.at/software/perl/illguts/
http://cpansearch.perl.org/src/GAAS/illguts-0.09/index.html
it occurred to me that just exchanging one pointer would be enough to solve
all the problems.

GvIO(handle) returns an IO* pointer. The first element of this structure, the
SvANY-element, points to a struct xpvio. This structure contains all of the
data related to a file handle except for the reference count.

So, to save a standard handle the code now creates a new GV. Then swaps its
SvANY(GvIO(newhandle)) for SvANY(GvIO(STDIN)). Now STDIN looks like a fresh,
still closed file handle. So it can be opened with the Apache2 perlio layer as
before.

The restoring code then flushes and closes the STD{IN,OUT} handle. After that
any resources bound to an open file handle are destroyed. So, it's safe to
undo the swap-operation. Then the temporary handle is destroyed and the
standard handle looks exactly the same as it has before the whole operation.

I think, this is the safest (and fastest) way to do preserve a file handle.

Now, one could do such stuff:

<Perl>
open STDIN, '<', '/dev/urandom';
{
package My::XXX;
use Apache2::RequestRec ();
use Apache2::Const -compile=>'OK';
sub handler {
my ($r)=@_;
local $/=\10;
my $str=readline STDIN;
$r->print("$.: ".unpack('H*',$str)."\n");
return Apache2::Const::OK;
}
}
</Perl>

<Location /My__XXX/mp>
SetHandler modperl
PerlResponseHandler My::XXX
</Location>

<Location /My__XXX/ps>
SetHandler perl-script
PerlResponseHandler My::XXX
</Location>

and intermix calls to /My__XXX/mp with calls to /My__XXX/ps on the same apache
instance. And $. will still count upwards.

$ curl http://localhost:8529/My__XXX/mp
1: 645d1c3a880c15a4f889
$ curl http://localhost:8529/My__XXX/ps
0:
$ curl http://localhost:8529/My__XXX/mp
2: 86b0ebdc88936475ef21
$ curl http://localhost:8529/My__XXX/ps
0:
$ curl http://localhost:8529/My__XXX/mp
3: 91de660a45e64a2a6dfb
$ curl http://localhost:8529/My__XXX/ps
0:
$ curl http://localhost:8529/My__XXX/mp
4: f4184c04e20422a67bd9

httpd was started with -D ONE_PROCESS. $. is preserved.

Index: src/modules/perl/modperl_io.c
===================================================================
--- src/modules/perl/modperl_io.c (revision 929182)
+++ src/modules/perl/modperl_io.c (working copy)
@@ -104,137 +104,51 @@
sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
}

-MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int
mode)
{
- dHANDLE("STDIN");
+ dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
int status;
GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();
+ IO *srcio, *destio;
+ void *tmp;

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDIN is open, dup it, to be restored at the end of response */
if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
+ IoTYPE(srcio=GvIO(handle)) != IoTYPE_CLOSED) {
handle_save = gv_fetchpv(Perl_form(aTHX_
"Apache2::RequestIO::_GEN_%ld",
(long)PL_gensym++),
- TRUE, SVt_PVIO);
+ GV_ADD, SVt_PVIO);

- /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
- status = do_open(handle_save, "<&STDIN", 7, FALSE,
- O_RDONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!",
TRUE));
- }
+ destio=GvIO(handle_save);

- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDIN must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
+ tmp=SvANY(destio);
+ SvANY(destio)=SvANY(srcio);
+ SvANY(srcio)=tmp;
}

sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
- 0, Nullfp, sv, 1);
+ status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
+ 9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
+ Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

- MP_TRACE_o(MP_FUNC, "end");
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");

return handle_save;
}

-/* XXX: refactor to merge with the previous function */
-MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
{
- dHANDLE("STDOUT");
- int status;
- GV *handle_save = (GV*)Nullsv;
- SV *sv = sv_newmortal();
+ GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
+ FALSE, SVt_PVIO);

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDOUT is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
-
- /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
- status = do_open(handle_save, ">&STDOUT", 8, FALSE,
- O_WRONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!",
TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDOUT must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
- }
-
- sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
- 0, Nullfp, sv, 1);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-
- /* XXX: shouldn't we preserve the value STDOUT had before it was
- * overridden? */
- IoFLUSH_off(handle); /* STDOUT's $|=0 */
-
- return handle_save;
-
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
- /* close the overriding filehandle */
- do_close(handle_orig, FALSE);
-
- /*
- * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
- * close STDIN_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
-
- MP_TRACE_o(MP_FUNC, "restoring STDIN");
-
- if (do_open9(handle_orig, "<&", 2, FALSE,
- O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
-
- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
-
- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
* handler call, which may try to close STDOUT too. We will
@@ -242,7 +156,8 @@
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
- if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
+ if (mode != O_RDONLY &&
+ GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}
@@ -250,28 +165,43 @@
/* close the overriding filehandle */
do_close(handle_orig, FALSE);

- /*
- * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
- * close STDOUT_SAVED;
- */
if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
+ IO *srcio, *destio;
+ void *tmp;

- MP_TRACE_o(MP_FUNC, "restoring STDOUT");
+ MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ? "IN" :
"OUT");

- if (do_open9(handle_orig, ">&", 2, FALSE,
- O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
+ srcio=GvIO(handle);
+ destio=GvIO(handle_orig);

- do_close(handle, FALSE);
+ tmp=SvANY(destio);
+ SvANY(destio)=SvANY(srcio);
+ SvANY(srcio)=tmp;
+
(void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
-
- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
- }
}

- MP_TRACE_o(MP_FUNC, "end");
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
}
+
+MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+{
+ return modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
+}
+
+MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+{
+ return modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
+}
+
+MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_RDONLY);
+}
+
+MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_WRONLY);
+}
+


Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


pgollucci at p6m7g8

Apr 2, 2010, 11:04 AM

Post #9 of 13 (2337 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

God speed messing with PerlIO stuff.


On 04/01/10 14:34, Torsten Förtsch wrote:
> On Wednesday 31 March 2010 17:55:47 Fred Moyer wrote:
>> Can you repost the latest patch inline so that interested parties can
>> add comments and understand what is going on in there? I know that
>> only a few people understand the innards of mod_perl with XS magic,
>> but just getting it out there will help with that and the more eyes on
>> the code the better.
>>
> Let me explain what the patch does. As mentioned before the previous code did
> something like this:
>
> open SAVEFH, '<&STDIN';
> close STDIN;
> ...
> open STDIN, '<&SAVEFH';
>
> This code opens SAVEFH on a different file descriptor. Before STDIN is closed
> fileno(SAVEFH)!=fileno(STDIN). Later, when STDIN is restored from STDIN it is
> still the same file but it is not necessarily bound to file descriptor 0. This
> is the heart of the problem.
>
> My first solution replaced the dup() by an fdopen(). Thus, the file descriptor
> remains the same.
>
> open SAVEFH, '<&='.fileno(STDIN);
> close STDIN;
> ...
> open STDIN, '<&='.fileno(SAVEFH);
>
> But in Perl there is more data related to a file handle save for the file
> descriptor. There are flags like $|, integer values like $. or $=, even GVs.
>
> Both of the approaches above destroy that information.
>
> After studying Reini Urban's and Gisle Aas' illguts document:
> http://rurban.xarch.at/software/perl/illguts/
> http://cpansearch.perl.org/src/GAAS/illguts-0.09/index.html
> it occurred to me that just exchanging one pointer would be enough to solve
> all the problems.
>
> GvIO(handle) returns an IO* pointer. The first element of this structure, the
> SvANY-element, points to a struct xpvio. This structure contains all of the
> data related to a file handle except for the reference count.
>
> So, to save a standard handle the code now creates a new GV. Then swaps its
> SvANY(GvIO(newhandle)) for SvANY(GvIO(STDIN)). Now STDIN looks like a fresh,
> still closed file handle. So it can be opened with the Apache2 perlio layer as
> before.
>
> The restoring code then flushes and closes the STD{IN,OUT} handle. After that
> any resources bound to an open file handle are destroyed. So, it's safe to
> undo the swap-operation. Then the temporary handle is destroyed and the
> standard handle looks exactly the same as it has before the whole operation.
>
> I think, this is the safest (and fastest) way to do preserve a file handle.
>
> Now, one could do such stuff:
>
> <Perl>
> open STDIN, '<', '/dev/urandom';
> {
> package My::XXX;
> use Apache2::RequestRec ();
> use Apache2::Const -compile=>'OK';
> sub handler {
> my ($r)=@_;
> local $/=\10;
> my $str=readline STDIN;
> $r->print("$.: ".unpack('H*',$str)."\n");
> return Apache2::Const::OK;
> }
> }
> </Perl>
>
> <Location /My__XXX/mp>
> SetHandler modperl
> PerlResponseHandler My::XXX
> </Location>
>
> <Location /My__XXX/ps>
> SetHandler perl-script
> PerlResponseHandler My::XXX
> </Location>
>
> and intermix calls to /My__XXX/mp with calls to /My__XXX/ps on the same apache
> instance. And $. will still count upwards.
>
> $ curl http://localhost:8529/My__XXX/mp
> 1: 645d1c3a880c15a4f889
> $ curl http://localhost:8529/My__XXX/ps
> 0:
> $ curl http://localhost:8529/My__XXX/mp
> 2: 86b0ebdc88936475ef21
> $ curl http://localhost:8529/My__XXX/ps
> 0:
> $ curl http://localhost:8529/My__XXX/mp
> 3: 91de660a45e64a2a6dfb
> $ curl http://localhost:8529/My__XXX/ps
> 0:
> $ curl http://localhost:8529/My__XXX/mp
> 4: f4184c04e20422a67bd9
>
> httpd was started with -D ONE_PROCESS. $. is preserved.
>
> Index: src/modules/perl/modperl_io.c
> ===================================================================
> --- src/modules/perl/modperl_io.c (revision 929182)
> +++ src/modules/perl/modperl_io.c (working copy)
> @@ -104,137 +104,51 @@
> sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
> }
>
> -MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
> +static GV *modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int
> mode)
> {
> - dHANDLE("STDIN");
> + dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
> int status;
> GV *handle_save = (GV*)Nullsv;
> SV *sv = sv_newmortal();
> + IO *srcio, *destio;
> + void *tmp;
>
> - MP_TRACE_o(MP_FUNC, "start");
> + MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");
>
> - /* if STDIN is open, dup it, to be restored at the end of response */
> if (handle&& SvTYPE(handle) == SVt_PVGV&&
> - IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
> + IoTYPE(srcio=GvIO(handle)) != IoTYPE_CLOSED) {
> handle_save = gv_fetchpv(Perl_form(aTHX_
> "Apache2::RequestIO::_GEN_%ld",
> (long)PL_gensym++),
> - TRUE, SVt_PVIO);
> + GV_ADD, SVt_PVIO);
>
> - /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
> - status = do_open(handle_save, "<&STDIN", 7, FALSE,
> - O_RDONLY, 0, Nullfp);
> - if (status == 0) {
> - Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!",
> TRUE));
> - }
> + destio=GvIO(handle_save);
>
> - /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
> - * have file descriptors, so STDIN must be closed before it can
> - * be reopened */
> - do_close(handle, TRUE);
> + tmp=SvANY(destio);
> + SvANY(destio)=SvANY(srcio);
> + SvANY(srcio)=tmp;
> }
>
> sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
> - status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
> - 0, Nullfp, sv, 1);
> + status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
> + 9, FALSE, mode, 0, Nullfp, sv, 1);
> if (status == 0) {
> - Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
> + Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
> + mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
> }
>
> - MP_TRACE_o(MP_FUNC, "end");
> + MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");
>
> return handle_save;
> }
>
> -/* XXX: refactor to merge with the previous function */
> -MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
> +static void modperl_io_perlio_restore_stdhandle(pTHX_ GV *handle, int mode)
> {
> - dHANDLE("STDOUT");
> - int status;
> - GV *handle_save = (GV*)Nullsv;
> - SV *sv = sv_newmortal();
> + GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
> + FALSE, SVt_PVIO);
>
> - MP_TRACE_o(MP_FUNC, "start");
> + MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");
>
> - /* if STDOUT is open, dup it, to be restored at the end of response */
> - if (handle&& SvTYPE(handle) == SVt_PVGV&&
> - IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
> - handle_save = gv_fetchpv(Perl_form(aTHX_
> - "Apache2::RequestIO::_GEN_%ld",
> - (long)PL_gensym++),
> - TRUE, SVt_PVIO);
> -
> - /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
> - status = do_open(handle_save, ">&STDOUT", 8, FALSE,
> - O_WRONLY, 0, Nullfp);
> - if (status == 0) {
> - Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!",
> TRUE));
> - }
> -
> - /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
> - * have file descriptors, so STDOUT must be closed before it can
> - * be reopened */
> - do_close(handle, TRUE);
> - }
> -
> - sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
> - status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
> - 0, Nullfp, sv, 1);
> - if (status == 0) {
> - Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
> - }
> -
> - MP_TRACE_o(MP_FUNC, "end");
> -
> - /* XXX: shouldn't we preserve the value STDOUT had before it was
> - * overridden? */
> - IoFLUSH_off(handle); /* STDOUT's $|=0 */
> -
> - return handle_save;
> -
> -}
> -
> -MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
> -{
> - GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
> -
> - MP_TRACE_o(MP_FUNC, "start");
> -
> - /* close the overriding filehandle */
> - do_close(handle_orig, FALSE);
> -
> - /*
> - * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
> - * close STDIN_SAVED;
> - */
> - if (handle != (GV*)Nullsv) {
> - SV *err = Nullsv;
> -
> - MP_TRACE_o(MP_FUNC, "restoring STDIN");
> -
> - if (do_open9(handle_orig, "<&", 2, FALSE,
> - O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
> - err = get_sv("!", TRUE);
> - }
> -
> - do_close(handle, FALSE);
> - (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
> - GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
> -
> - if (err != Nullsv) {
> - Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
> - }
> - }
> -
> - MP_TRACE_o(MP_FUNC, "end");
> -}
> -
> -MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
> -{
> - GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
> -
> - MP_TRACE_o(MP_FUNC, "start");
> -
> /* since closing unflushed STDOUT may trigger a subrequest
> * (e.g. via mod_include), resulting in potential another response
> * handler call, which may try to close STDOUT too. We will
> @@ -242,7 +156,8 @@
> * level STDOUT is attempted to be closed. To prevent this
> * situation always explicitly flush STDOUT, before reopening it.
> */
> - if (GvIOn(handle_orig)&& IoOFP(GvIOn(handle_orig))&&
> + if (mode != O_RDONLY&&
> + GvIOn(handle_orig)&& IoOFP(GvIOn(handle_orig))&&
> (PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
> Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
> }
> @@ -250,28 +165,43 @@
> /* close the overriding filehandle */
> do_close(handle_orig, FALSE);
>
> - /*
> - * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
> - * close STDOUT_SAVED;
> - */
> if (handle != (GV*)Nullsv) {
> - SV *err = Nullsv;
> + IO *srcio, *destio;
> + void *tmp;
>
> - MP_TRACE_o(MP_FUNC, "restoring STDOUT");
> + MP_TRACE_o(MP_FUNC, "restoring STD%s", mode == O_RDONLY ? "IN" :
> "OUT");
>
> - if (do_open9(handle_orig, ">&", 2, FALSE,
> - O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
> - err = get_sv("!", TRUE);
> - }
> + srcio=GvIO(handle);
> + destio=GvIO(handle_orig);
>
> - do_close(handle, FALSE);
> + tmp=SvANY(destio);
> + SvANY(destio)=SvANY(srcio);
> + SvANY(srcio)=tmp;
> +
> (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
> GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
> -
> - if (err != Nullsv) {
> - Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
> - }
> }
>
> - MP_TRACE_o(MP_FUNC, "end");
> + MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
> }
> +
> +MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
> +{
> + return modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
> +}
> +
> +MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
> +{
> + return modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
> +}
> +
> +MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
> +{
> + modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_RDONLY);
> +}
> +
> +MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
> +{
> + modperl_io_perlio_restore_stdhandle(aTHX_ handle, O_WRONLY);
> +}
> +
>
>
> Torsten Förtsch
>


--
------------------------------------------------------------------------
1024D/DB9B8C1C B90B FBC3 A3A1 C71A 8E70 3F8C 75B8 8FFB DB9B 8C1C
Philip M. Gollucci (pgollucci [at] p6m7g8) c: 703.336.9354
VP Apache Infrastructure; Member, Apache Software Foundation
Committer, FreeBSD Foundation
Consultant, P6M7G8 Inc.
Sr. System Admin, Ridecharge Inc.

Work like you don't need the money,
love like you'll never get hurt,
and dance like nobody's watching.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


gozer at ectoplasm

Apr 2, 2010, 1:56 PM

Post #10 of 13 (2331 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On 10-03-31 10:59 , Torsten Förtsch wrote:
> On Wednesday 31 March 2010 16:43:04 Torsten Förtsch wrote:
>> I believe the IoFLUSH_off in the override function can be omitted since
>> this is standard for a new handle.
>>
> This appears to be true. This is now the final version of the patch. Are there
> any objections against applying it to trunk?

I am still having a look over that patch, and I would very much
appreciate seeing a test case for this known issue/bug.

--
Philippe M. Chiasson GPG: F9BFE0C2480E7680 1AE53631CB32A107 88C3A5A5
http://gozer.ectoplasm.org/ m/gozer\@(apache|cpan|ectoplasm)\.org/
Attachments: signature.asc (0.24 KB)


torsten.foertsch at gmx

Apr 4, 2010, 5:48 AM

Post #11 of 13 (2295 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Friday 02 April 2010 22:56:48 Philippe M. Chiasson wrote:
> I would very much
> appreciate seeing a test case for this known issue/bug.
>
Here are 2 test cases. The 2nd one is a bit stricter in that it requires a
file handle attribute ($.) to survive, not the file descriptor:

Index: t/response/TestModperl/stdfd.pm
===================================================================
--- t/response/TestModperl/stdfd.pm (revision 0)
+++ t/response/TestModperl/stdfd.pm (revision 0)
@@ -0,0 +1,41 @@
+package TestModperl::stdfd;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache2::RequestRec ();
+use Apache2::RequestIO ();
+use Apache2::SubRequest ();
+
+use Apache2::Const -compile => 'OK';
+
+sub fixup {
+ my $r = shift;
+
+ $r->handler($r->main ? 'perl-script' : 'modperl');
+ return Apache2::Const::OK;
+}
+
+sub handler {
+ my $r = shift;
+
+ return Apache2::Const::OK if $r->main;
+
+ my @fds=(fileno(STDIN), fileno(STDOUT));
+
+ $r->lookup_uri($r->uri)->run;
+
+ $r->print("1..2\n");
+ $r->print((fileno(STDIN)==$fds[0] ? '' : 'not ').
+ "ok 1 - fileno(STDIN)=".fileno(STDIN)." expected $fds[0]\n");
+ $r->print((fileno(STDOUT)==$fds[1] ? '' : 'not ').
+ "ok 1 - fileno(STDOUT)=".fileno(STDOUT)." expected $fds[1]\n");
+
+ return Apache2::Const::OK;
+}
+
+1;
+__DATA__
+PerlModule TestModperl::stdfd
+PerlFixupHandler TestModperl::stdfd::fixup
+PerlResponseHandler TestModperl::stdfd


Index: t/response/TestModperl/stdfd2.pm
===================================================================
--- t/response/TestModperl/stdfd2.pm (revision 0)
+++ t/response/TestModperl/stdfd2.pm (revision 0)
@@ -0,0 +1,44 @@
+package TestModperl::stdfd2;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache2::RequestRec ();
+use Apache2::RequestIO ();
+use Apache2::SubRequest ();
+
+use Apache2::Const -compile => 'OK';
+
+sub fixup {
+ my $r = shift;
+
+ $r->handler($r->main ? 'perl-script' : 'modperl');
+ return Apache2::Const::OK;
+}
+
+sub handler {
+ my $r = shift;
+
+ return Apache2::Const::OK if $r->main;
+
+ local *STDIN;
+ open STDIN, '<', $INC{'TestModperl/stdfd2.pm'}
+ or die "Cannot open $INC{'TestModperl/stdfd2.pm'}";
+ scalar readline STDIN for(1..2);
+
+ my $expected=$.;
+
+ $r->lookup_uri($r->uri)->run;
+
+ $r->print("1..1\n");
+ $r->print(($.==$expected ? '' : 'not ').
+ "ok 1 - \$.=$. expected $expected\n");
+
+ return Apache2::Const::OK;
+}
+
+1;
+__DATA__
+PerlModule TestModperl::stdfd2
+PerlFixupHandler TestModperl::stdfd2::fixup
+PerlResponseHandler TestModperl::stdfd2


Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


torsten.foertsch at gmx

Apr 4, 2010, 9:43 AM

Post #12 of 13 (2291 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Wednesday 31 March 2010 16:43:04 Torsten Förtsch wrote:
> This one is much simpler.
>
This is another idea to solve the problem. We used to save and restore the
file handle. Why not simply localize it?

The caller of the override/restore functions already creates the opening and
closing braces:

/* need to create a block around the IO setup so the temp vars
* will be automatically cleaned up when we are done with IO */
ENTER;SAVETMPS;
h_stdin = modperl_io_override_stdin(aTHX_ r);
h_stdout = modperl_io_override_stdout(aTHX_ r);
...
modperl_io_restore_stdin(aTHX_ h_stdin);
modperl_io_restore_stdout(aTHX_ h_stdout);
FREETMPS;LEAVE;

So the only thing the overriding function has to do is

dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
save_gp(handle, 1);

The restoring function does noting to restore the handle. It is left to perl.

Would that be better than messing with the perlio internals?

The patch below implements the idea for the perlio case. But I think it can be
used in the tie case as well. Thus, the code can be simplified and a few
#ifdefs can be eliminated.

Opinions?

How do I build a modperl that uses tied IO?

Index: src/modules/perl/modperl_io.c
===================================================================
--- src/modules/perl/modperl_io.c (revision 930668)
+++ src/modules/perl/modperl_io.c (working copy)
@@ -104,137 +104,36 @@
sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
}

-MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+MP_INLINE static void
+modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
{
- dHANDLE("STDIN");
+ dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
int status;
- GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDIN is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
+ save_gp(handle, 1);

- /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
- status = do_open(handle_save, "<&STDIN", 7, FALSE,
- O_RDONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!",
TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDIN must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
- }
-
sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
- 0, Nullfp, sv, 1);
+ status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
+ 9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
+ Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

- MP_TRACE_o(MP_FUNC, "end");
-
- return handle_save;
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");
}

-/* XXX: refactor to merge with the previous function */
-MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+MP_INLINE static void
+modperl_io_perlio_restore_stdhandle(pTHX_ int mode)
{
- dHANDLE("STDOUT");
- int status;
- GV *handle_save = (GV*)Nullsv;
- SV *sv = sv_newmortal();
+ GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
+ FALSE, SVt_PVIO);

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDOUT is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
-
- /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
- status = do_open(handle_save, ">&STDOUT", 8, FALSE,
- O_WRONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!",
TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDOUT must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
- }
-
- sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
- 0, Nullfp, sv, 1);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-
- /* XXX: shouldn't we preserve the value STDOUT had before it was
- * overridden? */
- IoFLUSH_off(handle); /* STDOUT's $|=0 */
-
- return handle_save;
-
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
- /* close the overriding filehandle */
- do_close(handle_orig, FALSE);
-
- /*
- * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
- * close STDIN_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
-
- MP_TRACE_o(MP_FUNC, "restoring STDIN");
-
- if (do_open9(handle_orig, "<&", 2, FALSE,
- O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
-
- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
-
- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
* handler call, which may try to close STDOUT too. We will
@@ -242,7 +141,8 @@
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
- if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
+ if (mode != O_RDONLY &&
+ GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}
@@ -250,28 +150,26 @@
/* close the overriding filehandle */
do_close(handle_orig, FALSE);

- /*
- * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
- * close STDOUT_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
+}

- MP_TRACE_o(MP_FUNC, "restoring STDOUT");
+MP_INLINE void modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+{
+ modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
+}

- if (do_open9(handle_orig, ">&", 2, FALSE,
- O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
+MP_INLINE void modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+{
+ modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
+}

- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
+MP_INLINE void modperl_io_perlio_restore_stdin(pTHX)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ O_RDONLY);
+}

- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
+MP_INLINE void modperl_io_perlio_restore_stdout(pTHX)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ O_WRONLY);
}
+
Index: src/modules/perl/modperl_io.h
===================================================================
--- src/modules/perl/modperl_io.h (revision 930668)
+++ src/modules/perl/modperl_io.h (working copy)
@@ -51,13 +51,13 @@

MP_INLINE void modperl_io_handle_untie(pTHX_ GV *handle);

-MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r);
+MP_INLINE void modperl_io_perlio_override_stdin(pTHX_ request_rec *r);

-MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r);
+MP_INLINE void modperl_io_perlio_override_stdout(pTHX_ request_rec *r);

-MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle);
+MP_INLINE void modperl_io_perlio_restore_stdin(pTHX);

-MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle);
+MP_INLINE void modperl_io_perlio_restore_stdout(pTHX);

#if defined(MP_IO_TIE_SFIO)
/* XXX */
Index: src/modules/perl/mod_perl.c
===================================================================
--- src/modules/perl/mod_perl.c (revision 930669)
+++ src/modules/perl/mod_perl.c (working copy)
@@ -1056,7 +1056,6 @@
int modperl_response_handler_cgi(request_rec *r)
{
MP_dDCFG;
- GV *h_stdin, *h_stdout;
apr_status_t retval, rc;
MP_dRCFG;
#ifdef USE_ITHREADS
@@ -1091,8 +1090,8 @@
/* need to create a block around the IO setup so the temp vars
* will be automatically cleaned up when we are done with IO */
ENTER;SAVETMPS;
- h_stdin = modperl_io_override_stdin(aTHX_ r);
- h_stdout = modperl_io_override_stdout(aTHX_ r);
+ modperl_io_override_stdin(aTHX_ r);
+ modperl_io_override_stdout(aTHX_ r);

modperl_env_request_tie(aTHX_ r);

@@ -1102,8 +1101,8 @@

modperl_perl_global_request_restore(aTHX_ r);

- modperl_io_restore_stdin(aTHX_ h_stdin);
- modperl_io_restore_stdout(aTHX_ h_stdout);
+ modperl_io_restore_stdin(aTHX);
+ modperl_io_restore_stdout(aTHX);
FREETMPS;LEAVE;

#ifdef USE_ITHREADS


Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe [at] perl
For additional commands, e-mail: dev-help [at] perl


torsten.foertsch at gmx

Apr 7, 2010, 8:08 AM

Post #13 of 13 (2181 views)
Permalink
Re: [patch]avoid closing fd 0/1 [In reply to]

On Sunday 04 April 2010 18:43:29 Torsten Förtsch wrote:
> This is another idea to solve the problem. We used to save and restore the
> file handle. Why not simply localize it?
>
[...]
> Opinions?
>
> How do I build a modperl that uses tied IO?
>
This version compiles cleanly and passes all tests for a perl 5.10.1 compiled
with and without useperlio.

Index: src/modules/perl/modperl_io.c
===================================================================
--- src/modules/perl/modperl_io.c (revision 931462)
+++ src/modules/perl/modperl_io.c (working copy)
@@ -104,137 +104,36 @@
sv_unmagic(TIEHANDLE_SV(handle), PERL_MAGIC_tiedscalar);
}

-MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+MP_INLINE static void
+modperl_io_perlio_override_stdhandle(pTHX_ request_rec *r, int mode)
{
- dHANDLE("STDIN");
+ dHANDLE(mode == O_RDONLY ? "STDIN" : "STDOUT");
int status;
- GV *handle_save = (GV*)Nullsv;
SV *sv = sv_newmortal();

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDIN is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
+ save_gp(handle, 1);

- /* open my $oldout, "<&STDIN" or die "Can't dup STDIN: $!"; */
- status = do_open(handle_save, "<&STDIN", 7, FALSE,
- O_RDONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDIN: %" SVf, get_sv("!",
TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDIN must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
- }
-
sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, "<:Apache2", 9, FALSE, O_RDONLY,
- 0, Nullfp, sv, 1);
+ status = do_open9(handle, mode == O_RDONLY ? "<:Apache2" : ">:Apache2",
+ 9, FALSE, mode, 0, Nullfp, sv, 1);
if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDIN: %" SVf, get_sv("!", TRUE));
+ Perl_croak(aTHX_ "Failed to open STD%s: %" SVf,
+ mode == O_RDONLY ? "IN" : "OUT", get_sv("!", TRUE));
}

- MP_TRACE_o(MP_FUNC, "end");
-
- return handle_save;
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode==O_RDONLY ? "IN" : "OUT");
}

-/* XXX: refactor to merge with the previous function */
-MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+MP_INLINE static void
+modperl_io_perlio_restore_stdhandle(pTHX_ int mode)
{
- dHANDLE("STDOUT");
- int status;
- GV *handle_save = (GV*)Nullsv;
- SV *sv = sv_newmortal();
+ GV *handle_orig = gv_fetchpv(mode == O_RDONLY ? "STDIN" : "STDOUT",
+ FALSE, SVt_PVIO);

- MP_TRACE_o(MP_FUNC, "start");
+ MP_TRACE_o(MP_FUNC, "start STD%s", mode == O_RDONLY ? "IN" : "OUT");

- /* if STDOUT is open, dup it, to be restored at the end of response */
- if (handle && SvTYPE(handle) == SVt_PVGV &&
- IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
- handle_save = gv_fetchpv(Perl_form(aTHX_
- "Apache2::RequestIO::_GEN_%ld",
- (long)PL_gensym++),
- TRUE, SVt_PVIO);
-
- /* open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; */
- status = do_open(handle_save, ">&STDOUT", 8, FALSE,
- O_WRONLY, 0, Nullfp);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to dup STDOUT: %" SVf, get_sv("!",
TRUE));
- }
-
- /* similar to PerlIO::scalar, the PerlIO::Apache layer doesn't
- * have file descriptors, so STDOUT must be closed before it can
- * be reopened */
- do_close(handle, TRUE);
- }
-
- sv_setref_pv(sv, "Apache2::RequestRec", (void*)r);
- status = do_open9(handle, ">:Apache2", 9, FALSE, O_WRONLY,
- 0, Nullfp, sv, 1);
- if (status == 0) {
- Perl_croak(aTHX_ "Failed to open STDOUT: %" SVf, get_sv("!", TRUE));
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-
- /* XXX: shouldn't we preserve the value STDOUT had before it was
- * overridden? */
- IoFLUSH_off(handle); /* STDOUT's $|=0 */
-
- return handle_save;
-
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDIN", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
- /* close the overriding filehandle */
- do_close(handle_orig, FALSE);
-
- /*
- * open STDIN, "<&STDIN_SAVED" or die "Can't dup STDIN_SAVED: $!";
- * close STDIN_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
-
- MP_TRACE_o(MP_FUNC, "restoring STDIN");
-
- if (do_open9(handle_orig, "<&", 2, FALSE,
- O_RDONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
-
- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
-
- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDIN: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
-}
-
-MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
-{
- GV *handle_orig = gv_fetchpv("STDOUT", FALSE, SVt_PVIO);
-
- MP_TRACE_o(MP_FUNC, "start");
-
/* since closing unflushed STDOUT may trigger a subrequest
* (e.g. via mod_include), resulting in potential another response
* handler call, which may try to close STDOUT too. We will
@@ -242,7 +141,8 @@
* level STDOUT is attempted to be closed. To prevent this
* situation always explicitly flush STDOUT, before reopening it.
*/
- if (GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
+ if (mode != O_RDONLY &&
+ GvIOn(handle_orig) && IoOFP(GvIOn(handle_orig)) &&
(PerlIO_flush(IoOFP(GvIOn(handle_orig))) == -1)) {
Perl_croak(aTHX_ "Failed to flush STDOUT: %" SVf, get_sv("!", TRUE));
}
@@ -250,28 +150,28 @@
/* close the overriding filehandle */
do_close(handle_orig, FALSE);

- /*
- * open STDOUT, ">&STDOUT_SAVED" or die "Can't dup STDOUT_SAVED: $!";
- * close STDOUT_SAVED;
- */
- if (handle != (GV*)Nullsv) {
- SV *err = Nullsv;
+ MP_TRACE_o(MP_FUNC, "end STD%s", mode == O_RDONLY ? "IN" : "OUT");
+}

- MP_TRACE_o(MP_FUNC, "restoring STDOUT");
+MP_INLINE GV *modperl_io_perlio_override_stdin(pTHX_ request_rec *r)
+{
+ modperl_io_perlio_override_stdhandle(aTHX_ r, O_RDONLY);
+ return NULL;
+}

- if (do_open9(handle_orig, ">&", 2, FALSE,
- O_WRONLY, 0, Nullfp, (SV*)handle, 1) == 0) {
- err = get_sv("!", TRUE);
- }
+MP_INLINE GV *modperl_io_perlio_override_stdout(pTHX_ request_rec *r)
+{
+ modperl_io_perlio_override_stdhandle(aTHX_ r, O_WRONLY);
+ return NULL;
+}

- do_close(handle, FALSE);
- (void)hv_delete(gv_stashpv("Apache2::RequestIO", TRUE),
- GvNAME(handle), GvNAMELEN(handle), G_DISCARD);
+MP_INLINE void modperl_io_perlio_restore_stdin(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ O_RDONLY);
+}

- if (err != Nullsv) {
- Perl_croak(aTHX_ "Failed to restore STDOUT: %" SVf, err);
- }
- }
-
- MP_TRACE_o(MP_FUNC, "end");
+MP_INLINE void modperl_io_perlio_restore_stdout(pTHX_ GV *handle)
+{
+ modperl_io_perlio_restore_stdhandle(aTHX_ O_WRONLY);
}
+
Index: t/response/TestModperl/stdfd.pm
===================================================================
--- t/response/TestModperl/stdfd.pm (revision 0)
+++ t/response/TestModperl/stdfd.pm (revision 0)
@@ -0,0 +1,41 @@
+package TestModperl::stdfd;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache2::RequestRec ();
+use Apache2::RequestIO ();
+use Apache2::SubRequest ();
+
+use Apache2::Const -compile => 'OK';
+
+sub fixup {
+ my $r = shift;
+
+ $r->handler($r->main ? 'perl-script' : 'modperl');
+ return Apache2::Const::OK;
+}
+
+sub handler {
+ my $r = shift;
+
+ return Apache2::Const::OK if $r->main;
+
+ my @fds=(fileno(STDIN), fileno(STDOUT));
+
+ $r->lookup_uri($r->uri)->run;
+
+ $r->print("1..2\n");
+ $r->print((fileno(STDIN)==$fds[0] ? '' : 'not ').
+ "ok 1 - fileno(STDIN)=".fileno(STDIN)." expected $fds[0]\n");
+ $r->print((fileno(STDOUT)==$fds[1] ? '' : 'not ').
+ "ok 2 - fileno(STDOUT)=".fileno(STDOUT)." expected $fds[1]\n");
+
+ return Apache2::Const::OK;
+}
+
+1;
+__DATA__
+PerlModule TestModperl::stdfd
+PerlFixupHandler TestModperl::stdfd::fixup
+PerlResponseHandler TestModperl::stdfd
Index: t/response/TestModperl/stdfd2.pm
===================================================================
--- t/response/TestModperl/stdfd2.pm (revision 0)
+++ t/response/TestModperl/stdfd2.pm (revision 0)
@@ -0,0 +1,44 @@
+package TestModperl::stdfd2;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache2::RequestRec ();
+use Apache2::RequestIO ();
+use Apache2::SubRequest ();
+
+use Apache2::Const -compile => 'OK';
+
+sub fixup {
+ my $r = shift;
+
+ $r->handler($r->main ? 'perl-script' : 'modperl');
+ return Apache2::Const::OK;
+}
+
+sub handler {
+ my $r = shift;
+
+ return Apache2::Const::OK if $r->main;
+
+ local *STDIN;
+ open STDIN, '<', $INC{'TestModperl/stdfd2.pm'}
+ or die "Cannot open $INC{'TestModperl/stdfd2.pm'}";
+ scalar readline STDIN for(1..2);
+
+ my $expected=$.;
+
+ $r->lookup_uri($r->uri)->run;
+
+ $r->print("1..1\n");
+ $r->print(($.==$expected ? '' : 'not ').
+ "ok 1 - \$.=$. expected $expected\n");
+
+ return Apache2::Const::OK;
+}
+
+1;
+__DATA__
+PerlModule TestModperl::stdfd2
+PerlFixupHandler TestModperl::stdfd2::fixup
+PerlResponseHandler TestModperl::stdfd2

Torsten Förtsch

--
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net
Attachments: modperl_io2.patch (9.75 KB)

ModPerl dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.