⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.xs

📁 UNIX下perl实现代码
💻 XS
📖 第 1 页 / 共 2 页
字号:
#define PERL_NO_GET_CONTEXT#include "EXTERN.h"#include "perl.h"#include "XSUB.h"/* Magic signature for Thread's mg_private is "Th" */ #define Thread_MAGIC_SIGNATURE 0x5468#ifdef __cplusplus#ifdef I_UNISTD#include <unistd.h>#endif#endif#include <fcntl.h>                        static int sig_pipe[2];            #ifndef THREAD_RET_TYPE#define THREAD_RET_TYPE void *#define THREAD_RET_CAST(x) ((THREAD_RET_TYPE) x)#endifstatic voidremove_thread(pTHX_ Thread t){#ifdef USE_THREADS    DEBUG_S(WITH_THR(PerlIO_printf(Perl_debug_log,				   "%p: remove_thread %p\n", thr, t)));    MUTEX_LOCK(&PL_threads_mutex);    MUTEX_DESTROY(&t->mutex);    PL_nthreads--;    t->prev->next = t->next;    t->next->prev = t->prev;    SvREFCNT_dec(t->oursv);    COND_BROADCAST(&PL_nthreads_cond);    MUTEX_UNLOCK(&PL_threads_mutex);#endif}static THREAD_RET_TYPEthreadstart(void *arg){#ifdef USE_THREADS#ifdef FAKE_THREADS    Thread savethread = thr;    LOGOP myop;    dSP;    I32 oldscope = PL_scopestack_ix;    I32 retval;    AV *av;    int i;    DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p starting at %s\n",			  thr, SvPEEK(TOPs)));    thr = (Thread) arg;    savemark = TOPMARK;    thr->prev = thr->prev_run = savethread;    thr->next = savethread->next;    thr->next_run = savethread->next_run;    savethread->next = savethread->next_run = thr;    thr->wait_queue = 0;    thr->private = 0;    /* Now duplicate most of perl_call_sv but with a few twists */    PL_op = (OP*)&myop;    Zero(PL_op, 1, LOGOP);    myop.op_flags = OPf_STACKED;    myop.op_next = Nullop;    myop.op_flags |= OPf_KNOW;    myop.op_flags |= OPf_WANT_LIST;    PL_op = pp_entersub(ARGS);    DEBUG_S(if (!PL_op)	    PerlIO_printf(Perl_debug_log, "thread starts at Nullop\n"));    /*     * When this thread is next scheduled, we start in the right     * place. When the thread runs off the end of the sub, perl.c     * handles things, using savemark to figure out how much of the     * stack is the return value for any join.     */    thr = savethread;		/* back to the old thread */    return 0;#else    Thread thr = (Thread) arg;    LOGOP myop;    dSP;    I32 oldmark = TOPMARK;    I32 oldscope = PL_scopestack_ix;    I32 retval;    SV *sv;    AV *av;    int i, ret;    dJMPENV;#if defined(MULTIPLICITY)    PERL_SET_INTERP(thr->interp);#endif    DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p waiting to start\n",			  thr));    /*     * Wait until our creator releases us. If we didn't do this, then     * it would be potentially possible for out thread to carry on and     * do stuff before our creator fills in our "self" field. For example,     * if we went and created another thread which tried to JOIN with us,     * then we'd be in a mess.     */    MUTEX_LOCK(&thr->mutex);    MUTEX_UNLOCK(&thr->mutex);    /*     * It's safe to wait until now to set the thread-specific pointer     * from our pthread_t structure to our struct perl_thread, since     * we're the only thread who can get at it anyway.     */    PERL_SET_THX(thr);    DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p starting at %s\n",			  thr, SvPEEK(TOPs)));    av = newAV();    sv = POPs;    PUTBACK;    ENTER;    SAVETMPS;    perl_call_sv(sv, G_ARRAY|G_EVAL);    SPAGAIN;    retval = SP - (PL_stack_base + oldmark);    SP = PL_stack_base + oldmark + 1;    if (SvCUR(thr->errsv)) {	MUTEX_LOCK(&thr->mutex);	thr->flags |= THRf_DID_DIE;	MUTEX_UNLOCK(&thr->mutex);	av_store(av, 0, &PL_sv_no);	av_store(av, 1, newSVsv(thr->errsv));	DEBUG_S(PerlIO_printf(Perl_debug_log, "%p died: %s\n",			      thr, SvPV(thr->errsv, PL_na)));    }    else {	DEBUG_S(STMT_START {	    for (i = 1; i <= retval; i++) {		PerlIO_printf(Perl_debug_log, "%p return[%d] = %s\n",				thr, i, SvPEEK(SP[i - 1]));	    }	} STMT_END);	av_store(av, 0, &PL_sv_yes);	for (i = 1; i <= retval; i++, SP++)	    sv_setsv(*av_fetch(av, i, TRUE), SvREFCNT_inc(*SP));    }    FREETMPS;    LEAVE;  finishoff:#if 0        /* removed for debug */    SvREFCNT_dec(PL_curstack);#endif    SvREFCNT_dec(thr->cvcache);    SvREFCNT_dec(thr->threadsv);    SvREFCNT_dec(thr->specific);    SvREFCNT_dec(thr->errsv);    /*Safefree(cxstack);*/    while (PL_curstackinfo->si_next)	PL_curstackinfo = PL_curstackinfo->si_next;    while (PL_curstackinfo) {	PERL_SI *p = PL_curstackinfo->si_prev;	SvREFCNT_dec(PL_curstackinfo->si_stack);	Safefree(PL_curstackinfo->si_cxstack);	Safefree(PL_curstackinfo);	PL_curstackinfo = p;    }        Safefree(PL_markstack);    Safefree(PL_scopestack);    Safefree(PL_savestack);    Safefree(PL_retstack);    Safefree(PL_tmps_stack);    Safefree(PL_ofs);    SvREFCNT_dec(PL_rs);    SvREFCNT_dec(PL_nrs);    SvREFCNT_dec(PL_statname);    SvREFCNT_dec(PL_errors);    Safefree(PL_screamfirst);    Safefree(PL_screamnext);    Safefree(PL_reg_start_tmp);    SvREFCNT_dec(PL_lastscream);    SvREFCNT_dec(PL_defoutgv);    Safefree(PL_reg_poscache);    MUTEX_LOCK(&thr->mutex);    DEBUG_S(PerlIO_printf(Perl_debug_log,			  "%p: threadstart finishing: state is %u\n",			  thr, ThrSTATE(thr)));    switch (ThrSTATE(thr)) {    case THRf_R_JOINABLE:	ThrSETSTATE(thr, THRf_ZOMBIE);	MUTEX_UNLOCK(&thr->mutex);	DEBUG_S(PerlIO_printf(Perl_debug_log,			      "%p: R_JOINABLE thread finished\n", thr));	break;    case THRf_R_JOINED:	ThrSETSTATE(thr, THRf_DEAD);	MUTEX_UNLOCK(&thr->mutex);	remove_thread(aTHX_ thr);	DEBUG_S(PerlIO_printf(Perl_debug_log,			      "%p: R_JOINED thread finished\n", thr));	break;    case THRf_R_DETACHED:	ThrSETSTATE(thr, THRf_DEAD);	MUTEX_UNLOCK(&thr->mutex);	SvREFCNT_dec(av);	DEBUG_S(PerlIO_printf(Perl_debug_log,			      "%p: DETACHED thread finished\n", thr));	remove_thread(aTHX_ thr);	/* This might trigger main thread to finish */	break;    default:	MUTEX_UNLOCK(&thr->mutex);	croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr));	/* NOTREACHED */    }    return THREAD_RET_CAST(av);	/* Available for anyone to join with */					/* us unless we're detached, in which */					/* case noone sees the value anyway. */#endif    #else    return THREAD_RET_CAST(NULL);#endif}static SV *newthread (pTHX_ SV *startsv, AV *initargs, char *classname){#ifdef USE_THREADS    dSP;    Thread savethread;    int i;    SV *sv;    int err;#ifndef THREAD_CREATE    static pthread_attr_t attr;    static int attr_inited = 0;    sigset_t fullmask, oldmask;    static int attr_joinable = PTHREAD_CREATE_JOINABLE;#endif    savethread = thr;    thr = new_struct_thread(thr);    /* temporarily pretend to be the child thread in case the     * XPUSHs() below want to grow the child's stack.  This is     * safe, since the other thread is not yet created, and we     * are the only ones who know about it */    PERL_SET_THX(thr);    SPAGAIN;    DEBUG_S(PerlIO_printf(Perl_debug_log,			  "%p: newthread (%p), tid is %u, preparing stack\n",			  savethread, thr, thr->tid));    /* The following pushes the arg list and startsv onto the *new* stack */    PUSHMARK(SP);    /* Could easily speed up the following greatly */    for (i = 0; i <= AvFILL(initargs); i++)	XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE)));    XPUSHs(SvREFCNT_inc(startsv));    PUTBACK;    /* On your marks... */    PERL_SET_THX(savethread);    MUTEX_LOCK(&thr->mutex);#ifdef THREAD_CREATE    err = THREAD_CREATE(thr, threadstart);#else        /* Get set...  */    sigfillset(&fullmask);    if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1)	croak("panic: sigprocmask");    err = 0;    if (!attr_inited) {	attr_inited = 1;	err = pthread_attr_init(&attr);#  ifdef PTHREAD_ATTR_SETDETACHSTATE	if (err == 0)	    err = PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable);#  else	croak("panic: can't pthread_attr_setdetachstate");#  endif    }    if (err == 0)	err = PTHREAD_CREATE(&thr->self, attr, threadstart, (void*) thr);#endif    if (err) {	MUTEX_UNLOCK(&thr->mutex);        DEBUG_S(PerlIO_printf(Perl_debug_log,			      "%p: create of %p failed %d\n",			      savethread, thr, err));	/* Thread creation failed--clean up */	SvREFCNT_dec(thr->cvcache);	remove_thread(aTHX_ thr);	for (i = 0; i <= AvFILL(initargs); i++)	    SvREFCNT_dec(*av_fetch(initargs, i, FALSE));	SvREFCNT_dec(startsv);	return NULL;    }#ifdef THREAD_POST_CREATE    THREAD_POST_CREATE(thr);#else    if (sigprocmask(SIG_SETMASK, &oldmask, 0))	croak("panic: sigprocmask");#endif    sv = newSViv(thr->tid);    sv_magic(sv, thr->oursv, '~', 0, 0);    SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;    sv = sv_bless(newRV_noinc(sv), gv_stashpv(classname, TRUE));    /* Go */    MUTEX_UNLOCK(&thr->mutex);    return sv;#else#  ifdef USE_ITHREADS    croak("This perl was built for \"ithreads\", which currently does not support Thread.pm.\n"	  "Run \"perldoc Thread\" for more information");#  else    croak("This perl was not built with support for 5.005-style threads.\n"	  "Run \"perldoc Thread\" for more information");#  endif    return &PL_sv_undef;#endif}static Signal_t handle_thread_signal (int sig);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -