static inline void sched_process_timeslice(void) { FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; /* Check if the currently executing task uses round robin * scheduling. */ if ((rtcb->flags & TCB_FLAG_ROUND_ROBIN) != 0) { /* Yes, check if decrementing the timeslice counter * would cause the timeslice to expire */ if (rtcb->timeslice <= 1) { /* Yes, Now check if the task has pre-emption disabled. * If so, then we will freeze the timeslice count at * the value until the next tick after pre-emption * has been enabled. */ if (!rtcb->lockcount) { /* Reset the timeslice in any case. */ rtcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; /* We know we are at the head of the ready to run * prioritized list. We must be the highest priority * task eligible for execution. Check the next task * in the ready to run list. If it is the same * priority, then we need to relinquish the CPU and * give that task a shot. */ if (rtcb->flink && rtcb->flink->sched_priority >= rtcb->sched_priority) { /* Just resetting the task priority to its current * value. This this will cause the task to be * rescheduled behind any other tasks at the same * priority. */ up_reprioritize_rtr(rtcb, rtcb->sched_priority); } } } else { /* Decrement the timeslice counter */ rtcb->timeslice--; } } }
int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority) { FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; tstate_t task_state; irqstate_t saved_state; /* Verify that the requested priority is in the valid range */ if (sched_priority < SCHED_PRIORITY_MIN || sched_priority > SCHED_PRIORITY_MAX) { set_errno(EINVAL); return ERROR; } /* We need to assure that there there is no interrupt activity while * performing the following. */ saved_state = irqsave(); /* There are four cases that must be considered: */ task_state = tcb->task_state; switch (task_state) { /* CASE 1. The task is running or ready-to-run and a context switch * may be caused by the re-prioritization */ case TSTATE_TASK_RUNNING: /* A context switch will occur if the new priority of the running * task becomes less than OR EQUAL TO the next highest priority * ready to run task. */ if (sched_priority <= tcb->flink->sched_priority) { /* A context switch will occur. */ up_reprioritize_rtr(tcb, (uint8_t)sched_priority); } /* Otherwise, we can just change priority since it has no effect */ else { /* Change the task priority */ tcb->sched_priority = (uint8_t)sched_priority; } break; /* CASE 2. The task is running or ready-to-run and a context switch * may be caused by the re-prioritization */ case TSTATE_TASK_READYTORUN: /* A context switch will occur if the new priority of the ready-to * run task is (strictly) greater than the current running task */ if (sched_priority > rtcb->sched_priority) { /* A context switch will occur. */ up_reprioritize_rtr(tcb, (uint8_t)sched_priority); } /* Otherwise, we can just change priority and re-schedule (since it * have no other effect). */ else { /* Remove the TCB from the ready-to-run task list */ ASSERT(!sched_removereadytorun(tcb)); /* Change the task priority */ tcb->sched_priority = (uint8_t)sched_priority; /* Put it back into the ready-to-run task list */ ASSERT(!sched_addreadytorun(tcb)); } break; /* CASE 3. The task is not in the ready to run list. Changing its * Priority cannot effect the currently executing task. */ default: /* CASE 3a. The task resides in a prioritized list. */ if (g_tasklisttable[task_state].prioritized) { /* Remove the TCB from the prioritized task list */ dq_rem((FAR dq_entry_t*)tcb, (FAR dq_queue_t*)g_tasklisttable[task_state].list); /* Change the task priority */ tcb->sched_priority = (uint8_t)sched_priority; /* Put it back into the prioritized list at the correct * position */ sched_addprioritized(tcb, (FAR dq_queue_t*)g_tasklisttable[task_state].list); } /* CASE 3b. The task resides in a non-prioritized list. */ else { /* Just change the task's priority */ tcb->sched_priority = (uint8_t)sched_priority; } break; } irqrestore(saved_state); return OK; }
uint32_t sched_roundrobin_process(FAR struct tcb_s *tcb, uint32_t ticks, bool noswitches) { uint32_t ret; int decr; /* How much can we decrement the timeslice delay? If 'ticks' is greater * than the timeslice value, then we ignore any excess amount. * * 'ticks' should never be greater than the remaining timeslice. We try * to handle that gracefully but it would be an error in the scheduling * if there ever were the case. */ DEBUGASSERT(tcb != NULL && ticks <= tcb->timeslice); decr = MIN(tcb->timeslice, ticks); /* Decrement the timeslice counter */ tcb->timeslice -= decr; /* Did decrementing the timeslice counter cause the timeslice to expire? * * If the task has pre-emption disabled. Then we will let the timeslice * count go negative as a indication of this situation. */ ret = tcb->timeslice; if (tcb->timeslice <= 0 && tcb->lockcount == 0) { /* We will also suppress context switches if we were called via one * of the unusual cases handled by sched_timer_reasses(). In that * case, we will return a value of one so that the timer will expire * as soon as possible and we can perform this action in the normal * timer expiration context. * * This is kind of kludge, but I am not to concerned because I hope * that the situation is impossible or at least could only occur on * rare corner-cases. */ if (noswitches) { ret = 1; } else { /* Reset the timeslice. */ tcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL); ret = tcb->timeslice; /* We know we are at the head of the ready to run prioritized * list. We must be the highest priority task eligible for * execution. Check the next task in the ready to run list. If * it is the same priority, then we need to relinquish the CPU and * give that task a shot. */ if (tcb->flink && tcb->flink->sched_priority >= tcb->sched_priority) { /* Just resetting the task priority to its current value. * This this will cause the task to be rescheduled behind any * other tasks at the same priority. */ up_reprioritize_rtr(tcb, tcb->sched_priority); } } } return ret; }