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-unsubscr...@perl.apache.org
For additional commands, e-mail: dev-h...@perl.apache.org

Reply via email to