summaryrefslogtreecommitdiff
path: root/perl.c
diff options
context:
space:
mode:
Diffstat (limited to 'perl.c')
-rw-r--r--perl.c206
1 files changed, 183 insertions, 23 deletions
diff --git a/perl.c b/perl.c
index 7df632d74e..16e74b8975 100644
--- a/perl.c
+++ b/perl.c
@@ -72,7 +72,6 @@ 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 *));
@@ -81,6 +80,19 @@ static void validate_suid _((char *, char*));
static int fdscript = -1;
+#if defined(DEBUGGING) && defined(USE_THREADS) && defined(__linux__)
+#include <asm/sigcontext.h>
+static void
+catch_sigsegv(int signo, struct sigcontext_struct sc)
+{
+ signal(SIGSEGV, SIG_DFL);
+ fprintf(stderr, "Segmentation fault dereferencing 0x%lx\n"
+ "return_address = 0x%lx, eip = 0x%lx\n",
+ sc.cr2, __builtin_return_address(0), sc.eip);
+ fprintf(stderr, "thread = 0x%lx\n", (unsigned long)THR);
+}
+#endif
+
PerlInterpreter *
perl_alloc()
{
@@ -95,6 +107,10 @@ void
perl_construct( sv_interp )
register PerlInterpreter *sv_interp;
{
+#if defined(USE_THREADS) && !defined(FAKE_THREADS)
+ struct thread *thr;
+#endif
+
if (!(curinterp = sv_interp))
return;
@@ -102,8 +118,36 @@ register PerlInterpreter *sv_interp;
Zero(sv_interp, 1, PerlInterpreter);
#endif
- /* Init the real globals? */
+ /* Init the real globals (and main thread)? */
if (!linestr) {
+#ifdef USE_THREADS
+ INIT_THREADS;
+ New(53, thr, 1, struct thread);
+ MUTEX_INIT(&malloc_mutex);
+ MUTEX_INIT(&sv_mutex);
+ MUTEX_INIT(&eval_mutex);
+ COND_INIT(&eval_cond);
+ MUTEX_INIT(&threads_mutex);
+ COND_INIT(&nthreads_cond);
+ nthreads = 1;
+ cvcache = newHV();
+ curcop = &compiling;
+ thr->flags = THRf_R_JOINABLE;
+ MUTEX_INIT(&thr->mutex);
+ thr->next = thr;
+ thr->prev = thr;
+ thr->tid = 0;
+#ifdef HAVE_THREAD_INTERN
+ init_thread_intern(thr);
+#else
+ self = pthread_self();
+ if (pthread_key_create(&thr_key, 0))
+ croak("panic: pthread_key_create");
+ if (pthread_setspecific(thr_key, (void *) thr))
+ croak("panic: pthread_setspecific");
+#endif /* FAKE_THREADS */
+#endif /* USE_THREADS */
+
linestr = NEWSV(65,80);
sv_upgrade(linestr,SVt_PVIV);
@@ -122,6 +166,7 @@ register PerlInterpreter *sv_interp;
nrs = newSVpv("\n", 1);
rs = SvREFCNT_inc(nrs);
+ sighandlerp = sighandler;
pidstatus = newHV();
#ifdef MSDOS
@@ -170,7 +215,12 @@ 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;
}
@@ -178,13 +228,78 @@ 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;
+ Thread t;
if (!(curinterp = sv_interp))
return;
+#ifdef USE_THREADS
+#ifndef FAKE_THREADS
+ /* Join with any remaining non-detached threads */
+ MUTEX_LOCK(&threads_mutex);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: waiting for %d threads...\n",
+ nthreads - 1));
+ for (t = thr->next; t != thr; t = t->next) {
+ MUTEX_LOCK(&t->mutex);
+ switch (ThrSTATE(t)) {
+ AV *av;
+ case THRf_ZOMBIE:
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: joining zombie %p\n", t));
+ ThrSETSTATE(t, THRf_DEAD);
+ MUTEX_UNLOCK(&t->mutex);
+ nthreads--;
+ MUTEX_UNLOCK(&threads_mutex);
+ if (pthread_join(t->Tself, (void**)&av))
+ croak("panic: pthread_join failed during global destruction");
+ SvREFCNT_dec((SV*)av);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: joined zombie %p OK\n", t));
+ break;
+ case THRf_R_JOINABLE:
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: detaching thread %p\n", t));
+ ThrSETSTATE(t, THRf_R_DETACHED);
+ /*
+ * We unlock threads_mutex and t->mutex in the opposite order
+ * from which we locked them just so that DETACH won't
+ * deadlock if it panics. It's only a breach of good style
+ * not a bug since they are unlocks not locks.
+ */
+ MUTEX_UNLOCK(&threads_mutex);
+ DETACH(t);
+ MUTEX_UNLOCK(&t->mutex);
+ break;
+ default:
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: ignoring %p (state %u)\n",
+ t, ThrSTATE(t)));
+ MUTEX_UNLOCK(&t->mutex);
+ MUTEX_UNLOCK(&threads_mutex);
+ /* fall through and out */
+ }
+ }
+ /* Now wait for the thread count nthreads to drop to one */
+ while (nthreads > 1)
+ {
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: final wait for %d threads\n",
+ nthreads - 1));
+ COND_WAIT(&nthreads_cond, &threads_mutex);
+ }
+ /* At this point, we're the last thread */
+ MUTEX_UNLOCK(&threads_mutex);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(), "perl_destruct: armageddon has arrived\n"));
+ MUTEX_DESTROY(&threads_mutex);
+ COND_DESTROY(&nthreads_cond);
+#endif /* !defined(FAKE_THREADS) */
+#endif /* USE_THREADS */
+
destruct_level = perl_destruct_level;
#ifdef DEBUGGING
{
@@ -336,8 +451,10 @@ register PerlInterpreter *sv_interp;
/* startup and shutdown function lists */
SvREFCNT_dec(beginav);
SvREFCNT_dec(endav);
+ SvREFCNT_dec(initav);
beginav = Nullav;
endav = Nullav;
+ initav = Nullav;
/* temp stack during pp_sort() */
SvREFCNT_dec(sortstack);
@@ -432,6 +549,12 @@ 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);
+ COND_DESTROY(&eval_cond);
+#endif /* USE_THREADS */
/* As the absolutely last thing, free the non-arena SV for mess() */
@@ -462,6 +585,7 @@ int argc;
char **argv;
char **env;
{
+ dTHR;
register SV *sv;
register char *s;
char *scriptname = NULL;
@@ -779,6 +903,14 @@ print \" \\@INC:\\n @INC\\n\";");
comppad_name_fill = 0;
min_intro_pending = 0;
padix = 0;
+#ifdef USE_THREADS
+ av_store(comppad_name, 0, newSVpv("@_", 2));
+ curpad[0] = (SV*)newAV();
+ SvPADMY_on(curpad[0]); /* XXX Needed? */
+ CvOWNER(compcv) = 0;
+ New(666, CvMUTEXP(compcv), 1, perl_mutex);
+ MUTEX_INIT(CvMUTEXP(compcv));
+#endif /* USE_THREADS */
comppadlist = newAV();
AvREAL_off(comppadlist);
@@ -793,6 +925,10 @@ print \" \\@INC:\\n @INC\\n\";");
init_os_extras();
#endif
+#if defined(DEBUGGING) && defined(USE_THREADS) && defined(__linux__)
+ DEBUG_L(signal(SIGSEGV, (void(*)(int))catch_sigsegv););
+#endif
+
init_predump_symbols();
if (!do_undump)
init_postdump_symbols(argc,argv,env);
@@ -848,6 +984,7 @@ int
perl_run(sv_interp)
PerlInterpreter *sv_interp;
{
+ dTHR;
I32 oldscope;
dJMPENV;
int ret;
@@ -896,6 +1033,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);
@@ -903,6 +1044,8 @@ PerlInterpreter *sv_interp;
}
if (PERLDB_SINGLE && DBsingle)
sv_setiv(DBsingle, 1);
+ if (initav)
+ call_list(oldscope, initav);
}
/* do it */
@@ -984,6 +1127,7 @@ char *subname;
I32 flags; /* See G_* flags in cop.h */
register char **argv; /* null terminated arg list */
{
+ dTHR;
dSP;
PUSHMARK(sp);
@@ -1010,13 +1154,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);
}
@@ -1026,6 +1171,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;
@@ -1049,7 +1195,7 @@ I32 flags; /* See G_* flags in cop.h */
myop.op_flags |= ((flags & G_VOID) ? OPf_WANT_VOID :
(flags & G_ARRAY) ? OPf_WANT_LIST :
OPf_WANT_SCALAR);
- SAVESPTR(op);
+ SAVEOP();
op = (OP*)&myop;
EXTEND(stack_sp, 1);
@@ -1125,7 +1271,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);
@@ -1169,6 +1315,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;
@@ -1183,7 +1330,7 @@ I32 flags; /* See G_* flags in cop.h */
SAVETMPS;
}
- SAVESPTR(op);
+ SAVEOP();
op = (OP*)&myop;
Zero(op, 1, UNOP);
EXTEND(stack_sp, 1);
@@ -1233,7 +1380,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);
@@ -1257,6 +1404,7 @@ perl_eval_pv(p, croak_on_error)
char* p;
I32 croak_on_error;
{
+ dTHR;
dSP;
SV* sv = newSVpv(p, 0);
@@ -1464,30 +1612,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));
@@ -1614,6 +1763,7 @@ my_unexec()
static void
init_main_stash()
{
+ dTHR;
GV *gv;
/* Note that strtab is a rather special HV. Assumptions are made
@@ -1657,6 +1807,7 @@ bool dosearch;
SV *sv;
#endif
{
+ dTHR;
char *xfound = Nullch;
char *xfailed = Nullch;
register char *s;
@@ -2194,6 +2345,7 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
#else /* !DOSUID */
if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */
#ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
+ dTHR;
Fstat(PerlIO_fileno(rsfp),&statbuf); /* may be either wrapped or real suid */
if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
||
@@ -2264,6 +2416,7 @@ char *s;
static void
init_debugger()
{
+ dTHR;
curstash = debstash;
dbargs = GvAV(gv_AVadd((gv_fetchpv("args", GV_ADDMULTI, SVt_PVAV))));
AvREAL_off(dbargs);
@@ -2279,8 +2432,9 @@ init_debugger()
curstash = defstash;
}
-static void
-init_stacks()
+void
+init_stacks(ARGS)
+dARGS
{
curstack = newAV();
mainstack = curstack; /* remember in case we switch stacks */
@@ -2296,14 +2450,10 @@ init_stacks()
cxstack_ix = -1;
New(50,tmps_stack,128,SV*);
+ tmps_floor = -1;
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
@@ -2345,6 +2495,7 @@ init_stacks()
static void
nuke_stacks()
{
+ dTHR;
Safefree(cxstack);
Safefree(tmps_stack);
DEBUG( {
@@ -2368,6 +2519,7 @@ init_lexer()
static void
init_predump_symbols()
{
+ dTHR;
GV *tmpgv;
GV *othergv;
@@ -2655,6 +2807,7 @@ call_list(oldscope, list)
I32 oldscope;
AV* list;
{
+ dTHR;
line_t oldline = curcop->cop_line;
STRLEN len;
dJMPENV;
@@ -2727,6 +2880,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;
@@ -2767,6 +2926,7 @@ my_failure_exit()
static void
my_exit_jump()
{
+ dTHR;
register CONTEXT *cx;
I32 gimme;
SV **newsp;