michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "cpr.h" michael@0: #include "cpr_stdlib.h" michael@0: #include "cpr_stdio.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "thread_monitor.h" michael@0: #include "prtypes.h" michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: #define ANDROID_MIN_THREAD_PRIORITY (-20) /* tbd: check MV linux: current val from Larry port */ michael@0: #define ANDROID_MAX_THREAD_PRIORITY (+19) /* tbd: check MV linux. current val from Larry port */ michael@0: michael@0: void CSFLogRegisterThread(const cprThread_t thread); michael@0: michael@0: /** michael@0: * cprCreateThread michael@0: * michael@0: * @brief Create a thread michael@0: * michael@0: * The cprCreateThread function creates another execution thread within the michael@0: * current process. If the input parameter "name" is present, then this is used michael@0: * for debugging purposes. The startRoutine is the address of the function where michael@0: * the thread execution begins. The start routine prototype is defined as michael@0: * follows michael@0: * @code michael@0: * int32_t (*cprThreadStartRoutine)(void* data) michael@0: * @endcode michael@0: * michael@0: * @param[in] name - name of the thread created (optional) michael@0: * @param[in] startRoutine - function where thread execution begins michael@0: * @param[in] stackSize - size of the thread's stack michael@0: * @param[in] priority - thread's execution priority michael@0: * @param[in] data - parameter to pass to startRoutine michael@0: * michael@0: * Return Value: Thread handle or NULL if creation failed. michael@0: */ michael@0: cprThread_t michael@0: cprCreateThread (const char *name, michael@0: cprThreadStartRoutine startRoutine, michael@0: uint16_t stackSize, michael@0: uint16_t priority, michael@0: void *data) michael@0: { michael@0: static const char fname[] = "cprCreateThread"; michael@0: static uint16_t id = 0; michael@0: cpr_thread_t *threadPtr; michael@0: pthread_t threadId; michael@0: pthread_attr_t attr; michael@0: michael@0: CPR_INFO("%s: creating '%s' thread\n", fname, name); michael@0: michael@0: /* Malloc memory for a new thread */ michael@0: threadPtr = (cpr_thread_t *)cpr_malloc(sizeof(cpr_thread_t)); michael@0: if (threadPtr != NULL) { michael@0: if (pthread_attr_init(&attr) != 0) { michael@0: michael@0: CPR_ERROR("%s - Failed to init attribute for thread %s\n", michael@0: fname, name); michael@0: cpr_free(threadPtr); michael@0: return (cprThread_t)NULL; michael@0: } michael@0: michael@0: if (pthread_attr_setstacksize(&attr, stackSize) != 0) { michael@0: CPR_ERROR("%s - Invalid stacksize %d specified for thread %s\n", michael@0: fname, stackSize, name); michael@0: cpr_free(threadPtr); michael@0: return (cprThread_t)NULL; michael@0: } michael@0: michael@0: if (pthread_create(&threadId, &attr, startRoutine, data) != 0) { michael@0: CPR_ERROR("%s - Creation of thread %s failed: %d\n", michael@0: fname, name, errno); michael@0: cpr_free(threadPtr); michael@0: return (cprThread_t)NULL; michael@0: } michael@0: michael@0: /* Assign name to CPR if one was passed in */ michael@0: if (name != NULL) { michael@0: threadPtr->name = name; michael@0: } michael@0: michael@0: /* michael@0: * TODO - It would be nice for CPR to keep a linked michael@0: * list of running threads for debugging purposes michael@0: * such as a show command or walking the list to ensure michael@0: * that an application does not attempt to create michael@0: * the same thread twice. michael@0: */ michael@0: threadPtr->u.handleInt = threadId; michael@0: threadPtr->threadId = ++id; michael@0: CSFLogRegisterThread(threadPtr); michael@0: return (cprThread_t)threadPtr; michael@0: } michael@0: michael@0: /* Malloc failed */ michael@0: CPR_ERROR("%s - Malloc for thread %s failed.\n", fname, name); michael@0: errno = ENOMEM; michael@0: return (cprThread_t)NULL; michael@0: } michael@0: michael@0: /* michael@0: * cprJoinThread michael@0: * michael@0: * wait for thread termination michael@0: */ michael@0: void cprJoinThread(cprThread_t thread) michael@0: { michael@0: cpr_thread_t *cprThreadPtr; michael@0: michael@0: cprThreadPtr = (cpr_thread_t *) thread; michael@0: MOZ_ASSERT(cprThreadPtr); michael@0: pthread_join(cprThreadPtr->u.handleInt, NULL); michael@0: } michael@0: michael@0: /** michael@0: * cprDestroyThread michael@0: * michael@0: * @brief Destroys the thread passed in. michael@0: * michael@0: * The cprDestroyThread function is called to destroy a thread. The thread michael@0: * parameter may be any valid thread including the calling thread itself. michael@0: * michael@0: * @param[in] thread - thread to destroy. michael@0: * michael@0: * @return CPR_SUCCESS or CPR_FAILURE. errno should be set for FAILURE case. michael@0: * michael@0: * @note In Linux there will never be a success indication as the michael@0: * calling thread will have been terminated. michael@0: */ michael@0: cprRC_t michael@0: cprDestroyThread (cprThread_t thread) michael@0: { michael@0: cpr_thread_t *cprThreadPtr; michael@0: michael@0: cprThreadPtr = (cpr_thread_t *) thread; michael@0: if (cprThreadPtr) { michael@0: /* michael@0: * Make sure thread is trying to destroy itself. michael@0: */ michael@0: if ((pthread_t) cprThreadPtr->u.handleInt == pthread_self()) { michael@0: CPR_INFO("%s: Destroying Thread %d", __FUNCTION__, cprThreadPtr->threadId); michael@0: pthread_exit(NULL); michael@0: return CPR_SUCCESS; michael@0: } michael@0: michael@0: CPR_ERROR("%s: Thread attempted to destroy another thread, not itself.", michael@0: __FUNCTION__); michael@0: MOZ_ASSERT(PR_FALSE); michael@0: errno = EINVAL; michael@0: return CPR_FAILURE; michael@0: } michael@0: michael@0: CPR_ERROR("%s - NULL pointer passed in.", __FUNCTION__); michael@0: MOZ_ASSERT(PR_FALSE); michael@0: errno = EINVAL; michael@0: return CPR_FAILURE; michael@0: } michael@0: michael@0: /** michael@0: * cprAdjustRelativeThreadPriority michael@0: * michael@0: * @brief The function sets the relative thread priority up or down by the given value. michael@0: * michael@0: * This function is used pSIPCC to set up the thread priority. The values of the michael@0: * priority range from -20 (Maximum priority) to +19 (Minimum priority). michael@0: * michael@0: * @param[in] relPri - nice value of the thread -20 is MAX and 19 is MIN michael@0: * michael@0: * @return CPR_SUCCESS or CPR_FAILURE michael@0: */ michael@0: cprRC_t michael@0: cprAdjustRelativeThreadPriority (int relPri) michael@0: { michael@0: const char *fname = "cprAdjustRelativeThreadPriority"; michael@0: michael@0: if (setpriority(PRIO_PROCESS, 0, relPri) == -1) { michael@0: CPR_ERROR("%s: could not set the nice..err=%d\n", michael@0: fname, errno); michael@0: return CPR_FAILURE; michael@0: } michael@0: return CPR_SUCCESS; michael@0: } michael@0: michael@0: /** michael@0: * @} michael@0: * @addtogroup ThreadInternal Helper functions for implementing threads in CPR michael@0: * @ingroup Threads michael@0: * @brief Helper functions used by CPR for thread implementation michael@0: * michael@0: * @{ michael@0: */ michael@0: michael@0: /** michael@0: * cprGetThreadId michael@0: * michael@0: * @brief Return the pthread ID for the given CPR thread. michael@0: * michael@0: * @param[in] thread - thread to query michael@0: * michael@0: * @return Thread's Id or zero(0) michael@0: * michael@0: */ michael@0: pthread_t michael@0: cprGetThreadId (cprThread_t thread) michael@0: { michael@0: if (thread) { michael@0: return ((cpr_thread_t *)thread)->u.handleInt; michael@0: } michael@0: return 0; michael@0: } michael@0: /** michael@0: * @} michael@0: */