perl-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Torsten Förtsch <torsten.foert...@gmx.net>
Subject Re: [patch]avoid closing fd 0/1
Date Wed, 31 Mar 2010 14:43:04 GMT
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

Mime
View raw message