diff options
author | Malcolm Beattie <mbeattie@sable.ox.ac.uk> | 1997-05-26 20:10:42 +0000 |
---|---|---|
committer | Malcolm Beattie <mbeattie@sable.ox.ac.uk> | 1997-05-26 20:10:42 +0000 |
commit | 5dc0d6134ebb76636f69238201dde15cec972fd0 (patch) | |
tree | 3f466c13b594ff662ce13454c90ecf35572088ea | |
parent | 5bc6513ddd9360f3cbfa6bf29425e38b658230f5 (diff) | |
parent | 9ed32d99bcab50ff8df392e9741dd3de08a596a4 (diff) | |
download | perl-5dc0d6134ebb76636f69238201dde15cec972fd0.tar.gz |
Integrate thrperl 5.003->5.004.
p4raw-id: //depot/perl@24
-rw-r--r-- | XSUB.h | 2 | ||||
-rw-r--r-- | av.c | 7 | ||||
-rw-r--r-- | cv.h | 10 | ||||
-rw-r--r-- | deb.c | 23 | ||||
-rw-r--r-- | doio.c | 10 | ||||
-rw-r--r-- | doop.c | 1 | ||||
-rw-r--r-- | dump.c | 156 | ||||
-rw-r--r-- | embed.h | 16 | ||||
-rw-r--r-- | global.sym | 4 | ||||
-rw-r--r-- | gv.c | 10 | ||||
-rw-r--r-- | hv.c | 2 | ||||
-rw-r--r-- | keywords.h | 492 | ||||
-rw-r--r-- | malloc.c | 8 | ||||
-rw-r--r-- | mg.c | 24 | ||||
-rw-r--r-- | op.c | 1509 | ||||
-rw-r--r-- | op.h | 14 | ||||
-rwxr-xr-x | opcode.pl | 4 | ||||
-rw-r--r-- | perl.c | 144 | ||||
-rw-r--r-- | perl.h | 31 | ||||
-rw-r--r-- | pp.h | 7 | ||||
-rw-r--r-- | pp_ctl.c | 117 | ||||
-rw-r--r-- | pp_hot.c | 151 | ||||
-rw-r--r-- | pp_sys.c | 12 | ||||
-rw-r--r-- | proto.h | 62 | ||||
-rw-r--r-- | regcomp.c | 20 | ||||
-rw-r--r-- | regexec.c | 3 | ||||
-rw-r--r-- | run.c | 31 | ||||
-rw-r--r-- | scope.c | 39 | ||||
-rw-r--r-- | sv.c | 56 | ||||
-rw-r--r-- | sv.h | 4 | ||||
-rw-r--r-- | thread.h | 235 | ||||
-rw-r--r-- | toke.c | 44 | ||||
-rw-r--r-- | util.c | 57 |
33 files changed, 2156 insertions, 1149 deletions
@@ -7,7 +7,7 @@ #endif #define dXSARGS \ - dSP; dMARK; \ + dTHR; dSP; dMARK; \ I32 ax = mark - stack_base + 1; \ I32 items = sp - mark @@ -30,8 +30,10 @@ AV* av; while (key) { sv = AvARRAY(av)[--key]; assert(sv); - if (sv != &sv_undef) + if (sv != &sv_undef) { + dTHR; (void)SvREFCNT_inc(sv); + } } key = AvARRAY(av) - AvALLOC(av); while (key) @@ -44,6 +46,7 @@ av_extend(av,key) AV *av; I32 key; { + dTHR; /* only necessary if we have to extend stack */ if (key > AvMAX(av)) { SV** ary; I32 tmp; @@ -134,6 +137,7 @@ I32 lval; if (SvRMAGICAL(av)) { if (mg_find((SV*)av,'P')) { + dTHR; sv = sv_newmortal(); mg_copy((SV*)av, sv, 0, key); Sv = sv; @@ -207,6 +211,7 @@ SV *val; ary = AvARRAY(av); if (AvFILL(av) < key) { if (!AvREAL(av)) { + dTHR; if (av == curstack && key > stack_sp - stack_base) stack_sp = stack_base + key; /* XPUSH in disguise */ do @@ -28,6 +28,11 @@ struct xpvcv { long xcv_depth; /* >= 2 indicates recursive call */ AV * xcv_padlist; CV * xcv_outside; +#ifdef USE_THREADS + pthread_mutex_t * xcv_mutexp; + pthread_cond_t * xcv_condp; /* signalled when owner leaves CV */ + struct thread * xcv_owner; /* current owner thread */ +#endif /* USE_THREADS */ U8 xcv_flags; }; @@ -43,6 +48,11 @@ struct xpvcv { #define CvDEPTH(sv) ((XPVCV*)SvANY(sv))->xcv_depth #define CvPADLIST(sv) ((XPVCV*)SvANY(sv))->xcv_padlist #define CvOUTSIDE(sv) ((XPVCV*)SvANY(sv))->xcv_outside +#ifdef USE_THREADS +#define CvMUTEXP(sv) ((XPVCV*)SvANY(sv))->xcv_mutexp +#define CvCONDP(sv) ((XPVCV*)SvANY(sv))->xcv_condp +#define CvOWNER(sv) ((XPVCV*)SvANY(sv))->xcv_owner +#endif /* USE_THREADS */ #define CvFLAGS(sv) ((XPVCV*)SvANY(sv))->xcv_flags #define CVf_CLONE 0x01 /* anon CV uses external lexicals */ @@ -27,12 +27,20 @@ void deb(pat,a1,a2,a3,a4,a5,a6,a7,a8) char *pat; { + dTHR; register I32 i; GV* gv = curcop->cop_filegv; +#ifdef USE_THREADS + PerlIO_printf(Perl_debug_log,"0x%lx (%s:%ld)\t", + (unsigned long) thr, + SvTYPE(gv) == SVt_PVGV ? SvPVX(GvSV(gv)) : "<free>", + (long)curcop->cop_line); +#else PerlIO_printf(Perl_debug_log, "(%s:%ld)\t", SvTYPE(gv) == SVt_PVGV ? SvPVX(GvSV(gv)) : "<free>", (long)curcop->cop_line); +#endif /* USE_THREADS */ for (i=0; i<dlevel; i++) PerlIO_printf(Perl_debug_log, "%c%c ",debname[i],debdelim[i]); PerlIO_printf(Perl_debug_log, pat,a1,a2,a3,a4,a5,a6,a7,a8); @@ -51,13 +59,21 @@ deb(pat, va_alist) va_dcl # endif { + dTHR; va_list args; register I32 i; GV* gv = curcop->cop_filegv; +#ifdef USE_THREADS + PerlIO_printf(Perl_debug_log, "0x%lx (%s:%ld)\t", + (unsigned long) thr, + SvTYPE(gv) == SVt_PVGV ? SvPVX(GvSV(gv)) : "<free>", + (long)curcop->cop_line); +#else PerlIO_printf(Perl_debug_log, "(%s:%ld)\t", SvTYPE(gv) == SVt_PVGV ? SvPVX(GvSV(gv)) : "<free>", (long)curcop->cop_line); +#endif /* USE_THREADS */ for (i=0; i<dlevel; i++) PerlIO_printf(Perl_debug_log, "%c%c ",debname[i],debdelim[i]); @@ -82,6 +98,7 @@ deb_growlevel() I32 debstackptrs() { + dTHR; PerlIO_printf(Perl_debug_log, "%8lx %8lx %8ld %8ld %8ld\n", (unsigned long)curstack, (unsigned long)stack_base, (long)*markstack_ptr, (long)(stack_sp-stack_base), @@ -95,6 +112,7 @@ debstackptrs() I32 debstack() { + dTHR; I32 top = stack_sp - stack_base; register I32 i = top - 30; I32 *markscan = markstack; @@ -106,7 +124,12 @@ debstack() if (*markscan >= i) break; +#ifdef USE_THREADS + PerlIO_printf(Perl_debug_log, i ? "0x%lx => ... " : "0x%lx => ", + (unsigned long) thr); +#else PerlIO_printf(Perl_debug_log, i ? " => ... " : " => "); +#endif /* USE_THREADS */ if (stack_base[0] != &sv_undef || stack_sp < stack_base) PerlIO_printf(Perl_debug_log, " [STACK UNDERFLOW!!!]\n"); do { @@ -384,6 +384,7 @@ register GV *gv; } filemode = 0; while (av_len(GvAV(gv)) >= 0) { + dTHR; STRLEN len; sv = av_shift(GvAV(gv)); SAVEFREESV(sv); @@ -621,6 +622,7 @@ bool do_eof(gv) GV *gv; { + dTHR; register IO *io; int ch; @@ -905,6 +907,7 @@ register SV **sp; char *tmps; if (sp > mark) { + dTHR; New(401,Argv, sp - mark + 1, char*); a = Argv; while (++mark <= sp) { @@ -1039,6 +1042,7 @@ I32 type; register SV **mark; register SV **sp; { + dTHR; register I32 val; register I32 val2; register I32 tot = 0; @@ -1292,6 +1296,7 @@ I32 optype; SV **mark; SV **sp; { + dTHR; key_t key; I32 n, flags; @@ -1327,6 +1332,7 @@ I32 optype; SV **mark; SV **sp; { + dTHR; SV *astr; char *a; I32 id, n, cmd, infosize, getinfo; @@ -1429,6 +1435,7 @@ SV **mark; SV **sp; { #ifdef HAS_MSG + dTHR; SV *mstr; char *mbuf; I32 id, msize, flags; @@ -1453,6 +1460,7 @@ SV **mark; SV **sp; { #ifdef HAS_MSG + dTHR; SV *mstr; char *mbuf; long mtype; @@ -1491,6 +1499,7 @@ SV **mark; SV **sp; { #ifdef HAS_SEM + dTHR; SV *opstr; char *opbuf; I32 id; @@ -1518,6 +1527,7 @@ SV **mark; SV **sp; { #ifdef HAS_SHM + dTHR; SV *mstr; char *mbuf, *shm; I32 id, mpos, msize; @@ -23,6 +23,7 @@ do_trans(sv,arg) SV *sv; OP *arg; { + dTHR; register short *tbl; register U8 *s; register U8 *send; @@ -31,6 +31,7 @@ static void dump(); void dump_all() { + dTHR; PerlIO_setlinebuf(Perl_debug_log); if (main_root) dump_op(main_root); @@ -41,6 +42,7 @@ void dump_packsubs(stash) HV* stash; { + dTHR; I32 i; HE *entry; @@ -100,36 +102,36 @@ dump_eval() } void -dump_op(op) -register OP *op; +dump_op(o) +register OP *o; { dump("{\n"); - if (op->op_seq) - PerlIO_printf(Perl_debug_log, "%-4d", op->op_seq); + if (o->op_seq) + PerlIO_printf(Perl_debug_log, "%-4d", o->op_seq); else PerlIO_printf(Perl_debug_log, " "); - dump("TYPE = %s ===> ", op_name[op->op_type]); - if (op->op_next) { - if (op->op_seq) - PerlIO_printf(Perl_debug_log, "%d\n", op->op_next->op_seq); + dump("TYPE = %s ===> ", op_name[o->op_type]); + if (o->op_next) { + if (o->op_seq) + PerlIO_printf(Perl_debug_log, "%d\n", o->op_next->op_seq); else - PerlIO_printf(Perl_debug_log, "(%d)\n", op->op_next->op_seq); + PerlIO_printf(Perl_debug_log, "(%d)\n", o->op_next->op_seq); } else PerlIO_printf(Perl_debug_log, "DONE\n"); dumplvl++; - if (op->op_targ) { - if (op->op_type == OP_NULL) - dump(" (was %s)\n", op_name[op->op_targ]); + if (o->op_targ) { + if (o->op_type == OP_NULL) + dump(" (was %s)\n", op_name[o->op_targ]); else - dump("TARG = %d\n", op->op_targ); + dump("TARG = %d\n", o->op_targ); } #ifdef DUMPADDR - dump("ADDR = 0x%lx => 0x%lx\n",op, op->op_next); + dump("ADDR = 0x%lx => 0x%lx\n",o, o->op_next); #endif - if (op->op_flags) { + if (o->op_flags) { SV *tmpsv = newSVpv("", 0); - switch (op->op_flags & OPf_WANT) { + switch (o->op_flags & OPf_WANT) { case OPf_WANT_VOID: sv_catpv(tmpsv, ",VOID"); break; @@ -143,58 +145,58 @@ register OP *op; sv_catpv(tmpsv, ",UNKNOWN"); break; } - if (op->op_flags & OPf_KIDS) + if (o->op_flags & OPf_KIDS) sv_catpv(tmpsv, ",KIDS"); - if (op->op_flags & OPf_PARENS) + if (o->op_flags & OPf_PARENS) sv_catpv(tmpsv, ",PARENS"); - if (op->op_flags & OPf_STACKED) + if (o->op_flags & OPf_STACKED) sv_catpv(tmpsv, ",STACKED"); - if (op->op_flags & OPf_REF) + if (o->op_flags & OPf_REF) sv_catpv(tmpsv, ",REF"); - if (op->op_flags & OPf_MOD) + if (o->op_flags & OPf_MOD) sv_catpv(tmpsv, ",MOD"); - if (op->op_flags & OPf_SPECIAL) + if (o->op_flags & OPf_SPECIAL) sv_catpv(tmpsv, ",SPECIAL"); dump("FLAGS = (%s)\n", SvCUR(tmpsv) ? SvPVX(tmpsv) + 1 : ""); SvREFCNT_dec(tmpsv); } - if (op->op_private) { + if (o->op_private) { SV *tmpsv = newSVpv("", 0); - if (op->op_type == OP_AASSIGN) { - if (op->op_private & OPpASSIGN_COMMON) + if (o->op_type == OP_AASSIGN) { + if (o->op_private & OPpASSIGN_COMMON) sv_catpv(tmpsv, ",COMMON"); } - else if (op->op_type == OP_SASSIGN) { - if (op->op_private & OPpASSIGN_BACKWARDS) + else if (o->op_type == OP_SASSIGN) { + if (o->op_private & OPpASSIGN_BACKWARDS) sv_catpv(tmpsv, ",BACKWARDS"); } - else if (op->op_type == OP_TRANS) { - if (op->op_private & OPpTRANS_SQUASH) + else if (o->op_type == OP_TRANS) { + if (o->op_private & OPpTRANS_SQUASH) sv_catpv(tmpsv, ",SQUASH"); - if (op->op_private & OPpTRANS_DELETE) + if (o->op_private & OPpTRANS_DELETE) sv_catpv(tmpsv, ",DELETE"); - if (op->op_private & OPpTRANS_COMPLEMENT) + if (o->op_private & OPpTRANS_COMPLEMENT) sv_catpv(tmpsv, ",COMPLEMENT"); } - else if (op->op_type == OP_REPEAT) { - if (op->op_private & OPpREPEAT_DOLIST) + else if (o->op_type == OP_REPEAT) { + if (o->op_private & OPpREPEAT_DOLIST) sv_catpv(tmpsv, ",DOLIST"); } - else if (op->op_type == OP_ENTERSUB || - op->op_type == OP_RV2SV || - op->op_type == OP_RV2AV || - op->op_type == OP_RV2HV || - op->op_type == OP_RV2GV || - op->op_type == OP_AELEM || - op->op_type == OP_HELEM ) + else if (o->op_type == OP_ENTERSUB || + o->op_type == OP_RV2SV || + o->op_type == OP_RV2AV || + o->op_type == OP_RV2HV || + o->op_type == OP_RV2GV || + o->op_type == OP_AELEM || + o->op_type == OP_HELEM ) { - if (op->op_type == OP_ENTERSUB) { - if (op->op_private & OPpENTERSUB_AMPER) + if (o->op_type == OP_ENTERSUB) { + if (o->op_private & OPpENTERSUB_AMPER) sv_catpv(tmpsv, ",AMPER"); - if (op->op_private & OPpENTERSUB_DB) + if (o->op_private & OPpENTERSUB_DB) sv_catpv(tmpsv, ",DB"); } - switch (op->op_private & OPpDEREF) { + switch (o->op_private & OPpDEREF) { case OPpDEREF_SV: sv_catpv(tmpsv, ",SV"); break; @@ -205,42 +207,42 @@ register OP *op; sv_catpv(tmpsv, ",HV"); break; } - if (op->op_type == OP_AELEM || op->op_type == OP_HELEM) { - if (op->op_private & OPpLVAL_DEFER) + if (o->op_type == OP_AELEM || o->op_type == OP_HELEM) { + if (o->op_private & OPpLVAL_DEFER) sv_catpv(tmpsv, ",LVAL_DEFER"); } else { - if (op->op_private & HINT_STRICT_REFS) + if (o->op_private & HINT_STRICT_REFS) sv_catpv(tmpsv, ",STRICT_REFS"); } } - else if (op->op_type == OP_CONST) { - if (op->op_private & OPpCONST_BARE) + else if (o->op_type == OP_CONST) { + if (o->op_private & OPpCONST_BARE) sv_catpv(tmpsv, ",BARE"); } - else if (op->op_type == OP_FLIP) { - if (op->op_private & OPpFLIP_LINENUM) + else if (o->op_type == OP_FLIP) { + if (o->op_private & OPpFLIP_LINENUM) sv_catpv(tmpsv, ",LINENUM"); } - else if (op->op_type == OP_FLOP) { - if (op->op_private & OPpFLIP_LINENUM) + else if (o->op_type == OP_FLOP) { + if (o->op_private & OPpFLIP_LINENUM) sv_catpv(tmpsv, ",LINENUM"); } - if (op->op_flags & OPf_MOD && op->op_private & OPpLVAL_INTRO) + if (o->op_flags & OPf_MOD && o->op_private & OPpLVAL_INTRO) sv_catpv(tmpsv, ",INTRO"); if (SvCUR(tmpsv)) dump("PRIVATE = (%s)\n", SvPVX(tmpsv) + 1); SvREFCNT_dec(tmpsv); } - switch (op->op_type) { + switch (o->op_type) { case OP_GVSV: case OP_GV: - if (cGVOP->op_gv) { + if (cGVOPo->op_gv) { SV *tmpsv = NEWSV(0,0); ENTER; SAVEFREESV(tmpsv); - gv_fullname3(tmpsv, cGVOP->op_gv, Nullch); + gv_fullname3(tmpsv, cGVOPo->op_gv, Nullch); dump("GV = %s\n", SvPV(tmpsv, na)); LEAVE; } @@ -248,41 +250,41 @@ register OP *op; dump("GV = NULL\n"); break; case OP_CONST: - dump("SV = %s\n", SvPEEK(cSVOP->op_sv)); + dump("SV = %s\n", SvPEEK(cSVOPo->op_sv)); break; case OP_NEXTSTATE: case OP_DBSTATE: - if (cCOP->cop_line) - dump("LINE = %d\n",cCOP->cop_line); - if (cCOP->cop_label) - dump("LABEL = \"%s\"\n",cCOP->cop_label); + if (cCOPo->cop_line) + dump("LINE = %d\n",cCOPo->cop_line); + if (cCOPo->cop_label) + dump("LABEL = \"%s\"\n",cCOPo->cop_label); break; case OP_ENTERLOOP: dump("REDO ===> "); - if (cLOOP->op_redoop) - PerlIO_printf(Perl_debug_log, "%d\n", cLOOP->op_redoop->op_seq); + if (cLOOPo->op_redoop) + PerlIO_printf(Perl_debug_log, "%d\n", cLOOPo->op_redoop->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); dump("NEXT ===> "); - if (cLOOP->op_nextop) - PerlIO_printf(Perl_debug_log, "%d\n", cLOOP->op_nextop->op_seq); + if (cLOOPo->op_nextop) + PerlIO_printf(Perl_debug_log, "%d\n", cLOOPo->op_nextop->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); dump("LAST ===> "); - if (cLOOP->op_lastop) - PerlIO_printf(Perl_debug_log, "%d\n", cLOOP->op_lastop->op_seq); + if (cLOOPo->op_lastop) + PerlIO_printf(Perl_debug_log, "%d\n", cLOOPo->op_lastop->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); break; case OP_COND_EXPR: dump("TRUE ===> "); - if (cCONDOP->op_true) - PerlIO_printf(Perl_debug_log, "%d\n", cCONDOP->op_true->op_seq); + if (cCONDOPo->op_true) + PerlIO_printf(Perl_debug_log, "%d\n", cCONDOPo->op_true->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); dump("FALSE ===> "); - if (cCONDOP->op_false) - PerlIO_printf(Perl_debug_log, "%d\n", cCONDOP->op_false->op_seq); + if (cCONDOPo->op_false) + PerlIO_printf(Perl_debug_log, "%d\n", cCONDOPo->op_false->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); break; @@ -291,22 +293,22 @@ register OP *op; case OP_OR: case OP_AND: dump("OTHER ===> "); - if (cLOGOP->op_other) - PerlIO_printf(Perl_debug_log, "%d\n", cLOGOP->op_other->op_seq); + if (cLOGOPo->op_other) + PerlIO_printf(Perl_debug_log, "%d\n", cLOGOPo->op_other->op_seq); else PerlIO_printf(Perl_debug_log, "DONE\n"); break; case OP_PUSHRE: case OP_MATCH: case OP_SUBST: - dump_pm((PMOP*)op); + dump_pm(cPMOPo); break; default: break; } - if (op->op_flags & OPf_KIDS) { + if (o->op_flags & OPf_KIDS) { OP *kid; - for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) dump_op(kid); } dumplvl--; @@ -50,6 +50,18 @@ #define av_store Perl_av_store #define av_undef Perl_av_undef #define av_unshift Perl_av_unshift +#define avhv_delete Perl_avhv_delete +#define avhv_delete_ent Perl_avhv_delete_ent +#define avhv_exists Perl_avhv_exists +#define avhv_exists_ent Perl_avhv_exists_ent +#define avhv_fetch Perl_avhv_fetch +#define avhv_fetch_ent Perl_avhv_fetch_ent +#define avhv_iterinit Perl_avhv_iterinit +#define avhv_iternext Perl_avhv_iternext +#define avhv_iternextsv Perl_avhv_iternextsv +#define avhv_iterval Perl_avhv_iterval +#define avhv_store Perl_avhv_store +#define avhv_store_ent Perl_avhv_store_ent #define band_amg Perl_band_amg #define bind_match Perl_bind_match #define block_end Perl_block_end @@ -264,6 +276,7 @@ #define ibcmp Perl_ibcmp #define ibcmp_locale Perl_ibcmp_locale #define in_my Perl_in_my +#define in_my_stash Perl_in_my_stash #define inc_amg Perl_inc_amg #define ingroup Perl_ingroup #define instr Perl_instr @@ -1295,6 +1308,7 @@ #define preambleav (curinterp->Ipreambleav) #define preambled (curinterp->Ipreambled) #define preprocess (curinterp->Ipreprocess) +#define restartav (curinterp->Irestartav) #define restartop (curinterp->Irestartop) #define rightgv (curinterp->Irightgv) #define rs (curinterp->Irs) @@ -1449,6 +1463,7 @@ #define Ipreambleav preambleav #define Ipreambled preambled #define Ipreprocess preprocess +#define Irestartav restartav #define Irestartop restartop #define Irightgv rightgv #define Irs rs @@ -1612,6 +1627,7 @@ #define preambleav Perl_preambleav #define preambled Perl_preambled #define preprocess Perl_preprocess +#define restartav Perl_restartav #define restartop Perl_restartop #define rightgv Perl_rightgv #define rs Perl_rs diff --git a/global.sym b/global.sym index 27d80c5dc3..219e9a518e 100644 --- a/global.sym +++ b/global.sym @@ -255,6 +255,7 @@ vtbl_glob vtbl_isa vtbl_isaelem vtbl_mglob +vtbl_mutex vtbl_nkeys vtbl_pack vtbl_packelem @@ -372,6 +373,7 @@ ck_split ck_subr ck_svconst ck_trunc +condpair_magic convert croak cv_ckproto @@ -492,6 +494,7 @@ hv_undef ibcmp ibcmp_locale ingroup +init_stacks instr intro_my intuit_more @@ -521,6 +524,7 @@ magic_getsig magic_gettaint magic_getuvar magic_len +magic_mutexfree magic_nextpack magic_set magic_setamagic @@ -420,6 +420,7 @@ char *nambeg; I32 add; I32 sv_type; { + dTHR; register char *name = nambeg; register GV *gv = 0; GV**gvp; @@ -820,6 +821,7 @@ GV *gv; IO * newIO() { + dTHR; IO *io; GV *iogv; @@ -836,6 +838,7 @@ void gv_check(stash) HV* stash; { + dTHR; register HE *entry; register I32 i; register GV *gv; @@ -963,6 +966,7 @@ bool Gv_AMupdate(stash) HV* stash; { + dTHR; GV** gvp; HV* hv; GV* gv; @@ -1126,6 +1130,7 @@ SV* right; int method; int flags; { + dTHR; MAGIC *mg; CV *cv; CV **cvp=NULL, **ocvp=NULL; @@ -1325,6 +1330,7 @@ int flags; || inc_dec_ass) RvDEEPCP(left); } { + dTHR; dSP; BINOP myop; SV* res; @@ -1342,7 +1348,7 @@ int flags; if (perldb && curstash != debstash) op->op_private |= OPpENTERSUB_DB; PUTBACK; - pp_pushmark(); + pp_pushmark(ARGS); EXTEND(sp, notfound + 5); PUSHs(lr>0? right: left); @@ -1354,7 +1360,7 @@ int flags; PUSHs((SV*)cv); PUTBACK; - if (op = pp_entersub()) + if (op = pp_entersub(ARGS)) runops(); LEAVE; SPAGAIN; @@ -100,6 +100,7 @@ I32 lval; if (SvRMAGICAL(hv)) { if (mg_find((SV*)hv,'P')) { + dTHR; sv = sv_newmortal(); mg_copy((SV*)hv, sv, key, klen); Sv = sv; @@ -511,6 +512,7 @@ U32 klen; if (SvRMAGICAL(hv)) { if (mg_find((SV*)hv,'P')) { + dTHR; sv = sv_newmortal(); mg_copy((SV*)hv, sv, key, klen); magic_existspack(sv, mg_find(sv, 'p')); diff --git a/keywords.h b/keywords.h index a6dabf3e61..7d7164945f 100644 --- a/keywords.h +++ b/keywords.h @@ -1,246 +1,248 @@ #define KEY_NULL 0 -#define KEY___LINE__ 1 -#define KEY___FILE__ 2 -#define KEY___DATA__ 3 -#define KEY___END__ 4 -#define KEY_AUTOLOAD 5 -#define KEY_BEGIN 6 -#define KEY_CORE 7 -#define KEY_DESTROY 8 -#define KEY_END 9 -#define KEY_EQ 10 -#define KEY_GE 11 -#define KEY_GT 12 -#define KEY_LE 13 -#define KEY_LT 14 -#define KEY_NE 15 -#define KEY_RESTART 16 -#define KEY_abs 17 -#define KEY_accept 18 -#define KEY_alarm 19 -#define KEY_and 20 -#define KEY_atan2 21 -#define KEY_bind 22 -#define KEY_binmode 23 -#define KEY_bless 24 -#define KEY_caller 25 -#define KEY_chdir 26 -#define KEY_chmod 27 -#define KEY_chomp 28 -#define KEY_chop 29 -#define KEY_chown 30 -#define KEY_chr 31 -#define KEY_chroot 32 -#define KEY_close 33 -#define KEY_closedir 34 -#define KEY_cmp 35 -#define KEY_connect 36 -#define KEY_continue 37 -#define KEY_cos 38 -#define KEY_crypt 39 -#define KEY_dbmclose 40 -#define KEY_dbmopen 41 -#define KEY_defined 42 -#define KEY_delete 43 -#define KEY_die 44 -#define KEY_do 45 -#define KEY_dump 46 -#define KEY_each 47 -#define KEY_else 48 -#define KEY_elsif 49 -#define KEY_endgrent 50 -#define KEY_endhostent 51 -#define KEY_endnetent 52 -#define KEY_endprotoent 53 -#define KEY_endpwent 54 -#define KEY_endservent 55 -#define KEY_eof 56 -#define KEY_eq 57 -#define KEY_eval 58 -#define KEY_exec 59 -#define KEY_exists 60 -#define KEY_exit 61 -#define KEY_exp 62 -#define KEY_fcntl 63 -#define KEY_fileno 64 -#define KEY_flock 65 -#define KEY_for 66 -#define KEY_foreach 67 -#define KEY_fork 68 -#define KEY_format 69 -#define KEY_formline 70 -#define KEY_ge 71 -#define KEY_getc 72 -#define KEY_getgrent 73 -#define KEY_getgrgid 74 -#define KEY_getgrnam 75 -#define KEY_gethostbyaddr 76 -#define KEY_gethostbyname 77 -#define KEY_gethostent 78 -#define KEY_getlogin 79 -#define KEY_getnetbyaddr 80 -#define KEY_getnetbyname 81 -#define KEY_getnetent 82 -#define KEY_getpeername 83 -#define KEY_getpgrp 84 -#define KEY_getppid 85 -#define KEY_getpriority 86 -#define KEY_getprotobyname 87 -#define KEY_getprotobynumber 88 -#define KEY_getprotoent 89 -#define KEY_getpwent 90 -#define KEY_getpwnam 91 -#define KEY_getpwuid 92 -#define KEY_getservbyname 93 -#define KEY_getservbyport 94 -#define KEY_getservent 95 -#define KEY_getsockname 96 -#define KEY_getsockopt 97 -#define KEY_glob 98 -#define KEY_gmtime 99 -#define KEY_goto 100 -#define KEY_grep 101 -#define KEY_gt 102 -#define KEY_hex 103 -#define KEY_if 104 -#define KEY_index 105 -#define KEY_int 106 -#define KEY_ioctl 107 -#define KEY_join 108 -#define KEY_keys 109 -#define KEY_kill 110 -#define KEY_last 111 -#define KEY_lc 112 -#define KEY_lcfirst 113 -#define KEY_le 114 -#define KEY_length 115 -#define KEY_link 116 -#define KEY_listen 117 -#define KEY_local 118 -#define KEY_localtime 119 -#define KEY_log 120 -#define KEY_lstat 121 -#define KEY_lt 122 -#define KEY_m 123 -#define KEY_map 124 -#define KEY_mkdir 125 -#define KEY_msgctl 126 -#define KEY_msgget 127 -#define KEY_msgrcv 128 -#define KEY_msgsnd 129 -#define KEY_my 130 -#define KEY_ne 131 -#define KEY_next 132 -#define KEY_no 133 -#define KEY_not 134 -#define KEY_oct 135 -#define KEY_open 136 -#define KEY_opendir 137 -#define KEY_or 138 -#define KEY_ord 139 -#define KEY_pack 140 -#define KEY_package 141 -#define KEY_pipe 142 -#define KEY_pop 143 -#define KEY_pos 144 -#define KEY_print 145 -#define KEY_printf 146 -#define KEY_prototype 147 -#define KEY_push 148 -#define KEY_q 149 -#define KEY_qq 150 -#define KEY_quotemeta 151 -#define KEY_qw 152 -#define KEY_qx 153 -#define KEY_rand 154 -#define KEY_read 155 -#define KEY_readdir 156 -#define KEY_readline 157 -#define KEY_readlink 158 -#define KEY_readpipe 159 -#define KEY_recv 160 -#define KEY_redo 161 -#define KEY_ref 162 -#define KEY_rename 163 -#define KEY_require 164 -#define KEY_reset 165 -#define KEY_return 166 -#define KEY_reverse 167 -#define KEY_rewinddir 168 -#define KEY_rindex 169 -#define KEY_rmdir 170 -#define KEY_s 171 -#define KEY_scalar 172 -#define KEY_seek 173 -#define KEY_seekdir 174 -#define KEY_select 175 -#define KEY_semctl 176 -#define KEY_semget 177 -#define KEY_semop 178 -#define KEY_send 179 -#define KEY_setgrent 180 -#define KEY_sethostent 181 -#define KEY_setnetent 182 -#define KEY_setpgrp 183 -#define KEY_setpriority 184 -#define KEY_setprotoent 185 -#define KEY_setpwent 186 -#define KEY_setservent 187 -#define KEY_setsockopt 188 -#define KEY_shift 189 -#define KEY_shmctl 190 -#define KEY_shmget 191 -#define KEY_shmread 192 -#define KEY_shmwrite 193 -#define KEY_shutdown 194 -#define KEY_sin 195 -#define KEY_sleep 196 -#define KEY_socket 197 -#define KEY_socketpair 198 -#define KEY_sort 199 -#define KEY_splice 200 -#define KEY_split 201 -#define KEY_sprintf 202 -#define KEY_sqrt 203 -#define KEY_srand 204 -#define KEY_stat 205 -#define KEY_study 206 -#define KEY_sub 207 -#define KEY_substr 208 -#define KEY_symlink 209 -#define KEY_syscall 210 -#define KEY_sysopen 211 -#define KEY_sysread 212 -#define KEY_system 213 -#define KEY_syswrite 214 -#define KEY_tell 215 -#define KEY_telldir 216 -#define KEY_tie 217 -#define KEY_tied 218 -#define KEY_time 219 -#define KEY_times 220 -#define KEY_tr 221 -#define KEY_truncate 222 -#define KEY_uc 223 -#define KEY_ucfirst 224 -#define KEY_umask 225 -#define KEY_undef 226 -#define KEY_unless 227 -#define KEY_unlink 228 -#define KEY_unpack 229 -#define KEY_unshift 230 -#define KEY_untie 231 -#define KEY_until 232 -#define KEY_use 233 -#define KEY_utime 234 -#define KEY_values 235 -#define KEY_vec 236 -#define KEY_wait 237 -#define KEY_waitpid 238 -#define KEY_wantarray 239 -#define KEY_warn 240 -#define KEY_while 241 -#define KEY_write 242 -#define KEY_x 243 -#define KEY_xor 244 -#define KEY_y 245 +#define KEY___FILE__ 1 +#define KEY___LINE__ 2 +#define KEY___PACKAGE__ 3 +#define KEY___DATA__ 4 +#define KEY___END__ 5 +#define KEY_AUTOLOAD 6 +#define KEY_BEGIN 7 +#define KEY_CORE 8 +#define KEY_DESTROY 9 +#define KEY_END 10 +#define KEY_EQ 11 +#define KEY_GE 12 +#define KEY_GT 13 +#define KEY_LE 14 +#define KEY_LT 15 +#define KEY_NE 16 +#define KEY_RESTART 17 +#define KEY_abs 18 +#define KEY_accept 19 +#define KEY_alarm 20 +#define KEY_and 21 +#define KEY_atan2 22 +#define KEY_bind 23 +#define KEY_binmode 24 +#define KEY_bless 25 +#define KEY_caller 26 +#define KEY_chdir 27 +#define KEY_chmod 28 +#define KEY_chomp 29 +#define KEY_chop 30 +#define KEY_chown 31 +#define KEY_chr 32 +#define KEY_chroot 33 +#define KEY_close 34 +#define KEY_closedir 35 +#define KEY_cmp 36 +#define KEY_connect 37 +#define KEY_continue 38 +#define KEY_cos 39 +#define KEY_crypt 40 +#define KEY_dbmclose 41 +#define KEY_dbmopen 42 +#define KEY_defined 43 +#define KEY_delete 44 +#define KEY_die 45 +#define KEY_do 46 +#define KEY_dump 47 +#define KEY_each 48 +#define KEY_else 49 +#define KEY_elsif 50 +#define KEY_endgrent 51 +#define KEY_endhostent 52 +#define KEY_endnetent 53 +#define KEY_endprotoent 54 +#define KEY_endpwent 55 +#define KEY_endservent 56 +#define KEY_eof 57 +#define KEY_eq 58 +#define KEY_eval 59 +#define KEY_exec 60 +#define KEY_exists 61 +#define KEY_exit 62 +#define KEY_exp 63 +#define KEY_fcntl 64 +#define KEY_fileno 65 +#define KEY_flock 66 +#define KEY_for 67 +#define KEY_foreach 68 +#define KEY_fork 69 +#define KEY_format 70 +#define KEY_formline 71 +#define KEY_ge 72 +#define KEY_getc 73 +#define KEY_getgrent 74 +#define KEY_getgrgid 75 +#define KEY_getgrnam 76 +#define KEY_gethostbyaddr 77 +#define KEY_gethostbyname 78 +#define KEY_gethostent 79 +#define KEY_getlogin 80 +#define KEY_getnetbyaddr 81 +#define KEY_getnetbyname 82 +#define KEY_getnetent 83 +#define KEY_getpeername 84 +#define KEY_getpgrp 85 +#define KEY_getppid 86 +#define KEY_getpriority 87 +#define KEY_getprotobyname 88 +#define KEY_getprotobynumber 89 +#define KEY_getprotoent 90 +#define KEY_getpwent 91 +#define KEY_getpwnam 92 +#define KEY_getpwuid 93 +#define KEY_getservbyname 94 +#define KEY_getservbyport 95 +#define KEY_getservent 96 +#define KEY_getsockname 97 +#define KEY_getsockopt 98 +#define KEY_glob 99 +#define KEY_gmtime 100 +#define KEY_goto 101 +#define KEY_grep 102 +#define KEY_gt 103 +#define KEY_hex 104 +#define KEY_if 105 +#define KEY_index 106 +#define KEY_int 107 +#define KEY_ioctl 108 +#define KEY_join 109 +#define KEY_keys 110 +#define KEY_kill 111 +#define KEY_last 112 +#define KEY_lc 113 +#define KEY_lcfirst 114 +#define KEY_le 115 +#define KEY_length 116 +#define KEY_link 117 +#define KEY_listen 118 +#define KEY_local 119 +#define KEY_localtime 120 +#define KEY_log 121 +#define KEY_lstat 122 +#define KEY_lt 123 +#define KEY_m 124 +#define KEY_map 125 +#define KEY_mkdir 126 +#define KEY_msgctl 127 +#define KEY_msgget 128 +#define KEY_msgrcv 129 +#define KEY_msgsnd 130 +#define KEY_my 131 +#define KEY_ne 132 +#define KEY_next 133 +#define KEY_no 134 +#define KEY_not 135 +#define KEY_oct 136 +#define KEY_open 137 +#define KEY_opendir 138 +#define KEY_or 139 +#define KEY_ord 140 +#define KEY_pack 141 +#define KEY_package 142 +#define KEY_pipe 143 +#define KEY_pop 144 +#define KEY_pos 145 +#define KEY_print 146 +#define KEY_printf 147 +#define KEY_prototype 148 +#define KEY_push 149 +#define KEY_q 150 +#define KEY_qq 151 +#define KEY_quotemeta 152 +#define KEY_qw 153 +#define KEY_qx 154 +#define KEY_rand 155 +#define KEY_read 156 +#define KEY_readdir 157 +#define KEY_readline 158 +#define KEY_readlink 159 +#define KEY_readpipe 160 +#define KEY_recv 161 +#define KEY_redo 162 +#define KEY_ref 163 +#define KEY_rename 164 +#define KEY_require 165 +#define KEY_reset 166 +#define KEY_return 167 +#define KEY_reverse 168 +#define KEY_rewinddir 169 +#define KEY_rindex 170 +#define KEY_rmdir 171 +#define KEY_s 172 +#define KEY_scalar 173 +#define KEY_seek 174 +#define KEY_seekdir 175 +#define KEY_select 176 +#define KEY_semctl 177 +#define KEY_semget 178 +#define KEY_semop 179 +#define KEY_send 180 +#define KEY_setgrent 181 +#define KEY_sethostent 182 +#define KEY_setnetent 183 +#define KEY_setpgrp 184 +#define KEY_setpriority 185 +#define KEY_setprotoent 186 +#define KEY_setpwent 187 +#define KEY_setservent 188 +#define KEY_setsockopt 189 +#define KEY_shift 190 +#define KEY_shmctl 191 +#define KEY_shmget 192 +#define KEY_shmread 193 +#define KEY_shmwrite 194 +#define KEY_shutdown 195 +#define KEY_sin 196 +#define KEY_sleep 197 +#define KEY_socket 198 +#define KEY_socketpair 199 +#define KEY_sort 200 +#define KEY_splice 201 +#define KEY_split 202 +#define KEY_sprintf 203 +#define KEY_sqrt 204 +#define KEY_srand 205 +#define KEY_stat 206 +#define KEY_study 207 +#define KEY_sub 208 +#define KEY_substr 209 +#define KEY_symlink 210 +#define KEY_syscall 211 +#define KEY_sysopen 212 +#define KEY_sysread 213 +#define KEY_sysseek 214 +#define KEY_system 215 +#define KEY_syswrite 216 +#define KEY_tell 217 +#define KEY_telldir 218 +#define KEY_tie 219 +#define KEY_tied 220 +#define KEY_time 221 +#define KEY_times 222 +#define KEY_tr 223 +#define KEY_truncate 224 +#define KEY_uc 225 +#define KEY_ucfirst 226 +#define KEY_umask 227 +#define KEY_undef 228 +#define KEY_unless 229 +#define KEY_unlink 230 +#define KEY_unpack 231 +#define KEY_unshift 232 +#define KEY_untie 233 +#define KEY_until 234 +#define KEY_use 235 +#define KEY_utime 236 +#define KEY_values 237 +#define KEY_vec 238 +#define KEY_wait 239 +#define KEY_waitpid 240 +#define KEY_wantarray 241 +#define KEY_warn 242 +#define KEY_while 243 +#define KEY_write 244 +#define KEY_x 245 +#define KEY_xor 246 +#define KEY_y 247 @@ -287,6 +287,7 @@ malloc(nbytes) #endif #endif /* PERL_CORE */ + MUTEX_LOCK(&malloc_mutex); /* * Convert amount of memory requested into * closest block size stored in hash buckets @@ -317,6 +318,7 @@ malloc(nbytes) if (nextf[bucket] == NULL) morecore(bucket); if ((p = (union overhead *)nextf[bucket]) == NULL) { + MUTEX_UNLOCK(&malloc_mutex); #ifdef PERL_CORE if (!nomemok) { PerlIO_puts(PerlIO_stderr(),"Out of memory!\n"); @@ -354,6 +356,7 @@ malloc(nbytes) p->ov_rmagic = RMAGIC; *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC; #endif + MUTEX_UNLOCK(&malloc_mutex); return ((Malloc_t)(p + CHUNK_SHIFT)); } @@ -511,6 +514,7 @@ free(mp) #endif return; /* sanity */ } + MUTEX_LOCK(&malloc_mutex); #ifdef RCHECK ASSERT(op->ov_rmagic == RMAGIC); if (OV_INDEX(op) <= MAX_SHORT_BUCKET) @@ -521,6 +525,7 @@ free(mp) size = OV_INDEX(op); op->ov_next = nextf[size]; nextf[size] = op; + MUTEX_UNLOCK(&malloc_mutex); } /* @@ -568,6 +573,7 @@ realloc(mp, nbytes) #endif #endif /* PERL_CORE */ + MUTEX_LOCK(&malloc_mutex); op = (union overhead *)((caddr_t)cp - sizeof (union overhead) * CHUNK_SHIFT); i = OV_INDEX(op); @@ -632,8 +638,10 @@ realloc(mp, nbytes) } #endif res = cp; + MUTEX_UNLOCK(&malloc_mutex); } else { + MUTEX_UNLOCK(&malloc_mutex); if ((res = (char*)malloc(nbytes)) == NULL) return (NULL); if (cp != res) /* common optimization */ @@ -704,6 +704,7 @@ magic_setsig(sv,mg) SV* sv; MAGIC* mg; { + dTHR; register char *s; I32 i; SV** svp; @@ -815,6 +816,7 @@ SV* sv; MAGIC* mg; char *meth; { + dTHR; dSP; ENTER; @@ -856,6 +858,7 @@ magic_setpack(sv,mg) SV* sv; MAGIC* mg; { + dTHR; dSP; PUSHMARK(sp); @@ -889,6 +892,7 @@ int magic_wipepack(sv,mg) SV* sv; MAGIC* mg; { + dTHR; dSP; PUSHMARK(sp); @@ -906,6 +910,7 @@ SV* sv; MAGIC* mg; SV* key; { + dTHR; dSP; char *meth = SvOK(key) ? "NEXTKEY" : "FIRSTKEY"; @@ -939,6 +944,7 @@ magic_setdbline(sv,mg) SV* sv; MAGIC* mg; { + dTHR; OP *o; I32 i; GV* gv; @@ -1093,6 +1099,7 @@ magic_settaint(sv,mg) SV* sv; MAGIC* mg; { + dTHR; if (localizing) { if (localizing == 1) mg->mg_len <<= 1; @@ -1272,6 +1279,7 @@ magic_set(sv,mg) SV* sv; MAGIC* mg; { + dTHR; register char *s; I32 i; STRLEN len; @@ -1605,6 +1613,21 @@ MAGIC* mg; return 0; } +#ifdef USE_THREADS +int +magic_mutexfree(sv, mg) +SV *sv; +MAGIC *mg; +{ + dTHR; + if (MgOWNER(mg)) + croak("panic: magic_mutexfree"); + MUTEX_DESTROY(MgMUTEXP(mg)); + COND_DESTROY(MgCONDP(mg)); + return 0; +} +#endif /* USE_THREADS */ + I32 whichsig(sig) char *sig; @@ -1629,6 +1652,7 @@ Signal_t sighandler(sig) int sig; { + dTHR; dSP; GV *gv; HV *st; @@ -18,32 +18,26 @@ #include "EXTERN.h" #include "perl.h" -#define USE_OP_MASK /* Turned on by default in 5.002beta1h */ - -#ifdef USE_OP_MASK /* - * In the following definition, the ", (OP *) op" is just to make the compiler + * In the following definition, the ", Nullop" is just to make the compiler * think the expression is of the right type: croak actually does a Siglongjmp. */ -#define CHECKOP(type,op) \ +#define CHECKOP(type,o) \ ((op_mask && op_mask[type]) \ - ? ( op_free((OP*)op), \ + ? ( op_free((OP*)o), \ croak("%s trapped by operation mask", op_desc[type]), \ Nullop ) \ - : (*check[type])((OP*)op)) -#else -#define CHECKOP(type,op) (*check[type])(op) -#endif /* USE_OP_MASK */ + : (*check[type])((OP*)o)) -static I32 list_assignment _((OP *op)); +static I32 list_assignment _((OP *o)); static OP *bad_type _((I32 n, char *t, char *name, OP *kid)); -static OP *modkids _((OP *op, I32 type)); -static OP *no_fh_allowed _((OP *op)); -static bool scalar_mod_type _((OP *op, I32 type)); -static OP *scalarboolean _((OP *op)); -static OP *too_few_arguments _((OP *op, char* name)); -static OP *too_many_arguments _((OP *op, char* name)); -static void null _((OP* op)); +static OP *modkids _((OP *o, I32 type)); +static OP *no_fh_allowed _((OP *o)); +static bool scalar_mod_type _((OP *o, I32 type)); +static OP *scalarboolean _((OP *o)); +static OP *too_few_arguments _((OP *o, char* name)); +static OP *too_many_arguments _((OP *o, char* name)); +static void null _((OP* o)); static PADOFFSET pad_findlex _((char* name, PADOFFSET newoff, U32 seq, CV* startcv, I32 cx_ix)); @@ -57,33 +51,33 @@ GV* gv; } static OP * -no_fh_allowed(op) -OP *op; +no_fh_allowed(o) +OP *o; { yyerror(form("Missing comma after first argument to %s function", op_desc[op->op_type])); - return op; + return o; } static OP * -too_few_arguments(op, name) -OP* op; +too_few_arguments(o, name) +OP* o; char* name; { yyerror(form("Not enough arguments for %s", name)); - return op; + return o; } static OP * -too_many_arguments(op, name) -OP *op; +too_many_arguments(o, name) +OP *o; char* name; { yyerror(form("Too many arguments for %s", name)); - return op; + return o; } -static OP * +static void bad_type(n, t, name, kid) I32 n; char *t; @@ -92,14 +86,13 @@ OP *kid; { yyerror(form("Type of arg %d to %s must be %s (not %s)", (int)n, name, t, op_desc[kid->op_type])); - return op; } void -assertref(op) -OP *op; +assertref(o) +OP *o; { - int type = op->op_type; + int type = o->op_type; if (type != OP_AELEM && type != OP_HELEM) { yyerror(form("Can't use subscript on %s", op_desc[type])); if (type == OP_ENTERSUB || type == OP_RV2HV || type == OP_PADHV) @@ -114,6 +107,7 @@ PADOFFSET pad_allocmy(name) char *name; { + dTHR; PADOFFSET off; SV *sv; @@ -176,6 +170,7 @@ I32 cx_ix; pad_findlex(char *name, PADOFFSET newoff, U32 seq, CV* startcv, I32 cx_ix) #endif { + dTHR; CV *cv; I32 off; SV *sv; @@ -303,12 +298,26 @@ PADOFFSET pad_findmy(name) char *name; { + dTHR; I32 off; I32 pendoff = 0; SV *sv; SV **svp = AvARRAY(comppad_name); U32 seq = cop_seqmax; +#ifdef USE_THREADS + /* + * Special case to get lexical (and hence per-thread) @_. + * XXX I need to find out how to tell at parse-time whether use + * of @_ should refer to a lexical (from a sub) or defgv (global + * scope and maybe weird sub-ish things like formats). See + * startsub in perly.y. It's possible that @_ could be lexical + * (at least from subs) even in non-threaded perl. + */ + if (strEQ(name, "@_")) + return 0; /* success. (NOT_IN_PAD indicates failure) */ +#endif /* USE_THREADS */ + /* The one we're looking for is probably just before comppad_name_fill. */ for (off = AvFILL(comppad_name); off > 0; off--) { if ((sv = svp[off]) && @@ -330,10 +339,9 @@ char *name; /* If there is a pending local definition, this new alias must die */ if (pendoff) SvIVX(AvARRAY(comppad_name)[off]) = seq; - return off; + return off; /* pad_findlex returns 0 for failure...*/ } - - return 0; + return NOT_IN_PAD; /* ...but we return NOT_IN_PAD for failure */ } void @@ -361,6 +369,7 @@ pad_alloc(optype,tmptype) I32 optype; U32 tmptype; { + dTHR; SV *sv; I32 retval; @@ -394,7 +403,14 @@ U32 tmptype; } SvFLAGS(sv) |= tmptype; curpad = AvARRAY(comppad); - DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad alloc %ld for %s\n", (long) retval, op_name[optype])); +#ifdef USE_THREADS + DEBUG_X(PerlIO_printf(Perl_debug_log, "0x%lx Pad 0x%lx alloc %ld for %s\n", + (unsigned long) thr, (unsigned long) curpad, + (long) retval, op_name[optype])); +#else + DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad alloc %ld for %s\n", + (long) retval, op_name[optype])); +#endif /* USE_THREADS */ return (PADOFFSET)retval; } @@ -406,9 +422,15 @@ PADOFFSET po; pad_sv(PADOFFSET po) #endif /* CAN_PROTOTYPE */ { + dTHR; +#ifdef USE_THREADS + DEBUG_X(PerlIO_printf(Perl_debug_log, "0x%lx Pad 0x%lx sv %d\n", + (unsigned long) thr, (unsigned long) curpad, po)); +#else if (!po) croak("panic: pad_sv po"); - DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad sv %lu\n", (unsigned long)po)); + DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad sv %d\n", po)); +#endif /* USE_THREADS */ return curpad[po]; /* eventually we'll turn this into a macro */ } @@ -420,14 +442,20 @@ PADOFFSET po; pad_free(PADOFFSET po) #endif /* CAN_PROTOTYPE */ { + dTHR; if (!curpad) return; if (AvARRAY(comppad) != curpad) croak("panic: pad_free curpad"); if (!po) croak("panic: pad_free po"); - DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad free %lu\n", (unsigned long)po)); - if (curpad[po] && !SvIMMORTAL(curpad[po])) +#ifdef USE_THREADS + DEBUG_X(PerlIO_printf(Perl_debug_log, "0x%lx Pad 0x%lx free %d\n", + (unsigned long) thr, (unsigned long) curpad, po)); +#else + DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad free %d\n", po)); +#endif /* USE_THREADS */ + if (curpad[po] && curpad[po] != &sv_undef) SvPADTMP_off(curpad[po]); if ((I32)po < padix) padix = po - 1; @@ -441,11 +469,17 @@ PADOFFSET po; pad_swipe(PADOFFSET po) #endif /* CAN_PROTOTYPE */ { + dTHR; if (AvARRAY(comppad) != curpad) croak("panic: pad_swipe curpad"); if (!po) croak("panic: pad_swipe po"); - DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad swipe %lu\n", (unsigned long)po)); +#ifdef USE_THREADS + DEBUG_X(PerlIO_printf(Perl_debug_log, "0x%lx Pad 0x%lx swipe %d\n", + (unsigned long) thr, (unsigned long) curpad, po)); +#else + DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad swipe %d\n", po)); +#endif /* USE_THREADS */ SvPADTMP_off(curpad[po]); curpad[po] = NEWSV(1107,0); SvPADTMP_on(curpad[po]); @@ -456,11 +490,17 @@ pad_swipe(PADOFFSET po) void pad_reset() { + dTHR; register I32 po; if (AvARRAY(comppad) != curpad) croak("panic: pad_reset curpad"); +#ifdef USE_THREADS + DEBUG_X(PerlIO_printf(Perl_debug_log, "0x%lx Pad 0x%lx reset\n", + (unsigned long) thr, (unsigned long) curpad)); +#else DEBUG_X(PerlIO_printf(Perl_debug_log, "Pad reset\n")); +#endif /* USE_THREADS */ if (!tainting) { /* Can't mix tainted and non-tainted temporaries. */ for (po = AvMAX(comppad); po > padix_floor; po--) { if (curpad[po] && !SvIMMORTAL(curpad[po])) @@ -474,27 +514,27 @@ pad_reset() /* Destructor */ void -op_free(op) -OP *op; +op_free(o) +OP *o; { register OP *kid, *nextkid; - if (!op || op->op_seq == (U16)-1) + if (!o || o->op_seq == (U16)-1) return; - if (op->op_flags & OPf_KIDS) { - for (kid = cUNOP->op_first; kid; kid = nextkid) { + if (o->op_flags & OPf_KIDS) { + for (kid = cUNOPo->op_first; kid; kid = nextkid) { nextkid = kid->op_sibling; /* Get before next freeing kid */ op_free(kid); } } - switch (op->op_type) { + switch (o->op_type) { case OP_NULL: - op->op_targ = 0; /* Was holding old type, if any. */ + o->op_targ = 0; /* Was holding old type, if any. */ break; case OP_ENTEREVAL: - op->op_targ = 0; /* Was holding hints. */ + o->op_targ = 0; /* Was holding hints. */ break; default: if (!(op->op_flags & OPf_REF) || (check[op->op_type] != ck_ftst)) @@ -503,51 +543,51 @@ OP *op; case OP_GVSV: case OP_GV: case OP_AELEMFAST: - SvREFCNT_dec(cGVOP->op_gv); + SvREFCNT_dec(cGVOPo->op_gv); break; case OP_NEXTSTATE: case OP_DBSTATE: Safefree(cCOP->cop_label); - SvREFCNT_dec(cCOP->cop_filegv); + SvREFCNT_dec(cCOPo->cop_filegv); break; case OP_CONST: - SvREFCNT_dec(cSVOP->op_sv); + SvREFCNT_dec(cSVOPo->op_sv); break; case OP_GOTO: case OP_NEXT: case OP_LAST: case OP_REDO: - if (op->op_flags & (OPf_SPECIAL|OPf_STACKED|OPf_KIDS)) + if (o->op_flags & (OPf_SPECIAL|OPf_STACKED|OPf_KIDS)) break; /* FALL THROUGH */ case OP_TRANS: - Safefree(cPVOP->op_pv); + Safefree(cPVOPo->op_pv); break; case OP_SUBST: - op_free(cPMOP->op_pmreplroot); + op_free(cPMOPo->op_pmreplroot); /* FALL THROUGH */ case OP_PUSHRE: case OP_MATCH: - pregfree(cPMOP->op_pmregexp); - SvREFCNT_dec(cPMOP->op_pmshort); + pregfree(cPMOPo->op_pmregexp); + SvREFCNT_dec(cPMOPo->op_pmshort); break; } - if (op->op_targ > 0) - pad_free(op->op_targ); + if (o->op_targ > 0) + pad_free(o->op_targ); - Safefree(op); + Safefree(o); } static void -null(op) -OP* op; +null(o) +OP* o; { - if (op->op_type != OP_NULL && op->op_targ > 0) - pad_free(op->op_targ); - op->op_targ = op->op_type; - op->op_type = OP_NULL; - op->op_ppaddr = ppaddr[OP_NULL]; + if (o->op_type != OP_NULL && o->op_targ > 0) + pad_free(o->op_targ); + o->op_targ = o->op_type; + o->op_type = OP_NULL; + o->op_ppaddr = ppaddr[OP_NULL]; } /* Contextualizers */ @@ -555,48 +595,48 @@ OP* op; #define LINKLIST(o) ((o)->op_next ? (o)->op_next : linklist((OP*)o)) OP * -linklist(op) -OP *op; +linklist(o) +OP *o; { register OP *kid; - if (op->op_next) - return op->op_next; + if (o->op_next) + return o->op_next; /* establish postfix order */ - if (cUNOP->op_first) { - op->op_next = LINKLIST(cUNOP->op_first); - for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) { + if (cUNOPo->op_first) { + o->op_next = LINKLIST(cUNOPo->op_first); + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) { if (kid->op_sibling) kid->op_next = LINKLIST(kid->op_sibling); else - kid->op_next = op; + kid->op_next = o; } } else - op->op_next = op; + o->op_next = o; - return op->op_next; + return o->op_next; } OP * -scalarkids(op) -OP *op; +scalarkids(o) +OP *o; { OP *kid; - if (op && op->op_flags & OPf_KIDS) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + if (o && o->op_flags & OPf_KIDS) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) scalar(kid); } - return op; + return o; } static OP * -scalarboolean(op) -OP *op; +scalarboolean(o) +OP *o; { if (dowarn && - op->op_type == OP_SASSIGN && cBINOP->op_first->op_type == OP_CONST) { + o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST) { line_t oldline = curcop->cop_line; if (copline != NOLINE) @@ -604,36 +644,36 @@ OP *op; warn("Found = in conditional, should be =="); curcop->cop_line = oldline; } - return scalar(op); + return scalar(o); } OP * -scalar(op) -OP *op; +scalar(o) +OP *o; { OP *kid; /* assumes no premature commitment */ - if (!op || (op->op_flags & OPf_WANT) || error_count - || op->op_type == OP_RETURN) - return op; + if (!o || (o->op_flags & OPf_WANT) || error_count + || o->op_type == OP_RETURN) + return o; - op->op_flags = (op->op_flags & ~OPf_WANT) | OPf_WANT_SCALAR; + o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_SCALAR; - switch (op->op_type) { + switch (o->op_type) { case OP_REPEAT: - if (op->op_private & OPpREPEAT_DOLIST) - null(((LISTOP*)cBINOP->op_first)->op_first); - scalar(cBINOP->op_first); + if (o->op_private & OPpREPEAT_DOLIST) + null(((LISTOP*)cBINOPo->op_first)->op_first); + scalar(cBINOPo->op_first); break; case OP_OR: case OP_AND: case OP_COND_EXPR: - for (kid = cUNOP->op_first->op_sibling; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling) scalar(kid); break; case OP_SPLIT: - if ((kid = ((LISTOP*)op)->op_first) && kid->op_type == OP_PUSHRE) { + if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) { if (!kPMOP->op_pmreplroot) deprecate("implicit split to @_"); } @@ -642,14 +682,14 @@ OP *op; case OP_SUBST: case OP_NULL: default: - if (op->op_flags & OPf_KIDS) { - for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) + if (o->op_flags & OPf_KIDS) { + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) scalar(kid); } break; case OP_LEAVE: case OP_LEAVETRY: - kid = cLISTOP->op_first; + kid = cLISTOPo->op_first; scalar(kid); while (kid = kid->op_sibling) { if (kid->op_sibling) @@ -662,7 +702,7 @@ OP *op; case OP_SCOPE: case OP_LINESEQ: case OP_LIST: - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) { if (kid->op_sibling) scalarvoid(kid); else @@ -671,31 +711,31 @@ OP *op; curcop = &compiling; break; } - return op; + return o; } OP * -scalarvoid(op) -OP *op; +scalarvoid(o) +OP *o; { OP *kid; char* useless = 0; SV* sv; /* assumes no premature commitment */ - if (!op || (op->op_flags & OPf_WANT) == OPf_WANT_LIST || error_count - || op->op_type == OP_RETURN) - return op; + if (!o || (o->op_flags & OPf_WANT) == OPf_WANT_LIST || error_count + || o->op_type == OP_RETURN) + return o; - op->op_flags = (op->op_flags & ~OPf_WANT) | OPf_WANT_VOID; + o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_VOID; - switch (op->op_type) { + switch (o->op_type) { default: - if (!(opargs[op->op_type] & OA_FOLDCONST)) + if (!(opargs[o->op_type] & OA_FOLDCONST)) break; /* FALL THROUGH */ case OP_REPEAT: - if (op->op_flags & OPf_STACKED) + if (o->op_flags & OPf_STACKED) break; /* FALL THROUGH */ case OP_GVSV: @@ -766,26 +806,26 @@ OP *op; case OP_GGRNAM: case OP_GGRGID: case OP_GETLOGIN: - if (!(op->op_private & OPpLVAL_INTRO)) - useless = op_desc[op->op_type]; + if (!(o->op_private & OPpLVAL_INTRO)) + useless = op_desc[o->op_type]; break; case OP_RV2GV: case OP_RV2SV: case OP_RV2AV: case OP_RV2HV: - if (!(op->op_private & OPpLVAL_INTRO) && - (!op->op_sibling || op->op_sibling->op_type != OP_READLINE)) + if (!(o->op_private & OPpLVAL_INTRO) && + (!o->op_sibling || o->op_sibling->op_type != OP_READLINE)) useless = "a variable"; break; case OP_NEXTSTATE: case OP_DBSTATE: - curcop = ((COP*)op); /* for warning below */ + curcop = ((COP*)o); /* for warning below */ break; case OP_CONST: - sv = cSVOP->op_sv; + sv = cSVOPo->op_sv; if (dowarn) { useless = "a constant"; if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0)) @@ -797,37 +837,37 @@ OP *op; useless = 0; } } - null(op); /* don't execute a constant */ + null(o); /* don't execute a constant */ SvREFCNT_dec(sv); /* don't even remember it */ break; case OP_POSTINC: - op->op_type = OP_PREINC; /* pre-increment is faster */ - op->op_ppaddr = ppaddr[OP_PREINC]; + o->op_type = OP_PREINC; /* pre-increment is faster */ + o->op_ppaddr = ppaddr[OP_PREINC]; break; case OP_POSTDEC: - op->op_type = OP_PREDEC; /* pre-decrement is faster */ - op->op_ppaddr = ppaddr[OP_PREDEC]; + o->op_type = OP_PREDEC; /* pre-decrement is faster */ + o->op_ppaddr = ppaddr[OP_PREDEC]; break; case OP_OR: case OP_AND: case OP_COND_EXPR: - for (kid = cUNOP->op_first->op_sibling; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling) scalarvoid(kid); break; case OP_NULL: - if (op->op_targ == OP_NEXTSTATE || op->op_targ == OP_DBSTATE) - curcop = ((COP*)op); /* for warning below */ - if (op->op_flags & OPf_STACKED) + if (o->op_targ == OP_NEXTSTATE || o->op_targ == OP_DBSTATE) + curcop = ((COP*)o); /* for warning below */ + if (o->op_flags & OPf_STACKED) break; /* FALL THROUGH */ case OP_ENTERTRY: case OP_ENTER: case OP_SCALAR: - if (!(op->op_flags & OPf_KIDS)) + if (!(o->op_flags & OPf_KIDS)) break; /* FALL THROUGH */ case OP_SCOPE: @@ -836,7 +876,7 @@ OP *op; case OP_LEAVELOOP: case OP_LINESEQ: case OP_LIST: - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) scalarvoid(kid); break; case OP_ENTEREVAL: @@ -847,7 +887,7 @@ OP *op; op->op_flags &= ~OPf_WANT; return scalar(op); case OP_SPLIT: - if ((kid = ((LISTOP*)op)->op_first) && kid->op_type == OP_PUSHRE) { + if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) { if (!kPMOP->op_pmreplroot) deprecate("implicit split to @_"); } @@ -855,61 +895,61 @@ OP *op; } if (useless && dowarn) warn("Useless use of %s in void context", useless); - return op; + return o; } OP * -listkids(op) -OP *op; +listkids(o) +OP *o; { OP *kid; - if (op && op->op_flags & OPf_KIDS) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + if (o && o->op_flags & OPf_KIDS) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) list(kid); } - return op; + return o; } OP * -list(op) -OP *op; +list(o) +OP *o; { OP *kid; /* assumes no premature commitment */ - if (!op || (op->op_flags & OPf_WANT) || error_count - || op->op_type == OP_RETURN) - return op; + if (!o || (o->op_flags & OPf_WANT) || error_count + || o->op_type == OP_RETURN) + return o; - op->op_flags = (op->op_flags & ~OPf_WANT) | OPf_WANT_LIST; + o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_LIST; - switch (op->op_type) { + switch (o->op_type) { case OP_FLOP: case OP_REPEAT: - list(cBINOP->op_first); + list(cBINOPo->op_first); break; case OP_OR: case OP_AND: case OP_COND_EXPR: - for (kid = cUNOP->op_first->op_sibling; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling) list(kid); break; default: case OP_MATCH: case OP_SUBST: case OP_NULL: - if (!(op->op_flags & OPf_KIDS)) + if (!(o->op_flags & OPf_KIDS)) break; - if (!op->op_next && cUNOP->op_first->op_type == OP_FLOP) { - list(cBINOP->op_first); - return gen_constant_list(op); + if (!o->op_next && cUNOPo->op_first->op_type == OP_FLOP) { + list(cBINOPo->op_first); + return gen_constant_list(o); } case OP_LIST: - listkids(op); + listkids(o); break; case OP_LEAVE: case OP_LEAVETRY: - kid = cLISTOP->op_first; + kid = cLISTOPo->op_first; list(kid); while (kid = kid->op_sibling) { if (kid->op_sibling) @@ -921,7 +961,7 @@ OP *op; break; case OP_SCOPE: case OP_LINESEQ: - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) { if (kid->op_sibling) scalarvoid(kid); else @@ -934,68 +974,69 @@ OP *op; op->op_flags &= ~OPf_WANT; return scalar(op); } - return op; + return o; } OP * -scalarseq(op) -OP *op; +scalarseq(o) +OP *o; { OP *kid; - if (op) { - if (op->op_type == OP_LINESEQ || - op->op_type == OP_SCOPE || - op->op_type == OP_LEAVE || - op->op_type == OP_LEAVETRY) + if (o) { + if (o->op_type == OP_LINESEQ || + o->op_type == OP_SCOPE || + o->op_type == OP_LEAVE || + o->op_type == OP_LEAVETRY) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) { if (kid->op_sibling) { scalarvoid(kid); } } curcop = &compiling; } - op->op_flags &= ~OPf_PARENS; + o->op_flags &= ~OPf_PARENS; if (hints & HINT_BLOCK_SCOPE) - op->op_flags |= OPf_PARENS; + o->op_flags |= OPf_PARENS; } else - op = newOP(OP_STUB, 0); - return op; + o = newOP(OP_STUB, 0); + return o; } static OP * -modkids(op, type) -OP *op; +modkids(o, type) +OP *o; I32 type; { OP *kid; - if (op && op->op_flags & OPf_KIDS) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + if (o && o->op_flags & OPf_KIDS) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) mod(kid, type); } - return op; + return o; } static I32 modcount; OP * -mod(op, type) -OP *op; +mod(o, type) +OP *o; I32 type; { + dTHR; OP *kid; SV *sv; - if (!op || error_count) - return op; + if (!o || error_count) + return o; - switch (op->op_type) { + switch (o->op_type) { case OP_UNDEF: - return op; + return o; case OP_CONST: - if (!(op->op_private & (OPpCONST_ARYBASE))) + if (!(o->op_private & (OPpCONST_ARYBASE))) goto nomod; if (eval_start && eval_start->op_type == OP_CONST) { compiling.cop_arybase = (I32)SvIV(((SVOP*)eval_start)->op_sv); @@ -1016,11 +1057,11 @@ I32 type; goto nomod; case OP_ENTERSUB: if ((type == OP_UNDEF || type == OP_REFGEN) && - !(op->op_flags & OPf_STACKED)) { - op->op_type = OP_RV2CV; /* entersub => rv2cv */ - op->op_ppaddr = ppaddr[OP_RV2CV]; - assert(cUNOP->op_first->op_type == OP_NULL); - null(((LISTOP*)cUNOP->op_first)->op_first); /* disable pushmark */ + !(o->op_flags & OPf_STACKED)) { + o->op_type = OP_RV2CV; /* entersub => rv2cv */ + o->op_ppaddr = ppaddr[OP_RV2CV]; + assert(cUNOPo->op_first->op_type == OP_NULL); + null(((LISTOP*)cUNOPo->op_first)->op_first);/* disable pushmark */ break; } /* FALL THROUGH */ @@ -1030,9 +1071,9 @@ I32 type; if (type == OP_GREPSTART || type == OP_ENTERSUB || type == OP_REFGEN) break; yyerror(form("Can't modify %s in %s", - op_desc[op->op_type], + op_desc[o->op_type], type ? op_desc[type] : "local")); - return op; + return o; case OP_PREINC: case OP_PREDEC: @@ -1054,27 +1095,27 @@ I32 type; case OP_I_MODULO: case OP_I_ADD: case OP_I_SUBTRACT: - if (!(op->op_flags & OPf_STACKED)) + if (!(o->op_flags & OPf_STACKED)) goto nomod; modcount++; break; case OP_COND_EXPR: - for (kid = cUNOP->op_first->op_sibling; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling) mod(kid, type); break; case OP_RV2AV: case OP_RV2HV: - if (type == OP_REFGEN && op->op_flags & OPf_PARENS) { + if (type == OP_REFGEN && o->op_flags & OPf_PARENS) { modcount = 10000; - return op; /* Treat \(@foo) like ordinary list. */ + return o; /* Treat \(@foo) like ordinary list. */ } /* FALL THROUGH */ case OP_RV2GV: - if (scalar_mod_type(op, type)) + if (scalar_mod_type(o, type)) goto nomod; - ref(cUNOP->op_first, op->op_type); + ref(cUNOPo->op_first, o->op_type); /* FALL THROUGH */ case OP_AASSIGN: case OP_ASLICE: @@ -1086,9 +1127,9 @@ I32 type; modcount = 10000; break; case OP_RV2SV: - if (!type && cUNOP->op_first->op_type != OP_GV) + if (!type && cUNOPo->op_first->op_type != OP_GV) croak("Can't localize a reference"); - ref(cUNOP->op_first, op->op_type); + ref(cUNOPo->op_first, o->op_type); /* FALL THROUGH */ case OP_GV: case OP_AV2ARYLEN: @@ -1109,7 +1150,7 @@ I32 type; modcount++; if (!type) croak("Can't localize lexical variable %s", - SvPV(*av_fetch(comppad_name, op->op_targ, 4), na)); + SvPV(*av_fetch(comppad_name, o->op_targ, 4), na)); break; case OP_PUSHMARK: @@ -1122,53 +1163,53 @@ I32 type; case OP_POS: case OP_VEC: case OP_SUBSTR: - pad_free(op->op_targ); - op->op_targ = pad_alloc(op->op_type, SVs_PADMY); - assert(SvTYPE(PAD_SV(op->op_targ)) == SVt_NULL); - if (op->op_flags & OPf_KIDS) - mod(cBINOP->op_first->op_sibling, type); + pad_free(o->op_targ); + o->op_targ = pad_alloc(o->op_type, SVs_PADMY); + assert(SvTYPE(PAD_SV(o->op_targ)) == SVt_NULL); + if (o->op_flags & OPf_KIDS) + mod(cBINOPo->op_first->op_sibling, type); break; case OP_AELEM: case OP_HELEM: - ref(cBINOP->op_first, op->op_type); + ref(cBINOPo->op_first, o->op_type); if (type == OP_ENTERSUB && - !(op->op_private & (OPpLVAL_INTRO | OPpDEREF))) - op->op_private |= OPpLVAL_DEFER; + !(o->op_private & (OPpLVAL_INTRO | OPpDEREF))) + o->op_private |= OPpLVAL_DEFER; modcount++; break; case OP_SCOPE: case OP_LEAVE: case OP_ENTER: - if (op->op_flags & OPf_KIDS) - mod(cLISTOP->op_last, type); + if (o->op_flags & OPf_KIDS) + mod(cLISTOPo->op_last, type); break; case OP_NULL: - if (!(op->op_flags & OPf_KIDS)) + if (!(o->op_flags & OPf_KIDS)) break; - if (op->op_targ != OP_LIST) { - mod(cBINOP->op_first, type); + if (o->op_targ != OP_LIST) { + mod(cBINOPo->op_first, type); break; } /* FALL THROUGH */ case OP_LIST: - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) mod(kid, type); break; } - op->op_flags |= OPf_MOD; + o->op_flags |= OPf_MOD; if (type == OP_AASSIGN || type == OP_SASSIGN) - op->op_flags |= OPf_SPECIAL|OPf_REF; + o->op_flags |= OPf_SPECIAL|OPf_REF; else if (!type) { - op->op_private |= OPpLVAL_INTRO; - op->op_flags &= ~OPf_SPECIAL; + o->op_private |= OPpLVAL_INTRO; + o->op_flags &= ~OPf_SPECIAL; } else if (type != OP_GREPSTART && type != OP_ENTERSUB) - op->op_flags |= OPf_REF; - return op; + o->op_flags |= OPf_REF; + return o; } static bool @@ -1218,83 +1259,83 @@ I32 type; } OP * -refkids(op, type) -OP *op; +refkids(o, type) +OP *o; I32 type; { OP *kid; - if (op && op->op_flags & OPf_KIDS) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + if (o && o->op_flags & OPf_KIDS) { + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) ref(kid, type); } - return op; + return o; } OP * -ref(op, type) -OP *op; +ref(o, type) +OP *o; I32 type; { OP *kid; - if (!op || error_count) - return op; + if (!o || error_count) + return o; - switch (op->op_type) { + switch (o->op_type) { case OP_ENTERSUB: if ((type == OP_DEFINED) && - !(op->op_flags & OPf_STACKED)) { - op->op_type = OP_RV2CV; /* entersub => rv2cv */ - op->op_ppaddr = ppaddr[OP_RV2CV]; - assert(cUNOP->op_first->op_type == OP_NULL); - null(((LISTOP*)cUNOP->op_first)->op_first); /* disable pushmark */ - op->op_flags |= OPf_SPECIAL; + !(o->op_flags & OPf_STACKED)) { + o->op_type = OP_RV2CV; /* entersub => rv2cv */ + o->op_ppaddr = ppaddr[OP_RV2CV]; + assert(cUNOPo->op_first->op_type == OP_NULL); + null(((LISTOP*)cUNOPo->op_first)->op_first); /* disable pushmark */ + o->op_flags |= OPf_SPECIAL; } break; case OP_COND_EXPR: - for (kid = cUNOP->op_first->op_sibling; kid; kid = kid->op_sibling) + for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling) ref(kid, type); break; case OP_RV2SV: - ref(cUNOP->op_first, op->op_type); + ref(cUNOPo->op_first, o->op_type); /* FALL THROUGH */ case OP_PADSV: if (type == OP_RV2SV || type == OP_RV2AV || type == OP_RV2HV) { - op->op_private |= (type == OP_RV2AV ? OPpDEREF_AV - : type == OP_RV2HV ? OPpDEREF_HV - : OPpDEREF_SV); - op->op_flags |= OPf_MOD; + o->op_private |= (type == OP_RV2AV ? OPpDEREF_AV + : type == OP_RV2HV ? OPpDEREF_HV + : OPpDEREF_SV); + o->op_flags |= OPf_MOD; } break; case OP_RV2AV: case OP_RV2HV: - op->op_flags |= OPf_REF; + o->op_flags |= OPf_REF; /* FALL THROUGH */ case OP_RV2GV: - ref(cUNOP->op_first, op->op_type); + ref(cUNOPo->op_first, o->op_type); break; case OP_PADAV: case OP_PADHV: - op->op_flags |= OPf_REF; + o->op_flags |= OPf_REF; break; case OP_SCALAR: case OP_NULL: - if (!(op->op_flags & OPf_KIDS)) + if (!(o->op_flags & OPf_KIDS)) break; - ref(cBINOP->op_first, type); + ref(cBINOPo->op_first, type); break; case OP_AELEM: case OP_HELEM: - ref(cBINOP->op_first, op->op_type); + ref(cBINOPo->op_first, o->op_type); if (type == OP_RV2SV || type == OP_RV2AV || type == OP_RV2HV) { - op->op_private |= (type == OP_RV2AV ? OPpDEREF_AV - : type == OP_RV2HV ? OPpDEREF_HV - : OPpDEREF_SV); - op->op_flags |= OPf_MOD; + o->op_private |= (type == OP_RV2AV ? OPpDEREF_AV + : type == OP_RV2HV ? OPpDEREF_HV + : OPpDEREF_SV); + o->op_flags |= OPf_MOD; } break; @@ -1302,30 +1343,30 @@ I32 type; case OP_LEAVE: case OP_ENTER: case OP_LIST: - if (!(op->op_flags & OPf_KIDS)) + if (!(o->op_flags & OPf_KIDS)) break; - ref(cLISTOP->op_last, type); + ref(cLISTOPo->op_last, type); break; default: break; } - return scalar(op); + return scalar(o); } OP * -my(op) -OP *op; +my(o) +OP *o; { OP *kid; I32 type; - if (!op || error_count) - return op; + if (!o || error_count) + return o; - type = op->op_type; + type = o->op_type; if (type == OP_LIST) { - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) my(kid); } else if (type != OP_PADSV && @@ -1333,12 +1374,12 @@ OP *op; type != OP_PADHV && type != OP_PUSHMARK) { - yyerror(form("Can't declare %s in my", op_desc[op->op_type])); - return op; + yyerror(form("Can't declare %s in my", op_desc[o->op_type])); + return o; } - op->op_flags |= OPf_MOD; - op->op_private |= OPpLVAL_INTRO; - return op; + o->op_flags |= OPf_MOD; + o->op_private |= OPpLVAL_INTRO; + return o; } OP * @@ -1356,7 +1397,7 @@ I32 type; OP *left; OP *right; { - OP *op; + OP *o; if (dowarn && (left->op_type == OP_RV2AV || @@ -1379,12 +1420,12 @@ OP *right; if (right->op_type != OP_MATCH) left = mod(left, right->op_type); if (right->op_type == OP_TRANS) - op = newBINOP(OP_NULL, OPf_STACKED, scalar(left), right); + o = newBINOP(OP_NULL, OPf_STACKED, scalar(left), right); else - op = prepend_elem(right->op_type, scalar(left), right); + o = prepend_elem(right->op_type, scalar(left), right); if (type == OP_NOT) - return newUNOP(OP_NOT, 0, scalar(op)); - return op; + return newUNOP(OP_NOT, 0, scalar(o)); + return o; } else return bind_match(type, left, @@ -1392,13 +1433,13 @@ OP *right; } OP * -invert(op) -OP *op; +invert(o) +OP *o; { - if (!op) - return op; + if (!o) + return o; /* XXX need to optimize away NOT NOT here? Or do we let optimizer do it? */ - return newUNOP(OP_NOT, OPf_SPECIAL, scalar(op)); + return newUNOP(OP_NOT, OPf_SPECIAL, scalar(o)); } OP * @@ -1433,6 +1474,7 @@ int block_start(full) int full; { + dTHR; int retval = savestack_ix; SAVEI32(comppad_name_floor); if (full) { @@ -1458,6 +1500,7 @@ block_end(floor, seq) I32 floor; OP* seq; { + dTHR; int needblockscope = hints & HINT_BLOCK_SCOPE; OP* retval = scalarseq(seq); LEAVE_SCOPE(floor); @@ -1470,19 +1513,20 @@ OP* seq; } void -newPROG(op) -OP *op; +newPROG(o) +OP *o; { + dTHR; if (in_eval) { - eval_root = newUNOP(OP_LEAVEEVAL, ((in_eval & 4) ? OPf_SPECIAL : 0), op); + eval_root = newUNOP(OP_LEAVEEVAL, ((in_eval & 4) ? OPf_SPECIAL : 0), o); eval_start = linklist(eval_root); eval_root->op_next = 0; peep(eval_start); } else { - if (!op) + if (!o) return; - main_root = scope(sawparens(scalarvoid(op))); + main_root = scope(sawparens(scalarvoid(o))); curcop = &compiling; main_start = LINKLIST(main_root); main_root->op_next = 0; @@ -1544,6 +1588,7 @@ OP * fold_constants(o) register OP *o; { + dTHR; register OP *curop; I32 type = o->op_type; SV *sv; @@ -1627,6 +1672,7 @@ OP * gen_constant_list(o) register OP *o; { + dTHR; register OP *curop; I32 oldtmps_floor = tmps_floor; @@ -1636,10 +1682,10 @@ register OP *o; op = curop = LINKLIST(o); o->op_next = 0; - pp_pushmark(); + pp_pushmark(ARGS); runops(); op = curop; - pp_anonlist(); + pp_anonlist(ARGS); tmps_floor = oldtmps_floor; o->op_type = OP_RV2AV; @@ -1652,38 +1698,38 @@ register OP *o; } OP * -convert(type, flags, op) +convert(type, flags, o) I32 type; I32 flags; -OP* op; +OP* o; { OP *kid; OP *last = 0; - if (!op || op->op_type != OP_LIST) - op = newLISTOP(OP_LIST, 0, op, Nullop); + if (!o || o->op_type != OP_LIST) + o = newLISTOP(OP_LIST, 0, o, Nullop); else - op->op_flags &= ~OPf_WANT; + o->op_flags &= ~OPf_WANT; if (!(opargs[type] & OA_MARK)) - null(cLISTOP->op_first); + null(cLISTOPo->op_first); - op->op_type = type; - op->op_ppaddr = ppaddr[type]; - op->op_flags |= flags; + o->op_type = type; + o->op_ppaddr = ppaddr[type]; + o->op_flags |= flags; - op = CHECKOP(type, op); - if (op->op_type != type) - return op; + o = CHECKOP(type, o); + if (o->op_type != type) + return o; - if (cLISTOP->op_children < 7) { + if (cLISTOPo->op_children < 7) { /* XXX do we really need to do this if we're done appending?? */ - for (kid = cLISTOP->op_first; kid; kid = kid->op_sibling) + for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) last = kid; - cLISTOP->op_last = last; /* in case check substituted last arg */ + cLISTOPo->op_last = last; /* in case check substituted last arg */ } - return fold_constants(op); + return fold_constants(o); } /* List constructors */ @@ -1783,13 +1829,13 @@ newNULLLIST() } OP * -force_list(op) -OP* op; +force_list(o) +OP *o; { - if (!op || op->op_type != OP_LIST) - op = newLISTOP(OP_LIST, 0, op, Nullop); - null(op); - return op; + if (!o || o->op_type != OP_LIST) + o = newLISTOP(OP_LIST, 0, o, Nullop); + null(o); + return o; } OP * @@ -1836,19 +1882,19 @@ newOP(type, flags) I32 type; I32 flags; { - OP *op; - Newz(1101, op, 1, OP); - op->op_type = type; - op->op_ppaddr = ppaddr[type]; - op->op_flags = flags; + OP *o; + Newz(1101, o, 1, OP); + o->op_type = type; + o->op_ppaddr = ppaddr[type]; + o->op_flags = flags; - op->op_next = op; - op->op_private = 0 + (flags >> 8); + o->op_next = o; + o->op_private = 0 + (flags >> 8); if (opargs[type] & OA_RETSCALAR) - scalar(op); + scalar(o); if (opargs[type] & OA_TARGET) - op->op_targ = pad_alloc(type, SVs_PADTMP); - return CHECKOP(type, op); + o->op_targ = pad_alloc(type, SVs_PADTMP); + return CHECKOP(type, o); } OP * @@ -1914,8 +1960,8 @@ OP* last; } OP * -pmtrans(op, expr, repl) -OP *op; +pmtrans(o, expr, repl) +OP *o; OP *expr; OP *repl; { @@ -1931,10 +1977,10 @@ OP *repl; I32 complement; register short *tbl; - tbl = (short*)cPVOP->op_pv; - complement = op->op_private & OPpTRANS_COMPLEMENT; - delete = op->op_private & OPpTRANS_DELETE; - /* squash = op->op_private & OPpTRANS_SQUASH; */ + tbl = (short*)cPVOPo->op_pv; + complement = o->op_private & OPpTRANS_COMPLEMENT; + delete = o->op_private & OPpTRANS_DELETE; + /* squash = o->op_private & OPpTRANS_SQUASH; */ if (complement) { Zero(tbl, 256, short); @@ -1977,7 +2023,7 @@ OP *repl; op_free(expr); op_free(repl); - return op; + return o; } OP * @@ -1985,6 +2031,7 @@ newPMOP(type, flags) I32 type; I32 flags; { + dTHR; PMOP *pmop; Newz(1101, pmop, 1, PMOP); @@ -2006,24 +2053,24 @@ I32 flags; } OP * -pmruntime(op, expr, repl) -OP *op; +pmruntime(o, expr, repl) +OP *o; OP *expr; OP *repl; { PMOP *pm; LOGOP *rcop; - if (op->op_type == OP_TRANS) - return pmtrans(op, expr, repl); + if (o->op_type == OP_TRANS) + return pmtrans(o, expr, repl); - pm = (PMOP*)op; + pm = (PMOP*)o; if (expr->op_type == OP_CONST) { STRLEN plen; SV *pat = ((SVOP*)expr)->op_sv; char *p = SvPV(pat, plen); - if ((op->op_flags & OPf_SPECIAL) && strEQ(p, " ")) { + if ((o->op_flags & OPf_SPECIAL) && strEQ(p, " ")) { sv_setpvn(pat, "\\s+", 3); p = SvPV(pat, plen); pm->op_pmflags |= PMf_SKIPWHITE; @@ -2044,7 +2091,7 @@ OP *repl; rcop->op_first = scalar(expr); rcop->op_flags |= OPf_KIDS; rcop->op_private = 1; - rcop->op_other = op; + rcop->op_other = o; /* establish postfix order */ if (pm->op_pmflags & PMf_KEEP) { @@ -2057,7 +2104,7 @@ OP *repl; expr->op_next = (OP*)rcop; } - prepend_elem(op->op_type, scalar((OP*)rcop), op); + prepend_elem(o->op_type, scalar((OP*)rcop), o); } if (repl) { @@ -2099,7 +2146,7 @@ OP *repl; if (curop == repl) { pm->op_pmflags |= PMf_CONST; /* const for long enough */ pm->op_pmpermflags |= PMf_CONST; /* const for long enough */ - prepend_elem(op->op_type, scalar(repl), op); + prepend_elem(o->op_type, scalar(repl), o); } else { Newz(1101, rcop, 1, LOGOP); @@ -2108,7 +2155,7 @@ OP *repl; rcop->op_first = scalar(repl); rcop->op_flags |= OPf_KIDS; rcop->op_private = 1; - rcop->op_other = op; + rcop->op_other = o; /* establish postfix order */ rcop->op_next = LINKLIST(repl); @@ -2149,6 +2196,7 @@ I32 type; I32 flags; GV *gv; { + dTHR; GVOP *gvop; Newz(1101, gvop, 1, GVOP); gvop->op_type = type; @@ -2184,21 +2232,22 @@ char *pv; } void -package(op) -OP *op; +package(o) +OP *o; { + dTHR; SV *sv; save_hptr(&curstash); save_item(curstname); - if (op) { + if (o) { STRLEN len; char *name; - sv = cSVOP->op_sv; + sv = cSVOPo->op_sv; name = SvPV(sv, len); curstash = gv_stashpvn(name,len,TRUE); sv_setpvn(curstname, name, len); - op_free(op); + op_free(o); } else { sv_setpv(curstname,"<none>"); @@ -2301,18 +2350,18 @@ OP *listval; } static I32 -list_assignment(op) -register OP *op; +list_assignment(o) +register OP *o; { - if (!op) + if (!o) return TRUE; - if (op->op_type == OP_NULL && op->op_flags & OPf_KIDS) - op = cUNOP->op_first; + if (o->op_type == OP_NULL && o->op_flags & OPf_KIDS) + o = cUNOPo->op_first; - if (op->op_type == OP_COND_EXPR) { - I32 t = list_assignment(cCONDOP->op_first->op_sibling); - I32 f = list_assignment(cCONDOP->op_first->op_sibling->op_sibling); + if (o->op_type == OP_COND_EXPR) { + I32 t = list_assignment(cCONDOPo->op_first->op_sibling); + I32 f = list_assignment(cCONDOPo->op_first->op_sibling->op_sibling); if (t && f) return TRUE; @@ -2321,15 +2370,15 @@ register OP *op; return FALSE; } - if (op->op_type == OP_LIST || op->op_flags & OPf_PARENS || - op->op_type == OP_RV2AV || op->op_type == OP_RV2HV || - op->op_type == OP_ASLICE || op->op_type == OP_HSLICE) + if (o->op_type == OP_LIST || o->op_flags & OPf_PARENS || + o->op_type == OP_RV2AV || o->op_type == OP_RV2HV || + o->op_type == OP_ASLICE || o->op_type == OP_HSLICE) return TRUE; - if (op->op_type == OP_PADAV || op->op_type == OP_PADHV) + if (o->op_type == OP_PADAV || o->op_type == OP_PADHV) return TRUE; - if (op->op_type == OP_RV2SV) + if (o->op_type == OP_RV2SV) return FALSE; return FALSE; @@ -2342,7 +2391,7 @@ OP *left; I32 optype; OP *right; { - OP *op; + OP *o; if (optype) { if (optype == OP_ANDASSIGN || optype == OP_ORASSIGN) { @@ -2367,16 +2416,16 @@ OP *right; op_free(right); return Nullop; } - op = newBINOP(OP_AASSIGN, flags, + o = newBINOP(OP_AASSIGN, flags, list(force_list(right)), list(force_list(left)) ); - op->op_private = 0 | (flags >> 8); + o->op_private = 0 | (flags >> 8); if (!(left->op_private & OPpLVAL_INTRO)) { static int generation = 100; OP *curop; - OP *lastop = op; + OP *lastop = o; generation++; - for (curop = LINKLIST(op); curop != op; curop = LINKLIST(curop)) { + for (curop = LINKLIST(o); curop != o; curop = LINKLIST(curop)) { if (opargs[curop->op_type] & OA_DANGEROUS) { if (curop->op_type == OP_GV) { GV *gv = ((GVOP*)curop)->op_gv; @@ -2408,8 +2457,8 @@ OP *right; } lastop = curop; } - if (curop != op) - op->op_private = OPpASSIGN_COMMON; + if (curop != o) + o->op_private = OPpASSIGN_COMMON; } if (right && right->op_type == OP_SPLIT) { OP* tmpop; @@ -2419,17 +2468,17 @@ OP *right; PMOP *pm = (PMOP*)tmpop; if (left->op_type == OP_RV2AV && !(left->op_private & OPpLVAL_INTRO) && - !(op->op_private & OPpASSIGN_COMMON) ) + !(o->op_private & OPpASSIGN_COMMON) ) { tmpop = ((UNOP*)left)->op_first; if (tmpop->op_type == OP_GV && !pm->op_pmreplroot) { pm->op_pmreplroot = (OP*)((GVOP*)tmpop)->op_gv; pm->op_pmflags |= PMf_ONCE; - tmpop = ((UNOP*)op)->op_first; /* to list (nulled) */ + tmpop = cUNOPo->op_first; /* to list (nulled) */ tmpop = ((UNOP*)tmpop)->op_first; /* to pushmark */ tmpop->op_sibling = Nullop; /* don't free split */ right->op_next = tmpop->op_next; /* fix starting loc */ - op_free(op); /* blow off assign */ + op_free(o); /* blow off assign */ right->op_flags &= ~OPf_WANT; /* "I don't know and I don't care." */ return right; @@ -2446,7 +2495,7 @@ OP *right; } } } - return op; + return o; } if (!right) right = newOP(OP_UNDEF, 0); @@ -2456,24 +2505,25 @@ OP *right; } else { eval_start = right; /* Grandfathering $[ assignment here. Bletch.*/ - op = newBINOP(OP_SASSIGN, flags, + o = newBINOP(OP_SASSIGN, flags, scalar(right), mod(scalar(left), OP_SASSIGN) ); if (eval_start) eval_start = 0; else { - op_free(op); + op_free(o); return Nullop; } } - return op; + return o; } OP * -newSTATEOP(flags, label, op) +newSTATEOP(flags, label, o) I32 flags; char *label; -OP *op; +OP *o; { + dTHR; U32 seq = intro_my(); register COP *cop; @@ -2518,7 +2568,7 @@ OP *op; } } - return prepend_elem(OP_LINESEQ, (OP*)cop, op); + return prepend_elem(OP_LINESEQ, (OP*)cop, o); } /* "Introduce" my variables to visible status. */ @@ -2551,8 +2601,9 @@ I32 flags; OP* first; OP* other; { + dTHR; LOGOP *logop; - OP *op; + OP *o; if (type == OP_XOR) /* Not short circuit, but here by precedence. */ return newBINOP(type, flags, scalar(first), scalar(other)); @@ -2565,12 +2616,12 @@ OP* other; type = OP_OR; else type = OP_AND; - op = first; - first = cUNOP->op_first; - if (op->op_next) - first->op_next = op->op_next; - cUNOP->op_first = Nullop; - op_free(op); + o = first; + first = cUNOPo->op_first; + if (o->op_next) + first->op_next = o->op_next; + cUNOPo->op_first = Nullop; + op_free(o); } } if (first->op_type == OP_CONST) { @@ -2642,10 +2693,10 @@ OP* other; first->op_next = (OP*)logop; first->op_sibling = other; - op = newUNOP(OP_NULL, 0, (OP*)logop); - other->op_next = op; + o = newUNOP(OP_NULL, 0, (OP*)logop); + other->op_next = o; - return op; + return o; } OP * @@ -2655,8 +2706,9 @@ OP* first; OP* trueop; OP* falseop; { + dTHR; CONDOP *condop; - OP *op; + OP *o; if (!falseop) return newLOGOP(OP_AND, 0, first, trueop); @@ -2696,12 +2748,12 @@ OP* falseop; first->op_sibling = trueop; trueop->op_sibling = falseop; - op = newUNOP(OP_NULL, 0, (OP*)condop); + o = newUNOP(OP_NULL, 0, (OP*)condop); - trueop->op_next = op; - falseop->op_next = op; + trueop->op_next = o; + falseop->op_next = o; - return op; + return o; } OP * @@ -2710,10 +2762,11 @@ I32 flags; OP *left; OP *right; { + dTHR; CONDOP *condop; OP *flip; OP *flop; - OP *op; + OP *o; Newz(1101, condop, 1, CONDOP); @@ -2730,7 +2783,7 @@ OP *right; condop->op_next = (OP*)condop; flip = newUNOP(OP_FLIP, flags, (OP*)condop); flop = newUNOP(OP_FLOP, 0, flip); - op = newUNOP(OP_NULL, 0, flop); + o = newUNOP(OP_NULL, 0, flop); linklist(flop); left->op_next = flip; @@ -2744,11 +2797,11 @@ OP *right; flip->op_private = left->op_type == OP_CONST ? OPpFLIP_LINENUM : 0; flop->op_private = right->op_type == OP_CONST ? OPpFLIP_LINENUM : 0; - flip->op_next = op; + flip->op_next = o; if (!flip->op_private || !flop->op_private) - linklist(op); /* blow off optimizer unless constant */ + linklist(o); /* blow off optimizer unless constant */ - return op; + return o; } OP * @@ -2758,8 +2811,9 @@ I32 debuggable; OP *expr; OP *block; { + dTHR; OP* listop; - OP* op; + OP* o; int once = block && block->op_flags & OPf_SPECIAL && (block->op_type == OP_ENTERSUB || block->op_type == OP_NULL); @@ -2773,20 +2827,20 @@ OP *block; } listop = append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0)); - op = newLOGOP(OP_AND, 0, expr, listop); + o = newLOGOP(OP_AND, 0, expr, listop); - ((LISTOP*)listop)->op_last->op_next = LINKLIST(op); + ((LISTOP*)listop)->op_last->op_next = LINKLIST(o); - if (once && op != listop) - op->op_next = ((LOGOP*)cUNOP->op_first)->op_other; + if (once && o != listop) + o->op_next = ((LOGOP*)cUNOPo->op_first)->op_other; - if (op == listop) - op = newUNOP(OP_NULL, 0, op); /* or do {} while 1 loses outer block */ + if (o == listop) + o = newUNOP(OP_NULL, 0, o); /* or do {} while 1 loses outer block */ - op->op_flags |= flags; - op = scope(op); - op->op_flags |= OPf_SPECIAL; /* suppress POPBLOCK curpm restoration*/ - return op; + o->op_flags |= flags; + o = scope(o); + o->op_flags |= OPf_SPECIAL; /* suppress POPBLOCK curpm restoration*/ + return o; } OP * @@ -2798,10 +2852,11 @@ OP *expr; OP *block; OP *cont; { + dTHR; OP *redo; OP *next = 0; OP *listop; - OP *op; + OP *o; OP *condop; if (expr && (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB)) { @@ -2821,19 +2876,19 @@ OP *cont; redo = LINKLIST(listop); if (expr) { - op = newLOGOP(OP_AND, 0, expr, scalar(listop)); - if (op == expr && op->op_type == OP_CONST && !SvTRUE(cSVOP->op_sv)) { + o = newLOGOP(OP_AND, 0, expr, scalar(listop)); + if (o == expr && o->op_type == OP_CONST && !SvTRUE(cSVOPo->op_sv)) { op_free(expr); /* oops, it's a while (0) */ op_free((OP*)loop); return Nullop; /* (listop already freed by newLOGOP) */ } ((LISTOP*)listop)->op_last->op_next = condop = - (op == listop ? redo : LINKLIST(op)); + (o == listop ? redo : LINKLIST(o)); if (!next) next = condop; } else - op = listop; + o = listop; if (!loop) { Newz(1101,loop,1,LOOP); @@ -2843,19 +2898,19 @@ OP *cont; loop->op_next = (OP*)loop; } - op = newBINOP(OP_LEAVELOOP, 0, (OP*)loop, op); + o = newBINOP(OP_LEAVELOOP, 0, (OP*)loop, o); loop->op_redoop = redo; - loop->op_lastop = op; + loop->op_lastop = o; if (next) loop->op_nextop = next; else - loop->op_nextop = op; + loop->op_nextop = o; - op->op_flags |= flags; - op->op_private |= (flags >> 8); - return op; + o->op_flags |= flags; + o->op_private |= (flags >> 8); + return o; } OP * @@ -2912,9 +2967,10 @@ newLOOPEX(type, label) I32 type; OP* label; { - OP *op; + dTHR; + OP *o; if (type != OP_GOTO || label->op_type == OP_CONST) { - op = newPVOP(type, 0, savepv( + o = newPVOP(type, 0, savepv( label->op_type == OP_CONST ? SvPVx(((SVOP*)label)->op_sv, na) : "" )); @@ -2923,19 +2979,34 @@ OP* label; else { if (label->op_type == OP_ENTERSUB) label = newUNOP(OP_REFGEN, 0, mod(label, OP_REFGEN)); - op = newUNOP(type, OPf_STACKED, label); + o = newUNOP(type, OPf_STACKED, label); } hints |= HINT_BLOCK_SCOPE; - return op; + return o; } void cv_undef(cv) CV *cv; { + dTHR; +#ifdef USE_THREADS + MUTEX_DESTROY(CvMUTEXP(cv)); + Safefree(CvMUTEXP(cv)); + if (CvCONDP(cv)) { + COND_DESTROY(CvCONDP(cv)); + Safefree(CvCONDP(cv)); + } +#endif /* USE_THREADS */ + if (!CvXSUB(cv) && CvROOT(cv)) { +#ifdef USE_THREADS + if (CvDEPTH(cv) || (CvOWNER(cv) && CvOWNER(cv) != thr)) + croak("Can't undef active subroutine"); +#else if (CvDEPTH(cv)) croak("Can't undef active subroutine"); +#endif /* USE_THREADS */ ENTER; SAVESPTR(curpad); @@ -3026,6 +3097,7 @@ cv_clone2(proto, outside) CV* proto; CV* outside; { + dTHR; AV* av; I32 ix; AV* protopadlist = CvPADLIST(proto); @@ -3052,6 +3124,13 @@ CV* outside; if (CvANON(proto)) CvANON_on(cv); +#ifdef USE_THREADS + New(666, CvMUTEXP(cv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(cv)); + New(666, CvCONDP(cv), 1, pthread_cond_t); + COND_INIT(CvCONDP(cv)); + CvOWNER(cv) = 0; +#endif /* USE_THREADS */ CvFILEGV(cv) = CvFILEGV(proto); CvGV(cv) = (GV*)SvREFCNT_inc(CvGV(proto)); CvSTASH(cv) = CvSTASH(proto); @@ -3203,7 +3282,7 @@ CV* cv; if (sv) return Nullsv; if (type == OP_CONST) - sv = ((SVOP*)o)->op_sv; + sv = cSVOPo->op_sv; else if (type == OP_PADSV) { AV* pad = (AV*)(AvARRAY(CvPADLIST(cv))[1]); sv = pad ? AvARRAY(pad)[o->op_targ] : Nullsv; @@ -3219,20 +3298,21 @@ CV* cv; } CV * -newSUB(floor,op,proto,block) +newSUB(floor,o,proto,block) I32 floor; -OP *op; +OP *o; OP *proto; OP *block; { - char *name = op ? SvPVx(cSVOP->op_sv, na) : Nullch; + dTHR; + char *name = o ? SvPVx(cSVOPo->op_sv, na) : Nullch; GV *gv = gv_fetchpv(name ? name : "__ANON__", GV_ADDMULTI, SVt_PVCV); char *ps = proto ? SvPVx(((SVOP*)proto)->op_sv, na) : Nullch; register CV *cv; I32 ix; - if (op) - SAVEFREEOP(op); + if (o) + SAVEFREEOP(o); if (proto) SAVEFREEOP(proto); @@ -3285,6 +3365,13 @@ OP *block; CvGV(cv) = (GV*)SvREFCNT_inc(gv); CvFILEGV(cv) = curcop->cop_filegv; CvSTASH(cv) = curstash; +#ifdef USE_THREADS + CvOWNER(cv) = 0; + New(666, CvMUTEXP(cv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(cv)); + New(666, CvCONDP(cv), 1, pthread_cond_t); + COND_INIT(CvCONDP(cv)); +#endif /* USE_THREADS */ if (ps) sv_setpv((SV*)cv, ps); @@ -3451,6 +3538,7 @@ char *name; void (*subaddr) _((CV*)); char *filename; { + dTHR; GV *gv = gv_fetchpv(name ? name : "__ANON__", GV_ADDMULTI, SVt_PVCV); register CV *cv; @@ -3484,7 +3572,14 @@ char *filename; sub_generation++; } } - CvGV(cv) = (GV*)SvREFCNT_inc(gv); + CvGV(cv) = SvREFCNT_inc(gv); +#ifdef USE_THREADS + New(666, CvMUTEXP(cv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(cv)); + New(666, CvCONDP(cv), 1, pthread_cond_t); + COND_INIT(CvCONDP(cv)); + CvOWNER(cv) = 0; +#endif /* USE_THREADS */ CvFILEGV(cv) = gv_fetchfile(filename); CvXSUB(cv) = subaddr; @@ -3520,18 +3615,19 @@ char *filename; } void -newFORM(floor,op,block) +newFORM(floor,o,block) I32 floor; -OP *op; +OP *o; OP *block; { + dTHR; register CV *cv; char *name; GV *gv; I32 ix; - if (op) - name = SvPVx(cSVOP->op_sv, na); + if (o) + name = SvPVx(cSVOPo->op_sv, na); else name = "STDOUT"; gv = gv_fetchpv(name,TRUE, SVt_PVFM); @@ -3560,25 +3656,25 @@ OP *block; CvSTART(cv) = LINKLIST(CvROOT(cv)); CvROOT(cv)->op_next = 0; peep(CvSTART(cv)); - op_free(op); + op_free(o); copline = NOLINE; LEAVE_SCOPE(floor); } OP * -newANONLIST(op) -OP* op; +newANONLIST(o) +OP* o; { return newUNOP(OP_REFGEN, 0, - mod(list(convert(OP_ANONLIST, 0, op)), OP_REFGEN)); + mod(list(convert(OP_ANONLIST, 0, o)), OP_REFGEN)); } OP * -newANONHASH(op) -OP* op; +newANONHASH(o) +OP* o; { return newUNOP(OP_REFGEN, 0, - mod(list(convert(OP_ANONHASH, 0, op)), OP_REFGEN)); + mod(list(convert(OP_ANONHASH, 0, o)), OP_REFGEN)); } OP * @@ -3705,8 +3801,8 @@ OP *o; /* Check routines. */ OP * -ck_anoncode(op) -OP *op; +ck_anoncode(o) +OP *o; { PADOFFSET ix; SV* name; @@ -3716,42 +3812,42 @@ OP *op; sv_setpvn(name, "&", 1); SvIVX(name) = -1; SvNVX(name) = 1; - ix = pad_alloc(op->op_type, SVs_PADMY); + ix = pad_alloc(o->op_type, SVs_PADMY); av_store(comppad_name, ix, name); - av_store(comppad, ix, cSVOP->op_sv); - SvPADMY_on(cSVOP->op_sv); - cSVOP->op_sv = Nullsv; - cSVOP->op_targ = ix; - return op; + av_store(comppad, ix, cSVOPo->op_sv); + SvPADMY_on(cSVOPo->op_sv); + cSVOPo->op_sv = Nullsv; + cSVOPo->op_targ = ix; + return o; } OP * -ck_bitop(op) -OP *op; +ck_bitop(o) +OP *o; { - op->op_private = hints; - return op; + o->op_private = hints; + return o; } OP * -ck_concat(op) -OP *op; +ck_concat(o) +OP *o; { - if (cUNOP->op_first->op_type == OP_CONCAT) - op->op_flags |= OPf_STACKED; - return op; + if (cUNOPo->op_first->op_type == OP_CONCAT) + o->op_flags |= OPf_STACKED; + return o; } OP * -ck_spair(op) -OP *op; +ck_spair(o) +OP *o; { - if (op->op_flags & OPf_KIDS) { + if (o->op_flags & OPf_KIDS) { OP* newop; OP* kid; - OPCODE type = op->op_type; - op = modkids(ck_fun(op), type); - kid = cUNOP->op_first; + OPCODE type = o->op_type; + o = modkids(ck_fun(o), type); + kid = cUNOPo->op_first; newop = kUNOP->op_first->op_sibling; if (newop && (newop->op_sibling || @@ -3759,68 +3855,68 @@ OP *op; newop->op_type == OP_PADAV || newop->op_type == OP_PADHV || newop->op_type == OP_RV2AV || newop->op_type == OP_RV2HV)) { - return op; + return o; } op_free(kUNOP->op_first); kUNOP->op_first = newop; } - op->op_ppaddr = ppaddr[++op->op_type]; - return ck_fun(op); + o->op_ppaddr = ppaddr[++o->op_type]; + return ck_fun(o); } OP * -ck_delete(op) -OP *op; +ck_delete(o) +OP *o; { - op = ck_fun(op); - op->op_private = 0; - if (op->op_flags & OPf_KIDS) { - OP *kid = cUNOP->op_first; + o = ck_fun(o); + o->op_private = 0; + if (o->op_flags & OPf_KIDS) { + OP *kid = cUNOPo->op_first; if (kid->op_type == OP_HSLICE) - op->op_private |= OPpSLICE; + o->op_private |= OPpSLICE; else if (kid->op_type != OP_HELEM) croak("%s argument is not a HASH element or slice", - op_desc[op->op_type]); + op_desc[o->op_type]); null(kid); } - return op; + return o; } OP * -ck_eof(op) -OP *op; +ck_eof(o) +OP *o; { - I32 type = op->op_type; + I32 type = o->op_type; - if (op->op_flags & OPf_KIDS) { - if (cLISTOP->op_first->op_type == OP_STUB) { - op_free(op); - op = newUNOP(type, OPf_SPECIAL, + if (o->op_flags & OPf_KIDS) { + if (cLISTOPo->op_first->op_type == OP_STUB) { + op_free(o); + o = newUNOP(type, OPf_SPECIAL, newGVOP(OP_GV, 0, gv_fetchpv("main'ARGV", TRUE, SVt_PVAV))); } - return ck_fun(op); + return ck_fun(o); } - return op; + return o; } OP * -ck_eval(op) -OP *op; +ck_eval(o) +OP *o; { hints |= HINT_BLOCK_SCOPE; - if (op->op_flags & OPf_KIDS) { - SVOP *kid = (SVOP*)cUNOP->op_first; + if (o->op_flags & OPf_KIDS) { + SVOP *kid = (SVOP*)cUNOPo->op_first; if (!kid) { - op->op_flags &= ~OPf_KIDS; - null(op); + o->op_flags &= ~OPf_KIDS; + null(o); } else if (kid->op_type == OP_LINESEQ) { LOGOP *enter; - kid->op_next = op->op_next; - cUNOP->op_first = 0; - op_free(op); + kid->op_next = o->op_next; + cUNOPo->op_first = 0; + op_free(o); Newz(1101, enter, 1, LOGOP); enter->op_type = OP_ENTERTRY; @@ -3830,35 +3926,35 @@ OP *op; /* establish postfix order */ enter->op_next = (OP*)enter; - op = prepend_elem(OP_LINESEQ, (OP*)enter, (OP*)kid); - op->op_type = OP_LEAVETRY; - op->op_ppaddr = ppaddr[OP_LEAVETRY]; - enter->op_other = op; - return op; + o = prepend_elem(OP_LINESEQ, (OP*)enter, (OP*)kid); + o->op_type = OP_LEAVETRY; + o->op_ppaddr = ppaddr[OP_LEAVETRY]; + enter->op_other = o; + return o; } } else { - op_free(op); - op = newUNOP(OP_ENTEREVAL, 0, newSVREF(newGVOP(OP_GV, 0, defgv))); + op_free(o); + o = newUNOP(OP_ENTEREVAL, 0, newSVREF(newGVOP(OP_GV, 0, defgv))); } - op->op_targ = (PADOFFSET)hints; - return op; + o->op_targ = (PADOFFSET)hints; + return o; } OP * -ck_exec(op) -OP *op; +ck_exec(o) +OP *o; { OP *kid; - if (op->op_flags & OPf_STACKED) { - op = ck_fun(op); - kid = cUNOP->op_first->op_sibling; + if (o->op_flags & OPf_STACKED) { + o = ck_fun(o); + kid = cUNOPo->op_first->op_sibling; if (kid->op_type == OP_RV2GV) null(kid); } else - op = listkids(op); - return op; + o = listkids(o); + return o; } OP * @@ -3886,12 +3982,13 @@ register OP *o; } OP * -ck_rvconst(op) -register OP *op; +ck_rvconst(o) +register OP *o; { - SVOP *kid = (SVOP*)cUNOP->op_first; + dTHR; + SVOP *kid = (SVOP*)cUNOPo->op_first; - op->op_private |= (hints & HINT_STRICT_REFS); + o->op_private |= (hints & HINT_STRICT_REFS); if (kid->op_type == OP_CONST) { char *name; int iscv; @@ -3900,7 +3997,7 @@ register OP *op; name = SvPV(kid->op_sv, na); if ((hints & HINT_STRICT_REFS) && (kid->op_private & OPpCONST_BARE)) { char *badthing = Nullch; - switch (op->op_type) { + switch (o->op_type) { case OP_RV2SV: badthing = "a SCALAR"; break; @@ -3931,71 +4028,73 @@ register OP *op; iscv | !(kid->op_private & OPpCONST_ENTERED), iscv ? SVt_PVCV - : op->op_type == OP_RV2SV + : o->op_type == OP_RV2SV ? SVt_PV - : op->op_type == OP_RV2AV + : o->op_type == OP_RV2AV ? SVt_PVAV - : op->op_type == OP_RV2HV + : o->op_type == OP_RV2HV ? SVt_PVHV : SVt_PVGV); } SvREFCNT_dec(kid->op_sv); kid->op_sv = SvREFCNT_inc(gv); } - return op; + return o; } OP * -ck_ftst(op) -OP *op; +ck_ftst(o) +OP *o; { - I32 type = op->op_type; + dTHR; + I32 type = o->op_type; - if (op->op_flags & OPf_REF) - return op; + if (o->op_flags & OPf_REF) + return o; - if (op->op_flags & OPf_KIDS) { - SVOP *kid = (SVOP*)cUNOP->op_first; + if (o->op_flags & OPf_KIDS) { + SVOP *kid = (SVOP*)cUNOPo->op_first; if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) { OP *newop = newGVOP(type, OPf_REF, gv_fetchpv(SvPVx(kid->op_sv, na), TRUE, SVt_PVIO)); - op_free(op); + op_free(o); return newop; } } else { - op_free(op); + op_free(o); if (type == OP_FTTTY) return newGVOP(type, OPf_REF, gv_fetchpv("main'STDIN", TRUE, SVt_PVIO)); else return newUNOP(type, 0, newSVREF(newGVOP(OP_GV, 0, defgv))); } - return op; + return o; } OP * -ck_fun(op) -OP *op; +ck_fun(o) +OP *o; { + dTHR; register OP *kid; OP **tokid; OP *sibl; I32 numargs = 0; - int type = op->op_type; + int type = o->op_type; register I32 oa = opargs[type] >> OASHIFT; - if (op->op_flags & OPf_STACKED) { + if (o->op_flags & OPf_STACKED) { if ((oa & OA_OPTIONAL) && (oa >> 4) && !((oa >> 4) & OA_OPTIONAL)) oa &= ~OA_OPTIONAL; else - return no_fh_allowed(op); + return no_fh_allowed(o); } - if (op->op_flags & OPf_KIDS) { - tokid = &cLISTOP->op_first; - kid = cLISTOP->op_first; + if (o->op_flags & OPf_KIDS) { + tokid = &cLISTOPo->op_first; + kid = cLISTOPo->op_first; if (kid->op_type == OP_PUSHMARK || kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK) { @@ -4035,7 +4134,7 @@ OP *op; *tokid = kid; } else if (kid->op_type != OP_RV2AV && kid->op_type != OP_PADAV) - bad_type(numargs, "array", op_desc[op->op_type], kid); + bad_type(numargs, "array", op_desc[o->op_type], kid); mod(kid, type); break; case OA_HVREF: @@ -4053,7 +4152,7 @@ OP *op; *tokid = kid; } else if (kid->op_type != OP_RV2HV && kid->op_type != OP_PADHV) - bad_type(numargs, "hash", op_desc[op->op_type], kid); + bad_type(numargs, "hash", op_desc[o->op_type], kid); mod(kid, type); break; case OA_CVREF: @@ -4094,13 +4193,13 @@ OP *op; tokid = &kid->op_sibling; kid = kid->op_sibling; } - op->op_private |= numargs; + o->op_private |= numargs; if (kid) - return too_many_arguments(op,op_desc[op->op_type]); - listkids(op); + return too_many_arguments(o,op_desc[o->op_type]); + listkids(o); } else if (opargs[type] & OA_DEFGV) { - op_free(op); + op_free(o); return newUNOP(type, 0, newSVREF(newGVOP(OP_GV, 0, defgv))); } @@ -4108,14 +4207,14 @@ OP *op; while (oa & OA_OPTIONAL) oa >>= 4; if (oa && oa != OA_LIST) - return too_few_arguments(op,op_desc[op->op_type]); + return too_few_arguments(o,op_desc[o->op_type]); } - return op; + return o; } OP * -ck_glob(op) -OP *op; +ck_glob(o) +OP *o; { GV *gv = gv_fetchpv("glob", FALSE, SVt_PVCV); @@ -4138,57 +4237,57 @@ OP *op; append_elem(OP_GLOB, op, newSVREF(newGVOP(OP_GV, 0, defgv))); gv = newGVgen("main"); gv_IOadd(gv); - append_elem(OP_GLOB, op, newGVOP(OP_GV, 0, gv)); - scalarkids(op); - return ck_fun(op); + append_elem(OP_GLOB, o, newGVOP(OP_GV, 0, gv)); + scalarkids(o); + return ck_fun(o); } OP * -ck_grep(op) -OP *op; +ck_grep(o) +OP *o; { LOGOP *gwop; OP *kid; - OPCODE type = op->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE; + OPCODE type = o->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE; - op->op_ppaddr = ppaddr[OP_GREPSTART]; + o->op_ppaddr = ppaddr[OP_GREPSTART]; Newz(1101, gwop, 1, LOGOP); - if (op->op_flags & OPf_STACKED) { + if (o->op_flags & OPf_STACKED) { OP* k; - op = ck_sort(op); - kid = cLISTOP->op_first->op_sibling; - for (k = cLISTOP->op_first->op_sibling->op_next; k; k = k->op_next) { + o = ck_sort(o); + kid = cLISTOPo->op_first->op_sibling; + for (k = cLISTOPo->op_first->op_sibling->op_next; k; k = k->op_next) { kid = k; } kid->op_next = (OP*)gwop; - op->op_flags &= ~OPf_STACKED; + o->op_flags &= ~OPf_STACKED; } - kid = cLISTOP->op_first->op_sibling; + kid = cLISTOPo->op_first->op_sibling; if (type == OP_MAPWHILE) list(kid); else scalar(kid); - op = ck_fun(op); + o = ck_fun(o); if (error_count) - return op; - kid = cLISTOP->op_first->op_sibling; + return o; + kid = cLISTOPo->op_first->op_sibling; if (kid->op_type != OP_NULL) croak("panic: ck_grep"); kid = kUNOP->op_first; gwop->op_type = type; gwop->op_ppaddr = ppaddr[type]; - gwop->op_first = listkids(op); + gwop->op_first = listkids(o); gwop->op_flags |= OPf_KIDS; gwop->op_private = 1; gwop->op_other = LINKLIST(kid); gwop->op_targ = pad_alloc(type, SVs_PADTMP); kid->op_next = (OP*)gwop; - kid = cLISTOP->op_first->op_sibling; + kid = cLISTOPo->op_first->op_sibling; if (!kid || !kid->op_sibling) - return too_few_arguments(op,op_desc[op->op_type]); + return too_few_arguments(o,op_desc[o->op_type]); for (kid = kid->op_sibling; kid; kid = kid->op_sibling) mod(kid, OP_GREPSTART); @@ -4196,142 +4295,142 @@ OP *op; } OP * -ck_index(op) -OP *op; +ck_index(o) +OP *o; { - if (op->op_flags & OPf_KIDS) { - OP *kid = cLISTOP->op_first->op_sibling; /* get past pushmark */ + if (o->op_flags & OPf_KIDS) { + OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ if (kid && kid->op_type == OP_CONST) fbm_compile(((SVOP*)kid)->op_sv); } - return ck_fun(op); + return ck_fun(o); } OP * -ck_lengthconst(op) -OP *op; +ck_lengthconst(o) +OP *o; { /* XXX length optimization goes here */ - return ck_fun(op); + return ck_fun(o); } OP * -ck_lfun(op) -OP *op; +ck_lfun(o) +OP *o; { - OPCODE type = op->op_type; - return modkids(ck_fun(op), type); + OPCODE type = o->op_type; + return modkids(ck_fun(o), type); } OP * -ck_rfun(op) -OP *op; +ck_rfun(o) +OP *o; { - OPCODE type = op->op_type; - return refkids(ck_fun(op), type); + OPCODE type = o->op_type; + return refkids(ck_fun(o), type); } OP * -ck_listiob(op) -OP *op; +ck_listiob(o) +OP *o; { register OP *kid; - kid = cLISTOP->op_first; + kid = cLISTOPo->op_first; if (!kid) { - op = force_list(op); - kid = cLISTOP->op_first; + o = force_list(o); + kid = cLISTOPo->op_first; } if (kid->op_type == OP_PUSHMARK) kid = kid->op_sibling; - if (kid && op->op_flags & OPf_STACKED) + if (kid && o->op_flags & OPf_STACKED) kid = kid->op_sibling; else if (kid && !kid->op_sibling) { /* print HANDLE; */ if (kid->op_type == OP_CONST && kid->op_private & OPpCONST_BARE) { - op->op_flags |= OPf_STACKED; /* make it a filehandle */ + o->op_flags |= OPf_STACKED; /* make it a filehandle */ kid = newUNOP(OP_RV2GV, OPf_REF, scalar(kid)); - cLISTOP->op_first->op_sibling = kid; - cLISTOP->op_last = kid; + cLISTOPo->op_first->op_sibling = kid; + cLISTOPo->op_last = kid; kid = kid->op_sibling; } } if (!kid) - append_elem(op->op_type, op, newSVREF(newGVOP(OP_GV, 0, defgv)) ); + append_elem(o->op_type, o, newSVREF(newGVOP(OP_GV, 0, defgv)) ); - op = listkids(op); + o = listkids(o); - op->op_private = 0; + o->op_private = 0; #ifdef USE_LOCALE if (hints & HINT_LOCALE) - op->op_private |= OPpLOCALE; + o->op_private |= OPpLOCALE; #endif - return op; + return o; } OP * -ck_fun_locale(op) -OP *op; +ck_fun_locale(o) +OP *o; { - op = ck_fun(op); + o = ck_fun(o); - op->op_private = 0; + o->op_private = 0; #ifdef USE_LOCALE if (hints & HINT_LOCALE) - op->op_private |= OPpLOCALE; + o->op_private |= OPpLOCALE; #endif - return op; + return o; } OP * -ck_scmp(op) -OP *op; +ck_scmp(o) +OP *o; { - op->op_private = 0; + o->op_private = 0; #ifdef USE_LOCALE if (hints & HINT_LOCALE) - op->op_private |= OPpLOCALE; + o->op_private |= OPpLOCALE; #endif - return op; + return o; } OP * -ck_match(op) -OP *op; +ck_match(o) +OP *o; { - op->op_private |= OPpRUNTIME; - return op; + o->op_private |= OPpRUNTIME; + return o; } OP * -ck_null(op) -OP *op; +ck_null(o) +OP *o; { - return op; + return o; } OP * -ck_repeat(op) -OP *op; +ck_repeat(o) +OP *o; { - if (cBINOP->op_first->op_flags & OPf_PARENS) { - op->op_private |= OPpREPEAT_DOLIST; - cBINOP->op_first = force_list(cBINOP->op_first); + if (cBINOPo->op_first->op_flags & OPf_PARENS) { + o->op_private |= OPpREPEAT_DOLIST; + cBINOPo->op_first = force_list(cBINOPo->op_first); } else - scalar(op); - return op; + scalar(o); + return o; } OP * -ck_require(op) -OP *op; +ck_require(o) +OP *o; { - if (op->op_flags & OPf_KIDS) { /* Shall we supply missing .pm? */ - SVOP *kid = (SVOP*)cUNOP->op_first; + if (o->op_flags & OPf_KIDS) { /* Shall we supply missing .pm? */ + SVOP *kid = (SVOP*)cUNOPo->op_first; if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) { char *s; @@ -4345,68 +4444,68 @@ OP *op; sv_catpvn(kid->op_sv, ".pm", 3); } } - return ck_fun(op); + return ck_fun(o); } OP * -ck_retarget(op) -OP *op; +ck_retarget(o) +OP *o; { croak("NOT IMPL LINE %d",__LINE__); /* STUB */ - return op; + return o; } OP * -ck_select(op) -OP *op; +ck_select(o) +OP *o; { OP* kid; - if (op->op_flags & OPf_KIDS) { - kid = cLISTOP->op_first->op_sibling; /* get past pushmark */ + if (o->op_flags & OPf_KIDS) { + kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ if (kid && kid->op_sibling) { - op->op_type = OP_SSELECT; - op->op_ppaddr = ppaddr[OP_SSELECT]; - op = ck_fun(op); - return fold_constants(op); + o->op_type = OP_SSELECT; + o->op_ppaddr = ppaddr[OP_SSELECT]; + o = ck_fun(o); + return fold_constants(o); } } - op = ck_fun(op); - kid = cLISTOP->op_first->op_sibling; /* get past pushmark */ + o = ck_fun(o); + kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ if (kid && kid->op_type == OP_RV2GV) kid->op_private &= ~HINT_STRICT_REFS; - return op; + return o; } OP * -ck_shift(op) -OP *op; +ck_shift(o) +OP *o; { - I32 type = op->op_type; + I32 type = o->op_type; - if (!(op->op_flags & OPf_KIDS)) { - op_free(op); + if (!(o->op_flags & OPf_KIDS)) { + op_free(o); return newUNOP(type, 0, scalar(newUNOP(OP_RV2AV, 0, scalar(newGVOP(OP_GV, 0, subline ? defgv : gv_fetchpv("ARGV", TRUE, SVt_PVAV) ))))); } - return scalar(modkids(ck_fun(op), type)); + return scalar(modkids(ck_fun(o), type)); } OP * -ck_sort(op) -OP *op; +ck_sort(o) +OP *o; { - op->op_private = 0; + o->op_private = 0; #ifdef USE_LOCALE if (hints & HINT_LOCALE) - op->op_private |= OPpLOCALE; + o->op_private |= OPpLOCALE; #endif - if (op->op_flags & OPf_STACKED) { - OP *kid = cLISTOP->op_first->op_sibling; /* get past pushmark */ + if (o->op_flags & OPf_STACKED) { + OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ OP *k; kid = kUNOP->op_first; /* get past rv2gv */ @@ -4417,7 +4516,7 @@ OP *op; kid->op_next = 0; } else if (kid->op_type == OP_LEAVE) { - if (op->op_type == OP_SORT) { + if (o->op_type == OP_SORT) { null(kid); /* wipe out leave */ kid->op_next = kid; @@ -4432,47 +4531,47 @@ OP *op; } peep(k); - kid = cLISTOP->op_first->op_sibling; /* get past pushmark */ + kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ null(kid); /* wipe out rv2gv */ - if (op->op_type == OP_SORT) + if (o->op_type == OP_SORT) kid->op_next = kid; else kid->op_next = k; - op->op_flags |= OPf_SPECIAL; + o->op_flags |= OPf_SPECIAL; } } - return op; + return o; } OP * -ck_split(op) -OP *op; +ck_split(o) +OP *o; { register OP *kid; PMOP* pm; - if (op->op_flags & OPf_STACKED) - return no_fh_allowed(op); + if (o->op_flags & OPf_STACKED) + return no_fh_allowed(o); - kid = cLISTOP->op_first; + kid = cLISTOPo->op_first; if (kid->op_type != OP_NULL) croak("panic: ck_split"); kid = kid->op_sibling; - op_free(cLISTOP->op_first); - cLISTOP->op_first = kid; + op_free(cLISTOPo->op_first); + cLISTOPo->op_first = kid; if (!kid) { - cLISTOP->op_first = kid = newSVOP(OP_CONST, 0, newSVpv(" ", 1)); - cLISTOP->op_last = kid; /* There was only one element previously */ + cLISTOPo->op_first = kid = newSVOP(OP_CONST, 0, newSVpv(" ", 1)); + cLISTOPo->op_last = kid; /* There was only one element previously */ } if (kid->op_type != OP_MATCH) { OP *sibl = kid->op_sibling; kid->op_sibling = 0; kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, Nullop); - if (cLISTOP->op_first == cLISTOP->op_last) - cLISTOP->op_last = kid; - cLISTOP->op_first = kid; + if (cLISTOPo->op_first == cLISTOPo->op_last) + cLISTOPo->op_last = kid; + cLISTOPo->op_first = kid; kid->op_sibling = sibl; } pm = (PMOP*)kid; @@ -4486,30 +4585,31 @@ OP *op; scalar(kid); if (!kid->op_sibling) - append_elem(OP_SPLIT, op, newSVREF(newGVOP(OP_GV, 0, defgv)) ); + append_elem(OP_SPLIT, o, newSVREF(newGVOP(OP_GV, 0, defgv)) ); kid = kid->op_sibling; scalar(kid); if (!kid->op_sibling) - append_elem(OP_SPLIT, op, newSVOP(OP_CONST, 0, newSViv(0))); + append_elem(OP_SPLIT, o, newSVOP(OP_CONST, 0, newSViv(0))); kid = kid->op_sibling; scalar(kid); if (kid->op_sibling) - return too_many_arguments(op,op_desc[op->op_type]); + return too_many_arguments(o,op_desc[o->op_type]); - return op; + return o; } OP * -ck_subr(op) -OP *op; +ck_subr(o) +OP *o; { - OP *prev = ((cUNOP->op_first->op_sibling) - ? cUNOP : ((UNOP*)cUNOP->op_first))->op_first; - OP *o = prev->op_sibling; + dTHR; + OP *prev = ((cUNOPo->op_first->op_sibling) + ? cUNOPo : ((UNOP*)cUNOPo->op_first))->op_first; + OP *o2 = prev->op_sibling; OP *cvop; char *proto = 0; CV *cv = 0; @@ -4517,28 +4617,28 @@ OP *op; int optional = 0; I32 arg = 0; - for (cvop = o; cvop->op_sibling; cvop = cvop->op_sibling) ; + for (cvop = o2; cvop->op_sibling; cvop = cvop->op_sibling) ; if (cvop->op_type == OP_RV2CV) { SVOP* tmpop; - op->op_private |= (cvop->op_private & OPpENTERSUB_AMPER); + o->op_private |= (cvop->op_private & OPpENTERSUB_AMPER); null(cvop); /* disable rv2cv */ tmpop = (SVOP*)((UNOP*)cvop)->op_first; if (tmpop->op_type == OP_GV) { cv = GvCVu(tmpop->op_sv); - if (cv && SvPOK(cv) && !(op->op_private & OPpENTERSUB_AMPER)) { + if (cv && SvPOK(cv) && !(o->op_private & OPpENTERSUB_AMPER)) { namegv = CvANON(cv) ? (GV*)tmpop->op_sv : CvGV(cv); proto = SvPV((SV*)cv, na); } } } - op->op_private |= (hints & HINT_STRICT_REFS); + o->op_private |= (hints & HINT_STRICT_REFS); if (perldb && curstash != debstash) - op->op_private |= OPpENTERSUB_DB; - while (o != cvop) { + o->op_private |= OPpENTERSUB_DB; + while (o2 != cvop) { if (proto) { switch (*proto) { case '\0': - return too_many_arguments(op, gv_ename(namegv)); + return too_many_arguments(o, gv_ename(namegv)); case ';': optional = 1; proto++; @@ -4546,28 +4646,28 @@ OP *op; case '$': proto++; arg++; - scalar(o); + scalar(o2); break; case '%': case '@': - list(o); + list(o2); arg++; break; case '&': proto++; arg++; - if (o->op_type != OP_REFGEN && o->op_type != OP_UNDEF) - bad_type(arg, "block", gv_ename(namegv), o); + if (o2->op_type != OP_REFGEN && o2->op_type != OP_UNDEF) + bad_type(arg, "block", gv_ename(namegv), o2); break; case '*': proto++; arg++; - if (o->op_type == OP_RV2GV) + if (o2->op_type == OP_RV2GV) goto wrapref; { - OP* kid = o; - o = newUNOP(OP_RV2GV, 0, kid); - o->op_sibling = kid->op_sibling; + OP* kid = o2; + o2 = newUNOP(OP_RV2GV, 0, kid); + o2->op_sibling = kid->op_sibling; kid->op_sibling = 0; prev->op_sibling = o; } @@ -4577,29 +4677,29 @@ OP *op; arg++; switch (*proto++) { case '*': - if (o->op_type != OP_RV2GV) - bad_type(arg, "symbol", gv_ename(namegv), o); + if (o2->op_type != OP_RV2GV) + bad_type(arg, "symbol", gv_ename(namegv), o2); goto wrapref; case '&': - if (o->op_type != OP_RV2CV) - bad_type(arg, "sub", gv_ename(namegv), o); + if (o2->op_type != OP_RV2CV) + bad_type(arg, "sub", gv_ename(namegv), o2); goto wrapref; case '$': - if (o->op_type != OP_RV2SV && o->op_type != OP_PADSV) - bad_type(arg, "scalar", gv_ename(namegv), o); + if (o2->op_type != OP_RV2SV && o2->op_type != OP_PADSV) + bad_type(arg, "scalar", gv_ename(namegv), o2); goto wrapref; case '@': - if (o->op_type != OP_RV2AV && o->op_type != OP_PADAV) - bad_type(arg, "array", gv_ename(namegv), o); + if (o2->op_type != OP_RV2AV && o2->op_type != OP_PADAV) + bad_type(arg, "array", gv_ename(namegv), o2); goto wrapref; case '%': - if (o->op_type != OP_RV2HV && o->op_type != OP_PADHV) - bad_type(arg, "hash", gv_ename(namegv), o); + if (o2->op_type != OP_RV2HV && o2->op_type != OP_PADHV) + bad_type(arg, "hash", gv_ename(namegv), o2); wrapref: { - OP* kid = o; - o = newUNOP(OP_REFGEN, 0, kid); - o->op_sibling = kid->op_sibling; + OP* kid = o2; + o2 = newUNOP(OP_REFGEN, 0, kid); + o2->op_sibling = kid->op_sibling; kid->op_sibling = 0; prev->op_sibling = o; } @@ -4617,38 +4717,38 @@ OP *op; } } else - list(o); - mod(o, OP_ENTERSUB); - prev = o; - o = o->op_sibling; + list(o2); + mod(o2, OP_ENTERSUB); + prev = o2; + o2 = o2->op_sibling; } if (proto && !optional && *proto == '$') - return too_few_arguments(op, gv_ename(namegv)); - return op; + return too_few_arguments(o, gv_ename(namegv)); + return o; } OP * -ck_svconst(op) -OP *op; +ck_svconst(o) +OP *o; { - SvREADONLY_on(cSVOP->op_sv); - return op; + SvREADONLY_on(cSVOPo->op_sv); + return o; } OP * -ck_trunc(op) -OP *op; +ck_trunc(o) +OP *o; { - if (op->op_flags & OPf_KIDS) { - SVOP *kid = (SVOP*)cUNOP->op_first; + if (o->op_flags & OPf_KIDS) { + SVOP *kid = (SVOP*)cUNOPo->op_first; if (kid->op_type == OP_NULL) kid = (SVOP*)kid->op_sibling; if (kid && kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) - op->op_flags |= OPf_SPECIAL; + o->op_flags |= OPf_SPECIAL; } - return ck_fun(op); + return ck_fun(o); } /* A peephole optimizer. We visit the ops in the order they're to execute. */ @@ -4657,6 +4757,7 @@ void peep(o) register OP* o; { + dTHR; register OP* oldop = 0; if (!o || o->op_seq) return; @@ -24,6 +24,7 @@ */ typedef U32 PADOFFSET; +#define NOT_IN_PAD ((PADOFFSET) -1) #ifdef DEBUGGING_OPS #define OPCODE opcode @@ -233,6 +234,19 @@ struct loop { #define cCOP ((COP*)op) #define cLOOP ((LOOP*)op) +#define cUNOPo ((UNOP*)o) +#define cBINOPo ((BINOP*)o) +#define cLISTOPo ((LISTOP*)o) +#define cLOGOPo ((LOGOP*)o) +#define cCONDOPo ((CONDOP*)o) +#define cPMOPo ((PMOP*)o) +#define cSVOPo ((SVOP*)o) +#define cGVOPo ((GVOP*)o) +#define cPVOPo ((PVOP*)o) +#define cCVOPo ((CVOP*)o) +#define cCOPo ((COP*)o) +#define cLOOPo ((LOOP*)o) + #define kUNOP ((UNOP*)kid) #define kBINOP ((BINOP*)kid) #define kLISTOP ((LISTOP*)kid) @@ -82,13 +82,13 @@ END # Emit function declarations. for (sort keys %ckname) { - print "OP *\t", &tab(3,$_),"_((OP* op));\n"; + print "OP *\t", &tab(3,$_),"_((OP* o));\n"; } print "\n"; for (@ops) { - print "OP *\t", &tab(3, "pp_\L$_"), "_((void));\n"; + print "OP *\t", &tab(3, "pp_\L$_"), "_((ARGSproto));\n"; } # Emit ppcode switch array. @@ -72,10 +72,12 @@ static void init_main_stash _((void)); static void init_perllib _((void)); static void init_postdump_symbols _((int, char **, char **)); static void init_predump_symbols _((void)); -static void init_stacks _((void)); static void my_exit_jump _((void)) __attribute__((noreturn)); static void nuke_stacks _((void)); static void open_script _((char *, bool, SV *)); +#ifdef USE_THREADS +static void thread_destruct _((void *)); +#endif /* USE_THREADS */ static void usage _((char *)); static void validate_suid _((char *, char*)); @@ -95,6 +97,10 @@ void perl_construct( sv_interp ) register PerlInterpreter *sv_interp; { +#ifdef USE_THREADS + struct thread *thr; +#endif /* USE_THREADS */ + if (!(curinterp = sv_interp)) return; @@ -102,6 +108,21 @@ register PerlInterpreter *sv_interp; Zero(sv_interp, 1, PerlInterpreter); #endif +#ifdef USE_THREADS +#ifdef NEED_PTHREAD_INIT + pthread_init(); +#endif /* NEED_PTHREAD_INIT */ + New(53, thr, 1, struct thread); + self = pthread_self(); + if (pthread_key_create(&thr_key, thread_destruct)) + croak("panic: pthread_key_create"); + if (pthread_setspecific(thr_key, (void *) thr)) + croak("panic: pthread_setspecific"); + nthreads = 1; + cvcache = newHV(); + thrflags = 0; +#endif /* USE_THREADS */ + /* Init the real globals? */ if (!linestr) { linestr = NEWSV(65,80); @@ -122,6 +143,12 @@ register PerlInterpreter *sv_interp; nrs = newSVpv("\n", 1); rs = SvREFCNT_inc(nrs); + MUTEX_INIT(&malloc_mutex); + MUTEX_INIT(&sv_mutex); + MUTEX_INIT(&eval_mutex); + MUTEX_INIT(&nthreads_mutex); + COND_INIT(&nthreads_cond); + pidstatus = newHV(); #ifdef MSDOS @@ -169,14 +196,42 @@ register PerlInterpreter *sv_interp; fdpid = newAV(); /* for remembering popen pids by fd */ - init_stacks(); + init_stacks(ARGS); + DEBUG( { + New(51,debname,128,char); + New(52,debdelim,128,char); + } ) + ENTER; } +#ifdef USE_THREADS +void +thread_destruct(arg) +void *arg; +{ + struct thread *thr = (struct thread *) arg; + /* + * Decrement the global thread count and signal anyone listening. + * The only official thread listening is the original thread while + * in perl_destruct. It waits until it's the only thread and then + * performs END blocks and other process clean-ups. + */ + DEBUG_L(fprintf(stderr, "thread_destruct: 0x%lx\n", (unsigned long) thr)); + + Safefree(thr); + MUTEX_LOCK(&nthreads_mutex); + nthreads--; + COND_BROADCAST(&nthreads_cond); + MUTEX_UNLOCK(&nthreads_mutex); +} +#endif /* USE_THREADS */ + void perl_destruct(sv_interp) register PerlInterpreter *sv_interp; { + dTHR; int destruct_level; /* 0=none, 1=full, 2=full with checks */ I32 last_sv_count; HV *hv; @@ -184,6 +239,22 @@ register PerlInterpreter *sv_interp; if (!(curinterp = sv_interp)) return; +#ifdef USE_THREADS + /* Wait until all user-created threads go away */ + MUTEX_LOCK(&nthreads_mutex); + while (nthreads > 1) + { + DEBUG_L(fprintf(stderr, "perl_destruct: waiting for %d threads\n", + nthreads - 1)); + COND_WAIT(&nthreads_cond, &nthreads_mutex); + } + /* At this point, we're the last thread */ + MUTEX_UNLOCK(&nthreads_mutex); + DEBUG_L(fprintf(stderr, "perl_destruct: armageddon has arrived\n")); + MUTEX_DESTROY(&nthreads_mutex); + COND_DESTROY(&nthreads_cond); +#endif /* USE_THREADS */ + destruct_level = perl_destruct_level; #ifdef DEBUGGING { @@ -431,6 +502,11 @@ register PerlInterpreter *sv_interp; hints = 0; /* Reset hints. Should hints be per-interpreter ? */ DEBUG_P(debprofdump()); +#ifdef USE_THREADS + MUTEX_DESTROY(&sv_mutex); + MUTEX_DESTROY(&malloc_mutex); + MUTEX_DESTROY(&eval_mutex); +#endif /* USE_THREADS */ /* As the absolutely last thing, free the non-arena SV for mess() */ @@ -461,6 +537,7 @@ int argc; char **argv; char **env; { + dTHR; register SV *sv; register char *s; char *scriptname = NULL; @@ -753,12 +830,22 @@ print \" \\@INC:\\n @INC\\n\";"); main_cv = compcv = (CV*)NEWSV(1104,0); sv_upgrade((SV *)compcv, SVt_PVCV); CvUNIQUE_on(compcv); +#ifdef USE_THREADS + CvOWNER(compcv) = 0; + New(666, CvMUTEXP(compcv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(compcv)); + New(666, CvCONDP(compcv), 1, pthread_cond_t); + COND_INIT(CvCONDP(compcv)); +#endif /* USE_THREADS */ comppad = newAV(); av_push(comppad, Nullsv); curpad = AvARRAY(comppad); comppad_name = newAV(); comppad_name_fill = 0; +#ifdef USE_THREADS + av_store(comppad_name, 0, newSVpv("@_", 2)); +#endif /* USE_THREADS */ min_intro_pending = 0; padix = 0; @@ -830,6 +917,7 @@ int perl_run(sv_interp) PerlInterpreter *sv_interp; { + dTHR; I32 oldscope; dJMPENV; int ret; @@ -878,6 +966,10 @@ PerlInterpreter *sv_interp; if (!restartop) { DEBUG_x(dump_all()); DEBUG(PerlIO_printf(Perl_debug_log, "\nEXECUTING...\n\n")); +#ifdef USE_THREADS + DEBUG_L(PerlIO_printf(Perl_debug_log, "main thread is 0x%lx\n", + (unsigned long) thr)); +#endif /* USE_THREADS */ if (minus_c) { PerlIO_printf(PerlIO_stderr(), "%s syntax OK\n", origfilename); @@ -968,6 +1060,7 @@ char *subname; I32 flags; /* See G_* flags in cop.h */ register char **argv; /* null terminated arg list */ { + dTHR; dSP; PUSHMARK(sp); @@ -994,13 +1087,14 @@ perl_call_method(methname, flags) char *methname; /* name of the subroutine */ I32 flags; /* See G_* flags in cop.h */ { + dTHR; dSP; OP myop; if (!op) op = &myop; XPUSHs(sv_2mortal(newSVpv(methname,0))); PUTBACK; - pp_method(); + pp_method(ARGS); return perl_call_sv(*stack_sp--, flags); } @@ -1010,6 +1104,7 @@ perl_call_sv(sv, flags) SV* sv; I32 flags; /* See G_* flags in cop.h */ { + dTHR; LOGOP myop; /* fake syntax tree node */ SV** sp = stack_sp; I32 oldmark; @@ -1108,7 +1203,7 @@ I32 flags; /* See G_* flags in cop.h */ CATCH_SET(TRUE); if (op == (OP*)&myop) - op = pp_entersub(); + op = pp_entersub(ARGS); if (op) runops(); retval = stack_sp - (stack_base + oldmark); @@ -1151,6 +1246,7 @@ perl_eval_sv(sv, flags) SV* sv; I32 flags; /* See G_* flags in cop.h */ { + dTHR; UNOP myop; /* fake syntax tree node */ SV** sp = stack_sp; I32 oldmark = sp - stack_base; @@ -1214,7 +1310,7 @@ I32 flags; /* See G_* flags in cop.h */ } if (op == (OP*)&myop) - op = pp_entereval(); + op = pp_entereval(ARGS); if (op) runops(); retval = stack_sp - (stack_base + oldmark); @@ -1432,30 +1528,31 @@ char *s; forbid_setid("-m"); /* XXX ? */ if (*++s) { char *start; + SV *sv; char *use = "use "; /* -M-foo == 'no foo' */ if (*s == '-') { use = "no "; ++s; } - Sv = newSVpv(use,0); + sv = newSVpv(use,0); start = s; /* We allow -M'Module qw(Foo Bar)' */ while(isALNUM(*s) || *s==':') ++s; if (*s != '=') { - sv_catpv(Sv, start); + sv_catpv(sv, start); if (*(start-1) == 'm') { if (*s != '\0') croak("Can't use '%c' after -mname", *s); - sv_catpv( Sv, " ()"); + sv_catpv( sv, " ()"); } } else { - sv_catpvn(Sv, start, s-start); - sv_catpv(Sv, " split(/,/,q{"); - sv_catpv(Sv, ++s); - sv_catpv(Sv, "})"); + sv_catpvn(sv, start, s-start); + sv_catpv(sv, " split(/,/,q{"); + sv_catpv(sv, ++s); + sv_catpv(sv, "})"); } s += strlen(s); if (preambleav == NULL) preambleav = newAV(); - av_push(preambleav, Sv); + av_push(preambleav, sv); } else croak("No space allowed after -%c", *(s-1)); @@ -1575,6 +1672,7 @@ my_unexec() static void init_main_stash() { + dTHR; GV *gv; /* Note that strtab is a rather special HV. Assumptions are made @@ -2147,6 +2245,7 @@ char *s; static void init_debugger() { + dTHR; curstash = debstash; dbargs = GvAV(gv_AVadd((gv_fetchpv("args", GV_ADDMULTI, SVt_PVAV)))); AvREAL_off(dbargs); @@ -2162,8 +2261,9 @@ init_debugger() curstash = defstash; } -static void -init_stacks() +void +init_stacks(ARGS) +dARGS { curstack = newAV(); mainstack = curstack; /* remember in case we switch stacks */ @@ -2182,11 +2282,6 @@ init_stacks() tmps_ix = -1; tmps_max = 128; - DEBUG( { - New(51,debname,128,char); - New(52,debdelim,128,char); - } ) - /* * The following stacks almost certainly should be per-interpreter, * but for now they're not. XXX @@ -2234,6 +2329,7 @@ nuke_stacks() Safefree(debname); Safefree(debdelim); } ) +<<<< } static PerlIO *tmpfp; /* moved outside init_lexer() because of UNICOS bug */ @@ -2250,6 +2346,7 @@ init_lexer() static void init_predump_symbols() { + dTHR; GV *tmpgv; GV *othergv; @@ -2533,6 +2630,7 @@ call_list(oldscope, list) I32 oldscope; AV* list; { + dTHR; line_t oldline = curcop->cop_line; STRLEN len; dJMPENV; @@ -2605,6 +2703,12 @@ void my_exit(status) U32 status; { + dTHR; + +#ifdef USE_THREADS + DEBUG_L(PerlIO_printf(Perl_debug_log, "my_exit: thread 0x%lx, status %lu\n", + (unsigned long) thr, (unsigned long) status)); +#endif /* USE_THREADS */ switch (status) { case 0: STATUS_ALL_SUCCESS; @@ -52,6 +52,10 @@ # endif #endif +#ifdef USE_THREADS +#include <pthread.h> +#endif + /* * SOFT_CAST can be used for args to prototyped functions to retain some * type checking; it only casts if the compiler does not know prototypes. @@ -988,6 +992,12 @@ union any { void (*any_dptr) _((void*)); }; +#ifdef USE_THREADS +#define ARGSproto struct thread * +#else +#define ARGSproto void +#endif /* USE_THREADS */ + /* Work around some cygwin32 problems with importing global symbols */ #if defined(CYGWIN32) && defined(DLLIMPORT) # include "cw32imp.h" @@ -1291,6 +1301,18 @@ typedef Sighandler_t Sigsave_t; /* global state */ EXT PerlInterpreter * curinterp; /* currently running interpreter */ +#ifdef USE_THREADS +EXT pthread_key_t thr_key; /* For per-thread struct thread ptr */ +EXT pthread_mutex_t sv_mutex; /* Mutex for allocating SVs in sv.c */ +EXT pthread_mutex_t malloc_mutex; /* Mutex for malloc */ +EXT pthread_mutex_t eval_mutex; /* Mutex for doeval */ +EXT pthread_cond_t eval_cond; /* Condition variable for doeval */ +EXT struct thread * eval_owner; /* Owner thread for doeval */ +EXT int nthreads; /* Number of threads currently */ +EXT pthread_mutex_t nthreads_mutex; /* Mutex for nthreads */ +EXT pthread_cond_t nthreads_cond; /* Condition variable for nthreads */ +#endif /* USE_THREADS */ + /* VMS doesn't use environ array and NeXT has problems with crt0.o globals */ #if !defined(VMS) && !(defined(NeXT) && defined(__DYNAMIC__)) #ifndef DONT_DECLARE_STD @@ -1901,6 +1923,7 @@ struct interpreter { }; #endif +#include "thread.h" #include "pp.h" #ifdef __cplusplus @@ -1976,6 +1999,9 @@ EXT MGVTBL vtbl_fm = {0, magic_setfm, EXT MGVTBL vtbl_uvar = {magic_getuvar, magic_setuvar, 0, 0, 0}; +#ifdef USE_THREADS +EXT MGVTBL vtbl_mutex = {0, 0, 0, 0, magic_mutexfree}; +#endif /* USE_THREADS */ EXT MGVTBL vtbl_defelem = {magic_getdefelem,magic_setdefelem, 0, 0, magic_freedefelem}; @@ -2015,6 +2041,11 @@ EXT MGVTBL vtbl_pos; EXT MGVTBL vtbl_bm; EXT MGVTBL vtbl_fm; EXT MGVTBL vtbl_uvar; + +#ifdef USE_THREADS +EXT MGVTBL vtbl_mutex; +#endif /* USE_THREADS */ + EXT MGVTBL vtbl_defelem; #ifdef USE_LOCALE_COLLATE @@ -7,10 +7,15 @@ * */ +#ifdef USE_THREADS +#define ARGS thr +#define dARGS struct thread *thr; +#define PP(s) OP* s(ARGS) dARGS +#else #define ARGS -#define ARGSproto void #define dARGS #define PP(s) OP* s(ARGS) dARGS +#endif /* USE_THREADS */ #define SP sp #define MARK mark @@ -27,7 +27,7 @@ static OP *docatch _((OP *o)); static OP *doeval _((int gimme)); -static OP *dofindlabel _((OP *op, char *label, OP **opstack, OP **oplimit)); +static OP *dofindlabel _((OP *o, char *label, OP **opstack, OP **oplimit)); static void doparseform _((SV *sv)); static I32 dopoptoeval _((I32 startingblock)); static I32 dopoptolabel _((char *label)); @@ -533,8 +533,8 @@ PP(pp_grepstart) RETURNOP(op->op_next->op_next); } stack_sp = stack_base + *markstack_ptr + 1; - pp_pushmark(); /* push dst */ - pp_pushmark(); /* push src */ + pp_pushmark(ARGS); /* push dst */ + pp_pushmark(ARGS); /* push src */ ENTER; /* enter outer scope */ SAVETMPS; @@ -549,7 +549,7 @@ PP(pp_grepstart) PUTBACK; if (op->op_type == OP_MAPSTART) - pp_pushmark(); /* push top */ + pp_pushmark(ARGS); /* push top */ return ((LOGOP*)op->op_next)->op_other; } @@ -849,6 +849,7 @@ static I32 dopoptolabel(label) char *label; { + dTHR; register I32 i; register CONTEXT *cx; @@ -895,6 +896,7 @@ dowantarray() I32 block_gimme() { + dTHR; I32 cxix; cxix = dopoptosub(cxstack_ix); @@ -917,6 +919,7 @@ static I32 dopoptosub(startingblock) I32 startingblock; { + dTHR; I32 i; register CONTEXT *cx; for (i = startingblock; i >= 0; i--) { @@ -937,6 +940,7 @@ static I32 dopoptoeval(startingblock) I32 startingblock; { + dTHR; I32 i; register CONTEXT *cx; for (i = startingblock; i >= 0; i--) { @@ -956,6 +960,7 @@ static I32 dopoptoloop(startingblock) I32 startingblock; { + dTHR; I32 i; register CONTEXT *cx; for (i = startingblock; i >= 0; i--) { @@ -989,6 +994,7 @@ void dounwind(cxix) I32 cxix; { + dTHR; register CONTEXT *cx; SV **newsp; I32 optype; @@ -1022,6 +1028,7 @@ OP * die_where(message) char *message; { + dTHR; if (in_eval) { I32 cxix; register CONTEXT *cx; @@ -1120,7 +1127,7 @@ PP(pp_entersubr) mark++; } *sp = cv; - return pp_entersub(); + return pp_entersub(ARGS); } #endif @@ -1226,6 +1233,7 @@ sortcv(a, b) const void *a; const void *b; { + dTHR; SV * const *str1 = (SV * const *)a; SV * const *str2 = (SV * const *)b; I32 oldsaveix = savestack_ix; @@ -1264,9 +1272,54 @@ const void *b; return sv_cmp_locale(*(SV * const *)a, *(SV * const *)b); } +#ifdef USE_THREADS +static void +unlock_condpair(svv) +void *svv; +{ + dTHR; + MAGIC *mg = mg_find((SV*)svv, 'm'); + + if (!mg) + croak("panic: unlock_condpair unlocking non-mutex"); + MUTEX_LOCK(MgMUTEXP(mg)); + if (MgOWNER(mg) != thr) + croak("panic: unlock_condpair unlocking mutex that we don't own"); + MgOWNER(mg) = 0; + COND_SIGNAL(MgOWNERCONDP(mg)); + MUTEX_UNLOCK(MgMUTEXP(mg)); +} +#endif /* USE_THREADS */ + PP(pp_reset) { dSP; +#ifdef USE_THREADS + dTOPss; + MAGIC *mg; + + if (MAXARG < 1) + croak("reset requires mutex argument with USE_THREADS"); + if (SvROK(sv)) { + /* + * Kludge to allow lock of real objects without requiring + * to pass in every type of argument by explicit reference. + */ + sv = SvRV(sv); + } + mg = condpair_magic(sv); + MUTEX_LOCK(MgMUTEXP(mg)); + if (MgOWNER(mg) == thr) + MUTEX_UNLOCK(MgMUTEXP(mg)); + else { + while (MgOWNER(mg)) + COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg)); + MgOWNER(mg) = thr; + MUTEX_UNLOCK(MgMUTEXP(mg)); + save_destructor(unlock_condpair, sv); + } + RETURN; +#else char *tmps; if (MAXARG < 1) @@ -1276,6 +1329,7 @@ PP(pp_reset) sv_reset(tmps, curcop->cop_stash); PUSHs(&sv_yes); RETURN; +#endif /* USE_THREADS */ } PP(pp_lineseq) @@ -1634,8 +1688,8 @@ PP(pp_redo) static OP* lastgotoprobe; static OP * -dofindlabel(op,label,opstack,oplimit) -OP *op; +dofindlabel(o,label,opstack,oplimit) +OP *o; char *label; OP **opstack; OP **oplimit; @@ -1646,24 +1700,24 @@ OP **oplimit; if (ops >= oplimit) croak(too_deep); - if (op->op_type == OP_LEAVE || - op->op_type == OP_SCOPE || - op->op_type == OP_LEAVELOOP || - op->op_type == OP_LEAVETRY) + if (o->op_type == OP_LEAVE || + o->op_type == OP_SCOPE || + o->op_type == OP_LEAVELOOP || + o->op_type == OP_LEAVETRY) { - *ops++ = cUNOP->op_first; + *ops++ = cUNOPo->op_first; if (ops >= oplimit) croak(too_deep); } *ops = 0; - if (op->op_flags & OPf_KIDS) { + if (o->op_flags & OPf_KIDS) { /* First try all the kids at this level, since that's likeliest. */ - for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) { + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) { if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) && kCOP->cop_label && strEQ(kCOP->cop_label, label)) return kid; } - for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) { + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) { if (kid == lastgotoprobe) continue; if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) && @@ -1671,8 +1725,8 @@ OP **oplimit; (ops[-1]->op_type != OP_NEXTSTATE && ops[-1]->op_type != OP_DBSTATE))) *ops++ = kid; - if (op = dofindlabel(kid, label, ops, oplimit)) - return op; + if (o = dofindlabel(kid, label, ops, oplimit)) + return o; } } *ops = 0; @@ -1939,7 +1993,7 @@ PP(pp_goto) OP *oldop = op; for (ix = 1; enterops[ix]; ix++) { op = enterops[ix]; - (*op->op_ppaddr)(); + (*op->op_ppaddr)(ARGS); } op = oldop; } @@ -2097,12 +2151,21 @@ static OP * doeval(gimme) int gimme; { + dTHR; dSP; OP *saveop = op; HV *newstash; CV *caller; AV* comppadlist; +#ifdef USE_THREADS + MUTEX_LOCK(&eval_mutex); + if (eval_owner && eval_owner != thr) + while (eval_owner) + COND_WAIT(&eval_cond, &eval_mutex); + eval_owner = thr; + MUTEX_UNLOCK(&eval_mutex); +#endif /* USE_THREADS */ in_eval = 1; PUSHMARK(SP); @@ -2122,10 +2185,20 @@ int gimme; compcv = (CV*)NEWSV(1104,0); sv_upgrade((SV *)compcv, SVt_PVCV); CvUNIQUE_on(compcv); +#ifdef USE_THREADS + CvOWNER(compcv) = 0; + New(666, CvMUTEXP(compcv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(compcv)); + New(666, CvCONDP(compcv), 1, pthread_cond_t); + COND_INIT(CvCONDP(compcv)); +#endif /* USE_THREADS */ comppad = newAV(); comppad_name = newAV(); comppad_name_fill = 0; +#ifdef USE_THREADS + av_store(comppad_name, 0, newSVpv("@_", 2)); +#endif /* USE_THREADS */ min_intro_pending = 0; av_push(comppad, Nullsv); curpad = AvARRAY(comppad); @@ -2218,8 +2291,14 @@ int gimme; /* compiled okay, so do it */ CvDEPTH(compcv) = 1; - SP = stack_base + POPMARK; /* pop original mark */ +#ifdef USE_THREADS + MUTEX_LOCK(&eval_mutex); + eval_owner = 0; + COND_SIGNAL(&eval_cond); + MUTEX_UNLOCK(&eval_mutex); +#endif /* USE_THREADS */ + RETURNOP(eval_start); } @@ -20,6 +20,43 @@ /* Hot code. */ +#ifdef USE_THREADS +static void +unset_cvowner(cvarg) +void *cvarg; +{ + register CV* cv = (CV *) cvarg; +#ifdef DEBUGGING + dTHR; +#endif /* DEBUGGING */ + + DEBUG_L((fprintf(stderr, "0x%lx unsetting CvOWNER of 0x%lx:%s\n", + (unsigned long)thr, (unsigned long)cv, SvPEEK((SV*)cv)))); + MUTEX_LOCK(CvMUTEXP(cv)); + /* assert(CvDEPTH(cv) == 0); */ + assert(thr == CvOWNER(cv)); + CvOWNER(cv) = 0; + if (CvCONDP(cv)) + COND_SIGNAL(CvCONDP(cv)); /* next please */ + MUTEX_UNLOCK(CvMUTEXP(cv)); + SvREFCNT_dec(cv); +} + +#if 0 +void +mutex_unlock(m) +void *m; +{ +#ifdef DEBUGGING + dTHR; + DEBUG_L((fprintf(stderr, "0x%lx unlocking mutex 0x%lx\n", + (unsigned long) thr, (unsigned long) m))); +#endif /* DEBUGGING */ + MUTEX_UNLOCK((pthread_mutex_t *) m); +} +#endif +#endif /* USE_THREADS */ + PP(pp_const) { dSP; @@ -982,6 +1019,7 @@ ret_no: OP * do_readline() { + dTHR; dSP; dTARGETSTACKED; register SV *sv; STRLEN tmplen = 0; @@ -1847,6 +1885,119 @@ PP(pp_entersub) DIE("No DBsub routine"); } +#ifdef USE_THREADS + MUTEX_LOCK(CvMUTEXP(cv)); + if (!CvCONDP(cv)) { +#ifdef DEBUGGING + DEBUG_L((fprintf(stderr, "0x%lx entering fast %s\n", + (unsigned long)thr, SvPEEK((SV*)cv)))); +#endif /* DEBUGGING */ + MUTEX_UNLOCK(CvMUTEXP(cv)); /* fast sub wants neither sync nor clone */ + } + else if (SvFLAGS(cv) & SVp_SYNC) { + /* + * It's a synchronised CV. Wait until it's free unless + * we own it already (in which case we're recursing). + */ + if (CvOWNER(cv) && CvOWNER(cv) != thr) { + do { + DEBUG_L((fprintf(stderr, "0x%lx wait for 0x%lx to leave %s\n", + (unsigned long)thr,(unsigned long)CvOWNER(cv), + SvPEEK((SV*)cv)))); + COND_WAIT(CvCONDP(cv), CvMUTEXP(cv)); /* yawn */ + } while (CvOWNER(cv)); + } + CvOWNER(cv) = thr; /* Assert ownership */ + SvREFCNT_inc(cv); + MUTEX_UNLOCK(CvMUTEXP(cv)); + if (CvDEPTH(cv) == 0) + SAVEDESTRUCTOR(unset_cvowner, (void*) cv); + } + else { + /* + * It's an ordinary unsynchronised CV so we must distinguish + * three cases. (1) It's ours already (and we're recursing); + * (2) it's free (but we may already be using a cached clone); + * (3) another thread owns it. Case (1) is easy: we just use it. + * Case (2) means we look for a clone--if we have one, use it + * otherwise grab ownership of cv. Case (3) means look we for a + * clone and have to create one if we don't already have one. + * Why look for a clone in case (2) when we could just grab + * ownership of cv straight away? Well, we could be recursing, + * i.e. we originally tried to enter cv while another thread + * owned it (hence we used a clone) but it has been freed up + * and we're now recursing into it. It may or may not be "better" + * to use the clone but at least CvDEPTH can be trusted. + */ + if (CvOWNER(cv) == thr) + MUTEX_UNLOCK(CvMUTEXP(cv)); + else { + /* Case (2) or (3) */ + SV **svp; + + /* + * XXX Might it be better to release CvMUTEXP(cv) while we + * do the hv_fetch? We might find someone has pinched it + * when we look again, in which case we would be in case + * (3) instead of (2) so we'd have to clone. Would the fact + * that we released the mutex more quickly make up for this? + */ + svp = hv_fetch(cvcache, (char *)cv, sizeof(cv), FALSE); + if (svp) { + /* We already have a clone to use */ + MUTEX_UNLOCK(CvMUTEXP(cv)); + cv = *(CV**)svp; + DEBUG_L(fprintf(stderr, + "entersub: 0x%lx already has clone 0x%lx:%s\n", + (unsigned long) thr, (unsigned long) cv, + SvPEEK((SV*)cv))); + CvOWNER(cv) = thr; + SvREFCNT_inc(cv); + if (CvDEPTH(cv) == 0) + SAVEDESTRUCTOR(unset_cvowner, (void*) cv); + } + else { + /* (2) => grab ownership of cv. (3) => make clone */ + if (!CvOWNER(cv)) { + CvOWNER(cv) = thr; + SvREFCNT_inc(cv); + MUTEX_UNLOCK(CvMUTEXP(cv)); + DEBUG_L(fprintf(stderr, + "entersub: 0x%lx grabbing 0x%lx:%s\n", + (unsigned long) thr, (unsigned long) cv, + SvPEEK((SV*)cv))); + } else { + /* Make a new clone. */ + CV *clonecv; + SvREFCNT_inc(cv); /* don't let it vanish from under us */ + MUTEX_UNLOCK(CvMUTEXP(cv)); + DEBUG_L((fprintf(stderr, + "entersub: 0x%lx cloning 0x%lx:%s\n", + (unsigned long) thr, (unsigned long) cv, + SvPEEK((SV*)cv)))); + /* + * We're creating a new clone so there's no race + * between the original MUTEX_UNLOCK and the + * SvREFCNT_inc since no one will be trying to undef + * it out from underneath us. At least, I don't think + * there's a race... + */ + clonecv = cv_clone(cv); + SvREFCNT_dec(cv); /* finished with this */ + hv_store(cvcache, (char*)cv, sizeof(cv), (SV*)clonecv,0); + CvOWNER(clonecv) = thr; + cv = clonecv; + SvREFCNT_inc(cv); + } + assert(CvDEPTH(cv) == 0); + SAVEDESTRUCTOR(unset_cvowner, (void*) cv); + } + } + } +#endif /* USE_THREADS */ + + gimme = GIMME; + if (CvXSUB(cv)) { if (CvOLDSTYLE(cv)) { I32 (*fp3)_((int,int,int)); @@ -530,7 +530,7 @@ PP(pp_tie) XPUSHs((SV*)GvCV(gv)); PUTBACK; - if (op = pp_entersub()) + if (op = pp_entersub(ARGS)) runops(); SPAGAIN; @@ -638,7 +638,7 @@ PP(pp_dbmopen) if (perldb && curstash != debstash) op->op_private |= OPpENTERSUB_DB; PUTBACK; - pp_pushmark(); + pp_pushmark(ARGS); EXTEND(sp, 5); PUSHs(sv); @@ -651,7 +651,7 @@ PP(pp_dbmopen) PUSHs((SV*)GvCV(gv)); PUTBACK; - if (op = pp_entersub()) + if (op = pp_entersub(ARGS)) runops(); SPAGAIN; @@ -659,7 +659,7 @@ PP(pp_dbmopen) sp--; op = (OP *) &myop; PUTBACK; - pp_pushmark(); + pp_pushmark(ARGS); PUSHs(sv); PUSHs(left); @@ -668,7 +668,7 @@ PP(pp_dbmopen) PUSHs((SV*)GvCV(gv)); PUTBACK; - if (op = pp_entersub()) + if (op = pp_entersub(ARGS)) runops(); SPAGAIN; } @@ -823,6 +823,7 @@ void setdefout(gv) GV *gv; { + dTHR; if (gv) (void)SvREFCNT_inc(gv); if (defoutgv) @@ -910,6 +911,7 @@ CV *cv; GV *gv; OP *retop; { + dTHR; register CONTEXT *cx; I32 gimme = GIMME_V; AV* padlist = CvPADLIST(cv); @@ -13,7 +13,7 @@ bool Gv_AMupdate _((HV* stash)); OP* append_elem _((I32 optype, OP* head, OP* tail)); OP* append_list _((I32 optype, LISTOP* first, LISTOP* last)); I32 apply _((I32 type, SV** mark, SV** sp)); -void assertref _((OP* op)); +void assertref _((OP* o)); SV* avhv_delete _((AV *ar, char* key, U32 klen, I32 flags)); SV* avhv_delete_ent _((AV *ar, SV* keysv, I32 flags, U32 hash)); bool avhv_exists _((AV *ar, char* key, U32 klen)); @@ -52,8 +52,11 @@ U32 cast_ulong _((double f)); I32 my_chsize _((int fd, Off_t length)); #endif OP* ck_gvconst _((OP* o)); -OP* ck_retarget _((OP* op)); -OP* convert _((I32 optype, I32 flags, OP* op)); +OP* ck_retarget _((OP* o)); +#ifdef USE_THREADS +MAGIC * condpair_magic _((SV *sv)); +#endif +OP* convert _((I32 optype, I32 flags, OP* o)); void croak _((const char* pat,...)) __attribute__((noreturn)); void cv_ckproto _((CV* cv, GV* gv, char* p)); CV* cv_clone _((CV* proto)); @@ -68,7 +71,7 @@ I32 filter_read _((int idx, SV* buffer, int maxlen)); I32 cxinc _((void)); void deb _((const char* pat,...)) __attribute__((format(printf,1,2))); void deb_growlevel _((void)); -I32 debop _((OP* op)); +I32 debop _((OP* o)); I32 debstackptrs _((void)); #ifdef DEBUGGING void debprofdump _((void)); @@ -91,7 +94,7 @@ I32 do_ipcctl _((I32 optype, SV** mark, SV** sp)); I32 do_ipcget _((I32 optype, SV** mark, SV** sp)); #endif void do_join _((SV* sv, SV* del, SV** mark, SV** sp)); -OP* do_kv _((void)); +OP* do_kv _((ARGSproto)); #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM) I32 do_msgrcv _((SV** mark, SV** sp)); I32 do_msgsnd _((SV** mark, SV** sp)); @@ -134,7 +137,7 @@ OP* force_list _((OP* arg)); OP* fold_constants _((OP* arg)); char* form _((const char* pat, ...)); void free_tmps _((void)); -OP* gen_constant_list _((OP* op)); +OP* gen_constant_list _((OP* o)); void gp_free _((GV* gv)); GP* gp_ref _((GP* gp)); GV* gv_AVadd _((GV* gv)); @@ -179,6 +182,7 @@ void hv_undef _((HV* tb)); I32 ibcmp _((char* a, char* b, I32 len)); I32 ibcmp_locale _((char* a, char* b, I32 len)); I32 ingroup _((I32 testgid, I32 effective)); +void init_stacks _((ARGSproto)); U32 intro_my _((void)); char* instr _((char* big, char* little)); bool io_close _((IO* io)); @@ -188,7 +192,7 @@ I32 keyword _((char* d, I32 len)); void leave_scope _((I32 base)); void lex_end _((void)); void lex_start _((SV* line)); -OP* linklist _((OP* op)); +OP* linklist _((OP* o)); OP* list _((OP* o)); OP* listkids _((OP* o)); OP* localize _((OP* arg, I32 lexical)); @@ -208,6 +212,9 @@ int magic_getsig _((SV* sv, MAGIC* mg)); int magic_gettaint _((SV* sv, MAGIC* mg)); int magic_getuvar _((SV* sv, MAGIC* mg)); U32 magic_len _((SV* sv, MAGIC* mg)); +#ifdef USE_THREADS +int magic_mutexfree _((SV* sv, MAGIC* mg)); +#endif /* USE_THREADS */ int magic_nextpack _((SV* sv, MAGIC* mg, SV* key)); int magic_set _((SV* sv, MAGIC* mg)); #ifdef OVERLOAD @@ -249,9 +256,12 @@ int mg_get _((SV* sv)); U32 mg_len _((SV* sv)); void mg_magical _((SV* sv)); int mg_set _((SV* sv)); -OP* mod _((OP* op, I32 type)); +OP* mod _((OP* o, I32 type)); char* moreswitches _((char* s)); -OP* my _((OP* op)); +#ifdef USE_THREADS +void mutex_unlock _((void *m)); +#endif /* USE_THREADS */ +OP* my _((OP* o)); #if !defined(HAS_BCOPY) || !defined(HAS_SAFE_BCOPY) char* my_bcopy _((char* from, char* to, I32 len)); #endif @@ -260,7 +270,7 @@ char* my_bzero _((char* loc, I32 len)); #endif void my_exit _((U32 status)) __attribute__((noreturn)); void my_failure_exit _((void)) __attribute__((noreturn)); -I32 my_lstat _((void)); +I32 my_lstat _((ARGSproto)); #if !defined(HAS_MEMCMP) || !defined(HAS_SANE_MEMCMP) I32 my_memcmp _((char* s1, char* s2, I32 len)); #endif @@ -270,30 +280,30 @@ void* my_memset _((char* loc, I32 ch, I32 len)); I32 my_pclose _((PerlIO* ptr)); PerlIO* my_popen _((char* cmd, char* mode)); void my_setenv _((char* nam, char* val)); -I32 my_stat _((void)); +I32 my_stat _((ARGSproto)); #ifdef MYSWAP short my_swap _((short s)); long my_htonl _((long l)); long my_ntohl _((long l)); #endif void my_unexec _((void)); -OP* newANONLIST _((OP* op)); -OP* newANONHASH _((OP* op)); +OP* newANONLIST _((OP* o)); +OP* newANONHASH _((OP* o)); OP* newANONSUB _((I32 floor, OP* proto, OP* block)); OP* newASSIGNOP _((I32 flags, OP* left, I32 optype, OP* right)); OP* newCONDOP _((I32 flags, OP* expr, OP* trueop, OP* falseop)); -void newFORM _((I32 floor, OP* op, OP* block)); +void newFORM _((I32 floor, OP* o, OP* block)); OP* newFOROP _((I32 flags, char* label, line_t forline, OP* scalar, OP* expr, OP*block, OP*cont)); OP* newLOGOP _((I32 optype, I32 flags, OP* left, OP* right)); OP* newLOOPEX _((I32 type, OP* label)); OP* newLOOPOP _((I32 flags, I32 debuggable, OP* expr, OP* block)); OP* newNULLLIST _((void)); OP* newOP _((I32 optype, I32 flags)); -void newPROG _((OP* op)); +void newPROG _((OP* o)); OP* newRANGE _((I32 flags, OP* left, OP* right)); OP* newSLICEOP _((I32 flags, OP* subscript, OP* list)); OP* newSTATEOP _((I32 flags, char* label, OP* o)); -CV* newSUB _((I32 floor, OP* op, OP* proto, OP* block)); +CV* newSUB _((I32 floor, OP* o, OP* proto, OP* block)); CV* newXS _((char* name, void (*subaddr)(CV* cv), char* filename)); #ifdef DEPRECATED CV* newXSUB _((char* name, I32 ix, I32 (*subaddr)(int,int,int), char* filename)); @@ -331,7 +341,7 @@ PerlIO* nextargv _((GV* gv)); char* ninstr _((char* big, char* bigend, char* little, char* lend)); OP* oopsCV _((OP* o)); void op_free _((OP* arg)); -void package _((OP* op)); +void package _((OP* o)); PADOFFSET pad_alloc _((I32 optype, U32 tmptype)); PADOFFSET pad_allocmy _((char* name)); PADOFFSET pad_findmy _((char* name)); @@ -342,7 +352,7 @@ SV* pad_sv _((PADOFFSET po)); void pad_free _((PADOFFSET po)); void pad_reset _((void)); void pad_swipe _((PADOFFSET po)); -void peep _((OP* op)); +void peep _((OP* o)); PerlInterpreter* perl_alloc _((void)); I32 perl_call_argv _((char* subname, I32 flags, char** argv)); I32 perl_call_method _((char* methname, I32 flags)); @@ -371,20 +381,20 @@ int perl_run _((PerlInterpreter* sv_interp)); void pidgone _((int pid, int status)); void pmflag _((U16* pmfl, int ch)); OP* pmruntime _((OP* pm, OP* expr, OP* repl)); -OP* pmtrans _((OP* op, OP* expr, OP* repl)); +OP* pmtrans _((OP* o, OP* expr, OP* repl)); OP* pop_return _((void)); void pop_scope _((void)); OP* prepend_elem _((I32 optype, OP* head, OP* tail)); -void push_return _((OP* op)); +void push_return _((OP* o)); void push_scope _((void)); regexp* pregcomp _((char* exp, char* xend, PMOP* pm)); -OP* ref _((OP* op, I32 type)); -OP* refkids _((OP* op, I32 type)); +OP* ref _((OP* o, I32 type)); +OP* refkids _((OP* o, I32 type)); void regdump _((regexp* r)); I32 pregexec _((regexp* prog, char* stringarg, char* strend, char* strbeg, I32 minend, SV* screamer, I32 safebase)); void pregfree _((struct regexp* r)); char* regnext _((char* p)); -void regprop _((SV* sv, char* op)); +void regprop _((SV* sv, char* o)); void repeatcpy _((char* to, char* from, I32 len, I32 count)); char* rninstr _((char* big, char* bigend, char* little, char* lend)); Sighandler_t rsignal _((int, Sighandler_t)); @@ -409,7 +419,7 @@ void save_delete _((HV* hv, char* key, I32 klen)); void save_destructor _((void (*f)(void*), void* p)); #endif /* titan */ void save_freesv _((SV* sv)); -void save_freeop _((OP* op)); +void save_freeop _((OP* o)); void save_freepv _((char* pv)); void save_gp _((GV* gv, I32 empty)); HV* save_hash _((GV* gv)); @@ -428,9 +438,9 @@ void save_sptr _((SV** sptr)); SV* save_svref _((SV** sptr)); OP* sawparens _((OP* o)); OP* scalar _((OP* o)); -OP* scalarkids _((OP* op)); +OP* scalarkids _((OP* o)); OP* scalarseq _((OP* o)); -OP* scalarvoid _((OP* op)); +OP* scalarvoid _((OP* o)); UV scan_hex _((char* start, I32 len, I32* retlen)); char* scan_num _((char* s)); UV scan_oct _((char* start, I32 len, I32* retlen)); @@ -58,6 +58,10 @@ #include "INTERN.h" #include "regcomp.h" +#ifdef USE_THREADS +#undef op +#endif /* USE_THREADS */ + #ifdef MSDOS # if defined(BUGGY_MSC6) /* MSC 6.00A breaks on op/regexp.t test 85 unless we turn this off */ @@ -1590,14 +1594,14 @@ regexp *r; - regprop - printable representation of opcode */ void -regprop(sv, op) +regprop(sv, o) SV *sv; -char *op; +char *o; { register char *p = 0; sv_setpv(sv, ":"); - switch (OP(op)) { + switch (OP(o)) { case BOL: p = "BOL"; break; @@ -1659,19 +1663,19 @@ char *op; p = "NBOUNDL"; break; case CURLY: - sv_catpvf(sv, "CURLY {%d,%d}", ARG1(op), ARG2(op)); + sv_catpvf(sv, "CURLY {%d,%d}", ARG1(o), ARG2(o)); break; case CURLYX: - sv_catpvf(sv, "CURLYX {%d,%d}", ARG1(op), ARG2(op)); + sv_catpvf(sv, "CURLYX {%d,%d}", ARG1(o), ARG2(o)); break; case REF: - sv_catpvf(sv, "REF%d", ARG1(op)); + sv_catpvf(sv, "REF%d", ARG1(o)); break; case OPEN: - sv_catpvf(sv, "OPEN%d", ARG1(op)); + sv_catpvf(sv, "OPEN%d", ARG1(o)); break; case CLOSE: - sv_catpvf(sv, "CLOSE%d", ARG1(op)); + sv_catpvf(sv, "CLOSE%d", ARG1(o)); p = NULL; break; case STAR: @@ -89,6 +89,7 @@ static CHECKPOINT regcppush(parenfloor) I32 parenfloor; { + dTHR; int retval = savestack_ix; int i = (regsize - parenfloor) * 3; int p; @@ -110,6 +111,7 @@ I32 parenfloor; static char * regcppop() { + dTHR; I32 i = SSPOPINT; U32 paren = 0; char *input; @@ -863,6 +865,7 @@ char *prog; *reglastparen = n; break; case CURLYX: { + dTHR; CURCUR cc; CHECKPOINT cp = savestack_ix; cc.oldcc = regcc; @@ -23,10 +23,11 @@ dEXT char *watchok; int runops() { + dTHR; SAVEI32(runlevel); runlevel++; - while ( op = (*op->op_ppaddr)() ) ; + while ( op = (*op->op_ppaddr)(ARGS) ) ; TAINT_NOT; return 0; @@ -34,10 +35,11 @@ runops() { #else -static void debprof _((OP*op)); +static void debprof _((OP*o)); int runops() { + dTHR; if (!op) { warn("NULL OP IN RUN"); return 0; @@ -54,28 +56,31 @@ runops() { DEBUG_s(debstack()); DEBUG_t(debop(op)); DEBUG_P(debprof(op)); +#ifdef USE_THREADS + DEBUG_L(YIELD()); /* shake up scheduling a bit */ +#endif /* USE_THREADS */ } - } while ( op = (*op->op_ppaddr)() ); + } while ( op = (*op->op_ppaddr)(ARGS) ); TAINT_NOT; return 0; } I32 -debop(op) -OP *op; +debop(o) +OP *o; { SV *sv; - deb("%s", op_name[op->op_type]); - switch (op->op_type) { + deb("%s", op_name[o->op_type]); + switch (o->op_type) { case OP_CONST: - PerlIO_printf(Perl_debug_log, "(%s)", SvPEEK(cSVOP->op_sv)); + PerlIO_printf(Perl_debug_log, "(%s)", SvPEEK(cSVOPo->op_sv)); break; case OP_GVSV: case OP_GV: - if (cGVOP->op_gv) { + if (cGVOPo->op_gv) { sv = NEWSV(0,0); - gv_fullname3(sv, cGVOP->op_gv, Nullch); + gv_fullname3(sv, cGVOPo->op_gv, Nullch); PerlIO_printf(Perl_debug_log, "(%s)", SvPV(sv, na)); SvREFCNT_dec(sv); } @@ -100,12 +105,12 @@ char **addr; } static void -debprof(op) -OP* op; +debprof(o) +OP* o; { if (!profiledata) New(000, profiledata, MAXO, U32); - ++profiledata[op->op_type]; + ++profiledata[o->op_type]; } void @@ -21,6 +21,7 @@ SV** sp; SV** p; int n; { + dTHR; stack_sp = sp; av_extend(curstack, (p - stack_base) + (n) + 128); return stack_sp; @@ -29,6 +30,7 @@ int n; I32 cxinc() { + dTHR; cxstack_max = cxstack_max * 3 / 2; Renew(cxstack, cxstack_max + 1, CONTEXT); /* XXX should fix CXINC macro */ return cxstack_ix + 1; @@ -38,6 +40,7 @@ void push_return(retop) OP *retop; { + dTHR; if (retstack_ix == retstack_max) { retstack_max = retstack_max * 3 / 2; Renew(retstack, retstack_max, OP*); @@ -48,6 +51,7 @@ OP *retop; OP * pop_return() { + dTHR; if (retstack_ix > 0) return retstack[--retstack_ix]; else @@ -57,6 +61,7 @@ pop_return() void push_scope() { + dTHR; if (scopestack_ix == scopestack_max) { scopestack_max = scopestack_max * 3 / 2; Renew(scopestack, scopestack_max, I32); @@ -68,6 +73,7 @@ push_scope() void pop_scope() { + dTHR; I32 oldsave = scopestack[--scopestack_ix]; LEAVE_SCOPE(oldsave); } @@ -75,6 +81,7 @@ pop_scope() void markstack_grow() { + dTHR; I32 oldmax = markstack_max - markstack; I32 newmax = oldmax * 3 / 2; @@ -86,6 +93,7 @@ markstack_grow() void savestack_grow() { + dTHR; savestack_max = savestack_max * 3 / 2; Renew(savestack, savestack_max, ANY); } @@ -93,6 +101,7 @@ savestack_grow() void free_tmps() { + dTHR; /* XXX should tmps_floor live in cxstack? */ I32 myfloor = tmps_floor; while (tmps_ix > myfloor) { /* clean up after last statement */ @@ -111,6 +120,7 @@ static SV * save_scalar_at(sptr) SV **sptr; { + dTHR; register SV *sv; SV *osv = *sptr; @@ -142,6 +152,7 @@ SV * save_scalar(gv) GV *gv; { + dTHR; SSCHECK(3); SSPUSHPTR(gv); SSPUSHPTR(GvSV(gv)); @@ -153,6 +164,7 @@ SV* save_svref(sptr) SV **sptr; { + dTHR; SSCHECK(3); SSPUSHPTR(sptr); SSPUSHPTR(*sptr); @@ -188,6 +200,7 @@ AV * save_ary(gv) GV *gv; { + dTHR; SSCHECK(3); SSPUSHPTR(gv); SSPUSHPTR(GvAVn(gv)); @@ -201,6 +214,7 @@ HV * save_hash(gv) GV *gv; { + dTHR; SSCHECK(3); SSPUSHPTR(gv); SSPUSHPTR(GvHVn(gv)); @@ -214,6 +228,7 @@ void save_item(item) register SV *item; { + dTHR; register SV *sv; SSCHECK(3); @@ -228,6 +243,7 @@ void save_int(intp) int *intp; { + dTHR; SSCHECK(3); SSPUSHINT(*intp); SSPUSHPTR(intp); @@ -238,6 +254,7 @@ void save_long(longp) long *longp; { + dTHR; SSCHECK(3); SSPUSHLONG(*longp); SSPUSHPTR(longp); @@ -248,6 +265,7 @@ void save_I32(intp) I32 *intp; { + dTHR; SSCHECK(3); SSPUSHINT(*intp); SSPUSHPTR(intp); @@ -268,6 +286,7 @@ void save_iv(ivp) IV *ivp; { + dTHR; SSCHECK(3); SSPUSHIV(*ivp); SSPUSHPTR(ivp); @@ -281,6 +300,7 @@ void save_pptr(pptr) char **pptr; { + dTHR; SSCHECK(3); SSPUSHPTR(*pptr); SSPUSHPTR(pptr); @@ -291,6 +311,7 @@ void save_sptr(sptr) SV **sptr; { + dTHR; SSCHECK(3); SSPUSHPTR(*sptr); SSPUSHPTR(sptr); @@ -301,6 +322,7 @@ void save_nogv(gv) GV *gv; { + dTHR; SSCHECK(2); SSPUSHPTR(gv); SSPUSHINT(SAVEt_NSTAB); @@ -310,6 +332,7 @@ void save_hptr(hptr) HV **hptr; { + dTHR; SSCHECK(3); SSPUSHPTR(*hptr); SSPUSHPTR(hptr); @@ -320,6 +343,7 @@ void save_aptr(aptr) AV **aptr; { + dTHR; SSCHECK(3); SSPUSHPTR(*aptr); SSPUSHPTR(aptr); @@ -330,17 +354,19 @@ void save_freesv(sv) SV *sv; { + dTHR; SSCHECK(2); SSPUSHPTR(sv); SSPUSHINT(SAVEt_FREESV); } void -save_freeop(op) -OP *op; +save_freeop(o) +OP *o; { + dTHR; SSCHECK(2); - SSPUSHPTR(op); + SSPUSHPTR(o); SSPUSHINT(SAVEt_FREEOP); } @@ -348,6 +374,7 @@ void save_freepv(pv) char *pv; { + dTHR; SSCHECK(2); SSPUSHPTR(pv); SSPUSHINT(SAVEt_FREEPV); @@ -357,6 +384,7 @@ void save_clearsv(svp) SV** svp; { + dTHR; SSCHECK(2); SSPUSHLONG((long)(svp-curpad)); SSPUSHINT(SAVEt_CLEARSV); @@ -368,6 +396,7 @@ HV *hv; char *key; I32 klen; { + dTHR; SSCHECK(4); SSPUSHINT(klen); SSPUSHPTR(key); @@ -380,6 +409,7 @@ save_list(sarg,maxsarg) register SV **sarg; I32 maxsarg; { + dTHR; register SV *sv; register I32 i; @@ -398,6 +428,7 @@ save_destructor(f,p) void (*f) _((void*)); void* p; { + dTHR; SSCHECK(3); SSPUSHDPTR(f); SSPUSHPTR(p); @@ -408,6 +439,7 @@ void leave_scope(base) I32 base; { + dTHR; register SV *sv; register SV *value; register GV *gv; @@ -614,6 +646,7 @@ void cx_dump(cx) CONTEXT* cx; { + dTHR; PerlIO_printf(Perl_debug_log, "CX %d = %s\n", cx - cxstack, block_type[cx->cx_type]); if (cx->cx_type != CXt_SUBST) { PerlIO_printf(Perl_debug_log, "BLK_OLDSP = %ld\n", (long)cx->blk_oldsp); @@ -172,9 +172,11 @@ U32 flags; #define uproot_SV(p) \ do { \ + MUTEX_LOCK(&sv_mutex); \ (p) = sv_root; \ sv_root = (SV*)SvANY(p); \ ++sv_count; \ + MUTEX_UNLOCK(&sv_mutex); \ } while (0) #define new_SV(p) \ @@ -1120,8 +1122,11 @@ IV i; case SVt_PVCV: case SVt_PVFM: case SVt_PVIO: - croak("Can't coerce %s to integer in %s", sv_reftype(sv,0), - op_desc[op->op_type]); + { + dTHR; + croak("Can't coerce %s to integer in %s", sv_reftype(sv,0), + op_desc[op->op_type]); + } } (void)SvIOK_only(sv); /* validate number */ SvIVX(sv) = i; @@ -1179,8 +1184,11 @@ double num; case SVt_PVCV: case SVt_PVFM: case SVt_PVIO: - croak("Can't coerce %s to number in %s", sv_reftype(sv,0), - op_name[op->op_type]); + { + dTHR; + croak("Can't coerce %s to number in %s", sv_reftype(sv,0), + op_name[op->op_type]); + } } SvNVX(sv) = num; (void)SvNOK_only(sv); /* validate number */ @@ -1191,6 +1199,7 @@ static void not_a_number(sv) SV *sv; { + dTHR; char tmpbuf[64]; char *d = tmpbuf; char *s; @@ -1312,6 +1321,7 @@ register SV *sv; SvIVX(sv) = asIV(sv); } else { + dTHR; if (dowarn && !localizing && !(SvFLAGS(sv) & SVs_PADTMP)) warn(warn_uninit); return 0; @@ -1460,6 +1470,7 @@ register SV *sv; SvNVX(sv) = atof(SvPVX(sv)); } else { + dTHR; if (dowarn && !localizing && !(SvFLAGS(sv) & SVs_PADTMP)) warn(warn_uninit); return 0.0; @@ -1717,6 +1728,7 @@ STRLEN *lp; s = SvEND(sv); } else { + dTHR; if (dowarn && !localizing && !(SvFLAGS(sv) & SVs_PADTMP)) warn(warn_uninit); *lp = 0; @@ -1781,6 +1793,7 @@ register SV *sv; if (SvROK(sv)) { #ifdef OVERLOAD { + dTHR; SV* tmpsv; if (SvAMAGIC(sv) && (tmpsv = AMG_CALLun(sv,bool_))) return SvTRUE(tmpsv); @@ -1789,11 +1802,11 @@ register SV *sv; return SvRV(sv) != 0; } if (SvPOKp(sv)) { - register XPV* Xpv; - if ((Xpv = (XPV*)SvANY(sv)) && - (*Xpv->xpv_pv > '0' || - Xpv->xpv_cur > 1 || - (Xpv->xpv_cur && *Xpv->xpv_pv != '0'))) + register XPV* Xpvtmp; + if ((Xpvtmp = (XPV*)SvANY(sv)) && + (*Xpvtmp->xpv_pv > '0' || + Xpvtmp->xpv_cur > 1 || + (Xpvtmp->xpv_cur && *Xpvtmp->xpv_pv != '0'))) return 1; else return 0; @@ -1820,6 +1833,7 @@ sv_setsv(dstr,sstr) SV *dstr; register SV *sstr; { + dTHR; register U32 sflags; register int dtype; register int stype; @@ -1963,6 +1977,7 @@ register SV *sstr; if (sflags & SVf_ROK) { if (dtype >= SVt_PV) { if (dtype == SVt_PVGV) { + dTHR; SV *sref = SvREFCNT_inc(SvRV(sstr)); SV *dref = 0; int intro = GvINTRO(dstr); @@ -2386,6 +2401,7 @@ I32 namlen; if (!obj || obj == sv || how == '#') mg->mg_obj = obj; else { + dTHR; mg->mg_obj = SvREFCNT_inc(obj); mg->mg_flags |= MGf_REFCOUNTED; } @@ -2443,6 +2459,11 @@ I32 namlen; case 'l': mg->mg_virtual = &vtbl_dbline; break; +#ifdef USE_THREADS + case 'm': + mg->mg_virtual = &vtbl_mutex; + break; +#endif /* USE_THREADS */ #ifdef USE_LOCALE_COLLATE case 'o': mg->mg_virtual = &vtbl_collxfrm; @@ -2661,6 +2682,7 @@ register SV *sv; if (SvOBJECT(sv)) { if (defstash) { /* Still have a symbol table? */ + dTHR; dSP; GV* destructor; @@ -3413,6 +3435,7 @@ register SV *sv; static void sv_mortalgrow() { + dTHR; tmps_max += (tmps_max < 512) ? 128 : 512; Renew(tmps_stack, tmps_max, SV*); } @@ -3421,6 +3444,7 @@ SV * sv_mortalcopy(oldstr) SV *oldstr; { + dTHR; register SV *sv; new_SV(sv); @@ -3438,6 +3462,7 @@ SV *oldstr; SV * sv_newmortal() { + dTHR; register SV *sv; new_SV(sv); @@ -3456,6 +3481,7 @@ SV * sv_2mortal(sv) register SV *sv; { + dTHR; if (!sv) return sv; if (SvREADONLY(sv) && curcop != &compiling) @@ -3545,6 +3571,7 @@ SV * newRV(ref) SV *ref; { + dTHR; register SV *sv; new_SV(sv); @@ -3861,9 +3888,11 @@ STRLEN *lp; s = SvPVX(sv); *lp = SvCUR(sv); } - else + else { + dTHR; croak("Can't coerce %s to string in %s", sv_reftype(sv,0), op_name[op->op_type]); + } } else s = sv_2pv(sv, lp); @@ -3960,6 +3989,7 @@ newSVrv(rv, classname) SV *rv; char *classname; { + dTHR; SV *sv; new_SV(sv); @@ -4026,6 +4056,7 @@ sv_bless(sv,stash) SV* sv; HV* stash; { + dTHR; SV *ref; if (!SvROK(sv)) croak("Can't bless non-reference value"); @@ -4872,6 +4903,11 @@ SV* sv; PerlIO_printf(Perl_debug_log, " DEPTH = %ld\n", (long)CvDEPTH(sv)); PerlIO_printf(Perl_debug_log, " PADLIST = 0x%lx\n", (long)CvPADLIST(sv)); PerlIO_printf(Perl_debug_log, " OUTSIDE = 0x%lx\n", (long)CvOUTSIDE(sv)); +#ifdef USE_THREADS + PerlIO_printf(Perl_debug_log, " MUTEXP = 0x%lx\n", (long)CvMUTEXP(sv)); + PerlIO_printf(Perl_debug_log, " CONDP = 0x%lx\n", (long)CvCONDP(sv)); + PerlIO_printf(Perl_debug_log, " OWNER = 0x%lx\n", (long)CvOWNER(sv)); +#endif /* USE_THREADS */ if (type == SVt_PVFM) PerlIO_printf(Perl_debug_log, " LINES = %ld\n", (long)FmLINES(sv)); break; @@ -131,6 +131,10 @@ struct io { #define SVphv_SHAREKEYS 0x20000000 /* keys live on shared string table */ #define SVphv_LAZYDEL 0x40000000 /* entry in xhv_eiter must be deleted */ +#ifdef USE_THREADS +#define SVp_SYNC 0x10000000 /* Synchronised CV or an SV lock */ +#endif /* USE_THREADS */ + struct xrv { SV * xrv_rv; /* pointer to another SV */ }; diff --git a/thread.h b/thread.h new file mode 100644 index 0000000000..466dea5520 --- /dev/null +++ b/thread.h @@ -0,0 +1,235 @@ +#ifndef USE_THREADS +#define MUTEX_LOCK(m) +#define MUTEX_UNLOCK(m) +#define MUTEX_INIT(m) +#define MUTEX_DESTROY(m) +#define COND_INIT(c) +#define COND_SIGNAL(c) +#define COND_BROADCAST(c) +#define COND_WAIT(c, m) +#define COND_DESTROY(c) + +#define THR +/* Rats: if dTHR is just blank then the subsequent ";" throws an error */ +#define dTHR extern int errno +#else +#include <pthread.h> + +#ifdef OLD_PTHREADS_API +#define pthread_mutexattr_init(a) pthread_mutexattr_create(a) +#define pthread_mutexattr_settype(a,t) pthread_mutexattr_setkind_np(a,t) +#define pthread_key_create(k,d) pthread_keycreate(k,(pthread_destructor_t)(d)) +#else +#define pthread_mutexattr_default NULL +#endif /* OLD_PTHREADS_API */ + +#define MUTEX_INIT(m) \ + if (pthread_mutex_init((m), pthread_mutexattr_default)) \ + croak("panic: MUTEX_INIT"); \ + else 1 +#define MUTEX_LOCK(m) \ + if (pthread_mutex_lock((m))) croak("panic: MUTEX_LOCK"); else 1 +#define MUTEX_UNLOCK(m) \ + if (pthread_mutex_unlock((m))) croak("panic: MUTEX_UNLOCK"); else 1 +#define MUTEX_DESTROY(m) \ + if (pthread_mutex_destroy((m))) croak("panic: MUTEX_DESTROY"); else 1 +#define COND_INIT(c) \ + if (pthread_cond_init((c), NULL)) croak("panic: COND_INIT"); else 1 +#define COND_SIGNAL(c) \ + if (pthread_cond_signal((c))) croak("panic: COND_SIGNAL"); else 1 +#define COND_BROADCAST(c) \ + if (pthread_cond_broadcast((c))) croak("panic: COND_BROADCAST"); else 1 +#define COND_WAIT(c, m) \ + if (pthread_cond_wait((c), (m))) croak("panic: COND_WAIT"); else 1 +#define COND_DESTROY(c) \ + if (pthread_cond_destroy((c))) croak("panic: COND_DESTROY"); else 1 +/* XXX Add "old" (?) POSIX draft interface too */ +#ifdef OLD_PTHREADS_API +struct thread *getTHR _((void)); +#define THR getTHR() +#else +#define THR ((struct thread *) pthread_getspecific(thr_key)) +#endif /* OLD_PTHREADS_API */ +#define dTHR struct thread *thr = THR + +struct thread { + pthread_t Tself; + + /* The fields that used to be global */ + SV ** Tstack_base; + SV ** Tstack_sp; + SV ** Tstack_max; + + OP * Top; + + I32 * Tscopestack; + I32 Tscopestack_ix; + I32 Tscopestack_max; + + ANY * Tsavestack; + I32 Tsavestack_ix; + I32 Tsavestack_max; + + OP ** Tretstack; + I32 Tretstack_ix; + I32 Tretstack_max; + + I32 * Tmarkstack; + I32 * Tmarkstack_ptr; + I32 * Tmarkstack_max; + + SV ** Tcurpad; + + SV * TSv; + XPV * TXpv; + char Tbuf[2048]; /* should be a global locked by a mutex */ + char Ttokenbuf[256]; /* should be a global locked by a mutex */ + struct stat Tstatbuf; + struct tms Ttimesbuf; + + /* XXX What about regexp stuff? */ + + /* Now the fields that used to be "per interpreter" (even when global) */ + + /* XXX What about magic variables such as $/, $? and so on? */ + HV * Tdefstash; + HV * Tcurstash; + AV * Tpad; + AV * Tpadname; + + SV ** Ttmps_stack; + I32 Ttmps_ix; + I32 Ttmps_floor; + I32 Ttmps_max; + + int Tin_eval; + OP * Trestartop; + int Tdelaymagic; + bool Tdirty; + U8 Tlocalizing; + + CONTEXT * Tcxstack; + I32 Tcxstack_ix; + I32 Tcxstack_max; + + AV * Tstack; + AV * Tmainstack; + Sigjmp_buf Ttop_env; + I32 Trunlevel; + + /* XXX Sort stuff, firstgv, secongv and so on? */ + + pthread_mutex_t * Tthreadstart_mutexp; + HV * Tcvcache; + U32 Tthrflags; +}; + +typedef struct thread *Thread; + +/* Values and macros for thrflags */ +#define THR_STATE_MASK 3 +#define THR_NORMAL 0 +#define THR_DETACHED 1 +#define THR_JOINED 2 +#define THR_DEAD 3 + +#define ThrSTATE(t) (t->Tthrflags & THR_STATE_MASK) +#define ThrSETSTATE(t, s) STMT_START { \ + (t)->Tthrflags &= ~THR_STATE_MASK; \ + (t)->Tthrflags |= (s); \ + DEBUG_L(fprintf(stderr, "thread 0x%lx set to state %d\n", \ + (unsigned long)(t), (s))); \ + } STMT_END + +typedef struct condpair { + pthread_mutex_t mutex; + pthread_cond_t owner_cond; + pthread_cond_t cond; + Thread owner; +} condpair_t; + +#define MgMUTEXP(mg) (&((condpair_t *)(mg->mg_ptr))->mutex) +#define MgOWNERCONDP(mg) (&((condpair_t *)(mg->mg_ptr))->owner_cond) +#define MgCONDP(mg) (&((condpair_t *)(mg->mg_ptr))->cond) +#define MgOWNER(mg) ((condpair_t *)(mg->mg_ptr))->owner + +#undef stack_base +#undef stack_sp +#undef stack_max +#undef stack +#undef mainstack +#undef markstack +#undef markstack_ptr +#undef markstack_max +#undef scopestack +#undef scopestack_ix +#undef scopestack_max +#undef savestack +#undef savestack_ix +#undef savestack_max +#undef retstack +#undef retstack_ix +#undef retstack_max +#undef cxstack +#undef cxstack_ix +#undef cxstack_max +#undef curpad +#undef Sv +#undef Xpv +#undef op +#undef top_env +#undef runlevel +#undef in_eval + +#define self (thr->Tself) +#define stack_base (thr->Tstack_base) +#define stack_sp (thr->Tstack_sp) +#define stack_max (thr->Tstack_max) +#define op (thr->Top) +#define stack (thr->Tstack) +#define mainstack (thr->Tmainstack) +#define markstack (thr->Tmarkstack) +#define markstack_ptr (thr->Tmarkstack_ptr) +#define markstack_max (thr->Tmarkstack_max) +#define scopestack (thr->Tscopestack) +#define scopestack_ix (thr->Tscopestack_ix) +#define scopestack_max (thr->Tscopestack_max) + +#define savestack (thr->Tsavestack) +#define savestack_ix (thr->Tsavestack_ix) +#define savestack_max (thr->Tsavestack_max) + +#define retstack (thr->Tretstack) +#define retstack_ix (thr->Tretstack_ix) +#define retstack_max (thr->Tretstack_max) + +#define cxstack (thr->Tcxstack) +#define cxstack_ix (thr->Tcxstack_ix) +#define cxstack_max (thr->Tcxstack_max) + +#define curpad (thr->Tcurpad) +#define Sv (thr->TSv) +#define Xpv (thr->TXpv) +#define defstash (thr->Tdefstash) +#define curstash (thr->Tcurstash) +#define pad (thr->Tpad) +#define padname (thr->Tpadname) + +#define tmps_stack (thr->Ttmps_stack) +#define tmps_ix (thr->Ttmps_ix) +#define tmps_floor (thr->Ttmps_floor) +#define tmps_max (thr->Ttmps_max) + +#define in_eval (thr->Tin_eval) +#define restartop (thr->Trestartop) +#define delaymagic (thr->Tdelaymagic) +#define dirty (thr->Tdirty) +#define localizing (thr->Tlocalizing) + +#define top_env (thr->Ttop_env) +#define runlevel (thr->Trunlevel) + +#define threadstart_mutexp (thr->Tthreadstart_mutexp) +#define cvcache (thr->Tcvcache) +#define thrflags (thr->Tthrflags) +#endif /* USE_THREADS */ @@ -350,6 +350,7 @@ static char * skipspace(s) register char *s; { + dTHR; if (lex_formbrack && lex_brackets <= lex_formbrack) { while (s < bufend && (*s == ' ' || *s == '\t')) s++; @@ -531,11 +532,11 @@ register char *s; int kind; { if (s && *s) { - OP* op = (OP*)newSVOP(OP_CONST, 0, newSVpv(s,0)); - nextval[nexttoke].opval = op; + OP* o = (OP*)newSVOP(OP_CONST, 0, newSVpv(s,0)); + nextval[nexttoke].opval = o; force_next(WORD); if (kind) { - op->op_private = OPpCONST_ENTERED; + o->op_private = OPpCONST_ENTERED; /* XXX see note in pp_entereval() for why we forgo typo warnings if the symbol must be introduced in an eval. GSAR 96-10-12 */ @@ -1226,6 +1227,7 @@ EXT int yychar; /* last token */ int yylex() { + dTHR; register char *s; register char *d; register I32 tmp; @@ -1243,7 +1245,8 @@ yylex() return PRIVATEREF; } - if (!strchr(tokenbuf,':') && (tmp = pad_findmy(tokenbuf))) { + if (!strchr(tokenbuf,':') + && (tmp = pad_findmy(tokenbuf)) != NOT_IN_PAD) { if (last_lop_op == OP_SORT && tokenbuf[0] == '$' && (tokenbuf[1] == 'a' || tokenbuf[1] == 'b') @@ -4606,6 +4609,7 @@ void hoistmust(pm) register PMOP *pm; { + dTHR; if (!pm->op_pmshort && pm->op_pmregexp->regstart && (!pm->op_pmregexp->regmust || pm->op_pmregexp->reganch & ROPT_ANCH) ) { @@ -4647,7 +4651,7 @@ scan_trans(start) char *start; { register char* s; - OP *op; + OP *o; short *tbl; I32 squash; I32 delete; @@ -4677,7 +4681,7 @@ char *start; } New(803,tbl,256,short); - op = newPVOP(OP_TRANS, 0, (char*)tbl); + o = newPVOP(OP_TRANS, 0, (char*)tbl); complement = delete = squash = 0; while (*s == 'c' || *s == 'd' || *s == 's') { @@ -4689,9 +4693,9 @@ char *start; squash = OPpTRANS_SQUASH; s++; } - op->op_private = delete|squash|complement; + o->op_private = delete|squash|complement; - lex_op = op; + lex_op = o; yylval.ival = OP_TRANS; return s; } @@ -4700,6 +4704,7 @@ static char * scan_heredoc(s) register char *s; { + dTHR; SV *herewas; I32 op_type = OP_SCALAR; I32 len; @@ -4856,10 +4861,10 @@ char *start; (void)strcpy(d,"ARGV"); if (*d == '$') { I32 tmp; - if (tmp = pad_findmy(d)) { - OP *op = newOP(OP_PADSV, 0); - op->op_targ = tmp; - lex_op = (OP*)newUNOP(OP_READLINE, 0, newUNOP(OP_RV2GV, 0, op)); + if ((tmp = pad_findmy(d)) != NOT_IN_PAD) { + OP *o = newOP(OP_PADSV, 0); + o->op_targ = tmp; + lex_op = (OP*)newUNOP(OP_READLINE, 0, newUNOP(OP_RV2GV, 0, o)); } else { GV *gv = gv_fetchpv(d+1,TRUE, SVt_PV); @@ -4883,6 +4888,7 @@ static char * scan_str(start) char *start; { + dTHR; SV *sv; char *tmps; register char *s = start; @@ -5108,6 +5114,7 @@ static char * scan_formline(s) register char *s; { + dTHR; register char *eol; register char *t; SV *stuff = newSVpv("",0); @@ -5188,6 +5195,7 @@ start_subparse(is_format, flags) I32 is_format; U32 flags; { + dTHR; I32 oldsavestack_ix = savestack_ix; CV* outsidecv = compcv; AV* comppadlist; @@ -5214,6 +5222,9 @@ U32 flags; comppad = newAV(); comppad_name = newAV(); comppad_name_fill = 0; +#ifdef USE_THREADS + av_store(comppad_name, 0, newSVpv("@_", 2)); +#endif /* USE_THREADS */ min_intro_pending = 0; av_push(comppad, Nullsv); curpad = AvARRAY(comppad); @@ -5227,6 +5238,13 @@ U32 flags; CvPADLIST(compcv) = comppadlist; CvOUTSIDE(compcv) = (CV*)SvREFCNT_inc((SV*)outsidecv); +#ifdef USE_THREADS + CvOWNER(compcv) = 0; + New(666, CvMUTEXP(compcv), 1, pthread_mutex_t); + MUTEX_INIT(CvMUTEXP(compcv)); + New(666, CvCONDP(compcv), 1, pthread_cond_t); + COND_INIT(CvCONDP(compcv)); +#endif /* USE_THREADS */ return oldsavestack_ix; } @@ -5235,6 +5253,7 @@ int yywarn(s) char *s; { + dTHR; --error_count; in_eval |= 2; yyerror(s); @@ -5246,6 +5265,7 @@ int yyerror(s) char *s; { + dTHR; char *where = NULL; char *context = NULL; int contlen = -1; @@ -1162,6 +1162,7 @@ die(pat, va_alist) va_dcl #endif { + dTHR; va_list args; char *message; I32 oldrunlevel = runlevel; @@ -1229,6 +1230,7 @@ croak(pat, va_alist) va_dcl #endif { + dTHR; va_list args; char *message; HV *stash; @@ -1242,6 +1244,9 @@ croak(pat, va_alist) #endif message = mess(pat, &args); va_end(args); +#ifdef USE_THREADS + DEBUG_L(fprintf(stderr, "croak: 0x%lx %s", (unsigned long) thr, message)); +#endif /* USE_THREADS */ if (diehook) { /* sv_2cv might call croak() */ SV *olddiehook = diehook; @@ -1263,6 +1268,7 @@ croak(pat, va_alist) XPUSHs(msg); PUTBACK; perl_call_sv((SV*)cv, G_DISCARD); +<<<< LEAVE; } @@ -1302,6 +1308,7 @@ warn(pat,va_alist) if (warnhook) { /* sv_2cv might call warn() */ + dTHR; SV *oldwarnhook = warnhook; ENTER; SAVESPTR(warnhook); @@ -2285,6 +2292,56 @@ I32 *retlen; return retval; } +#ifdef USE_THREADS +#ifdef OLD_PTHREADS_API +struct thread * +getTHR _((void)) +{ + pthread_addr_t t; + + if (pthread_getspecific(thr_key, &t)) + croak("panic: pthread_getspecific"); + return (struct thread *) t; +} +#endif /* OLD_PTHREADS_API */ + +MAGIC * +condpair_magic(sv) +SV *sv; +{ + MAGIC *mg; + + SvUPGRADE(sv, SVt_PVMG); + mg = mg_find(sv, 'm'); + if (!mg) { + condpair_t *cp; + + New(53, cp, 1, condpair_t); + MUTEX_INIT(&cp->mutex); + COND_INIT(&cp->owner_cond); + COND_INIT(&cp->cond); + cp->owner = 0; + MUTEX_LOCK(&sv_mutex); + mg = mg_find(sv, 'm'); + if (mg) { + /* someone else beat us to initialising it */ + MUTEX_UNLOCK(&sv_mutex); + MUTEX_DESTROY(&cp->mutex); + COND_DESTROY(&cp->owner_cond); + COND_DESTROY(&cp->cond); + Safefree(cp); + } + else { + sv_magic(sv, Nullsv, 'm', 0, 0); + mg = SvMAGIC(sv); + mg->mg_ptr = (char *)cp; + mg->mg_len = sizeof(cp); + MUTEX_UNLOCK(&sv_mutex); + } + } + return mg; +} +#endif /* USE_THREADS */ #ifdef HUGE_VAL /* |