📄 pruthr.c
字号:
goto found_thread; } } } _PR_CPU_LIST_UNLOCK(); if (wakeup_cpus == PR_TRUE) _PR_MD_WAKEUP_CPUS();#endif /* _PR_LOCAL_THREADS_ONLY */idle_thread: /* ** There are no threads to run. Switch to the idle thread */ PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing")); thread = _PR_MD_CURRENT_CPU()->idle_thread;found_thread: PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) && (!(thread->no_sched)))); /* Resume the thread */ PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("switching to %d[%p]", thread->id, thread)); PR_ASSERT(thread->state != _PR_RUNNING); thread->state = _PR_RUNNING; /* If we are on the runq, it just means that we went to sleep on some * resource, and by the time we got here another real native thread had * already given us the resource and put us back on the runqueue */ PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU()); if (thread != me) _PR_MD_RESTORE_CONTEXT(thread);#if 0 /* XXXMB; with setjmp/longjmp it is impossible to land here, but * it is not with fibers... Is this a bad thing? I believe it is * still safe. */ PR_NOT_REACHED("impossible return from schedule");#endif}/*** Attaches a thread. ** Does not set the _PR_MD_CURRENT_THREAD. ** Does not specify the scope of the thread.*/static PRThread *_PR_AttachThread(PRThreadType type, PRThreadPriority priority, PRThreadStack *stack){#if defined(XP_MAC)#pragma unused (type)#endif PRThread *thread; char *mem; if (priority > PR_PRIORITY_LAST) { priority = PR_PRIORITY_LAST; } else if (priority < PR_PRIORITY_FIRST) { priority = PR_PRIORITY_FIRST; } mem = (char*) PR_CALLOC(sizeof(PRThread)); if (mem) { thread = (PRThread*) mem; thread->priority = priority; thread->stack = stack; thread->state = _PR_RUNNING; PR_INIT_CLIST(&thread->lockList); if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { PR_DELETE(thread); return 0; } return thread; } return 0;}PR_IMPLEMENT(PRThread*) _PR_NativeCreateThread(PRThreadType type, void (*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize, PRUint32 flags){#if defined(XP_MAC)#pragma unused (scope)#endif PRThread *thread; thread = _PR_AttachThread(type, priority, NULL); if (thread) { PR_Lock(_pr_activeLock); thread->flags = (flags | _PR_GLOBAL_SCOPE); thread->id = ++_pr_utid; if (type == PR_SYSTEM_THREAD) { thread->flags |= _PR_SYSTEM; _pr_systemActive++; } else { _pr_userActive++; } PR_Unlock(_pr_activeLock); thread->stack = PR_NEWZAP(PRThreadStack); if (!thread->stack) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); goto done; } thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE; thread->stack->thr = thread; thread->startFunc = start; thread->arg = arg; /* Set thread flags related to scope and joinable state. If joinable thread, allocate a "termination" conidition variable. */ if (state == PR_JOINABLE_THREAD) { thread->term = PR_NewCondVar(_pr_terminationCVLock); if (thread->term == NULL) { PR_DELETE(thread->stack); goto done; } } thread->state = _PR_RUNNING; if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority, scope,state,stackSize) == PR_SUCCESS) { return thread; } if (thread->term) { PR_DestroyCondVar(thread->term); thread->term = NULL; } PR_DELETE(thread->stack); }done: if (thread) { _PR_DecrActiveThreadCount(thread); _PR_DestroyThread(thread); } return NULL;}/************************************************************************/PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, void (*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize, PRUint32 flags){ PRThread *me; PRThread *thread = NULL; PRThreadStack *stack; char *top; PRIntn is; PRIntn native = 0; PRIntn useRecycled = 0; PRBool status; /* 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 (priority > PR_PRIORITY_LAST) { priority = PR_PRIORITY_LAST; } else if (priority < PR_PRIORITY_FIRST) { priority = PR_PRIORITY_FIRST; } if (!_pr_initialized) _PR_ImplicitInitialization(); if (! (flags & _PR_IDLE_THREAD)) me = _PR_MD_CURRENT_THREAD();#if defined(_PR_GLOBAL_THREADS_ONLY) /* * can create global threads only */ if (scope == PR_LOCAL_THREAD) scope = PR_GLOBAL_THREAD;#endif if (_native_threads_only) scope = PR_GLOBAL_THREAD; native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD)) && _PR_IS_NATIVE_THREAD_SUPPORTED()); _PR_ADJUST_STACKSIZE(stackSize); if (native) { /* * clear the IDLE_THREAD flag which applies to LOCAL * threads only */ flags &= ~_PR_IDLE_THREAD; flags |= _PR_GLOBAL_SCOPE; if (_PR_NUM_DEADNATIVE > 0) { _PR_DEADQ_LOCK; if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */ _PR_DEADQ_UNLOCK; } else { thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next); PR_REMOVE_LINK(&thread->links); _PR_DEC_DEADNATIVE; _PR_DEADQ_UNLOCK; _PR_InitializeRecycledThread(thread); thread->startFunc = start; thread->arg = arg; thread->flags = (flags | _PR_GLOBAL_SCOPE); if (type == PR_SYSTEM_THREAD) { thread->flags |= _PR_SYSTEM; PR_AtomicIncrement(&_pr_systemActive); } else PR_AtomicIncrement(&_pr_userActive); if (state == PR_JOINABLE_THREAD) { if (!thread->term) thread->term = PR_NewCondVar(_pr_terminationCVLock); } else { if(thread->term) { PR_DestroyCondVar(thread->term); thread->term = 0; } } thread->priority = priority; _PR_MD_SET_PRIORITY(&(thread->md), priority); /* XXX what about stackSize? */ thread->state = _PR_RUNNING; _PR_MD_WAKEUP_WAITER(thread); return thread; } } thread = _PR_NativeCreateThread(type, start, arg, priority, scope, state, stackSize, flags); } else { if (_PR_NUM_DEADUSER > 0) { _PR_DEADQ_LOCK; if (_PR_NUM_DEADUSER == 0) { /* thread safe check */ _PR_DEADQ_UNLOCK; } else { PRCList *ptr; /* Go down list checking for a recycled thread with a * large enough stack. XXXMB - this has a bad degenerate case. */ ptr = _PR_DEADUSERQ.next; while( ptr != &_PR_DEADUSERQ ) { thread = _PR_THREAD_PTR(ptr); if ((thread->stack->stackSize >= stackSize) && (!thread->no_sched)) { PR_REMOVE_LINK(&thread->links); _PR_DEC_DEADUSER; break; } else { ptr = ptr->next; thread = NULL; } } _PR_DEADQ_UNLOCK; if (thread) { _PR_InitializeRecycledThread(thread); thread->startFunc = start; thread->arg = arg; thread->priority = priority; if (state == PR_JOINABLE_THREAD) { if (!thread->term) thread->term = PR_NewCondVar(_pr_terminationCVLock); } else { if(thread->term) { PR_DestroyCondVar(thread->term); thread->term = 0; } } useRecycled++; } } } if (thread == NULL) {#ifndef HAVE_CUSTOM_USER_THREADS stack = _PR_NewStack(stackSize); if (!stack) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } /* Allocate thread object and per-thread data off the top of the stack*/ top = stack->stackTop;#ifdef HAVE_STACK_GROWING_UP thread = (PRThread*) top; top = top + sizeof(PRThread); /* * Make stack 64-byte aligned */ if ((PRUptrdiff)top & 0x3f) { top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f); }#else top = top - sizeof(PRThread); thread = (PRThread*) top; /* * Make stack 64-byte aligned */ if ((PRUptrdiff)top & 0x3f) { top = (char*)((PRUptrdiff)top & ~0x3f); }#endif#if defined(GC_LEAK_DETECTOR) /* * sorry, it is not safe to allocate the thread on the stack, * because we assign to this object before the GC can learn * about this thread. we'll just leak thread objects instead. */ thread = PR_NEW(PRThread);#endif stack->thr = thread; memset(thread, 0, sizeof(PRThread)); thread->threadAllocatedOnStack = 1;#else thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg); if (!thread) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } thread->threadAllocatedOnStack = 0; stack = NULL; top = NULL;#endif /* Initialize thread */ thread->tpdLength = 0; thread->privateData = NULL; thread->stack = stack; thread->priority = priority; thread->startFunc = start; thread->arg = arg; PR_INIT_CLIST(&thread->lockList); if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { if (thread->threadAllocatedOnStack == 1) _PR_FreeStack(thread->stack); else { PR_DELETE(thread); } PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); return NULL; } if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { if (thread->threadAllocatedOnStack == 1) _PR_FreeStack(thread->stack); else { PR_DELETE(thread->privateData); PR_DELETE(thread); } PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); return NULL; } _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status); if (status == PR_FALSE) { _PR_MD_FREE_LOCK(&thread->threadLock); if (thread->threadAllocatedOnStack == 1) _PR_FreeStack(thread->stack); else { PR_DELETE(thread->privateData); PR_DELETE(thread); } return NULL; } /* Set thread flags related to scope and joinable state. If joinable thread, allocate a "termination" condition variable. */ if (state == PR_JOINABLE_THREAD) { thread->term = PR_NewCondVar(_pr_terminationCVLock); if (thread->term == NULL) { _PR_MD_FREE_LOCK(&thread->threadLock); if (thread->threadAllocatedOnStack == 1) _PR_FreeStack(thread->stack); else { PR_DELETE(thread->privateData); PR_DELETE(thread); } return NULL; } } } /* Update thread type counter */ PR_Lock(_pr_activeLock); thread->flags = flags; thread->id = ++_pr_utid; if (type == PR_SYSTEM_THREAD) { thread->flags |= _PR_SYSTEM; _pr_systemActive++; } else { _pr_userActive++; } /* Make thread runnable */ thread->state = _PR_RUNNABLE; /* * Add to list of active threads */ PR_Unlock(_pr_activeLock); if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) ) thread->cpu = _PR_GetPrimordialCPU(); else thread->cpu = _PR_MD_CURRENT_CPU(); PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) { _PR_INTSOFF(is); _PR_RUNQ_LOCK(thread->cpu); _PR_ADD_RUNQ(thread, thread->cpu, priority); _PR_RUNQ_UNLOCK(thread->cpu); } if (thread->flags & _PR_IDLE_THREAD) { /* ** If the creating thread is a kernel thread, we need to ** awaken the user thread idle thread somehow; potentially ** it could be sleeping in its idle loop, and we need to poke ** it. To do so, wake the idle thread... */ _PR_MD_WAKEUP_WAITER(NULL); } else if (_PR_IS_NATIVE_THREAD(me)) { _PR_MD_WAKEUP_WAITER(thread); } if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) ) _PR_INTSON(is); } return thread;}PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type, void (*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize){ return _PR_CreateThread(type, start, arg, priority, scope, state,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -