rvthread.c
来自「基于h323协议的软phone」· C语言 代码 · 共 1,787 行 · 第 1/5 页
C
1,787 行
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
if(pthread_attr_init(&th->tcb) != 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
th->tcb = NULL; /* make sure its clear so we know when a handle has been created */
#endif
RvLockRelease(&RvThreadLock);
return result;
}
/* Construct a thread which is actually a dummy thread used to attach */
/* information to the calling thread, which must be a thread that was not */
/* contructed with the RvThreadConstruct function. This function must be */
/* called from any thread not constructed with the RvThreadConstruct */
/* function before making any other calls to rvthread. Obviously, some */
/* rvthread calls can not be used on threads constructed in this manner. */
RVCOREAPI RvStatus RVCALLCONV RvThreadConstructFromUserThread(RvThread *th)
{
RvStatus result;
/* Use the regular construct with a dummy function to set up the basics. */
result = RvThreadConstruct(th, (RvThreadFunc)0xff, NULL);
if(result != RV_OK)
return result;
/* Now create the special version for our purposes. */
RvLockGet(&RvThreadLock);
th->state = RV_THREAD_STATE_SPECIAL;
strncpy(th->name, "RvUserDefault", RV_THREAD_MAX_NAMESIZE);
th->id = RvThreadCurrentId();
RvThreadGetOsPriority(th->id, (RvInt32*)&th->priority);
result = RvThreadSetupThreadPtr(th);
RvLockRelease(&RvThreadLock);
return result;
}
/* Will wait for a thread to exit and then destroy it. Obviously only */
/* one destruct is allowed on each thread. */
RVCOREAPI RvStatus RVCALLCONV RvThreadDestruct(RvThread *th)
{
#if defined(RV_NULLCHECK)
if(th == NULL)
return RvThreadErrorCode(RV_ERROR_NULLPTR);
#endif
RvLockGet(&RvThreadLock);
/* Check if thread already destroyed. Obviously can't lock */
/* and could be a problem if the memory has been deallocated. */
if(th->state == RV_THREAD_STATE_DESTROYED) {
RvLockRelease(&RvThreadLock);
return RV_OK;
}
RvLockGet(&th->datalock);
if(th->waitdestruct == RV_TRUE) {
/* Someone is already detructing this thread */
RvLockRelease(&th->datalock);
RvLockRelease(&RvThreadLock);
return RvThreadErrorCode(RV_THREAD_ERROR_DESTRUCTING);
}
/* Deal with application threads (created with RvThreadConstructFromUserThread) */
if(th->state == RV_THREAD_STATE_SPECIAL) {
if(RvThreadIdEqual(th->id, RvThreadCurrentId()) == RV_FALSE) {
/* May only be destructed from thread itself */
RvLockRelease(&RvThreadLock);
return RvThreadErrorCode(RV_THREAD_ERROR_USERAPP);
}
/* Call exit functions (unlock thread lock to prevent dealocks) */
RvLockRelease(&th->datalock);
RvThreadCallExits(th);
RvLockGet(&th->datalock);
/* Remove thread pointer. */
RvThreadRemoveThreadPtr(th);
}
if(th->state == RV_THREAD_STATE_CREATED) {
/* Task created but never started, just kill it off */
if(RvThreadDelete(th) != RV_OK) {
RvLockRelease(&th->datalock);
RvLockRelease(&RvThreadLock);
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
}
/* Wait to make sure thread no longer exists (from OS perspective). */
/* If any thread specific cleanup has to be done than do it. */
RvThreadWaitOnExit(th);
}
if((th->state == RV_THREAD_STATE_STARTING) || (th->state == RV_THREAD_STATE_RUNNING) ||
(th->state == RV_THREAD_STATE_EXITING)) {
/* Task is running, wait for thread wrapper to trigger exit semaphore */
th->waitdestruct = RV_TRUE;
RvLockRelease(&th->datalock);
RvLockRelease(&RvThreadLock);
RvSemaphoreWait(&th->exitsignal);
RvLockGet(&RvThreadLock);
RvLockGet(&th->datalock);
/* Wait to make sure thread no longer exists (from OS perspective). */
/* If any thread specific cleanup has to be done than do it. */
RvThreadWaitOnExit(th);
}
/* If the stack had been allocated, we need to free it */
if(th->stackallocated == RV_TRUE)
RvMemoryFree(th->stackaddr);
/* OS specific destruction */
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
pthread_attr_destroy(&th->tcb);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
if(th->tcb != NULL)
CloseHandle(th->tcb);
#endif
/* Set state and destroy components */
th->state = RV_THREAD_STATE_DESTROYED;
RvSemaphoreDestruct(&th->exitsignal);
RvLockDestruct(&th->datalock);
RvLockRelease(&RvThreadLock);
return RV_OK;
}
/* Physically tell the OS to delete a thread when it has been */
/* created but never started. Called internally only, so no */
/* locking is not needed (should be done by caller). */
static RvStatus RvThreadDelete(RvThread *th)
{
/* Since POSIX threads (and variations) can't be created without */
/* being started there is no thread before start is called. Thus, */
/* we don't have to do anything here. */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
if(taskDelete(th->id) != OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
if(t_delete(th->id) != 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
if(NU_Terminate_Task(th->id) != NU_SUCCESS)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(NU_Delete_Task(th->id) != NU_SUCCESS)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
kill_proc(th->id); /* Doesn't return any errors */
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
if(TerminateThread(th->tcb, 0) == 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
return RV_OK;
}
/* Wait to make sure thread has completely exited by finding out from */
/* the OS. If anything has to be done to release the thread then do it. */
/* Called internally only so locking is not needed (should be done */
/* by the caller). */
static RvStatus RvThreadWaitOnExit(RvThread *th)
{
/* For POSIX (and variations), there is no way to tell when a thread */
/* has actually exited unless join is used. But join can not be used */
/* on all thread types, so we can't use it. Thus we just have to assume */
/* the thread is gone after it hits the semaphore and make sure */
/* nothing is done that can cause a problem. */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
while((th->tcb.status & WIND_DEAD) == 0)
RvThreadNanosleep(RvInt32Const(100) * RV_TIME_NSECPERMSEC);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS) && \
(RV_TOOL_TYPE != RV_TOOL_TYPE_CADUL) /* NO support for this feature in X86 BSP version */
/* This should, in theory, fail when the task is gone */
while(t_info(th->id, &th->tcb) == 0)
RvThreadNanosleep(Rv64Multiply(RvInt32Const(100), RV_TIME_NSECPERMSEC));
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
CHAR name[10];
DATA_ELEMENT task_status;
UNSIGNED scheduled_count, time_slice, stack_size, minimum_stack;
OPTION priority, preempt;
VOID *stack_base;
for(;;) {
if(NU_Task_Information(th->id, name, &task_status, &scheduled_count, &priority, &preempt, &time_slice, &stack_base, &stack_size, &minimum_stack) != NU_SUCCESS)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(task_status == NU_FINISHED)
break;
RvThreadNanosleep(RvInt32Const(100) * RV_TIME_NSECPERMSEC);
}
/* We need to actually delete the task after it has exited */
if(NU_Delete_Task(th->id) != NU_SUCCESS)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
struct OS_pcb *pcb;
enum PROCESS_TYPE status;
for(;;) {
pcb = get_pcb(th->id);
if(pcb == NULL)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
status = (enum PROCESS_TYPE)pcb->type;
free_buf((union SIGNAL **)&pcb); /* get_pcb allocates a buffer so we need to free it */
if((status == OS_ZOOMBIE) || (status == OS_ILLEGAL))
break;
RvThreadNanosleep(RvInt32Const(100) * RV_TIME_NSECPERMSEC);
}
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
DWORD exitcode;
for(;;) {
if(GetExitCodeThread(th->tcb, &exitcode) == 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(exitcode != STILL_ACTIVE)
break;
RvThreadNanosleep(RvInt32Const(100) * RV_TIME_NSECPERMSEC);
}
#endif
return RV_OK;
}
/* If this function fails, the only function that should be called */
/* on the thread is RvThreadDestruct to insure proper cleanup. */
RVCOREAPI RvStatus RVCALLCONV RvThreadCreate(RvThread *th)
{
RvStatus result;
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
unsigned long tmpslice;
unsigned long errCode;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
struct sched_param params;
int presult;
#endif
#if defined(RV_NULLCHECK)
if(th == NULL)
return RvThreadErrorCode(RV_ERROR_NULLPTR);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NONE)
result = RvThreadErrorCode(RV_ERROR_NOTSUPPORTED);
return result;
#endif
if(RvLockGet(&th->datalock) != RV_OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(th->state != RV_THREAD_STATE_INIT){
RvLockRelease(&th->datalock);
return RvThreadErrorCode(RV_THREAD_ERROR_CREATED);
}
/* Set up the stack for the OS */
result = RvThreadSetupStack(th);
if(result != RV_OK) {
RvLockRelease(&th->datalock);
return result;
}
/* Create the task in the OS (but don't start it). */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
if(taskInit(&th->tcb, th->name, th->priority, th->attr, th->stackstart, th->realstacksize, (FUNCPTR)RvThreadWrapper, (int)th, 0,0,0,0,0,0,0,0,0) != OK)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
errCode = t_create(th->name,
(unsigned long)th->priority,
(unsigned long)th->realstacksize,
0, th->attr.flags, &th->id);
if(errCode == 0)
{
/* Set the slice value in case slicing has been turned on */
#if (RV_OS_VERSION == RV_OS_PSOS_2_0)
PsosCfg.kc_ticks2slice = th->attr.tslice; /* todo: hopefully Jay meant it to be in ticks per slice units... */
#else
if(t_tslice(th->id, th->attr.tslice, &tmpslice) != 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
}
else
{
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
}
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
if(NU_Create_Task(&th->tcb, th->name, RvThreadWrapper, 1, th, th->stackstart, th->realstacksize, th->priority, th->attr.time_slice, th->attr.preempt, NU_NO_START) != NU_SUCCESS)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
/* OSE doesn't return errors on process create */
th->id = create_process(th->attr.proc_type, th->name, RvThreadWrapper, th->realstacksize, th->priority, th->attr.timeslice, th->attr.block, th->attr.redir_table, th->attr.vector, th->attr.user);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
/* We can't actually create the thread, but we can set up all the attributes. */
/* We'll have to set a copy of the thread pointer in the ThreadWrapper. */
presult = pthread_attr_getschedparam(&th->tcb, ¶ms);
if(presult == 0) {
params.sched_priority = th->priority;
/* FIX THIS presult |= */ pthread_attr_setschedparam(&th->tcb, ¶ms);
}
presult |= pthread_attr_setdetachstate(&th->tcb, PTHREAD_CREATE_DETACHED);
if (th->realstacksize != 0)
presult |= pthread_attr_setstacksize(&th->tcb, th->realstacksize);
/* Now set attributes we allow the user to set */
presult |= pthread_attr_setscope(&th->tcb, th->attr.contentionscope);
presult |= pthread_attr_setschedpolicy(&th->tcb, th->attr.policy);
presult |= pthread_attr_setinheritsched(&th->tcb, th->attr.inheritsched);
#if (RV_THREAD_TYPE == RV_THREAD_SOLARIS)
/* Solaris extension */
if(th->attr.guardsize != (size_t)(-1)) {
presult |= pthread_attr_setguardsize(&th->tcb, th->attr.guardsize);
}
#endif
if(presult != 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WINCE)
th->tcb = (HANDLE)CreateThread(NULL, th->realstacksize, RvThreadWrapper, th, CREATE_SUSPENDED, (unsigned *)&th->id);
if(th->tcb == NULL)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32)
th->tcb = (HANDLE)_beginthreadex(NULL, th->realstacksize, RvThreadWrapper, th, CREATE_SUSPENDED , (unsigned *)&th->id);
if(th->tcb != NULL)
{
#if(_WIN32_WINNT >= 0x0400)
if(SetThreadPriorityBoost(th->tcb, th->attr.disablepriorityboost) == 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(SetThreadAffinityMask(th->tcb, th->attr.affinitymask) == 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(SetThreadIdealProcessor(th->tcb, th->attr.idealprocessor) == -1)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?