/** * Signal the user event. * * @returns iprt status code. */ RTDECL(int) RTThreadUserSignal(RTTHREAD Thread) { int rc; PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { rc = RTSemEventMultiSignal(pThread->EventUser); rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; return rc; }
RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread) { RTTHREADSTATE enmState = RTTHREADSTATE_INVALID; PRTTHREADINT pThread = rtThreadGet(hThread); if (pThread) { enmState = rtThreadGetState(pThread); if (!ASMAtomicUoReadBool(&pThread->fReallySleeping)) enmState = RTTHREADSTATE_RUNNING; rtThreadRelease(pThread); } return enmState; }
/** * Wait for the user event, return on interruption. * * @returns iprt status code. * @param Thread The thread to wait for. * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for * an indefinite wait. */ RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies) { int rc; PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies); rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; return rc; }
RTR3DECL(int) RTTlsSet(RTTLS iTls, void *pvValue) { if (RT_UNLIKELY( iTls < 0 || iTls >= RTTHREAD_TLS_ENTRIES || !ASMBitTest(&g_au32AllocatedBitmap[0], iTls))) return VERR_INVALID_PARAMETER; PRTTHREADINT pThread = rtThreadGet(RTThreadSelf()); AssertReturn(pThread, VERR_NOT_SUPPORTED); pThread->apvTlsEntries[iTls] = pvValue; rtThreadRelease(pThread); return VINF_SUCCESS; }
/** * Wait for the thread to terminate. * * @returns iprt status code. * @param Thread The thread to wait for. * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for * an indefinite wait. * @param prc Where to store the return code of the thread. Optional. * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED. */ static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume) { int rc = VERR_INVALID_HANDLE; if (Thread != NIL_RTTHREAD) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { if (pThread->fFlags & RTTHREADFLAGS_WAITABLE) { if (fAutoResume) rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies); else rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies); if (RT_SUCCESS(rc)) { if (prc) *prc = pThread->rc; /* * If the thread is marked as waitable, we'll do one additional * release in order to free up the thread structure (see how we * init cRef in rtThreadAlloc()). */ if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT)) rtThreadRelease(pThread); } } else { rc = VERR_THREAD_NOT_WAITABLE; AssertRC(rc); } rtThreadRelease(pThread); } } return rc; }
/** * Gets the name of a thread. * * @returns Pointer to readonly name string. * @returns NULL on failure. * @param Thread Thread handle of the thread to query the name of. */ RTDECL(const char *) RTThreadGetName(RTTHREAD Thread) { PRTTHREADINT pThread; if (Thread == NIL_RTTHREAD) return NULL; pThread = rtThreadGet(Thread); if (pThread) { const char *szName = pThread->szName; rtThreadRelease(pThread); return szName; } return NULL; }
/** * Gets the name of the current thread thread. * * @returns Pointer to readonly name string. * @returns NULL on failure. */ RTDECL(const char *) RTThreadSelfName(void) { RTTHREAD Thread = RTThreadSelf(); if (Thread != NIL_RTTHREAD) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { const char *szName = pThread->szName; rtThreadRelease(pThread); return szName; } } return NULL; }
RTDECL(int) RTThreadPoke(RTTHREAD hThread) { AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER); PRTTHREADINT pThread = rtThreadGet(hThread); AssertReturn(pThread, VERR_INVALID_HANDLE); int rc; if (g_iSigPokeThread != -1) { rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread); rc = RTErrConvertFromErrno(rc); } else rc = VERR_NOT_SUPPORTED; rtThreadRelease(pThread); return rc; }
/** * Changes the type of the specified thread. * * @returns iprt status code. * @param Thread The thread which type should be changed. * @param enmType The new thread type. */ RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType) { /* * Validate input. */ int rc; if ( enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { if (rtThreadIsAlive(pThread)) { /* * Do the job. */ RT_THREAD_LOCK_RW(); rc = rtThreadNativeSetPriority(pThread, enmType); if (RT_SUCCESS(rc)) ASMAtomicXchgSize(&pThread->enmType, enmType); RT_THREAD_UNLOCK_RW(); if (RT_FAILURE(rc)) Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc)); } else rc = VERR_THREAD_IS_DEAD; rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; } else { AssertMsgFailed(("enmType=%d\n", enmType)); rc = VERR_INVALID_PARAMETER; } return rc; }
/** * Sets the name of a thread. * * @returns iprt status code. * @param Thread Thread handle of the thread to query the name of. * @param pszName The thread name. */ RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName) { /* * Validate input. */ PRTTHREADINT pThread; size_t cchName = strlen(pszName); if (cchName >= RTTHREAD_NAME_LEN) { AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1)); return VERR_INVALID_PARAMETER; } pThread = rtThreadGet(Thread); if (!pThread) return VERR_INVALID_HANDLE; /* * Update the name. */ pThread->szName[cchName] = '\0'; /* paranoia */ memcpy(pThread->szName, pszName, cchName); rtThreadRelease(pThread); return VINF_SUCCESS; }
/** * Create a new thread. * * @returns iprt status code. * @param pThread Where to store the thread handle to the new thread. (optional) * @param pfnThread The thread function. * @param pvUser User argument. * @param cbStack The size of the stack for the new thread. * Use 0 for the default stack size. * @param enmType The thread type. Used for deciding scheduling attributes * of the thread. * @param fFlags Flags of the RTTHREADFLAGS type (ORed together). * @param pszName Thread name. */ RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack, RTTHREADTYPE enmType, unsigned fFlags, const char *pszName) { int rc; PRTTHREADINT pThreadInt; LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n", pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName)); /* * Validate input. */ if (!VALID_PTR(pThread) && pThread) { Assert(VALID_PTR(pThread)); return VERR_INVALID_PARAMETER; } if (!VALID_PTR(pfnThread)) { Assert(VALID_PTR(pfnThread)); return VERR_INVALID_PARAMETER; } if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN) { AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1)); return VERR_INVALID_PARAMETER; } if (fFlags & ~RTTHREADFLAGS_MASK) { AssertMsgFailed(("fFlags=%#x\n", fFlags)); return VERR_INVALID_PARAMETER; } /* * Allocate thread argument. */ pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName); if (pThreadInt) { RTNATIVETHREAD NativeThread; pThreadInt->pfnThread = pfnThread; pThreadInt->pvUser = pvUser; pThreadInt->cbStack = cbStack; rc = rtThreadNativeCreate(pThreadInt, &NativeThread); if (RT_SUCCESS(rc)) { rtThreadInsert(pThreadInt, NativeThread); rtThreadRelease(pThreadInt); Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName)); if (pThread) *pThread = pThreadInt; return VINF_SUCCESS; } pThreadInt->cRefs = 1; rtThreadRelease(pThreadInt); } else rc = VERR_NO_TMP_MEMORY; LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc)); AssertReleaseRC(rc); return rc; }
RTDECL(RTTHREADNATIVESTATE) RTThreadGetNativeState(RTTHREAD hThread) { RTTHREADNATIVESTATE enmRet = RTTHREADNATIVESTATE_INVALID; PRTTHREADINT pThread = rtThreadGet(hThread); if (pThread) { enmRet = RTTHREADNATIVESTATE_UNKNOWN; char szName[512]; RTStrPrintf(szName, sizeof(szName), "/proc/self/task/%u/stat", pThread->tid); int fd = open(szName, O_RDONLY, 0); if (fd >= 0) { ssize_t cch = read(fd, szName, sizeof(szName) - 1); close(fd); if (cch > 0) { szName[cch] = '\0'; /* skip the pid, the (comm name) and stop at the status char. */ const char *psz = szName; while ( *psz && ( *psz != ')' || !RT_C_IS_SPACE(psz[1]) || !RT_C_IS_ALPHA(psz[2]) || !RT_C_IS_SPACE(psz[3]) ) ) psz++; if (*psz == ')') { switch (psz[2]) { case 'R': /* running */ enmRet = RTTHREADNATIVESTATE_RUNNING; break; case 'S': /* sleeping */ case 'D': /* disk sleeping */ enmRet = RTTHREADNATIVESTATE_BLOCKED; break; case 'T': /* stopped or tracking stop */ enmRet = RTTHREADNATIVESTATE_SUSPENDED; break; case 'Z': /* zombie */ case 'X': /* dead */ enmRet = RTTHREADNATIVESTATE_TERMINATED; break; default: AssertMsgFailed(("state=%c\n", psz[2])); enmRet = RTTHREADNATIVESTATE_UNKNOWN; break; } } else AssertMsgFailed(("stat='%s'\n", szName)); } } rtThreadRelease(pThread); } return enmRet; }