nrk_status_t nrk_terminate_task(nrk_task_type * Task) { nrk_queue *curNode; //PAJA: CRITICAL SECTIONS!!!!!!! nrk_int_disable(); //////// nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); nrk_rem_from_readyQ(Task->task_ID); nrk_cur_task_TCB->task_state = FINISHED; //(Task->taskTCB)->task_state = FINISHED; (Task->taskTCB)->event_suspend = 0; //fix srinivas tasksNumber--; curNode = _free_node; //free node can not be NULL while (curNode->Next!=NULL) curNode = curNode->Next; if (_free_node->Next!=NULL) (curNode->Prev)->Next = NULL; else _free_node = NULL; //free(curNode); paja: mui importante!!!!!!!!! nrk_int_enable(); // HAHA, there is NO next period... nrk_wait_until_next_period (); return NRK_OK; }
nrk_status_t nrk_terminate_task() { nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->task_state = FINISHED; // HAHA, there is NO next period... nrk_wait_until_next_period(); return NRK_OK; }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; //uint16_t start_time_stamp; /* _nrk_precision_os_timer_reset(); */ /* nrk_int_disable(); */ // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp=_nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake=60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_SW_WDT _nrk_sw_wdt_check(); #endif #ifdef NRK_KERNEL_TEST //nrk_kprintf( PSTR("*")); //Check if OS tick was delayed... // if(_nrk_cpu_state!=CPU_SLEEP && _nrk_os_timer_get()!=0) { // nrk_kprintf( PSTR("X" )); //printf( "%u ",_nrk_os_timer_get()); // } //printf( "%u\r\n",_nrk_prev_timer_val); if((_nrk_cpu_state!=CPU_ACTIVE) && (_nrk_os_timer_get()>nrk_max_sleep_wakeup_time)) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs+=((uint32_t)_nrk_prev_timer_val*NANOS_PER_TICK); nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==CPU_SLEEP) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif while(nrk_system_time.nano_secs>=NANOS_PER_SEC) { nrk_system_time.nano_secs-=NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); } // _nrk_time_trigger--; //} if(nrk_cur_task_TCB->suspend_flag==1 && nrk_cur_task_TCB->task_state!=FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if(nrk_cur_task_TCB->event_suspend==RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend=0; nrk_cur_task_TCB->nw_flag=0; } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if(nrk_cur_task_TCB->cpu_reserve!=0 && nrk_cur_task_TCB->task_ID!=NRK_IDLE_TASK_ID) { // Update CASH and cpu_remaining // First use up any available CASH budget uint8_t ticksToAccountFor = _nrk_prev_timer_val; nrk_budget_t *budgetFromCASH = nrk_peek_budget(); while (ticksToAccountFor > 0 && budgetFromCASH) { // We've found some cash budget uint8_t availableCASH = budgetFromCASH->amount_left; nrk_time_t system_time; nrk_time_get(&system_time); // We need to look at the deadline for the cash budget // If it has passed, we can only use the portion that came before the deadline if (nrk_time_compare(&system_time, &budgetFromCASH->expire_time) == 1) { nrk_time_t difference; nrk_time_sub(&difference, system_time, budgetFromCASH->expire_time); uint8_t differenceInTicks = _nrk_time_to_ticks(&difference); // Check if it expired before we got a chance to use it if (differenceInTicks > ticksToAccountFor) { availableCASH = 0; } else { uint8_t usableBudget = ticksToAccountFor - _nrk_time_to_ticks(&difference); // Take the minimum of available vs usable availableCASH = usableBudget < availableCASH ? usableBudget : availableCASH; } // pop it off the queue. Expired now. nrk_get_budget(); } if (availableCASH > ticksToAccountFor) { budgetFromCASH->amount_left -= ticksToAccountFor; ticksToAccountFor = 0; } else { ticksToAccountFor -= availableCASH; // Pop the now empty cash budget off the queue nrk_get_budget(); } budgetFromCASH = budgetFromCASH->Next; } // If we still have ticks to account for, take them off cpu_remaining if (ticksToAccountFor > 0) { nrk_cur_task_TCB->cpu_remaining -= ticksToAccountFor; } // For finished tasks that still have cpu remaining, give it to the CASH queue if (nrk_cur_task_TCB->task_state==FINISHED && nrk_cur_task_TCB->cpu_remaining > 0) { // Add to CASH queue nrk_add_nrk_budget(nrk_cur_task_TCB->absolute_deadline, nrk_cur_task_TCB->cpu_remaining); } else if (nrk_cur_task_TCB->cpu_remaining ==0 ) { // Support for Constant Bandwith Servers if(nrk_cur_task_TCB->task_type == CBS_TASK) { // Recharge budget nrk_cur_task_TCB->cpu_remaining = nrk_cur_task_TCB->cpu_reserve; // Increase the absolute deadline nrk_time_t increase = _nrk_ticks_to_time(nrk_cur_task_TCB->period); nrk_time_add(&nrk_cur_task_TCB->absolute_deadline, nrk_cur_task_TCB->absolute_deadline, increase); // Remove/re-add from ready queue to re-sort based on new absolute deadline nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); nrk_add_to_readyQ(nrk_cur_task_TCB->task_ID); } else { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_VIOLATED,nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) { if(nrk_task_TCB[task_ID].task_ID==-1) continue; nrk_task_TCB[task_ID].suspend_flag=0; if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state!=FINISHED ) { if( nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val; else { nrk_task_TCB[task_ID].next_wakeup=0; } // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if( nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_period-=_nrk_prev_timer_val; else { if(nrk_task_TCB[task_ID].period>_nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period= nrk_task_TCB[task_ID].period-_nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period= _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if(nrk_task_TCB[task_ID].next_period==0) nrk_task_TCB[task_ID].next_period=nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED ) { // printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if(nrk_task_TCB[task_ID].event_suspend>0 && nrk_task_TCB[task_ID].nw_flag==1) nrk_task_TCB[task_ID].active_signal_mask=SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend=0; nrk_task_TCB[task_ID].nw_flag=0; nrk_task_TCB[task_ID].suspend_flag=0; if(nrk_task_TCB[task_ID].num_periods==1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; // If there is no period set, don't wakeup periodically if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; //nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; //nrk_task_TCB[task_ID].num_periods--; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_task_TCB[task_ID].num_periods=1; // printf( "np = %d\r\n",nrk_task_TCB[task_ID].next_wakeup); // nrk_task_TCB[task_ID].num_periods=1; } } if(nrk_task_TCB[task_ID].next_wakeup!=0 && nrk_task_TCB[task_ID].next_wakeup<next_wake ) { // Find closest next_wake task next_wake=nrk_task_TCB[task_ID].next_wakeup; } } } #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if(task_ID!=NRK_IDLE_TASK_ID) { // You are a non-Idle Task if(nrk_task_TCB[task_ID].cpu_reserve!=0 && nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME) { if(next_wake>nrk_task_TCB[task_ID].cpu_remaining) next_wake=nrk_task_TCB[task_ID].cpu_remaining; } else { if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. #ifndef NRK_NO_POWER_DOWN if(next_wake>NRK_SLEEP_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<MAX_SCHED_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<NRK_SLEEP_WAKEUP_TIME) { next_wake=NRK_SLEEP_WAKEUP_TIME-1; } else { next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME; } } else if(next_wake>NRK_SLEEP_WAKEUP_TIME+MAX_SCHED_WAKEUP_TIME) { next_wake=MAX_SCHED_WAKEUP_TIME; } else { next_wake=MAX_SCHED_WAKEUP_TIME-NRK_SLEEP_WAKEUP_TIME; } } #endif } /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ // If we disable power down, we still need to wakeup before the overflow #ifdef NRK_NO_POWER_DOWN if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; #endif //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif //printf( "n %u %u %u %u\r\n",task_ID, _nrk_prev_timer_val, next_wake,_nrk_os_timer_get()); _nrk_prev_timer_val=next_wake; if((_nrk_os_timer_get()+1)>=next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==CPU_SLEEP)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake=_nrk_os_timer_get()+2; _nrk_prev_timer_val=next_wake; } if(task_ID!=NRK_IDLE_TASK_ID) _nrk_cpu_state=CPU_ACTIVE; _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp,CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; uint16_t start_time_stamp; _nrk_precision_os_timer_reset(); nrk_int_disable(); // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp=_nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake=60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_SW_WDT _nrk_sw_wdt_check(); #endif //printf( "last run: %d\n",nrk_cur_task_TCB->task_ID ); //for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) //{ //printf( "%d nw:%lu\n",task_ID,nrk_task_TCB[task_ID].next_wakeup ); //} #ifdef NRK_KERNEL_TEST //nrk_kprintf( PSTR("*")); //Check if OS tick was delayed... // if(_nrk_cpu_state!=CPU_SLEEP && _nrk_os_timer_get()!=0) { // nrk_kprintf( PSTR("X" )); //printf( "%u ",_nrk_os_timer_get()); // } //printf( "%u\r\n",_nrk_prev_timer_val); if((_nrk_cpu_state!=CPU_ACTIVE) && (_nrk_os_timer_get()>nrk_max_sleep_wakeup_time)) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs+=((uint32_t)_nrk_prev_timer_val*NANOS_PER_TICK); nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==CPU_SLEEP) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif while(nrk_system_time.nano_secs>=NANOS_PER_SEC) { nrk_system_time.nano_secs-=NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); } // _nrk_time_trigger--; //} if(nrk_cur_task_TCB->suspend_flag==1 && nrk_cur_task_TCB->task_state!=FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if(nrk_cur_task_TCB->event_suspend==RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend=0; nrk_cur_task_TCB->nw_flag=0; // agr added to fix initial startup scheduling problem if(nrk_cur_task_TCB->next_wakeup==0) { nrk_cur_task_TCB->next_wakeup=nrk_cur_task_TCB->next_period; } } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if(nrk_cur_task_TCB->cpu_reserve!=0 && nrk_cur_task_TCB->task_ID!=NRK_IDLE_TASK_ID && nrk_cur_task_TCB->task_state!=FINISHED ) { if(nrk_cur_task_TCB->cpu_remaining<_nrk_prev_timer_val) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_ERROR,nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->cpu_remaining=0; } else nrk_cur_task_TCB->cpu_remaining-=_nrk_prev_timer_val; task_ID= nrk_cur_task_TCB->task_ID; if (nrk_cur_task_TCB->cpu_remaining ==0 ) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_VIOLATED,task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(task_ID); } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) { if(nrk_task_TCB[task_ID].task_ID==-1) continue; nrk_task_TCB[task_ID].suspend_flag=0; if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state!=FINISHED ) { if( nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val; else { nrk_task_TCB[task_ID].next_wakeup=0; } // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if( nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_period-=_nrk_prev_timer_val; else { if(nrk_task_TCB[task_ID].period>_nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period= nrk_task_TCB[task_ID].period-_nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period= _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if(nrk_task_TCB[task_ID].next_period==0) nrk_task_TCB[task_ID].next_period=nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED ) { //printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if(nrk_task_TCB[task_ID].event_suspend>0 && nrk_task_TCB[task_ID].nw_flag==1) nrk_task_TCB[task_ID].active_signal_mask=SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend=0; nrk_task_TCB[task_ID].nw_flag=0; nrk_task_TCB[task_ID].suspend_flag=0; if(nrk_task_TCB[task_ID].num_periods==1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; // If there is no period set, don't wakeup periodically if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; //nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; //nrk_task_TCB[task_ID].num_periods--; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_task_TCB[task_ID].num_periods=1; // printf( "np = %d\r\n",nrk_task_TCB[task_ID].next_wakeup); // nrk_task_TCB[task_ID].num_periods=1; } } if(nrk_task_TCB[task_ID].next_wakeup!=0 && nrk_task_TCB[task_ID].next_wakeup<next_wake ) { // Find closest next_wake task next_wake=nrk_task_TCB[task_ID].next_wakeup; } } } #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if(task_ID!=NRK_IDLE_TASK_ID) { // You are a non-Idle Task if(nrk_task_TCB[task_ID].cpu_reserve!=0 && nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME) { if(next_wake>nrk_task_TCB[task_ID].cpu_remaining) next_wake=nrk_task_TCB[task_ID].cpu_remaining; } else { if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. #ifndef NRK_NO_POWER_DOWN if(next_wake>NRK_SLEEP_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<MAX_SCHED_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<NRK_SLEEP_WAKEUP_TIME) { next_wake=NRK_SLEEP_WAKEUP_TIME-1; } else { next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME; } } else if(next_wake>NRK_SLEEP_WAKEUP_TIME+MAX_SCHED_WAKEUP_TIME) { next_wake=MAX_SCHED_WAKEUP_TIME; } else { next_wake=MAX_SCHED_WAKEUP_TIME-NRK_SLEEP_WAKEUP_TIME; } } #endif } /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ // If we disable power down, we still need to wakeup before the overflow #ifdef NRK_NO_POWER_DOWN if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; #endif //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif //printf( "n %u %u %u %u\r\n",task_ID, _nrk_prev_timer_val, next_wake,_nrk_os_timer_get()); _nrk_prev_timer_val=next_wake; // Maybe the signals are triggering this problem? if((_nrk_os_timer_get()+1)>=next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==CPU_SLEEP)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake=_nrk_os_timer_get()+2; _nrk_prev_timer_val=next_wake; } if(task_ID!=NRK_IDLE_TASK_ID) _nrk_cpu_state=CPU_ACTIVE; _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp,CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; uint16_t start_time_stamp; nrk_int_disable(); // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp = _nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake = 60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_KERNEL_TEST if(_nrk_cpu_state && _nrk_os_timer_get()>nrk_max_sleep_wakeup_time) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs += ((uint32_t) _nrk_prev_timer_val * NANOS_PER_TICK); nrk_system_time.nano_secs -= (nrk_system_time.nano_secs % (uint32_t) NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==2) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif printf("==============================\r\n"); printf("ENTERING SCHEDULER @ %u \r\n", nrk_system_time.nano_secs); printf("!! Interrupted TID %u after %u.\r\n ", nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); while (nrk_system_time.nano_secs >= NANOS_PER_SEC) { nrk_system_time.nano_secs -= NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs -= (nrk_system_time.nano_secs % (uint32_t) NANOS_PER_TICK); } // _nrk_time_trigger--; //} if (nrk_cur_task_TCB->suspend_flag == 1 && nrk_cur_task_TCB->task_state != FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if (nrk_cur_task_TCB->event_suspend == RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if (nrk_cur_task_TCB->event_suspend > 0 && nrk_cur_task_TCB->nw_flag == 0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if (nrk_cur_task_TCB->event_suspend > 0 && nrk_cur_task_TCB->nw_flag == 1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend = 0; nrk_cur_task_TCB->nw_flag = 0; } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if (nrk_cur_task_TCB->cpu_reserve != 0 && nrk_cur_task_TCB->task_ID != NRK_IDLE_TASK_ID && nrk_cur_task_TCB->task_state != FINISHED) { if (nrk_cur_task_TCB->cpu_remaining < _nrk_prev_timer_val) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif printf("< MISS > Deadline Missed for Task %u\r\n",task_ID); nrk_kernel_error_add(NRK_RESERVE_ERROR, nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->cpu_remaining = 0; } else nrk_cur_task_TCB->cpu_remaining -= _nrk_prev_timer_val; task_ID = nrk_cur_task_TCB->task_ID; if (nrk_cur_task_TCB->cpu_remaining == 0) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif printf("xxxxxx >> Deadline Violated for Task %u\r\n",task_ID); nrk_kernel_error_add(NRK_RESERVE_VIOLATED, task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(task_ID); } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID = 0; task_ID < NRK_MAX_TASKS; task_ID++) { if (nrk_task_TCB[task_ID].task_ID == -1) continue; nrk_task_TCB[task_ID].suspend_flag = 0; if (nrk_task_TCB[task_ID].task_ID != NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state != FINISHED) { if (nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_wakeup -= _nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_wakeup = 0; // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if (nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period -= _nrk_prev_timer_val; else { if (nrk_task_TCB[task_ID].period > _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period = nrk_task_TCB[task_ID].period - _nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period = _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if (nrk_task_TCB[task_ID].next_period == 0) nrk_task_TCB[task_ID].next_period = nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED) { // printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if (nrk_task_TCB[task_ID].event_suspend > 0 && nrk_task_TCB[task_ID].nw_flag == 1) nrk_task_TCB[task_ID].active_signal_mask =SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend = 0; nrk_task_TCB[task_ID].nw_flag = 0; nrk_task_TCB[task_ID].suspend_flag = 0; if (nrk_task_TCB[task_ID].num_periods == 1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; nrk_task_TCB[task_ID].abs_deadline += nrk_task_TCB[task_ID].period; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period * (nrk_task_TCB[task_ID].num_periods - 1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period * (nrk_task_TCB[task_ID].num_periods - 1)); nrk_task_TCB[task_ID].num_periods = 1; } } if (nrk_task_TCB[task_ID].next_wakeup != 0 && nrk_task_TCB[task_ID].next_wakeup < next_wake) { // Find closest next_wake task next_wake = nrk_task_TCB[task_ID].next_wakeup; } printf("SQueue Contents :\r\n"); printf( "%u. TID %u, CPU Rem %u, CPU Res %u, Period %u, State %u, NW %u, NP %u, AD %u \r\n", task_ID, nrk_task_TCB[task_ID].task_ID, nrk_task_TCB[task_ID].cpu_remaining, nrk_task_TCB[task_ID].cpu_reserve, nrk_task_TCB[task_ID].period, nrk_task_TCB[task_ID].task_state, nrk_task_TCB[task_ID].next_wakeup, nrk_task_TCB[task_ID].next_period, nrk_task_TCB[task_ID].abs_deadline); } } printf(">>> next_wake is @ %u after loop .\r\n", next_wake); #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if (task_ID != NRK_IDLE_TASK_ID) { // You are a non-Idle Task if (nrk_task_TCB[task_ID].cpu_reserve != 0 && nrk_task_TCB[task_ID].cpu_remaining < MAX_SCHED_WAKEUP_TIME) { if (next_wake > nrk_task_TCB[task_ID].cpu_remaining) next_wake = nrk_task_TCB[task_ID].cpu_remaining; } else { if (next_wake > MAX_SCHED_WAKEUP_TIME) next_wake = MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. if (next_wake > NRK_SLEEP_WAKEUP_TIME) { if (next_wake - NRK_SLEEP_WAKEUP_TIME < MAX_SCHED_WAKEUP_TIME) { if (next_wake - NRK_SLEEP_WAKEUP_TIME < NRK_SLEEP_WAKEUP_TIME) { next_wake = NRK_SLEEP_WAKEUP_TIME - 1; } else { next_wake = next_wake - NRK_SLEEP_WAKEUP_TIME; } } else if (next_wake > NRK_SLEEP_WAKEUP_TIME + MAX_SCHED_WAKEUP_TIME) { next_wake = MAX_SCHED_WAKEUP_TIME; } else { next_wake = MAX_SCHED_WAKEUP_TIME - NRK_SLEEP_WAKEUP_TIME; } } } printf(">>> next_wake CHANGED TO REM_TIME,i.e. %u .\r\n", next_wake); /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif _nrk_prev_timer_val = next_wake; if (_nrk_os_timer_get() >= next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==2)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake = _nrk_os_timer_get() + 2; _nrk_prev_timer_val = next_wake; } if (task_ID != NRK_IDLE_TASK_ID) _nrk_cpu_state = 0; nrk_queue * printer = _head_node; int j = 0; printf("RQueue Contents :\r\n"); while (printer) { printf( "%u. TID %u, CPU Rem %u, CPU Res %u, Period %u, State %u, NW %u, NP %u, AD %u . \r\n", j, printer->task_ID, nrk_task_TCB[printer->task_ID].cpu_remaining, nrk_task_TCB[printer->task_ID].cpu_reserve, nrk_task_TCB[printer->task_ID].period, nrk_task_TCB[printer->task_ID].task_state, nrk_task_TCB[printer->task_ID].next_wakeup, nrk_task_TCB[printer->task_ID].next_period, nrk_task_TCB[printer->task_ID].abs_deadline); printer = printer->Next; j++; } _nrk_set_next_wakeup(next_wake); printf("Setting TACCR0 to (nw-1) -> %u \r\n", (next_wake - 1)); printf("Starting TID %u \r\n", task_ID); printf("EXITING SCHEDULER\r\n"); printf("==============================\r\n"); _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp, CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }