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

📄 pruthr.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 4 页
字号:
                            stackSize, 0);}/*** Associate a thread object with an existing native thread.**     "type" is the type of thread object to attach**     "priority" is the priority to assign to the thread**     "stack" defines the shape of the threads stack**** This can return NULL if some kind of error occurs, or if memory is** tight.**** This call is not normally needed unless you create your own native** thread. PR_Init does this automatically for the primordial thread.*/PRThread* _PRI_AttachThread(PRThreadType type,    PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags){    PRThread *thread;    if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) {        return thread;    }    _PR_MD_SET_CURRENT_THREAD(NULL);    /* Clear out any state if this thread was attached before */    _PR_MD_SET_CURRENT_CPU(NULL);    thread = _PR_AttachThread(type, priority, stack);    if (thread) {        PRIntn is;        _PR_MD_SET_CURRENT_THREAD(thread);        thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED;        if (!stack) {            thread->stack = PR_NEWZAP(PRThreadStack);            if (!thread->stack) {                _PR_DestroyThread(thread);                return NULL;            }            thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE;        }        PR_INIT_CLIST(&thread->links);        if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) {                PR_DELETE(thread->stack);                _PR_DestroyThread(thread);                return NULL;        }        _PR_MD_SET_CURRENT_CPU(NULL);        if (_PR_MD_CURRENT_CPU()) {            _PR_INTSOFF(is);            PR_Lock(_pr_activeLock);        }        if (type == PR_SYSTEM_THREAD) {            thread->flags |= _PR_SYSTEM;            _pr_systemActive++;        } else {            _pr_userActive++;        }        if (_PR_MD_CURRENT_CPU()) {            PR_Unlock(_pr_activeLock);            _PR_INTSON(is);        }    }    return thread;}PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type,    PRThreadPriority priority, PRThreadStack *stack){#ifdef XP_MAC#pragma unused( type, priority, stack )#endif    return PR_GetCurrentThread();}PR_IMPLEMENT(void) PR_DetachThread(void){}void _PRI_DetachThread(void){    PRThread *me = _PR_MD_CURRENT_THREAD();	if (me->flags & _PR_PRIMORDIAL) {		/*		 * ignore, if primordial thread		 */		return;	}    PR_ASSERT(me->flags & _PR_ATTACHED);    PR_ASSERT(_PR_IS_NATIVE_THREAD(me));    _PR_CleanupThread(me);    PR_DELETE(me->privateData);    _PR_DecrActiveThreadCount(me);    _PR_MD_CLEAN_THREAD(me);    _PR_MD_SET_CURRENT_THREAD(NULL);    if (!me->threadAllocatedOnStack)         PR_DELETE(me->stack);    _PR_MD_FREE_LOCK(&me->threadLock);    PR_DELETE(me);}/*** Wait for thread termination:**     "thread" is the target thread **** This can return PR_FAILURE if no joinable thread could be found ** corresponding to the specified target thread.**** The calling thread is suspended until the target thread completes.** Several threads cannot wait for the same thread to complete; one thread** will complete successfully and others will terminate with an error PR_FAILURE.** The calling thread will not be blocked if the target thread has already** terminated.*/PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread){    PRIntn is;    PRCondVar *term;    PRThread *me = _PR_MD_CURRENT_THREAD();    if (!_PR_IS_NATIVE_THREAD(me))        _PR_INTSOFF(is);    term = thread->term;    /* can't join a non-joinable thread */    if (term == NULL) {        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);        goto ErrorExit;    }    /* multiple threads can't wait on the same joinable thread */    if (term->condQ.next != &term->condQ) {        goto ErrorExit;    }    if (!_PR_IS_NATIVE_THREAD(me))        _PR_INTSON(is);    /* wait for the target thread's termination cv invariant */    PR_Lock (_pr_terminationCVLock);    while (thread->state != _PR_JOIN_WAIT) {        (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT);    }    (void) PR_Unlock (_pr_terminationCVLock);        /*      Remove target thread from global waiting to join Q; make it runnable     again and put it back on its run Q.  When it gets scheduled later in     _PR_RunThread code, it will clean up its stack.    */        if (!_PR_IS_NATIVE_THREAD(me))        _PR_INTSOFF(is);    thread->state = _PR_RUNNABLE;    if ( !_PR_IS_NATIVE_THREAD(thread) ) {        _PR_THREAD_LOCK(thread);        _PR_MISCQ_LOCK(thread->cpu);        _PR_DEL_JOINQ(thread);        _PR_MISCQ_UNLOCK(thread->cpu);        _PR_AddThreadToRunQ(me, thread);        _PR_THREAD_UNLOCK(thread);    }    if (!_PR_IS_NATIVE_THREAD(me))        _PR_INTSON(is);    _PR_MD_WAKEUP_WAITER(thread);    return PR_SUCCESS;ErrorExit:    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);    return PR_FAILURE;   }PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread,    PRThreadPriority newPri){    /*     First, pin down the priority.  Not all compilers catch passing out of    range enum here.  If we let bad values thru, priority queues won't work.    */    if ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) {        newPri = PR_PRIORITY_LAST;    } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) {        newPri = PR_PRIORITY_FIRST;    }            if ( _PR_IS_NATIVE_THREAD(thread) ) {        thread->priority = newPri;        _PR_MD_SET_PRIORITY(&(thread->md), newPri);    } else _PR_SetThreadPriority(thread, newPri);}/*** This routine prevents all other threads from running. This call is needed by ** the garbage collector.*/PR_IMPLEMENT(void) PR_SuspendAll(void){    PRThread *me = _PR_MD_CURRENT_THREAD();    PRCList *qp;    /*     * Stop all user and native threads which are marked GC able.     */    PR_Lock(_pr_activeLock);    suspendAllOn = PR_TRUE;    suspendAllThread = _PR_MD_CURRENT_THREAD();    _PR_MD_BEGIN_SUSPEND_ALL();    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;        qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) {            _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp));                PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING);            }    }    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;        qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))            /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */                _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp));     }    _PR_MD_END_SUSPEND_ALL();}/*** This routine unblocks all other threads that were suspended from running by ** PR_SuspendAll(). This call is needed by the garbage collector.*/PR_IMPLEMENT(void) PR_ResumeAll(void){    PRThread *me = _PR_MD_CURRENT_THREAD();    PRCList *qp;    /*     * Resume all user and native threads which are marked GC able.     */    _PR_MD_BEGIN_RESUME_ALL();    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;        qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))            _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp));    }    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;        qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {        if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&            _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))                _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp));    }    _PR_MD_END_RESUME_ALL();    suspendAllThread = NULL;    suspendAllOn = PR_FALSE;    PR_Unlock(_pr_activeLock);}PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg){    PRCList *qp, *qp_next;    PRIntn i = 0;    PRStatus rv = PR_SUCCESS;    PRThread* t;    /*    ** Currently Enumerate threads happen only with suspension and    ** pr_activeLock held    */    PR_ASSERT(suspendAllOn);    /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking     * qp->next after applying the function "func".  In particular, "func"     * might remove the thread from the queue and put it into another one in     * which case qp->next no longer points to the next entry in the original     * queue.     *     * To get around this problem, we save qp->next in qp_next before applying     * "func" and use that saved value as the next value after applying "func".     */    /*     * Traverse the list of local and global threads     */    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next)    {        qp_next = qp->next;        t = _PR_ACTIVE_THREAD_PTR(qp);        if (_PR_IS_GCABLE_THREAD(t))        {            rv = (*func)(t, i, arg);            if (rv != PR_SUCCESS)                return rv;            i++;        }    }    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next)    {        qp_next = qp->next;        t = _PR_ACTIVE_THREAD_PTR(qp);        if (_PR_IS_GCABLE_THREAD(t))        {            rv = (*func)(t, i, arg);            if (rv != PR_SUCCESS)                return rv;            i++;        }    }    return rv;}/* FUNCTION: _PR_AddSleepQ** DESCRIPTION:**    Adds a thread to the sleep/pauseQ.** RESTRICTIONS:**    Caller must have the RUNQ lock.**    Caller must be a user level thread*/PR_IMPLEMENT(void)_PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout){    _PRCPU *cpu = thread->cpu;    if (timeout == PR_INTERVAL_NO_TIMEOUT) {        /* append the thread to the global pause Q */        PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu));        thread->flags |= _PR_ON_PAUSEQ;    } else {        PRIntervalTime sleep;        PRCList *q;        PRThread *t;        /* sort onto global sleepQ */        sleep = timeout;        /* Check if we are longest timeout */        if (timeout >= _PR_SLEEPQMAX(cpu)) {            PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu));            thread->sleep = timeout - _PR_SLEEPQMAX(cpu);            _PR_SLEEPQMAX(cpu) = timeout;        } else {            /* Sort thread into global sleepQ at appropriate point */            q = _PR_SLEEPQ(cpu).next;            /* Now scan the list for where to insert this entry */            while (q != &_PR_SLEEPQ(cpu)) {                t = _PR_THREAD_PTR(q);                if (sleep < t->sleep) {                    /* Found sleeper to insert in front of */                    break;                }                sleep -= t->sleep;                q = q->next;            }            thread->sleep = sleep;            PR_INSERT_BEFORE(&thread->links, q);            /*            ** Subtract our sleep time from the sleeper that follows us (there            ** must be one) so that they remain relative to us.            */            PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu));                      t = _PR_THREAD_PTR(thread->links.next);            PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread);            t->sleep -= sleep;        }        thread->flags |= _PR_ON_SLEEPQ;    }}/* FUNCTION: _PR_DelSleepQ** DESCRIPTION:**    Removes a thread from the sleep/pauseQ.** INPUTS:**    If propogate_time is true, then the thread following the deleted**    thread will be get the time from the deleted thread.  This is used**    when deleting a sleeper that has not timed out.** RESTRICTIONS:**    Caller must have the RUNQ lock.**    Caller must be a user level thread*/PR_IMPLEMENT(void)_PR_DelSleepQ(PRThread *thread, PRBool propogate_time){    _PRCPU *cpu = thread->cpu;    /* Remove from pauseQ/sleepQ */    if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {        if (thread->flags & _PR_ON_SLEEPQ) {            PRCList *q = thread->links.next;            if (q != &_PR_SLEEPQ(cpu)) {                if (propogate_time == PR_TRUE) {                    PRThread *after = _PR_THREAD_PTR(q);                    after->sleep += thread->sleep;                } else                     _PR_SLEEPQMAX(cpu) -= thread->sleep;            } else {                /* Check if prev is the beggining of the list; if so,                 * we are the only element on the list.                   */                if (thread->links.prev != &_PR_SLEEPQ(cpu))                    _PR_SLEEPQMAX(cpu) -= thread->sleep;                else                    _PR_SLEEPQMAX(cpu) = 0;            }            thread->flags &= ~_PR_ON_SLEEPQ;        } else {            thread->flags &= ~_PR_ON_PAUSEQ;        }        PR_REMOVE_LINK(&thread->links);    } else         PR_ASSERT(0);}void_PR_AddThreadToRunQ(    PRThread *me,     /* the current thread */    PRThread *thread) /* the local thread to be added to a run queue */{    PRThreadPriority pri = thread->priority;    _PRCPU *cpu = thread->cpu;    PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));#if defined(WINNT)    /*     * On NT, we can only reliably know that the current CPU     * is not idle.  We add the awakened thread to the run     * queue of its CPU if its CPU is the current CPU.     * For any other CPU, we don't really know whether it     * is busy or idle.  So in all other cases, we just     * "post" the awakened thread to the IO completion port     * for the next idle CPU to execute (this is done in     * _PR_MD_WAKEUP_WAITER).	 * Threads with a suspended I/O operation remain bound to	 * the same cpu until I/O is cancelled     *     * NOTE: the boolean expression below must be the exact     * opposite of the corresponding boolean expression in     * _PR_MD_WAKEUP_WAITER.     */    if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) ||					(thread->md.thr_bound_cpu)) {		PR_ASSERT(!thread->md.thr_bound_cpu ||							(thread->md.thr_bound_cpu == cpu));        _PR_RUNQ_LOCK(cpu);        _PR_ADD_RUNQ(thread, cpu, pri);        _PR_RUNQ_UNLOCK(cpu);    }#else    _PR_RUNQ_LOCK(cpu);    _PR_ADD_RUNQ(thread, cpu, pri);    _PR_RUNQ_UNLOCK(cpu);    if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {        if (pri > me->priority) {            _PR_SET_RESCHED_FLAG();        }    }#endif}

⌨️ 快捷键说明

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