📄 rvthread.c
字号:
else
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
/* Set up thread pointer for those OS's that can do it from */
/* outside the task itself. Its better to know about a problem now. */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS) || (RV_THREAD_TYPE == RV_THREAD_PSOS) || \
(RV_THREAD_TYPE == RV_THREAD_NUCLEUS) || (RV_THREAD_TYPE == RV_THREAD_OSE)
if(result == RV_OK) {
result = RvThreadSetupThreadPtr(th);
if(result != RV_OK)
RvThreadDelete(th); /* Undo the thread creation */
}
#endif
if(result == RV_OK)
th->state = RV_THREAD_STATE_CREATED;
if(RvLockRelease(&th->datalock) != RV_OK) {
/* Deep trouble, do our best. */
th->state = RV_THREAD_STATE_CREATED;
RvThreadDelete(th); /* Undo the thread creation */
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
}
return result;
}
/* Do anything special required to set up a stack for the OS including */
/* allocating it if needed. The elements stackaddr, stackstart, and */
/* stackallocated should be dealt with as needed for the OS. Called */
/* internally only so locking is not needed (should be done by caller). */
static RvStatus RvThreadSetupStack(RvThread *th)
{
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS) || (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
RvStatus result;
#endif
/* For pSOS, OSE, and Win32 we really do nothing since we can't control */
/* the stack. For POSIX (and variations), we could allocate the stack but */
/* it causes problems on exit so we won't allow it. */
/* For some OS's we must allocate the stack space if it hasn't been done for us */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS) || (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
if(th->stackaddr == NULL) {
result = RvMemoryAlloc(NULL, &th->stackaddr, th->stacksize);
if(result != RV_OK)
return result;
th->stackallocated = RV_TRUE;
}
#endif
/* Set stackstart to beginning of stack memory to use */
th->stackstart = th->stackaddr;
/* do any special manipulations to stack pointers */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS) && (_STACK_DIR == _STACK_GROWS_DOWN)
/* Some architectures need stack pointer to be at end of memory block */
th->stackstart += th->realstacksize;
#endif
return RV_OK;
}
/* Actually start the thread. Obviously it must have already been created. */
RVCOREAPI RvStatus RVCALLCONV RvThreadStart(RvThread *th)
{
RvStatus result;
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
unsigned long args[4]; /* For passing pSOS arguments */
unsigned long errCode;
#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
result = RV_OK;
if(RvLockGet(&th->datalock) != RV_OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
/* We can't start something that hasn't been created or has already been started */
if(th->state != RV_THREAD_STATE_CREATED){
if(th->state == RV_THREAD_STATE_INIT) {
result = RvThreadErrorCode(RV_THREAD_ERROR_NOTCREATED);
} else result = RvThreadErrorCode(RV_THREAD_ERROR_RUNNING);
RvLockRelease(&th->datalock);
return result;
}
th->state = RV_THREAD_STATE_STARTING;
/* Actually tell the OS to start running the task */
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
if(taskActivate(th->id) != OK)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
args[0] = (unsigned long)th;
args[1] = 0;
args[2] = 0;
args[3] = 0;
errCode = t_start(th->id, th->attr.mode, RvThreadWrapper, args);
if(errCode != 0)
{
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
}
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
if(NU_Resume_Task(th->id) != NU_SUCCESS)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
start(th->id); /* No error codes */
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
if(pthread_create(&th->id, &th->tcb, RvThreadWrapper, th) != 0)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
if(ResumeThread(th->tcb) != 1)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
if(RvLockRelease(&th->datalock) != RV_OK)
result = RvThreadErrorCode(RV_ERROR_UNKNOWN);
return result;
}
/* Attach thread pointer to the task so that it can be retrieved by */
/* the RvThreadCurrent function. If an OS can only attach to the */
/* current thread (instead of that pointer to by th) then it should */
/* do so but the caller needs to account for it. Called internally */
/* only so locking is not needed (should be done by caller).*/
static RvStatus RvThreadSetupThreadPtr(RvThread *th)
{
#if (RV_THREAD_TYPE == RV_THREAD_NONE)
RvThreadCurrentPtr = th;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
/* Use a task variable to store a copy of the thread pointer */
if(taskVarAdd(th->id, (int *)&RvThreadCurrentPtr) != OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(taskVarSet(th->id, &RvThreadCurrentPtr, (int)th) != OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
/* Use a task variable to store a copy of the thread pointer */
#if (RV_OS_VERSION == RV_OS_PSOS_2_0)
unsigned long errCode;
errCode = t_setreg((unsigned long)th->id,
(unsigned long)0/*TASK_REGISTER_SLOT*/,
(unsigned long)th);
if(errCode != 0)
{
}
#else
if(t_addvar(th->id, (void **)&RvThreadCurrentPtr, (void *)th) != 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
/* Used the reseved element of the tcb structure to save a copy of the thread pointer */
th->id->tc_app_reserved_1 = (UNSIGNED)th;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
/* Use the environment to store a copy of the thread pointer */
if(set_envp(th->id, RV_THREAD_ENVPTR, (OSADDRESS)th) == 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
/* Use a thread specific variable to store a copy of the thread pointer. */
/* RvThreadCurrentKey must be set up in RvThreadInit. */
/**** Pointer is set for current task NOT the task pointer to by th. ****/
if(pthread_setspecific(RvThreadCurrentKey, (void *)th) != 0)
return 0;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
/* Use thread local storage to save a copy of the thread pointer. */
/* RvThreadCurrentKey must be set up in RvThreadInit. */
/**** Pointer is set for current task NOT the task pointer to by th. ****/
if(TlsSetValue(RvThreadCurrentKey, (LPVOID)th) == 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
return RV_OK;
}
/* Remove thread pointer from a task. Obviously, if the pointer */
/* can only be removed from the current task then that is what it */
/* will do. */
static RvStatus RvThreadRemoveThreadPtr(RvThread *th)
{
#if (RV_THREAD_TYPE == RV_THREAD_NONE)
RvThreadCurrentPtr = NULL;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
/* A task variable was used to store a copy of the thread pointer, clear and remove it. */
if(taskVarSet(th->id, &RvThreadCurrentPtr, 0) != OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
if(taskVarDelete(th->id, (int *)&RvThreadCurrentPtr) != OK)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
#if (RV_OS_VERSION == RV_OS_PSOS_2_0)
/* A task variable was used to store a copy of the thread pointer, so we clear it
but we cant actually remove it. */
unsigned long errCode;
errCode = t_setreg((unsigned long)th->id,
(unsigned long)TASK_REGISTER_SLOT,
(unsigned long)0);
if(errCode != 0)
{
}
else
printf("RvThreadRemoveThreadPtr: t_setreg succeded. storing %d.\n", 0);
#else
/* A task variable was used to store a copy of the thread pointer, remove it. */
/* We can't clear it from another thread so don't worry about it. */
if(t_delvar(th->id, (void **)&RvThreadCurrentPtr) != 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
/* Used the reseved element of the tcb structure, just clear it. */
th->id->tc_app_reserved_1 = NULL;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
/* Used an environment variable to store a copy of the thread pointer */
if(set_env(th->id, RV_THREAD_ENVPTR, NULL) == 0) /* This should clear it. */
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
/* Used a thread specific variable to store a copy of the thread pointer, just clear it. */
/**** Pointer is cleared for current task NOT the task pointer to by th. ****/
if(pthread_setspecific(RvThreadCurrentKey, NULL) != 0)
return 0;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
RV_UNUSED_ARG(th);
/* Used thread local storage to save a copy of the thread pointer, just clear it. */
/**** Pointer is cleared for current task NOT the task pointer to by th. ****/
if(TlsSetValue(RvThreadCurrentKey, NULL) == 0)
return RvThreadErrorCode(RV_ERROR_UNKNOWN);
#endif
return RV_OK;
}
/* Can only be used by threads which have been created using this module */
/* or have used RvThreadConstructFromUserThread to attach to a user thread. */
RVCOREAPI RvThread * RVCALLCONV RvThreadCurrent(void)
{
RvThread *result;
#if (RV_THREAD_TYPE == RV_THREAD_NONE)
result = RvThreadCurrentPtr;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS) || ((RV_THREAD_TYPE == RV_THREAD_PSOS) && (RV_TOOL_TYPE != RV_TOOL_TYPE_CADUL))
RvThreadId id;
id = RvThreadCurrentId(); /* We need to check for tasks which have no variable set */
if(RvThreadCurrentPtr->id == id)
result = RvThreadCurrentPtr;
else
result = NULL;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS) && (RV_OS_VERSION == RV_OS_PSOS_2_0)
RvThreadId id;
unsigned long errCode;
id = RvThreadCurrentId();
errCode = t_getreg((unsigned long)id,
(unsigned long)TASK_REGISTER_SLOT,
(unsigned long*)RvThreadCurrentPtr);
if(errCode != 0)
{
}
if(RvThreadCurrentPtr->id == id)
result = RvThreadCurrentPtr;
else
result = NULL;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
/* IMPORTANT: User create threads must make sure tc_app_reserved_1 is set to 0 */
/* for any thread making calls to this function but haven't been constructed */
/* with either construct function in the module. */
TC_TCB *task; /* TC_TCB = NU_TASK but only defined that way when compiling in DEBUG */
task = (TC_TCB *)NU_Current_Task_Pointer();
result = (RvThread *)task->tc_app_reserved_1;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
result = (RvThread *)get_envp(0, RV_THREAD_ENVPTR);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
result = (RvThread *)pthread_getspecific(RvThreadCurrentKey);
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
result = (RvThread *)TlsGetValue(RvThreadCurrentKey);
#endif
return result;
}
/* Returns the OS specific thread id */
RVCOREAPI RvThreadId RVCALLCONV RvThreadCurrentId(void)
{
#if (RV_THREAD_TYPE == RV_THREAD_NONE)
return 1;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_VXWORKS)
return taskIdSelf();
#endif
#if (RV_THREAD_TYPE == RV_THREAD_PSOS)
RvThreadId current;
t_ident(0, 0, ¤t);
return current;
#endif
#if (RV_THREAD_TYPE == RV_THREAD_NUCLEUS)
return NU_Current_Task_Pointer();
#endif
#if (RV_THREAD_TYPE == RV_THREAD_OSE)
return current_process();
#endif
#if (RV_THREAD_TYPE == RV_THREAD_POSIX) || (RV_THREAD_TYPE == RV_THREAD_SOLARIS) || \
(RV_THREAD_TYPE == RV_THREAD_UNIXWARE)
return pthread_self();
#endif
#if (RV_THREAD_TYPE == RV_THREAD_WIN32) || (RV_THREAD_TYPE == RV_THREAD_WINCE)
return GetCurrentThreadId();
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -