Skip to content

Commit

Permalink
Revert "[perl #117855] Store CopFILEGV in a pad under ithreads"
Browse files Browse the repository at this point in the history
This reverts commit c82ecf3.

It turn out to be faulty, because a location shared betweens threads
(the cop) was holding a reference count on a pad entry in a particu-
lar thread.  So when you free the cop, how do you know where to do
SvREFCNT_dec?

In reverting c82ecf3, this commit still preserves the bug fix from
1311cfc, but shifts it around.
  • Loading branch information
Father Chrysostomos committed Aug 10, 2013
1 parent 449dd03 commit 1dc74fd
Show file tree
Hide file tree
Showing 19 changed files with 69 additions and 161 deletions.
2 changes: 1 addition & 1 deletion MANIFEST
Expand Up @@ -3870,7 +3870,7 @@ ext/XS-APItest/t/cleanup.t test stack behaviour on unwinding
ext/XS-APItest/t/clone-with-stack.t test clone with CLONEf_COPY_STACKS works
ext/XS-APItest/t/cophh.t test COPHH API
ext/XS-APItest/t/coplabel.t test cop_*_label
ext/XS-APItest/t/cop.t test other cop stuff
ext/XS-APItest/t/copstash.t test alloccopstash
ext/XS-APItest/t/copyhints.t test hv_copy_hints_hv() API
ext/XS-APItest/t/customop.t XS::APItest: tests for custom ops
ext/XS-APItest/t/eval-filter.t Simple source filter/eval test
Expand Down
49 changes: 35 additions & 14 deletions cop.h
Expand Up @@ -389,8 +389,7 @@ struct cop {
#ifdef USE_ITHREADS
PADOFFSET cop_stashoff; /* offset into PL_stashpad, for the
package the line was compiled in */
PADOFFSET cop_filegvoff; /* PL_filegv offset, for the file name the
following line # is from */
char * cop_file; /* file name the following line # is from */
#else
HV * cop_stash; /* package line was compiled in */
GV * cop_filegv; /* file the following line # is from */
Expand All @@ -405,32 +404,54 @@ struct cop {
};

#ifdef USE_ITHREADS
# define CopFILEGV(c) PL_filegvpad[(c)->cop_filegvoff]
# define CopFILEGV_set(c,gv) ((c)->cop_filegvoff = (gv) \
? allocfilegv((GV *)SvREFCNT_inc_NN(gv)) \
: 0)
# define CopFILE(c) ((c)->cop_file)
# define CopFILEGV(c) (CopFILE(c) \
? gv_fetchfile(CopFILE(c)) : NULL)

# ifdef NETWARE
# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv))
# define CopFILE_setn(c,pv,l) ((c)->cop_file = savepv((pv),(l)))
# else
# define CopFILE_set(c,pv) ((c)->cop_file = savesharedpv(pv))
# define CopFILE_setn(c,pv,l) ((c)->cop_file = savesharedpvn((pv),(l)))
# endif

# define CopFILESV(c) (CopFILE(c) \
? GvSV(gv_fetchfile(CopFILE(c))) : NULL)
# define CopFILEAV(c) (CopFILE(c) \
? GvAV(gv_fetchfile(CopFILE(c))) : NULL)
# define CopFILEAVx(c) (assert_(CopFILE(c)) \
GvAV(gv_fetchfile(CopFILE(c))))

# define CopSTASH(c) PL_stashpad[(c)->cop_stashoff]
# define CopSTASH_set(c,hv) ((c)->cop_stashoff = (hv) \
? alloccopstash(hv) \
: 0)
# define CopFILE_free(c) S_CopFILE_free(aTHX_ c)
# ifdef NETWARE
# define CopFILE_free(c) SAVECOPFILE_FREE(c)
# else
# define CopFILE_free(c) (PerlMemShared_free(CopFILE(c)),(CopFILE(c) = NULL))
# endif
#else
# define CopFILEGV(c) ((c)->cop_filegv)
# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv))
# define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv))
# define CopFILE_setn(c,pv,l) CopFILEGV_set((c), gv_fetchfile_flags((pv),(l),0))
# define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : NULL)
# define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : NULL)
# ifdef DEBUGGING
# define CopFILEAVx(c) (assert(CopFILEGV(c)), GvAV(CopFILEGV(c)))
# else
# define CopFILEAVx(c) (GvAV(CopFILEGV(c)))
# endif
# define CopFILE(c) (CopFILEGV(c) \
? GvNAME(CopFILEGV(c))+2 : NULL)
# define CopSTASH(c) ((c)->cop_stash)
# define CopSTASH_set(c,hv) ((c)->cop_stash = (hv))
# define CopFILE_free(c) (SvREFCNT_dec(CopFILEGV(c)),(CopFILEGV(c) = NULL))

#endif /* USE_ITHREADS */

#define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv))
#define CopFILE_setn(c,pv,l) CopFILEGV_set((c), gv_fetchfile_flags((pv),(l),0))
#define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : NULL)
#define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : NULL)
#define CopFILEAVx(c) (assert_(CopFILEGV(c)) GvAV(CopFILEGV(c)))
#define CopFILE(c) (CopFILEGV(c) \
? GvNAME(CopFILEGV(c))+2 : NULL)
#define CopSTASHPV(c) (CopSTASH(c) ? HvNAME_get(CopSTASH(c)) : NULL)
/* cop_stash is not refcounted */
#define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD))
Expand Down
5 changes: 0 additions & 5 deletions embed.fnc
Expand Up @@ -1024,7 +1024,6 @@ p |PADOFFSET|allocmy |NN const char *const name|const STRLEN len\
|const U32 flags
#ifdef USE_ITHREADS
AMp |PADOFFSET|alloccopstash|NN HV *hv
AMp |PADOFFSET|allocfilegv |NN GV *gv
#endif
: Used in perly.y
pR |OP* |oopsAV |NN OP* o
Expand Down Expand Up @@ -2660,8 +2659,4 @@ op |void |populate_isa |NN const char *name|STRLEN len|...
Xop |bool |feature_is_enabled|NN const char *const name \
|STRLEN namelen

: Some static inline functions that implement macros need predeclaration
: because they are used inside other static inline functions.
Aoi |void |SvREFCNT_dec_NN|NN SV *sv

