/* * Extend the os_procAttr struct with scheduling * settings derived from the u_scheduler class. * All other attributes from the os_procAttr struct * are not modified. */ u_result u_procAttrInit( struct v_schedulePolicy *v_schedParam, os_procAttr *os_procParam ) { if (v_schedParam->kind == V_SCHED_DEFAULT) { os_procParam->schedClass = os_procAttrGetClass (); } else if (v_schedParam->kind == V_SCHED_REALTIME) { os_procParam->schedClass = OS_SCHED_REALTIME; } else if (v_schedParam->kind == V_SCHED_TIMESHARING) { os_procParam->schedClass = OS_SCHED_TIMESHARE; } if (v_schedParam->priorityKind == V_SCHED_PRIO_RELATIVE) { os_procParam->schedPriority = os_procAttrGetPriority () + v_schedParam->priority; } else { os_procParam->schedPriority = v_schedParam->priority; } return U_RESULT_OK; }
/** \brief Create a new thread * * \b os_threadCreate creates a thread by calling \b pthread_create. * But first it processes all thread attributes in \b threadAttr and * sets the scheduling properties with \b pthread_attr_setscope * to create a bounded thread, \b pthread_attr_setschedpolicy to * set the scheduling class and \b pthread_attr_setschedparam to * set the scheduling priority. * \b pthread_attr_setdetachstate is called with parameter * \PTHREAD_CREATE_JOINABLE to make the thread joinable, which * is needed to be able to wait for the threads termination * in \b os_threadWaitExit. */ os_result os_threadCreate ( os_threadId *threadId, const char *name, const os_threadAttr *threadAttr, void *(* start_routine)(void *), void *arg) { pthread_attr_t attr; struct sched_param sched_param; os_result rv = os_resultSuccess; os_threadContext *threadContext; os_threadAttr tattr; int result, create_ret; int policy; assert (threadId != NULL); assert (name != NULL); assert (threadAttr != NULL); assert (start_routine != NULL); tattr = *threadAttr; if (tattr.schedClass == OS_SCHED_DEFAULT) { #ifndef PIKEOS_POSIX #ifndef VXWORKS_RTP tattr.schedClass = os_procAttrGetClass (); #endif tattr.schedPriority = os_procAttrGetPriority (); #endif } if (pthread_attr_init (&attr) != 0) { rv = os_resultFail; } else { #ifdef VXWORKS_RTP (void)pthread_attr_setname(&attr, name); #endif if (pthread_getschedparam(pthread_self(), &policy, &sched_param) != 0 || #if !defined (OS_RTEMS_DEFS_H) && !defined (PIKEOS_POSIX) pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM) != 0 || #endif pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE) != 0 || pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED) != 0) { rv = os_resultFail; } else { if (tattr.stackSize != 0) { #ifdef PTHREAD_STACK_MIN if ( tattr.stackSize < PTHREAD_STACK_MIN ) { tattr.stackSize = PTHREAD_STACK_MIN; } #endif #ifdef OSPL_STACK_MAX if ( tattr.stackSize > OSPL_STACK_MAX ) { tattr.stackSize = OSPL_STACK_MAX; } #endif if (pthread_attr_setstacksize (&attr, tattr.stackSize) != 0) { rv = os_resultFail; } } } if (rv == os_resultSuccess) { if (tattr.schedClass == OS_SCHED_REALTIME) { result = pthread_attr_setschedpolicy (&attr, SCHED_FIFO); if (result != 0) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_attr_setschedpolicy failed for SCHED_FIFO with "\ "error %d (%s) for thread '%s', reverting to SCHED_OTHER.", result, os_strError(result), name); result = pthread_attr_setschedpolicy (&attr, SCHED_OTHER); if (result != 0) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_attr_setschedpolicy failed with error %d (%s)", result, name); } } } else { result = pthread_attr_setschedpolicy (&attr, SCHED_OTHER); if (result != 0) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_attr_setschedpolicy failed with error %d (%s)", result, name); } } pthread_attr_getschedpolicy(&attr, &policy); if ((tattr.schedPriority < sched_get_priority_min(policy)) || (tattr.schedPriority > sched_get_priority_max(policy))) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "scheduling priority outside valid range for the policy "\ "reverted to valid value (%s)", name); sched_param.sched_priority = (sched_get_priority_min(policy) + sched_get_priority_max(policy)) / 2; } else { sched_param.sched_priority = tattr.schedPriority; } /* Take over the thread context: name, start routine and argument */ threadContext = os_malloc (sizeof (os_threadContext)); threadContext->threadName = os_malloc (strlen (name)+1); os_strncpy (threadContext->threadName, name, strlen (name)+1); threadContext->startRoutine = start_routine; threadContext->arguments = arg; /* start the thread */ result = pthread_attr_setschedparam (&attr, &sched_param); if (result != 0) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_attr_setschedparam failed with error %d (%s)", result, name); } create_ret = pthread_create(threadId, &attr, os_startRoutineWrapper, threadContext); if (create_ret != 0) { /* In case real-time thread creation failed due to a lack * of permissions, try reverting to time-sharing and continue. */ if((create_ret == EPERM) && (tattr.schedClass == OS_SCHED_REALTIME)) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_create failed with SCHED_FIFO " \ "for thread '%s', reverting to SCHED_OTHER.", name); pthread_attr_setschedpolicy (&attr, SCHED_OTHER); pthread_attr_getschedpolicy(&attr, &policy); if ((tattr.schedPriority < sched_get_priority_min(policy)) || (tattr.schedPriority > sched_get_priority_max(policy))) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "scheduling priority outside valid range for the " \ "policy reverted to valid value (%s)", name); sched_param.sched_priority = (sched_get_priority_min(policy) + sched_get_priority_max(policy)) / 2; } else { sched_param.sched_priority = tattr.schedPriority; } result = pthread_attr_setschedparam (&attr, &sched_param); if (result != 0) { OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_attr_setschedparam failed " \ "with error %d (%s)", result, name); } else { create_ret = pthread_create(threadId, &attr, os_startRoutineWrapper, threadContext); } } } else { rv = os_resultSuccess; } if(create_ret != 0){ os_free (threadContext->threadName); os_free (threadContext); OS_REPORT (OS_WARNING, "os_threadCreate", 2, "pthread_create failed with error %d (%s)", create_ret, name); rv = os_resultFail; } } pthread_attr_destroy (&attr); } return rv; }