////////////////////////////////////////////////////////////////////////////////// // File : ctx_handler.c // Date : 01/04/2012 // Authors : alain greiner & joel porquet // Copyright (c) UPMC-LIP6 ////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////// // Extern variables and functions ///////////////////////////////////////////////////////////////////////////////// // defined in giet_kernel/switch.s file extern void _thread_switch( thread_context_t* , thread_context_t* ); // allocated in boot.c or kernel_init.c files extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; // allocated in kernel_init.c file extern fat_desc_t _fat; ////////////////////////////////////////////////////////////////// // This function is called by the _ctx_switch() function. // It desactivates a thread that received a KILL signal. // We must release all ressources allocated to the thread // before the actual desactivation, that uses NORUN_MASK_THREAD. ////////////////////////////////////////////////////////////////// static void _ctx_kill_thread( unsigned int x, unsigned int y, unsigned int p, unsigned int ltid ) { // get scheduler address static_scheduler_t* psched = _schedulers[x][y][p]; // pretend the thread to kill is the currently scheduled thread // (required by the _sys_***_release() calls) unsigned int cur_thread = psched->current; psched->current = ltid; // release BDV lock if taken and reset BDV peripheral if ( psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_BDV ) { _bdv_set_register( BLOCK_DEVICE_STATUS , 0 ); _spin_lock_release( &_bdv_lock ); } // release FAT lock if taken if ( psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FAT ) { _spin_lock_release( &_fat.fat_lock ); } // release FBF lock if taken if ( psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF ) { _sys_fbf_release(); } // release private TTY terminal if required if ( psched->context[ltid].slot[CTX_TTY_ID] < NB_TTY_CHANNELS ) _sys_tty_release(); // release private TIM channel if required if ( psched->context[ltid].slot[CTX_TIM_ID] < NB_TIM_CHANNELS ) { _sys_tim_release(); } // release private NIC_RX and CMA_RX channels if required if ( psched->context[ltid].slot[CTX_NIC_RX_ID] < NB_NIC_CHANNELS ) { _sys_nic_release( 1 ); } // release private NIC_TX and CMA_TX channels if required if ( psched->context[ltid].slot[CTX_NIC_TX_ID] < NB_NIC_CHANNELS ) { _sys_nic_release( 0 ); } // release private FBF_CMA channel if required if ( psched->context[ltid].slot[CTX_CMA_FB_ID] < NB_CMA_CHANNELS ) { _sys_fbf_cma_release(); } // restore scheduled thread index psched->current = cur_thread; // set NORUN_MASK_THREAD bit to desactivate the target thread psched->context[ltid].slot[CTX_NORUN_ID] = NORUN_MASK_THREAD; } // end _ctx_kill_thread() ////////////////// void _ctx_switch() { unsigned int gpid = _get_procid(); unsigned int cluster_xy = gpid >> P_WIDTH; unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<threads; // get current thread ltid unsigned int curr_thread_id = psched->current; // first loop on threads: handle all pending KILL signals for ( ltid = 0 ; ltid < threads ; ltid++ ) { if ( psched->context[ltid].slot[CTX_SIGS_ID] & SIGS_MASK_KILL ) { // acknowledge KILL signal _atomic_and( &psched->context[ltid].slot[CTX_SIGS_ID], ~SIGS_MASK_KILL ); // desactivate the killed thread _ctx_kill_thread( x , y , p , ltid ); } } // second loop: select next thread using a round-robin policy unsigned int next_thread_id; unsigned int found = 0; for ( ltid = curr_thread_id + 1 ; ltid < (curr_thread_id + 1 + threads) ; ltid++ ) { next_thread_id = ltid % threads; // test if the thread is runable if ( psched->context[next_thread_id].slot[CTX_NORUN_ID] == 0 ) { found = 1; break; } } // launch idle_thread if no runable thread if ( found == 0 ) next_thread_id = IDLE_THREAD_INDEX; if ( curr_thread_id != next_thread_id ) // actual thread switch required { #if GIET_DEBUG_SWITCH unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1< GIET_DEBUG_SWITCH) && (x == 0) && (y == 0) && (p == 0) ) _printf("\n[DEBUG SWITCH] (%d) -> (%d) on processor[%d,%d,%d] at cycle %d\n", curr_thread_id, next_thread_id, x, y , p, _get_proctime() ); #endif thread_context_t* curr_ctx_vaddr = &(psched->context[curr_thread_id]); thread_context_t* next_ctx_vaddr = &(psched->context[next_thread_id]); // reset TICK timer counter. _xcu_timer_reset_cpt( cluster_xy, p ); // set current thread index psched->current = next_thread_id; // makes context switch _thread_switch( curr_ctx_vaddr , next_ctx_vaddr ); } } //end _ctx_switch() /////////////////// void _idle_thread() { unsigned int gpid = _get_procid(); unsigned int cluster_xy = gpid >> P_WIDTH; unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<