: ex: set ts=8 sts=4 sw=4 noet:
1 change: 0 additions & 1 deletion embed.h
Expand Up @@ -806,7 +806,6 @@
#endif
#if defined(USE_ITHREADS)
#define alloccopstash(a) Perl_alloccopstash(aTHX_ a)
#define allocfilegv(a) Perl_allocfilegv(aTHX_ a)
#define any_dup(a,b) Perl_any_dup(aTHX_ a,b)
#define cx_dup(a,b,c,d) Perl_cx_dup(aTHX_ a,b,c,d)
#define dirp_dup(a,b) Perl_dirp_dup(aTHX_ a,b)
Expand Down
3 changes: 0 additions & 3 deletions embedvar.h
Expand Up @@ -146,9 +146,6 @@
#define PL_exitlist (vTHX->Iexitlist)
#define PL_exitlistlen (vTHX->Iexitlistlen)
#define PL_fdpid (vTHX->Ifdpid)
#define PL_filegvpad (vTHX->Ifilegvpad)
#define PL_filegvpadix (vTHX->Ifilegvpadix)
#define PL_filegvpadmax (vTHX->Ifilegvpadmax)
#define PL_filemode (vTHX->Ifilemode)
#define PL_firstgv (vTHX->Ifirstgv)
#define PL_forkprocess (vTHX->Iforkprocess)
Expand Down
2 changes: 0 additions & 2 deletions ext/B/B.pm
Expand Up @@ -1228,8 +1228,6 @@ Since perl 5.17.1
=item file
=item filegvoff (threaded only)
=item cop_seq
=item arybase
Expand Down
11 changes: 1 addition & 10 deletions ext/B/B.xs
Expand Up @@ -682,11 +682,7 @@ struct OP_methods {
#ifdef USE_ITHREADS
STR_WITH_LEN("pmoffset"),IVp, offsetof(struct pmop, op_pmoffset),/*20*/
STR_WITH_LEN("filegv"), op_offset_special, 0, /*21*/
# if PERL_VERSION < 19
STR_WITH_LEN("file"), char_pp, offsetof(struct cop, cop_file), /*22*/
# else
STR_WITH_LEN("file"), op_offset_special, 0, /*22*/
# endif
STR_WITH_LEN("stash"), op_offset_special, 0, /*23*/
# if PERL_VERSION < 17
STR_WITH_LEN("stashpv"), char_pp, offsetof(struct cop, cop_stashpv), /*24*/
Expand Down Expand Up @@ -732,11 +728,6 @@ struct OP_methods {
STR_WITH_LEN("folded"), op_offset_special, 0, /*50*/
#endif
#endif
#if PERL_VERSION < 19 || !defined(USE_ITHREADS)
STR_WITH_LEN("filegvoff"),op_offset_special, 0, /*51*/
#else
STR_WITH_LEN("filegvoff"),PADOFFSETp,offsetof(struct cop, cop_filegvoff),/*51*/
#endif
};

#include "const-c.inc"
Expand Down Expand Up @@ -1040,7 +1031,7 @@ next(o)
ret = make_sv_object(aTHX_ (SV *)CopFILEGV((COP*)o));
break;
#endif
#if !defined(USE_ITHREADS) || PERL_VERSION >= 19
#ifndef USE_ITHREADS
case 22: /* file */
ret = sv_2mortal(newSVpv(CopFILE((COP*)o), 0));
break;
Expand Down
7 changes: 0 additions & 7 deletions ext/XS-APItest/APItest.xs
Expand Up @@ -3387,13 +3387,6 @@ CODE:
OUTPUT:
RETVAL

bool
test_allocfilegv()
CODE:
RETVAL = PL_filegvpad[allocfilegv(PL_defgv)] == PL_defgv;
OUTPUT:
RETVAL

#endif

bool
Expand Down
3 changes: 1 addition & 2 deletions ext/XS-APItest/t/cop.t → ext/XS-APItest/t/copstash.t
Expand Up @@ -2,9 +2,8 @@ use Config;
use Test::More;
BEGIN { plan skip_all => 'no threads' unless $Config{useithreads} }

plan tests => 2;
plan tests => 1;

use XS::APItest;

ok test_alloccopstash;
ok test_allocfilegv;
9 changes: 6 additions & 3 deletions gv.c
Expand Up @@ -2105,9 +2105,12 @@ Perl_gv_check(pTHX_ HV *stash)
continue;
file = GvFILE(gv);
CopLINE_set(PL_curcop, GvLINE(gv));
/* set file name for warning */
CopFILE_setn(PL_curcop, file, HEK_LEN(GvFILE_HEK(gv)));
SvREFCNT_dec(CopFILEGV(PL_curcop));
#ifdef USE_ITHREADS
CopFILE(PL_curcop) = (char *)file; /* set for warning */
#else
CopFILEGV(PL_curcop)
= gv_fetchfile_flags(file, HEK_LEN(GvFILE_HEK(gv)), 0);
#endif
Perl_warner(aTHX_ packWARN(WARN_ONCE),
"Name \"%"HEKf"::%"HEKf
"\" used only once: possible typo",
Expand Down
15 changes: 0 additions & 15 deletions inline.h
Expand Up @@ -23,20 +23,6 @@ S_av_top_index(pTHX_ AV *av)
return AvFILL(av);
}

/* ------------------------------- cop.h ------------------------------ */

#ifdef USE_ITHREADS
PERL_STATIC_INLINE void
S_CopFILE_free(pTHX_ COP * const c)
{
GV * const gv = CopFILEGV(c);
if (!gv) return;
if (SvREFCNT(gv) == 1) PL_filegvpad[c->cop_filegvoff] = NULL;
SvREFCNT_dec_NN(gv);
c->cop_filegvoff = 0;
}
#endif

/* ------------------------------- cv.h ------------------------------- */

PERL_STATIC_INLINE I32 *
Expand Down Expand Up @@ -122,7 +108,6 @@ PERL_STATIC_INLINE void
S_SvREFCNT_dec_NN(pTHX_ SV *sv)
{
U32 rc = SvREFCNT(sv);
PERL_ARGS_ASSERT_SVREFCNT_DEC_NN;
if (LIKELY(rc > 1))
SvREFCNT(sv) = rc - 1;
else
Expand Down
3 changes: 0 additions & 3 deletions intrpvar.h
Expand Up @@ -657,9 +657,6 @@ PERLVAR(I, regex_padav, AV *) /* All regex objects, indexed via the
PERLVAR(I, stashpad, HV **) /* for CopSTASH */
PERLVARI(I, stashpadmax, PADOFFSET, 64)
PERLVARI(I, stashpadix, PADOFFSET, 0)
PERLVAR(I, filegvpad, GV **) /* for CopFILEGV */
PERLVARI(I, filegvpadmax, PADOFFSET, 64)
PERLVARI(I, filegvpadix, PADOFFSET, 0)
#endif

#ifdef USE_REENTRANT_API
Expand Down
3 changes: 0 additions & 3 deletions makedef.pl
Expand Up @@ -363,9 +363,6 @@ sub readvar {
PL_stashpad
PL_stashpadix
PL_stashpadmax
PL_filegvpad
PL_filegvpadix
PL_filegvpadmax
Perl_alloccopstash
Perl_allocfilegv
Perl_clone_params_del
Expand Down
66 changes: 15 additions & 51 deletions op.c
Expand Up @@ -634,64 +634,31 @@ C<PL_stashpad> for the stash passed to it.
*/

#ifdef USE_ITHREADS

PADOFFSET
S_alloc_global_pad_slot(pTHX_ SV *sv, svtype type, SV ***padp,
PADOFFSET *ixp, PADOFFSET *maxp)
Perl_alloccopstash(pTHX_ HV *hv)
{
PADOFFSET off = 0, o = 1;
bool found_slot = FALSE;
SV **pad = *padp;

if (pad[*ixp] == sv) return *ixp;
PERL_ARGS_ASSERT_ALLOCCOPSTASH;

if (PL_stashpad[PL_stashpadix] == hv) return PL_stashpadix;

for (; o < *maxp; ++o) {
if (pad[o] == sv) return *ixp = o;
if (!pad[o] || SvTYPE(pad[o]) != type)
for (; o < PL_stashpadmax; ++o) {
if (PL_stashpad[o] == hv) return PL_stashpadix = o;
if (!PL_stashpad[o] || SvTYPE(PL_stashpad[o]) != SVt_PVHV)
found_slot = TRUE, off = o;
}
if (!found_slot) {
Renew(*padp, *maxp + 10, SV *);
pad = *padp;
Zero(pad + *maxp, 10, SV *);
off = *maxp;
*maxp += 10;
Renew(PL_stashpad, PL_stashpadmax + 10, HV *);
Zero(PL_stashpad + PL_stashpadmax, 10, HV *);
off = PL_stashpadmax;
PL_stashpadmax += 10;
}

pad[*ixp = off] = sv;
PL_stashpad[PL_stashpadix = off] = hv;
return off;
}

PADOFFSET
Perl_alloccopstash(pTHX_ HV *hv)
{
PERL_ARGS_ASSERT_ALLOCCOPSTASH;
return S_alloc_global_pad_slot(aTHX_
(SV *)hv, SVt_PVHV, (SV ***)&PL_stashpad, &PL_stashpadix,
&PL_stashpadmax
);
}
#endif

/*
=for apidoc allocfilegv
Available only under threaded builds, this function allocates an entry in
C<PL_filegvpad> for the GV passed to it.
=cut
*/

#ifdef USE_ITHREADS
PADOFFSET
Perl_allocfilegv(pTHX_ GV *gv)
{
PERL_ARGS_ASSERT_ALLOCFILEGV;
return S_alloc_global_pad_slot(aTHX_
(SV *)gv, SVt_PVGV, (SV ***)&PL_filegvpad, &PL_filegvpadix,
&PL_filegvpadmax
);
}
#endif

/* free the body of an op without examining its contents.
Expand Down Expand Up @@ -5752,10 +5719,7 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
PL_parser->copline = NOLINE;
}
#ifdef USE_ITHREADS
/* While CopFILEGV_set does work under ithreads, this is faster, as it
avoids a linear scan of the filegv pad: */
if((cop->cop_filegvoff = PL_curcop->cop_filegvoff))
SvREFCNT_inc_void_NN(PL_filegvpad[cop->cop_filegvoff]);
CopFILE_set(cop, CopFILE(PL_curcop)); /* XXX share in a pvtable? */
#else
CopFILEGV_set(cop, CopFILEGV(PL_curcop));
#endif
Expand Down Expand Up @@ -10898,7 +10862,7 @@ Perl_rpeep(pTHX_ OP *o)
firstcop->cop_line = secondcop->cop_line;
#ifdef USE_ITHREADS
firstcop->cop_stashoff = secondcop->cop_stashoff;
firstcop->cop_filegvoff = secondcop->cop_filegvoff;
firstcop->cop_file = secondcop->cop_file;
#else
firstcop->cop_stash = secondcop->cop_stash;
firstcop->cop_filegv = secondcop->cop_filegv;
Expand All @@ -10910,7 +10874,7 @@ Perl_rpeep(pTHX_ OP *o)

#ifdef USE_ITHREADS
secondcop->cop_stashoff = 0;
secondcop->cop_filegvoff = 0;
secondcop->cop_file = NULL;
#else
secondcop->cop_stash = NULL;
secondcop->cop_filegv = NULL;
Expand Down
2 changes: 0 additions & 2 deletions perl.c
Expand Up @@ -286,7 +286,6 @@ perl_construct(pTHXx)
Perl_av_create_and_push(aTHX_ &PL_regex_padav, newSVpvs(""));
PL_regex_pad = AvARRAY(PL_regex_padav);
Newxz(PL_stashpad, PL_stashpadmax, HV *);
Newxz(PL_filegvpad, PL_filegvpadmax, GV *);
#endif
#ifdef USE_REENTRANT_API
Perl_reentrant_init(aTHX);
Expand Down Expand Up @@ -1093,7 +1092,6 @@ perl_destruct(pTHXx)

#ifdef USE_ITHREADS
Safefree(PL_stashpad); /* must come after sv_clean_all */
Safefree(PL_filegvpad);
#endif

AvREAL_off(PL_fdpid); /* no surviving entries */
Expand Down
10 changes: 0 additions & 10 deletions proto.h
Expand Up @@ -32,11 +32,6 @@ PERL_CALLCONV void Perl_Slab_Free(pTHX_ void *op)
#define PERL_ARGS_ASSERT_SLAB_FREE \
assert(op)

PERL_STATIC_INLINE void S_SvREFCNT_dec_NN(pTHX_ SV *sv)
__attribute__nonnull__(pTHX_1);
#define PERL_ARGS_ASSERT_SVREFCNT_DEC_NN \
assert(sv)

PERL_CALLCONV bool Perl__is_uni_FOO(pTHX_ const U8 classnum, const UV c)
__attribute__warn_unused_result__;

Expand Down Expand Up @@ -7651,11 +7646,6 @@ PERL_CALLCONV PADOFFSET Perl_alloccopstash(pTHX_ HV *hv)
#define PERL_ARGS_ASSERT_ALLOCCOPSTASH \
assert(hv)

PERL_CALLCONV PADOFFSET Perl_allocfilegv(pTHX_ GV *gv)
__attribute__nonnull__(pTHX_1);
#define PERL_ARGS_ASSERT_ALLOCFILEGV \
assert(gv)

PERL_CALLCONV void* Perl_any_dup(pTHX_ void* v, const PerlInterpreter* proto_perl)
__attribute__warn_unused_result__
__attribute__nonnull__(pTHX_2);
Expand Down

0 comments on commit 1dc74fd

Please sign in to comment.