📄 pruthr.c
字号:
*/ _PR_MD_EXIT_THREAD(thread); /* * Free memory allocated for the thread */ _PR_NativeDestroyThread(thread); /* * thread gone, cannot de-reference thread now */ return; } /* Now wait for someone to activate us again... */ _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); }}static void _PR_UserRunThread(void){ PRThread *thread = _PR_MD_CURRENT_THREAD(); PRIntn is; if (_MD_LAST_THREAD()) _MD_LAST_THREAD()->no_sched = 0;#ifdef HAVE_CUSTOM_USER_THREADS if (thread->stack == NULL) { thread->stack = PR_NEWZAP(PRThreadStack); _PR_InitializeNativeStack(thread->stack); }#endif /* HAVE_CUSTOM_USER_THREADS */ while(1) { /* Run thread main */ if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0); /* * Add to list of active threads */ if (!(thread->flags & _PR_IDLE_THREAD)) { PR_Lock(_pr_activeLock); PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); _pr_local_threads++; PR_Unlock(_pr_activeLock); } (*thread->startFunc)(thread->arg); /* * The following two assertions are meant for NT asynch io. * * The thread should have no asynch io in progress when it * exits, otherwise the overlapped buffer, which is part of * the thread structure, would become invalid. */ PR_ASSERT(thread->io_pending == PR_FALSE); /* * This assertion enforces the programming guideline that * if an io function times out or is interrupted, the thread * should close the fd to force the asynch io to abort * before it exits. Right now, closing the fd is the only * way to clear the io_suspended flag. */ PR_ASSERT(thread->io_suspended == PR_FALSE); PR_Lock(_pr_activeLock); /* * remove thread from list of active threads */ if (!(thread->flags & _PR_IDLE_THREAD)) { PR_REMOVE_LINK(&thread->active); _pr_local_threads--; } PR_Unlock(_pr_activeLock); PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); /* All done, time to go away */ _PR_CleanupThread(thread); _PR_INTSOFF(is); _PR_NotifyJoinWaiters(thread); _PR_DecrActiveThreadCount(thread); thread->state = _PR_DEAD_STATE; if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == PR_FAILURE)) { /* ** Destroy the thread resources */ _PR_UserDestroyThread(thread); } /* ** Find another user thread to run. This cpu has finished the ** previous threads main and is now ready to run another thread. */ { PRInt32 is; _PR_INTSOFF(is); _PR_MD_SWITCH_CONTEXT(thread); } /* Will land here when we get scheduled again if we are recycling... */ }}void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri){ PRThread *me = _PR_MD_CURRENT_THREAD(); PRIntn is; if ( _PR_IS_NATIVE_THREAD(thread) ) { _PR_MD_SET_PRIORITY(&(thread->md), newPri); return; } if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_THREAD_LOCK(thread); if (newPri != thread->priority) { _PRCPU *cpu = thread->cpu; switch (thread->state) { case _PR_RUNNING: /* Change my priority */ _PR_RUNQ_LOCK(cpu); thread->priority = newPri; if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) { if (!_PR_IS_NATIVE_THREAD(me)) _PR_SET_RESCHED_FLAG(); } _PR_RUNQ_UNLOCK(cpu); break; case _PR_RUNNABLE: _PR_RUNQ_LOCK(cpu); /* Move to different runQ */ _PR_DEL_RUNQ(thread); thread->priority = newPri; PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); _PR_ADD_RUNQ(thread, cpu, newPri); _PR_RUNQ_UNLOCK(cpu); if (newPri > me->priority) { if (!_PR_IS_NATIVE_THREAD(me)) _PR_SET_RESCHED_FLAG(); } break; case _PR_LOCK_WAIT: case _PR_COND_WAIT: case _PR_IO_WAIT: case _PR_SUSPENDED: thread->priority = newPri; break; } } _PR_THREAD_UNLOCK(thread); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);}/*** Suspend the named thread and copy its gc registers into regBuf*/static void _PR_Suspend(PRThread *thread){ PRIntn is; PRThread *me = _PR_MD_CURRENT_THREAD(); PR_ASSERT(thread != me); PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu)); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_THREAD_LOCK(thread); switch (thread->state) { case _PR_RUNNABLE: if (!_PR_IS_NATIVE_THREAD(thread)) { _PR_RUNQ_LOCK(thread->cpu); _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(thread->cpu); _PR_MISCQ_LOCK(thread->cpu); _PR_ADD_SUSPENDQ(thread, thread->cpu); _PR_MISCQ_UNLOCK(thread->cpu); } else { /* * Only LOCAL threads are suspended by _PR_Suspend */ PR_ASSERT(0); } thread->state = _PR_SUSPENDED; break; case _PR_RUNNING: /* * The thread being suspended should be a LOCAL thread with * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state */ PR_ASSERT(0); break; case _PR_LOCK_WAIT: case _PR_IO_WAIT: case _PR_COND_WAIT: if (_PR_IS_NATIVE_THREAD(thread)) { _PR_MD_SUSPEND_THREAD(thread); } thread->flags |= _PR_SUSPENDING; break; default: PR_Abort(); } _PR_THREAD_UNLOCK(thread); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);}static void _PR_Resume(PRThread *thread){ PRThreadPriority pri; PRIntn is; PRThread *me = _PR_MD_CURRENT_THREAD(); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_THREAD_LOCK(thread); switch (thread->state) { case _PR_SUSPENDED: thread->state = _PR_RUNNABLE; thread->flags &= ~_PR_SUSPENDING; if (!_PR_IS_NATIVE_THREAD(thread)) { _PR_MISCQ_LOCK(thread->cpu); _PR_DEL_SUSPENDQ(thread); _PR_MISCQ_UNLOCK(thread->cpu); pri = thread->priority; _PR_RUNQ_LOCK(thread->cpu); _PR_ADD_RUNQ(thread, thread->cpu, pri); _PR_RUNQ_UNLOCK(thread->cpu); if (pri > _PR_MD_CURRENT_THREAD()->priority) { if (!_PR_IS_NATIVE_THREAD(me)) _PR_SET_RESCHED_FLAG(); } } else { PR_ASSERT(0); } break; case _PR_IO_WAIT: case _PR_COND_WAIT: thread->flags &= ~_PR_SUSPENDING;/* PR_ASSERT(thread->wait.monitor->stickyCount == 0); */ break; case _PR_LOCK_WAIT: { PRLock *wLock = thread->wait.lock; thread->flags &= ~_PR_SUSPENDING; _PR_LOCK_LOCK(wLock); if (thread->wait.lock->owner == 0) { _PR_UnblockLockWaiter(thread->wait.lock); } _PR_LOCK_UNLOCK(wLock); break; } case _PR_RUNNABLE: break; case _PR_RUNNING: /* * The thread being suspended should be a LOCAL thread with * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state */ PR_ASSERT(0); break; default: /* * thread should have been in one of the above-listed blocked states * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE) */ PR_Abort(); } _PR_THREAD_UNLOCK(thread); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);}#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus){ PRThread *thread; PRIntn pri; PRUint32 r; PRCList *qp; PRIntn priMin, priMax; _PR_RUNQ_LOCK(cpu); r = _PR_RUNQREADYMASK(cpu); if (r==0) { priMin = priMax = PR_PRIORITY_FIRST; } else if (r == (1<<PR_PRIORITY_NORMAL) ) { priMin = priMax = PR_PRIORITY_NORMAL; } else { priMin = PR_PRIORITY_FIRST; priMax = PR_PRIORITY_LAST; } thread = NULL; for (pri = priMax; pri >= priMin ; pri-- ) { if (r & (1 << pri)) { for (qp = _PR_RUNQ(cpu)[pri].next; qp != &_PR_RUNQ(cpu)[pri]; qp = qp->next) { thread = _PR_THREAD_PTR(qp); /* * skip non-schedulable threads */ PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); if (thread->no_sched) { thread = NULL; /* * Need to wakeup cpus to avoid missing a * runnable thread * Waking up all CPU's need happen only once. */ *wakeup_cpus = PR_TRUE; continue; } else if (thread->flags & _PR_BOUND_THREAD) { /* * Thread bound to cpu 0 */ thread = NULL;#ifdef IRIX _PR_MD_WAKEUP_PRIMORDIAL_CPU();#endif continue; } else if (thread->io_pending == PR_TRUE) { /* * A thread that is blocked for I/O needs to run * on the same cpu on which it was blocked. This is because * the cpu's ioq is accessed without lock protection and scheduling * the thread on a different cpu would preclude this optimization. */ thread = NULL; continue; } else { /* Pull thread off of its run queue */ _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(cpu); return(thread); } } } thread = NULL; } _PR_RUNQ_UNLOCK(cpu); return(thread);}#endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) *//*** Schedule this native thread by finding the highest priority nspr** thread that is ready to run.**** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls** PR_Schedule() rather than calling PR_Schedule. Otherwise if there** is initialization required for switching from SWITCH_CONTEXT,** it will not get done!*/void _PR_Schedule(void){ PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); _PRCPU *cpu = _PR_MD_CURRENT_CPU(); PRIntn pri; PRUint32 r; PRCList *qp; PRIntn priMin, priMax;#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) PRBool wakeup_cpus;#endif /* Interrupts must be disabled */ PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); /* Since we are rescheduling, we no longer want to */ _PR_CLEAR_RESCHED_FLAG(); /* ** Find highest priority thread to run. Bigger priority numbers are ** higher priority threads */ _PR_RUNQ_LOCK(cpu); /* * if we are in SuspendAll mode, can schedule only the thread * that called PR_SuspendAll * * The thread may be ready to run now, after completing an I/O * operation, for example */ if ((thread = suspendAllThread) != 0) { if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) { /* Pull thread off of its run queue */ _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(cpu); goto found_thread; } else { thread = NULL; _PR_RUNQ_UNLOCK(cpu); goto idle_thread; } } r = _PR_RUNQREADYMASK(cpu); if (r==0) { priMin = priMax = PR_PRIORITY_FIRST; } else if (r == (1<<PR_PRIORITY_NORMAL) ) { priMin = priMax = PR_PRIORITY_NORMAL; } else { priMin = PR_PRIORITY_FIRST; priMax = PR_PRIORITY_LAST; } thread = NULL; for (pri = priMax; pri >= priMin ; pri-- ) { if (r & (1 << pri)) { for (qp = _PR_RUNQ(cpu)[pri].next; qp != &_PR_RUNQ(cpu)[pri]; qp = qp->next) { thread = _PR_THREAD_PTR(qp); /* * skip non-schedulable threads */#if !defined(XP_MAC) PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));#endif if ((thread->no_sched) && (me != thread)){ thread = NULL; continue; } else { /* Pull thread off of its run queue */ _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(cpu); goto found_thread; } } } thread = NULL; } _PR_RUNQ_UNLOCK(cpu);#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) wakeup_cpus = PR_FALSE; _PR_CPU_LIST_LOCK(); for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { if (cpu != _PR_CPU_PTR(qp)) { if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus)) != NULL) { thread->cpu = cpu; _PR_CPU_LIST_UNLOCK(); if (wakeup_cpus == PR_TRUE) _PR_MD_WAKEUP_CPUS();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -