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, &params);
    if(presult == 0) {
        params.sched_priority = th->priority;
        /* FIX THIS presult |= */ pthread_attr_setschedparam(&th->tcb, &params);
    }
    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 + -
显示快捷键?